2 Commits

Author SHA1 Message Date
67cd8ee250 Add versioning (WIP)
Some checks failed
Flatpak / Flatpak (push) Failing after 7m42s
Don't upload the artifact; uploading to flathub
will probably need a different approach.
2025-11-03 21:28:27 +01:00
3d6a07e81c Add versioning (WIP)
Some checks failed
Flatpak / Flatpak (push) Failing after 8m4s
* Gradle Git Versioning Plugin
* Changelog
* Flatpack build workflow
2025-11-03 19:22:48 +01:00
13 changed files with 112 additions and 402 deletions

View File

@@ -0,0 +1,35 @@
on:
push:
# TODO: remove versioning branch once everything works
branches: [main,versioning]
tags:
- '[0-9]+.[0-9]+.[0-9]+'
name: Flatpak
jobs:
flatpak:
name: Flatpak
runs-on: ubuntu-latest
container:
image: ghcr.io/flathub-infra/flatpak-github-actions:gnome-48
options: --privileged
steps:
- uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: 21
distribution: 'temurin'
- name: Cache Gradle packages
uses: actions/cache@v4
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle
restore-keys: ${{ runner.os }}-gradle
- name: Build Release Uber JAR
run: ./gradlew packageReleaseUberJarForCurrentOS
- uses: flatpak/flatpak-github-actions/flatpak-builder@v6
with:
bundle: YAEP.flatpak
manifest-path: ./flatpak/ch.dissem.YAEP.yml
cache-key: flatpak-builder-${{ github.sha }}
upload-artifact: false

26
CHANGELOG.md Normal file
View File

@@ -0,0 +1,26 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Added
- Yet Another Einstein Puzzle, for Desktop and not-quite-yet Android
### Changed
### Deprecated
### Removed
### Fixed
### Security
[unreleased]: https://git.dissem.ch/chris/YAEP/compare/1b9c8633c96e479e63afcd7301125ce67247a198...HEAD
[0.0.0]: https://git.dissem.ch/chris/YAEP/releases/tag/0.0.0

View File

