Ignore/Unignore: makes more sense to be at the client level than room
This commit is contained in:
parent
ccfe0bb10c
commit
884cdb9575
10 changed files with 60 additions and 35 deletions
|
|
@ -49,7 +49,7 @@ object RoomMemberProvidesModule {
|
||||||
): RoomMemberDetailsPresenter.Factory {
|
): RoomMemberDetailsPresenter.Factory {
|
||||||
return object : RoomMemberDetailsPresenter.Factory {
|
return object : RoomMemberDetailsPresenter.Factory {
|
||||||
override fun create(roomMember: RoomMember): RoomMemberDetailsPresenter {
|
override fun create(roomMember: RoomMember): RoomMemberDetailsPresenter {
|
||||||
return RoomMemberDetailsPresenter(matrixClient.sessionId, room, roomMember)
|
return RoomMemberDetailsPresenter(matrixClient, room, roomMember)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsState.ConfirmationDialog
|
import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsState.ConfirmationDialog
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
import io.element.android.libraries.matrix.api.core.SessionId
|
import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
import io.element.android.libraries.matrix.api.core.UserId
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||||
|
|
@ -36,7 +37,7 @@ import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class RoomMemberDetailsPresenter @AssistedInject constructor(
|
class RoomMemberDetailsPresenter @AssistedInject constructor(
|
||||||
private val currentUserSessionId: SessionId,
|
private val client: MatrixClient,
|
||||||
private val room: MatrixRoom,
|
private val room: MatrixRoom,
|
||||||
@Assisted private val roomMember: RoomMember,
|
@Assisted private val roomMember: RoomMember,
|
||||||
) : Presenter<RoomMemberDetailsState> {
|
) : Presenter<RoomMemberDetailsState> {
|
||||||
|
|
@ -91,16 +92,16 @@ class RoomMemberDetailsPresenter @AssistedInject constructor(
|
||||||
avatarUrl = userAvatar,
|
avatarUrl = userAvatar,
|
||||||
isBlocked = isBlocked.value,
|
isBlocked = isBlocked.value,
|
||||||
displayConfirmationDialog = confirmationDialog,
|
displayConfirmationDialog = confirmationDialog,
|
||||||
isCurrentUser = roomMember.userId == currentUserSessionId,
|
isCurrentUser = roomMember.userId == client.sessionId,
|
||||||
eventSink = ::handleEvents
|
eventSink = ::handleEvents
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun CoroutineScope.blockUser(userId: UserId, isBlockedState: MutableState<Boolean>) = launch {
|
private fun CoroutineScope.blockUser(userId: UserId, isBlockedState: MutableState<Boolean>) = launch {
|
||||||
room.ignoreUser(userId).onSuccess { isBlockedState.value = true }
|
client.ignoreUser(userId).onSuccess { isBlockedState.value = true }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun CoroutineScope.unblockUser(userId: UserId, isBlockedState: MutableState<Boolean>) = launch {
|
private fun CoroutineScope.unblockUser(userId: UserId, isBlockedState: MutableState<Boolean>) = launch {
|
||||||
room.unignoreUser(userId).onSuccess { isBlockedState.value = false }
|
client.unignoreUser(userId).onSuccess { isBlockedState.value = false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import io.element.android.features.roomdetails.impl.RoomDetailsType
|
||||||
import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsPresenter
|
import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsPresenter
|
||||||
import io.element.android.libraries.architecture.Async
|
import io.element.android.libraries.architecture.Async
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
|
import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
import io.element.android.libraries.matrix.api.core.UserId
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||||
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
|
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
|
||||||
|
|
@ -39,6 +40,7 @@ import io.element.android.libraries.matrix.test.A_ROOM_NAME
|
||||||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||||
import io.element.android.libraries.matrix.test.A_USER_ID
|
import io.element.android.libraries.matrix.test.A_USER_ID
|
||||||
import io.element.android.libraries.matrix.test.A_USER_ID_2
|
import io.element.android.libraries.matrix.test.A_USER_ID_2
|
||||||
|
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
|
@ -57,7 +59,7 @@ class RoomDetailsPresenterTests {
|
||||||
private fun aRoomDetailsPresenter(room: MatrixRoom): RoomDetailsPresenter {
|
private fun aRoomDetailsPresenter(room: MatrixRoom): RoomDetailsPresenter {
|
||||||
val roomMemberDetailsPresenterFactory = object : RoomMemberDetailsPresenter.Factory {
|
val roomMemberDetailsPresenterFactory = object : RoomMemberDetailsPresenter.Factory {
|
||||||
override fun create(roomMember: RoomMember): RoomMemberDetailsPresenter {
|
override fun create(roomMember: RoomMember): RoomMemberDetailsPresenter {
|
||||||
return RoomMemberDetailsPresenter(A_SESSION_ID, room, roomMember)
|
return RoomMemberDetailsPresenter(aMatrixClient(), room, roomMember)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return RoomDetailsPresenter(room, roomMembershipObserver, testCoroutineDispatchers, roomMemberDetailsPresenterFactory)
|
return RoomDetailsPresenter(room, roomMembershipObserver, testCoroutineDispatchers, roomMemberDetailsPresenterFactory)
|
||||||
|
|
@ -240,6 +242,10 @@ class RoomDetailsPresenterTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun aMatrixClient(
|
||||||
|
sessionId: SessionId = A_SESSION_ID,
|
||||||
|
) = FakeMatrixClient()
|
||||||
|
|
||||||
fun aMatrixRoom(
|
fun aMatrixRoom(
|
||||||
roomId: RoomId = A_ROOM_ID,
|
roomId: RoomId = A_ROOM_ID,
|
||||||
name: String? = A_ROOM_NAME,
|
name: String? = A_ROOM_NAME,
|
||||||
|
|
|
||||||
|
|
@ -20,12 +20,12 @@ import app.cash.molecule.RecompositionClock
|
||||||
import app.cash.molecule.moleculeFlow
|
import app.cash.molecule.moleculeFlow
|
||||||
import app.cash.turbine.test
|
import app.cash.turbine.test
|
||||||
import com.google.common.truth.Truth
|
import com.google.common.truth.Truth
|
||||||
|
import io.element.android.features.roomdetails.aMatrixClient
|
||||||
import io.element.android.features.roomdetails.aMatrixRoom
|
import io.element.android.features.roomdetails.aMatrixRoom
|
||||||
import io.element.android.features.roomdetails.aRoomMember
|
import io.element.android.features.roomdetails.aRoomMember
|
||||||
import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsEvents
|
import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsEvents
|
||||||
import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsPresenter
|
import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsPresenter
|
||||||
import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsState
|
import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsState
|
||||||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
@ -33,6 +33,8 @@ import org.junit.Test
|
||||||
@ExperimentalCoroutinesApi
|
@ExperimentalCoroutinesApi
|
||||||
class RoomMemberDetailsPresenterTests {
|
class RoomMemberDetailsPresenterTests {
|
||||||
|
|
||||||
|
private val matrixClient = aMatrixClient()
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - returns the room member's data, then updates it if needed`() = runTest {
|
fun `present - returns the room member's data, then updates it if needed`() = runTest {
|
||||||
val room = aMatrixRoom().apply {
|
val room = aMatrixRoom().apply {
|
||||||
|
|
@ -40,7 +42,7 @@ class RoomMemberDetailsPresenterTests {
|
||||||
givenUserAvatarUrlResult(Result.success("A custom avatar"))
|
givenUserAvatarUrlResult(Result.success("A custom avatar"))
|
||||||
}
|
}
|
||||||
val roomMember = aRoomMember(displayName = "Alice")
|
val roomMember = aRoomMember(displayName = "Alice")
|
||||||
val presenter = RoomMemberDetailsPresenter(A_SESSION_ID, room, roomMember)
|
val presenter = RoomMemberDetailsPresenter(matrixClient, room, roomMember)
|
||||||
moleculeFlow(RecompositionClock.Immediate) {
|
moleculeFlow(RecompositionClock.Immediate) {
|
||||||
presenter.present()
|
presenter.present()
|
||||||
}.test {
|
}.test {
|
||||||
|
|
@ -63,7 +65,7 @@ class RoomMemberDetailsPresenterTests {
|
||||||
givenUserAvatarUrlResult(Result.failure(Throwable()))
|
givenUserAvatarUrlResult(Result.failure(Throwable()))
|
||||||
}
|
}
|
||||||
val roomMember = aRoomMember(displayName = "Alice")
|
val roomMember = aRoomMember(displayName = "Alice")
|
||||||
val presenter = RoomMemberDetailsPresenter(A_SESSION_ID, room, roomMember)
|
val presenter = RoomMemberDetailsPresenter(matrixClient, room, roomMember)
|
||||||
moleculeFlow(RecompositionClock.Immediate) {
|
moleculeFlow(RecompositionClock.Immediate) {
|
||||||
presenter.present()
|
presenter.present()
|
||||||
}.test {
|
}.test {
|
||||||
|
|
@ -82,7 +84,7 @@ class RoomMemberDetailsPresenterTests {
|
||||||
givenUserAvatarUrlResult(Result.success(null))
|
givenUserAvatarUrlResult(Result.success(null))
|
||||||
}
|
}
|
||||||
val roomMember = aRoomMember(displayName = "Alice")
|
val roomMember = aRoomMember(displayName = "Alice")
|
||||||
val presenter = RoomMemberDetailsPresenter(A_SESSION_ID, room, roomMember)
|
val presenter = RoomMemberDetailsPresenter(matrixClient, room, roomMember)
|
||||||
moleculeFlow(RecompositionClock.Immediate) {
|
moleculeFlow(RecompositionClock.Immediate) {
|
||||||
presenter.present()
|
presenter.present()
|
||||||
}.test {
|
}.test {
|
||||||
|
|
@ -98,7 +100,7 @@ class RoomMemberDetailsPresenterTests {
|
||||||
fun `present - BlockUser needing confirmation displays confirmation dialog`() = runTest {
|
fun `present - BlockUser needing confirmation displays confirmation dialog`() = runTest {
|
||||||
val room = aMatrixRoom()
|
val room = aMatrixRoom()
|
||||||
val roomMember = aRoomMember()
|
val roomMember = aRoomMember()
|
||||||
val presenter = RoomMemberDetailsPresenter(A_SESSION_ID, room, roomMember)
|
val presenter = RoomMemberDetailsPresenter(matrixClient, room, roomMember)
|
||||||
moleculeFlow(RecompositionClock.Immediate) {
|
moleculeFlow(RecompositionClock.Immediate) {
|
||||||
presenter.present()
|
presenter.present()
|
||||||
}.test {
|
}.test {
|
||||||
|
|
@ -119,7 +121,7 @@ class RoomMemberDetailsPresenterTests {
|
||||||
fun `present - BlockUser and UnblockUser without confirmation change the 'blocked' state`() = runTest {
|
fun `present - BlockUser and UnblockUser without confirmation change the 'blocked' state`() = runTest {
|
||||||
val room = aMatrixRoom()
|
val room = aMatrixRoom()
|
||||||
val roomMember = aRoomMember()
|
val roomMember = aRoomMember()
|
||||||
val presenter = RoomMemberDetailsPresenter(A_SESSION_ID, room, roomMember)
|
val presenter = RoomMemberDetailsPresenter(matrixClient, room, roomMember)
|
||||||
moleculeFlow(RecompositionClock.Immediate) {
|
moleculeFlow(RecompositionClock.Immediate) {
|
||||||
presenter.present()
|
presenter.present()
|
||||||
}.test {
|
}.test {
|
||||||
|
|
@ -136,7 +138,7 @@ class RoomMemberDetailsPresenterTests {
|
||||||
fun `present - UnblockUser needing confirmation displays confirmation dialog`() = runTest {
|
fun `present - UnblockUser needing confirmation displays confirmation dialog`() = runTest {
|
||||||
val room = aMatrixRoom()
|
val room = aMatrixRoom()
|
||||||
val roomMember = aRoomMember()
|
val roomMember = aRoomMember()
|
||||||
val presenter = RoomMemberDetailsPresenter(A_SESSION_ID, room, roomMember)
|
val presenter = RoomMemberDetailsPresenter(matrixClient, room, roomMember)
|
||||||
moleculeFlow(RecompositionClock.Immediate) {
|
moleculeFlow(RecompositionClock.Immediate) {
|
||||||
presenter.present()
|
presenter.present()
|
||||||
}.test {
|
}.test {
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,8 @@ interface MatrixClient : Closeable {
|
||||||
val invitesDataSource: RoomSummaryDataSource
|
val invitesDataSource: RoomSummaryDataSource
|
||||||
fun getRoom(roomId: RoomId): MatrixRoom?
|
fun getRoom(roomId: RoomId): MatrixRoom?
|
||||||
fun findDM(userId: UserId): MatrixRoom?
|
fun findDM(userId: UserId): MatrixRoom?
|
||||||
|
suspend fun ignoreUser(userId: UserId): Result<Unit>
|
||||||
|
suspend fun unignoreUser(userId: UserId): Result<Unit>
|
||||||
suspend fun createRoom(createRoomParams: CreateRoomParameters): Result<RoomId>
|
suspend fun createRoom(createRoomParams: CreateRoomParameters): Result<RoomId>
|
||||||
suspend fun createDM(userId: UserId): Result<RoomId>
|
suspend fun createDM(userId: UserId): Result<RoomId>
|
||||||
fun startSync()
|
fun startSync()
|
||||||
|
|
|
||||||
|
|
@ -68,10 +68,6 @@ interface MatrixRoom : Closeable {
|
||||||
|
|
||||||
suspend fun redactEvent(eventId: EventId, reason: String? = null): Result<Unit>
|
suspend fun redactEvent(eventId: EventId, reason: String? = null): Result<Unit>
|
||||||
|
|
||||||
suspend fun ignoreUser(userId: UserId): Result<Unit>
|
|
||||||
|
|
||||||
suspend fun unignoreUser(userId: UserId): Result<Unit>
|
|
||||||
|
|
||||||
suspend fun leave(): Result<Unit>
|
suspend fun leave(): Result<Unit>
|
||||||
|
|
||||||
suspend fun acceptInvitation(): Result<Unit>
|
suspend fun acceptInvitation(): Result<Unit>
|
||||||
|
|
|
||||||
|
|
@ -212,6 +212,18 @@ class RustMatrixClient constructor(
|
||||||
return roomId?.let { getRoom(it) }
|
return roomId?.let { getRoom(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun ignoreUser(userId: UserId): Result<Unit> = withContext(dispatchers.io) {
|
||||||
|
runCatching {
|
||||||
|
client.ignoreUser(userId.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun unignoreUser(userId: UserId): Result<Unit> = withContext(dispatchers.io) {
|
||||||
|
runCatching {
|
||||||
|
client.unignoreUser(userId.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun createRoom(createRoomParams: CreateRoomParameters): Result<RoomId> = withContext(dispatchers.io) {
|
override suspend fun createRoom(createRoomParams: CreateRoomParameters): Result<RoomId> = withContext(dispatchers.io) {
|
||||||
runCatching {
|
runCatching {
|
||||||
val rustParams = RustCreateRoomParameters(
|
val rustParams = RustCreateRoomParameters(
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ import org.matrix.rustcomponents.sdk.SlidingSyncRoom
|
||||||
import org.matrix.rustcomponents.sdk.UpdateSummary
|
import org.matrix.rustcomponents.sdk.UpdateSummary
|
||||||
import org.matrix.rustcomponents.sdk.genTransactionId
|
import org.matrix.rustcomponents.sdk.genTransactionId
|
||||||
import org.matrix.rustcomponents.sdk.messageEventContentFromMarkdown
|
import org.matrix.rustcomponents.sdk.messageEventContentFromMarkdown
|
||||||
|
import org.matrix.rustcomponents.sdk.use
|
||||||
import org.matrix.rustcomponents.sdk.RoomMember as RustRoomMember
|
import org.matrix.rustcomponents.sdk.RoomMember as RustRoomMember
|
||||||
|
|
||||||
class RustMatrixRoom(
|
class RustMatrixRoom(
|
||||||
|
|
@ -200,19 +201,10 @@ class RustMatrixRoom(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun ignoreUser(userId: UserId): Result<Unit> {
|
private fun findRoomMember(userId: UserId, action: (RustRoomMember).() -> Unit) {
|
||||||
return runCatching {
|
return innerRoom.members()
|
||||||
getRustMember(userId)?.ignore() ?: error("No member with userId $userId exists in room $roomId")
|
.find { it.userId() == userId.value }
|
||||||
}
|
?.use(action)
|
||||||
}
|
?: error("No member with userId $userId exists in room $roomId")
|
||||||
|
|
||||||
override suspend fun unignoreUser(userId: UserId): Result<Unit> {
|
|
||||||
return runCatching {
|
|
||||||
getRustMember(userId)?.unignore() ?: error("No member with userId $userId exists in room $roomId")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getRustMember(userId: UserId): RustRoomMember? {
|
|
||||||
return innerRoom.members().find { it.userId() == userId.value }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,8 @@ class FakeMatrixClient(
|
||||||
private val notificationService: FakeNotificationService = FakeNotificationService(),
|
private val notificationService: FakeNotificationService = FakeNotificationService(),
|
||||||
) : MatrixClient {
|
) : MatrixClient {
|
||||||
|
|
||||||
|
private var ignoreUserResult: Result<Unit> = Result.success(Unit)
|
||||||
|
private var unignoreUserResult: Result<Unit> = Result.success(Unit)
|
||||||
private var createRoomResult: Result<RoomId> = Result.success(A_ROOM_ID)
|
private var createRoomResult: Result<RoomId> = Result.success(A_ROOM_ID)
|
||||||
private var createDmResult: Result<RoomId> = Result.success(A_ROOM_ID)
|
private var createDmResult: Result<RoomId> = Result.success(A_ROOM_ID)
|
||||||
private var createDmFailure: Throwable? = null
|
private var createDmFailure: Throwable? = null
|
||||||
|
|
@ -62,6 +64,14 @@ class FakeMatrixClient(
|
||||||
return findDmResult
|
return findDmResult
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun ignoreUser(userId: UserId): Result<Unit> {
|
||||||
|
return ignoreUserResult
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun unignoreUser(userId: UserId): Result<Unit> {
|
||||||
|
return unignoreUserResult
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun createRoom(createRoomParams: CreateRoomParameters): Result<RoomId> {
|
override suspend fun createRoom(createRoomParams: CreateRoomParameters): Result<RoomId> {
|
||||||
delay(100)
|
delay(100)
|
||||||
return createRoomResult
|
return createRoomResult
|
||||||
|
|
@ -130,6 +140,14 @@ class FakeMatrixClient(
|
||||||
createDmResult = result
|
createDmResult = result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun givenIgnoreUserResult(result: Result<Unit>) {
|
||||||
|
ignoreUserResult = result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun givenUnignoreUserResult(result: Result<Unit>) {
|
||||||
|
unignoreUserResult = result
|
||||||
|
}
|
||||||
|
|
||||||
fun givenCreateDmError(failure: Throwable?) {
|
fun givenCreateDmError(failure: Throwable?) {
|
||||||
createDmFailure = failure
|
createDmFailure = failure
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -117,10 +117,6 @@ class FakeMatrixRoom(
|
||||||
return Result.success(Unit)
|
return Result.success(Unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun ignoreUser(userId: UserId): Result<Unit> = ignoreResult
|
|
||||||
|
|
||||||
override suspend fun unignoreUser(userId: UserId): Result<Unit> = unignoreResult
|
|
||||||
|
|
||||||
override suspend fun leave(): Result<Unit> = leaveRoomError?.let { Result.failure(it) } ?: Result.success(Unit)
|
override suspend fun leave(): Result<Unit> = leaveRoomError?.let { Result.failure(it) } ?: Result.success(Unit)
|
||||||
override suspend fun acceptInvitation(): Result<Unit> {
|
override suspend fun acceptInvitation(): Result<Unit> {
|
||||||
isInviteAccepted = true
|
isInviteAccepted = true
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue