Skip to content

Commit 4a042df

Browse files
committed
feature: prepare dynamic theme choosing
1 parent 355b6a9 commit 4a042df

File tree

22 files changed

+433
-86
lines changed

22 files changed

+433
-86
lines changed

panel-core/build.gradle.kts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ plugins {
33
id("convention.compose")
44
id("convention-publish")
55
id("convention.detekt")
6+
alias(stack.plugins.kotlin.serialization)
67
}
78

89
description = "Debug panel core library"
@@ -51,7 +52,9 @@ dependencies {
5152
implementation(androidx.appcompat)
5253
implementation(androidx.lifecycle.livedata)
5354

55+
implementation(androidx.datastore)
5456
implementation(stack.kotlinx.coroutines.android)
57+
implementation(stack.kotlinx.serialization.json)
5558
implementation(stack.timber)
5659
implementation(stack.material)
5760

panel-core/src/main/kotlin/com/redmadrobot/debug/core/DebugPanelInstance.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ import android.app.Application
44
import android.content.Context
55
import androidx.lifecycle.LiveData
66
import androidx.lifecycle.MutableLiveData
7+
import com.redmadrobot.debug.core.data.storage.theme.ThemeDataStore
78
import com.redmadrobot.debug.core.internal.CommonContainer
89
import com.redmadrobot.debug.core.plugin.Plugin
910
import com.redmadrobot.debug.core.plugin.PluginManager
11+
import com.redmadrobot.debug.uikit.theme.model.ThemeMode
1012
import kotlinx.coroutines.channels.BufferOverflow
1113
import kotlinx.coroutines.flow.Flow
1214
import kotlinx.coroutines.flow.MutableSharedFlow
@@ -22,6 +24,9 @@ internal class DebugPanelInstance(
2224
extraBufferCapacity = 1,
2325
onBufferOverflow = BufferOverflow.DROP_OLDEST,
2426
)
27+
private val themeDataStore by lazy {
28+
ThemeDataStore(context = application.applicationContext)
29+
}
2530

2631
init {
2732
initContainer(application.applicationContext)
@@ -46,6 +51,16 @@ internal class DebugPanelInstance(
4651
?: error("PluginManager not initialised")
4752
}
4853

54+
internal fun observeDebugPanelTheme(): Flow<ThemeMode> {
55+
return themeDataStore.observeThemeMode()
56+
}
57+
58+
internal suspend fun updateDebugPanelTheme(themeMode: ThemeMode) {
59+
themeDataStore.saveThemeMode(mode = themeMode)
60+
}
61+
62+
internal fun getSelectedTheme() = themeDataStore.getSelectedTheme()
63+
4964
private fun initContainer(context: Context) {
5065
commonContainer = CommonContainer(context)
5166
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.redmadrobot.debug.core.data.storage.model
2+
3+
import com.redmadrobot.debug.uikit.theme.model.ThemeMode
4+
import kotlinx.serialization.Serializable
5+
6+
@Serializable
7+
internal data class ThemeData(
8+
val themeMode: ThemeMode = ThemeMode.System,
9+
)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.redmadrobot.debug.core.data.storage.theme
2+
3+
import androidx.datastore.core.Serializer
4+
import com.redmadrobot.debug.core.data.storage.model.ThemeData
5+
import kotlinx.serialization.ExperimentalSerializationApi
6+
import kotlinx.serialization.json.Json
7+
import kotlinx.serialization.json.decodeFromStream
8+
import kotlinx.serialization.json.encodeToStream
9+
import java.io.InputStream
10+
import java.io.OutputStream
11+
12+
@OptIn(ExperimentalSerializationApi::class)
13+
internal object ThemeDataSerializer : Serializer<ThemeData> {
14+
override val defaultValue: ThemeData = ThemeData()
15+
16+
override suspend fun readFrom(input: InputStream): ThemeData {
17+
return Json.decodeFromStream(input)
18+
}
19+
20+
override suspend fun writeTo(themeData: ThemeData, output: OutputStream) {
21+
Json.encodeToStream(themeData, output)
22+
}
23+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.redmadrobot.debug.core.data.storage.theme
2+
3+
import android.content.Context
4+
import com.redmadrobot.debug.uikit.theme.model.ThemeMode
5+
import kotlinx.coroutines.flow.Flow
6+
import kotlinx.coroutines.flow.first
7+
import kotlinx.coroutines.flow.map
8+
import kotlinx.coroutines.runBlocking
9+
10+
internal class ThemeDataStore(private val context: Context) {
11+
private val dataStore by lazy { context.themeStorage }
12+
13+
fun getSelectedTheme(): ThemeMode {
14+
return runBlocking { dataStore.data.first().themeMode }
15+
}
16+
17+
fun observeThemeMode(): Flow<ThemeMode> {
18+
return dataStore.data.map { it.themeMode }
19+
}
20+
21+
suspend fun saveThemeMode(mode: ThemeMode) {
22+
dataStore.updateData { data -> data.copy(themeMode = mode) }
23+
}
24+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.redmadrobot.debug.core.data.storage.theme
2+
3+
import android.content.Context
4+
import androidx.datastore.dataStore
5+
6+
internal val Context.themeStorage by dataStore(
7+
fileName = "debug_panel_theme.json",
8+
serializer = ThemeDataSerializer,
9+
)

panel-core/src/main/kotlin/com/redmadrobot/debug/core/inapp/compose/DebugPanelScreen.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,16 @@ import androidx.compose.ui.unit.dp
2828
import com.redmadrobot.debug.core.R
2929
import com.redmadrobot.debug.core.extension.getAllPlugins
3030
import com.redmadrobot.debug.core.plugin.Plugin
31+
import com.redmadrobot.debug.uikit.theme.model.ThemeMode
3132
import kotlinx.coroutines.launch
3233

34+
@Suppress("UnusedParameter")
3335
@Composable
34-
public fun DebugPanelScreen(onClose: () -> Unit) {
36+
public fun DebugPanelScreen(
37+
themeMode: ThemeMode,
38+
onClose: () -> Unit,
39+
onThemeModeChange: (ThemeMode) -> Unit = {}
40+
) {
3541
val plugins = remember { getAllPlugins() }
3642
val pluginsName = remember { plugins.map { it.getName() } }
3743
val pagerState = rememberPagerState(initialPage = 0, pageCount = { plugins.size })

panel-core/src/main/kotlin/com/redmadrobot/debug/core/ui/debugpanel/DebugPanelActivity.kt

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,32 @@ package com.redmadrobot.debug.core.ui.debugpanel
33
import android.os.Bundle
44
import androidx.activity.ComponentActivity
55
import androidx.activity.compose.setContent
6+
import androidx.compose.runtime.getValue
67
import androidx.compose.runtime.remember
8+
import androidx.lifecycle.compose.collectAsStateWithLifecycle
9+
import androidx.lifecycle.lifecycleScope
10+
import com.redmadrobot.debug.core.DebugPanel
711
import com.redmadrobot.debug.core.inapp.compose.DebugPanelScreen
812
import com.redmadrobot.debug.uikit.theme.DebugPanelTheme
9-
import com.redmadrobot.debug.uikit.theme.ThemeState
13+
import kotlinx.coroutines.launch
1014

1115
internal class DebugPanelActivity : ComponentActivity() {
1216
override fun onCreate(savedInstanceState: Bundle?) {
1317
super.onCreate(savedInstanceState)
18+
1419
setContent {
15-
val themeState = remember { ThemeState() }
16-
DebugPanelTheme(themeState = themeState) {
17-
DebugPanelScreen(onClose = { finish() })
20+
val debugPanel = remember { DebugPanel.getInstance()!! }
21+
val themeMode by debugPanel.observeDebugPanelTheme()
22+
.collectAsStateWithLifecycle(initialValue = debugPanel.getSelectedTheme())
23+
24+
DebugPanelTheme(themeMode = themeMode) {
25+
DebugPanelScreen(
26+
themeMode = themeMode,
27+
onThemeModeChange = { mode ->
28+
lifecycleScope.launch { debugPanel.updateDebugPanelTheme(themeMode = mode) }
29+
},
30+
onClose = { finish() },
31+
)
1832
}
1933
}
2034
}

panel-core/src/main/kotlin/com/redmadrobot/debug/core/ui/settings/DebugSettingsActivity.kt

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,31 @@ package com.redmadrobot.debug.core.ui.settings
33
import android.os.Bundle
44
import androidx.activity.compose.setContent
55
import androidx.appcompat.app.AppCompatActivity
6-
import androidx.compose.material.MaterialTheme
6+
import androidx.compose.runtime.getValue
77
import androidx.compose.runtime.remember
8+
import androidx.lifecycle.compose.collectAsStateWithLifecycle
89
import androidx.navigation.compose.rememberNavController
10+
import com.redmadrobot.debug.core.DebugPanel
911
import com.redmadrobot.debug.core.extension.getAllPlugins
1012
import com.redmadrobot.debug.core.internal.EditablePlugin
13+
import com.redmadrobot.debug.uikit.theme.DebugPanelTheme
1114

1215
internal class DebugSettingsActivity : AppCompatActivity() {
1316
override fun onCreate(savedInstanceState: Bundle?) {
1417
super.onCreate(savedInstanceState)
1518

1619
setContent {
17-
MaterialTheme {
20+
val debugPanel = remember { DebugPanel.getInstance()!! }
21+
val themeMode by debugPanel.observeDebugPanelTheme()
22+
.collectAsStateWithLifecycle(initialValue = debugPanel.getSelectedTheme())
23+
24+
DebugPanelTheme(themeMode = themeMode) {
1825
val navController = rememberNavController()
1926
val pluginItems = remember { getSettingItems() }
20-
DebugSettingsNavHost(navController = navController, pluginItems = pluginItems)
27+
DebugSettingsNavHost(
28+
navController = navController,
29+
pluginItems = pluginItems,
30+
)
2131
}
2232
}
2333
}

panel-ui-kit/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,5 @@ dependencies {
4242
implementation(androidx.compose.material3)
4343
implementation(androidx.compose.ui.tooling)
4444
implementation(androidx.compose.ui.tooling.preview)
45+
implementation(androidx.core)
4546
}

0 commit comments

Comments
 (0)