@@ -8,6 +8,7 @@ plugins {
alias(libs.plugins.versions) alias(libs.plugins.versions)
alias(libs.plugins.sonarqube) alias(libs.plugins.sonarqube)
alias(libs.plugins.kotlin.kover) alias(libs.plugins.kotlin.kover)
alias(libs.plugins.versioning)
alias(libs.plugins.android.application) apply false alias(libs.plugins.android.application) apply false
alias(libs.plugins.android.library) apply false alias(libs.plugins.android.library) apply false
alias(libs.plugins.compose) apply false alias(libs.plugins.compose) apply false
@@ -17,6 +18,24 @@ plugins {
alias(libs.plugins.kotlin.android) apply false alias(libs.plugins.kotlin.android) apply false
} }
version = "0.0.0-SNAPSHOT"
gitVersioning.apply {
refs {
branch(".+") {
considerTagsOnBranches = true
version = "\${ref}-SNAPSHOT"
}
tag("(?<version>.*)") {
version = "\${ref.version}"
}
}
// optional fallback configuration in case of no matching ref configuration
rev {
version = "\${commit}"
}
}
sonar { sonar {
properties { properties {
property("sonar.projectKey", "YAEP") property("sonar.projectKey", "YAEP")

View File

@@ -1,6 +1,5 @@
package ch.dissem.yaep.ui.common package ch.dissem.yaep.ui.common
import SelectionManager
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -11,23 +10,21 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.TextUnitType import androidx.compose.ui.unit.TextUnitType
import ch.dissem.yaep.domain.Game import ch.dissem.yaep.domain.Game
import focus
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
import kotlin.time.ExperimentalTime import kotlin.time.ExperimentalTime
@Composable @Composable
@OptIn(ExperimentalTime::class) @OptIn(ExperimentalTime::class)
fun App( fun App(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
selectionManager: SelectionManager,
selectDirectly: Boolean, selectDirectly: Boolean,
spacing: Dp, spacing: Dp,
game: Game, game: Game,
@@ -58,14 +55,10 @@ fun App(
AdaptiveGameLayout( AdaptiveGameLayout(
modifier = Modifier.blurOnFinished(isSolved), modifier = Modifier.blurOnFinished(isSolved),
grid = { grid = {
val focusable = remember { selectionManager.add() }
PuzzleGrid( PuzzleGrid(
modifier = Modifier
.focus(focusable),
selectDirectly = selectDirectly,
selectionManager = selectionManager,
grid = game.grid, grid = game.grid,
spacing = spacing, spacing = spacing,
selectDirectly = selectDirectly,
onUpdate = { onUpdate = {
horizontalClues.forEach { it.update(game.grid) } horizontalClues.forEach { it.update(game.grid) }
verticalClues.forEach { it.update(game.grid) } verticalClues.forEach { it.update(game.grid) }
@@ -73,12 +66,9 @@ fun App(
) )
}, },
horizontalClues = { horizontalClues = {
val focusable = remember { selectionManager.add() }
for (clue in horizontalClues) { for (clue in horizontalClues) {
HorizontalClue( HorizontalClue(
modifier = Modifier modifier = Modifier.forClue(clue, spacing),
.focus(focusable)
.forClue(clue, spacing),
spacing = spacing, spacing = spacing,
clue = clue.clue, clue = clue.clue,
isClueViolated = clue.isViolated isClueViolated = clue.isViolated
@@ -86,12 +76,9 @@ fun App(
} }
}, },
verticalClues = { verticalClues = {
val focusable = remember { selectionManager.add() }
for (clue in verticalClues) { for (clue in verticalClues) {
VerticalClue( VerticalClue(
modifier = Modifier modifier = Modifier.forClue(clue, spacing),
.focus(focusable)
.forClue(clue, spacing),
spacing = spacing, spacing = spacing,
clue = clue.clue, clue = clue.clue,
isClueViolated = clue.isViolated isClueViolated = clue.isViolated

View File

@@ -1,6 +1,5 @@
package ch.dissem.yaep.ui.common package ch.dissem.yaep.ui.common
import SelectionManager
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
@@ -13,7 +12,6 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import ch.dissem.yaep.domain.GameCell import ch.dissem.yaep.domain.GameCell
@@ -21,13 +19,11 @@ import ch.dissem.yaep.domain.GameRow
import ch.dissem.yaep.domain.Grid import ch.dissem.yaep.domain.Grid
import ch.dissem.yaep.domain.Item import ch.dissem.yaep.domain.Item
import ch.dissem.yaep.domain.ItemClass import ch.dissem.yaep.domain.ItemClass
import focus
@Composable @Composable
fun PuzzleGrid( fun PuzzleGrid(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
selectDirectly: Boolean, selectDirectly: Boolean,
selectionManager: SelectionManager,
spacing: Dp = 8.dp, spacing: Dp = 8.dp,
grid: Grid, grid: Grid,
onUpdate: () -> Unit onUpdate: () -> Unit
@@ -40,8 +36,7 @@ fun PuzzleGrid(
onSnapshot = { grid.snapshot() }, onSnapshot = { grid.snapshot() },
onUndo = { grid.undo() }, onUndo = { grid.undo() },
spacing = spacing, spacing = spacing,
selectDirectly = selectDirectly, selectDirectly = selectDirectly
selectionManager = selectionManager
) )
} }
} }
@@ -54,20 +49,15 @@ private fun PuzzleRow(
onSnapshot: () -> Unit, onSnapshot: () -> Unit,
onUndo: () -> Boolean, onUndo: () -> Boolean,
spacing: Dp, spacing: Dp,
selectDirectly: Boolean, selectDirectly: Boolean
selectionManager: SelectionManager
) { ) {
val focusableRow = remember { selectionManager.add() }
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.wrapContentHeight() .wrapContentHeight()
) { ) {
val allOptions = row.options val allOptions = row.options
val columnSelectionManager =
remember { focusableRow.createChild(Key.DirectionRight, Key.DirectionLeft) }
for (cell in row) { for (cell in row) {
val focusableItem = remember { columnSelectionManager.add() }
var selection by remember(cell) { mutableStateOf(cell.selection) } var selection by remember(cell) { mutableStateOf(cell.selection) }
val options = remember(cell) { val options = remember(cell) {
allOptions.map { Toggleable(it, cell.options.contains(it)) } allOptions.map { Toggleable(it, cell.options.contains(it)) }
@@ -83,7 +73,6 @@ private fun PuzzleRow(
} }
Selector( Selector(
modifier = Modifier modifier = Modifier
.focus(focusableItem)
.padding(spacing) .padding(spacing)
.weight(1f), .weight(1f),
spacing, spacing,

View File

@@ -1,136 +0,0 @@
package ch.dissem.yaep.ui.common
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedCard
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.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.unit.dp
import ch.dissem.yaep.domain.Clue
import ch.dissem.yaep.domain.Grid
import ch.dissem.yaep.domain.HorizontalClue
import ch.dissem.yaep.domain.NeighbourClue
import ch.dissem.yaep.domain.OrderClue
import ch.dissem.yaep.domain.SameColumnClue
import ch.dissem.yaep.domain.TripletClue
import org.jetbrains.compose.resources.painterResource
import yaep.commonui.generated.resources.Res
import yaep.commonui.generated.resources.neighbour
import yaep.commonui.generated.resources.order
class DisplayClue<C : Clue>(val clue: C) {
var isActive: Boolean by mutableStateOf(true)
var isViolated: Boolean by mutableStateOf(false)
fun update(grid: Grid) {
isViolated = !clue.isValid(grid)
if (isViolated) {
isActive = true
}
}
}
internal fun Modifier.forClue(clue: DisplayClue<out Clue>): Modifier = this
.alpha(if (clue.isActive) 1f else 0.2f)
.padding(8.dp)
.onEitherPointerAction { clue.isActive = !clue.isActive }
@Composable
fun HorizontalClue(
modifier: Modifier = Modifier,
clue: HorizontalClue,
isClueViolated: Boolean
) {
ClueCard(
modifier = modifier,
isClueViolated = isClueViolated
) {
Row {
when (clue) {
is NeighbourClue<*, *> -> {
DrawItem(modifier = Modifier.weight(1f), clue.a)
Image(
modifier = Modifier.aspectRatio(1f).weight(1f),
painter = painterResource(Res.drawable.neighbour),
contentDescription = null
)
DrawItem(modifier = Modifier.weight(1f), clue.b)
}
is OrderClue<*, *> -> {
DrawItem(modifier = Modifier.weight(1f), clue.left)
Image(
modifier = Modifier.aspectRatio(1f).weight(1f),
painter = painterResource(Res.drawable.order),
contentDescription = null
)
DrawItem(modifier = Modifier.weight(1f), clue.right)
}
is TripletClue<*, *, *> -> {
DrawItem(modifier = Modifier.weight(1f), clue.a)
DrawItem(modifier = Modifier.weight(1f), clue.b)
DrawItem(modifier = Modifier.weight(1f), clue.c)
}
}
}
}
}
@Composable
fun VerticalClue(
modifier: Modifier = Modifier,
clue: SameColumnClue<*, *>,
isClueViolated: Boolean = false
) {
ClueCard(
modifier = modifier.aspectRatio(0.5f),
isClueViolated = isClueViolated
) {
Column {
DrawItem(modifier = Modifier.weight(1f), clue.a)
DrawItem(modifier = Modifier.weight(1f), clue.b)
}
}
}
@Composable
fun ClueCard(
modifier: Modifier = Modifier,
isClueViolated: Boolean,
content: @Composable () -> Unit
) {
val colors = MaterialTheme.colorScheme
OutlinedCard(
modifier = if (isClueViolated) {
modifier.shadow(
8.dp,
shape = CardDefaults.outlinedShape,
ambientColor = colors.error,
spotColor = colors.error
)
} else {
modifier
},
border = if (isClueViolated) {
remember { BorderStroke(1.0.dp, colors.error) }
} else {
CardDefaults.outlinedCardBorder()
}
) {
content()
}
}

View File

@@ -1,88 +0,0 @@
package ch.dissem.yaep.ui.common
import SelectionManager
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.unit.dp
import ch.dissem.yaep.domain.Grid
import focus
@Composable
fun PuzzleGrid(
modifier: Modifier = Modifier,
selectionManager: SelectionManager,
grid: Grid,
onUpdate: () -> Unit
) {
Column(modifier = modifier) {
for (row in grid) {
val focusableRow = remember { selectionManager.add() }
Row(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
) {
val allOptions = row.options
val columnSelectionManager =
remember { focusableRow.createChild(Key.DirectionRight, Key.DirectionLeft) }
for (item in row) {
val focusableItem = remember { columnSelectionManager.add() }
var selection by remember(item) { mutableStateOf(item.selection) }
val options = remember(item) {
allOptions.map { Toggleable(it, item.options.contains(it)) }
}
LaunchedEffect(item) {
item.optionsChangedListeners.add { enabled ->
options.forEach { it.enabled = enabled.contains(it.item) }
}
item.selectionChangedListeners.add {
selection = it
onUpdate()
}
}
Selector(
modifier = Modifier
.focus(focusableItem)
.padding(8.dp)
.weight(1f),
options = options,
onOptionRemoved = {
grid.snapshot()
item.options.remove(it)
row.cleanupOptions()
},
onOptionAdded = {
item.options.add(it)
},
selectedItem = selection,
onSelectItem = {
if (it != null) {
grid.snapshot()
item.selection = it
row.cleanupOptions()
} else {
while (item.selection != null) {
if (!grid.undo()) break
}
options.forEach {
it.enabled = item.options.contains(it.item)
}
}
}
)
}
}
}
}
}

View File

@@ -1,128 +0,0 @@
import androidx.compose.foundation.border
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.KeyEvent
import androidx.compose.ui.input.key.KeyEventType
import androidx.compose.ui.input.key.isShiftPressed
import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.key.type
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
import kotlin.IllegalStateException
class SelectionManager(
val keyNext: Key,
val keyPrevious: Key? = null
) {
var isActiveFlow = MutableStateFlow<Boolean>(false)
var isActive: Boolean
get() = isActiveFlow.value
set(value) {
isActiveFlow.value = value
}
var focusedFlow = MutableStateFlow<Focusable?>(null)
var focused: Focusable?
get() = focusedFlow.value
set(value) {
val previous = focusedFlow.value
if (previous != value) {
previous?.child?.isActive = false
value?.child?.isActive = true
}
focusedFlow.value = value
}
val last: Focusable
get() = focused?.previous ?: throw IllegalStateException("not initialized")
val child: SelectionManager?
get() = focused?.child
fun focusNext() {
focused = focused?.next
}
fun focusPrevious() {
focused = focused?.previous
}
fun add(): Focusable {
val new = Focusable(this)
if (focused != null) {
new.next = focused!!
} else {
focused = new
}
return new
}
fun onKeyEvent(event: KeyEvent): Boolean {
if (event.type != KeyEventType.KeyUp) return false
if (event.key == keyNext) {
if (keyPrevious == null && event.isShiftPressed) {
focusPrevious()
} else {
focusNext()
}
} else if (event.key == keyPrevious) {
focusPrevious()
} else {
return child?.onKeyEvent(event) == true
}
return true
}
}
class Focusable(
private val manager: SelectionManager,
) {
val hasFocus: Flow<Boolean> =
combine(manager.isActiveFlow, manager.focusedFlow) { isActive, focused ->
isActive && focused == this
}
var previous: Focusable = this
private set
private var _next: Focusable = this
var next: Focusable
get() = _next
set(value) {
previous = value.previous
previous._next = this
value.previous = this
_next = value
}
var child: SelectionManager? = null
private set
fun createChild(
keyNext: Key,
keyPrevious: Key? = null
): SelectionManager {
child = SelectionManager(keyNext, keyPrevious)
child!!.isActive = manager.isActive && manager.focused == this
return child!!
}
}
@Composable
fun Modifier.focus(holder: Focusable): Modifier = if (holder.hasFocus.collectAsState(false).value) {
border(
width = 2.dp,
color = MaterialTheme.colorScheme.primary,
shape = RectangleShape
)
} else {
this
}

View File

@@ -1,4 +1,6 @@
import org.jetbrains.compose.desktop.application.dsl.TargetFormat import org.jetbrains.compose.desktop.application.dsl.TargetFormat.Deb
import org.jetbrains.compose.desktop.application.dsl.TargetFormat.Dmg
import org.jetbrains.compose.desktop.application.dsl.TargetFormat.Msi
plugins { plugins {
alias(libs.plugins.kotlin.kover) alias(libs.plugins.kotlin.kover)
@@ -29,18 +31,31 @@ compose.desktop {
mainClass = "ch.dissem.yaep.ui.desktop.MainKt" mainClass = "ch.dissem.yaep.ui.desktop.MainKt"
nativeDistributions { nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb) val formats = mutableListOf(Deb)
packageName = "YAEP" packageName = "YAEP"
packageVersion = libs.versions.app.version.name.get() val baseVersion = version.toString()
macOS { packageVersion = baseVersion
iconFile.set(project.file("icon.icns")) if (baseVersion.matches(Regex("[1-9][0-9]*(\\.[0-9]+)(\\.[0-9]+)"))) {
formats.add(Dmg)
macOS {
iconFile.set(project.file("icon.icns"))
}
} }
windows { if (baseVersion.matches(Regex("[1-2]?[0-9]?[0-9]\\.[1-2]?[0-9]?[0-9]\\.[1-6]?[0-9]?[0-9]?[0-9]?[0-9]"))) {
iconFile.set(project.file("icon.ico")) windows {
formats.add(Msi)
iconFile.set(project.file("icon.ico"))
}
} }
linux { linux {
debPackageVersion = if (baseVersion.first().isDigit()) {
baseVersion
} else {
"0-$baseVersion"
}
iconFile.set(project.file("icon.png")) iconFile.set(project.file("icon.png"))
} }
targetFormats(*formats.toTypedArray())
buildTypes.release.proguard { buildTypes.release.proguard {
configurationFiles.from(project.file("proguard-rules.pro")) configurationFiles.from(project.file("proguard-rules.pro"))

View File

@@ -1,6 +1,5 @@
package ch.dissem.yaep.ui.desktop package ch.dissem.yaep.ui.desktop
import SelectionManager
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
@@ -17,8 +16,6 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.scale
import androidx.compose.ui.input.key.onKeyEvent
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.WindowPlacement import androidx.compose.ui.window.WindowPlacement
import androidx.compose.ui.window.WindowScope import androidx.compose.ui.window.WindowScope
@@ -43,13 +40,11 @@ import yaep.desktop.generated.resources.Res as DRes
@Composable @Composable
fun WindowScope.DesktopWindow( fun WindowScope.DesktopWindow(
useDarkMode: Boolean, useDarkMode: Boolean,
selectionManager: SelectionManager,
topBar: @Composable () -> Unit, topBar: @Composable () -> Unit,
content: @Composable (PaddingValues) -> Unit content: @Composable (PaddingValues) -> Unit
) { ) {
AppTheme(darkTheme = useDarkMode) { AppTheme(darkTheme = useDarkMode) {
Scaffold( Scaffold(
modifier = Modifier.onKeyEvent { event -> selectionManager.onKeyEvent(event) },
topBar = { topBar = {
WindowDraggableArea { WindowDraggableArea {
topBar() topBar()

View File

@@ -1,13 +1,11 @@
package ch.dissem.yaep.ui.desktop package ch.dissem.yaep.ui.desktop
import SelectionManager
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
@@ -49,12 +47,10 @@ fun main(): Unit = application {
state = windowState, state = windowState,
icon = painterResource(DRes.drawable.ic_launcher) icon = painterResource(DRes.drawable.ic_launcher)
) { ) {
val selectionManager = remember { SelectionManager(Key.Tab).apply { isActive = true } }
var useDarkMode by remember { mutableStateOf(true) } var useDarkMode by remember { mutableStateOf(true) }
var resetCluesBeacon by remember { mutableStateOf(Any()) } var resetCluesBeacon by remember { mutableStateOf(Any()) }
DesktopWindow( DesktopWindow(
useDarkMode = useDarkMode, useDarkMode = useDarkMode,
selectionManager = selectionManager,
topBar = { topBar = {
AppBar( AppBar(
useDarkMode = useDarkMode, useDarkMode = useDarkMode,
@@ -71,7 +67,6 @@ fun main(): Unit = application {
) { ) {
App( App(
modifier = Modifier.padding(it), modifier = Modifier.padding(it),
selectionManager = selectionManager,
spacing = 8.dp, spacing = 8.dp,
selectDirectly = true, selectDirectly = true,
game = game, game = game,

View File

@@ -81,7 +81,7 @@
<url type="vcs-browser">https://git.dissem.ch/chris/YAEP</url> <url type="vcs-browser">https://git.dissem.ch/chris/YAEP</url>
<releases> <releases>
<release date="2025-11-29" version="1.0.0"> <release date="2025-11-29" version="0.0.0">
<description> <description>
<ul> <ul>
<li>Initial release</li> <li>Initial release</li>

View File

@@ -1,14 +1,14 @@
[versions] [versions]
app-version-code = "1" app-version-code = "1"
app-version-name = "1.0.0" app-version-name = "1.0.0"
agp = "8.13.1" agp = "8.13.0"
jdk = "21" jdk = "21"
android-compileSdk = "36" android-compileSdk = "36"
android-minSdk = "26" android-minSdk = "26"
android-targetSdk = "36" android-targetSdk = "36"
androidx-activityCompose = "1.11.0" androidx-activityCompose = "1.11.0"
androidx-compose = "1.9.4" androidx-compose = "1.9.4"
compose-plugin = "1.9.3" compose-plugin = "1.9.2"
kotlin = "2.2.21" kotlin = "2.2.21"
coreKtx = "1.17.0" coreKtx = "1.17.0"
atrium = "1.2.0" atrium = "1.2.0"
@@ -33,6 +33,7 @@ logging-slf4j = { module = "org.slf4j:slf4j-simple", version = "2.0.17" }
logging = ["logging-jvm", "logging-slf4j"] logging = ["logging-jvm", "logging-slf4j"]
[plugins] [plugins]
versioning = { id = "me.qoomon.git-versioning", version = "6.4.4"}
versions = { id = "com.github.ben-manes.versions", version = "0.53.0" } versions = { id = "com.github.ben-manes.versions", version = "0.53.0" }
android-application = { id = "com.android.application", version.ref = "agp" } android-application = { id = "com.android.application", version.ref = "agp" }
android-library = { id = "com.android.library", version.ref = "agp" } android-library = { id = "com.android.library", version.ref = "agp" }