Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions panel-core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ plugins {
id("convention.compose")
id("convention-publish")
id("convention.detekt")
alias(stack.plugins.kotlin.serialization)
}

description = "Debug panel core library"
Expand Down Expand Up @@ -51,7 +52,9 @@ dependencies {
implementation(androidx.appcompat)
implementation(androidx.lifecycle.livedata)

implementation(androidx.datastore)
implementation(stack.kotlinx.coroutines.android)
implementation(stack.kotlinx.serialization.json)
implementation(stack.timber)
implementation(stack.material)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import android.app.Application
import android.content.Context
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.redmadrobot.debug.core.data.storage.theme.ThemeDataStore
import com.redmadrobot.debug.core.internal.CommonContainer
import com.redmadrobot.debug.core.plugin.Plugin
import com.redmadrobot.debug.core.plugin.PluginManager
import com.redmadrobot.debug.uikit.theme.model.ThemeMode
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
Expand All @@ -22,6 +24,9 @@ internal class DebugPanelInstance(
extraBufferCapacity = 1,
onBufferOverflow = BufferOverflow.DROP_OLDEST,
)
private val themeDataStore by lazy {
ThemeDataStore(context = application.applicationContext)
}

init {
initContainer(application.applicationContext)
Expand All @@ -46,6 +51,16 @@ internal class DebugPanelInstance(
?: error("PluginManager not initialised")
}

internal fun observeDebugPanelTheme(): Flow<ThemeMode> {
return themeDataStore.observeThemeMode()
}

internal suspend fun updateDebugPanelTheme(themeMode: ThemeMode) {
themeDataStore.saveThemeMode(mode = themeMode)
}

internal fun getSelectedTheme() = themeDataStore.getSelectedTheme()

private fun initContainer(context: Context) {
commonContainer = CommonContainer(context)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.redmadrobot.debug.core.data.storage.model

import com.redmadrobot.debug.uikit.theme.model.ThemeMode
import kotlinx.serialization.Serializable

@Serializable
internal data class ThemeData(
val themeMode: ThemeMode = ThemeMode.System,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.redmadrobot.debug.core.data.storage.theme

import androidx.datastore.core.Serializer
import com.redmadrobot.debug.core.data.storage.model.ThemeData
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromStream
import kotlinx.serialization.json.encodeToStream
import java.io.InputStream
import java.io.OutputStream

@OptIn(ExperimentalSerializationApi::class)
internal object ThemeDataSerializer : Serializer<ThemeData> {
override val defaultValue: ThemeData = ThemeData()

override suspend fun readFrom(input: InputStream): ThemeData {
return Json.decodeFromStream(input)
}

override suspend fun writeTo(themeData: ThemeData, output: OutputStream) {
Json.encodeToStream(themeData, output)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.redmadrobot.debug.core.data.storage.theme

import android.content.Context
import com.redmadrobot.debug.uikit.theme.model.ThemeMode
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.runBlocking

internal class ThemeDataStore(private val context: Context) {
private val dataStore by lazy { context.themeStorage }

fun getSelectedTheme(): ThemeMode {
return runBlocking { dataStore.data.first().themeMode }
}

fun observeThemeMode(): Flow<ThemeMode> {
return dataStore.data.map { it.themeMode }
}

suspend fun saveThemeMode(mode: ThemeMode) {
dataStore.updateData { data -> data.copy(themeMode = mode) }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.redmadrobot.debug.core.data.storage.theme

import android.content.Context
import androidx.datastore.dataStore

internal val Context.themeStorage by dataStore(
fileName = "debug_panel_theme.json",
serializer = ThemeDataSerializer,
)
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,16 @@ import androidx.compose.ui.unit.dp
import com.redmadrobot.debug.core.R
import com.redmadrobot.debug.core.extension.getAllPlugins
import com.redmadrobot.debug.core.plugin.Plugin
import com.redmadrobot.debug.uikit.theme.model.ThemeMode
import kotlinx.coroutines.launch

@Suppress("UnusedParameter")
@Composable
public fun DebugPanelScreen(onClose: () -> Unit) {
public fun DebugPanelScreen(
themeMode: ThemeMode,
onClose: () -> Unit,
onThemeModeChange: (ThemeMode) -> Unit = {}
) {
val plugins = remember { getAllPlugins() }
val pluginsName = remember { plugins.map { it.getName() } }
val pagerState = rememberPagerState(initialPage = 0, pageCount = { plugins.size })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,32 @@ package com.redmadrobot.debug.core.ui.debugpanel
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
import com.redmadrobot.debug.core.DebugPanel
import com.redmadrobot.debug.core.inapp.compose.DebugPanelScreen
import com.redmadrobot.debug.uikit.theme.DebugPanelTheme
import com.redmadrobot.debug.uikit.theme.ThemeState
import kotlinx.coroutines.launch

internal class DebugPanelActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

setContent {
val themeState = remember { ThemeState() }
DebugPanelTheme(themeState = themeState) {
DebugPanelScreen(onClose = { finish() })
val debugPanel = remember { DebugPanel.getInstance()!! }
val themeMode by debugPanel.observeDebugPanelTheme()
.collectAsStateWithLifecycle(initialValue = debugPanel.getSelectedTheme())

DebugPanelTheme(themeMode = themeMode) {
DebugPanelScreen(
themeMode = themeMode,
onThemeModeChange = { mode ->
lifecycleScope.launch { debugPanel.updateDebugPanelTheme(themeMode = mode) }
},
onClose = { finish() },
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,31 @@ package com.redmadrobot.debug.core.ui.settings
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.compose.rememberNavController
import com.redmadrobot.debug.core.DebugPanel
import com.redmadrobot.debug.core.extension.getAllPlugins
import com.redmadrobot.debug.core.internal.EditablePlugin
import com.redmadrobot.debug.uikit.theme.DebugPanelTheme

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

setContent {
MaterialTheme {
val debugPanel = remember { DebugPanel.getInstance()!! }
val themeMode by debugPanel.observeDebugPanelTheme()
.collectAsStateWithLifecycle(initialValue = debugPanel.getSelectedTheme())

DebugPanelTheme(themeMode = themeMode) {
val navController = rememberNavController()
val pluginItems = remember { getSettingItems() }
DebugSettingsNavHost(navController = navController, pluginItems = pluginItems)
DebugSettingsNavHost(
navController = navController,
pluginItems = pluginItems,
)
}
}
}
Expand Down
1 change: 1 addition & 0 deletions panel-ui-kit/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,5 @@ dependencies {
implementation(androidx.compose.material3)
implementation(androidx.compose.ui.tooling)
implementation(androidx.compose.ui.tooling.preview)
implementation(androidx.core)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.redmadrobot.debug.uikit.components

import androidx.compose.foundation.layout.size
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.key
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.redmadrobot.debug.uikit.theme.DebugPanelTheme
import com.redmadrobot.debug.uikit.theme.model.ThemeMode

@Composable
public fun ThemeSwitcher(
currentMode: ThemeMode,
onModeSelect: (ThemeMode) -> Unit,
modifier: Modifier = Modifier,
) {
var expanded by remember { mutableStateOf(false) }

IconButton(onClick = { expanded = true }, modifier = modifier) {
Icon(
painter = painterResource(id = ThemeMode.getIconRes(mode = currentMode)),
contentDescription = null,
tint = DebugPanelTheme.colors.content.secondary,
modifier = Modifier.size(size = 20.dp),
)
DropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false },
) {
ThemeMode.entries.forEach { mode ->
key(mode.name) {
DropdownMenuItem(
title = stringResource(id = ThemeMode.getTitleRes(mode = mode)),
onModeSelect = {
onModeSelect.invoke(mode)
expanded = false
}
)
}
}
}
}
}

@Composable
private fun DropdownMenuItem(
title: String,
onModeSelect: () -> Unit
) {
DropdownMenuItem(
text = { Text(text = title, style = DebugPanelTheme.typography.bodyMedium) },
onClick = { onModeSelect() },
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import androidx.compose.ui.graphics.luminance
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.redmadrobot.debug.uikit.theme.model.ThemeMode

internal object BaseColors {
// Purple
Expand Down Expand Up @@ -92,7 +93,7 @@ internal object BaseColors {
@Composable
@Preview(showBackground = true)
private fun Preview() {
DebugPanelTheme {
DebugPanelTheme(themeMode = ThemeMode.Light) {
FlowRow(
modifier = Modifier
.fillMaxSize()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.redmadrobot.debug.uikit.theme

import androidx.compose.material3.ColorScheme
import androidx.compose.material3.lightColorScheme

internal val LightDebugPanelColors = DebugPanelColors()

internal val DarkDebugPanelColors = DebugPanelColors(
Expand Down Expand Up @@ -44,3 +47,33 @@ internal val DarkDebugPanelColors = DebugPanelColors(
remoteBackground = BaseColors.OrangeDark,
),
)

internal fun DebugPanelColors.toMaterialColorScheme(): ColorScheme = lightColorScheme(
primary = button.primary,
onPrimary = button.onPrimary,
primaryContainer = surface.tertiary,
onPrimaryContainer = content.primary,
secondary = content.secondary,
onSecondary = button.onPrimary,
secondaryContainer = button.secondary,
onSecondaryContainer = content.primary,
tertiary = content.tertiary,
onTertiary = button.onPrimary,
error = content.error,
onError = button.onError,
errorContainer = BaseColors.Error90,
onErrorContainer = BaseColors.Error20,
background = background.primary,
onBackground = content.primary,
surface = surface.primary,
onSurface = content.primary,
surfaceVariant = stroke.primary,
onSurfaceVariant = content.secondary,
outline = content.tertiary,
outlineVariant = stroke.secondary,
surfaceContainer = surface.secondary,
surfaceContainerHigh = surface.tertiary,
inverseSurface = content.primary,
inverseOnSurface = background.primary,
inversePrimary = content.accent,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.redmadrobot.debug.uikit.theme

import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp

public object DebugPanelDimensions {
// Common
public val topBarHeight: Dp = 56.dp
public val tabRowHeight: Dp = 48.dp
public val bottomBarHeight: Dp = 56.dp
public val rowMinHeight: Dp = 48.dp

// Toggles
public val toggleWidth: Dp = 44.dp
public val toggleHeight: Dp = 24.dp
public val dotSize: Dp = 10.dp

// Icons
public val iconSizeSmall: Dp = 20.dp
public val iconSizeMedium: Dp = 24.dp
public val iconSizeLarge: Dp = 32.dp
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.redmadrobot.debug.uikit.theme

import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.ui.unit.dp

public object DebugPanelShapes {
public val small: RoundedCornerShape = RoundedCornerShape(4.dp)
public val medium: RoundedCornerShape = RoundedCornerShape(8.dp)
public val large: RoundedCornerShape = RoundedCornerShape(20.dp)
public val dialog: RoundedCornerShape = RoundedCornerShape(28.dp)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.redmadrobot.debug.uikit.theme

import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp

public object DebugPanelSpacing {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Кажется излишне

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Согласен, выглядит спорно, но я бы пока что оставил, общую картину посмотреть, потом если что можно дропнуть

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Потом можно и забыть)

public val xxs: Dp = 2.dp
public val xs: Dp = 4.dp
public val sm: Dp = 8.dp
public val md: Dp = 12.dp
public val lg: Dp = 16.dp
public val xl: Dp = 20.dp
public val xxl: Dp = 24.dp
}
Loading
Loading