Skip to content

Commit

Permalink
kmp UI locker apps/watchfaces, images, http cache
Browse files Browse the repository at this point in the history
  • Loading branch information
crc-32 committed Sep 18, 2024
1 parent 7fc8b40 commit aa86384
Show file tree
Hide file tree
Showing 21 changed files with 389 additions and 231 deletions.
9 changes: 1 addition & 8 deletions android/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,12 @@ room = "2.7.0-alpha07"
room-sqlite = "2.5.0-alpha07"
datastore = "1.1.1"
uuidVersion = "0.8.4"
compose-lib = "1.6.11"
compose-lib = "1.7.0-beta02"
compose-nav = "2.7.0-alpha07"
compose-viewmodel = "2.8.0"
compose-material3 = "1.3.0"
reorderable = "2.3.3"

appcompat = "1.7.0"
material3Android = "1.3.0"

ktorVersion = "2.3.12"

[plugins]
Expand Down Expand Up @@ -76,10 +73,6 @@ ktor-client-contentnegotiation = { module = "io.ktor:ktor-client-content-negotia
ktor-serialization-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktorVersion" }
ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktorVersion" }

compose-runtime = { module = "org.jetbrains.compose.runtime:runtime", version.ref = "compose-lib" }
compose-ui = { module = "org.jetbrains.compose.ui:ui", version.ref = "compose-lib" }
compose-material = { module = "org.jetbrains.compose.material3:material3", version.ref = "compose-material3" }
compose-foundation = { module = "org.jetbrains.compose.foundation:foundation", version.ref = "compose-lib" }
compose-navigation = { module = "org.jetbrains.androidx.navigation:navigation-compose", version.ref = "compose-nav" }
compose-viewmodel = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "compose-viewmodel" }
compose-components-resources = { module = "org.jetbrains.compose.components:components-resources", version.ref = "compose-lib" }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.rebble.cobble.shared.di

import io.ktor.client.plugins.cache.storage.CacheStorage
import io.ktor.client.plugins.cache.storage.FileStorage
import io.rebble.cobble.shared.AndroidPlatformContext
import io.rebble.cobble.shared.PlatformContext

