refactor: Use view binding to replace Kotlin synthetics (#824)
* refactor: Migrate home screen to data binding * Add view binding * Migrate ConversationView to view binding * Migrate ConversationActivityV2 to view binding * View model refactor * Move more functionality to the view model * Add ui state events flow * Update conversation item bindings * Update profile picture view bindings * Replace Kotlin synthetics with view bindings * Fix qr code fragment binding and optimize imports * View binding refactors * Make TextSecurePreferences an interface and add an implementation to improve testability * Add conversation repository * Migrate remaining TextSecurePreferences functions into the interface * Add unit conversation unit tests * Add unit test coverage for remaining view model functionspull/827/head
parent
366b5abdc8
commit
c113a447cf
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,130 @@
|
||||
package org.thoughtcrime.securesms.conversation.v2
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import org.session.libsession.utilities.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord
|
||||
import org.thoughtcrime.securesms.repository.ConversationRepository
|
||||
import java.util.UUID
|
||||
|
||||
class ConversationViewModel(
|
||||
val threadId: Long,
|
||||
private val repository: ConversationRepository
|
||||
) : ViewModel() {
|
||||
|
||||
private val _uiState = MutableStateFlow(ConversationUiState())
|
||||
val uiState: StateFlow<ConversationUiState> = _uiState
|
||||
|
||||
val recipient: Recipient by lazy {
|
||||
repository.getRecipientForThreadId(threadId)
|
||||
}
|
||||
|
||||
init {
|
||||
_uiState.update {
|
||||
it.copy(isOxenHostedOpenGroup = repository.isOxenHostedOpenGroup(threadId))
|
||||
}
|
||||
}
|
||||
|
||||
fun saveDraft(text: String) {
|
||||
repository.saveDraft(threadId, text)
|
||||
}
|
||||
|
||||
fun getDraft(): String? {
|
||||
return repository.getDraft(threadId)
|
||||
}
|
||||
|
||||
fun inviteContacts(contacts: List<Recipient>) {
|
||||
repository.inviteContacts(threadId, contacts)
|
||||
}
|
||||
|
||||
fun unblock() {
|
||||
if (recipient.isContactRecipient) {
|
||||
repository.unblock(recipient)
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteLocally(message: MessageRecord) {
|
||||
repository.deleteLocally(recipient, message)
|
||||
}
|
||||
|
||||
fun deleteForEveryone(message: MessageRecord) = viewModelScope.launch {
|
||||
repository.deleteForEveryone(threadId, recipient, message)
|
||||
.onFailure {
|
||||
showMessage("Couldn't delete message due to error: $it")
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteMessagesWithoutUnsendRequest(messages: Set<MessageRecord>) = viewModelScope.launch {
|
||||
repository.deleteMessageWithoutUnsendRequest(threadId, messages)
|
||||
.onFailure {
|
||||
showMessage("Couldn't delete message due to error: $it")
|
||||
}
|
||||
}
|
||||
|
||||
fun banUser(recipient: Recipient) = viewModelScope.launch {
|
||||
repository.banUser(threadId, recipient)
|
||||
.onSuccess {
|
||||
showMessage("Successfully banned user")
|
||||
}
|
||||
.onFailure {
|
||||
showMessage("Couldn't ban user due to error: $it")
|
||||
}
|
||||
}
|
||||
|
||||
fun banAndDeleteAll(recipient: Recipient) = viewModelScope.launch {
|
||||
repository.banAndDeleteAll(threadId, recipient)
|
||||
.onSuccess {
|
||||
showMessage("Successfully banned user and deleted all their messages")
|
||||
}
|
||||
.onFailure {
|
||||
showMessage("Couldn't execute request due to error: $it")
|
||||
}
|
||||
}
|
||||
|
||||
private fun showMessage(message: String) {
|
||||
_uiState.update { currentUiState ->
|
||||
val messages = currentUiState.uiMessages + UiMessage(
|
||||
id = UUID.randomUUID().mostSignificantBits,
|
||||
message = message
|
||||
)
|
||||
currentUiState.copy(uiMessages = messages)
|
||||
}
|
||||
}
|
||||
|
||||
fun messageShown(messageId: Long) {
|
||||
_uiState.update { currentUiState ->
|
||||
val messages = currentUiState.uiMessages.filterNot { it.id == messageId }
|
||||
currentUiState.copy(uiMessages = messages)
|
||||
}
|
||||
}
|
||||
|
||||
@dagger.assisted.AssistedFactory
|
||||
interface AssistedFactory {
|
||||
fun create(threadId: Long): Factory
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
class Factory @AssistedInject constructor(
|
||||
@Assisted private val threadId: Long,
|
||||
private val repository: ConversationRepository
|
||||
) : ViewModelProvider.Factory {
|
||||
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return ConversationViewModel(threadId, repository) as T
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class UiMessage(val id: Long, val message: String)
|
||||
|
||||
data class ConversationUiState(
|
||||
val isOxenHostedOpenGroup: Boolean = false,
|
||||
val uiMessages: List<UiMessage> = emptyList()
|
||||
)
|