Browse Source

COMPOSE-356 Support light theme for codeviewer example (#3853)

https://youtrack.jetbrains.com/issue/COMPOSE-356/Add-Dark-theme-to-codeviewer-examples

The MR does the following:
- Enables dark theme for iOS, Android and Desktop platforms
- Expands compose view to fullscreen and uses window padding to adjust
content location
- Adjusts toolbar clock style to application theme on mobile platforms
pull/3864/head
Andrei Salavei 7 months ago committed by GitHub
parent
commit
3f4a85491e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      examples/codeviewer/androidApp/src/androidMain/AndroidManifest.xml
  2. 2
      examples/codeviewer/androidApp/src/androidMain/assets/data/EditorView.kt
  3. 5
      examples/codeviewer/androidApp/src/androidMain/kotlin/org/jetbrains/codeviewer/MainActivity.kt
  4. 6
      examples/codeviewer/androidApp/src/androidMain/res/values-night/styles.xml
  5. 11
      examples/codeviewer/androidApp/src/androidMain/res/values/styles.xml
  6. 7
      examples/codeviewer/iosApp/iosApp/ContentView.swift
  7. 62
      examples/codeviewer/shared/src/commonMain/kotlin/org/jetbrains/codeviewer/ui/CodeViewerView.kt
  8. 19
      examples/codeviewer/shared/src/commonMain/kotlin/org/jetbrains/codeviewer/ui/MainView.kt
  9. 88
      examples/codeviewer/shared/src/commonMain/kotlin/org/jetbrains/codeviewer/ui/common/Theme.kt
  10. 4
      examples/codeviewer/shared/src/commonMain/kotlin/org/jetbrains/codeviewer/ui/editor/EditorTabsView.kt
  11. 16
      examples/codeviewer/shared/src/commonMain/kotlin/org/jetbrains/codeviewer/ui/editor/EditorView.kt
  12. 15
      examples/codeviewer/shared/src/commonMain/kotlin/org/jetbrains/codeviewer/ui/statusbar/StatusBar.kt
  13. 4
      examples/codeviewer/shared/src/commonMain/kotlin/org/jetbrains/codeviewer/util/VerticalSplittable.kt
  14. 2
      examples/codeviewer/shared/src/iosMain/resources/EditorView.kt

4
examples/codeviewer/androidApp/src/androidMain/AndroidManifest.xml

@ -7,11 +7,11 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
android:theme="@style/Theme.Application">
<activity
android:exported="true"
android:name="MainActivity"
>
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

2
examples/codeviewer/androidApp/src/androidMain/assets/data/EditorView.kt

@ -48,7 +48,7 @@ fun EditorView(model: Editor, settings: Settings) = key(model) {
)
.width(1.dp)
.fillMaxHeight()
.background(AppTheme.colors.backgroundLight)
.background(AppTheme.colors.codeGuide)
)
}
} else {

5
examples/codeviewer/androidApp/src/androidMain/kotlin/org/jetbrains/codeviewer/MainActivity.kt

@ -1,10 +1,11 @@
package org.jetbrains.codeviewer
import MainView
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.WindowCompat
import org.jetbrains.codeviewer.platform._HomeFolder
import MainView
import java.io.File
import java.io.FileOutputStream
@ -14,6 +15,8 @@ class MainActivity : AppCompatActivity() {
copyAssets()
_HomeFolder = filesDir
WindowCompat.setDecorFitsSystemWindows(window, false)
setContent {
MainView()
}

6
examples/codeviewer/androidApp/src/androidMain/res/values-night/styles.xml

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.Application" parent="Theme.General">
<item name="android:windowLightStatusBar">false</item>
</style>
</resources>

11
examples/codeviewer/androidApp/src/androidMain/res/values/styles.xml

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.General" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
</style>
<style name="Theme.Application" parent="Theme.General">
<item name="android:windowLightStatusBar">true</item>
</style>
</resources>

7
examples/codeviewer/iosApp/iosApp/ContentView.swift

@ -4,11 +4,8 @@ import shared
struct ContentView: View {
var body: some View {
ZStack {
Color(#colorLiteral(red: 0.235, green: 0.247, blue: 0.255, alpha: 1)).ignoresSafeArea(.all)
ComposeView()
.ignoresSafeArea(.all, edges: .bottom) // Compose has own keyboard handler
}.preferredColorScheme(.dark)
ComposeView()
.ignoresSafeArea(.all)
}
}

62
examples/codeviewer/shared/src/commonMain/kotlin/org/jetbrains/codeviewer/ui/CodeViewerView.kt

@ -5,13 +5,25 @@ import androidx.compose.animation.core.SpringSpec
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.material.Icon
import androidx.compose.material.LocalContentColor
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.ArrowForward
import androidx.compose.runtime.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
@ -38,32 +50,36 @@ fun CodeViewerView(model: CodeViewer) {
).value
}
VerticalSplittable(
Modifier.fillMaxSize(),
panelState.splitter,
onResize = {
panelState.expandedSize =
(panelState.expandedSize + it).coerceAtLeast(panelState.expandedSizeMin)
}
Box(Modifier
.windowInsetsPadding(WindowInsets.safeDrawing)
) {
ResizablePanel(Modifier.width(animatedSize).fillMaxHeight(), panelState) {
Column {
FileTreeViewTabView()
FileTreeView(model.fileTree)
VerticalSplittable(
Modifier.fillMaxSize(),
panelState.splitter,
onResize = {
panelState.expandedSize =
(panelState.expandedSize + it).coerceAtLeast(panelState.expandedSizeMin)
}
) {
ResizablePanel(Modifier.width(animatedSize).fillMaxHeight(), panelState) {
Column {
FileTreeViewTabView()
FileTreeView(model.fileTree)
}
}
}
Box {
if (model.editors.active != null) {
Column(Modifier.fillMaxSize()) {
EditorTabsView(model.editors)
Box(Modifier.weight(1f)) {
EditorView(model.editors.active!!, model.settings)
Box {
if (model.editors.active != null) {
Column(Modifier.fillMaxSize()) {
EditorTabsView(model.editors)
Box(Modifier.weight(1f)) {
EditorView(model.editors.active!!, model.settings)
}
StatusBar(model.settings)
}
StatusBar(model.settings)
} else {
EditorEmptyView()
}
} else {
EditorEmptyView()
}
}
}

19
examples/codeviewer/shared/src/commonMain/kotlin/org/jetbrains/codeviewer/ui/MainView.kt

@ -1,13 +1,16 @@
package org.jetbrains.codeviewer.ui
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.text.selection.DisableSelection
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.remember
import org.jetbrains.codeviewer.platform.HomeFolder
import org.jetbrains.codeviewer.ui.common.AppTheme
import org.jetbrains.codeviewer.ui.common.LocalTheme
import org.jetbrains.codeviewer.ui.common.Settings
import org.jetbrains.codeviewer.ui.common.Theme
import org.jetbrains.codeviewer.ui.editor.Editors
import org.jetbrains.codeviewer.ui.filetree.FileTree
@ -24,11 +27,17 @@ fun MainView() {
}
DisableSelection {
MaterialTheme(
colors = AppTheme.colors.material
val theme = if (isSystemInDarkTheme()) Theme.dark else Theme.light
CompositionLocalProvider(
LocalTheme provides theme,
) {
Surface {
CodeViewerView(codeViewer)
MaterialTheme(
colors = theme.materialColors
) {
Surface {
CodeViewerView(codeViewer)
}
}
}
}

88
examples/codeviewer/shared/src/commonMain/kotlin/org/jetbrains/codeviewer/ui/common/Theme.kt

@ -1,32 +1,76 @@
package org.jetbrains.codeviewer.ui.common
import androidx.compose.material.Colors
import androidx.compose.material.darkColors
import androidx.compose.material.lightColors
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.SpanStyle
object AppTheme {
val colors: Colors = Colors()
@Immutable
data class Theme(
val materialColors: Colors,
val colors: ExtendedColors,
val code: CodeStyle
) {
@Immutable
class ExtendedColors(
val codeGuide: Color
)
val code: Code = Code()
@Immutable
data class CodeStyle(
val simple: SpanStyle,
val value: SpanStyle,
val keyword: SpanStyle,
val punctuation: SpanStyle,
val annotation: SpanStyle,
val comment: SpanStyle
)
class Colors(
val backgroundDark: Color = Color(0xFF2B2B2B),
val backgroundMedium: Color = Color(0xFF3C3F41),
val backgroundLight: Color = Color(0xFF4E5254),
companion object {
val dark = Theme(
materialColors = darkColors(
background = Color(0xFF2B2B2B),
surface = Color(0xFF3C3F41)
),
colors = ExtendedColors(
codeGuide = Color(0xFF4E5254)
),
code = CodeStyle(
simple = SpanStyle(Color(0xFFA9B7C6)),
value = SpanStyle(Color(0xFF6897BB)),
keyword = SpanStyle(Color(0xFFCC7832)),
punctuation = SpanStyle(Color(0xFFA1C17E)),
annotation = SpanStyle(Color(0xFFBBB529)),
comment = SpanStyle(Color(0xFF808080))
)
)
val material: androidx.compose.material.Colors = darkColors(
background = backgroundDark,
surface = backgroundMedium,
primary = Color.White
),
)
val light = Theme(
materialColors = lightColors(
background = Color(0xFFF5F5F5),
surface = Color(0xFFFFFFFF)
),
colors = ExtendedColors(
codeGuide = Color(0xFF8E9294)
),
code = CodeStyle(
simple = SpanStyle(Color(0xFF000000)),
value = SpanStyle(Color(0xFF4A86E8)),
keyword = SpanStyle(Color(0xFF000080)),
punctuation = SpanStyle(Color(0xFFA1A1A1)),
annotation = SpanStyle(Color(0xFFBBB529)),
comment = SpanStyle(Color(0xFF808080))
)
)
}
}
class Code(
val simple: SpanStyle = SpanStyle(Color(0xFFA9B7C6)),
val value: SpanStyle = SpanStyle(Color(0xFF6897BB)),
val keyword: SpanStyle = SpanStyle(Color(0xFFCC7832)),
val punctuation: SpanStyle = SpanStyle(Color(0xFFA1C17E)),
val annotation: SpanStyle = SpanStyle(Color(0xFFBBB529)),
val comment: SpanStyle = SpanStyle(Color(0xFF808080))
)
}
val LocalTheme = staticCompositionLocalOf { Theme.dark }
val AppTheme
@Composable
get() = LocalTheme.current

4
examples/codeviewer/shared/src/commonMain/kotlin/org/jetbrains/codeviewer/ui/editor/EditorTabsView.kt

@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.material.Icon
import androidx.compose.material.LocalContentColor
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
@ -21,7 +22,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import org.jetbrains.codeviewer.ui.common.AppTheme
@Composable
fun EditorTabsView(model: Editors) = Row(Modifier.horizontalScroll(rememberScrollState())) {
@ -33,7 +33,7 @@ fun EditorTabsView(model: Editors) = Row(Modifier.horizontalScroll(rememberScrol
@Composable
fun EditorTabView(model: Editor) = Surface(
color = if (model.isActive) {
AppTheme.colors.backgroundDark
MaterialTheme.colors.background
} else {
Color.Transparent
}

16
examples/codeviewer/shared/src/commonMain/kotlin/org/jetbrains/codeviewer/ui/editor/EditorView.kt

@ -1,13 +1,22 @@
package org.jetbrains.codeviewer.ui.editor
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.text.selection.DisableSelection
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.LocalContentColor
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
@ -37,7 +46,7 @@ fun EditorView(model: Editor, settings: Settings) = key(model) {
SelectionContainer {
Surface(
Modifier.fillMaxSize(),
color = AppTheme.colors.backgroundDark,
color = MaterialTheme.colors.background,
) {
val lines by loadableScoped(model.lines)
@ -51,7 +60,7 @@ fun EditorView(model: Editor, settings: Settings) = key(model) {
)
.width(1.dp)
.fillMaxHeight()
.background(AppTheme.colors.backgroundLight)
.background(AppTheme.colors.codeGuide)
)
}
} else {
@ -143,6 +152,7 @@ private fun LineContent(content: Editor.Content, modifier: Modifier, settings: S
softWrap = false
)
@Composable
private fun codeString(str: String) = buildAnnotatedString {
withStyle(AppTheme.code.simple) {
val strFormatted = str.replace("\t", " ")

15
examples/codeviewer/shared/src/commonMain/kotlin/org/jetbrains/codeviewer/ui/statusbar/StatusBar.kt

@ -1,6 +1,12 @@
package org.jetbrains.codeviewer.ui.statusbar
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
import androidx.compose.material.LocalContentColor
import androidx.compose.material.Slider
import androidx.compose.material.Text
@ -9,7 +15,11 @@ import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.*
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.lerp
import androidx.compose.ui.unit.sp
import org.jetbrains.codeviewer.ui.common.Settings
private val MinFontSize = 6.sp
@ -18,7 +28,6 @@ private val MaxFontSize = 40.sp
@Composable
fun StatusBar(settings: Settings) = Box(
Modifier
.padding(16.dp, 4.dp, 16.dp, 16.dp)
.height(32.dp)
.fillMaxWidth()
) {

4
examples/codeviewer/shared/src/commonMain/kotlin/org/jetbrains/codeviewer/util/VerticalSplittable.kt

@ -7,6 +7,7 @@ import androidx.compose.foundation.gestures.rememberDraggableState
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.width
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@ -19,7 +20,6 @@ import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import org.jetbrains.codeviewer.platform.cursorForHorizontalResize
import org.jetbrains.codeviewer.ui.common.AppTheme
@Composable
fun VerticalSplittable(
@ -60,7 +60,7 @@ class SplitterState {
fun VerticalSplitter(
splitterState: SplitterState,
onResize: (delta: Dp) -> Unit,
color: Color = AppTheme.colors.backgroundDark
color: Color = MaterialTheme.colors.background
) = Box {
val density = LocalDensity.current
Box(

2
examples/codeviewer/shared/src/iosMain/resources/EditorView.kt

@ -48,7 +48,7 @@ fun EditorView(model: Editor, settings: Settings) = key(model) {
)
.width(1.dp)
.fillMaxHeight()
.background(AppTheme.colors.backgroundLight)
.background(AppTheme.colors.codeGuide)
)
}
} else {

Loading…
Cancel
Save