mirror of
https://github.com/jlengrand/compose-multiplatform.git
synced 2026-03-10 15:48:51 +00:00
Updated ImageViewer to 0.5.0-build270
This commit is contained in:
@@ -1,27 +1,23 @@
|
||||
buildscript {
|
||||
val composeVersion = System.getenv("COMPOSE_TEMPLATE_COMPOSE_VERSION") ?: "0.5.0-build270"
|
||||
|
||||
repositories {
|
||||
mavenLocal().mavenContent {
|
||||
includeModule("org.jetbrains.compose", "compose-gradle-plugin")
|
||||
}
|
||||
google()
|
||||
mavenCentral()
|
||||
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// __LATEST_COMPOSE_RELEASE_VERSION__
|
||||
classpath("org.jetbrains.compose:compose-gradle-plugin:0.4.0")
|
||||
classpath("org.jetbrains.compose:compose-gradle-plugin:$composeVersion")
|
||||
classpath("com.android.tools.build:gradle:4.0.1")
|
||||
// __KOTLIN_COMPOSE_VERSION__
|
||||
classpath(kotlin("gradle-plugin", version = "1.5.10"))
|
||||
classpath(kotlin("gradle-plugin", version = "1.5.21"))
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
google()
|
||||
mavenCentral()
|
||||
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package example.imageviewer.model
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.RememberObserver
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.window.WindowState
|
||||
import example.imageviewer.ResString
|
||||
import example.imageviewer.core.FilterType
|
||||
import example.imageviewer.model.filtration.FiltersManager
|
||||
@@ -19,10 +20,12 @@ import javax.swing.SwingUtilities.invokeLater
|
||||
|
||||
object ContentState : RememberObserver {
|
||||
|
||||
lateinit var windowState: WindowState
|
||||
private lateinit var repository: ImageRepository
|
||||
private lateinit var uriRepository: String
|
||||
|
||||
fun applyContent(uriRepository: String): ContentState {
|
||||
fun applyContent(state: WindowState, uriRepository: String): ContentState {
|
||||
windowState = state
|
||||
if (this::uriRepository.isInitialized && this.uriRepository == uriRepository) {
|
||||
return this
|
||||
}
|
||||
|
||||
@@ -1,58 +1,42 @@
|
||||
package example.imageviewer.style
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.res.imageResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import java.awt.image.BufferedImage
|
||||
import javax.imageio.ImageIO
|
||||
|
||||
@Composable
|
||||
fun icEmpty() = imageResource("images/empty.png")
|
||||
fun icEmpty() = painterResource("images/empty.png")
|
||||
|
||||
@Composable
|
||||
fun icBack() = imageResource("images/back.png")
|
||||
fun icBack() = painterResource("images/back.png")
|
||||
|
||||
@Composable
|
||||
fun icRefresh() = imageResource("images/refresh.png")
|
||||
fun icRefresh() = painterResource("images/refresh.png")
|
||||
|
||||
@Composable
|
||||
fun icDots() = imageResource("images/dots.png")
|
||||
fun icDots() = painterResource("images/dots.png")
|
||||
|
||||
@Composable
|
||||
fun icFilterGrayscaleOn() = imageResource("images/grayscale_on.png")
|
||||
fun icFilterGrayscaleOn() = painterResource("images/grayscale_on.png")
|
||||
|
||||
@Composable
|
||||
fun icFilterGrayscaleOff() = imageResource("images/grayscale_off.png")
|
||||
fun icFilterGrayscaleOff() = painterResource("images/grayscale_off.png")
|
||||
|
||||
@Composable
|
||||
fun icFilterPixelOn() = imageResource("images/pixel_on.png")
|
||||
fun icFilterPixelOn() = painterResource("images/pixel_on.png")
|
||||
|
||||
@Composable
|
||||
fun icFilterPixelOff() = imageResource("images/pixel_off.png")
|
||||
fun icFilterPixelOff() = painterResource("images/pixel_off.png")
|
||||
|
||||
@Composable
|
||||
fun icFilterBlurOn() = imageResource("images/blur_on.png")
|
||||
fun icFilterBlurOn() = painterResource("images/blur_on.png")
|
||||
|
||||
@Composable
|
||||
fun icFilterBlurOff() = imageResource("images/blur_off.png")
|
||||
fun icFilterBlurOff() = painterResource("images/blur_off.png")
|
||||
|
||||
@Composable
|
||||
fun icFilterUnknown() = imageResource("images/filter_unknown.png")
|
||||
fun icFilterUnknown() = painterResource("images/filter_unknown.png")
|
||||
|
||||
private var icon: BufferedImage? = null
|
||||
fun icAppRounded(): BufferedImage {
|
||||
if (icon != null) {
|
||||
return icon!!
|
||||
}
|
||||
try {
|
||||
val imageRes = "images/ic_imageviewer_round.png"
|
||||
val img = Thread.currentThread().contextClassLoader.getResource(imageRes)
|
||||
val bitmap: BufferedImage? = ImageIO.read(img)
|
||||
if (bitmap != null) {
|
||||
icon = bitmap
|
||||
return bitmap
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB)
|
||||
}
|
||||
@Composable
|
||||
fun icAppRounded() = painterResource("images/ic_imageviewer_round.png")
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
package example.imageviewer.utils
|
||||
|
||||
import androidx.compose.desktop.AppManager
|
||||
import androidx.compose.desktop.AppWindow
|
||||
import androidx.compose.desktop.WindowEvents
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.IntSize
|
||||
import androidx.compose.ui.window.v1.MenuBar
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.swing.Swing
|
||||
import java.awt.image.BufferedImage
|
||||
|
||||
fun Application(
|
||||
content: @Composable ApplicationScope.() -> Unit
|
||||
) {
|
||||
GlobalScope.launch(Dispatchers.Swing + ImmediateFrameClock()) {
|
||||
AppManager.setEvents(onWindowsEmpty = null)
|
||||
|
||||
withRunningRecomposer { recomposer ->
|
||||
val latch = CompletableDeferred<Unit>()
|
||||
val applier = ApplicationApplier { latch.complete(Unit) }
|
||||
|
||||
val composition = Composition(applier, recomposer)
|
||||
try {
|
||||
val scope = ApplicationScope(recomposer)
|
||||
|
||||
composition.setContent { scope.content() }
|
||||
|
||||
latch.join()
|
||||
} finally {
|
||||
composition.dispose()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ApplicationScope internal constructor(private val recomposer: Recomposer) {
|
||||
@Composable
|
||||
fun ComposableWindow(
|
||||
title: String = "JetpackDesktopWindow",
|
||||
size: IntSize = IntSize(800, 600),
|
||||
location: IntOffset = IntOffset.Zero,
|
||||
centered: Boolean = true,
|
||||
icon: BufferedImage? = null,
|
||||
menuBar: MenuBar? = null,
|
||||
undecorated: Boolean = false,
|
||||
resizable: Boolean = true,
|
||||
events: WindowEvents = WindowEvents(),
|
||||
onDismissRequest: (() -> Unit)? = null,
|
||||
content: @Composable () -> Unit = {}
|
||||
) {
|
||||
var isOpened by remember { mutableStateOf(true) }
|
||||
if (!isOpened) return
|
||||
ComposeNode<AppWindow, ApplicationApplier>(
|
||||
factory = {
|
||||
val window = AppWindow(
|
||||
title = title,
|
||||
size = size,
|
||||
location = location,
|
||||
centered = centered,
|
||||
icon = icon,
|
||||
menuBar = menuBar,
|
||||
undecorated = undecorated,
|
||||
resizable = resizable,
|
||||
events = events,
|
||||
onDismissRequest = {
|
||||
onDismissRequest?.invoke()
|
||||
isOpened = false
|
||||
}
|
||||
)
|
||||
window.show(recomposer, content)
|
||||
window
|
||||
},
|
||||
update = {
|
||||
set(title) { setTitle(it) }
|
||||
set(size) { setSize(it.width, it.height) }
|
||||
// set(location) { setLocation(it.x, it.y) }
|
||||
set(icon) { setIcon(it) }
|
||||
// set(menuBar) { if (it != null) setMenuBar(it) else removeMenuBar() }
|
||||
// set(resizable) { setResizable(it) }
|
||||
// set(events) { setEvents(it) }
|
||||
// set(onDismissRequest) { setDismiss(it) }
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class ImmediateFrameClock : MonotonicFrameClock {
|
||||
override suspend fun <R> withFrameNanos(
|
||||
onFrame: (frameTimeNanos: Long) -> R
|
||||
) = onFrame(System.nanoTime())
|
||||
}
|
||||
|
||||
private class ApplicationApplier(
|
||||
private val onWindowsEmpty: () -> Unit
|
||||
) : Applier<AppWindow?> {
|
||||
private val windows = mutableListOf<AppWindow>()
|
||||
|
||||
override var current: AppWindow? = null
|
||||
|
||||
override fun insertBottomUp(index: Int, instance: AppWindow?) {
|
||||
requireNotNull(instance)
|
||||
check(current == null) { "Windows cannot be nested!" }
|
||||
windows.add(index, instance)
|
||||
}
|
||||
|
||||
override fun remove(index: Int, count: Int) {
|
||||
repeat(count) {
|
||||
val window = windows.removeAt(index)
|
||||
if (!window.isClosed) {
|
||||
window.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun move(from: Int, to: Int, count: Int) {
|
||||
if (from > to) {
|
||||
var current = to
|
||||
repeat(count) {
|
||||
val node = windows.removeAt(from)
|
||||
windows.add(current, node)
|
||||
current++
|
||||
}
|
||||
} else {
|
||||
repeat(count) {
|
||||
val node = windows.removeAt(from)
|
||||
windows.add(to - 1, node)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun clear() {
|
||||
windows.forEach { if (!it.isClosed) it.close() }
|
||||
windows.clear()
|
||||
}
|
||||
|
||||
override fun onEndChanges() {
|
||||
if (windows.isEmpty()) {
|
||||
onWindowsEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
override fun down(node: AppWindow?) {
|
||||
requireNotNull(node)
|
||||
check(current == null) { "Windows cannot be nested!" }
|
||||
current = node
|
||||
}
|
||||
|
||||
override fun up() {
|
||||
check(current != null) { "Windows cannot be nested!" }
|
||||
current = null
|
||||
}
|
||||
|
||||
override fun insertTopDown(index: Int, instance: AppWindow?) {
|
||||
// ignored. Building tree bottom-up
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package example.imageviewer.utils
|
||||
|
||||
import androidx.compose.desktop.AppManager
|
||||
import androidx.compose.ui.unit.IntSize
|
||||
import androidx.compose.ui.window.WindowSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
import java.awt.Dimension
|
||||
import java.awt.Graphics2D
|
||||
import java.awt.Rectangle
|
||||
@@ -38,10 +38,10 @@ fun scaleBitmapAspectRatio(
|
||||
return result
|
||||
}
|
||||
|
||||
fun getDisplayBounds(bitmap: BufferedImage): Rectangle {
|
||||
fun getDisplayBounds(bitmap: BufferedImage, windowSize: WindowSize): Rectangle {
|
||||
|
||||
val boundW: Float = displayWidth().toFloat()
|
||||
val boundH: Float = displayHeight().toFloat()
|
||||
val boundW: Float = windowSize.width.value.toFloat()
|
||||
val boundH: Float = windowSize.height.value.toFloat()
|
||||
|
||||
val ratioX: Float = bitmap.width / boundW
|
||||
val ratioY: Float = bitmap.height / boundH
|
||||
@@ -108,22 +108,6 @@ fun applyBlurFilter(bitmap: BufferedImage): BufferedImage {
|
||||
)
|
||||
}
|
||||
|
||||
fun displayWidth(): Int {
|
||||
val window = AppManager.focusedWindow
|
||||
if (window != null) {
|
||||
return window.width
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
fun displayHeight(): Int {
|
||||
val window = AppManager.focusedWindow
|
||||
if (window != null) {
|
||||
return window.height
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
fun toByteArray(bitmap: BufferedImage) : ByteArray {
|
||||
val baos = ByteArrayOutputStream()
|
||||
ImageIO.write(bitmap, "png", baos)
|
||||
@@ -134,11 +118,11 @@ fun cropImage(bitmap: BufferedImage, crop: Rectangle) : BufferedImage {
|
||||
return bitmap.getSubimage(crop.x, crop.y, crop.width, crop.height)
|
||||
}
|
||||
|
||||
fun getPreferredWindowSize(desiredWidth: Int, desiredHeight: Int): IntSize {
|
||||
fun getPreferredWindowSize(desiredWidth: Int, desiredHeight: Int): WindowSize {
|
||||
val screenSize: Dimension = Toolkit.getDefaultToolkit().screenSize
|
||||
val preferredWidth: Int = (screenSize.width * 0.8f).toInt()
|
||||
val preferredHeight: Int = (screenSize.height * 0.8f).toInt()
|
||||
val width: Int = if (desiredWidth < preferredWidth) desiredWidth else preferredWidth
|
||||
val height: Int = if (desiredHeight < preferredHeight) desiredHeight else preferredHeight
|
||||
return IntSize(width, height)
|
||||
return WindowSize(width.dp, height.dp)
|
||||
}
|
||||
|
||||
@@ -25,13 +25,19 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.input.key.Key
|
||||
import androidx.compose.ui.input.key.shortcuts
|
||||
import androidx.compose.ui.input.key.key
|
||||
import androidx.compose.ui.input.key.type
|
||||
import androidx.compose.ui.input.key.KeyEventType
|
||||
import androidx.compose.ui.input.key.onPreviewKeyEvent
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.WindowSize
|
||||
import example.imageviewer.core.FilterType
|
||||
import example.imageviewer.model.AppState
|
||||
import example.imageviewer.model.ContentState
|
||||
@@ -50,11 +56,9 @@ import example.imageviewer.style.icFilterGrayscaleOn
|
||||
import example.imageviewer.style.icFilterPixelOff
|
||||
import example.imageviewer.style.icFilterPixelOn
|
||||
import example.imageviewer.utils.cropImage
|
||||
import example.imageviewer.utils.displayWidth
|
||||
import example.imageviewer.utils.getDisplayBounds
|
||||
import example.imageviewer.utils.toByteArray
|
||||
import java.awt.Rectangle
|
||||
import java.awt.event.KeyEvent
|
||||
import java.awt.image.BufferedImage
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.roundToInt
|
||||
@@ -192,7 +196,7 @@ fun FilterButton(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun getFilterImage(type: FilterType, content: ContentState): ImageBitmap {
|
||||
fun getFilterImage(type: FilterType, content: ContentState): Painter {
|
||||
|
||||
return when (type) {
|
||||
FilterType.GrayScale -> if (content.isFilterEnabled(type)) icFilterGrayscaleOn() else icFilterGrayscaleOff()
|
||||
@@ -201,6 +205,7 @@ fun getFilterImage(type: FilterType, content: ContentState): ImageBitmap {
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalComposeUiApi::class)
|
||||
@Composable
|
||||
fun setImage(content: ContentState) {
|
||||
val drag = remember { DragHandler() }
|
||||
@@ -214,13 +219,14 @@ fun setImage(content: ContentState) {
|
||||
Zoomable(
|
||||
onScale = scale,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
.shortcuts {
|
||||
on(Key(KeyEvent.VK_LEFT)) {
|
||||
content.swipePrevious()
|
||||
}
|
||||
on(Key(KeyEvent.VK_RIGHT)) {
|
||||
content.swipeNext()
|
||||
.onPreviewKeyEvent {
|
||||
if (it.type == KeyEventType.KeyUp) {
|
||||
when (it.key) {
|
||||
Key.DirectionLeft -> content.swipePrevious()
|
||||
Key.DirectionRight -> content.swipeNext()
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
) {
|
||||
val bitmap = imageByGesture(content, scale, drag)
|
||||
@@ -240,15 +246,20 @@ fun imageByGesture(
|
||||
scale: ScaleHandler,
|
||||
drag: DragHandler
|
||||
): ImageBitmap {
|
||||
val bitmap = cropBitmapByScale(content.getSelectedImage(), scale.factor.value, drag)
|
||||
val bitmap = cropBitmapByScale(content.getSelectedImage(), content.windowState.size, scale.factor.value, drag)
|
||||
return org.jetbrains.skija.Image.makeFromEncoded(toByteArray(bitmap)).asImageBitmap()
|
||||
}
|
||||
|
||||
private fun cropBitmapByScale(bitmap: BufferedImage, scale: Float, drag: DragHandler): BufferedImage {
|
||||
|
||||
private fun cropBitmapByScale(
|
||||
bitmap: BufferedImage,
|
||||
size: WindowSize,
|
||||
scale: Float,
|
||||
drag: DragHandler
|
||||
): BufferedImage {
|
||||
val crop = cropBitmapByBounds(
|
||||
bitmap,
|
||||
getDisplayBounds(bitmap),
|
||||
getDisplayBounds(bitmap, size),
|
||||
size,
|
||||
scale,
|
||||
drag
|
||||
)
|
||||
@@ -261,6 +272,7 @@ private fun cropBitmapByScale(bitmap: BufferedImage, scale: Float, drag: DragHan
|
||||
private fun cropBitmapByBounds(
|
||||
bitmap: BufferedImage,
|
||||
bounds: Rectangle,
|
||||
size: WindowSize,
|
||||
scaleFactor: Float,
|
||||
drag: DragHandler
|
||||
): Rectangle {
|
||||
@@ -274,7 +286,7 @@ private fun cropBitmapByBounds(
|
||||
var boundW = (bounds.width / scale).roundToInt()
|
||||
var boundH = (bounds.height / scale).roundToInt()
|
||||
|
||||
scale *= displayWidth() / bounds.width.toDouble()
|
||||
scale *= size.width.value / bounds.width.toDouble()
|
||||
|
||||
val offsetX = drag.getAmount().x / scale
|
||||
val offsetY = drag.getAmount().y / scale
|
||||
|
||||
@@ -35,8 +35,9 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.RectangleShape
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import androidx.compose.ui.graphics.painter.BitmapPainter
|
||||
import androidx.compose.ui.graphics.RectangleShape
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.unit.dp
|
||||
import example.imageviewer.ResString
|
||||
@@ -165,9 +166,9 @@ fun setPreviewImageUI(content: ContentState) {
|
||||
Image(
|
||||
if (content.isMainImageEmpty())
|
||||
icEmpty()
|
||||
else org.jetbrains.skija.Image.makeFromEncoded(
|
||||
else BitmapPainter(org.jetbrains.skija.Image.makeFromEncoded(
|
||||
toByteArray(content.getSelectedImage())
|
||||
).asImageBitmap(),
|
||||
).asImageBitmap()),
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth().padding(start = 1.dp, top = 1.dp, end = 1.dp, bottom = 5.dp),
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
package example.imageviewer.view
|
||||
|
||||
import androidx.compose.foundation.focusable
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.material.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusModifier
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.input.key.Key
|
||||
import androidx.compose.ui.input.key.shortcuts
|
||||
import androidx.compose.ui.input.key.key
|
||||
import androidx.compose.ui.input.key.type
|
||||
import androidx.compose.ui.input.key.KeyEventType
|
||||
import androidx.compose.ui.input.key.onPreviewKeyEvent
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import example.imageviewer.style.Transparent
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
|
||||
@OptIn(ExperimentalComposeUiApi::class)
|
||||
@Composable
|
||||
fun Zoomable(
|
||||
onScale: ScaleHandler,
|
||||
@@ -24,19 +29,18 @@ fun Zoomable(
|
||||
|
||||
Surface(
|
||||
color = Transparent,
|
||||
modifier = modifier.shortcuts {
|
||||
on(Key.I) {
|
||||
onScale.onScale(1.2f)
|
||||
}
|
||||
on(Key.O) {
|
||||
onScale.onScale(0.8f)
|
||||
}
|
||||
on(Key.R) {
|
||||
onScale.resetFactor()
|
||||
modifier = modifier.onPreviewKeyEvent {
|
||||
if (it.type == KeyEventType.KeyUp) {
|
||||
when (it.key) {
|
||||
Key.I -> onScale.onScale(1.2f)
|
||||
Key.O -> onScale.onScale(0.8f)
|
||||
Key.R -> onScale.resetFactor()
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
.focusRequester(focusRequester)
|
||||
.focusModifier()
|
||||
.focusable()
|
||||
.pointerInput(Unit) {
|
||||
detectTapGestures(onDoubleTap = { onScale.resetFactor() }) {
|
||||
focusRequester.requestFocus()
|
||||
|
||||
@@ -1,47 +1,58 @@
|
||||
package example.imageviewer
|
||||
|
||||
import androidx.compose.desktop.DesktopTheme
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.window.Window
|
||||
import androidx.compose.ui.window.WindowState
|
||||
import androidx.compose.ui.window.WindowPosition
|
||||
import androidx.compose.ui.window.application
|
||||
import androidx.compose.ui.window.rememberWindowState
|
||||
import example.imageviewer.model.ContentState
|
||||
import example.imageviewer.style.icAppRounded
|
||||
import example.imageviewer.utils.Application
|
||||
import example.imageviewer.utils.getPreferredWindowSize
|
||||
import example.imageviewer.view.BuildAppUI
|
||||
import example.imageviewer.view.SplashUI
|
||||
|
||||
fun main() = Application {
|
||||
fun main() = application {
|
||||
val state = rememberWindowState()
|
||||
val content = remember {
|
||||
ContentState.applyContent(
|
||||
state,
|
||||
"https://raw.githubusercontent.com/JetBrains/compose-jb/master/artwork/imageviewerrepo/fetching.list"
|
||||
)
|
||||
}
|
||||
|
||||
val icon = remember(::icAppRounded)
|
||||
val icon = icAppRounded()
|
||||
|
||||
if (content.isAppReady()) {
|
||||
ComposableWindow(
|
||||
Window(
|
||||
onCloseRequest = ::exitApplication,
|
||||
title = "Image Viewer",
|
||||
size = getPreferredWindowSize(800, 1000),
|
||||
state = WindowState(
|
||||
position = WindowPosition.Aligned(Alignment.Center),
|
||||
size = getPreferredWindowSize(800, 1000)
|
||||
),
|
||||
icon = icon
|
||||
) {
|
||||
MaterialTheme {
|
||||
DesktopTheme {
|
||||
BuildAppUI(content)
|
||||
}
|
||||
BuildAppUI(content)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ComposableWindow(
|
||||
Window(
|
||||
onCloseRequest = ::exitApplication,
|
||||
title = "Image Viewer",
|
||||
size = getPreferredWindowSize(800, 300),
|
||||
state = WindowState(
|
||||
position = WindowPosition.Aligned(Alignment.Center),
|
||||
size = getPreferredWindowSize(800, 300)
|
||||
),
|
||||
undecorated = true,
|
||||
icon = icon,
|
||||
) {
|
||||
MaterialTheme {
|
||||
DesktopTheme {
|
||||
SplashUI()
|
||||
}
|
||||
SplashUI()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user