Skip to content

Commit

Permalink
Merge branch 'develop' into fix/interactive-cli
Browse files Browse the repository at this point in the history
  • Loading branch information
MohamadJaara authored Oct 22, 2024
2 parents d5c2218 + a2f0ead commit ef9672f
Show file tree
Hide file tree
Showing 96 changed files with 3,582 additions and 1,004 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -293,15 +293,11 @@ sealed class ConversationDetails(open val conversation: Conversation) {
override val conversation: Conversation,
val otherUser: OtherUser,
val userType: UserType,
val unreadEventCount: UnreadEventCount,
val lastMessage: MessagePreview?
) : ConversationDetails(conversation)

data class Group(
override val conversation: Conversation,
val hasOngoingCall: Boolean = false,
val unreadEventCount: UnreadEventCount,
val lastMessage: MessagePreview?,
val isSelfUserMember: Boolean,
val isSelfUserCreator: Boolean,
val selfRole: Conversation.Member.Role?
Expand Down Expand Up @@ -344,6 +340,13 @@ sealed class ConversationDetails(open val conversation: Conversation) {
)
}

data class ConversationDetailsWithEvents(
val conversationDetails: ConversationDetails,
val unreadEventCount: UnreadEventCount = emptyMap(),
val lastMessage: MessagePreview? = null,
val hasNewActivitiesToShow: Boolean = false,
)

