mirror of
https://github.com/fromchat-messenger/app.git
synced 2026-09-22 19:15:05 +03:00
Implement desktop support
Signed-off-by: denis0001-dev <denis0001.dev@ya.ru>
This commit is contained in:
@@ -16,6 +16,8 @@ kotlin {
|
||||
minSdk = 24
|
||||
}
|
||||
|
||||
jvm()
|
||||
|
||||
listOf(
|
||||
iosArm64(),
|
||||
iosSimulatorArm64()
|
||||
@@ -62,6 +64,13 @@ kotlin {
|
||||
implementation(libs.multiplatform.settings.coroutines)
|
||||
implementation(libs.multiplatform.settings.serialization)
|
||||
}
|
||||
|
||||
jvmMain.dependencies {
|
||||
implementation(libs.kotlinx.datetime)
|
||||
implementation(libs.multiplatform.settings)
|
||||
implementation(libs.multiplatform.settings.coroutines)
|
||||
implementation(libs.multiplatform.settings.serialization)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,8 +21,8 @@ data class NavigationItem(
|
||||
@Composable
|
||||
fun SimpleNavigationBar(
|
||||
selectedItem: Int,
|
||||
vararg items: NavigationItem,
|
||||
modifier: Modifier = Modifier,
|
||||
vararg items: NavigationItem,
|
||||
) {
|
||||
NavigationBar(modifier) {
|
||||
items.forEachIndexed { index, item ->
|
||||
@@ -48,8 +48,8 @@ fun SimpleNavigationBar(
|
||||
@Composable
|
||||
fun SimpleNavigationRail(
|
||||
selectedItem: Int,
|
||||
vararg items: NavigationItem,
|
||||
modifier: Modifier = Modifier,
|
||||
vararg items: NavigationItem,
|
||||
) {
|
||||
NavigationRail(
|
||||
modifier,
|
||||
@@ -73,4 +73,4 @@ fun SimpleNavigationRail(
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import platform.CoreCrypto.CCHmac
|
||||
import platform.CoreCrypto.kCCHmacAlgSHA256
|
||||
|
||||
@OptIn(ExperimentalForeignApi::class)
|
||||
internal fun iosHmacSha256(key: ByteArray, data: ByteArray): ByteArray {
|
||||
fun iosHmacSha256(key: ByteArray, data: ByteArray): ByteArray {
|
||||
val mac = ByteArray(32)
|
||||
|
||||
key.usePinned { keyPinned ->
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.pr0gramm3r101.utils
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.platform.LocalWindowInfo
|
||||
|
||||
@OptIn(ExperimentalComposeUiApi::class)
|
||||
@Composable
|
||||
actual inline fun currentWindowSize() = LocalWindowInfo.current.containerSize
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.pr0gramm3r101.utils
|
||||
|
||||
import androidx.compose.ui.platform.Clipboard
|
||||
import java.awt.Toolkit
|
||||
import java.awt.datatransfer.DataFlavor
|
||||
import java.awt.datatransfer.StringSelection
|
||||
|
||||
actual fun Clipboard.toSupport(): SupportClipboardManager {
|
||||
return object : SupportClipboardManager {
|
||||
private var listener: ((String) -> Unit)? = null
|
||||
|
||||
override suspend fun setText(string: String) {
|
||||
Toolkit.getDefaultToolkit().systemClipboard.setContents(StringSelection(string), null)
|
||||
listener?.invoke(string)
|
||||
}
|
||||
|
||||
override suspend fun getText(): String? {
|
||||
val contents = Toolkit.getDefaultToolkit().systemClipboard.getContents(null) ?: return null
|
||||
if (!contents.isDataFlavorSupported(DataFlavor.stringFlavor)) return null
|
||||
return contents.getTransferData(DataFlavor.stringFlavor) as? String
|
||||
}
|
||||
|
||||
override fun setTextListener(listener: (String) -> Unit) {
|
||||
this.listener = listener
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.pr0gramm3r101.utils
|
||||
|
||||
import androidx.compose.ui.Modifier
|
||||
|
||||
actual fun Modifier.imeScrollWithKeyboard(): Modifier = this
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.pr0gramm3r101.utils
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
|
||||
@Composable
|
||||
actual fun rememberImeMotion(): ImeMotion =
|
||||
ImeMotion(
|
||||
currentBottomPx = 0,
|
||||
sourceBottomPx = 0,
|
||||
targetBottomPx = 0,
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.pr0gramm3r101.utils
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
|
||||
@Composable
|
||||
actual fun rememberSystemBarsController(): ((Boolean) -> Unit)? {
|
||||
return remember {
|
||||
{ _ -> }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.pr0gramm3r101.utils
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
|
||||
actual fun Modifier.clearFocusOnKeyboardDismiss() = this
|
||||
|
||||
@Composable
|
||||
actual fun ToggleNavScrimEffect(enabled: Boolean) {}
|
||||
|
||||
@Composable
|
||||
actual fun DialogEdgeToEdgeEffect() {}
|
||||
|
||||
actual val materialYouAvailable get() = false
|
||||
|
||||
actual fun currentDeviceInfo(): CurrentDeviceInfo =
|
||||
CurrentDeviceInfo(
|
||||
osName = System.getProperty("os.name")?.trim()?.takeIf { it.isNotEmpty() },
|
||||
osVersion = System.getProperty("os.version")?.trim()?.takeIf { it.isNotEmpty() },
|
||||
deviceType = "desktop",
|
||||
deviceName = System.getProperty("user.name")?.trim()?.takeIf { it.isNotEmpty() },
|
||||
brand = null,
|
||||
model = System.getProperty("os.arch")?.trim()?.takeIf { it.isNotEmpty() },
|
||||
)
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.pr0gramm3r101.utils
|
||||
|
||||
actual object UtilsLibrary {
|
||||
actual fun init(vararg args: Any) {}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.pr0gramm3r101.utils.crypto
|
||||
|
||||
actual object Base64 {
|
||||
actual fun encode(bytes: ByteArray): String =
|
||||
java.util.Base64.getEncoder().encodeToString(bytes)
|
||||
|
||||
actual fun decode(base64: String): ByteArray =
|
||||
runCatching { java.util.Base64.getDecoder().decode(base64) }.getOrDefault(ByteArray(0))
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.pr0gramm3r101.utils.crypto
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.crypto.Mac
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
|
||||
actual object Hmac {
|
||||
actual suspend fun hmacSha256(key: ByteArray, data: ByteArray): ByteArray =
|
||||
withContext(Dispatchers.Default) {
|
||||
val mac = Mac.getInstance("HmacSHA256")
|
||||
mac.init(SecretKeySpec(key, "HmacSHA256"))
|
||||
mac.doFinal(data)
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package com.pr0gramm3r101.utils.files
|
||||
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.StandardOpenOption
|
||||
|
||||
internal actual fun expectExists(path: String): Boolean = File(path).exists()
|
||||
|
||||
internal actual fun expectWriteBytes(path: String, bytes: ByteArray) {
|
||||
val file = File(path)
|
||||
file.parentFile?.mkdirs()
|
||||
file.writeBytes(bytes)
|
||||
}
|
||||
|
||||
internal actual fun expectAppendBytes(path: String, bytes: ByteArray) {
|
||||
val file = File(path)
|
||||
file.parentFile?.mkdirs()
|
||||
Files.write(
|
||||
file.toPath(),
|
||||
bytes,
|
||||
StandardOpenOption.CREATE,
|
||||
StandardOpenOption.APPEND,
|
||||
StandardOpenOption.WRITE,
|
||||
)
|
||||
}
|
||||
|
||||
internal actual fun expectFileSize(path: String): Long {
|
||||
val file = File(path)
|
||||
return if (file.exists()) file.length() else 0L
|
||||
}
|
||||
|
||||
internal actual fun expectDelete(path: String) {
|
||||
File(path).delete()
|
||||
}
|
||||
|
||||
internal actual fun expectDeleteFilesWithPrefix(dirPath: String, namePrefix: String) {
|
||||
val dir = File(dirPath)
|
||||
if (!dir.isDirectory) return
|
||||
dir.listFiles()?.forEach { file ->
|
||||
if (file.name.startsWith(namePrefix)) {
|
||||
file.delete()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal actual fun expectListFileNamesInDirectory(dirPath: String): List<String> {
|
||||
val dir = File(dirPath)
|
||||
if (!dir.isDirectory) return emptyList()
|
||||
return dir.list()?.toList().orEmpty()
|
||||
}
|
||||
|
||||
internal actual fun expectGetAppCacheDirectory(): String {
|
||||
val home = System.getProperty("user.home")
|
||||
return if (!home.isNullOrBlank()) {
|
||||
File(home, ".fromchat/cache").absolutePath
|
||||
} else {
|
||||
File(System.getProperty("java.io.tmpdir"), "fromchat").absolutePath
|
||||
}
|
||||
}
|
||||
|
||||
internal actual fun expectEnsureDirectory(path: String) {
|
||||
File(path).mkdirs()
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.pr0gramm3r101.utils.settings
|
||||
|
||||
import com.russhwolf.settings.ExperimentalSettingsApi
|
||||
import com.russhwolf.settings.PreferencesSettings
|
||||
import com.russhwolf.settings.coroutines.toSuspendSettings
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.prefs.Preferences
|
||||
|
||||
@OptIn(ExperimentalSettingsApi::class)
|
||||
class JvmSettings(
|
||||
nodeName: String,
|
||||
) : Settings {
|
||||
private val suspendSettings =
|
||||
PreferencesSettings(Preferences.userRoot().node(nodeName)).toSuspendSettings()
|
||||
|
||||
override suspend fun putString(key: String, value: String) = suspendSettings.putString(key, value)
|
||||
|
||||
override suspend fun getString(key: String, default: String) = suspendSettings.getString(key, default)
|
||||
|
||||
override suspend fun putInt(key: String, value: Int) = suspendSettings.putInt(key, value)
|
||||
|
||||
override suspend fun getInt(key: String, default: Int) = suspendSettings.getInt(key, default)
|
||||
|
||||
override suspend fun putLong(key: String, value: Long) = suspendSettings.putLong(key, value)
|
||||
|
||||
override suspend fun getLong(key: String, default: Long) = suspendSettings.getLong(key, default)
|
||||
|
||||
override suspend fun putFloat(key: String, value: Float) = suspendSettings.putFloat(key, value)
|
||||
|
||||
override suspend fun getFloat(key: String, default: Float) = suspendSettings.getFloat(key, default)
|
||||
|
||||
override suspend fun putBoolean(key: String, value: Boolean) = suspendSettings.putBoolean(key, value)
|
||||
|
||||
override suspend fun getBoolean(key: String, default: Boolean) = suspendSettings.getBoolean(key, default)
|
||||
|
||||
override suspend fun putStringSet(key: String, value: Set<String>) = withContext(Dispatchers.IO) {
|
||||
putStringList(key, value.toList())
|
||||
}
|
||||
|
||||
override suspend fun getStringSet(key: String, default: Set<String>) = withContext(Dispatchers.IO) {
|
||||
getStringList(key, default.toList()).toSet()
|
||||
}
|
||||
|
||||
override suspend fun remove(key: String) = suspendSettings.remove(key)
|
||||
|
||||
override suspend fun contains(key: String) = suspendSettings.hasKey(key)
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
package com.pr0gramm3r101.utils.settings
|
||||
|
||||
actual val settings: Settings get() = JvmSettings(nodeName = "ru.fromchat.settings")
|
||||
actual val secureSettings: Settings get() = JvmSettings(nodeName = "ru.fromchat.secure")
|
||||
Reference in New Issue
Block a user