Update dependencies, fix build warnings

Signed-off-by: denis0001-dev <denis0001.dev@ya.ru>
This commit is contained in:
2026-07-21 21:58:06 +03:00
Unverified
parent 032897b56d
commit 6b76161f80
17 changed files with 92 additions and 89 deletions
-5
View File
@@ -166,9 +166,4 @@ dependencies {
implementation(project(":app:shared")) implementation(project(":app:shared"))
implementation(project(":utils:shared")) implementation(project(":utils:shared"))
testImplementation("junit:junit:4.13.2")
testImplementation(libs.androidx.compose.material3)
testImplementation("androidx.graphics:graphics-shapes:1.0.1")
testImplementation("org.robolectric:robolectric:4.14.1")
} }
+3
View File
@@ -22,6 +22,9 @@
<meta-data <meta-data
android:name="com.google.firebase.messaging.default_notification_icon" android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_stat_fromchat" /> android:resource="@drawable/ic_stat_fromchat" />
<meta-data
android:name="firebase_messaging_installation_id_enabled"
android:value="true" />
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"
@@ -9,8 +9,8 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import ru.fromchat.Logger import ru.fromchat.Logger
import ru.fromchat.api.ApiClient import ru.fromchat.api.ApiClient
import ru.fromchat.notifications.NotificationHelper
import ru.fromchat.api.uploadPendingFcmTokenIfAvailable import ru.fromchat.api.uploadPendingFcmTokenIfAvailable
import ru.fromchat.notifications.NotificationHelper
@OptIn(DelicateCoroutinesApi::class) @OptIn(DelicateCoroutinesApi::class)
class FromChatFirebaseMessagingService : FirebaseMessagingService() { class FromChatFirebaseMessagingService : FirebaseMessagingService() {
@@ -65,18 +65,16 @@ class FromChatFirebaseMessagingService : FirebaseMessagingService() {
} }
} }
override fun onNewToken(token: String) { override fun onRegistered(installationId: String) {
Logger.i("FromChatFCM", "onNewToken received (...${token.takeLast(8)})") Logger.i("FromChatFCM", "onRegistered received (...${installationId.takeLast(8)})")
GlobalScope.launch(Dispatchers.IO) { GlobalScope.launch(Dispatchers.IO) {
try { try {
settings.putString("pending_fcm_token", token) settings.putString("pending_fcm_token", installationId)
uploadPendingFcmTokenIfAvailable() uploadPendingFcmTokenIfAvailable()
Logger.i("FromChatFCM", "FCM token queued or uploaded for this app instance") Logger.i("FromChatFCM", "FCM installation id queued or uploaded for this app instance")
} catch (e: Exception) { } catch (e: Exception) {
Logger.e("FromChatFCM", "onNewToken upload error: ${e.message}", e) Logger.e("FromChatFCM", "onRegistered upload error: ${e.message}", e)
} }
super.onNewToken(token)
} }
} }
} }
+2 -1
View File
@@ -1,3 +1,5 @@
@file:Suppress("TaskMissingDescription")
plugins { plugins {
alias(libs.plugins.kotlin.multiplatform) alias(libs.plugins.kotlin.multiplatform)
alias(libs.plugins.compose.multiplatform) alias(libs.plugins.compose.multiplatform)
@@ -21,7 +23,6 @@ kotlin {
listOf( listOf(
iosArm64(), iosArm64(),
iosSimulatorArm64(), iosSimulatorArm64(),
iosX64(),
).forEach { iosTarget -> ).forEach { iosTarget ->
iosTarget.binaries.framework { iosTarget.binaries.framework {
baseName = "ComposeApp" baseName = "ComposeApp"
@@ -1,6 +1,7 @@
package ru.fromchat.api package ru.fromchat.api
import com.google.android.gms.tasks.Task import com.google.android.gms.tasks.Task
import com.google.firebase.installations.FirebaseInstallations
import com.google.firebase.messaging.FirebaseMessaging import com.google.firebase.messaging.FirebaseMessaging
import com.pr0gramm3r101.utils.settings.settings import com.pr0gramm3r101.utils.settings.settings
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@@ -13,17 +14,25 @@ import kotlin.coroutines.resumeWithException
private const val PENDING_FCM_TOKEN_KEY = "pending_fcm_token" private const val PENDING_FCM_TOKEN_KEY = "pending_fcm_token"
private const val CURRENT_FCM_TOKEN_KEY = "current_fcm_token" private const val CURRENT_FCM_TOKEN_KEY = "current_fcm_token"
private suspend fun fetchCurrentFcmToken(): String? = suspendCancellableCoroutine { cont -> private suspend fun <T> Task<T>.awaitResult(): T = suspendCancellableCoroutine { cont ->
FirebaseMessaging.getInstance().token addOnCompleteListener { task ->
.addOnCompleteListener { task: Task<String> -> if (task.isSuccessful) {
if (task.isSuccessful) { cont.resume(task.result)
cont.resume(task.result) } else {
} else { cont.resumeWithException(
cont.resumeWithException( task.exception ?: IllegalStateException("Firebase task failed"),
task.exception ?: IllegalStateException("Failed to fetch FCM token") )
)
}
} }
}
}
/** Registers with FCM and returns the Firebase Installation ID used for targeting. */
private suspend fun fetchCurrentFcmToken(): String? = runCatching {
FirebaseMessaging.getInstance().register().awaitResult()
FirebaseInstallations.getInstance().id.awaitResult()
}.getOrElse { e ->
Logger.e("FcmReg", "Failed to fetch FCM installation id: ${e.message}", e)
null
} }
private suspend fun postFcmToken(token: String): Boolean { private suspend fun postFcmToken(token: String): Boolean {
@@ -40,7 +40,7 @@ internal actual suspend fun platformAesGcmStreamDecryptMekFile(
outputFile.delete() outputFile.delete()
} }
val cipher = GCMBlockCipher.newInstance(AESEngine()) val cipher = GCMBlockCipher.newInstance(AESEngine.newInstance())
cipher.init(false, AEADParameters(KeyParameter(key), 128, iv)) cipher.init(false, AEADParameters(KeyParameter(key), 128, iv))
val inBuf = ByteArray(FILE_DECRYPT_BUFFER_BYTES) val inBuf = ByteArray(FILE_DECRYPT_BUFFER_BYTES)
@@ -386,7 +386,7 @@ object MessageCacheStore {
if (product in 0.92f..1.08f && kotlin.math.abs(decodedAspect - serverAspect) > 0.15f) { if (product in 0.92f..1.08f && kotlin.math.abs(decodedAspect - serverAspect) > 0.15f) {
resolved = resolved.copy( resolved = resolved.copy(
fileAspectRatios = listOf(decodedAspect), fileAspectRatios = listOf(decodedAspect),
fileDimensions = thumbDims?.let { listOf(it.first to it.second) } ?: resolved.fileDimensions, fileDimensions = listOf(thumbDims.first to thumbDims.second),
) )
} }
} }
@@ -1189,7 +1189,7 @@ fun ChatScreen(
.getOrNull(panelState.messages.lastIndex - 1) .getOrNull(panelState.messages.lastIndex - 1)
previous != null && previous != null &&
messageListKey(previous) == listKey && messageListKey(previous) == listKey &&
classifyEnterMode(previous, newest!!) == classifyEnterMode(previous, newest) ==
EnterMode.ExtendGroup EnterMode.ExtendGroup
} }
val showTimestamp = when { val showTimestamp = when {
@@ -136,7 +136,7 @@ fun ChatFileAttachmentTile(
} }
} }
} }
downloadPaused && canDownload -> file?.let { downloadFile -> downloadPaused && file != null && canDownload -> {
{ {
AttachmentDownloadNotifier.beginDownload( AttachmentDownloadNotifier.beginDownload(
messageId = messageId, messageId = messageId,
@@ -148,7 +148,7 @@ fun ChatFileAttachmentTile(
val ok = downloadAttachmentToCache( val ok = downloadAttachmentToCache(
messageId = messageId, messageId = messageId,
fileIndex = fileIndex, fileIndex = fileIndex,
file = downloadFile, file = file,
dmEnvelope = dmEnvelope, dmEnvelope = dmEnvelope,
currentUserId = currentUserId, currentUserId = currentUserId,
clientMessageId = clientMessageId, clientMessageId = clientMessageId,
@@ -166,7 +166,7 @@ fun ChatFileAttachmentTile(
} }
} }
} }
canDownload && !isDownloading && !downloadPaused -> file?.let { downloadFile -> file != null && canDownload && !isDownloading && !downloadPaused -> {
{ {
AttachmentDownloadNotifier.beginDownload( AttachmentDownloadNotifier.beginDownload(
messageId = messageId, messageId = messageId,
@@ -178,7 +178,7 @@ fun ChatFileAttachmentTile(
val ok = downloadAttachmentToCache( val ok = downloadAttachmentToCache(
messageId = messageId, messageId = messageId,
fileIndex = fileIndex, fileIndex = fileIndex,
file = downloadFile, file = file,
dmEnvelope = dmEnvelope, dmEnvelope = dmEnvelope,
currentUserId = currentUserId, currentUserId = currentUserId,
clientMessageId = clientMessageId, clientMessageId = clientMessageId,
@@ -938,13 +938,13 @@ internal fun DmConversationRowContent(
val avatarUrl = if (isPeerDeleted) null else cached?.profilePicture val avatarUrl = if (isPeerDeleted) null else cached?.profilePicture
val peerTitle = when { val peerTitle = when {
isPeerDeleted -> deletedUserDisplayNameForUi() isPeerDeleted -> deletedUserDisplayNameForUi()
!cached?.displayName.isNullOrBlank() -> cached.displayName!!.trim() !cached?.displayName.isNullOrBlank() -> cached.displayName.trim()
conversation.displayName.isNotBlank() -> conversation.displayName conversation.displayName.isNotBlank() -> conversation.displayName
else -> cached?.visibleUsername(currentUserId).orEmpty() else -> cached?.visibleUsername(currentUserId).orEmpty()
} }
val avatarInitialsLabel = when { val avatarInitialsLabel = when {
isPeerDeleted -> deletedUserDisplayNameForUi() isPeerDeleted -> deletedUserDisplayNameForUi()
!cached?.displayName.isNullOrBlank() -> cached.displayName!!.trim() !cached?.displayName.isNullOrBlank() -> cached.displayName.trim()
conversation.displayName.isNotBlank() -> conversation.displayName conversation.displayName.isNotBlank() -> conversation.displayName
else -> "" else -> ""
} }
@@ -90,15 +90,14 @@ import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.layout.positionInRoot import androidx.compose.ui.layout.positionInRoot
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage import coil3.compose.AsyncImage
import com.pr0gramm3r101.utils.supportClipboardManagerImpl
import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
@@ -529,7 +528,7 @@ fun ChatsTab(
animatedVisibilityScope: AnimatedVisibilityScope? = null, animatedVisibilityScope: AnimatedVisibilityScope? = null,
) { ) {
val navController = LocalNavController.current val navController = LocalNavController.current
val clipboardManager = LocalClipboardManager.current val clipboard = supportClipboardManagerImpl
val haptic = rememberHapticFeedback() val haptic = rememberHapticFeedback()
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val connectionStatus by ConnectionStateStore.status.collectAsState() val connectionStatus by ConnectionStateStore.status.collectAsState()
@@ -1092,7 +1091,9 @@ fun ChatsTab(
chatContextMenuOverlay.onLink = { chatContextMenuOverlay.onLink = {
when (contextMenuState.target) { when (contextMenuState.target) {
ChatContextMenuTarget.Public -> { ChatContextMenuTarget.Public -> {
publicChatLink?.let { clipboardManager.setText(AnnotatedString(it)) } publicChatLink?.let { link ->
scope.launch { clipboard.setText(link) }
}
} }
ChatContextMenuTarget.Dm -> { ChatContextMenuTarget.Dm -> {
val link = contextMenuState.otherUserId?.let { userId -> val link = contextMenuState.otherUserId?.let { userId ->
@@ -1100,7 +1101,7 @@ fun ChatsTab(
val username = cached?.visibleUsername(ApiClient.user?.id) ?: cached?.username val username = cached?.visibleUsername(ApiClient.user?.id) ?: cached?.username
username?.let { "https://fromchat.ru/@$it" } ?: "https://fromchat.ru/?u=$userId" username?.let { "https://fromchat.ru/@$it" } ?: "https://fromchat.ru/?u=$userId"
} }
link?.let { clipboardManager.setText(AnnotatedString(it)) } link?.let { scope.launch { clipboard.setText(it) } }
} }
} }
} }
@@ -105,10 +105,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Rect import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.layout.positionInRoot import androidx.compose.ui.layout.positionInRoot
import androidx.compose.ui.platform.ClipboardManager
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.pr0gramm3r101.components.Category import com.pr0gramm3r101.components.Category
import com.pr0gramm3r101.components.ContextMenuPressable import com.pr0gramm3r101.components.ContextMenuPressable
@@ -267,7 +264,6 @@ fun ProfileScreen(
onOpenSettings: () -> Unit = {}, onOpenSettings: () -> Unit = {},
showBackButton: Boolean = false, showBackButton: Boolean = false,
) { ) {
val clipboardManager: ClipboardManager = LocalClipboardManager.current
val clipboard = supportClipboardManagerImpl val clipboard = supportClipboardManagerImpl
val navController = LocalNavController.current val navController = LocalNavController.current
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
@@ -377,7 +373,7 @@ fun ProfileScreen(
ApiClient.applyOwnProfile(refreshed) ApiClient.applyOwnProfile(refreshed)
state = latestUi.copy(profile = refreshed, error = null) state = latestUi.copy(profile = refreshed, error = null)
} catch (_: Exception) { } catch (_: Exception) {
ownUserId?.let { ProfileCache.get(it) }?.let { cached -> ownUserId.let { ProfileCache.get(it) }?.let { cached ->
state = latestUi.copy(profile = cached) state = latestUi.copy(profile = cached)
} }
} }
@@ -609,7 +605,7 @@ fun ProfileScreen(
ProfileAction( ProfileAction(
label = labelLink, label = labelLink,
icon = Icons.Filled.Link, icon = Icons.Filled.Link,
onClick = { clipboardManager.setText(AnnotatedString(profileLink.orEmpty())) }, onClick = { scope.launch { clipboard.setText(profileLink.orEmpty()) } },
), ),
ProfileAction( ProfileAction(
label = labelSettings, label = labelSettings,
@@ -654,7 +650,7 @@ fun ProfileScreen(
ProfileAction( ProfileAction(
label = labelLink, label = labelLink,
icon = Icons.Filled.Link, icon = Icons.Filled.Link,
onClick = { clipboardManager.setText(AnnotatedString(profileLink.orEmpty())) }, onClick = { scope.launch { clipboard.setText(profileLink.orEmpty()) } },
) )
) )
if (ServerConfig.callsEnabled) { if (ServerConfig.callsEnabled) {
@@ -831,7 +827,6 @@ fun ProfileScreen(
labelCopy = labelCopy, labelCopy = labelCopy,
labelEdit = labelEdit, labelEdit = labelEdit,
detailsBringIntoView = detailsBringIntoView, detailsBringIntoView = detailsBringIntoView,
clipboardManager = clipboardManager,
clipboard = clipboard, clipboard = clipboard,
navController = navController, navController = navController,
scope = scope, scope = scope,
@@ -880,7 +875,6 @@ fun PublicChatProfileScreen(
initialDisplayName: String? = null, initialDisplayName: String? = null,
showBackButton: Boolean = false, showBackButton: Boolean = false,
) { ) {
val clipboardManager = LocalClipboardManager.current
val clipboard = supportClipboardManagerImpl val clipboard = supportClipboardManagerImpl
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val snackbarHostState = remember { SnackbarHostState() } val snackbarHostState = remember { SnackbarHostState() }
@@ -962,7 +956,7 @@ fun PublicChatProfileScreen(
ProfileAction( ProfileAction(
label = labelLink, label = labelLink,
icon = Icons.Filled.Link, icon = Icons.Filled.Link,
onClick = { clipboardManager.setText(AnnotatedString(profileLink.orEmpty())) }, onClick = { scope.launch { clipboard.setText(profileLink.orEmpty()) } },
), ),
ProfileAction( ProfileAction(
label = labelSearch, label = labelSearch,
@@ -1003,15 +997,15 @@ fun PublicChatProfileScreen(
when { when {
useSharedAvatar && displayName.isNotBlank() -> { useSharedAvatar && displayName.isNotBlank() -> {
item { item {
with(sharedTransitionScope!!) { with(sharedTransitionScope) {
Avatar( Avatar(
profilePictureUrl = null, profilePictureUrl = null,
displayName = displayName, displayName = displayName,
modifier = Modifier modifier = Modifier
.padding(top = profileAvatarTop) .padding(top = profileAvatarTop)
.sharedElement( .sharedElement(
rememberSharedContentState(key = sharedAvatarKey!!), rememberSharedContentState(key = sharedAvatarKey),
animatedVisibilityScope = animatedVisibilityScope!!, animatedVisibilityScope = animatedVisibilityScope,
) )
.size(104.dp), .size(104.dp),
) )
@@ -1320,7 +1314,6 @@ private fun ProfileLoadedBody(
labelCopy: String, labelCopy: String,
labelEdit: String, labelEdit: String,
detailsBringIntoView: BringIntoViewRequester, detailsBringIntoView: BringIntoViewRequester,
clipboardManager: ClipboardManager,
clipboard: SupportClipboardManager, clipboard: SupportClipboardManager,
navController: NavController, navController: NavController,
scope: CoroutineScope, scope: CoroutineScope,
@@ -1349,7 +1342,7 @@ private fun ProfileLoadedBody(
onContextMenuOpen = openContextMenuHaptic, onContextMenuOpen = openContextMenuHaptic,
contextMenu = { contextMenu = {
item(Icons.Rounded.ContentCopy, labelCopy) { item(Icons.Rounded.ContentCopy, labelCopy) {
clipboardManager.setText(AnnotatedString(displayName)) scope.launch { clipboard.setText(displayName) }
} }
if (isOwnProfile) { if (isOwnProfile) {
item(Icons.Rounded.Edit, labelEdit) { item(Icons.Rounded.Edit, labelEdit) {
@@ -1453,9 +1446,9 @@ private fun ProfileLoadedBody(
}, },
contextMenu = { contextMenu = {
item(Icons.Rounded.ContentCopy, labelCopy) { item(Icons.Rounded.ContentCopy, labelCopy) {
clipboardManager.setText( scope.launch {
AnnotatedString(usernameForLinks.orEmpty()), clipboard.setText(usernameForLinks.orEmpty())
) }
} }
if (isOwnProfile) { if (isOwnProfile) {
item(Icons.Rounded.Edit, labelEdit) { item(Icons.Rounded.Edit, labelEdit) {
@@ -1491,7 +1484,7 @@ private fun ProfileLoadedBody(
}, },
contextMenu = { contextMenu = {
item(Icons.Rounded.ContentCopy, labelCopy) { item(Icons.Rounded.ContentCopy, labelCopy) {
clipboardManager.setText(AnnotatedString(memberSinceText)) scope.launch { clipboard.setText(memberSinceText) }
} }
}, },
) )
+23 -23
View File
@@ -1,52 +1,53 @@
[versions] [versions]
agp = "9.1.1" agp = "9.3.0"
androidx-activityCompose = "1.13.0" androidx-activityCompose = "1.13.0"
androidx-appcompat = "1.7.1" androidx-appcompat = "1.7.1"
androidx-core-ktx = "1.18.0" androidx-core-ktx = "1.19.0"
androidx-exifinterface = "1.3.7" androidx-exifinterface = "1.4.2"
coilCompose = "3.4.0" coilCompose = "3.5.0"
compose-multiplatform = "1.10.3" compose-multiplatform = "1.11.1"
#noinspection NewerVersionAvailable #noinspection NewerVersionAvailable
constraintlayout = "0.6.1-shaded" constraintlayout = "0.6.1-shaded"
coreSplashscreen = "1.2.0" coreSplashscreen = "1.2.0"
firebaseMessaging = "25.0.2" firebaseMessaging = "25.1.1"
googleServices = "4.4.4" googleServices = "4.5.0"
haze = "1.7.2" haze = "1.7.2"
kotlin = "2.3.21" junit = "4.13.2"
kotlin = "2.4.10"
adaptiveAndroid = "1.2.0" adaptiveAndroid = "1.2.0"
biometric = "1.4.0-alpha07" biometric = "1.4.0-alpha07"
gson = "2.14.0" gson = "2.14.0"
kotlinxIoBytestring = "0.9.0" kotlinxIoBytestring = "0.9.1"
kotlinxCoroutinesCore = "1.11.0" kotlinxCoroutinesCore = "1.11.0"
kotlinxIoCore = "0.9.0" kotlinxIoCore = "0.9.1"
multiplatformCryptoLibsodiumBindings = "0.9.5" multiplatformCryptoLibsodiumBindings = "0.9.5"
multiplatformSettings = "1.3.0" multiplatformSettings = "1.3.0"
serialization = "2.3.21" serialization = "2.4.10"
serialization-json = "1.11.0" serialization-json = "1.11.0"
material = "1.13.0" material = "1.14.0"
activityKtx = "1.13.0" activityKtx = "1.13.0"
navigationCompose = "2.9.2" navigationCompose = "2.9.2"
datastore = "1.2.1" datastore = "1.2.1"
security-crypto = "1.1.0" security-crypto = "1.1.0"
ktor = "3.4.3" ktor = "3.5.1"
slf4j = "1.7.36" slf4j = "1.7.36"
kotlinxDatetime = "0.8.0" kotlinxDatetime = "0.8.0"
lifecycleRuntimeKtx = "2.10.0" lifecycleRuntimeKtx = "2.11.0"
composeBom = "2026.05.00" composeBom = "2026.06.01"
composeMaterialIconsExtended = "1.7.3" composeMaterialIconsExtended = "1.7.3"
composeMaterial3 = "1.10.0-alpha05" composeMaterial3 = "1.10.0-alpha05"
composeComponents = "1.10.3" composeComponents = "1.11.1"
playServicesBase = "18.10.0" playServicesBase = "18.10.0"
tweetnaclJava = "1.1.3" tweetnaclJava = "1.1.3"
androidxWork = "2.11.2" androidxWork = "2.11.2"
cryptography-kotlin = "0.6.0" cryptography-kotlin = "0.6.0"
krypto = "4.0.10" krypto = "4.0.10"
sqldelight = "2.3.2" sqldelight = "2.3.2"
livekitAndroid = "2.25.2" livekitAndroid = "2.27.0"
livekitAndroidComposeComponents = "2.3.0" livekitAndroidComposeComponents = "2.4.0"
markdownRendererM3 = "0.41.0" markdownRendererM3 = "0.43.0"
bouncycastle = "1.79" bouncycastle = "1.85"
webkit = "1.14.0" webkit = "1.16.0"
[libraries] [libraries]
androidx-core-splashscreen = { module = "androidx.core:core-splashscreen", version.ref = "coreSplashscreen" } androidx-core-splashscreen = { module = "androidx.core:core-splashscreen", version.ref = "coreSplashscreen" }
@@ -66,6 +67,7 @@ haze-materials = { module = "dev.chrisbanes.haze:haze-materials", version.ref =
jetbrains-kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinxCoroutinesCore" } jetbrains-kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinxCoroutinesCore" }
jetbrains-kotlinx-io-bytestring = { module = "org.jetbrains.kotlinx:kotlinx-io-bytestring", version.ref = "kotlinxIoBytestring" } jetbrains-kotlinx-io-bytestring = { module = "org.jetbrains.kotlinx:kotlinx-io-bytestring", version.ref = "kotlinxIoBytestring" }
androidx-adaptive-android = { group = "androidx.compose.material3.adaptive", name = "adaptive-android", version.ref = "adaptiveAndroid" } androidx-adaptive-android = { group = "androidx.compose.material3.adaptive", name = "adaptive-android", version.ref = "adaptiveAndroid" }
junit = { module = "junit:junit", version.ref = "junit" }
kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib", version.ref = "kotlin" } kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib", version.ref = "kotlin" }
biometric = { module = "androidx.biometric:biometric", version.ref = "biometric" } biometric = { module = "androidx.biometric:biometric", version.ref = "biometric" }
gson = { module = "com.google.code.gson:gson", version.ref = "gson" } gson = { module = "com.google.code.gson:gson", version.ref = "gson" }
@@ -87,7 +89,6 @@ ktor-client-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-
ktor-client-websockets = { module = "io.ktor:ktor-client-websockets", version.ref = "ktor" } ktor-client-websockets = { module = "io.ktor:ktor-client-websockets", version.ref = "ktor" }
ktor-client-logging = { module = "io.ktor:ktor-client-logging", version.ref = "ktor" } ktor-client-logging = { module = "io.ktor:ktor-client-logging", version.ref = "ktor" }
ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" } ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" }
ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" }
ktor-client-darwin = { module = "io.ktor:ktor-client-darwin", version.ref = "ktor" } ktor-client-darwin = { module = "io.ktor:ktor-client-darwin", version.ref = "ktor" }
slf4j-android = { module = "org.slf4j:slf4j-android", version.ref = "slf4j" } slf4j-android = { module = "org.slf4j:slf4j-android", version.ref = "slf4j" }
kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinxDatetime" } kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinxDatetime" }
@@ -104,7 +105,6 @@ compose-foundation = { module = "org.jetbrains.compose.foundation:foundation", v
compose-material3 = { module = "org.jetbrains.compose.material3:material3", version.ref = "composeMaterial3" } compose-material3 = { module = "org.jetbrains.compose.material3:material3", version.ref = "composeMaterial3" }
compose-ui = { module = "org.jetbrains.compose.ui:ui", version.ref = "compose-multiplatform" } compose-ui = { module = "org.jetbrains.compose.ui:ui", version.ref = "compose-multiplatform" }
compose-components-resources = { module = "org.jetbrains.compose.components:components-resources", version.ref = "composeComponents" } compose-components-resources = { module = "org.jetbrains.compose.components:components-resources", version.ref = "composeComponents" }
compose-ui-tooling-preview = { module = "org.jetbrains.compose.ui:ui-tooling-preview", version.ref = "compose-multiplatform" }
compose-materialIconsExtended = { module = "org.jetbrains.compose.material:material-icons-extended", version.ref = "composeMaterialIconsExtended" } compose-materialIconsExtended = { module = "org.jetbrains.compose.material:material-icons-extended", version.ref = "composeMaterialIconsExtended" }
tweetnacl-java = { module = "org.purejava:tweetnacl-java", version.ref = "tweetnaclJava" } tweetnacl-java = { module = "org.purejava:tweetnacl-java", version.ref = "tweetnaclJava" }
krypto = { module = "com.soywiz.korlibs.krypto:krypto", version.ref = "krypto" } krypto = { module = "com.soywiz.korlibs.krypto:krypto", version.ref = "krypto" }
+2 -5
View File
@@ -1,9 +1,6 @@
#Tue Jul 21 20:27:03 MSK 2026
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip
networkTimeout=10000
retries=0
retryBackOffMs=500
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
+1 -2
View File
@@ -18,8 +18,7 @@ kotlin {
listOf( listOf(
iosArm64(), iosArm64(),
iosSimulatorArm64(), iosSimulatorArm64()
iosX64(),
).forEach { ).forEach {
it.binaries.framework { it.binaries.framework {
baseName = "shared" baseName = "shared"
@@ -17,7 +17,7 @@ actual fun Clipboard.toSupport(): SupportClipboardManager {
override suspend fun getText(): String? { override suspend fun getText(): String? {
val entry = clipboard.getClipEntry() ?: return null val entry = clipboard.getClipEntry() ?: return null
return entry.clipData?.getItemAt(0)?.text?.toString() return entry.clipData.getItemAt(0)?.text?.toString()
} }
override fun setTextListener(listener: (String) -> Unit) { override fun setTextListener(listener: (String) -> Unit) {
@@ -1,3 +1,5 @@
@file:Suppress("DEPRECATION")
package com.pr0gramm3r101.utils.settings package com.pr0gramm3r101.utils.settings
import androidx.core.content.edit import androidx.core.content.edit
@@ -7,6 +9,12 @@ import com.pr0gramm3r101.utils.UtilsLibrary.context
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
/**
* Secure prefs via EncryptedSharedPreferences.
*
* These APIs are deprecated in favor of DataStore + Tink (`datastore-tink`, DataStore 1.3+).
* Kept until that stack is stable enough to migrate auth/identity keys without risk.
*/
class AndroidSecureSettings : Settings { class AndroidSecureSettings : Settings {
private val masterKey by lazy { private val masterKey by lazy {
MasterKey.Builder(context) MasterKey.Builder(context)
@@ -80,4 +88,3 @@ class AndroidSecureSettings : Settings {
encryptedPrefs.contains(key) encryptedPrefs.contains(key)
} }
} }