...
This commit is contained in:
parent
295b429d6d
commit
db134d5e9e
@ -14,6 +14,7 @@ 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.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
|
import androidx.compose.ui.focus.onFocusChanged
|
||||||
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
|
||||||
@ -80,6 +81,9 @@ fun getPastedPathFromClipboard(): String? {
|
|||||||
@OptIn(ExperimentalComposeUiApi::class)
|
@OptIn(ExperimentalComposeUiApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun SettingsScreen(onAuthSuccess: () -> Unit) {
|
fun SettingsScreen(onAuthSuccess: () -> Unit) {
|
||||||
|
|
||||||
|
var isModelBoxFocused by remember { mutableStateOf(false) }
|
||||||
|
var isEmbedBoxFocused by remember { mutableStateOf(false) }
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
var config by remember { mutableStateOf(KisSession.config) }
|
var config by remember { mutableStateOf(KisSession.config) }
|
||||||
var statusMessage by remember { mutableStateOf("프로그램 초기화") }
|
var statusMessage by remember { mutableStateOf("프로그램 초기화") }
|
||||||
@ -129,14 +133,14 @@ fun SettingsScreen(onAuthSuccess: () -> Unit) {
|
|||||||
while (true) {
|
while (true) {
|
||||||
val now = java.time.LocalTime.now(java.time.ZoneId.of("Asia/Seoul"))
|
val now = java.time.LocalTime.now(java.time.ZoneId.of("Asia/Seoul"))
|
||||||
// 08:30 ~ 15:30 사이이고, 키값이 최소한 하나라도 존재할 때 자동 실행
|
// 08:30 ~ 15:30 사이이고, 키값이 최소한 하나라도 존재할 때 자동 실행
|
||||||
if (now.isAfter(java.time.LocalTime.of(7, 40)) && now.isBefore(java.time.LocalTime.of(18, 0))) {
|
// if (now.isAfter(java.time.LocalTime.of(7, 40)) && now.isBefore(java.time.LocalTime.of(18, 0))) {
|
||||||
if (config.realAppKey.isNotEmpty() && config.vtsAppKey.isNotEmpty() && config.embedModelPath.isNotEmpty() && config.modelPath.isNotEmpty()) {
|
// if (config.realAppKey.isNotEmpty() && config.vtsAppKey.isNotEmpty() && config.embedModelPath.isNotEmpty() && config.modelPath.isNotEmpty()) {
|
||||||
SystemSleepPreventer.wakeDisplay() // 모니터 켜기
|
// SystemSleepPreventer.wakeDisplay() // 모니터 켜기
|
||||||
statusMessage = "⏰ 자동 실행 시간(08:30)입니다. 시스템을 가동합니다."
|
// statusMessage = "⏰ 자동 실행 시간(08:30)입니다. 시스템을 가동합니다."
|
||||||
authenticateAndStart()
|
// authenticateAndStart()
|
||||||
break // 성공하면 루프 탈출
|
// break // 성공하면 루프 탈출
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
delay(30_000) // 1분마다 시간 체크
|
delay(30_000) // 1분마다 시간 체크
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -228,18 +232,46 @@ 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))
|
||||||
|
.border(
|
||||||
|
width = if (isModelBoxFocused) 2.dp else 1.dp,
|
||||||
|
color = if (isModelBoxFocused) Color.Blue else Color.Gray,
|
||||||
|
shape = RoundedCornerShape(8.dp)
|
||||||
|
)
|
||||||
|
// 2. Modifier 순서가 매우 중요합니다.
|
||||||
.focusRequester(modelFocusRequester)
|
.focusRequester(modelFocusRequester)
|
||||||
// 2. 포커스 가능하게 설정
|
.onFocusChanged { focusState ->
|
||||||
|
isModelBoxFocused = focusState.isFocused // 포커스 여부 저장
|
||||||
|
if (focusState.isFocused) {
|
||||||
|
val rawUri = getPastedPathFromClipboard()
|
||||||
|
println("rawUri $rawUri")
|
||||||
|
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)
|
||||||
|
true // 이벤트 소비 처리
|
||||||
|
}
|
||||||
|
println("✅ Box에 포커스가 들어왔습니다!") // 로그 확인
|
||||||
|
}
|
||||||
|
}
|
||||||
.focusable()
|
.focusable()
|
||||||
// 3. 클릭하면 해당 박스로 키보드 포커스 이동
|
.clickable {
|
||||||
.clickable { modelFocusRequester.requestFocus() }
|
modelFocusRequester.requestFocus()
|
||||||
// 4. 키보드 이벤트 (Ctrl+V / Cmd+V) 감지
|
}
|
||||||
.onKeyEvent { event ->
|
// 3. onKeyEvent 대신 onPreviewKeyEvent 사용! (핵심)
|
||||||
// 키를 떼는 순간(KeyUp) && 누른 키가 'V' && (Ctrl 혹은 Cmd 키가 눌린 상태)
|
.onPreviewKeyEvent { event ->
|
||||||
|
// 디버깅용 로그: 어떤 키가 눌리는지 확인
|
||||||
|
println("키 입력 감지: ${event.key}, type: ${event.type}")
|
||||||
|
|
||||||
if (event.type == KeyEventType.KeyUp &&
|
if (event.type == KeyEventType.KeyUp &&
|
||||||
event.key == Key.V &&
|
event.key == Key.V &&
|
||||||
(event.isCtrlPressed || event.isMetaPressed)
|
(event.isCtrlPressed || event.isMetaPressed)
|
||||||
) {
|
) {
|
||||||
|
println("🚀 Ctrl+V 입력 성공!")
|
||||||
val rawUri = getPastedPathFromClipboard()
|
val rawUri = getPastedPathFromClipboard()
|
||||||
if (rawUri != null && rawUri.endsWith(".gguf", ignoreCase = true)) {
|
if (rawUri != null && rawUri.endsWith(".gguf", ignoreCase = true)) {
|
||||||
var path = rawUri.removePrefix("file://").removePrefix("file:")
|
var path = rawUri.removePrefix("file://").removePrefix("file:")
|
||||||
@ -250,7 +282,7 @@ fun SettingsScreen(onAuthSuccess: () -> Unit) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (path.endsWith(".gguf")) config = config.copy(modelPath = path)
|
if (path.endsWith(".gguf")) config = config.copy(modelPath = path)
|
||||||
return@onKeyEvent true // 이벤트 소비 처리
|
true // 이벤트 소비 처리
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
@ -275,26 +307,55 @@ fun SettingsScreen(onAuthSuccess: () -> Unit) {
|
|||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
if (config.modelPath.isEmpty()) "GGUF 모델 파일을 여기로 드래그하세요" else config.modelPath,
|
if (config.modelPath.isEmpty()) "클릭하여 파란 테두리가 생기면\nCtrl+V 로 붙여넣기 하세요"
|
||||||
fontSize = 12.sp
|
else config.modelPath,
|
||||||
|
fontSize = 12.sp,
|
||||||
|
textAlign = androidx.compose.ui.text.style.TextAlign.Center
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
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))
|
||||||
|
.border(
|
||||||
|
width = if (isEmbedBoxFocused) 2.dp else 1.dp,
|
||||||
|
color = if (isEmbedBoxFocused) Color.Blue else Color.Gray,
|
||||||
|
shape = RoundedCornerShape(8.dp)
|
||||||
|
)
|
||||||
|
// 2. Modifier 순서가 매우 중요합니다.
|
||||||
.focusRequester(embedModelFocusRequester)
|
.focusRequester(embedModelFocusRequester)
|
||||||
// 2. 포커스 가능하게 설정
|
.onFocusChanged { focusState ->
|
||||||
|
isEmbedBoxFocused = focusState.isFocused // 포커스 여부 저장
|
||||||
|
if (focusState.isFocused) {
|
||||||
|
val rawUri = getPastedPathFromClipboard()
|
||||||
|
println("rawUri $rawUri")
|
||||||
|
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)
|
||||||
|
true // 이벤트 소비 처리
|
||||||
|
}
|
||||||
|
println("✅ Box에 포커스가 들어왔습니다!") // 로그 확인
|
||||||
|
}
|
||||||
|
}
|
||||||
.focusable()
|
.focusable()
|
||||||
// 3. 클릭하면 해당 박스로 키보드 포커스 이동
|
.clickable {
|
||||||
.clickable { embedModelFocusRequester.requestFocus() }
|
embedModelFocusRequester.requestFocus()
|
||||||
|
}
|
||||||
// 4. 키보드 이벤트 (Ctrl+V / Cmd+V) 감지
|
// 4. 키보드 이벤트 (Ctrl+V / Cmd+V) 감지
|
||||||
.onKeyEvent { event ->
|
.onKeyEvent { event ->
|
||||||
|
println("event >> $event")
|
||||||
// 키를 떼는 순간(KeyUp) && 누른 키가 'V' && (Ctrl 혹은 Cmd 키가 눌린 상태)
|
// 키를 떼는 순간(KeyUp) && 누른 키가 'V' && (Ctrl 혹은 Cmd 키가 눌린 상태)
|
||||||
if (event.type == KeyEventType.KeyUp &&
|
if (event.type == KeyEventType.KeyUp &&
|
||||||
event.key == Key.V &&
|
event.key == Key.V &&
|
||||||
(event.isCtrlPressed || event.isMetaPressed)
|
(event.isCtrlPressed || event.isMetaPressed)
|
||||||
) {
|
) {
|
||||||
val rawUri = getPastedPathFromClipboard()
|
val rawUri = getPastedPathFromClipboard()
|
||||||
|
println("rawUri >> $rawUri")
|
||||||
if (rawUri != null && rawUri.endsWith(".gguf", ignoreCase = true)) {
|
if (rawUri != null && rawUri.endsWith(".gguf", ignoreCase = true)) {
|
||||||
var path = rawUri.removePrefix("file://").removePrefix("file:")
|
var path = rawUri.removePrefix("file://").removePrefix("file:")
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user