Skip to content

Commit

Permalink
🔨 Refactoring window management impl
Browse files Browse the repository at this point in the history
  • Loading branch information
guiyanakuang committed Jun 14, 2024
1 parent 74c74bd commit 8cca9d6
Show file tree
Hide file tree
Showing 17 changed files with 367 additions and 426 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.clipevery.app

interface AppTokenService {

var showToken: Boolean

var token: CharArray

fun startRefreshToken()

fun stopRefreshToken()
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,14 @@ interface AppWindowManager {

var showMainDialog: Boolean

val windowManager: WindowManager

var showSearchWindow: Boolean

var searchWindowState: WindowState

var focusRequester: FocusRequester
var searchFocusRequester: FocusRequester

val searchWindowDetailViewDpSize: DpSize

var showToken: Boolean

var token: CharArray

fun startRefreshToken()

fun stopRefreshToken()

fun getCurrentActiveAppName(): String?

fun activeMainWindow()
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.clipevery.LocalKoinApplication
import com.clipevery.app.AppWindowManager
import com.clipevery.app.AppTokenService
import com.clipevery.i18n.GlobalCopywriter
import com.clipevery.ui.base.autoRenew
import com.clipevery.ui.base.scan
Expand All @@ -58,7 +58,7 @@ val qrSize: DpSize = DpSize(275.dp, 275.dp)
fun bindingQRCode() {
val current = LocalKoinApplication.current
val copywriter = current.koin.get<GlobalCopywriter>()
val appWindowManager = current.koin.get<AppWindowManager>()
val appTokenService = current.koin.get<AppTokenService>()
val qrCodeGenerator = current.koin.get<QRCodeGenerator>()

val density = LocalDensity.current
Expand All @@ -69,20 +69,20 @@ fun bindingQRCode() {
var qrImage: ImageBitmap? by remember { mutableStateOf(null) }

LaunchedEffect(Unit) {
appWindowManager.startRefreshToken()
appTokenService.startRefreshToken()
}

LaunchedEffect(appWindowManager.token) {
LaunchedEffect(appTokenService.token) {
// maybe slow (get host), we use ioDispatcher to avoid blocking the UI
qrImage =
withContext(ioDispatcher) {
qrCodeGenerator.generateQRCode(width, height, appWindowManager.token)
qrCodeGenerator.generateQRCode(width, height, appTokenService.token)
}
}

DisposableEffect(Unit) {
onDispose {
appWindowManager.stopRefreshToken()
appTokenService.stopRefreshToken()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Popup
import androidx.compose.ui.window.PopupProperties
import com.clipevery.LocalKoinApplication
import com.clipevery.app.AppWindowManager
import com.clipevery.app.AppTokenService
import com.clipevery.i18n.GlobalCopywriter
import com.clipevery.ui.customFontFamily

Expand All @@ -50,12 +50,12 @@ fun TokenView() {
val current = LocalKoinApplication.current
val density = LocalDensity.current
val copywriter = current.koin.get<GlobalCopywriter>()
val appWindowManager = current.koin.get<AppWindowManager>()
val appTokenService = current.koin.get<AppTokenService>()

val offsetY =
animateIntOffsetAsState(
targetValue =
if (appWindowManager.showToken) {
if (appTokenService.showToken) {
IntOffset(
with(density) { (0.dp).roundToPx() },
with(density) { (50.dp).roundToPx() },
Expand All @@ -70,21 +70,21 @@ fun TokenView() {
)

val alpha by animateFloatAsState(
targetValue = if (appWindowManager.showToken) 1f else 0f,
targetValue = if (appTokenService.showToken) 1f else 0f,
animationSpec =
tween(
durationMillis = 500,
easing = LinearOutSlowInEasing,
),
)

LaunchedEffect(appWindowManager.showToken) {
appWindowManager.startRefreshToken()
LaunchedEffect(appTokenService.showToken) {
appTokenService.startRefreshToken()
}

DisposableEffect(appWindowManager.showToken) {
DisposableEffect(appTokenService.showToken) {
onDispose {
appWindowManager.stopRefreshToken()
appTokenService.stopRefreshToken()
}
}

Expand Down Expand Up @@ -124,7 +124,7 @@ fun TokenView() {
fontFamily = customFontFamily,
)
IconButton(
onClick = { appWindowManager.showToken = false },
onClick = { appTokenService.showToken = false },
modifier =
Modifier.align(Alignment.TopEnd)
.offset(y = (-8).dp)
Expand All @@ -146,17 +146,17 @@ fun TokenView() {
Modifier.align(Alignment.CenterHorizontally)
.padding(12.dp),
) {
OTPCodeBox(appWindowManager)
OTPCodeBox(appTokenService)
}
}
}
}
}

@Composable
fun OTPCodeBox(appWindowManager: AppWindowManager) {
fun OTPCodeBox(appTokenService: AppTokenService) {
Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) {
appWindowManager.token.forEach { char ->
appTokenService.token.forEach { char ->
Box(
contentAlignment = Alignment.Center,
modifier =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ fun ClipeverySearchWindow() {
val appWindowManager = current.koin.get<AppWindowManager>()
val clipSearchService = current.koin.get<ClipSearchService>()
val logger = current.koin.get<KLogger>()
val focusRequester = appWindowManager.focusRequester
val focusRequester = appWindowManager.searchFocusRequester

var lastInputTime by remember { mutableStateOf(0L) }

Expand Down
11 changes: 7 additions & 4 deletions composeApp/src/desktopMain/kotlin/com/clipevery/Clipevery.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,22 @@ import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
import com.clipevery.app.AbstractAppWindowManager.Companion.MAIN_WINDOW_TITLE
import com.clipevery.app.AbstractAppWindowManager.Companion.SEARCH_WINDOW_TITLE
import com.clipevery.app.AppEnv
import com.clipevery.app.AppFileType
import com.clipevery.app.AppInfo
import com.clipevery.app.AppLock
import com.clipevery.app.AppRestartService
import com.clipevery.app.AppStartUpService
import com.clipevery.app.AppTokenService
import com.clipevery.app.AppWindowManager
import com.clipevery.app.DesktopAppInfoFactory
import com.clipevery.app.DesktopAppLock
import com.clipevery.app.DesktopAppRestartService
import com.clipevery.app.DesktopAppStartUpService
import com.clipevery.app.DesktopAppWindowManager
import com.clipevery.app.DesktopAppWindowManager.Companion.MAIN_WINDOW_TITLE
import com.clipevery.app.DesktopAppWindowManager.Companion.SEARCH_WINDOW_TITLE
import com.clipevery.app.DesktopAppTokenService
import com.clipevery.app.getDesktopAppWindowManager
import com.clipevery.clean.CleanClipScheduler
import com.clipevery.clean.DesktopCleanClipScheduler
import com.clipevery.clip.CacheManager
Expand Down Expand Up @@ -281,7 +283,8 @@ class Clipevery {
}

// ui component
single<AppWindowManager> { DesktopAppWindowManager(lazy { get() }, get()) }
single<AppWindowManager> { getDesktopAppWindowManager(lazy { get() }, get()) }
single<AppTokenService> { DesktopAppTokenService() }
single<GlobalCopywriter> { GlobalCopywriterImpl(get()) }
single<DesktopShortcutKeysListener> { DesktopShortcutKeysListener(get()) }
single<ShortcutKeysListener> { get<DesktopShortcutKeysListener>() }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.clipevery.app

import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.WindowPlacement
import androidx.compose.ui.window.WindowPosition
import androidx.compose.ui.window.WindowState
import com.clipevery.path.DesktopPathProvider
import com.clipevery.path.PathProvider
import com.clipevery.utils.Memoize
import com.clipevery.utils.ioDispatcher
import io.github.oshai.kotlinlogging.KLogger
import io.github.oshai.kotlinlogging.KotlinLogging
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import java.awt.Rectangle

abstract class AbstractAppWindowManager : AppWindowManager {

companion object {
const val MAIN_WINDOW_TITLE: String = "Clipevery"

const val SEARCH_WINDOW_TITLE: String = "Clipevery Search"

// only use in Windows
const val MENU_WINDOW_TITLE: String = "Clipevery Menu"
}

protected val logger: KLogger = KotlinLogging.logger {}

protected val ioScope = CoroutineScope(ioDispatcher + SupervisorJob())

protected val pathProvider: PathProvider = DesktopPathProvider

override var showMainWindow by mutableStateOf(false)

override var mainWindowState: WindowState by mutableStateOf(
WindowState(
placement = WindowPlacement.Floating,
position = WindowPosition.PlatformDefault,
size = DpSize(width = 460.dp, height = 710.dp),
),
)

override var showMainDialog by mutableStateOf(false)

override var showSearchWindow by mutableStateOf(false)

override var searchWindowState: WindowState by mutableStateOf(
WindowState(
placement = WindowPlacement.Floating,
position = WindowPosition.Aligned(Alignment.Center),
size = DpSize(width = 800.dp, height = 520.dp),
),
)

override var searchFocusRequester = FocusRequester()

override val searchWindowDetailViewDpSize = DpSize(width = 500.dp, height = 240.dp)

protected val calPosition: (Rectangle) -> WindowPosition =
Memoize.memoize { bounds ->
val windowSize = searchWindowState.size
WindowPosition(
x = (bounds.x.dp + ((bounds.width.dp - windowSize.width) / 2)),
y = (bounds.y.dp + ((bounds.height.dp - windowSize.height) / 2)),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.clipevery.app

import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import com.clipevery.utils.mainDispatcher
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlin.random.Random

class DesktopAppTokenService : AppTokenService {

private var startRefreshNumber: Int = 0

private var refreshTokenJob: Job? = null

private val scope = CoroutineScope(Dispatchers.IO)

override var showToken by mutableStateOf(false)

override var token by mutableStateOf(charArrayOf('0', '0', '0', '0', '0', '0'))

private suspend fun refreshToken() {
withContext(mainDispatcher) {
token = CharArray(6) { (Random.nextInt(10) + '0'.code).toChar() }
}
}

@Synchronized
override fun startRefreshToken() {
if (startRefreshNumber++ == 0) {
refreshTokenJob =
scope.launch(CoroutineName("RefreshToken")) {
while (isActive) {
refreshToken()
delay(30000)
}
}
}
}

@Synchronized
override fun stopRefreshToken() {
startRefreshNumber -= 1
if (startRefreshNumber == 0) {
refreshTokenJob?.cancel()
}
}
}
Loading

0 comments on commit 8cca9d6

Please sign in to comment.