fun ConversationDetails.interactionAvailability(): InteractionAvailability {
val availability = when (this) {
is ConversationDetails.Connection -> InteractionAvailability.DISABLED
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ completeKotlin = "1.1.0"
desugar-jdk = "2.0.4"
kermit = "2.0.3"
detekt = "1.23.6"
agp = "8.3.2"
agp = "8.5.2"
dokka = "1.8.20"
carthage = "0.0.1"
libsodiumBindings = "0.8.7"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Wire
* Copyright (C) 2024 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.kalium.logic.feature.conversation

val ConversationScope.getPaginatedFlowOfConversationDetailsWithEventsBySearchQuery
get() = GetPaginatedFlowOfConversationDetailsWithEventsBySearchQueryUseCase(dispatcher, conversationRepository)
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Wire
* Copyright (C) 2024 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.kalium.logic.feature.conversation

import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.wire.kalium.logic.data.conversation.ConversationDetailsWithEvents
import com.wire.kalium.logic.data.conversation.ConversationRepository
import com.wire.kalium.logic.data.conversation.ConversationQueryConfig
import com.wire.kalium.util.KaliumDispatcher
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOn

/**
* This use case will observe and return a flow of paginated searched conversation details with last message and unread events counts.
* @see PagingData
* @see ConversationDetailsWithEvents
*/
class GetPaginatedFlowOfConversationDetailsWithEventsBySearchQueryUseCase internal constructor(
private val dispatcher: KaliumDispatcher,
private val conversationRepository: ConversationRepository,
) {
suspend operator fun invoke(
queryConfig: ConversationQueryConfig,
pagingConfig: PagingConfig,
startingOffset: Long,
): Flow<PagingData<ConversationDetailsWithEvents>> = conversationRepository.extensions
.getPaginatedConversationDetailsWithEventsBySearchQuery(queryConfig, pagingConfig, startingOffset).flowOn(dispatcher.io)
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.buffer
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
Expand Down Expand Up @@ -70,6 +71,7 @@ internal actual class NetworkStateObserverImpl(
else networkData.networkCapabilities.toState()
} else NetworkState.NotConnected
}
.buffer(capacity = 0)
.stateIn(scope, SharingStarted.Eagerly, initialState)

val callback = object : ConnectivityManager.NetworkCallback() {
Expand Down Expand Up @@ -110,8 +112,17 @@ internal actual class NetworkStateObserverImpl(
override fun onBlockedStatusChanged(network: Network, blocked: Boolean) {
kaliumLogger.i("${NetworkStateObserver.TAG} block connection changed to $blocked")
defaultNetworkDataStateFlow.update {
if (it is DefaultNetworkData.Connected) it.copy(isBlocked = blocked)
else it
kaliumLogger.d("${NetworkStateObserver.TAG} block connection changed to $blocked current state is $it")
when (it) {
is DefaultNetworkData.Connected -> {
it.copy(isBlocked = blocked)
}

is DefaultNetworkData.NotConnected -> {
if (blocked) it
else DefaultNetworkData.Connected(network)
}
}
}
super.onBlockedStatusChanged(network, blocked)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Wire
* Copyright (C) 2024 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.kalium.logic.feature.conversation

import androidx.paging.PagingData
import app.cash.paging.PagingConfig
import com.wire.kalium.logic.data.conversation.ConversationDetailsWithEvents
import com.wire.kalium.logic.data.conversation.ConversationQueryConfig
import com.wire.kalium.logic.data.conversation.ConversationRepository
import com.wire.kalium.logic.data.conversation.ConversationRepositoryExtensions
import com.wire.kalium.logic.test_util.TestKaliumDispatcher
import io.mockative.Mock
import io.mockative.any
import io.mockative.coEvery
import io.mockative.coVerify
import io.mockative.every
import io.mockative.mock
import io.mockative.once
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.test.runTest
import org.junit.Test

class GetPaginatedFlowOfConversationDetailsWithEventsBySearchQueryUseCaseTest {
private val dispatcher = TestKaliumDispatcher

@Test
fun givenSearchQuery_whenGettingPaginatedList_thenCallUseCaseWithProperParams() = runTest(dispatcher.default) {
// Given
val (arrangement, useCase) = Arrangement().withPaginatedConversationResult(emptyFlow()).arrange()
with(arrangement) {
// When
useCase(queryConfig = queryConfig, pagingConfig = pagingConfig, startingOffset = startingOffset)
// Then
coVerify {
conversationRepository.extensions
.getPaginatedConversationDetailsWithEventsBySearchQuery(queryConfig, pagingConfig, startingOffset)
}.wasInvoked(exactly = once)
}
}

inner class Arrangement {
@Mock
val conversationRepository = mock(ConversationRepository::class)

@Mock
val conversationRepositoryExtensions = mock(ConversationRepositoryExtensions::class)

val queryConfig = ConversationQueryConfig("search")
val pagingConfig = PagingConfig(20)
val startingOffset = 0L

init {
every {
conversationRepository.extensions
}.returns(conversationRepositoryExtensions)
}

suspend fun withPaginatedConversationResult(result: Flow<PagingData<ConversationDetailsWithEvents>>) = apply {
coEvery {
conversationRepositoryExtensions.getPaginatedConversationDetailsWithEventsBySearchQuery(any(), any(), any())
}.returns(result)
}

fun arrange() = this to GetPaginatedFlowOfConversationDetailsWithEventsBySearchQueryUseCase(dispatcher, conversationRepository)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,21 @@ class NetworkStateObserverImplTest {
}
}

@Test
fun givenNetworkNotConnectedAndButBlocked_whenItChangesToNotBlocked_thenStateChangesToConnectedWithInternet() =
runTest(dispatcher.default) {
// given
val (arrangement, networkStateObserverImpl) = Arrangement()
.arrange()
// when-then
networkStateObserverImpl.observeNetworkState().test {
assertEquals(NetworkState.NotConnected, awaitItem())
arrangement.connectNetwork(networkType = NetworkType.MOBILE, setAsDefault = true, withInternetValidated = true)
arrangement.changeNetworkBlocked(networkType = NetworkType.MOBILE, false)
assertEquals(NetworkState.ConnectedWithInternet, awaitItem())
}
}

@Test
fun givenOneNetworkConnectedWithoutInternetValidated_whenItChangesToBlocked_thenStateDoesNotChange() = runTest(dispatcher.default) {
// given
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ import com.wire.kalium.logic.feature.call.usecase.GetCallConversationTypeProvide
import com.wire.kalium.logic.feature.message.MessageSender
import com.wire.kalium.logic.featureFlags.KaliumConfigs
import com.wire.kalium.logic.functional.fold
import com.wire.kalium.logic.util.ServerTimeHandler
import com.wire.kalium.logic.util.ServerTimeHandlerImpl
import com.wire.kalium.logic.util.toInt
import com.wire.kalium.network.NetworkStateObserver
import com.wire.kalium.util.KaliumDispatcher
Expand Down Expand Up @@ -119,6 +121,7 @@ class CallManagerImpl internal constructor(
private val flowManagerService: FlowManagerService,
private val json: Json = Json { ignoreUnknownKeys = true },
private val shouldRemoteMuteChecker: ShouldRemoteMuteChecker = ShouldRemoteMuteCheckerImpl(),
private val serverTimeHandler: ServerTimeHandler = ServerTimeHandlerImpl(),
kaliumDispatchers: KaliumDispatcher = KaliumDispatcherImpl
) : CallManager {

Expand Down Expand Up @@ -255,8 +258,6 @@ class CallManagerImpl internal constructor(
)

if (callingValue.type != REMOTE_MUTE_TYPE || shouldRemoteMute) {
val currTime = System.currentTimeMillis()

val targetConversationId = if (message.isSelfMessage) {
content.conversationId ?: message.conversationId
} else {
Expand All @@ -270,7 +271,7 @@ class CallManagerImpl internal constructor(
inst = deferredHandle.await(),
msg = msg,
len = msg.size,
curr_time = Uint32_t(value = currTime / 1000),
curr_time = Uint32_t(value = serverTimeHandler.toServerTimestamp()),
msg_time = Uint32_t(value = message.date.epochSeconds),
convId = federatedIdMapper.parseToFederatedId(targetConversationId),
userId = federatedIdMapper.parseToFederatedId(message.senderUserId),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,29 @@ interface ClientRepository {
suspend fun isClientRegistrationBlockedByE2EI(): Either<CoreFailure, Boolean>
suspend fun deleteClient(param: DeleteClientParam): Either<NetworkFailure, Unit>
suspend fun selfListOfClients(): Either<NetworkFailure, List<Client>>
suspend fun observeClientsByUserIdAndClientId(userId: UserId, clientId: ClientId): Flow<Either<StorageFailure, Client>>
suspend fun observeClientsByUserIdAndClientId(
userId: UserId,
clientId: ClientId
): Flow<Either<StorageFailure, Client>>

suspend fun storeUserClientListAndRemoveRedundantClients(clients: List<InsertClientParam>): Either<StorageFailure, Unit>
suspend fun storeUserClientIdList(userId: UserId, clients: List<ClientId>): Either<StorageFailure, Unit>
suspend fun storeUserClientIdList(
userId: UserId,
clients: List<ClientId>
): Either<StorageFailure, Unit>

suspend fun storeMapOfUserToClientId(userToClientMap: Map<UserId, List<ClientId>>): Either<StorageFailure, Unit>
suspend fun removeClientsAndReturnUsersWithNoClients(
redundantClientsOfUsers: Map<UserId, List<ClientId>>
): Either<StorageFailure, List<UserId>>

suspend fun registerToken(body: PushTokenBody): Either<NetworkFailure, Unit>
suspend fun registerToken(
senderId: String,
client: String,
token: String,
transport: String
): Either<NetworkFailure, Unit>

suspend fun deregisterToken(token: String): Either<NetworkFailure, Unit>
suspend fun getClientsByUserId(userId: UserId): Either<StorageFailure, List<OtherUserClient>>
suspend fun observeClientsByUserId(userId: UserId): Flow<Either<StorageFailure, List<Client>>>
Expand Down Expand Up @@ -205,7 +219,10 @@ class ClientDataSource(
}
}

override suspend fun observeClientsByUserIdAndClientId(userId: UserId, clientId: ClientId): Flow<Either<StorageFailure, Client>> =
override suspend fun observeClientsByUserIdAndClientId(
userId: UserId,
clientId: ClientId
): Flow<Either<StorageFailure, Client>> =
clientDAO.observeClient(userId.toDao(), clientId.value)
.map { it?.let { clientMapper.fromClientEntity(it) } }
.wrapStorageRequest()
Expand Down Expand Up @@ -250,18 +267,32 @@ class ClientDataSource(
redundantClientsOfUsers.mapKeys { it.key.toDao() }
.mapValues { it.value.map { clientId -> clientId.value } }
.let { redundantClientsOfUsersDao ->
wrapStorageRequest { clientDAO.removeClientsAndReturnUsersWithNoClients(redundantClientsOfUsersDao) }
wrapStorageRequest {
clientDAO.removeClientsAndReturnUsersWithNoClients(
redundantClientsOfUsersDao
)
}
.map {
it.map { userId -> userId.toModel() }
}
}

override suspend fun storeUserClientListAndRemoveRedundantClients(
clients: List<InsertClientParam>
): Either<StorageFailure, Unit> = wrapStorageRequest { clientDAO.insertClientsAndRemoveRedundant(clients) }

override suspend fun registerToken(body: PushTokenBody): Either<NetworkFailure, Unit> = clientRemoteRepository.registerToken(body)
override suspend fun deregisterToken(token: String): Either<NetworkFailure, Unit> = clientRemoteRepository.deregisterToken(token)
): Either<StorageFailure, Unit> =
wrapStorageRequest { clientDAO.insertClientsAndRemoveRedundant(clients) }

override suspend fun registerToken(
senderId: String,
client: String,
token: String,
transport: String
): Either<NetworkFailure, Unit> = clientRemoteRepository.registerToken(
PushTokenBody(senderId, client, token, transport)
)

override suspend fun deregisterToken(token: String): Either<NetworkFailure, Unit> =
clientRemoteRepository.deregisterToken(token)

override suspend fun getClientsByUserId(userId: UserId): Either<StorageFailure, List<OtherUserClient>> =
wrapStorageRequest {
Expand Down
Loading

0 comments on commit ef9672f

Please sign in to comment.