Skip to content

Commit

Permalink
Feat: Allow creating instance with custom .minecraft directory
Browse files Browse the repository at this point in the history
Feat: Fullscreen mode
Feat: Buttons to open some common directories
Improvement: Use trailing icon button for choosing jvm path
Fix: Play button on home screen getting squished when title or desc too long
Feat: List user mods as a category
  • Loading branch information
0ffz committed Mar 12, 2024
1 parent 59f9f90 commit ef8c560
Show file tree
Hide file tree
Showing 23 changed files with 407 additions and 172 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
group=com.mineinabyss
version=2.0.0-alpha.12
version=2.0.0-alpha.13
idofrontVersion=0.22.3
3 changes: 2 additions & 1 deletion src/main/kotlin/com/mineinabyss/launchy/data/Dirs.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ object Dirs {

val modpackConfigsDir = (config / "modpacks")

fun modpackDir(string: String) = mineinabyss / "modpacks" / string
val modpacksDir = mineinabyss / "modpacks"
fun modpackDir(string: String) = modpacksDir / string
fun modpackConfigDir(name: String) = modpackConfigsDir / name

fun createDirs() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ data class Config(
val memoryAllocation: Int? = null,
val useRecommendedJvmArguments: Boolean = true,
val preferHue: Float? = null,
val startInFullscreen: Boolean = false,
) {
fun save() {
Dirs.configFile.writeText(Formats.yaml.encodeToString(this))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import kotlin.io.path.inputStream
import kotlin.io.path.outputStream

@Serializable
@OptIn(ExperimentalStdlibApi::class)
data class GameInstanceConfig(
val name: String,
val description: String,
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/com/mineinabyss/launchy/logic/Auth.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ object Auth {
profile,
onVerificationRequired = {
state.inProgressTasks.remove("auth")
Browser.browse(it.redirectTo)
DesktopHelpers.browse(it.redirectTo)
profile.authCode = it.code
dialog = Dialog.Auth
println(profile.authCode)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ package com.mineinabyss.launchy.logic
import com.mineinabyss.launchy.util.OS
import java.awt.Desktop
import java.net.URI
import java.nio.file.Path

object Browser {
object DesktopHelpers {
val desktop = Desktop.getDesktop()
fun browse(url: String): Result<*> = synchronized(desktop) {
val os = OS.get()
Expand All @@ -17,4 +18,16 @@ object Browser {
}
}
}

fun openDirectory(path: Path) {
val os = OS.get()
runCatching {
when {
Desktop.isDesktopSupported() && desktop.isSupported(Desktop.Action.OPEN) -> desktop.open(path.toFile())
os == OS.LINUX -> Runtime.getRuntime().exec("xdg-open $path")
os == OS.MAC -> Runtime.getRuntime().exec("open $path")
else -> error("Unsupported OS")
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,8 @@ object ModDownloader {
/**
* Updates mod loader versions and mods to latest modpack definition.
*/
suspend fun ModpackState.startInstall(state: LaunchyState, ignoreCachedCheck: Boolean = false) = coroutineScope {
suspend fun ModpackState.startInstall(state: LaunchyState, ignoreCachedCheck: Boolean = false): Result<*> =
coroutineScope {
userAgreedDeps = modpack.modLoaders
ensureDependenciesReady(state)
copyOverrides(state)
Expand Down Expand Up @@ -190,11 +191,13 @@ object ModDownloader {
saveToConfig()

if (queued.modDownloadInfo.any { it.value.hashCheck != HashCheck.VERIFIED }) {
error("Hash check failed on one or more downloads downloads, please re-run the installer!")
return@coroutineScope Result.failure(Exception("Failed to verify hashes"))
}

copyMods()

saveToConfig()

return@coroutineScope Result.success(Unit)
}
}
5 changes: 3 additions & 2 deletions src/main/kotlin/com/mineinabyss/launchy/state/LaunchyState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class LaunchyState(
var modpackState: ModpackState? by mutableStateOf(null)
private val launchedProcesses = mutableStateMapOf<String, Process>()
val jvm = JvmState(config)
var preferHue: Float by mutableStateOf(config.preferHue ?: 0f)
val ui = UIState(config)

val gameInstances = mutableStateListOf<GameInstance>().apply {
addAll(instances)
Expand Down Expand Up @@ -45,7 +45,8 @@ class LaunchyState(
jvmArguments = jvm.userJvmArgs,
memoryAllocation = jvm.userMemoryAllocation,
useRecommendedJvmArguments = jvm.useRecommendedJvmArgs,
preferHue = preferHue,
preferHue = ui.preferHue,
startInFullscreen = ui.fullscreen
).save()
}

Expand Down
11 changes: 11 additions & 0 deletions src/main/kotlin/com/mineinabyss/launchy/state/UIState.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.mineinabyss.launchy.state

import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import com.mineinabyss.launchy.data.config.Config

class UIState(config: Config) {
var preferHue: Float by mutableStateOf(config.preferHue ?: 0f)
var fullscreen: Boolean by mutableStateOf(config.startInFullscreen)
}
42 changes: 31 additions & 11 deletions src/main/kotlin/com/mineinabyss/launchy/ui/TopBar.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
Expand All @@ -24,6 +25,8 @@ import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.WindowPlacement
import com.mineinabyss.launchy.LocalLaunchyState
import com.mineinabyss.launchy.ui.elements.BetterWindowDraggableArea
import com.mineinabyss.launchy.ui.state.TopBarState

Expand All @@ -46,13 +49,26 @@ fun AppTopBar(
showTitle: Boolean,
showBackButton: Boolean,
onBackButtonClicked: (() -> Unit),
) = state.windowScope.BetterWindowDraggableArea(
Modifier.pointerInput(Unit) {
detectTapGestures(onDoubleTap = {
state.toggleMaximized()
})
}
) {
val appState = LocalLaunchyState
val forceFullscreen = appState.ui.fullscreen
LaunchedEffect(forceFullscreen) {
when (forceFullscreen) {
true -> state.windowState.placement = WindowPlacement.Fullscreen
false -> state.windowState.placement = WindowPlacement.Floating
}
}

if (!forceFullscreen) state.windowScope.BetterWindowDraggableArea(
Modifier.pointerInput(Unit) {
detectTapGestures(onDoubleTap = {
state.toggleMaximized()
})
}
) {
Box(Modifier.fillMaxWidth().height(40.dp))
}

Box(
Modifier.fillMaxWidth().height(40.dp)
) {
Expand Down Expand Up @@ -85,11 +101,15 @@ fun AppTopBar(
}
}
Row {
WindowButton(Icons.Rounded.Minimize) {
state.windowState.isMinimized = true
}
WindowButton(Icons.Rounded.CropSquare) {
state.toggleMaximized()
AnimatedVisibility(!forceFullscreen) {
Row {
WindowButton(Icons.Rounded.Minimize) {
state.windowState.isMinimized = true
}
WindowButton(Icons.Rounded.CropSquare) {
state.toggleMaximized()
}
}
}
WindowButton(Icons.Rounded.Close) {
state.onClose()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import androidx.compose.ui.text.*
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.unit.sp
import com.mineinabyss.launchy.LocalLaunchyState
import com.mineinabyss.launchy.logic.Browser
import com.mineinabyss.launchy.logic.DesktopHelpers
import com.mineinabyss.launchy.ui.elements.LaunchyDialog
import com.mineinabyss.launchy.ui.screens.Dialog
import com.mineinabyss.launchy.ui.screens.dialog
Expand Down Expand Up @@ -84,7 +84,7 @@ fun AuthDialog(
onClick = {
annotatedText.getUrlAnnotations(it, it)
.firstOrNull()
?.let { Browser.browse(it.item.url) }
?.let { DesktopHelpers.browse(it.item.url) }
},
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package com.mineinabyss.launchy.ui.elements

import androidx.compose.runtime.Composable
import androidx.compose.ui.window.AwtWindow
import com.darkrockstudios.libraries.mpfilepicker.DirectoryPicker
import com.darkrockstudios.libraries.mpfilepicker.FilePicker
import com.mineinabyss.launchy.data.Dirs
import com.mineinabyss.launchy.util.OS
import java.awt.FileDialog
import java.awt.Frame
import java.io.FilenameFilter
import java.nio.file.Path
import kotlin.io.path.Path
import kotlin.io.path.isDirectory


@Composable
fun DirectoryDialog(
shown: Boolean,
title: String,
fallbackTitle: String? = null,
parent: Frame? = null,
onCloseRequest: (result: Path?) -> Unit,
) {
when {
OS.get() == OS.WINDOWS || OS.get() == OS.MAC -> DirectoryPicker(
shown,
initialDirectory = Dirs.jdks.toString(),
title = title,
onFileSelected = { dir ->
onCloseRequest(dir?.let { Path(it) })
})

shown -> AwtWindow(
create = {
object : FileDialog(parent, fallbackTitle ?: title, LOAD) {
override fun setVisible(value: Boolean) {
super.setVisible(value)
if (value) {
val path = files.firstOrNull()?.toPath()
if (path?.isDirectory() == true)
onCloseRequest(path)
else onCloseRequest(path?.parent)
}
}
}
},
dispose = FileDialog::dispose
)
}
}

@Composable
fun SingleFileDialog(
shown: Boolean,
title: String,
fallbackTitle: String? = null,
parent: Frame? = null,
onCloseRequest: (result: Path?) -> Unit,
fileExtensions: () -> List<String>,
fallbackFilter: FilenameFilter
) {
when {
OS.get() == OS.WINDOWS || OS.get() == OS.MAC -> FilePicker(
shown,
initialDirectory = Dirs.jdks.toString(),
title = title,
fileExtensions = fileExtensions(),
onFileSelected = { file ->
onCloseRequest(file?.let { Path(it.path) })
})

shown -> AwtWindow(
create = {
object : FileDialog(parent, fallbackTitle ?: title, LOAD) {
override fun setVisible(value: Boolean) {
super.setVisible(value)
if (value) {
onCloseRequest(files.firstOrNull()?.toPath())
}
}
}.apply {
setFilenameFilter(fallbackFilter)
}
},
dispose = FileDialog::dispose
)
}
}
30 changes: 30 additions & 0 deletions src/main/kotlin/com/mineinabyss/launchy/ui/elements/Typography.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.mineinabyss.launchy.ui.elements

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
Expand All @@ -14,3 +16,31 @@ fun TitleSmall(text: String) {
Text(text, style = MaterialTheme.typography.titleSmall)
}
}

@Composable
fun TitleMedium(text: String) {
Box(Modifier.padding(top = 12.dp, bottom = 8.dp)) {
Text(text, style = MaterialTheme.typography.titleMedium)
}
}

@Composable
fun TitleLarge(text: String) {
Box(Modifier.padding(top = 8.dp, bottom = 4.dp)) {
Text(text, style = MaterialTheme.typography.titleLarge)
}
}


@Composable
fun Setting(title: String, icon: @Composable () -> Unit = {}, content: @Composable () -> Unit) {
Column {
TitleSmall(title)
Row(verticalAlignment = androidx.compose.ui.Alignment.CenterVertically) {
icon()
Column {
content()
}
}
}
}
4 changes: 2 additions & 2 deletions src/main/kotlin/com/mineinabyss/launchy/ui/screens/Screens.kt
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ fun Screens() = Scaffold(

val isDefault = screen is Screen.OnLeftSidebar

LaunchedEffect(isDefault, state.preferHue) {
if (isDefault) currentHue = state.preferHue
LaunchedEffect(isDefault, state.ui.preferHue) {
if (isDefault) currentHue = state.ui.preferHue
}

AppTopBar(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ fun AddNewModpackCard(modifier: Modifier = Modifier) {
Surface(
border = BorderStroke(3.dp, highlightColor),
shape = MaterialTheme.shapes.medium,
modifier = modifier.height(ModpackCardStyle.cardHeight).clickable { screen = Screen.NewInstance }
modifier = modifier.height(InstanceCardStyle.cardHeight).clickable { screen = Screen.NewInstance }
) {
Box {
Row(Modifier.align(Alignment.Center), verticalAlignment = Alignment.CenterVertically) {
Expand Down
Loading

0 comments on commit ef8c560

Please sign in to comment.