refactor: remove Jsoup dependency + replace runBlocking with Flow

Step 7: Remove Jsoup
- Delete implementation(libs.jsoup) from build.gradle.kts
- Delete jsoup version + library from libs.versions.toml
- 0 imports of Jsoup in codebase, pure dead dependency

Step 8: ChartSettingsStore Flow
- Replace runBlocking getUseUtc8() with StateFlow useUtc8State
- UsageChartViewModel: setWorkspace() reads useUtc8Flow.first() async
- ChartUiState: add useUtc8Initialized flag to prevent double-load
- Remove runBlocking import from ChartSettingsStore
This commit is contained in:
WaterRain 2026-07-07 00:05:33 +00:00
parent 220a74492a
commit 6e629d8eb2
No known key found for this signature in database
4 changed files with 27 additions and 16 deletions

View File

@ -96,7 +96,6 @@ dependencies {
implementation(libs.okhttp.logging.interceptor) implementation(libs.okhttp.logging.interceptor)
implementation(libs.kotlinx.serialization.json) implementation(libs.kotlinx.serialization.json)
implementation(libs.retrofit.kotlinx.serialization.converter) implementation(libs.retrofit.kotlinx.serialization.converter)
implementation(libs.jsoup)
// DataStore // DataStore
implementation(libs.androidx.datastore.preferences) implementation(libs.androidx.datastore.preferences)

View File

@ -7,14 +7,19 @@ import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.preferencesDataStore import androidx.datastore.preferences.preferencesDataStore
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.Dispatchers
private val Context.chartSettingsDataStore: DataStore<Preferences> by preferencesDataStore( private val Context.chartSettingsDataStore: DataStore<Preferences> by preferencesDataStore(
name = "chart_settings" name = "chart_settings"
) )
private val chartSettingsScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
/** 图表页偏好设置持久化 */ /** 图表页偏好设置持久化 */
class ChartSettingsStore(private val dataStore: DataStore<Preferences>) { class ChartSettingsStore(private val dataStore: DataStore<Preferences>) {
@ -27,10 +32,9 @@ class ChartSettingsStore(private val dataStore: DataStore<Preferences>) {
prefs[KEY_USE_UTC8] ?: false prefs[KEY_USE_UTC8] ?: false
} }
/** 同步读取(用于 ViewModel 初始化) */ /** StateFlow 版本,UI 层 collectAsState 直接使用 */
fun getUseUtc8(): Boolean = runBlocking { val useUtc8State: StateFlow<Boolean> = useUtc8Flow
dataStore.data.map { it[KEY_USE_UTC8] ?: false }.first() .stateIn(chartSettingsScope, kotlinx.coroutines.flow.SharingStarted.Eagerly, false)
}
/** 写入偏好 */ /** 写入偏好 */
suspend fun setUseUtc8(value: Boolean) { suspend fun setUseUtc8(value: Boolean) {

View File

@ -15,6 +15,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.time.Instant import java.time.Instant
import java.time.LocalDate import java.time.LocalDate
@ -29,9 +30,7 @@ class UsageChartViewModel @Inject constructor(
private val chartSettingsStore: ChartSettingsStore private val chartSettingsStore: ChartSettingsStore
) : ViewModel() { ) : ViewModel() {
private val _state = MutableStateFlow( private val _state = MutableStateFlow(ChartUiState(useUtc8 = false))
ChartUiState(useUtc8 = chartSettingsStore.getUseUtc8())
)
val state: StateFlow<ChartUiState> = _state.asStateFlow() val state: StateFlow<ChartUiState> = _state.asStateFlow()
private var workspaceIdOverride: String? = null private var workspaceIdOverride: String? = null
@ -43,11 +42,21 @@ class UsageChartViewModel @Inject constructor(
fun setWorkspace(wid: String) { fun setWorkspace(wid: String) {
workspaceIdOverride = wid workspaceIdOverride = wid
loadGeneration++ loadGeneration++
allowFallback = true // CCGO 首次加载也允许降级 allowFallback = true
// 先清空数据防止 init 自动加载的 OCGO 数据闪一下,但保留持久化偏好
_state.value = ChartUiState(useUtc8 = _state.value.useUtc8) _state.value = ChartUiState(useUtc8 = _state.value.useUtc8)
viewModelScope.launch {
// 首次加载时同步读取 UTC 偏好,避免用默认值 false 加载后再切换
if (!_state.value.useUtc8Initialized) {
val saved = chartSettingsStore.useUtc8Flow.first()
if (saved != _state.value.useUtc8) {
_state.update { it.copy(useUtc8 = saved, useUtc8Initialized = true) }
} else {
_state.update { it.copy(useUtc8Initialized = true) }
}
}
load() load()
} }
}
private suspend fun workspaceId(): String? { private suspend fun workspaceId(): String? {
workspaceIdOverride?.let { return it } workspaceIdOverride?.let { return it }
@ -259,5 +268,6 @@ data class ChartUiState(
val allModels: List<String> = emptyList(), val allModels: List<String> = emptyList(),
val selectedModels: Set<String> = emptySet(), // empty = all val selectedModels: Set<String> = emptySet(), // empty = all
val buckets: List<ChartBucket> = emptyList(), val buckets: List<ChartBucket> = emptyList(),
val useUtc8: Boolean = false val useUtc8: Boolean = false,
val useUtc8Initialized: Boolean = false
) )

View File

@ -18,7 +18,6 @@ retrofit = "2.11.0"
okhttp = "4.12.0" okhttp = "4.12.0"
kotlinxSerializationJson = "1.7.3" kotlinxSerializationJson = "1.7.3"
retrofitKotlinxSerializationConverter = "1.0.0" retrofitKotlinxSerializationConverter = "1.0.0"
jsoup = "1.18.3"
# DataStore # DataStore
datastorePreferences = "1.1.1" datastorePreferences = "1.1.1"
@ -69,7 +68,6 @@ okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhtt
okhttp-logging-interceptor = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "okhttp" } okhttp-logging-interceptor = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "okhttp" }
kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" } kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
retrofit-kotlinx-serialization-converter = { group = "com.jakewharton.retrofit", name = "retrofit2-kotlinx-serialization-converter", version.ref = "retrofitKotlinxSerializationConverter" } retrofit-kotlinx-serialization-converter = { group = "com.jakewharton.retrofit", name = "retrofit2-kotlinx-serialization-converter", version.ref = "retrofitKotlinxSerializationConverter" }
jsoup = { group = "org.jsoup", name = "jsoup", version.ref = "jsoup" }
# DataStore # DataStore
androidx-datastore-preferences = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "datastorePreferences" } androidx-datastore-preferences = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "datastorePreferences" }