actual fun makePlatformCacheStorage(platformContext: PlatformContext): CacheStorage {
val dir = (platformContext as AndroidPlatformContext).applicationContext.cacheDir.resolve("http_cache")
dir.mkdir()
return FileStorage(dir)
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,15 @@ import org.koin.mp.KoinPlatformTools
SyncedLockerEntry::class,
SyncedLockerEntryPlatform::class
],
version = 7,
version = 8,
autoMigrations = [
AutoMigration(1, 2),
AutoMigration(2, 3),
AutoMigration(3, 4),
AutoMigration(4, 5),
AutoMigration(5, 6),
AutoMigration(6, 7)
AutoMigration(6, 7),
AutoMigration(7, 8),
]
)
@TypeConverters(Converters::class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import io.rebble.cobble.shared.database.NextSyncAction
import io.rebble.cobble.shared.database.entity.SyncedLockerEntry
import io.rebble.cobble.shared.database.entity.SyncedLockerEntryPlatform
import io.rebble.cobble.shared.database.entity.SyncedLockerEntryWithPlatforms
import kotlinx.coroutines.flow.Flow

@Dao
interface LockerDao {
Expand All @@ -28,6 +29,10 @@ interface LockerDao {
@Query("SELECT * FROM SyncedLockerEntry ORDER BY `order`")
suspend fun getAllEntries(): List<SyncedLockerEntryWithPlatforms>

@Transaction
@Query("SELECT * FROM SyncedLockerEntry ORDER BY `order`")
fun getAllEntriesFlow(): Flow<List<SyncedLockerEntryWithPlatforms>>

@Query("DELETE FROM SyncedLockerEntryPlatform WHERE lockerEntryId = :entryId")
suspend fun clearPlatformsFor(entryId: String)

Expand All @@ -47,4 +52,7 @@ interface LockerDao {

@Query("UPDATE SyncedLockerEntry SET `order` = :order WHERE id = :id")
suspend fun updateOrder(id: String, order: Int)

@Query("DELETE FROM SyncedLockerEntry")
suspend fun clearAll()
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,14 @@ data class SyncedLockerEntryPlatform(
val processInfoFlags: Int,
val name: String,
val description: String,
val icon: String,
@Embedded
val images: SyncedLockerEntryPlatformImages,
)

data class SyncedLockerEntryPlatformImages(
val icon: String?,
val list: String?,
val screenshot: String?,
)

/**
Expand All @@ -81,5 +88,7 @@ fun SyncedLockerEntryPlatform.dataEqualTo(other: SyncedLockerEntryPlatform): Boo
processInfoFlags == other.processInfoFlags &&
name == other.name &&
description == other.description &&
icon == other.icon
images.icon == other.images.icon &&
images.list == other.images.list &&
images.screenshot == other.images.screenshot
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
package io.rebble.cobble.shared.di

import io.ktor.client.HttpClient
import io.ktor.client.plugins.cache.HttpCache
import io.ktor.client.plugins.cache.storage.CacheStorage
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
import io.ktor.serialization.kotlinx.json.json
import io.rebble.cobble.shared.PlatformContext
import org.koin.dsl.module

val dependenciesModule = module {
factory {
HttpClient {
install(HttpCache) {
publicStorage(makePlatformCacheStorage(get()))
}
install(ContentNegotiation) {
json()
}
}
}
}
}

expect fun makePlatformCacheStorage(platformContext: PlatformContext): CacheStorage
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import io.rebble.cobble.shared.domain.state.ConnectionState
import io.rebble.cobble.shared.domain.state.CurrentToken
import io.rebble.cobble.shared.domain.state.watchOrNull
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.*
import org.koin.core.qualifier.named
import org.koin.dsl.bind
Expand All @@ -18,6 +19,7 @@ val stateModule = module {
get<StateFlow<ConnectionState>>(named("connectionState"))
.flatMapLatest { it.watchOrNull?.metadata?.take(1) ?: flowOf(null) }
.filterNotNull()
.stateIn(CoroutineScope(Dispatchers.Default), SharingStarted.WhileSubscribed(), null)
}
single(named("connectionScope")) {
MutableStateFlow<CoroutineScope>(CoroutineScope(EmptyCoroutineContext))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package io.rebble.cobble.shared.domain.api.appstore
import io.rebble.cobble.shared.database.NextSyncAction
import io.rebble.cobble.shared.database.entity.SyncedLockerEntry
import io.rebble.cobble.shared.database.entity.SyncedLockerEntryPlatform
import io.rebble.cobble.shared.database.entity.SyncedLockerEntryPlatformImages
import io.rebble.cobble.shared.database.entity.SyncedLockerEntryWithPlatforms
import kotlinx.serialization.Serializable
import kotlinx.serialization.SerialName
Expand Down Expand Up @@ -132,6 +133,10 @@ fun LockerEntryPlatform.toEntity(lockerEntryId: String): SyncedLockerEntryPlatfo
processInfoFlags = pebbleProcessInfoFlags,
name = name,
description = description,
icon = images.icon
SyncedLockerEntryPlatformImages(
icon = images.icon,
list = images.list,
screenshot = images.screenshot
)
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class CalendarSync(
): AutoCloseable, KoinComponent {
private val calendarSyncer: PhoneCalendarSyncer by inject()
private val watchTimelineSyncer = WatchTimelineSyncer(blobDBService)
private val metadataFlow: Flow<WatchVersion.WatchVersionResponse> by inject(named("connectedWatchMetadata"))
private val metadataFlow: StateFlow<WatchVersion.WatchVersionResponse?> by inject(named("connectedWatchMetadata"))
private val timelinePinDao: TimelinePinDao by inject()
private val calendarDao: CalendarDao by inject()
private val calendarEnableChangeFlow: MutableSharedFlow<List<Calendar>> = MutableSharedFlow()
Expand All @@ -34,7 +34,7 @@ class CalendarSync(
Logging.d("CalendarSync init")
}

private val watchConnectedListener = metadataFlow.onEach {
private val watchConnectedListener = metadataFlow.filterNotNull().onEach {
Logging.d("Watch connected, syncing calendar pins")
val res = onWatchConnected(it.isUnfaithful.get() ?: false)
Logging.d("Calendar sync result: $res")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,5 @@ object ConnectionStateManager: KoinComponent {
/**
* Flow of the currently connected watch's metadata. This flow only emits when a watch is connected and will not emit if negotiation never completes.
*/
val connectedWatchMetadata: Flow<WatchVersion.WatchVersionResponse> by inject(named("connectedWatchMetadata"))
val connectedWatchMetadata: StateFlow<WatchVersion.WatchVersionResponse?> by inject(named("connectedWatchMetadata"))
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class LockerSyncJob: KoinComponent {
private val blobDBService: BlobDBService by inject()
suspend fun beginSync(): Boolean {
val locker = RWS.appstoreClient?.getLocker() ?: return false
lockerDao.clearAll()
val storedLocker = lockerDao.getAllEntries()

val changedEntries = locker.filter { new ->
Expand All @@ -45,6 +46,9 @@ class LockerSyncJob: KoinComponent {
lockerDao.clearPlatformsFor(it.id)
}
lockerDao.insertOrReplaceAll(changedEntries.map { it.toEntity() })
lockerDao.insertOrReplaceAllPlatforms(newEntries.flatMap { new ->
new.hardwarePlatforms.map { it.toEntity(new.id) }
})
lockerDao.insertOrReplaceAllPlatforms(changedEntries.flatMap { new ->
new.hardwarePlatforms.map { it.toEntity(new.id) }
})
Expand Down
Loading

0 comments on commit aa86384

Please sign in to comment.