feat: [DEEPLINK] add history (#248)

Co-authored-by: Florent Champigny <florent@bere.al>
This commit is contained in:
Florent CHAMPIGNY 2025-09-16 20:49:58 +02:00 committed by GitHub
parent 05045ef0b4
commit e52f5c1687
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 332 additions and 24 deletions

View file

@ -9,4 +9,21 @@ interface DeeplinkLocalDataSource {
suspend fun update(deviceIdAndPackageNameDomainModel: DeviceIdAndPackageNameDomainModel, deeplinks: List<DeeplinkDomainModel>)
fun observe(deviceIdAndPackageNameDomainModel: DeviceIdAndPackageNameDomainModel): Flow<List<DeeplinkDomainModel>>
fun observeHistory(deviceIdAndPackageNameDomainModel: DeviceIdAndPackageNameDomainModel): Flow<List<DeeplinkDomainModel>>
suspend fun addToHistory(
deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel,
item: DeeplinkDomainModel
)
suspend fun removeFromHistory(
deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel,
deeplinkId: Long,
)
suspend fun getDeeplinkById(
deeplinkId: Long,
deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel
): DeeplinkDomainModel?
}

View file

@ -11,6 +11,7 @@ import io.github.openflocon.domain.messages.models.FloconIncomingMessageDomainMo
import io.github.openflocon.domain.messages.repository.MessagesReceiverRepository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.withContext
class DeeplinkRepositoryImpl(
private val localDeeplinkDataSource: DeeplinkLocalDataSource,
@ -46,4 +47,40 @@ class DeeplinkRepositoryImpl(
override fun observe(deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel): Flow<List<DeeplinkDomainModel>> = localDeeplinkDataSource.observe(deviceIdAndPackageName)
.flowOn(dispatcherProvider.data)
override suspend fun getDeeplinkById(
deeplinkId: Long,
deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel
): DeeplinkDomainModel? {
return withContext(dispatcherProvider.data) {
localDeeplinkDataSource.getDeeplinkById(deeplinkId, deviceIdAndPackageName)
}
}
override fun observeHistory(deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel): Flow<List<DeeplinkDomainModel>> = localDeeplinkDataSource.observeHistory(deviceIdAndPackageName)
.flowOn(dispatcherProvider.data)
override suspend fun addToHistory(
item: DeeplinkDomainModel,
deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel
) {
withContext(dispatcherProvider.data) {
localDeeplinkDataSource.addToHistory(
deviceIdAndPackageName = deviceIdAndPackageName,
item = item,
)
}
}
override suspend fun removeFromHistory(
deeplinkId: Long,
deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel
) {
withContext(dispatcherProvider.data) {
localDeeplinkDataSource.removeFromHistory(
deviceIdAndPackageName = deviceIdAndPackageName,
deeplinkId = deeplinkId
)
}
}
}

View file

@ -1,11 +1,13 @@
package io.github.openflocon.data.local.deeplink.dao
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import io.github.openflocon.data.local.deeplink.models.DeeplinkEntity
import io.github.openflocon.domain.device.models.AppPackageName
import io.github.openflocon.domain.device.models.DeviceId
import kotlinx.coroutines.flow.Flow
@ -20,6 +22,7 @@ interface FloconDeeplinkDao {
DELETE FROM DeeplinkEntity
WHERE deviceId = :deviceId
AND packageName = :packageName
AND isHistory = false
""",
)
suspend fun deleteAll(deviceId: String, packageName: String)
@ -40,8 +43,45 @@ interface FloconDeeplinkDao {
FROM DeeplinkEntity
WHERE deviceId = :deviceId
AND packageName = :packageName
AND isHistory = false
ORDER BY id ASC
""",
)
fun observeAll(deviceId: String, packageName: String): Flow<List<DeeplinkEntity>>
@Query(
"""
SELECT *
FROM DeeplinkEntity
WHERE deviceId = :deviceId
AND packageName = :packageName
AND isHistory = true
ORDER BY id DESC
""",
)
fun observeHistory(deviceId: String, packageName: String): Flow<List<DeeplinkEntity>>
@Query(
"""
DELETE
FROM DeeplinkEntity
WHERE deviceId = :deviceId
AND id = :deeplinkId
AND packageName = :packageName
AND isHistory = :isHistory
""",
)
suspend fun delete(deviceId: String, packageName: String, deeplinkId: Long, isHistory: Boolean)
@Query(
"""
SELECT *
FROM DeeplinkEntity
WHERE deviceId = :deviceId
AND packageName = :packageName
AND id = :deeplinkId
LIMIT 1
""",
)
suspend fun getById(deviceId: String, packageName: String, deeplinkId: Long) : DeeplinkEntity?
}

View file

@ -2,8 +2,10 @@ package io.github.openflocon.data.local.deeplink.datasource
import io.github.openflocon.data.core.deeplink.datasource.DeeplinkLocalDataSource
import io.github.openflocon.data.local.deeplink.dao.FloconDeeplinkDao
import io.github.openflocon.data.local.deeplink.mapper.toDomainModel
import io.github.openflocon.data.local.deeplink.mapper.toDomainModels
import io.github.openflocon.data.local.deeplink.mapper.toEntities
import io.github.openflocon.data.local.deeplink.mapper.toEntity
import io.github.openflocon.domain.deeplink.models.DeeplinkDomainModel
import io.github.openflocon.domain.device.models.DeviceIdAndPackageNameDomainModel
import kotlinx.coroutines.flow.Flow
@ -13,6 +15,7 @@ import kotlinx.coroutines.flow.map
internal class LocalDeeplinkDataSourceRoom(
private val deeplinkDao: FloconDeeplinkDao,
) : DeeplinkLocalDataSource {
override suspend fun update(deviceIdAndPackageNameDomainModel: DeviceIdAndPackageNameDomainModel, deeplinks: List<DeeplinkDomainModel>) {
deeplinkDao.updateAll(
deviceId = deviceIdAndPackageNameDomainModel.deviceId,
@ -31,4 +34,45 @@ internal class LocalDeeplinkDataSourceRoom(
)
.map { toDomainModels(it) }
.distinctUntilChanged()
override fun observeHistory(deviceIdAndPackageNameDomainModel: DeviceIdAndPackageNameDomainModel): Flow<List<DeeplinkDomainModel>> =
deeplinkDao.observeHistory(
deviceId = deviceIdAndPackageNameDomainModel.deviceId,
packageName = deviceIdAndPackageNameDomainModel.packageName,
)
.map { toDomainModels(it) }
.distinctUntilChanged()
override suspend fun addToHistory(
deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel,
item: DeeplinkDomainModel
) {
deeplinkDao.insert(deeplink = item.toEntity(
deviceIdAndPackageName = deviceIdAndPackageName,
isHistory = true,
))
}
override suspend fun removeFromHistory(
deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel,
deeplinkId: Long,
) {
deeplinkDao.delete(
deviceId = deviceIdAndPackageName.deviceId,
packageName = deviceIdAndPackageName.packageName,
deeplinkId = deeplinkId,
isHistory = true,
)
}
override suspend fun getDeeplinkById(
deeplinkId: Long,
deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel
): DeeplinkDomainModel? {
return deeplinkDao.getById(
deviceId = deviceIdAndPackageName.deviceId,
packageName = deviceIdAndPackageName.packageName,
deeplinkId = deeplinkId,
)?.toDomainModel()
}
}

View file

@ -8,10 +8,12 @@ fun DeeplinkEntity.toDomainModel(): DeeplinkDomainModel = DeeplinkDomainModel(
label = this.label,
link = this.link,
description = this.description,
id = this.id,
)
fun DeeplinkDomainModel.toEntity(
deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel,
isHistory: Boolean,
): DeeplinkEntity {
// Note: L'ID sera généré automatiquement par Room lors de l'insertion,
// donc nous n'avons pas besoin de le spécifier ici si nous faisons une nouvelle insertion.
@ -22,6 +24,7 @@ fun DeeplinkDomainModel.toEntity(
label = label,
packageName = deviceIdAndPackageName.packageName,
description = description,
isHistory = isHistory,
)
}
@ -30,5 +33,5 @@ fun toDomainModels(entities: List<DeeplinkEntity>): List<DeeplinkDomainModel> =
fun toEntities(deviceIdAndPackageName: DeviceIdAndPackageNameDomainModel, deeplinks: List<DeeplinkDomainModel>): List<DeeplinkEntity> =
deeplinks.map {
it.toEntity(deviceIdAndPackageName = deviceIdAndPackageName)
it.toEntity(deviceIdAndPackageName = deviceIdAndPackageName, isHistory = false)
}

View file

@ -28,4 +28,5 @@ data class DeeplinkEntity(
val link: String,
val label: String?,
val description: String?,
val isHistory: Boolean,
)

View file

@ -13,5 +13,6 @@ internal fun DeeplinksReceivedDataModel.toDomain(): List<DeeplinkDomainModel> =
label = it.label,
link = it.link,
description = it.description,
id = 0, // will be created by the DB later
)
}