Skip to content

Commit 173963e

Browse files
authored
feat: Observe cells flags use cases (WPB-25214) (#4204)
* feat: use case to check viewer access for self user on a conversation * feat: cleanup * feat: cleanup * chore: address comment * feat: add use cases to observe cells flags
1 parent bf8924e commit 173963e

10 files changed

Lines changed: 108 additions & 2 deletions

File tree

data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/UserConfigDAO.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ interface UserConfigDAO {
7373
suspend fun getAsyncNotificationsEnabled(): Boolean
7474
suspend fun setCellsEnabled(enabled: Boolean)
7575
suspend fun isCellsEnabled(): Boolean
76+
suspend fun observeIsCellsEnabled(): Flow<Boolean>
7677
suspend fun setAppsEnabled(isAppsEnabled: Boolean)
7778
suspend fun getAppsEnabled(): Boolean
7879
fun observeAppsEnabled(): Flow<Boolean>
@@ -266,6 +267,9 @@ internal class UserConfigDAOImpl internal constructor(
266267
override suspend fun isCellsEnabled(): Boolean =
267268
metadataDAO.valueByKey(CELLS_ENABLED)?.toBoolean() ?: false
268269

270+
override suspend fun observeIsCellsEnabled(): Flow<Boolean> =
271+
metadataDAO.valueByKeyFlow(CELLS_ENABLED).map { it.toBoolean() }
272+
269273
override suspend fun setProfileQRCodeEnabled(enabled: Boolean) {
270274
metadataDAO.insertValue(enabled.toString(), PROFILE_QR_CODE_ENABLED)
271275
}

data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/conversation/ConversationDAO.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ interface ConversationDAO {
183183

184184
suspend fun getCellName(conversationId: QualifiedIDEntity): String?
185185
suspend fun hasConversationWithCell(): Boolean
186+
suspend fun observeHasConversationWithCell(): Flow<Boolean>
186187
suspend fun updateReadDateAndGetHasUnreadEvents(conversationID: QualifiedIDEntity, date: Instant): Boolean
187188
suspend fun updateReadDatesAndGetHasUnreadEvents(conversationDates: Map<QualifiedIDEntity, Instant>): Map<QualifiedIDEntity, Boolean>
188189
suspend fun getMLSConversationsByDomain(domain: String): List<ConversationEntity>

data/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/conversation/ConversationDAOImpl.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ package com.wire.kalium.persistence.dao.conversation
2121
import app.cash.sqldelight.async.coroutines.awaitAsList
2222
import app.cash.sqldelight.async.coroutines.awaitAsOne
2323
import app.cash.sqldelight.async.coroutines.awaitAsOneOrNull
24-
import app.cash.sqldelight.async.coroutines.await
25-
2624
import app.cash.sqldelight.coroutines.asFlow
2725
import com.wire.kalium.persistence.ConversationDetailsQueries
2826
import com.wire.kalium.persistence.ConversationDetailsWithEventsQueries
@@ -748,6 +746,11 @@ internal class ConversationDAOImpl internal constructor(
748746
conversationQueries.hasConversationWithCell().awaitAsOne()
749747
}
750748

749+
override suspend fun observeHasConversationWithCell(): Flow<Boolean> =
750+
conversationQueries.hasConversationWithCell().asFlow()
751+
.mapToOneOrDefault(false)
752+
.flowOn(readDispatcher.value)
753+
751754
override suspend fun updateReadDateAndGetHasUnreadEvents(
752755
conversationID: QualifiedIDEntity,
753756
date: Instant

domain/cells/src/commonMain/kotlin/com/wire/kalium/cells/CellsScope.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ import com.wire.kalium.cells.domain.usecase.GetConversationNameUseCase
131131
import com.wire.kalium.cells.domain.usecase.GetConversationNameUseCaseImpl
132132
import com.wire.kalium.cells.domain.usecase.GetUserNameUseCase
133133
import com.wire.kalium.cells.domain.usecase.GetUserNameUseCaseImpl
134+
import com.wire.kalium.cells.domain.usecase.ObserveIsAtLeastOneCellAvailableUseCase
135+
import com.wire.kalium.cells.domain.usecase.ObserveIsAtLeastOneCellAvailableUseCaseImpl
134136
import com.wire.kalium.cells.domain.usecase.offline.GetOfflineFileUseCase
135137
import com.wire.kalium.cells.domain.usecase.offline.GetOfflineFileUseCaseImpl
136138
import com.wire.kalium.cells.domain.usecase.offline.ObserveOfflineFilesUseCase
@@ -366,6 +368,9 @@ public class CellsScope(
366368
public val isCellAvailable: IsAtLeastOneCellAvailableUseCase by lazy {
367369
IsAtLeastOneCellAvailableUseCaseImpl(cellsConversationRepository)
368370
}
371+
public val observeIsCellAvailable: ObserveIsAtLeastOneCellAvailableUseCase by lazy {
372+
ObserveIsAtLeastOneCellAvailableUseCaseImpl(cellsConversationRepository)
373+
}
369374

370375
public val getMessageAttachmentUseCase: GetMessageAttachmentUseCase by lazy {
371376
GetMessageAttachmentUseCaseImpl(cellAttachmentsRepository)

domain/cells/src/commonMain/kotlin/com/wire/kalium/cells/data/CellConversationDataSource.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import com.wire.kalium.persistence.dao.conversation.ConversationDAO
3030
import com.wire.kalium.persistence.dao.conversation.ConversationEntity
3131
import com.wire.kalium.util.KaliumDispatcher
3232
import com.wire.kalium.util.KaliumDispatcherImpl
33+
import kotlinx.coroutines.flow.Flow
3334
import kotlinx.coroutines.flow.firstOrNull
3435
import kotlinx.coroutines.withContext
3536

@@ -72,6 +73,13 @@ internal class CellConversationDataSource(
7273
}
7374
}
7475

76+
override suspend fun observeHasConversationWithCell(): Either<StorageFailure, Flow<Boolean>> =
77+
withContext(dispatchers.io) {
78+
wrapStorageRequest {
79+
conversationDao.observeHasConversationWithCell()
80+
}
81+
}
82+
7583
override suspend fun getCellGroupConversations(): Either<StorageFailure, List<CellConversation>> =
7684
withContext(dispatchers.io) {
7785
wrapStorageRequest {

domain/cells/src/commonMain/kotlin/com/wire/kalium/cells/domain/CellConversationRepository.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@ import com.wire.kalium.cells.domain.model.CellConversation
2121
import com.wire.kalium.common.error.StorageFailure
2222
import com.wire.kalium.common.functional.Either
2323
import com.wire.kalium.persistence.dao.QualifiedIDEntity
24+
import kotlinx.coroutines.flow.Flow
2425

2526
internal interface CellConversationRepository {
2627
suspend fun getCellName(conversationId: QualifiedIDEntity): Either<StorageFailure, String?>
2728
suspend fun getConversationNames(): Either<StorageFailure, List<Pair<String, String>>>
2829
suspend fun getConversationNameById(conversationId: String): Either<StorageFailure, String?>
2930
suspend fun hasConversationWithCell(): Either<StorageFailure, Boolean>
31+
suspend fun observeHasConversationWithCell(): Either<StorageFailure, Flow<Boolean>>
3032
suspend fun getCellGroupConversations(): Either<StorageFailure, List<CellConversation>>
3133
suspend fun getPaginatedCellGroupConversations(
3234
limit: Int,
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Wire
3+
* Copyright (C) 2026 Wire Swiss GmbH
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see http://www.gnu.org/licenses/.
17+
*/
18+
package com.wire.kalium.cells.domain.usecase
19+
20+
import com.wire.kalium.cells.domain.CellConversationRepository
21+
import com.wire.kalium.common.error.StorageFailure
22+
import com.wire.kalium.common.functional.Either
23+
import kotlinx.coroutines.flow.Flow
24+
25+
/**
26+
* Use case to observe if there is at least one conversation available with cell feature enabled.
27+
* This is required to determine if we can call Cell API methods without getting a Not Authenticated error.
28+
*/
29+
public interface ObserveIsAtLeastOneCellAvailableUseCase {
30+
public suspend operator fun invoke(): Either<StorageFailure, Flow<Boolean>>
31+
}
32+
33+
internal class ObserveIsAtLeastOneCellAvailableUseCaseImpl(
34+
private val conversationRepository: CellConversationRepository
35+
) : ObserveIsAtLeastOneCellAvailableUseCase {
36+
37+
override suspend fun invoke(): Either<StorageFailure, Flow<Boolean>> = conversationRepository.observeHasConversationWithCell()
38+
}

logic/src/commonMain/kotlin/com/wire/kalium/logic/configuration/UserConfigRepository.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ internal interface UserConfigRepository {
156156
suspend fun isAsyncNotificationsEnabled(): Boolean
157157
suspend fun setCellsEnabled(enabled: Boolean): Either<StorageFailure, Unit>
158158
suspend fun isCellsEnabled(): Boolean
159+
suspend fun observeIsCellsEnabled(): Flow<Boolean>
159160
suspend fun setAppsEnabled(isAppsEnabled: Boolean): Either<StorageFailure, Unit>
160161
suspend fun isAppsEnabled(): Boolean
161162
fun observeAppsEnabled(): Flow<Either<StorageFailure, Boolean>>
@@ -584,6 +585,8 @@ internal class UserConfigDataSource internal constructor(
584585

585586
override suspend fun isCellsEnabled(): Boolean = userConfigDAO.isCellsEnabled()
586587

588+
override suspend fun observeIsCellsEnabled(): Flow<Boolean> = userConfigDAO.observeIsCellsEnabled()
589+
587590
override suspend fun setAppsEnabled(isAppsEnabled: Boolean): Either<StorageFailure, Unit> =
588591
wrapStorageRequest {
589592
userConfigDAO.setAppsEnabled(isAppsEnabled)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Wire
3+
* Copyright (C) 2026 Wire Swiss GmbH
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see http://www.gnu.org/licenses/.
17+
*/
18+
package com.wire.kalium.logic.feature.client
19+
20+
import com.wire.kalium.logic.configuration.UserConfigRepository
21+
import kotlinx.coroutines.flow.Flow
22+
23+
/**
24+
* Use case to observe if Wire Cells feature is enabled.
25+
*/
26+
public interface ObserveIsWireCellsEnabledUseCase {
27+
public suspend operator fun invoke(): Flow<Boolean>
28+
}
29+
30+
internal class ObserveIsWireCellsEnabledUseCaseImpl(
31+
private val userConfigRepository: UserConfigRepository,
32+
) : ObserveIsWireCellsEnabledUseCase {
33+
override suspend fun invoke(): Flow<Boolean> = userConfigRepository.observeIsCellsEnabled()
34+
}

logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/user/UserScope.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ import com.wire.kalium.logic.feature.client.IsWireCellsEnabledForConversationUse
6262
import com.wire.kalium.logic.feature.client.IsWireCellsEnabledUseCase
6363
import com.wire.kalium.logic.feature.client.IsWireCellsEnabledUseCaseImpl
6464
import com.wire.kalium.logic.feature.client.MLSClientManager
65+
import com.wire.kalium.logic.feature.client.ObserveIsWireCellsEnabledUseCase
66+
import com.wire.kalium.logic.feature.client.ObserveIsWireCellsEnabledUseCaseImpl
6567
import com.wire.kalium.logic.feature.client.RegisterMLSClientUseCase
6668
import com.wire.kalium.logic.feature.conversation.GetAllContactsNotInConversationUseCase
6769
import com.wire.kalium.logic.feature.conversation.keyingmaterials.KeyingMaterialsManager
@@ -301,6 +303,12 @@ public class UserScope internal constructor(
301303
get() = IsWireCellsEnabledUseCaseImpl(
302304
userConfigRepository = userConfigRepository,
303305
)
306+
307+
public val observeIsWireCellsEnabled: ObserveIsWireCellsEnabledUseCase
308+
get() = ObserveIsWireCellsEnabledUseCaseImpl(
309+
userConfigRepository = userConfigRepository,
310+
)
311+
304312
public val isWireCellsEnabledForConversation: IsWireCellsEnabledForConversationUseCase
305313
get() = IsWireCellsEnabledForConversationUseCaseImpl(
306314
conversationRepository = conversationRepository

0 commit comments

Comments
 (0)