Codeviewer. Migrate to build154

This commit is contained in:
Igor Demin
2021-02-16 20:07:44 +03:00
parent f9e4f04387
commit e25d74d457
20 changed files with 88 additions and 180 deletions

View File

@@ -22,4 +22,11 @@ android {
dependencies {
implementation(project(":common"))
implementation("androidx.activity:activity-compose:1.3.0-alpha02") {
exclude(group = "androidx.compose.animation")
exclude(group = "androidx.compose.foundation")
exclude(group = "androidx.compose.material")
exclude(group = "androidx.compose.runtime")
exclude(group = "androidx.compose.ui")
}
}

View File

@@ -1,8 +1,8 @@
package org.jetbrains.codeviewer
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.ui.platform.setContent
import org.jetbrains.codeviewer.platform._HomeFolder
import org.jetbrains.codeviewer.ui.MainView
import java.io.File

View File

@@ -9,10 +9,10 @@ buildscript {
dependencies {
// __LATEST_COMPOSE_RELEASE_VERSION__
classpath("org.jetbrains.compose:compose-gradle-plugin:0.3.0-build148")
classpath("org.jetbrains.compose:compose-gradle-plugin:0.3.0-build154")
classpath("com.android.tools.build:gradle:4.0.1")
// __KOTLIN_COMPOSE_VERSION__
classpath(kotlin("gradle-plugin", version = "1.4.21-2"))
classpath(kotlin("gradle-plugin", version = "1.4.30"))
}
}

View File

@@ -1,31 +1,14 @@
package org.jetbrains.codeviewer.platform
import android.graphics.BitmapFactory
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.platform.AmbientContext
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import java.io.InputStream
import java.net.URL
@Composable
actual fun imageResource(res: String): ImageBitmap {
val context = AmbientContext.current
val id = context.resources.getIdentifier(res, "drawable", context.packageName)
return androidx.compose.ui.res.imageResource(id)
}
actual suspend fun imageFromUrl(url: String): ImageBitmap {
val bytes = URL(url).openStream().buffered().use(InputStream::readBytes)
return BitmapFactory.decodeByteArray(bytes, 0, bytes.size).asImageBitmap()
}
@Composable
actual fun Font(name: String, res: String, weight: FontWeight, style: FontStyle): Font {
val context = AmbientContext.current
val context = LocalContext.current
val id = context.resources.getIdentifier(res, "font", context.packageName)
return androidx.compose.ui.text.font.Font(id, weight, style)
return Font(id, weight, style)
}

View File

@@ -1,19 +0,0 @@
package org.jetbrains.codeviewer.platform
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.selection.Selection
import androidx.compose.ui.selection.SelectionContainer
import androidx.compose.ui.text.InternalTextApi
@OptIn(InternalTextApi::class)
@Composable
actual fun SelectionContainer(children: @Composable () -> Unit) {
val selection = remember { mutableStateOf<Selection?>(null) }
SelectionContainer(
selection = selection.value,
onSelectionChange = { selection.value = it },
children = children
)
}

View File

@@ -1,15 +1,9 @@
package org.jetbrains.codeviewer.platform
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
@Composable
expect fun imageResource(res: String): ImageBitmap
expect suspend fun imageFromUrl(url: String): ImageBitmap
@Composable
expect fun Font(name: String, res: String, weight: FontWeight, style: FontStyle): Font

View File

@@ -1,6 +0,0 @@
package org.jetbrains.codeviewer.platform
import androidx.compose.runtime.Composable
@Composable
expect fun SelectionContainer(children: @Composable () -> Unit)

View File

@@ -1,12 +1,13 @@
package org.jetbrains.codeviewer.ui
import androidx.compose.animation.animate
import androidx.compose.animation.core.Spring.StiffnessLow
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.material.AmbientContentColor
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
@@ -31,10 +32,10 @@ fun CodeViewerView(model: CodeViewer) {
val animatedSize = if (panelState.splitter.isResizing) {
if (panelState.isExpanded) panelState.expandedSize else panelState.collapsedSize
} else {
animate(
animateDpAsState(
if (panelState.isExpanded) panelState.expandedSize else panelState.collapsedSize,
SpringSpec(stiffness = StiffnessLow)
)
).value
}
VerticalSplittable(
@@ -82,7 +83,7 @@ private fun ResizablePanel(
state: PanelState,
content: @Composable () -> Unit,
) {
val alpha = animate(if (state.isExpanded) 1f else 0f, SpringSpec(stiffness = StiffnessLow))
val alpha by animateFloatAsState(if (state.isExpanded) 1f else 0f, SpringSpec(stiffness = StiffnessLow))
Box(modifier) {
Box(Modifier.fillMaxSize().graphicsLayer(alpha = alpha)) {
@@ -92,7 +93,7 @@ private fun ResizablePanel(
Icon(
if (state.isExpanded) Icons.Default.ArrowBack else Icons.Default.ArrowForward,
contentDescription = if (state.isExpanded) "Collapse" else "Expand",
tint = AmbientContentColor.current,
tint = LocalContentColor.current,
modifier = Modifier
.padding(top = 4.dp)
.width(24.dp)

View File

@@ -45,6 +45,7 @@ fun Editor(file: File) = Editor(
fun content(index: Int): Editor.Content {
val text = textLines.get(index)
.trim('\r', '\n') // fix for native crash in skia
val state = mutableStateOf(text)
return Editor.Content(state, isCode)
}

View File

@@ -4,8 +4,8 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.AmbientContentColor
import androidx.compose.material.Icon
import androidx.compose.material.LocalContentColor
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Code
@@ -21,13 +21,13 @@ fun EditorEmptyView() = Box(Modifier.fillMaxSize()) {
Icon(
Icons.Default.Code,
contentDescription = null,
tint = AmbientContentColor.current.copy(alpha = 0.60f),
tint = LocalContentColor.current.copy(alpha = 0.60f),
modifier = Modifier.align(Alignment.CenterHorizontally)
)
Text(
"To view file open it from the file tree",
color = AmbientContentColor.current.copy(alpha = 0.60f),
color = LocalContentColor.current.copy(alpha = 0.60f),
fontSize = 20.sp,
modifier = Modifier.align(Alignment.CenterHorizontally).padding(16.dp)
)

View File

@@ -1,19 +1,21 @@
package org.jetbrains.codeviewer.ui.editor
import androidx.compose.animation.animate
import androidx.compose.foundation.ScrollableRow
import androidx.compose.foundation.clickable
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.AmbientContentColor
import androidx.compose.foundation.rememberScrollState
import androidx.compose.material.Icon
import androidx.compose.material.LocalContentColor
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@@ -22,7 +24,7 @@ import androidx.compose.ui.unit.sp
import org.jetbrains.codeviewer.ui.common.AppTheme
@Composable
fun EditorTabsView(model: Editors) = ScrollableRow {
fun EditorTabsView(model: Editors) = Row(Modifier.horizontalScroll(rememberScrollState())) {
for (editor in model.editors) {
EditorTabView(editor)
}
@@ -30,15 +32,15 @@ fun EditorTabsView(model: Editors) = ScrollableRow {
@Composable
fun EditorTabView(model: Editor) = Surface(
color = animate(if (model.isActive) {
color = if (model.isActive) {
AppTheme.colors.backgroundDark
} else {
Color.Transparent
})
}
) {
Row(
Modifier
.clickable {
.clickable(remember(::MutableInteractionSource), indication = null) {
model.activate()
}
.padding(4.dp),
@@ -46,7 +48,7 @@ fun EditorTabView(model: Editor) = Surface(
) {
Text(
model.fileName,
color = AmbientContentColor.current,
color = LocalContentColor.current,
fontSize = 12.sp,
modifier = Modifier.padding(horizontal = 4.dp)
)
@@ -56,7 +58,7 @@ fun EditorTabView(model: Editor) = Surface(
if (close != null) {
Icon(
Icons.Default.Close,
tint = AmbientContentColor.current,
tint = LocalContentColor.current,
contentDescription = "Close",
modifier = Modifier
.size(24.dp)

View File

@@ -2,9 +2,14 @@ package org.jetbrains.codeviewer.ui.editor
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.text.selection.DisableSelection
import androidx.compose.material.*
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.LocalContentColor
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.key
@@ -12,19 +17,16 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.platform.AmbientDensity
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp
import org.jetbrains.codeviewer.platform.SelectionContainer
import org.jetbrains.codeviewer.platform.VerticalScrollbar
import org.jetbrains.codeviewer.ui.common.AppTheme
import org.jetbrains.codeviewer.ui.common.Fonts
import org.jetbrains.codeviewer.ui.common.Settings
import org.jetbrains.codeviewer.util.LazyColumnFor
import org.jetbrains.codeviewer.util.loadableScoped
import org.jetbrains.codeviewer.util.withoutWidthConstraints
import kotlin.text.Regex.Companion.fromLiteral
@@ -65,7 +67,7 @@ fun EditorView(model: Editor, settings: Settings) = key(model) {
}
@Composable
private fun Lines(lines: Editor.Lines, settings: Settings) = with(AmbientDensity.current) {
private fun Lines(lines: Editor.Lines, settings: Settings) = with(LocalDensity.current) {
val maxNum = remember(lines.lineNumberDigitCount) {
(1..lines.lineNumberDigitCount).joinToString(separator = "") { "9" }
}
@@ -74,16 +76,16 @@ private fun Lines(lines: Editor.Lines, settings: Settings) = with(AmbientDensity
val scrollState = rememberLazyListState()
val lineHeight = settings.fontSize.toDp() * 1.6f
LazyColumnFor(
lines.size,
LazyColumn(
modifier = Modifier.fillMaxSize(),
state = scrollState,
itemContent = { index ->
state = scrollState
) {
items(lines.size) { index ->
Box(Modifier.height(lineHeight)) {
Line(Modifier.align(Alignment.CenterStart), maxNum, lines[index], settings)
}
}
)
}
VerticalScrollbar(
Modifier.align(Alignment.CenterEnd),

View File

@@ -2,10 +2,10 @@ package org.jetbrains.codeviewer.ui.filetree
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumnFor
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.AmbientContentColor
import androidx.compose.material.Icon
import androidx.compose.material.LocalContentColor
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
@@ -17,7 +17,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.AmbientDensity
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.TextUnit
@@ -35,7 +35,7 @@ fun FileTreeViewTabView() = Surface {
) {
Text(
"Files",
color = AmbientContentColor.current.copy(alpha = 0.60f),
color = LocalContentColor.current.copy(alpha = 0.60f),
fontSize = 12.sp,
modifier = Modifier.padding(horizontal = 4.dp)
)
@@ -46,18 +46,20 @@ fun FileTreeViewTabView() = Surface {
fun FileTreeView(model: FileTree) = Surface(
modifier = Modifier.fillMaxSize()
) {
with(AmbientDensity.current) {
with(LocalDensity.current) {
Box {
val scrollState = rememberLazyListState()
val fontSize = 14.sp
val lineHeight = fontSize.toDp() * 1.5f
LazyColumnFor(
model.items,
LazyColumn(
modifier = Modifier.fillMaxSize().withoutWidthConstraints(),
state = scrollState,
itemContent = { FileTreeItemView(fontSize, lineHeight, it) }
)
state = scrollState
) {
items(model.items.size) {
FileTreeItemView(fontSize, lineHeight, model.items[it])
}
}
VerticalScrollbar(
Modifier.align(Alignment.CenterEnd),
@@ -83,7 +85,7 @@ private fun FileTreeItemView(fontSize: TextUnit, height: Dp, model: FileTree.Ite
FileItemIcon(Modifier.align(Alignment.CenterVertically), model)
Text(
text = model.name,
color = if (active.value) AmbientContentColor.current.copy(alpha = 0.60f) else AmbientContentColor.current,
color = if (active.value) LocalContentColor.current.copy(alpha = 0.60f) else LocalContentColor.current,
modifier = Modifier
.align(Alignment.CenterVertically)
.clipToBounds()
@@ -110,10 +112,10 @@ private fun FileItemIcon(modifier: Modifier, model: FileTree.Item) = Box(modifie
is FileTree.ItemType.Folder -> when {
!type.canExpand -> Unit
type.isExpanded -> Icon(
Icons.Default.KeyboardArrowDown, contentDescription = null, tint = AmbientContentColor.current
Icons.Default.KeyboardArrowDown, contentDescription = null, tint = LocalContentColor.current
)
else -> Icon(
Icons.Default.KeyboardArrowRight, contentDescription = null, tint = AmbientContentColor.current
Icons.Default.KeyboardArrowRight, contentDescription = null, tint = LocalContentColor.current
)
}
is FileTree.ItemType.File -> when (type.ext) {

View File

@@ -1,14 +1,14 @@
package org.jetbrains.codeviewer.ui.statusbar
import androidx.compose.foundation.layout.*
import androidx.compose.material.AmbientContentColor
import androidx.compose.material.LocalContentColor
import androidx.compose.material.Slider
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Providers
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.AmbientDensity
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.*
import org.jetbrains.codeviewer.ui.common.Settings
@@ -26,13 +26,13 @@ fun StatusBar(settings: Settings) = Box(
Text(
text = "Text size",
modifier = Modifier.align(Alignment.CenterVertically),
color = AmbientContentColor.current.copy(alpha = 0.60f),
color = LocalContentColor.current.copy(alpha = 0.60f),
fontSize = 12.sp
)
Spacer(Modifier.width(8.dp))
Providers(AmbientDensity provides AmbientDensity.current.scale(0.5f)) {
CompositionLocalProvider(LocalDensity provides LocalDensity.current.scale(0.5f)) {
Slider(
(settings.fontSize - MinFontSize) / (MaxFontSize - MinFontSize),
onValueChange = { settings.fontSize = lerp(MinFontSize, MaxFontSize, it) },

View File

@@ -1,33 +0,0 @@
package org.jetbrains.codeviewer.util
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.lazy.LazyColumnForIndexed
import androidx.compose.foundation.lazy.LazyItemScope
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun LazyColumnFor(
size: Int,
modifier: Modifier = Modifier,
state: LazyListState = rememberLazyListState(),
contentPadding: PaddingValues = PaddingValues(0.dp),
horizontalAlignment: Alignment.Horizontal = Alignment.Start,
itemContent: @Composable LazyItemScope.(index: Int) -> Unit
) = LazyColumnForIndexed(
items = UnitList(size),
modifier = modifier,
state = state,
contentPadding = contentPadding,
horizontalAlignment = horizontalAlignment,
) { index, _ ->
itemContent(index)
}
private class UnitList(override val size: Int) : AbstractList<Unit>() {
override fun get(index: Int) = Unit
}

View File

@@ -1,7 +1,9 @@
package org.jetbrains.codeviewer.util
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.draggable
import androidx.compose.foundation.gestures.rememberDraggableState
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.width
@@ -10,9 +12,9 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.gesture.scrollorientationlocking.Orientation
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
@@ -28,7 +30,7 @@ fun VerticalSplittable(
) = Layout({
children()
VerticalSplitter(splitterState, onResize)
}, modifier, measureBlock = { measurables, constraints ->
}, modifier, measurePolicy = { measurables, constraints ->
require(measurables.size == 3)
val firstPlaceable = measurables[0].measure(constraints.copy(minWidth = 0))
@@ -60,6 +62,7 @@ fun VerticalSplitter(
onResize: (delta: Dp) -> Unit,
color: Color = AppTheme.colors.backgroundDark
) = Box {
val density = LocalDensity.current
Box(
Modifier
.width(8.dp)
@@ -67,14 +70,16 @@ fun VerticalSplitter(
.run {
if (splitterState.isResizeEnabled) {
this.draggable(
Orientation.Horizontal,
state = rememberDraggableState {
with(density) {
onResize(it.toDp())
}
},
orientation = Orientation.Horizontal,
startDragImmediately = true,
onDragStarted = { splitterState.isResizing = true },
onDragStopped = { splitterState.isResizing = false }
) {
onResize(it.toDp())
}
.cursorForHorizontalResize()
).cursorForHorizontalResize()
} else {
this
}

View File

@@ -1,6 +1,6 @@
package org.jetbrains.codeviewer.platform
import androidx.compose.desktop.AppWindowAmbient
import androidx.compose.desktop.LocalAppWindow
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -21,9 +21,9 @@ actual fun Modifier.cursorForHorizontalResize(): Modifier = composed {
var isHover by remember { mutableStateOf(false) }
if (isHover) {
AppWindowAmbient.current!!.window.cursor = Cursor(Cursor.E_RESIZE_CURSOR)
LocalAppWindow.current.window.cursor = Cursor(Cursor.E_RESIZE_CURSOR)
} else {
AppWindowAmbient.current!!.window.cursor = Cursor.getDefaultCursor()
LocalAppWindow.current.window.cursor = Cursor.getDefaultCursor()
}
pointerMoveFilter(

View File

@@ -1,24 +1,9 @@
package org.jetbrains.codeviewer.platform
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.jetbrains.skija.Image
import java.io.InputStream
import java.net.URL
@Composable
actual fun imageResource(res: String) = androidx.compose.ui.res.imageResource("drawable/$res.png")
actual suspend fun imageFromUrl(url: String): ImageBitmap = withContext(Dispatchers.IO) {
val bytes = URL(url).openStream().buffered().use(InputStream::readBytes)
Image.makeFromEncoded(bytes).asImageBitmap()
}
@Composable
actual fun Font(name: String, res: String, weight: FontWeight, style: FontStyle): Font =

View File

@@ -1,9 +0,0 @@
package org.jetbrains.codeviewer.platform
import androidx.compose.foundation.text.selection.DesktopSelectionContainer
import androidx.compose.runtime.Composable
@Composable
actual fun SelectionContainer(children: @Composable () -> Unit) {
DesktopSelectionContainer(content = children)
}

View File

@@ -1,24 +1,17 @@
package org.jetbrains.codeviewer
import androidx.compose.desktop.Window
import androidx.compose.foundation.layout.ExperimentalLayout
import androidx.compose.ui.unit.IntSize
import org.jetbrains.codeviewer.ui.MainView
import java.awt.image.BufferedImage
import javax.imageio.ImageIO
import javax.swing.SwingUtilities.invokeLater
@OptIn(ExperimentalLayout::class)
fun main() {
invokeLater {
Window(
title = "Code Viewer",
size = IntSize(1280, 768),
icon = loadImageResource("ic_launcher.png")
) {
MainView()
}
}
fun main() = Window(
title = "Code Viewer",
size = IntSize(1280, 768),
icon = loadImageResource("ic_launcher.png"),
) {
MainView()
}