Skip to content

Commit

Permalink
抽取 FileDialog
Browse files Browse the repository at this point in the history
  • Loading branch information
leavesCZY committed Jun 16, 2024
1 parent 8b8cfc8 commit e091ca5
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@ class LogDecodeViewModel : ViewModel(viewModelScope = CoroutineScope(SupervisorJ
value = MainPageViewState(
page = Page.Main,
privateKey = "",
openDialog = DialogState(),
logPath = "",
runtimeLog = "",
logScrollState = ScrollState(initial = 0),
onInputPrivateKey = ::onInputPrivateKey,
openFileDialog = ::openFileDialog,
onInputLogFilePath = ::onInputLogFilePath,
decodeLog = ::decodeLog,
openFile = ::openFile,
Expand Down Expand Up @@ -104,6 +106,10 @@ class LogDecodeViewModel : ViewModel(viewModelScope = CoroutineScope(SupervisorJ
mainPageViewState = mainPageViewState.copy(logPath = logPath)
}

private suspend fun openFileDialog() {
mainPageViewState.openDialog.awaitResult()
}

private suspend fun decodeLog(): File? {
return withContext(context = Dispatchers.Default) {
val logPath = mainPageViewState.logPath
Expand All @@ -116,7 +122,7 @@ class LogDecodeViewModel : ViewModel(viewModelScope = CoroutineScope(SupervisorJ
outFile = outFile
)
appendLog {
"解析成功,文件路径:" + outFile.absolutePath
"解析成功,文件路径:" + outFile.absolutePath + "\n\n"
}
autoOpenFileIfNeed(file = outFile)
outFile
Expand All @@ -125,7 +131,7 @@ class LogDecodeViewModel : ViewModel(viewModelScope = CoroutineScope(SupervisorJ
appendLog {
val stringWriter = StringWriter()
throwable.printStackTrace(PrintWriter(stringWriter, true))
stringWriter.buffer.toString()
stringWriter.toString()
}
null
}
Expand Down
7 changes: 2 additions & 5 deletions src/main/kotlin/github/leavesczy/xlog/decode/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.WindowPosition
import androidx.compose.ui.window.application
import androidx.compose.ui.window.rememberWindowState
import androidx.compose.ui.window.*
import androidx.lifecycle.viewmodel.compose.viewModel
import github.leavesczy.xlog.decode.ui.CryptKeyPage
import github.leavesczy.xlog.decode.ui.MainPage
Expand Down Expand Up @@ -42,7 +39,7 @@ fun main() = application {
}

@Composable
private fun Main() {
private fun FrameWindowScope.Main() {
val logDecodeViewModel = viewModel { LogDecodeViewModel() }
val pageViewState = logDecodeViewModel.mainPageViewState
AppTheme(theme = logDecodeViewModel.settingsPageViewState.theme) {
Expand Down
64 changes: 64 additions & 0 deletions src/main/kotlin/github/leavesczy/xlog/decode/ui/FileLoadDialog.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package github.leavesczy.xlog.decode.ui

import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.window.AwtWindow
import androidx.compose.ui.window.FrameWindowScope
import kotlinx.coroutines.CompletableDeferred
import java.awt.FileDialog
import java.io.File
import java.nio.file.Path

@Composable
fun FrameWindowScope.FileLoadDialog(
title: String = "Choose a file",
fileExtension: String? = null,
isMultipleMode: Boolean = false,
onResult: (result: Path?) -> Unit
) = AwtWindow(
create = {
object : FileDialog(window, title, LOAD) {
override fun setVisible(value: Boolean) {
super.setVisible(value)
if (value) {
if (file != null) {
onResult(File(directory).resolve(file).toPath())
} else {
onResult(null)
}
}
}
}
},
update = {
it.title = title
it.isMultipleMode = isMultipleMode
it.setFilenameFilter { _, name ->
if (fileExtension.isNullOrBlank()) {
true
} else {
name.endsWith(suffix = fileExtension)
}
}
},
dispose = FileDialog::dispose
)

class DialogState<T> {

private var onResult: CompletableDeferred<T>? by mutableStateOf(null)

val isAwaiting get() = onResult != null

suspend fun awaitResult(): T {
onResult = CompletableDeferred()
val result = onResult!!.await()
onResult = null
return result
}

fun onResult(result: T) = onResult!!.complete(result)

}
85 changes: 45 additions & 40 deletions src/main/kotlin/github/leavesczy/xlog/decode/ui/MainPage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.*
import androidx.compose.ui.awt.ComposeWindow
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawWithCache
import androidx.compose.ui.geometry.CornerRadius
Expand All @@ -18,10 +17,11 @@ import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.FrameWindowScope
import kotlinx.coroutines.launch
import java.awt.FileDialog
import java.io.File
import java.net.URI
import java.nio.file.Path
import kotlin.io.path.pathString
import kotlin.io.path.toPath

Expand All @@ -30,14 +30,32 @@ import kotlin.io.path.toPath
* @Date: 2024/6/4 14:15
* @Desc:
*/
private const val xLogFileExtension = "xlog"
internal const val xLogFileExtension = "xlog"

@Composable
fun MainPage(
fun FrameWindowScope.MainPage(
pageViewState: MainPageViewState,
snackBarHostState: SnackbarHostState
) {
val coroutineScope = rememberCoroutineScope()
fun confirmLogFilePath(paths: List<Path>) {
val filePath = paths.firstNotNullOfOrNull {
val pathString = it.pathString
val file = File(pathString)
if (file.exists() && file.isFile && file.extension == xLogFileExtension) {
pathString
} else {
null
}
}
if (filePath != null) {
pageViewState.onInputLogFilePath(filePath)
} else {
coroutineScope.launch {
snackBarHostState.showSnackbar(message = "请选择 $xLogFileExtension 文件")
}
}
}
Column(
modifier = Modifier
.fillMaxSize()
Expand All @@ -51,13 +69,10 @@ fun MainPage(
)
LogFilePath(
logPath = pageViewState.logPath,
onInputLogFilePath = {
if (it.endsWith(suffix = xLogFileExtension)) {
pageViewState.onInputLogFilePath(it)
} else {
coroutineScope.launch {
snackBarHostState.showSnackbar(message = "请选择 $xLogFileExtension 文件")
}
confirmLogFilePath = ::confirmLogFilePath,
openFileDialog = {
coroutineScope.launch {
pageViewState.openFileDialog()
}
}
)
Expand Down Expand Up @@ -105,6 +120,19 @@ fun MainPage(
scrollState = pageViewState.logScrollState
)
}
if (pageViewState.openDialog.isAwaiting) {
FileLoadDialog(
title = "请选择 $xLogFileExtension 文件",
isMultipleMode = false,
fileExtension = xLogFileExtension,
onResult = {
if (it != null) {
confirmLogFilePath(paths = listOf(it))
}
pageViewState.openDialog.onResult(it)
}
)
}
}

@Composable
Expand All @@ -130,7 +158,8 @@ private fun PrivateKey(
@Composable
private fun LogFilePath(
logPath: String,
onInputLogFilePath: (String) -> Unit
confirmLogFilePath: (List<Path>) -> Unit,
openFileDialog: () -> Unit
) {
Box(
modifier = Modifier
Expand Down Expand Up @@ -162,18 +191,10 @@ private fun LogFilePath(
isDragging = false
val dragData = value.dragData
if (dragData is DragData.FilesList) {
val file = dragData.readFiles().firstNotNullOfOrNull {
val path = URI(it).toPath().pathString
val file = File(path)
if (file.exists() && file.isFile) {
file
} else {
null
}
}
if (file != null) {
onInputLogFilePath(file.absolutePath)
val paths = dragData.readFiles().map {
URI(it).toPath()
}
confirmLogFilePath(paths)
}
}
),
Expand All @@ -192,23 +213,7 @@ private fun LogFilePath(
modifier = Modifier
.matchParentSize()
.clip(shape = RoundedCornerShape(size = 16.dp))
.clickable {
val fileDialog = FileDialog(ComposeWindow(), "请选择 $xLogFileExtension 文件")
fileDialog.apply {
mode = FileDialog.LOAD
isMultipleMode = false
setFilenameFilter { _, name ->
name.endsWith(suffix = xLogFileExtension)
}
isVisible = true
val fileDirectory = fileDialog.directory
val fileName = fileDialog.file
if (!fileDirectory.isNullOrBlank() && !fileName.isNullOrBlank()) {
val filePath = fileDirectory + fileName
onInputLogFilePath(filePath)
}
}
}
.clickable(onClick = openFileDialog)
)
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/main/kotlin/github/leavesczy/xlog/decode/ui/Models.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import androidx.compose.material.icons.outlined.Settings
import androidx.compose.runtime.Stable
import androidx.compose.ui.graphics.vector.ImageVector
import java.io.File
import java.nio.file.Path

/**
* @Author: leavesCZY
Expand All @@ -30,10 +31,12 @@ enum class Theme(val type: Int) {
data class MainPageViewState(
val page: Page,
val privateKey: String,
val openDialog: DialogState<Path?>,
val logPath: String,
val runtimeLog: String,
val logScrollState: ScrollState,
val onInputPrivateKey: (String) -> Unit,
val openFileDialog: suspend () -> Unit,
val onInputLogFilePath: (String) -> Unit,
val decodeLog: suspend () -> File?,
val openFile: suspend (File) -> Unit,
Expand Down

0 comments on commit e091ca5

Please sign in to comment.