...
This commit is contained in:
parent
84cfb2782d
commit
295b429d6d
@ -1,6 +1,8 @@
|
|||||||
package ui
|
package ui
|
||||||
|
|
||||||
import androidx.compose.foundation.border
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.focusable
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
@ -10,6 +12,8 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.DragData
|
import androidx.compose.ui.DragData
|
||||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
|
import androidx.compose.ui.focus.focusRequester
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.onExternalDrag
|
import androidx.compose.ui.onExternalDrag
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
@ -36,6 +40,40 @@ import org.jetbrains.exposed.sql.deleteAll
|
|||||||
import org.jetbrains.exposed.sql.insert
|
import org.jetbrains.exposed.sql.insert
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
import service.SystemSleepPreventer
|
import service.SystemSleepPreventer
|
||||||
|
import java.awt.Toolkit
|
||||||
|
import java.awt.datatransfer.DataFlavor
|
||||||
|
import java.io.File
|
||||||
|
import androidx.compose.ui.input.key.*
|
||||||
|
|
||||||
|
fun getPastedPathFromClipboard(): String? {
|
||||||
|
val clipboard = Toolkit.getDefaultToolkit().systemClipboard
|
||||||
|
try {
|
||||||
|
// 1. 파일 자체가 복사된 경우 (탐색기/파인더에서 Ctrl+C / Cmd+C)
|
||||||
|
if (clipboard.isDataFlavorAvailable(DataFlavor.javaFileListFlavor)) {
|
||||||
|
val files = clipboard.getData(DataFlavor.javaFileListFlavor) as? List<*>
|
||||||
|
val file = files?.firstOrNull() as? File
|
||||||
|
if (file != null) return file.absolutePath
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 텍스트(경로 문자열)가 복사된 경우
|
||||||
|
if (clipboard.isDataFlavorAvailable(DataFlavor.stringFlavor)) {
|
||||||
|
val text = clipboard.getData(DataFlavor.stringFlavor) as? String
|
||||||
|
if (text != null) {
|
||||||
|
// 앞뒤 공백, 따옴표, file:// 접두사 등을 깔끔하게 제거
|
||||||
|
var cleanPath = text.trim('"', '\'', ' ', '\n', '\r')
|
||||||
|
.removePrefix("file://").removePrefix("file:")
|
||||||
|
// 윈도우 드라이브 문자 앞 슬래시 제거 (예: /C:/ -> C:/)
|
||||||
|
if (cleanPath.startsWith("/") && cleanPath.getOrNull(2) == ':') {
|
||||||
|
cleanPath = cleanPath.drop(1)
|
||||||
|
}
|
||||||
|
return cleanPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// src/main/kotlin/ui/SettingsScreen.kt
|
// src/main/kotlin/ui/SettingsScreen.kt
|
||||||
@ -46,6 +84,9 @@ fun SettingsScreen(onAuthSuccess: () -> Unit) {
|
|||||||
var config by remember { mutableStateOf(KisSession.config) }
|
var config by remember { mutableStateOf(KisSession.config) }
|
||||||
var statusMessage by remember { mutableStateOf("프로그램 초기화") }
|
var statusMessage by remember { mutableStateOf("프로그램 초기화") }
|
||||||
|
|
||||||
|
val modelFocusRequester = remember { FocusRequester() }
|
||||||
|
val embedModelFocusRequester = remember { FocusRequester() }
|
||||||
|
|
||||||
val authenticateAndStart: suspend () -> Unit = {
|
val authenticateAndStart: suspend () -> Unit = {
|
||||||
var retryCount = 0
|
var retryCount = 0
|
||||||
val maxRetries = 3
|
val maxRetries = 3
|
||||||
@ -187,6 +228,33 @@ fun SettingsScreen(onAuthSuccess: () -> Unit) {
|
|||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.weight(0.5f).height(60.dp).border(1.dp, Color.Gray, RoundedCornerShape(8.dp))
|
modifier = Modifier.weight(0.5f).height(60.dp).border(1.dp, Color.Gray, RoundedCornerShape(8.dp))
|
||||||
|
.focusRequester(modelFocusRequester)
|
||||||
|
// 2. 포커스 가능하게 설정
|
||||||
|
.focusable()
|
||||||
|
// 3. 클릭하면 해당 박스로 키보드 포커스 이동
|
||||||
|
.clickable { modelFocusRequester.requestFocus() }
|
||||||
|
// 4. 키보드 이벤트 (Ctrl+V / Cmd+V) 감지
|
||||||
|
.onKeyEvent { event ->
|
||||||
|
// 키를 떼는 순간(KeyUp) && 누른 키가 'V' && (Ctrl 혹은 Cmd 키가 눌린 상태)
|
||||||
|
if (event.type == KeyEventType.KeyUp &&
|
||||||
|
event.key == Key.V &&
|
||||||
|
(event.isCtrlPressed || event.isMetaPressed)
|
||||||
|
) {
|
||||||
|
val rawUri = getPastedPathFromClipboard()
|
||||||
|
if (rawUri != null && rawUri.endsWith(".gguf", ignoreCase = true)) {
|
||||||
|
var path = rawUri.removePrefix("file://").removePrefix("file:")
|
||||||
|
|
||||||
|
// 2. 윈도우 환경의 드라이브 문자(예: /C:/) 앞의 슬래시 제거
|
||||||
|
if (path.startsWith("/") && path.getOrNull(2) == ':') {
|
||||||
|
path = path.drop(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path.endsWith(".gguf")) config = config.copy(modelPath = path)
|
||||||
|
return@onKeyEvent true // 이벤트 소비 처리
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
.onExternalDrag(onDrop = { state ->
|
.onExternalDrag(onDrop = { state ->
|
||||||
val data = state.dragData
|
val data = state.dragData
|
||||||
if (data is DragData.FilesList) {
|
if (data is DragData.FilesList) {
|
||||||
@ -214,6 +282,33 @@ fun SettingsScreen(onAuthSuccess: () -> Unit) {
|
|||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.weight(0.5f).height(60.dp).border(1.dp, Color.Gray, RoundedCornerShape(8.dp))
|
modifier = Modifier.weight(0.5f).height(60.dp).border(1.dp, Color.Gray, RoundedCornerShape(8.dp))
|
||||||
|
.focusRequester(embedModelFocusRequester)
|
||||||
|
// 2. 포커스 가능하게 설정
|
||||||
|
.focusable()
|
||||||
|
// 3. 클릭하면 해당 박스로 키보드 포커스 이동
|
||||||
|
.clickable { embedModelFocusRequester.requestFocus() }
|
||||||
|
// 4. 키보드 이벤트 (Ctrl+V / Cmd+V) 감지
|
||||||
|
.onKeyEvent { event ->
|
||||||
|
// 키를 떼는 순간(KeyUp) && 누른 키가 'V' && (Ctrl 혹은 Cmd 키가 눌린 상태)
|
||||||
|
if (event.type == KeyEventType.KeyUp &&
|
||||||
|
event.key == Key.V &&
|
||||||
|
(event.isCtrlPressed || event.isMetaPressed)
|
||||||
|
) {
|
||||||
|
val rawUri = getPastedPathFromClipboard()
|
||||||
|
if (rawUri != null && rawUri.endsWith(".gguf", ignoreCase = true)) {
|
||||||
|
var path = rawUri.removePrefix("file://").removePrefix("file:")
|
||||||
|
|
||||||
|
// 2. 윈도우 환경의 드라이브 문자(예: /C:/) 앞의 슬래시 제거
|
||||||
|
if (path.startsWith("/") && path.getOrNull(2) == ':') {
|
||||||
|
path = path.drop(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path.endsWith(".gguf")) config = config.copy(modelPath = path)
|
||||||
|
return@onKeyEvent true // 이벤트 소비 처리
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
.onExternalDrag(onDrop = { state ->
|
.onExternalDrag(onDrop = { state ->
|
||||||
val data = state.dragData
|
val data = state.dragData
|
||||||
if (data is DragData.FilesList) {
|
if (data is DragData.FilesList) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user