diff --git a/KNOWN_ISSUES.md b/KNOWN_ISSUES.md index 17bbd57..066666e 100644 --- a/KNOWN_ISSUES.md +++ b/KNOWN_ISSUES.md @@ -16,7 +16,7 @@ **Key files**: - `feature/chat/.../components/MessageList.kt` — scroll logic, `pendingFineTuneScroll` flag - `feature/chat/.../components/MarkdownContent.kt` — `HighlightedTextSegment` with `onGloballyPositioned` -- `feature/chat/.../components/ContentPartRenderer.kt` — forwards `onFocusedOccurrencePositioned` callback +- `feature/chat/.../components/ContentPartRenderer.kt` — forwards `onFocusedOccurrencePosition` callback - `feature/chat/.../components/MessageBubble.kt` — forwards callback when `isCurrentSearchMatch` **What's needed**: On-device debugging session with Logcat/Timber to trace: diff --git a/app/detekt-baseline.xml b/app/detekt-baseline.xml deleted file mode 100644 index 9d0bc30..0000000 --- a/app/detekt-baseline.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - LambdaParameterInRestartableEffect:LibreChatNavHost.kt$onDeepLinkConsumed - MutableStateAutoboxing:MainActivity.kt$MainActivity$mutableStateOf(0) - ParameterNaming:LibreChatNavHost.kt$onDeepLinkConsumed - ViewModelForwarding:TabletLayout.kt$MainContent( navigator = navigator, navHostViewModel = navHostViewModel, isInAuthFlow = false, banners = banners, dismissedBannerIds = dismissedBannerIds, onToggleDrawer = { navHostViewModel.setTabletSidebarOpen(!isSidebarOpen) }, ) - ViewModelForwarding:TabletLayout.kt$MainContent( navigator = navigator, navHostViewModel = navHostViewModel, isInAuthFlow = true, banners = banners, dismissedBannerIds = dismissedBannerIds, onToggleDrawer = {}, modifier = Modifier.fillMaxSize(), ) - ViewModelForwarding:TabletLayout.kt$MainNavDisplay( navigator = navigator, navHostViewModel = navHostViewModel, onMenuClick = onToggleDrawer, modifier = Modifier.fillMaxSize(), ) - ViewModelForwarding:TabletLayout.kt$SidebarScaffold( viewModel = navHostViewModel, onNewChat = { if (navigator.currentRoute !is NewChat) { navigator.navigateToTopLevel(NewChat) } }, onConversationClick = { conversationId -> navigator.navigateToChat(conversationId) }, onSettingsClick = { navigator.navigate(SettingsTabbed) }, onSettingsCategorySelected = { category -> navigator.navigate(category.toRoute()) }, onAgentsClick = { navigator.navigate(AgentMarketplace) }, onFilesClick = { navigator.navigate(Files) }, modifier = Modifier .width(SidebarWidth) .fillMaxHeight(), ) - - diff --git a/app/src/androidTest/kotlin/com/garfiec/librechat/AuthFlowTest.kt b/app/src/androidTest/kotlin/com/garfiec/librechat/AuthFlowTest.kt index 9158299..d4e8ecc 100644 --- a/app/src/androidTest/kotlin/com/garfiec/librechat/AuthFlowTest.kt +++ b/app/src/androidTest/kotlin/com/garfiec/librechat/AuthFlowTest.kt @@ -20,7 +20,7 @@ class AuthFlowTest { composeTestRule.setContent { LibreChatTheme { ServerUrlScreen( - onServerValidated = {}, + onServerValidate = {}, ) } } diff --git a/app/src/main/kotlin/com/garfiec/librechat/MainActivity.kt b/app/src/main/kotlin/com/garfiec/librechat/MainActivity.kt index 1c4d61c..f2e451b 100644 --- a/app/src/main/kotlin/com/garfiec/librechat/MainActivity.kt +++ b/app/src/main/kotlin/com/garfiec/librechat/MainActivity.kt @@ -24,6 +24,7 @@ import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSiz import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass import androidx.compose.runtime.SideEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment @@ -55,7 +56,7 @@ class MainActivity : ComponentActivity() { * - Navigates to NewChat if the user is not on a chat screen, or * - Lets the active ChatViewModel consume the shared content in-place if already on a chat screen. */ - private var shareNavigationTrigger by mutableStateOf(0) + private var shareNavigationTrigger by mutableIntStateOf(0) @OptIn(ExperimentalMaterial3WindowSizeClassApi::class) override fun onCreate(savedInstanceState: Bundle?) { @@ -108,7 +109,7 @@ class MainActivity : ComponentActivity() { LibreChatNavHost( windowSizeClass = windowSizeClass, deepLinkUri = deepLinkUri, - onDeepLinkConsumed = { deepLinkUri = null }, + onDeepLinkConsume = { deepLinkUri = null }, shareNavigationTrigger = shareNavigationTrigger, modifier = Modifier.weight(1f), ) diff --git a/app/src/main/kotlin/com/garfiec/librechat/navigation/LibreChatNavHost.kt b/app/src/main/kotlin/com/garfiec/librechat/navigation/LibreChatNavHost.kt index a427840..38d5af4 100644 --- a/app/src/main/kotlin/com/garfiec/librechat/navigation/LibreChatNavHost.kt +++ b/app/src/main/kotlin/com/garfiec/librechat/navigation/LibreChatNavHost.kt @@ -5,6 +5,8 @@ import androidx.compose.material3.windowsizeclass.WindowSizeClass import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Modifier import co.touchlab.kermit.Logger import com.garfiec.librechat.MainActivity @@ -22,11 +24,12 @@ fun LibreChatNavHost( modifier: Modifier = Modifier, windowSizeClass: WindowSizeClass? = null, deepLinkUri: Uri? = null, - onDeepLinkConsumed: () -> Unit = {}, + onDeepLinkConsume: () -> Unit = {}, shareNavigationTrigger: Int = 0, ) { SharedLibreChatNavHost(modifier = modifier) { navigator, navHostViewModel, mod -> // Handle deep links + val currentOnDeepLinkConsume by rememberUpdatedState(onDeepLinkConsume) LaunchedEffect(deepLinkUri) { deepLinkUri?.let { uri -> if (uri.scheme == "librechat" && uri.host == "conversation") { @@ -38,7 +41,7 @@ fun LibreChatNavHost( } } } - onDeepLinkConsumed() + currentOnDeepLinkConsume() } } @@ -65,7 +68,6 @@ fun LibreChatNavHost( } else { PhoneLayout( navigator = navigator, - navHostViewModel = navHostViewModel, modifier = mod, ) } diff --git a/app/src/main/kotlin/com/garfiec/librechat/navigation/TabletLayout.kt b/app/src/main/kotlin/com/garfiec/librechat/navigation/TabletLayout.kt index d33eb57..2db3ca5 100644 --- a/app/src/main/kotlin/com/garfiec/librechat/navigation/TabletLayout.kt +++ b/app/src/main/kotlin/com/garfiec/librechat/navigation/TabletLayout.kt @@ -149,7 +149,6 @@ fun TabletLayout( // Slot 0: Sidebar -- always 320dp, slides from off-screen left to x=0 Row(modifier = Modifier.fillMaxHeight()) { SidebarScaffold( - viewModel = navHostViewModel, onNewChat = { if (navigator.currentRoute !is NewChat) { navigator.navigateToTopLevel(NewChat) @@ -161,7 +160,7 @@ fun TabletLayout( onSettingsClick = { navigator.navigate(SettingsTabbed) }, - onSettingsCategorySelected = { category -> + onSettingsCategorySelect = { category -> navigator.navigate(category.toRoute()) }, onAgentsClick = { @@ -181,10 +180,10 @@ fun TabletLayout( // Slot 1: Main content -- resizes to fill remaining space MainContent( navigator = navigator, - navHostViewModel = navHostViewModel, isInAuthFlow = false, banners = banners, dismissedBannerIds = dismissedBannerIds, + onDismissBanner = navHostViewModel::dismissBanner, onToggleDrawer = { navHostViewModel.setTabletSidebarOpen(!isSidebarOpen) }, @@ -212,10 +211,10 @@ fun TabletLayout( // Auth flow -- no sidebar, just main content MainContent( navigator = navigator, - navHostViewModel = navHostViewModel, isInAuthFlow = true, banners = banners, dismissedBannerIds = dismissedBannerIds, + onDismissBanner = navHostViewModel::dismissBanner, onToggleDrawer = {}, modifier = Modifier.fillMaxSize(), ) @@ -225,10 +224,10 @@ fun TabletLayout( @Composable private fun MainContent( navigator: Navigator, - navHostViewModel: NavHostViewModel, isInAuthFlow: Boolean, banners: List, dismissedBannerIds: Set, + onDismissBanner: (String) -> Unit, onToggleDrawer: () -> Unit, modifier: Modifier = Modifier, ) { @@ -237,13 +236,12 @@ private fun MainContent( BannerDisplay( banners = banners, dismissedIds = dismissedBannerIds, - onDismiss = navHostViewModel::dismissBanner, + onDismiss = onDismissBanner, modifier = Modifier.padding(top = 4.dp), ) } MainNavDisplay( navigator = navigator, - navHostViewModel = navHostViewModel, onMenuClick = onToggleDrawer, modifier = Modifier.fillMaxSize(), ) diff --git a/app/src/test/kotlin/com/garfiec/librechat/KoinGraphVerificationTest.kt b/app/src/test/kotlin/com/garfiec/librechat/KoinGraphVerificationTest.kt index a86a54f..eb37dc8 100644 --- a/app/src/test/kotlin/com/garfiec/librechat/KoinGraphVerificationTest.kt +++ b/app/src/test/kotlin/com/garfiec/librechat/KoinGraphVerificationTest.kt @@ -2,7 +2,6 @@ package com.garfiec.librechat import android.app.Application import android.content.Context -import androidx.lifecycle.SavedStateHandle import com.garfiec.librechat.core.common.di.commonModule import com.garfiec.librechat.core.common.network.ConnectivityObserver import com.garfiec.librechat.core.data.datastore.ConfigCacheDataStore @@ -105,7 +104,6 @@ class KoinGraphVerificationTest { // Android framework Context::class, Application::class, - SavedStateHandle::class, // core:common provides CoroutineDispatcher::class, CoroutineScope::class, diff --git a/build-logic/convention/src/main/kotlin/DetektConventionPlugin.kt b/build-logic/convention/src/main/kotlin/DetektConventionPlugin.kt index 93a8010..e6873c8 100644 --- a/build-logic/convention/src/main/kotlin/DetektConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/DetektConventionPlugin.kt @@ -1,8 +1,10 @@ +import io.gitlab.arturbosch.detekt.DetektCreateBaselineTask import io.gitlab.arturbosch.detekt.extensions.DetektExtension import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.kotlin.dsl.configure import org.gradle.kotlin.dsl.dependencies +import org.gradle.kotlin.dsl.withType class DetektConventionPlugin : Plugin { override fun apply(target: Project) { @@ -14,7 +16,10 @@ class DetektConventionPlugin : Plugin { buildUponDefaultConfig = true allRules = false parallel = true - baseline = file("detekt-baseline.xml") + } + + tasks.withType().configureEach { + enabled = false } dependencies { diff --git a/build-logic/convention/src/main/kotlin/KmpComposeConventionPlugin.kt b/build-logic/convention/src/main/kotlin/KmpComposeConventionPlugin.kt index cbfcbf1..d510fc2 100644 --- a/build-logic/convention/src/main/kotlin/KmpComposeConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/KmpComposeConventionPlugin.kt @@ -3,6 +3,7 @@ import org.gradle.api.Project import org.gradle.kotlin.dsl.configure import org.gradle.kotlin.dsl.getByType import org.jetbrains.compose.ComposeExtension +import org.jetbrains.compose.resources.ResourcesExtension import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension class KmpComposeConventionPlugin : Plugin { @@ -11,7 +12,16 @@ class KmpComposeConventionPlugin : Plugin { pluginManager.apply("org.jetbrains.compose") pluginManager.apply("org.jetbrains.kotlin.plugin.compose") - val compose = extensions.getByType().dependencies + val composeExtension = extensions.getByType() + val compose = composeExtension.dependencies + + // Override Compose Resources' default package. ResourcesExtension is a + // sub-extension of ComposeExtension — `extensions.configure` + // at project level throws "extension does not exist". + composeExtension.extensions.configure { + val modulePath = project.path.removePrefix(":").replace(":", ".") + packageOfResClass = "com.garfiec.librechat.$modulePath.resources" + } extensions.configure { sourceSets.commonMain.dependencies { diff --git a/config/detekt/detekt.yml b/config/detekt/detekt.yml index 0b82b2a..1fd1584 100644 --- a/config/detekt/detekt.yml +++ b/config/detekt/detekt.yml @@ -45,6 +45,8 @@ style: excludePackageStatements: true excludeImportStatements: true excludeRawStrings: true + excludes: + - "**/build/generated/compose/resourceGenerator/**" ForbiddenComment: active: false UnusedPrivateMember: @@ -52,11 +54,14 @@ style: allowedNames: "(_|ignored|expected|serialVersionUID)" ignoreAnnotated: - "Preview" + UnusedPrivateProperty: + active: true + allowedNames: "(_|ignored|expected|serialVersionUID)" WildcardImport: active: true excludeImports: - "kotlinx.coroutines.flow.*" - - "*.generated.resources.*" + - "*.resources.*" LoopWithTooManyJumpStatements: maxJumpCount: 3 ThrowsCount: @@ -70,6 +75,19 @@ naming: FunctionNaming: ignoreAnnotated: - "Composable" + # Detekt's `excludes:` REPLACES (does not merge with) the default value, so + # the default test-source exemptions must be repeated here alongside the + # generated-resources exclude. + excludes: + - "**/test/**" + - "**/androidTest/**" + - "**/commonTest/**" + - "**/jvmTest/**" + - "**/androidUnitTest/**" + - "**/androidInstrumentedTest/**" + - "**/jsTest/**" + - "**/iosTest/**" + - "**/build/generated/compose/resourceGenerator/**" TopLevelPropertyNaming: constantPattern: "[A-Z][A-Za-z0-9_]*" MatchingDeclarationName: @@ -131,3 +149,6 @@ formatting: active: false FunctionSignature: active: false + ImportOrdering: + excludes: + - "**/build/generated/compose/resourceGenerator/**" diff --git a/core/common/detekt-baseline.xml b/core/common/detekt-baseline.xml deleted file mode 100644 index 1b8d918..0000000 --- a/core/common/detekt-baseline.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - ImportOrdering:DateExt.kt$import kotlin.time.Clock import kotlin.time.Instant import kotlinx.datetime.LocalDate import kotlinx.datetime.TimeZone import kotlinx.datetime.daysUntil import kotlinx.datetime.toLocalDateTime - ImportOrdering:FlowExt.kt$import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.retryWhen import kotlin.time.Clock import kotlin.math.pow - NoUnusedImports:CommonModule.kt$com.garfiec.librechat.core.common.di.CommonModule.kt - - diff --git a/core/common/src/commonMain/kotlin/com/garfiec/librechat/core/common/di/CommonModule.kt b/core/common/src/commonMain/kotlin/com/garfiec/librechat/core/common/di/CommonModule.kt index 1898432..3e5a8e4 100644 --- a/core/common/src/commonMain/kotlin/com/garfiec/librechat/core/common/di/CommonModule.kt +++ b/core/common/src/commonMain/kotlin/com/garfiec/librechat/core/common/di/CommonModule.kt @@ -1,12 +1,10 @@ package com.garfiec.librechat.core.common.di -import com.garfiec.librechat.core.common.network.ConnectivityObserver import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import org.koin.core.module.Module -import org.koin.core.module.dsl.singleOf import org.koin.dsl.module expect val commonPlatformModule: Module diff --git a/core/common/src/commonMain/kotlin/com/garfiec/librechat/core/common/extensions/DateExt.kt b/core/common/src/commonMain/kotlin/com/garfiec/librechat/core/common/extensions/DateExt.kt index e4d2066..9042192 100644 --- a/core/common/src/commonMain/kotlin/com/garfiec/librechat/core/common/extensions/DateExt.kt +++ b/core/common/src/commonMain/kotlin/com/garfiec/librechat/core/common/extensions/DateExt.kt @@ -1,11 +1,11 @@ package com.garfiec.librechat.core.common.extensions -import kotlin.time.Clock -import kotlin.time.Instant import kotlinx.datetime.LocalDate import kotlinx.datetime.TimeZone import kotlinx.datetime.daysUntil import kotlinx.datetime.toLocalDateTime +import kotlin.time.Clock +import kotlin.time.Instant fun String.toInstantOrNull(): Instant? = try { Instant.parse(this) } catch (_: Exception) { null } diff --git a/core/common/src/commonMain/kotlin/com/garfiec/librechat/core/common/extensions/FlowExt.kt b/core/common/src/commonMain/kotlin/com/garfiec/librechat/core/common/extensions/FlowExt.kt index 4c83b80..3a4c5f4 100644 --- a/core/common/src/commonMain/kotlin/com/garfiec/librechat/core/common/extensions/FlowExt.kt +++ b/core/common/src/commonMain/kotlin/com/garfiec/librechat/core/common/extensions/FlowExt.kt @@ -4,8 +4,8 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.retryWhen -import kotlin.time.Clock import kotlin.math.pow +import kotlin.time.Clock fun Flow.retryWithBackoff( maxRetries: Int = 3, diff --git a/core/data/detekt-baseline.xml b/core/data/detekt-baseline.xml deleted file mode 100644 index 8e40f4b..0000000 --- a/core/data/detekt-baseline.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - ImportOrdering:ConfigCacheDataStore.kt$import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.stringPreferencesKey import com.garfiec.librechat.core.model.EndpointConfig import com.garfiec.librechat.core.model.config.StartupConfig import kotlinx.coroutines.flow.first import kotlinx.serialization.builtins.ListSerializer import kotlinx.serialization.builtins.MapSerializer import kotlinx.serialization.builtins.serializer import kotlinx.serialization.json.Json import co.touchlab.kermit.Logger - ImportOrdering:ConfigRepositoryImpl.kt$import com.garfiec.librechat.core.common.BackendVersion import com.garfiec.librechat.core.common.result.ApiException import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.common.result.safeApiCall import com.garfiec.librechat.core.data.datastore.ConfigCacheDataStore import com.garfiec.librechat.core.model.EndpointConfig import com.garfiec.librechat.core.model.config.StartupConfig import com.garfiec.librechat.core.network.api.ConfigApi import io.ktor.client.plugins.HttpRequestTimeoutException import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.serialization.SerializationException import co.touchlab.kermit.Logger - ImportOrdering:ConversationMapper.kt$import com.garfiec.librechat.core.data.db.entity.ConversationEntity import com.garfiec.librechat.core.model.Conversation import com.garfiec.librechat.core.model.EModelEndpoint import kotlin.time.Clock import kotlin.time.Instant import kotlinx.serialization.builtins.ListSerializer import kotlinx.serialization.json.Json import kotlinx.serialization.serializer - ImportOrdering:ConversationRepositoryImpl.kt$import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.common.result.safeApiCall import com.garfiec.librechat.core.data.db.dao.ConversationDao import com.garfiec.librechat.core.data.mapper.toEntity import com.garfiec.librechat.core.data.mapper.toModel import com.garfiec.librechat.core.data.mapper.toModels import com.garfiec.librechat.core.model.Conversation import com.garfiec.librechat.core.model.request.ForkConversationRequest import com.garfiec.librechat.core.network.api.ConversationsApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import kotlin.time.Clock import co.touchlab.kermit.Logger - ImportOrdering:MessageMapper.kt$import com.garfiec.librechat.core.data.db.entity.MessageEntity import com.garfiec.librechat.core.model.Attachment import com.garfiec.librechat.core.model.Feedback import com.garfiec.librechat.core.model.FileReference import com.garfiec.librechat.core.model.Message import com.garfiec.librechat.core.model.content.MessageContentPart import kotlin.time.Clock import kotlin.time.Instant import kotlinx.serialization.builtins.ListSerializer import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonObject - ImportOrdering:MessageRepositoryImpl.kt$import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.common.result.safeApiCall import com.garfiec.librechat.core.data.db.dao.MessageDao import com.garfiec.librechat.core.data.mapper.toEntity import com.garfiec.librechat.core.data.mapper.toModels import com.garfiec.librechat.core.model.Message import com.garfiec.librechat.core.model.request.BranchMessageRequest import com.garfiec.librechat.core.model.request.UpdateMessageRequest import com.garfiec.librechat.core.network.api.MessagesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map import co.touchlab.kermit.Logger - NoUnusedImports:DataModule.kt$com.garfiec.librechat.core.data.di.DataModule.kt - - diff --git a/core/data/src/androidUnitTest/kotlin/com/garfiec/librechat/core/data/di/DataModuleVerificationTest.kt b/core/data/src/androidUnitTest/kotlin/com/garfiec/librechat/core/data/di/DataModuleVerificationTest.kt index ff3684e..a24a99f 100644 --- a/core/data/src/androidUnitTest/kotlin/com/garfiec/librechat/core/data/di/DataModuleVerificationTest.kt +++ b/core/data/src/androidUnitTest/kotlin/com/garfiec/librechat/core/data/di/DataModuleVerificationTest.kt @@ -3,7 +3,6 @@ package com.garfiec.librechat.core.data.di import android.app.Application import android.content.Context import androidx.datastore.core.DataStore -import androidx.lifecycle.SavedStateHandle import com.garfiec.librechat.core.common.network.ConnectivityObserver import com.garfiec.librechat.core.network.api.AgentsApi import com.garfiec.librechat.core.network.api.ApiKeysApi @@ -40,7 +39,6 @@ class DataModuleVerificationTest { extraTypes = listOf( Context::class, Application::class, - SavedStateHandle::class, Lazy::class, HttpClient::class, Json::class, diff --git a/core/data/src/commonMain/kotlin/com/garfiec/librechat/core/data/datastore/ConfigCacheDataStore.kt b/core/data/src/commonMain/kotlin/com/garfiec/librechat/core/data/datastore/ConfigCacheDataStore.kt index ea82214..f8ebbd5 100644 --- a/core/data/src/commonMain/kotlin/com/garfiec/librechat/core/data/datastore/ConfigCacheDataStore.kt +++ b/core/data/src/commonMain/kotlin/com/garfiec/librechat/core/data/datastore/ConfigCacheDataStore.kt @@ -4,6 +4,7 @@ import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.stringPreferencesKey +import co.touchlab.kermit.Logger import com.garfiec.librechat.core.model.EndpointConfig import com.garfiec.librechat.core.model.config.StartupConfig import kotlinx.coroutines.flow.first @@ -11,7 +12,6 @@ import kotlinx.serialization.builtins.ListSerializer import kotlinx.serialization.builtins.MapSerializer import kotlinx.serialization.builtins.serializer import kotlinx.serialization.json.Json -import co.touchlab.kermit.Logger class ConfigCacheDataStore( private val dataStore: DataStore, diff --git a/core/data/src/commonMain/kotlin/com/garfiec/librechat/core/data/di/DataModule.kt b/core/data/src/commonMain/kotlin/com/garfiec/librechat/core/data/di/DataModule.kt index 9d43699..7155cf2 100644 --- a/core/data/src/commonMain/kotlin/com/garfiec/librechat/core/data/di/DataModule.kt +++ b/core/data/src/commonMain/kotlin/com/garfiec/librechat/core/data/di/DataModule.kt @@ -3,7 +3,6 @@ package com.garfiec.librechat.core.data.di import com.garfiec.librechat.core.common.di.KoinQualifiers import com.garfiec.librechat.core.data.datastore.ConfigCacheDataStore import com.garfiec.librechat.core.data.datastore.ServerDataStore -import com.garfiec.librechat.core.data.datastore.ServerUrlKeychainFallback import com.garfiec.librechat.core.data.datastore.SettingsDataStore import com.garfiec.librechat.core.data.datastore.ThemeDataStore import com.garfiec.librechat.core.data.db.LibreChatDatabase @@ -41,7 +40,6 @@ import com.garfiec.librechat.core.data.repository.PromptRepository import com.garfiec.librechat.core.data.repository.PromptRepositoryImpl import com.garfiec.librechat.core.data.repository.SearchRepository import com.garfiec.librechat.core.data.repository.SearchRepositoryImpl -import com.garfiec.librechat.core.data.repository.SessionCacheCleaner import com.garfiec.librechat.core.data.repository.ShareRepository import com.garfiec.librechat.core.data.repository.ShareRepositoryImpl import com.garfiec.librechat.core.data.repository.SpeechRepository diff --git a/core/data/src/commonMain/kotlin/com/garfiec/librechat/core/data/mapper/ConversationMapper.kt b/core/data/src/commonMain/kotlin/com/garfiec/librechat/core/data/mapper/ConversationMapper.kt index 7e2f693..1ebe453 100644 --- a/core/data/src/commonMain/kotlin/com/garfiec/librechat/core/data/mapper/ConversationMapper.kt +++ b/core/data/src/commonMain/kotlin/com/garfiec/librechat/core/data/mapper/ConversationMapper.kt @@ -3,11 +3,11 @@ package com.garfiec.librechat.core.data.mapper import com.garfiec.librechat.core.data.db.entity.ConversationEntity import com.garfiec.librechat.core.model.Conversation import com.garfiec.librechat.core.model.EModelEndpoint -import kotlin.time.Clock -import kotlin.time.Instant import kotlinx.serialization.builtins.ListSerializer import kotlinx.serialization.json.Json import kotlinx.serialization.serializer +import kotlin.time.Clock +import kotlin.time.Instant private val json = Json { ignoreUnknownKeys = true } diff --git a/core/data/src/commonMain/kotlin/com/garfiec/librechat/core/data/mapper/MessageMapper.kt b/core/data/src/commonMain/kotlin/com/garfiec/librechat/core/data/mapper/MessageMapper.kt index 9f08618..748f2e3 100644 --- a/core/data/src/commonMain/kotlin/com/garfiec/librechat/core/data/mapper/MessageMapper.kt +++ b/core/data/src/commonMain/kotlin/com/garfiec/librechat/core/data/mapper/MessageMapper.kt @@ -6,11 +6,11 @@ import com.garfiec.librechat.core.model.Feedback import com.garfiec.librechat.core.model.FileReference import com.garfiec.librechat.core.model.Message import com.garfiec.librechat.core.model.content.MessageContentPart -import kotlin.time.Clock -import kotlin.time.Instant import kotlinx.serialization.builtins.ListSerializer import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonObject +import kotlin.time.Clock +import kotlin.time.Instant private val json = Json { ignoreUnknownKeys = true } diff --git a/core/data/src/commonMain/kotlin/com/garfiec/librechat/core/data/repository/ConfigRepositoryImpl.kt b/core/data/src/commonMain/kotlin/com/garfiec/librechat/core/data/repository/ConfigRepositoryImpl.kt index 9214d10..e8ab03f 100644 --- a/core/data/src/commonMain/kotlin/com/garfiec/librechat/core/data/repository/ConfigRepositoryImpl.kt +++ b/core/data/src/commonMain/kotlin/com/garfiec/librechat/core/data/repository/ConfigRepositoryImpl.kt @@ -1,5 +1,6 @@ package com.garfiec.librechat.core.data.repository +import co.touchlab.kermit.Logger import com.garfiec.librechat.core.common.BackendVersion import com.garfiec.librechat.core.common.result.ApiException import com.garfiec.librechat.core.common.result.Result @@ -13,7 +14,6 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.serialization.SerializationException -import co.touchlab.kermit.Logger class ConfigRepositoryImpl( private val configApi: ConfigApi, diff --git a/core/data/src/commonMain/kotlin/com/garfiec/librechat/core/data/repository/ConversationRepositoryImpl.kt b/core/data/src/commonMain/kotlin/com/garfiec/librechat/core/data/repository/ConversationRepositoryImpl.kt index c6ed028..d938f69 100644 --- a/core/data/src/commonMain/kotlin/com/garfiec/librechat/core/data/repository/ConversationRepositoryImpl.kt +++ b/core/data/src/commonMain/kotlin/com/garfiec/librechat/core/data/repository/ConversationRepositoryImpl.kt @@ -1,5 +1,6 @@ package com.garfiec.librechat.core.data.repository +import co.touchlab.kermit.Logger import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.common.result.safeApiCall import com.garfiec.librechat.core.data.db.dao.ConversationDao @@ -12,7 +13,6 @@ import com.garfiec.librechat.core.network.api.ConversationsApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import kotlin.time.Clock -import co.touchlab.kermit.Logger class ConversationRepositoryImpl( private val conversationsApi: ConversationsApi, diff --git a/core/data/src/commonMain/kotlin/com/garfiec/librechat/core/data/repository/MessageRepositoryImpl.kt b/core/data/src/commonMain/kotlin/com/garfiec/librechat/core/data/repository/MessageRepositoryImpl.kt index f15c88f..e7bf1ac 100644 --- a/core/data/src/commonMain/kotlin/com/garfiec/librechat/core/data/repository/MessageRepositoryImpl.kt +++ b/core/data/src/commonMain/kotlin/com/garfiec/librechat/core/data/repository/MessageRepositoryImpl.kt @@ -1,5 +1,6 @@ package com.garfiec.librechat.core.data.repository +import co.touchlab.kermit.Logger import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.common.result.safeApiCall import com.garfiec.librechat.core.data.db.dao.MessageDao @@ -12,7 +13,6 @@ import com.garfiec.librechat.core.network.api.MessagesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map -import co.touchlab.kermit.Logger class MessageRepositoryImpl( private val messagesApi: MessagesApi, diff --git a/core/data/src/iosMain/kotlin/com/garfiec/librechat/core/data/datastore/IosTokenDataStore.kt b/core/data/src/iosMain/kotlin/com/garfiec/librechat/core/data/datastore/IosTokenDataStore.kt index dc60e68..271c8f4 100644 --- a/core/data/src/iosMain/kotlin/com/garfiec/librechat/core/data/datastore/IosTokenDataStore.kt +++ b/core/data/src/iosMain/kotlin/com/garfiec/librechat/core/data/datastore/IosTokenDataStore.kt @@ -1,5 +1,6 @@ package com.garfiec.librechat.core.data.datastore +import co.touchlab.kermit.Logger import io.ktor.client.HttpClient import kotlinx.cinterop.BetaInteropApi import kotlinx.cinterop.ExperimentalForeignApi @@ -9,9 +10,7 @@ import kotlinx.cinterop.ptr import kotlinx.cinterop.value import platform.CoreFoundation.CFDictionaryAddValue import platform.CoreFoundation.CFDictionaryCreateMutable -import platform.CoreFoundation.CFMutableDictionaryRef import platform.CoreFoundation.CFRelease -import platform.CoreFoundation.CFTypeRef import platform.CoreFoundation.CFTypeRefVar import platform.CoreFoundation.kCFBooleanTrue import platform.Foundation.CFBridgingRelease @@ -35,7 +34,6 @@ import platform.Security.kSecMatchLimit import platform.Security.kSecMatchLimitOne import platform.Security.kSecReturnData import platform.Security.kSecValueData -import co.touchlab.kermit.Logger @OptIn(ExperimentalForeignApi::class, BetaInteropApi::class) class IosTokenDataStore( diff --git a/core/model/detekt-baseline.xml b/core/model/detekt-baseline.xml deleted file mode 100644 index 5d3d383..0000000 --- a/core/model/detekt-baseline.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - NoUnusedImports:StartupConfig.kt$com.garfiec.librechat.core.model.config.StartupConfig.kt - - diff --git a/core/model/src/commonMain/kotlin/com/garfiec/librechat/core/model/config/StartupConfig.kt b/core/model/src/commonMain/kotlin/com/garfiec/librechat/core/model/config/StartupConfig.kt index 59d6dd3..455ec35 100644 --- a/core/model/src/commonMain/kotlin/com/garfiec/librechat/core/model/config/StartupConfig.kt +++ b/core/model/src/commonMain/kotlin/com/garfiec/librechat/core/model/config/StartupConfig.kt @@ -1,6 +1,5 @@ package com.garfiec.librechat.core.model.config -import com.garfiec.librechat.core.model.Preset import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonObject diff --git a/core/network/detekt-baseline.xml b/core/network/detekt-baseline.xml deleted file mode 100644 index 8c7baa4..0000000 --- a/core/network/detekt-baseline.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - ImportOrdering:AgentsApi.kt$import com.garfiec.librechat.core.model.Agent import com.garfiec.librechat.core.model.AgentAction import com.garfiec.librechat.core.model.AgentCategory import com.garfiec.librechat.core.model.AgentExpanded import com.garfiec.librechat.core.model.AgentTool import com.garfiec.librechat.core.model.ToolAuthStatus import com.garfiec.librechat.core.model.ToolCallRecord import com.garfiec.librechat.core.model.ToolCallResult import com.garfiec.librechat.core.model.request.CreateActionRequest import com.garfiec.librechat.core.model.request.CreateAgentRequest import com.garfiec.librechat.core.model.request.RevertAgentRequest import com.garfiec.librechat.core.model.request.ToolCallRequest import com.garfiec.librechat.core.model.request.UpdateAgentRequest import com.garfiec.librechat.core.model.response.AgentListResponse import io.ktor.client.HttpClient import io.ktor.client.call.body import io.ktor.client.request.delete import io.ktor.client.request.forms.formData import io.ktor.client.request.forms.submitFormWithBinaryData import io.ktor.client.request.get import io.ktor.client.request.parameter import io.ktor.client.request.patch import io.ktor.client.request.post import io.ktor.client.request.setBody import io.ktor.http.Headers import io.ktor.http.HttpHeaders import io.ktor.http.path import kotlinx.serialization.json.JsonArray import co.touchlab.kermit.Logger - ImportOrdering:AuthApi.kt$import com.garfiec.librechat.core.network.api.dto.LoginResult import com.garfiec.librechat.core.network.api.dto.RefreshResult import com.garfiec.librechat.core.network.api.dto.TwoFactorConfirmRequest import com.garfiec.librechat.core.model.request.LoginRequest import com.garfiec.librechat.core.model.request.OtpVerificationRequest import com.garfiec.librechat.core.model.request.PasswordResetRequest import com.garfiec.librechat.core.model.request.RegisterRequest import com.garfiec.librechat.core.model.request.ResetPasswordRequest import com.garfiec.librechat.core.model.request.TwoFactorDisableRequest import com.garfiec.librechat.core.model.request.TwoFactorVerifyRequest import com.garfiec.librechat.core.model.request.TwoFactorVerifyTempRequest import com.garfiec.librechat.core.model.response.LoginResponse import com.garfiec.librechat.core.model.response.RefreshResponse import com.garfiec.librechat.core.model.response.RegisterResponse import com.garfiec.librechat.core.model.response.TwoFactorSetupResponse import com.garfiec.librechat.core.network.client.CookieHelper import io.ktor.client.HttpClient import io.ktor.client.call.body import io.ktor.client.request.header import io.ktor.client.request.post import io.ktor.client.request.setBody import io.ktor.http.path - ImportOrdering:LibreChatHttpClient.kt$import co.touchlab.kermit.Logger import io.ktor.client.HttpClient import io.ktor.client.engine.HttpClientEngineFactory import io.ktor.client.plugins.HttpRequestRetry import io.ktor.client.plugins.HttpResponseValidator import io.ktor.client.plugins.HttpTimeout import io.ktor.client.plugins.contentnegotiation.ContentNegotiation import io.ktor.client.plugins.defaultRequest import io.ktor.client.plugins.logging.LogLevel import io.ktor.client.plugins.logging.Logger as KtorLogger import io.ktor.client.plugins.logging.Logging import io.ktor.client.statement.bodyAsText import io.ktor.http.ContentType import io.ktor.http.HttpHeaders import io.ktor.http.contentType import io.ktor.http.isSuccess import io.ktor.http.takeFrom import io.ktor.serialization.kotlinx.json.json import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.jsonObject - ImportOrdering:SseEventMapper.kt$import com.garfiec.librechat.core.model.Conversation import com.garfiec.librechat.core.model.Message import com.garfiec.librechat.core.model.StreamEvent import com.garfiec.librechat.core.model.content.MessageContentPart import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.booleanOrNull import kotlinx.serialization.json.contentOrNull import kotlinx.serialization.json.intOrNull import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonPrimitive import co.touchlab.kermit.Logger - ImportOrdering:UserApi.kt$import com.garfiec.librechat.core.network.api.dto.UpdateFavoritesRequest import com.garfiec.librechat.core.network.api.dto.UpdatePluginsRequest import com.garfiec.librechat.core.network.api.dto.UserUpdateRequest import com.garfiec.librechat.core.model.User import com.garfiec.librechat.core.model.UserFavorite import com.garfiec.librechat.core.model.request.OtpVerificationRequest import com.garfiec.librechat.core.model.request.ResendVerificationRequest import com.garfiec.librechat.core.model.request.VerifyEmailRequest import com.garfiec.librechat.core.model.response.TermsResponse import io.ktor.client.HttpClient import io.ktor.client.call.body import io.ktor.client.request.delete import io.ktor.client.request.forms.formData import io.ktor.client.request.forms.submitFormWithBinaryData import io.ktor.client.request.get import io.ktor.client.request.post import io.ktor.client.request.setBody import io.ktor.http.Headers import io.ktor.http.HttpHeaders import io.ktor.http.path - MaxLineLength:FilesApi.kt$FilesApi$"uploadFile success: fileId=${response.fileId}, filepath=${response.filepath}, type=${response.type}, width=${response.width}, height=${response.height}" - NoEmptyFirstLineInMethodBlock:LibreChatHttpClient.kt$LibreChatHttpClient$ - - diff --git a/core/network/src/commonMain/kotlin/com/garfiec/librechat/core/network/api/AgentsApi.kt b/core/network/src/commonMain/kotlin/com/garfiec/librechat/core/network/api/AgentsApi.kt index d03a901..eb88c4f 100644 --- a/core/network/src/commonMain/kotlin/com/garfiec/librechat/core/network/api/AgentsApi.kt +++ b/core/network/src/commonMain/kotlin/com/garfiec/librechat/core/network/api/AgentsApi.kt @@ -1,5 +1,6 @@ package com.garfiec.librechat.core.network.api +import co.touchlab.kermit.Logger import com.garfiec.librechat.core.model.Agent import com.garfiec.librechat.core.model.AgentAction import com.garfiec.librechat.core.model.AgentCategory @@ -28,7 +29,6 @@ import io.ktor.http.Headers import io.ktor.http.HttpHeaders import io.ktor.http.path import kotlinx.serialization.json.JsonArray -import co.touchlab.kermit.Logger class AgentsApi constructor( private val client: HttpClient, diff --git a/core/network/src/commonMain/kotlin/com/garfiec/librechat/core/network/api/AuthApi.kt b/core/network/src/commonMain/kotlin/com/garfiec/librechat/core/network/api/AuthApi.kt index 935deea..2373147 100644 --- a/core/network/src/commonMain/kotlin/com/garfiec/librechat/core/network/api/AuthApi.kt +++ b/core/network/src/commonMain/kotlin/com/garfiec/librechat/core/network/api/AuthApi.kt @@ -1,8 +1,5 @@ package com.garfiec.librechat.core.network.api -import com.garfiec.librechat.core.network.api.dto.LoginResult -import com.garfiec.librechat.core.network.api.dto.RefreshResult -import com.garfiec.librechat.core.network.api.dto.TwoFactorConfirmRequest import com.garfiec.librechat.core.model.request.LoginRequest import com.garfiec.librechat.core.model.request.OtpVerificationRequest import com.garfiec.librechat.core.model.request.PasswordResetRequest @@ -15,6 +12,9 @@ import com.garfiec.librechat.core.model.response.LoginResponse import com.garfiec.librechat.core.model.response.RefreshResponse import com.garfiec.librechat.core.model.response.RegisterResponse import com.garfiec.librechat.core.model.response.TwoFactorSetupResponse +import com.garfiec.librechat.core.network.api.dto.LoginResult +import com.garfiec.librechat.core.network.api.dto.RefreshResult +import com.garfiec.librechat.core.network.api.dto.TwoFactorConfirmRequest import com.garfiec.librechat.core.network.client.CookieHelper import io.ktor.client.HttpClient import io.ktor.client.call.body diff --git a/core/network/src/commonMain/kotlin/com/garfiec/librechat/core/network/api/FilesApi.kt b/core/network/src/commonMain/kotlin/com/garfiec/librechat/core/network/api/FilesApi.kt index 05aa127..0e4498b 100644 --- a/core/network/src/commonMain/kotlin/com/garfiec/librechat/core/network/api/FilesApi.kt +++ b/core/network/src/commonMain/kotlin/com/garfiec/librechat/core/network/api/FilesApi.kt @@ -69,7 +69,8 @@ class FilesApi constructor( }.body() Logger.d("FilesApi") { - "uploadFile success: fileId=${response.fileId}, filepath=${response.filepath}, type=${response.type}, width=${response.width}, height=${response.height}" + "uploadFile success: fileId=${response.fileId}, filepath=${response.filepath}, " + + "type=${response.type}, width=${response.width}, height=${response.height}" } return response } diff --git a/core/network/src/commonMain/kotlin/com/garfiec/librechat/core/network/api/UserApi.kt b/core/network/src/commonMain/kotlin/com/garfiec/librechat/core/network/api/UserApi.kt index 01d01ed..e27ce57 100644 --- a/core/network/src/commonMain/kotlin/com/garfiec/librechat/core/network/api/UserApi.kt +++ b/core/network/src/commonMain/kotlin/com/garfiec/librechat/core/network/api/UserApi.kt @@ -1,14 +1,14 @@ package com.garfiec.librechat.core.network.api -import com.garfiec.librechat.core.network.api.dto.UpdateFavoritesRequest -import com.garfiec.librechat.core.network.api.dto.UpdatePluginsRequest -import com.garfiec.librechat.core.network.api.dto.UserUpdateRequest import com.garfiec.librechat.core.model.User import com.garfiec.librechat.core.model.UserFavorite import com.garfiec.librechat.core.model.request.OtpVerificationRequest import com.garfiec.librechat.core.model.request.ResendVerificationRequest import com.garfiec.librechat.core.model.request.VerifyEmailRequest import com.garfiec.librechat.core.model.response.TermsResponse +import com.garfiec.librechat.core.network.api.dto.UpdateFavoritesRequest +import com.garfiec.librechat.core.network.api.dto.UpdatePluginsRequest +import com.garfiec.librechat.core.network.api.dto.UserUpdateRequest import io.ktor.client.HttpClient import io.ktor.client.call.body import io.ktor.client.request.delete diff --git a/core/network/src/commonMain/kotlin/com/garfiec/librechat/core/network/client/LibreChatHttpClient.kt b/core/network/src/commonMain/kotlin/com/garfiec/librechat/core/network/client/LibreChatHttpClient.kt index c487ce1..9ae9879 100644 --- a/core/network/src/commonMain/kotlin/com/garfiec/librechat/core/network/client/LibreChatHttpClient.kt +++ b/core/network/src/commonMain/kotlin/com/garfiec/librechat/core/network/client/LibreChatHttpClient.kt @@ -9,7 +9,6 @@ import io.ktor.client.plugins.HttpTimeout import io.ktor.client.plugins.contentnegotiation.ContentNegotiation import io.ktor.client.plugins.defaultRequest import io.ktor.client.plugins.logging.LogLevel -import io.ktor.client.plugins.logging.Logger as KtorLogger import io.ktor.client.plugins.logging.Logging import io.ktor.client.statement.bodyAsText import io.ktor.http.ContentType @@ -21,6 +20,7 @@ import io.ktor.serialization.kotlinx.json.json import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.jsonObject +import io.ktor.client.plugins.logging.Logger as KtorLogger object LibreChatHttpClient { @@ -31,7 +31,6 @@ object LibreChatHttpClient { serverUrlProvider: ServerUrlProvider, debug: Boolean = false, ): HttpClient = HttpClient(engineFactory) { - install(ContentNegotiation) { json(json) } diff --git a/core/network/src/commonMain/kotlin/com/garfiec/librechat/core/network/sse/SseEventMapper.kt b/core/network/src/commonMain/kotlin/com/garfiec/librechat/core/network/sse/SseEventMapper.kt index ad77ab1..b33bf96 100644 --- a/core/network/src/commonMain/kotlin/com/garfiec/librechat/core/network/sse/SseEventMapper.kt +++ b/core/network/src/commonMain/kotlin/com/garfiec/librechat/core/network/sse/SseEventMapper.kt @@ -1,5 +1,6 @@ package com.garfiec.librechat.core.network.sse +import co.touchlab.kermit.Logger import com.garfiec.librechat.core.model.Conversation import com.garfiec.librechat.core.model.Message import com.garfiec.librechat.core.model.StreamEvent @@ -14,7 +15,6 @@ import kotlinx.serialization.json.intOrNull import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonPrimitive -import co.touchlab.kermit.Logger /** * Maps raw SSE events into domain [StreamEvent]s. diff --git a/core/ui/detekt-baseline.xml b/core/ui/detekt-baseline.xml deleted file mode 100644 index 6be447f..0000000 --- a/core/ui/detekt-baseline.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - ComposableParamOrder:FilterChipBottomSheet.kt$FilterChipBottomSheet - FunctionNaming:Drawable0.commonMain.kt$@InternalResourceApi internal fun _collectCommonMainDrawable0Resources(map: MutableMap<String, DrawableResource>) - ImportOrdering:Drawable0.commonMain.kt$import kotlin.OptIn import kotlin.String import kotlin.collections.MutableMap import org.jetbrains.compose.resources.DrawableResource import org.jetbrains.compose.resources.InternalResourceApi import org.jetbrains.compose.resources.ResourceContentHash import org.jetbrains.compose.resources.ResourceItem - ImportOrdering:DynamicDropdown.kt$import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExposedDropdownMenuBox import androidx.compose.material3.ExposedDropdownMenuDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MenuAnchorType import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import org.jetbrains.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp - ImportOrdering:DynamicInput.kt$import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import org.jetbrains.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp - ImportOrdering:DynamicTextarea.kt$import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import org.jetbrains.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp - ImportOrdering:ExpectResourceCollectors.kt$import kotlin.String import kotlin.collections.Map import org.jetbrains.compose.resources.DrawableResource import org.jetbrains.compose.resources.FontResource import org.jetbrains.compose.resources.PluralStringResource import org.jetbrains.compose.resources.StringArrayResource import org.jetbrains.compose.resources.StringResource - ImportOrdering:Res.kt$import kotlin.ByteArray import kotlin.OptIn import kotlin.String import kotlin.Suppress import org.jetbrains.compose.resources.InternalResourceApi import org.jetbrains.compose.resources.getResourceUri import org.jetbrains.compose.resources.readResourceBytes - MaxLineLength:Res.kt$Res$public suspend - MultiLineIfElse:DynamicSlider.kt$str + "0".repeat(decimals - existing) - MultiLineIfElse:DynamicSlider.kt$str.substring(0, dot + decimals + 1) - PackageName:Drawable0.commonMain.kt$package librechat_mobile.core.ui.generated.resources - PackageName:ExpectResourceCollectors.kt$package librechat_mobile.core.ui.generated.resources - PackageName:Res.kt$package librechat_mobile.core.ui.generated.resources - PackageNaming:Drawable0.commonMain.kt$package librechat_mobile.core.ui.generated.resources - PackageNaming:ExpectResourceCollectors.kt$package librechat_mobile.core.ui.generated.resources - PackageNaming:Res.kt$package librechat_mobile.core.ui.generated.resources - ParameterNaming:DynamicParameterPanel.kt$onValueChanged - ParameterNaming:DynamicTagsInput.kt$onTagsChanged - ParameterNaming:FilterChipBottomSheet.kt$onSelectionChanged - ParameterNaming:ModelParameterSheet.kt$onParametersChanged - - diff --git a/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/DynamicDropdown.kt b/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/DynamicDropdown.kt index 4285f70..04f7fcd 100644 --- a/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/DynamicDropdown.kt +++ b/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/DynamicDropdown.kt @@ -18,8 +18,8 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import org.jetbrains.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import org.jetbrains.compose.ui.tooling.preview.Preview /** Labeled dropdown selector using ExposedDropdownMenuBox with read-only text field anchor. */ @OptIn(ExperimentalMaterial3Api::class) diff --git a/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/DynamicInput.kt b/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/DynamicInput.kt index 2a5150a..7761bd8 100644 --- a/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/DynamicInput.kt +++ b/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/DynamicInput.kt @@ -13,8 +13,8 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import org.jetbrains.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import org.jetbrains.compose.ui.tooling.preview.Preview /** Single-line text input with label, optional placeholder, and description. */ @Composable diff --git a/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/DynamicParameterPanel.kt b/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/DynamicParameterPanel.kt index 1686df5..35adabc 100644 --- a/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/DynamicParameterPanel.kt +++ b/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/DynamicParameterPanel.kt @@ -23,7 +23,7 @@ import org.jetbrains.compose.ui.tooling.preview.Preview fun DynamicParameterPanel( definitions: List, values: Map, - onValueChanged: (key: String, value: String) -> Unit, + onValueChange: (key: String, value: String) -> Unit, modifier: Modifier = Modifier, title: String = "Endpoint Parameters", ) { @@ -50,7 +50,7 @@ fun DynamicParameterPanel( DynamicSlider( label = definition.label, value = floatValue, - onValueChange = { onValueChanged(definition.key, it.toString()) }, + onValueChange = { onValueChange(definition.key, it.toString()) }, min = min, max = max, step = step, @@ -63,7 +63,7 @@ fun DynamicParameterPanel( label = definition.label, selectedValue = currentValue, options = definition.options ?: emptyList(), - onValueChange = { onValueChanged(definition.key, it) }, + onValueChange = { onValueChange(definition.key, it) }, description = definition.description, ) } @@ -73,7 +73,7 @@ fun DynamicParameterPanel( DynamicCheckbox( label = definition.label, checked = checked, - onCheckedChange = { onValueChanged(definition.key, it.toString()) }, + onCheckedChange = { onValueChange(definition.key, it.toString()) }, description = definition.description, ) } @@ -82,7 +82,7 @@ fun DynamicParameterPanel( DynamicInput( label = definition.label, value = currentValue, - onValueChange = { onValueChanged(definition.key, it) }, + onValueChange = { onValueChange(definition.key, it) }, placeholder = definition.default, description = definition.description, ) @@ -93,7 +93,7 @@ fun DynamicParameterPanel( DynamicCheckbox( label = definition.label, checked = checked, - onCheckedChange = { onValueChanged(definition.key, it.toString()) }, + onCheckedChange = { onValueChange(definition.key, it.toString()) }, description = definition.description, ) } @@ -102,7 +102,7 @@ fun DynamicParameterPanel( DynamicTextarea( label = definition.label, value = currentValue, - onValueChange = { onValueChanged(definition.key, it) }, + onValueChange = { onValueChange(definition.key, it) }, placeholder = definition.default, description = definition.description, ) @@ -116,8 +116,8 @@ fun DynamicParameterPanel( } else { currentValue.split("\n").filter { it.isNotBlank() } }, - onTagsChanged = { tags -> - onValueChanged(definition.key, tags.joinToString("\n")) + onTagsChange = { tags -> + onValueChange(definition.key, tags.joinToString("\n")) }, description = definition.description, maxTags = definition.max?.toInt() ?: 4, @@ -167,7 +167,7 @@ private fun DynamicParameterPanelPreview() { DynamicParameterPanel( definitions = definitions, values = values, - onValueChanged = { key, value -> + onValueChange = { key, value -> values = values.toMutableMap().apply { this[key] = value } }, ) diff --git a/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/DynamicSlider.kt b/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/DynamicSlider.kt index cc9bc0f..f1319bb 100644 --- a/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/DynamicSlider.kt +++ b/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/DynamicSlider.kt @@ -99,6 +99,9 @@ private fun roundToDecimals(value: Float, decimals: Int): String { val dot = str.indexOf('.') if (dot < 0) return str + "." + "0".repeat(decimals) val existing = str.length - dot - 1 - return if (existing >= decimals) str.substring(0, dot + decimals + 1) - else str + "0".repeat(decimals - existing) + return if (existing >= decimals) { + str.substring(0, dot + decimals + 1) + } else { + str + "0".repeat(decimals - existing) + } } diff --git a/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/DynamicTagsInput.kt b/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/DynamicTagsInput.kt index 5814f38..ef47924 100644 --- a/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/DynamicTagsInput.kt +++ b/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/DynamicTagsInput.kt @@ -34,7 +34,7 @@ import org.jetbrains.compose.ui.tooling.preview.Preview fun DynamicTagsInput( label: String, tags: List, - onTagsChanged: (List) -> Unit, + onTagsChange: (List) -> Unit, modifier: Modifier = Modifier, description: String? = null, maxTags: Int = 4, @@ -67,7 +67,7 @@ fun DynamicTagsInput( label = { Text(tag) }, trailingIcon = { IconButton( - onClick = { onTagsChanged(tags - tag) }, + onClick = { onTagsChange(tags - tag) }, modifier = Modifier.size(18.dp), ) { Icon( @@ -95,7 +95,7 @@ fun DynamicTagsInput( onDone = { val trimmed = inputText.trim() if (trimmed.isNotEmpty() && tags.size < maxTags) { - onTagsChanged(tags + trimmed) + onTagsChange(tags + trimmed) inputText = "" } }, @@ -112,7 +112,7 @@ private fun DynamicTagsInputPreview() { DynamicTagsInput( label = "Stop Sequences", tags = tags, - onTagsChanged = { tags = it }, + onTagsChange = { tags = it }, description = "Up to 4 sequences where the model will stop generating.", maxTags = 4, ) diff --git a/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/DynamicTextarea.kt b/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/DynamicTextarea.kt index 48a7dd8..67fafaf 100644 --- a/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/DynamicTextarea.kt +++ b/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/DynamicTextarea.kt @@ -13,8 +13,8 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import org.jetbrains.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import org.jetbrains.compose.ui.tooling.preview.Preview /** Multi-line text input with configurable minLines/maxLines, label, and optional description. */ @Composable diff --git a/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/EndpointIcons.kt b/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/EndpointIcons.kt index b3bf854..ddc81dc 100644 --- a/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/EndpointIcons.kt +++ b/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/EndpointIcons.kt @@ -3,13 +3,13 @@ package com.garfiec.librechat.core.ui.components import androidx.compose.runtime.Composable import androidx.compose.ui.graphics.painter.Painter import com.garfiec.librechat.core.model.EModelEndpoint -import librechat_mobile.core.ui.generated.resources.Res -import librechat_mobile.core.ui.generated.resources.ic_agents -import librechat_mobile.core.ui.generated.resources.ic_anthropic -import librechat_mobile.core.ui.generated.resources.ic_azure -import librechat_mobile.core.ui.generated.resources.ic_bedrock -import librechat_mobile.core.ui.generated.resources.ic_google -import librechat_mobile.core.ui.generated.resources.ic_openai +import com.garfiec.librechat.core.ui.resources.Res +import com.garfiec.librechat.core.ui.resources.ic_agents +import com.garfiec.librechat.core.ui.resources.ic_anthropic +import com.garfiec.librechat.core.ui.resources.ic_azure +import com.garfiec.librechat.core.ui.resources.ic_bedrock +import com.garfiec.librechat.core.ui.resources.ic_google +import com.garfiec.librechat.core.ui.resources.ic_openai import org.jetbrains.compose.resources.painterResource /** diff --git a/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/FilterChipBottomSheet.kt b/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/FilterChipBottomSheet.kt index f3f2ce8..2523e53 100644 --- a/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/FilterChipBottomSheet.kt +++ b/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/FilterChipBottomSheet.kt @@ -35,7 +35,7 @@ import androidx.compose.ui.unit.dp * * @param items All available items to display as chips. * @param selectedItems Currently selected items. - * @param onSelectionChanged Called with the final selection when the sheet is dismissed. + * @param onSelectionChange Called with the final selection when the sheet is dismissed. * @param label Extracts a display label from each item. * @param onDismiss Called when the sheet is dismissed. * @param title Title displayed at the top of the sheet. @@ -50,15 +50,15 @@ import androidx.compose.ui.unit.dp fun FilterChipBottomSheet( items: List, selectedItems: Set, - onSelectionChanged: (Set) -> Unit, + onSelectionChange: (Set) -> Unit, label: (T) -> String, onDismiss: () -> Unit, title: String, + modifier: Modifier = Modifier, emptyMessage: String = "", onAdd: ((String) -> T?)? = null, addPlaceholder: String = "", addContentDescription: String = "", - modifier: Modifier = Modifier, ) { val sheetState = rememberModalBottomSheetState() var currentSelection by remember { mutableStateOf(selectedItems) } @@ -66,7 +66,7 @@ fun FilterChipBottomSheet( ModalBottomSheet( onDismissRequest = { - onSelectionChanged(currentSelection) + onSelectionChange(currentSelection) onDismiss() }, modifier = modifier, diff --git a/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/ModelParameterSheet.kt b/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/ModelParameterSheet.kt index 9a8757a..4b4f43d 100644 --- a/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/ModelParameterSheet.kt +++ b/core/ui/src/commonMain/kotlin/com/garfiec/librechat/core/ui/components/ModelParameterSheet.kt @@ -104,7 +104,7 @@ data class ModelParameters( @Composable fun ModelParameterSheet( parameters: ModelParameters, - onParametersChanged: (ModelParameters) -> Unit, + onParametersChange: (ModelParameters) -> Unit, onDismiss: () -> Unit, modifier: Modifier = Modifier, selectedEndpoint: String = "", @@ -119,7 +119,7 @@ fun ModelParameterSheet( ) { ModelParameterContent( parameters = parameters, - onParametersChanged = onParametersChanged, + onParametersChange = onParametersChange, selectedEndpoint = selectedEndpoint, dynamicParameterDefinitions = dynamicParameterDefinitions, onSaveAsPreset = onSaveAsPreset, @@ -133,7 +133,7 @@ fun ModelParameterSheet( @Composable fun ModelParameterContent( parameters: ModelParameters, - onParametersChanged: (ModelParameters) -> Unit, + onParametersChange: (ModelParameters) -> Unit, modifier: Modifier = Modifier, selectedEndpoint: String = "", dynamicParameterDefinitions: List? = null, @@ -170,7 +170,7 @@ fun ModelParameterContent( label = definition.label, value = currentValue, onValueChange = { newValue -> - onParametersChanged(parameters.withUpdatedKey(definition.key, newValue)) + onParametersChange(parameters.withUpdatedKey(definition.key, newValue)) }, placeholder = definition.default?.ifEmpty { "Default" } ?: "Default", description = definition.description, @@ -182,7 +182,7 @@ fun ModelParameterContent( label = definition.label, value = currentValue, onValueChange = { newValue -> - onParametersChanged(parameters.withUpdatedKey(definition.key, newValue)) + onParametersChange(parameters.withUpdatedKey(definition.key, newValue)) }, placeholder = definition.default?.ifEmpty { null }, description = definition.description, @@ -199,7 +199,7 @@ fun ModelParameterContent( label = definition.label, value = floatValue.coerceIn(min, max), onValueChange = { newValue -> - onParametersChanged(parameters.withUpdatedKey(definition.key, newValue.toString())) + onParametersChange(parameters.withUpdatedKey(definition.key, newValue.toString())) }, min = min, max = max, @@ -216,7 +216,7 @@ fun ModelParameterContent( label = definition.label, checked = checked, onCheckedChange = { newChecked -> - onParametersChanged(parameters.withUpdatedKey(definition.key, newChecked.toString())) + onParametersChange(parameters.withUpdatedKey(definition.key, newChecked.toString())) }, description = definition.description, ) @@ -234,7 +234,7 @@ fun ModelParameterContent( selectedValue = displayValue, options = definition.options ?: emptyList(), onValueChange = { newValue -> - onParametersChanged(parameters.withUpdatedKey(definition.key, newValue)) + onParametersChange(parameters.withUpdatedKey(definition.key, newValue)) }, description = definition.description, ) @@ -250,8 +250,8 @@ fun ModelParameterContent( DynamicTagsInput( label = definition.label, tags = tags, - onTagsChanged = { newTags -> - onParametersChanged( + onTagsChange = { newTags -> + onParametersChange( parameters.withUpdatedKey(definition.key, newTags.joinToString("\n")), ) }, @@ -265,7 +265,7 @@ fun ModelParameterContent( // Reset to defaults OutlinedButton( onClick = { - onParametersChanged(ModelParameters.DEFAULT) + onParametersChange(ModelParameters.DEFAULT) }, modifier = Modifier.fillMaxWidth(), ) { diff --git a/feature/agents/detekt-baseline.xml b/feature/agents/detekt-baseline.xml deleted file mode 100644 index c9f880a..0000000 --- a/feature/agents/detekt-baseline.xml +++ /dev/null @@ -1,72 +0,0 @@ - - - - - ComposableParamOrder:AgentDetailScreen.kt$AgentDetailScreen - ComposableParamOrder:AgentEditorScreen.kt$AgentEditorScreen - DeprecatedKoinApi:AgentsModule.kt$viewModel { params -> AgentDetailViewModel( savedStateHandle = get(), agentRepository = get(), serverDataStore = get(), initialAgentId = params.getOrNull(), ) } - DeprecatedKoinApi:AgentsModule.kt$viewModel { params -> AgentEditorViewModel( savedStateHandle = get(), agentRepository = get(), configRepository = get(), mcpRepository = get(), contentReader = get(), initialAgentId = params.getOrNull(), ) } - FunctionNaming:String0.commonMain.kt$@InternalResourceApi internal fun _collectCommonMainString0Resources(map: MutableMap<String, StringResource>) - FunctionNaming:String1.commonMain.kt$@InternalResourceApi internal fun _collectCommonMainString1Resources(map: MutableMap<String, StringResource>) - ImportOrdering:AgentActionsPanel.kt$import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.clickable import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Edit import androidx.compose.material.icons.filled.ExpandLess import androidx.compose.material.icons.filled.ExpandMore import androidx.compose.material.icons.filled.Lock import androidx.compose.material.icons.filled.Security import androidx.compose.material3.AlertDialog import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.RadioButton import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import com.garfiec.librechat.core.model.ActionAuth import com.garfiec.librechat.core.model.ActionMetadata import com.garfiec.librechat.core.model.request.FunctionTool import com.garfiec.librechat.feature.agents.AgentActionDisplayData import librechat_mobile.feature.agents.generated.resources.Res import librechat_mobile.feature.agents.generated.resources.* import com.garfiec.librechat.feature.agents.util.OpenApiSpecParser import com.garfiec.librechat.feature.agents.util.ParsedFunctionInfo import kotlinx.coroutines.delay - ImportOrdering:AgentAdvancedPanel.kt$import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ExpandLess import androidx.compose.material.icons.filled.ExpandMore import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Slider import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp import librechat_mobile.feature.agents.generated.resources.Res import librechat_mobile.feature.agents.generated.resources.* import kotlin.math.roundToInt import com.garfiec.librechat.feature.agents.components.model.AgentAdvancedSettings - ImportOrdering:AgentCapabilitiesSection.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp import librechat_mobile.feature.agents.generated.resources.Res import librechat_mobile.feature.agents.generated.resources.* import com.garfiec.librechat.feature.agents.components.model.AgentCapabilities - ImportOrdering:AgentCategorySelector.kt$import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExposedDropdownMenuBox import androidx.compose.material3.ExposedDropdownMenuDefaults import androidx.compose.material3.MenuAnchorType import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import com.garfiec.librechat.core.model.AgentCategory import librechat_mobile.feature.agents.generated.resources.Res import librechat_mobile.feature.agents.generated.resources.* - ImportOrdering:AgentCodeInterpreterSection.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import librechat_mobile.feature.agents.generated.resources.Res import librechat_mobile.feature.agents.generated.resources.* - ImportOrdering:AgentDetailScreen.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.Chat import androidx.compose.material.icons.filled.ContentCopy import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Edit import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material3.AlertDialog import androidx.compose.material3.AssistChip import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.garfiec.librechat.core.model.EModelEndpoint import com.garfiec.librechat.core.ui.components.AvatarImage import com.garfiec.librechat.core.ui.components.endpointIconPainter import com.garfiec.librechat.core.ui.components.ErrorBanner import com.garfiec.librechat.core.ui.components.LoadingIndicator import librechat_mobile.feature.agents.generated.resources.Res import librechat_mobile.feature.agents.generated.resources.* import com.garfiec.librechat.feature.agents.viewmodel.AgentDetailEvent import com.garfiec.librechat.feature.agents.viewmodel.AgentDetailViewModel import org.koin.compose.viewmodel.koinViewModel import org.koin.core.parameter.parametersOf - ImportOrdering:AgentEditorScreen.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Build import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.ContentCopy import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.History import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.InputChip import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.garfiec.librechat.core.ui.components.ErrorBanner import com.garfiec.librechat.core.ui.components.LoadingIndicator import librechat_mobile.feature.agents.generated.resources.Res import librechat_mobile.feature.agents.generated.resources.* import com.garfiec.librechat.feature.agents.components.AgentActionsPanel import com.garfiec.librechat.feature.agents.components.AgentAdvancedPanel import com.garfiec.librechat.feature.agents.components.AgentAvatarPicker import com.garfiec.librechat.feature.agents.components.AgentCategorySelector import com.garfiec.librechat.feature.agents.components.AgentCodeInterpreterSection import com.garfiec.librechat.feature.agents.components.AgentFileSearchSection import com.garfiec.librechat.feature.agents.components.AgentHandoffConfig import com.garfiec.librechat.feature.agents.components.AgentMcpToolsSelector import com.garfiec.librechat.feature.agents.components.AgentModelPicker import com.garfiec.librechat.feature.agents.components.AgentSharingSection import com.garfiec.librechat.feature.agents.components.AgentSupportContactSection import com.garfiec.librechat.feature.agents.components.AgentVersionHistory import com.garfiec.librechat.feature.agents.components.ToolSelectDialog import com.garfiec.librechat.feature.agents.viewmodel.AgentEditorEvent import com.garfiec.librechat.feature.agents.viewmodel.AgentEditorViewModel import org.koin.compose.viewmodel.koinViewModel import org.koin.core.parameter.parametersOf - ImportOrdering:AgentEditorViewModel.kt$import androidx.compose.runtime.Immutable import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.garfiec.librechat.feature.agents.util.ContentReader import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.data.repository.AgentRepository import com.garfiec.librechat.core.data.repository.ConfigRepository import com.garfiec.librechat.core.data.repository.McpRepository import com.garfiec.librechat.core.model.ActionMetadata import com.garfiec.librechat.core.model.Agent import com.garfiec.librechat.core.model.AgentAction import com.garfiec.librechat.core.model.AgentCategory import com.garfiec.librechat.core.model.AgentTool import com.garfiec.librechat.core.model.SupportContact import com.garfiec.librechat.core.model.mcp.McpTool import com.garfiec.librechat.core.model.request.CreateActionRequest import com.garfiec.librechat.core.model.request.CreateAgentRequest import com.garfiec.librechat.core.model.request.FunctionTool import com.garfiec.librechat.core.model.request.RevertAgentRequest import com.garfiec.librechat.core.model.request.UpdateAgentRequest import com.garfiec.librechat.feature.agents.AgentActionDisplayData import com.garfiec.librechat.feature.agents.AgentHandoffDisplayData import com.garfiec.librechat.feature.agents.AgentToolDisplayData import com.garfiec.librechat.feature.agents.components.ModelOption import com.garfiec.librechat.feature.agents.components.model.AgentAdvancedSettings import com.garfiec.librechat.feature.agents.components.model.AgentCapabilities import com.garfiec.librechat.feature.agents.components.model.AgentSharingState import com.garfiec.librechat.feature.agents.components.model.AgentVersion import com.garfiec.librechat.feature.agents.components.model.AgentVisibility import com.garfiec.librechat.feature.agents.components.model.SupportContactState import com.garfiec.librechat.feature.agents.util.OpenApiSpecParser import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.floatOrNull import kotlinx.serialization.json.intOrNull import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonPrimitive import co.touchlab.kermit.Logger - ImportOrdering:AgentFileSearchSection.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import librechat_mobile.feature.agents.generated.resources.Res import librechat_mobile.feature.agents.generated.resources.* - ImportOrdering:AgentHandoffConfig.kt$import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.ExpandLess import androidx.compose.material.icons.filled.ExpandMore import androidx.compose.material3.AlertDialog import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExposedDropdownMenuBox import androidx.compose.material3.ExposedDropdownMenuDefaults import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.InputChip import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MenuAnchorType import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import com.garfiec.librechat.feature.agents.AgentHandoffDisplayData import librechat_mobile.feature.agents.generated.resources.Res import librechat_mobile.feature.agents.generated.resources.* - ImportOrdering:AgentMarketplaceScreen.kt$import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.GridItemSpan import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.items import androidx.compose.foundation.lazy.grid.rememberLazyGridState import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Search import androidx.compose.material.icons.filled.SmartToy import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.FilterChip import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.pulltorefresh.PullToRefreshBox import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.garfiec.librechat.core.model.EModelEndpoint import com.garfiec.librechat.core.ui.components.AvatarImage import com.garfiec.librechat.core.ui.components.endpointIconPainter import com.garfiec.librechat.core.ui.components.EmptyState import com.garfiec.librechat.core.ui.components.ErrorBanner import com.garfiec.librechat.core.ui.components.LibreChatTopBar import com.garfiec.librechat.core.ui.components.LoadingIndicator import com.garfiec.librechat.feature.agents.AgentCardDisplayData import librechat_mobile.feature.agents.generated.resources.Res import librechat_mobile.feature.agents.generated.resources.* import com.garfiec.librechat.feature.agents.viewmodel.AgentMarketplaceViewModel import org.koin.compose.viewmodel.koinViewModel - ImportOrdering:AgentMcpToolsSelector.kt$import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ExpandLess import androidx.compose.material.icons.filled.ExpandMore import androidx.compose.material3.Checkbox import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.model.mcp.McpTool import librechat_mobile.feature.agents.generated.resources.Res import librechat_mobile.feature.agents.generated.resources.* - ImportOrdering:AgentModelPicker.kt$import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.heightIn import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExposedDropdownMenuBox import androidx.compose.material3.ExposedDropdownMenuDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MenuAnchorType import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import librechat_mobile.feature.agents.generated.resources.Res import librechat_mobile.feature.agents.generated.resources.* - ImportOrdering:AgentSharingSection.kt$import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ExpandLess import androidx.compose.material.icons.filled.ExpandMore import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExposedDropdownMenuBox import androidx.compose.material3.ExposedDropdownMenuDefaults import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MenuAnchorType import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import librechat_mobile.feature.agents.generated.resources.Res import librechat_mobile.feature.agents.generated.resources.* import com.garfiec.librechat.feature.agents.components.model.AgentSharingState import com.garfiec.librechat.feature.agents.components.model.AgentVisibility - ImportOrdering:AgentSupportContactSection.kt$import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import librechat_mobile.feature.agents.generated.resources.Res import librechat_mobile.feature.agents.generated.resources.* import com.garfiec.librechat.feature.agents.components.model.SupportContactState - ImportOrdering:AgentVersionHistory.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material3.Button import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.SheetState import androidx.compose.material3.Text import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import librechat_mobile.feature.agents.generated.resources.Res import librechat_mobile.feature.agents.generated.resources.* import com.garfiec.librechat.feature.agents.components.model.AgentVersion - ImportOrdering:ExpectResourceCollectors.kt$import kotlin.String import kotlin.collections.Map import org.jetbrains.compose.resources.DrawableResource import org.jetbrains.compose.resources.FontResource import org.jetbrains.compose.resources.PluralStringResource import org.jetbrains.compose.resources.StringArrayResource import org.jetbrains.compose.resources.StringResource - ImportOrdering:Res.kt$import kotlin.ByteArray import kotlin.OptIn import kotlin.String import kotlin.Suppress import org.jetbrains.compose.resources.InternalResourceApi import org.jetbrains.compose.resources.getResourceUri import org.jetbrains.compose.resources.readResourceBytes - ImportOrdering:String0.commonMain.kt$import kotlin.OptIn import kotlin.String import kotlin.collections.MutableMap import org.jetbrains.compose.resources.InternalResourceApi import org.jetbrains.compose.resources.ResourceContentHash import org.jetbrains.compose.resources.ResourceItem import org.jetbrains.compose.resources.StringResource - ImportOrdering:String1.commonMain.kt$import kotlin.OptIn import kotlin.String import kotlin.collections.MutableMap import org.jetbrains.compose.resources.InternalResourceApi import org.jetbrains.compose.resources.ResourceContentHash import org.jetbrains.compose.resources.ResourceItem import org.jetbrains.compose.resources.StringResource - ImportOrdering:ToolSelectDialog.kt$import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.items import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Build import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Remove import androidx.compose.material.icons.filled.Search import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.FilledTonalButton import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.ContentScale import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import coil3.compose.AsyncImage import com.garfiec.librechat.feature.agents.AgentToolDisplayData import librechat_mobile.feature.agents.generated.resources.Res import librechat_mobile.feature.agents.generated.resources.* - LambdaParameterInRestartableEffect:AgentDetailScreen.kt$onBack - LambdaParameterInRestartableEffect:AgentDetailScreen.kt$onDuplicated - LambdaParameterInRestartableEffect:AgentEditorScreen.kt$onDeleted - LambdaParameterInRestartableEffect:AgentEditorScreen.kt$onDuplicated - LambdaParameterInRestartableEffect:AgentEditorScreen.kt$onSaved - LoopWithTooManyJumpStatements:YamlParser.kt$YamlParser$while - MaxLineLength:AgentEditorViewModel.kt$AgentEditorViewModel$"name=${agent.name}, description=${agent.description}, instructions=${agent.instructions}, model=${agent.model}, " - MaxLineLength:AgentEditorViewModel.kt$AgentEditorViewModel$"name=${newState.name}, description=${newState.description}, instructions=${newState.instructions}, model=${newState.model}, " - MaxLineLength:Res.kt$Res$public suspend - NoConsecutiveBlankLines:AgentDetailScreen.kt$ - NoConsecutiveBlankLines:AgentMarketplaceScreen.kt$ - NoUnusedImports:OpenApiSpecParser.kt$com.garfiec.librechat.feature.agents.util.OpenApiSpecParser.kt - PackageName:ExpectResourceCollectors.kt$package librechat_mobile.feature.agents.generated.resources - PackageName:Res.kt$package librechat_mobile.feature.agents.generated.resources - PackageName:String0.commonMain.kt$package librechat_mobile.feature.agents.generated.resources - PackageName:String1.commonMain.kt$package librechat_mobile.feature.agents.generated.resources - PackageNaming:ExpectResourceCollectors.kt$package librechat_mobile.feature.agents.generated.resources - PackageNaming:Res.kt$package librechat_mobile.feature.agents.generated.resources - PackageNaming:String0.commonMain.kt$package librechat_mobile.feature.agents.generated.resources - PackageNaming:String1.commonMain.kt$package librechat_mobile.feature.agents.generated.resources - ParameterNaming:AgentAdvancedPanel.kt$onSettingsChanged - ParameterNaming:AgentAvatarPicker.kt$onImageSelected - ParameterNaming:AgentCapabilitiesSection.kt$onCapabilitiesChanged - ParameterNaming:AgentCategorySelector.kt$onCategorySelected - ParameterNaming:AgentDetailScreen.kt$onDuplicated - ParameterNaming:AgentEditorScreen.kt$onDeleted - ParameterNaming:AgentEditorScreen.kt$onDuplicated - ParameterNaming:AgentEditorScreen.kt$onSaved - ParameterNaming:AgentMcpToolsSelector.kt$onToolToggled - ParameterNaming:AgentModelPicker.kt$onModelSelected - ParameterNaming:AgentSharingSection.kt$onSharingChanged - ParameterNaming:AgentSupportContactSection.kt$onSupportContactChanged - ParameterNaming:ToolSelectDialog.kt$onToolAdded - ParameterNaming:ToolSelectDialog.kt$onToolRemoved - SpacingBetweenDeclarationsWithAnnotations:AgentsNavigation.kt$AgentDetail : AgentsRoute - SpacingBetweenDeclarationsWithAnnotations:AgentsNavigation.kt$AgentEditorCreate : AgentsRoute - SpacingBetweenDeclarationsWithAnnotations:AgentsNavigation.kt$AgentEditorEdit : AgentsRoute - UnusedPrivateProperty:AgentDetailViewModel.kt$AgentDetailViewModel$savedStateHandle: SavedStateHandle - UnusedPrivateProperty:AgentEditorViewModel.kt$AgentEditorViewModel$savedStateHandle: SavedStateHandle - - diff --git a/feature/agents/src/androidMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentAvatarPicker.kt b/feature/agents/src/androidMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentAvatarPicker.kt index 10ce5a3..46cdf87 100644 --- a/feature/agents/src/androidMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentAvatarPicker.kt +++ b/feature/agents/src/androidMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentAvatarPicker.kt @@ -18,26 +18,26 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.ContentScale -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import coil3.compose.AsyncImage -import librechat_mobile.feature.agents.generated.resources.Res -import librechat_mobile.feature.agents.generated.resources.* +import com.garfiec.librechat.feature.agents.resources.* +import com.garfiec.librechat.feature.agents.resources.Res +import org.jetbrains.compose.resources.stringResource @Composable actual fun AgentAvatarPicker( avatarUrl: String?, agentName: String, - onImageSelected: (Any) -> Unit, + onImageSelect: (Any) -> Unit, modifier: Modifier, ) { val launcher = rememberLauncherForActivityResult( contract = ActivityResultContracts.GetContent(), ) { uri: Uri? -> if (uri != null) { - onImageSelected(uri) + onImageSelect(uri) } } diff --git a/feature/agents/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/agents/di/AgentsModuleVerificationTest.kt b/feature/agents/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/agents/di/AgentsModuleVerificationTest.kt index fb8879b..a9766ec 100644 --- a/feature/agents/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/agents/di/AgentsModuleVerificationTest.kt +++ b/feature/agents/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/agents/di/AgentsModuleVerificationTest.kt @@ -2,7 +2,6 @@ package com.garfiec.librechat.feature.agents.di import android.app.Application import android.content.Context -import androidx.lifecycle.SavedStateHandle import com.garfiec.librechat.core.data.datastore.ServerDataStore import com.garfiec.librechat.core.data.repository.AgentRepository import com.garfiec.librechat.core.data.repository.ConfigRepository @@ -17,7 +16,6 @@ class AgentsModuleVerificationTest { extraTypes = listOf( Context::class, Application::class, - SavedStateHandle::class, AgentRepository::class, ConfigRepository::class, McpRepository::class, diff --git a/feature/agents/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/agents/viewmodel/AgentMarketplaceViewModelTest.kt b/feature/agents/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/agents/viewmodel/AgentMarketplaceViewModelTest.kt index 3afabdf..1e80391 100644 --- a/feature/agents/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/agents/viewmodel/AgentMarketplaceViewModelTest.kt +++ b/feature/agents/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/agents/viewmodel/AgentMarketplaceViewModelTest.kt @@ -1,12 +1,12 @@ package com.garfiec.librechat.feature.agents.viewmodel -import com.google.common.truth.Truth.assertThat import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.data.datastore.ServerDataStore import com.garfiec.librechat.core.data.repository.AgentRepository import com.garfiec.librechat.core.model.Agent import com.garfiec.librechat.core.model.AgentCategory import com.garfiec.librechat.core.model.PaginatedAgents +import com.google.common.truth.Truth.assertThat import io.mockk.coEvery import io.mockk.coVerify import io.mockk.every diff --git a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentActionsPanel.kt b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentActionsPanel.kt index 6237f0c..83156f3 100644 --- a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentActionsPanel.kt +++ b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentActionsPanel.kt @@ -45,7 +45,6 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.PasswordVisualTransformation @@ -57,11 +56,12 @@ import com.garfiec.librechat.core.model.ActionAuth import com.garfiec.librechat.core.model.ActionMetadata import com.garfiec.librechat.core.model.request.FunctionTool import com.garfiec.librechat.feature.agents.AgentActionDisplayData -import librechat_mobile.feature.agents.generated.resources.Res -import librechat_mobile.feature.agents.generated.resources.* +import com.garfiec.librechat.feature.agents.resources.* +import com.garfiec.librechat.feature.agents.resources.Res import com.garfiec.librechat.feature.agents.util.OpenApiSpecParser import com.garfiec.librechat.feature.agents.util.ParsedFunctionInfo import kotlinx.coroutines.delay +import org.jetbrains.compose.resources.stringResource private const val VALIDATION_DEBOUNCE_MS = 800L private const val HIDDEN_PLACEHOLDER = "" diff --git a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentAdvancedPanel.kt b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentAdvancedPanel.kt index d0a7997..3e0bc32 100644 --- a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentAdvancedPanel.kt +++ b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentAdvancedPanel.kt @@ -26,18 +26,18 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp -import librechat_mobile.feature.agents.generated.resources.Res -import librechat_mobile.feature.agents.generated.resources.* -import kotlin.math.roundToInt import com.garfiec.librechat.feature.agents.components.model.AgentAdvancedSettings +import com.garfiec.librechat.feature.agents.resources.* +import com.garfiec.librechat.feature.agents.resources.Res +import org.jetbrains.compose.resources.stringResource +import kotlin.math.roundToInt @Composable fun AgentAdvancedPanel( settings: AgentAdvancedSettings, - onSettingsChanged: (AgentAdvancedSettings) -> Unit, + onSettingsChange: (AgentAdvancedSettings) -> Unit, modifier: Modifier = Modifier, ) { var expanded by remember { mutableStateOf(false) } @@ -71,7 +71,7 @@ fun AgentAdvancedPanel( label = stringResource(Res.string.label_temperature), value = settings.temperature ?: 1.0f, onValueChange = { - onSettingsChanged(settings.copy(temperature = roundToStep(it, 0.1f))) + onSettingsChange(settings.copy(temperature = roundToStep(it, 0.1f))) }, valueRange = 0f..2f, steps = 19, @@ -83,7 +83,7 @@ fun AgentAdvancedPanel( label = stringResource(Res.string.label_top_p), value = settings.topP ?: 1.0f, onValueChange = { - onSettingsChanged(settings.copy(topP = roundToStep(it, 0.05f))) + onSettingsChange(settings.copy(topP = roundToStep(it, 0.05f))) }, valueRange = 0f..1f, steps = 19, @@ -106,7 +106,7 @@ fun AgentAdvancedPanel( value = settings.maxTokens?.toString() ?: "", onValueChange = { newValue -> val filtered = newValue.filter { it.isDigit() } - onSettingsChanged( + onSettingsChange( settings.copy(maxTokens = filtered.toIntOrNull()), ) }, diff --git a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentAvatarPicker.kt b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentAvatarPicker.kt index 19ee00a..9bfe8de 100644 --- a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentAvatarPicker.kt +++ b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentAvatarPicker.kt @@ -7,6 +7,6 @@ import androidx.compose.ui.Modifier expect fun AgentAvatarPicker( avatarUrl: String?, agentName: String, - onImageSelected: (Any) -> Unit, + onImageSelect: (Any) -> Unit, modifier: Modifier = Modifier, ) diff --git a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentCapabilitiesSection.kt b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentCapabilitiesSection.kt index d64c251..bb6438f 100644 --- a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentCapabilitiesSection.kt +++ b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentCapabilitiesSection.kt @@ -15,17 +15,17 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp -import librechat_mobile.feature.agents.generated.resources.Res -import librechat_mobile.feature.agents.generated.resources.* import com.garfiec.librechat.feature.agents.components.model.AgentCapabilities +import com.garfiec.librechat.feature.agents.resources.* +import com.garfiec.librechat.feature.agents.resources.Res +import org.jetbrains.compose.resources.stringResource @Composable fun AgentCapabilitiesSection( capabilities: AgentCapabilities, - onCapabilitiesChanged: (AgentCapabilities) -> Unit, + onCapabilitiesChange: (AgentCapabilities) -> Unit, modifier: Modifier = Modifier, ) { Column(modifier = modifier.fillMaxWidth()) { @@ -40,7 +40,7 @@ fun AgentCapabilitiesSection( description = stringResource(Res.string.artifacts_description), checked = capabilities.artifacts, onCheckedChange = { - onCapabilitiesChanged(capabilities.copy(artifacts = it)) + onCapabilitiesChange(capabilities.copy(artifacts = it)) }, ) @@ -49,7 +49,7 @@ fun AgentCapabilitiesSection( description = stringResource(Res.string.end_after_tools_description), checked = capabilities.endAfterTools, onCheckedChange = { - onCapabilitiesChanged(capabilities.copy(endAfterTools = it)) + onCapabilitiesChange(capabilities.copy(endAfterTools = it)) }, ) @@ -58,7 +58,7 @@ fun AgentCapabilitiesSection( description = stringResource(Res.string.hide_sequential_description), checked = capabilities.hideSequentialOutputs, onCheckedChange = { - onCapabilitiesChanged(capabilities.copy(hideSequentialOutputs = it)) + onCapabilitiesChange(capabilities.copy(hideSequentialOutputs = it)) }, ) @@ -80,7 +80,7 @@ fun AgentCapabilitiesSection( onValueChange = { newValue -> val filtered = newValue.filter { it.isDigit() } val intVal = filtered.toIntOrNull() ?: 0 - onCapabilitiesChanged( + onCapabilitiesChange( capabilities.copy(recursionLimit = intVal.coerceIn(1, 100)), ) }, diff --git a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentCategorySelector.kt b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentCategorySelector.kt index aa61d2d..e249629 100644 --- a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentCategorySelector.kt +++ b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentCategorySelector.kt @@ -14,10 +14,10 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import com.garfiec.librechat.core.model.AgentCategory -import librechat_mobile.feature.agents.generated.resources.Res -import librechat_mobile.feature.agents.generated.resources.* +import com.garfiec.librechat.feature.agents.resources.* +import com.garfiec.librechat.feature.agents.resources.Res +import org.jetbrains.compose.resources.stringResource /** * Maps category values to human-readable English labels. @@ -51,7 +51,7 @@ private fun AgentCategory.displayLabel(): String { fun AgentCategorySelector( selectedCategory: String, categories: List, - onCategorySelected: (String) -> Unit, + onCategorySelect: (String) -> Unit, modifier: Modifier = Modifier, ) { var expanded by remember { mutableStateOf(false) } @@ -90,7 +90,7 @@ fun AgentCategorySelector( DropdownMenuItem( text = { Text(category.displayLabel()) }, onClick = { - onCategorySelected(category.value) + onCategorySelect(category.value) expanded = false }, ) diff --git a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentCodeInterpreterSection.kt b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentCodeInterpreterSection.kt index 95bbdb4..b12c055 100644 --- a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentCodeInterpreterSection.kt +++ b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentCodeInterpreterSection.kt @@ -13,10 +13,10 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp -import librechat_mobile.feature.agents.generated.resources.Res -import librechat_mobile.feature.agents.generated.resources.* +import com.garfiec.librechat.feature.agents.resources.* +import com.garfiec.librechat.feature.agents.resources.Res +import org.jetbrains.compose.resources.stringResource @Composable fun AgentCodeInterpreterSection( diff --git a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentFileSearchSection.kt b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentFileSearchSection.kt index 79a98f4..10d55c4 100644 --- a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentFileSearchSection.kt +++ b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentFileSearchSection.kt @@ -13,10 +13,10 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp -import librechat_mobile.feature.agents.generated.resources.Res -import librechat_mobile.feature.agents.generated.resources.* +import com.garfiec.librechat.feature.agents.resources.* +import com.garfiec.librechat.feature.agents.resources.Res +import org.jetbrains.compose.resources.stringResource @Composable fun AgentFileSearchSection( diff --git a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentHandoffConfig.kt b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentHandoffConfig.kt index e2ea5c0..97c8f59 100644 --- a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentHandoffConfig.kt +++ b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentHandoffConfig.kt @@ -35,11 +35,11 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import com.garfiec.librechat.feature.agents.AgentHandoffDisplayData -import librechat_mobile.feature.agents.generated.resources.Res -import librechat_mobile.feature.agents.generated.resources.* +import com.garfiec.librechat.feature.agents.resources.* +import com.garfiec.librechat.feature.agents.resources.Res +import org.jetbrains.compose.resources.stringResource @Composable fun AgentHandoffConfig( diff --git a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentMcpToolsSelector.kt b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentMcpToolsSelector.kt index d0ee80d..fac6dd7 100644 --- a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentMcpToolsSelector.kt +++ b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentMcpToolsSelector.kt @@ -21,18 +21,18 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.model.mcp.McpTool -import librechat_mobile.feature.agents.generated.resources.Res -import librechat_mobile.feature.agents.generated.resources.* +import com.garfiec.librechat.feature.agents.resources.* +import com.garfiec.librechat.feature.agents.resources.Res +import org.jetbrains.compose.resources.stringResource /** Hierarchical MCP tool picker grouped by server with checkbox selection. */ @Composable fun AgentMcpToolsSelector( mcpTools: List, selectedToolNames: Set, - onToolToggled: (toolName: String) -> Unit, + onToolToggle: (toolName: String) -> Unit, modifier: Modifier = Modifier, ) { var expanded by remember { mutableStateOf(false) } @@ -80,7 +80,7 @@ fun AgentMcpToolsSelector( serverName = serverName, tools = tools, selectedToolNames = selectedToolNames, - onToolToggled = onToolToggled, + onToolToggle = onToolToggle, ) } } @@ -94,7 +94,7 @@ private fun McpServerToolsGroup( serverName: String, tools: List, selectedToolNames: Set, - onToolToggled: (String) -> Unit, + onToolToggle: (String) -> Unit, modifier: Modifier = Modifier, ) { var serverExpanded by remember { mutableStateOf(true) } @@ -125,7 +125,7 @@ private fun McpServerToolsGroup( McpToolRow( tool = tool, isSelected = tool.name in selectedToolNames, - onToggle = { onToolToggled(tool.name) }, + onToggle = { onToolToggle(tool.name) }, ) } } diff --git a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentModelPicker.kt b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentModelPicker.kt index 4900722..766c096 100644 --- a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentModelPicker.kt +++ b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentModelPicker.kt @@ -16,10 +16,10 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp -import librechat_mobile.feature.agents.generated.resources.Res -import librechat_mobile.feature.agents.generated.resources.* +import com.garfiec.librechat.feature.agents.resources.* +import com.garfiec.librechat.feature.agents.resources.Res +import org.jetbrains.compose.resources.stringResource data class ModelOption( val id: String, @@ -32,7 +32,7 @@ data class ModelOption( fun AgentModelPicker( selectedModel: String, availableModels: List, - onModelSelected: (modelId: String, provider: String) -> Unit, + onModelSelect: (modelId: String, provider: String) -> Unit, modifier: Modifier = Modifier, ) { var expanded by remember { mutableStateOf(false) } @@ -107,7 +107,7 @@ fun AgentModelPicker( DropdownMenuItem( text = { Text(model.name) }, onClick = { - onModelSelected(model.id, model.endpoint) + onModelSelect(model.id, model.endpoint) expanded = false searchQuery = "" }, diff --git a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentSharingSection.kt b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentSharingSection.kt index 1d09050..9d9f3a2 100644 --- a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentSharingSection.kt +++ b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentSharingSection.kt @@ -29,19 +29,19 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp -import librechat_mobile.feature.agents.generated.resources.Res -import librechat_mobile.feature.agents.generated.resources.* import com.garfiec.librechat.feature.agents.components.model.AgentSharingState import com.garfiec.librechat.feature.agents.components.model.AgentVisibility +import com.garfiec.librechat.feature.agents.resources.* +import com.garfiec.librechat.feature.agents.resources.Res +import org.jetbrains.compose.resources.stringResource /** Visibility (Private/Team/Public) and collaborative toggle; maps to agent model isPublic/isCollaborative. */ @OptIn(ExperimentalMaterial3Api::class) @Composable fun AgentSharingSection( sharingState: AgentSharingState, - onSharingChanged: (AgentSharingState) -> Unit, + onSharingChange: (AgentSharingState) -> Unit, modifier: Modifier = Modifier, ) { var expanded by remember { mutableStateOf(false) } @@ -97,7 +97,7 @@ fun AgentSharingSection( DropdownMenuItem( text = { Text(visibility.label) }, onClick = { - onSharingChanged(sharingState.copy(visibility = visibility)) + onSharingChange(sharingState.copy(visibility = visibility)) dropdownExpanded = false }, ) @@ -129,7 +129,7 @@ fun AgentSharingSection( Switch( checked = sharingState.isCollaborative, onCheckedChange = { - onSharingChanged(sharingState.copy(isCollaborative = it)) + onSharingChange(sharingState.copy(isCollaborative = it)) }, ) } diff --git a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentSupportContactSection.kt b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentSupportContactSection.kt index 4ed0b6a..42bc648 100644 --- a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentSupportContactSection.kt +++ b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentSupportContactSection.kt @@ -9,16 +9,16 @@ import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp -import librechat_mobile.feature.agents.generated.resources.Res -import librechat_mobile.feature.agents.generated.resources.* import com.garfiec.librechat.feature.agents.components.model.SupportContactState +import com.garfiec.librechat.feature.agents.resources.* +import com.garfiec.librechat.feature.agents.resources.Res +import org.jetbrains.compose.resources.stringResource @Composable fun AgentSupportContactSection( supportContact: SupportContactState, - onSupportContactChanged: (SupportContactState) -> Unit, + onSupportContactChange: (SupportContactState) -> Unit, modifier: Modifier = Modifier, ) { Column(modifier = modifier.fillMaxWidth()) { @@ -37,7 +37,7 @@ fun AgentSupportContactSection( OutlinedTextField( value = supportContact.name, onValueChange = { - onSupportContactChanged(supportContact.copy(name = it)) + onSupportContactChange(supportContact.copy(name = it)) }, placeholder = { Text(stringResource(Res.string.support_contact_placeholder)) }, singleLine = true, @@ -55,7 +55,7 @@ fun AgentSupportContactSection( OutlinedTextField( value = supportContact.email, onValueChange = { - onSupportContactChanged(supportContact.copy(email = it)) + onSupportContactChange(supportContact.copy(email = it)) }, placeholder = { Text("support@example.com") }, singleLine = true, diff --git a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentVersionHistory.kt b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentVersionHistory.kt index 3bb1af8..5d55eb3 100644 --- a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentVersionHistory.kt +++ b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentVersionHistory.kt @@ -21,11 +21,11 @@ import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp -import librechat_mobile.feature.agents.generated.resources.Res -import librechat_mobile.feature.agents.generated.resources.* import com.garfiec.librechat.feature.agents.components.model.AgentVersion +import com.garfiec.librechat.feature.agents.resources.* +import com.garfiec.librechat.feature.agents.resources.Res +import org.jetbrains.compose.resources.stringResource @OptIn(ExperimentalMaterial3Api::class) @Composable diff --git a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/ToolSelectDialog.kt b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/ToolSelectDialog.kt index fddc32d..e808c2e 100644 --- a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/ToolSelectDialog.kt +++ b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/components/ToolSelectDialog.kt @@ -42,15 +42,15 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.ContentScale -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import coil3.compose.AsyncImage import com.garfiec.librechat.feature.agents.AgentToolDisplayData -import librechat_mobile.feature.agents.generated.resources.Res -import librechat_mobile.feature.agents.generated.resources.* +import com.garfiec.librechat.feature.agents.resources.* +import com.garfiec.librechat.feature.agents.resources.Res +import org.jetbrains.compose.resources.stringResource /** * Full-screen dialog for selecting agent tools, matching the web app's ToolSelectDialog. @@ -60,8 +60,8 @@ import librechat_mobile.feature.agents.generated.resources.* fun ToolSelectDialog( tools: List, selectedToolIds: List, - onToolAdded: (String) -> Unit, - onToolRemoved: (String) -> Unit, + onToolAdd: (String) -> Unit, + onToolRemove: (String) -> Unit, onDismiss: () -> Unit, modifier: Modifier = Modifier, ) { @@ -175,9 +175,9 @@ fun ToolSelectDialog( isInstalled = isInstalled, onToggle = { if (isInstalled) { - onToolRemoved(toolId) + onToolRemove(toolId) } else { - onToolAdded(toolId) + onToolAdd(toolId) } }, ) diff --git a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/di/AgentsModule.kt b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/di/AgentsModule.kt index 71b226b..dc61d96 100644 --- a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/di/AgentsModule.kt +++ b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/di/AgentsModule.kt @@ -14,17 +14,22 @@ val agentsModule = module { includes(agentsPlatformModule) viewModelOf(::AgentMarketplaceViewModel) + // Koin's constructor-DSL (`viewModelOf`) wires every argument via `get()` and cannot read + // values passed through `parametersOf`. Both VMs below receive `initialAgentId` from the + // navigation layer via `parametersOf`, so the lambda-form `viewModel { params -> ... }` is + // the only DSL that works here. Detekt's `DeprecatedKoinApi` is a blanket stylistic rule, + // not a real `@Deprecated` API, so we suppress it in the narrow places it applies. + @Suppress("DeprecatedKoinApi") viewModel { params -> AgentDetailViewModel( - savedStateHandle = get(), agentRepository = get(), serverDataStore = get(), initialAgentId = params.getOrNull(), ) } + @Suppress("DeprecatedKoinApi") viewModel { params -> AgentEditorViewModel( - savedStateHandle = get(), agentRepository = get(), configRepository = get(), mcpRepository = get(), diff --git a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/navigation/AgentsNavigation.kt b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/navigation/AgentsNavigation.kt index 32566ff..1347e4f 100644 --- a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/navigation/AgentsNavigation.kt +++ b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/navigation/AgentsNavigation.kt @@ -13,8 +13,11 @@ import kotlinx.serialization.modules.subclass @Serializable sealed interface AgentsRoute : NavKey @Serializable data object AgentMarketplace : AgentsRoute + @Serializable data class AgentDetail(val agentId: String) : AgentsRoute + @Serializable data object AgentEditorCreate : AgentsRoute + @Serializable data class AgentEditorEdit(val agentId: String) : AgentsRoute fun EntryProviderScope.agentsEntries( @@ -34,21 +37,21 @@ fun EntryProviderScope.agentsEntries( onBack = onBack, onStartChat = onStartChat, onEdit = { agentId -> onNavigate(AgentEditorEdit(agentId = agentId)) }, - onDuplicated = { agentId -> onNavigate(AgentDetail(agentId = agentId)) }, + onDuplicate = { agentId -> onNavigate(AgentDetail(agentId = agentId)) }, agentId = key.agentId, ) } entry { AgentEditorScreen( onBack = onBack, - onSaved = { agentId -> onNavigate(AgentDetail(agentId = agentId)) }, + onSave = { agentId -> onNavigate(AgentDetail(agentId = agentId)) }, agentId = null, ) } entry { key -> AgentEditorScreen( onBack = onBack, - onSaved = { agentId -> onNavigate(AgentDetail(agentId = agentId)) }, + onSave = { agentId -> onNavigate(AgentDetail(agentId = agentId)) }, agentId = key.agentId, ) } diff --git a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/screen/AgentDetailScreen.kt b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/screen/AgentDetailScreen.kt index 6e4528f..95c9044 100644 --- a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/screen/AgentDetailScreen.kt +++ b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/screen/AgentDetailScreen.kt @@ -39,45 +39,47 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.garfiec.librechat.core.model.EModelEndpoint import com.garfiec.librechat.core.ui.components.AvatarImage -import com.garfiec.librechat.core.ui.components.endpointIconPainter import com.garfiec.librechat.core.ui.components.ErrorBanner import com.garfiec.librechat.core.ui.components.LoadingIndicator -import librechat_mobile.feature.agents.generated.resources.Res -import librechat_mobile.feature.agents.generated.resources.* +import com.garfiec.librechat.core.ui.components.endpointIconPainter +import com.garfiec.librechat.feature.agents.resources.* +import com.garfiec.librechat.feature.agents.resources.Res import com.garfiec.librechat.feature.agents.viewmodel.AgentDetailEvent import com.garfiec.librechat.feature.agents.viewmodel.AgentDetailViewModel +import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel import org.koin.core.parameter.parametersOf - @OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class) @Composable fun AgentDetailScreen( onBack: () -> Unit, onStartChat: (String) -> Unit, onEdit: (String) -> Unit, - onDuplicated: (String) -> Unit, - agentId: String? = null, + onDuplicate: (String) -> Unit, modifier: Modifier = Modifier, + agentId: String? = null, viewModel: AgentDetailViewModel = koinViewModel { parametersOf(agentId) }, ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val currentOnBack by rememberUpdatedState(onBack) + val currentOnDuplicated by rememberUpdatedState(onDuplicate) LaunchedEffect(Unit) { viewModel.events.collect { event -> when (event) { - is AgentDetailEvent.Deleted -> onBack() - is AgentDetailEvent.Duplicated -> onDuplicated(event.agentId) + is AgentDetailEvent.Deleted -> currentOnBack() + is AgentDetailEvent.Duplicated -> currentOnDuplicated(event.agentId) } } } diff --git a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/screen/AgentEditorScreen.kt b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/screen/AgentEditorScreen.kt index ecc98f4..5752a8b 100644 --- a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/screen/AgentEditorScreen.kt +++ b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/screen/AgentEditorScreen.kt @@ -44,17 +44,15 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.garfiec.librechat.core.ui.components.ErrorBanner import com.garfiec.librechat.core.ui.components.LoadingIndicator -import librechat_mobile.feature.agents.generated.resources.Res -import librechat_mobile.feature.agents.generated.resources.* import com.garfiec.librechat.feature.agents.components.AgentActionsPanel import com.garfiec.librechat.feature.agents.components.AgentAdvancedPanel import com.garfiec.librechat.feature.agents.components.AgentAvatarPicker @@ -68,8 +66,11 @@ import com.garfiec.librechat.feature.agents.components.AgentSharingSection import com.garfiec.librechat.feature.agents.components.AgentSupportContactSection import com.garfiec.librechat.feature.agents.components.AgentVersionHistory import com.garfiec.librechat.feature.agents.components.ToolSelectDialog +import com.garfiec.librechat.feature.agents.resources.* +import com.garfiec.librechat.feature.agents.resources.Res import com.garfiec.librechat.feature.agents.viewmodel.AgentEditorEvent import com.garfiec.librechat.feature.agents.viewmodel.AgentEditorViewModel +import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel import org.koin.core.parameter.parametersOf @@ -77,22 +78,25 @@ import org.koin.core.parameter.parametersOf @Composable fun AgentEditorScreen( onBack: () -> Unit, - onSaved: (String) -> Unit, - agentId: String? = null, + onSave: (String) -> Unit, modifier: Modifier = Modifier, - onDeleted: () -> Unit = onBack, - onDuplicated: (String) -> Unit = onSaved, + agentId: String? = null, + onDelete: () -> Unit = onBack, + onDuplicate: (String) -> Unit = onSave, viewModel: AgentEditorViewModel = koinViewModel { parametersOf(agentId) }, ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() var showToolDialog by rememberSaveable { mutableStateOf(false) } + val currentOnSaved by rememberUpdatedState(onSave) + val currentOnDuplicated by rememberUpdatedState(onDuplicate) + val currentOnDeleted by rememberUpdatedState(onDelete) LaunchedEffect(Unit) { viewModel.events.collect { event -> when (event) { - is AgentEditorEvent.SaveSuccess -> onSaved(event.agentId) - is AgentEditorEvent.DuplicateSuccess -> onDuplicated(event.agentId) - is AgentEditorEvent.DeleteSuccess -> onDeleted() + is AgentEditorEvent.SaveSuccess -> currentOnSaved(event.agentId) + is AgentEditorEvent.DuplicateSuccess -> currentOnDuplicated(event.agentId) + is AgentEditorEvent.DeleteSuccess -> currentOnDeleted() } } } @@ -149,8 +153,8 @@ fun AgentEditorScreen( ToolSelectDialog( tools = uiState.availableTools, selectedToolIds = uiState.selectedTools, - onToolAdded = viewModel::onToolAdded, - onToolRemoved = viewModel::onToolRemoved, + onToolAdd = viewModel::onToolAdded, + onToolRemove = viewModel::onToolRemoved, onDismiss = { showToolDialog = false }, ) } @@ -283,7 +287,7 @@ fun AgentEditorScreen( AgentAvatarPicker( avatarUrl = uiState.avatarUrl, agentName = uiState.name, - onImageSelected = viewModel::uploadAvatar, + onImageSelect = viewModel::uploadAvatar, ) Spacer(modifier = Modifier.height(4.dp)) Text( @@ -330,7 +334,7 @@ fun AgentEditorScreen( AgentCategorySelector( selectedCategory = uiState.category, categories = uiState.categories, - onCategorySelected = viewModel::onCategoryChanged, + onCategorySelect = viewModel::onCategoryChanged, modifier = Modifier.fillMaxWidth(), ) @@ -353,7 +357,7 @@ fun AgentEditorScreen( AgentModelPicker( selectedModel = uiState.model, availableModels = uiState.availableModels, - onModelSelected = viewModel::onModelSelected, + onModelSelect = viewModel::onModelSelected, modifier = Modifier.fillMaxWidth(), ) @@ -389,7 +393,7 @@ fun AgentEditorScreen( AgentMcpToolsSelector( mcpTools = uiState.mcpTools, selectedToolNames = uiState.selectedMcpTools, - onToolToggled = viewModel::onMcpToolToggled, + onToolToggle = viewModel::onMcpToolToggled, ) Spacer(modifier = Modifier.height(12.dp)) @@ -472,7 +476,7 @@ fun AgentEditorScreen( // 10. Support Contact AgentSupportContactSection( supportContact = uiState.supportContact, - onSupportContactChanged = viewModel::onSupportContactChanged, + onSupportContactChange = viewModel::onSupportContactChanged, ) Spacer(modifier = Modifier.height(16.dp)) @@ -533,7 +537,7 @@ fun AgentEditorScreen( // Sharing & Permissions AgentSharingSection( sharingState = uiState.sharingState, - onSharingChanged = viewModel::onSharingChanged, + onSharingChange = viewModel::onSharingChanged, ) Spacer(modifier = Modifier.height(8.dp)) @@ -551,7 +555,7 @@ fun AgentEditorScreen( // 12. Advanced settings (collapsible) AgentAdvancedPanel( settings = uiState.advancedSettings, - onSettingsChanged = viewModel::onAdvancedSettingsChanged, + onSettingsChange = viewModel::onAdvancedSettingsChanged, ) Spacer(modifier = Modifier.height(24.dp)) diff --git a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/screen/AgentMarketplaceScreen.kt b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/screen/AgentMarketplaceScreen.kt index c7ebb6b..8e9f9d9 100644 --- a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/screen/AgentMarketplaceScreen.kt +++ b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/screen/AgentMarketplaceScreen.kt @@ -41,24 +41,23 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.garfiec.librechat.core.model.EModelEndpoint import com.garfiec.librechat.core.ui.components.AvatarImage -import com.garfiec.librechat.core.ui.components.endpointIconPainter import com.garfiec.librechat.core.ui.components.EmptyState import com.garfiec.librechat.core.ui.components.ErrorBanner import com.garfiec.librechat.core.ui.components.LibreChatTopBar import com.garfiec.librechat.core.ui.components.LoadingIndicator +import com.garfiec.librechat.core.ui.components.endpointIconPainter import com.garfiec.librechat.feature.agents.AgentCardDisplayData -import librechat_mobile.feature.agents.generated.resources.Res -import librechat_mobile.feature.agents.generated.resources.* +import com.garfiec.librechat.feature.agents.resources.* +import com.garfiec.librechat.feature.agents.resources.Res import com.garfiec.librechat.feature.agents.viewmodel.AgentMarketplaceViewModel +import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel - @OptIn(ExperimentalMaterial3Api::class) @Composable fun AgentMarketplaceScreen( diff --git a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/util/OpenApiSpecParser.kt b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/util/OpenApiSpecParser.kt index 2967b19..79af642 100644 --- a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/util/OpenApiSpecParser.kt +++ b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/util/OpenApiSpecParser.kt @@ -5,7 +5,6 @@ import com.garfiec.librechat.core.model.request.FunctionTool import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonElement -import kotlinx.serialization.json.JsonNull import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.jsonArray diff --git a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/util/YamlParser.kt b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/util/YamlParser.kt index 7f5e034..adef6db 100644 --- a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/util/YamlParser.kt +++ b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/util/YamlParser.kt @@ -54,19 +54,11 @@ private class YamlParser(input: String) { val entries = mutableMapOf() while (pos < lines.size) { skipBlanksAndComments() - if (pos >= lines.size) break - val indent = currentIndent() - if (indent < baseIndent) break - if (indent > baseIndent) break // belongs to parent + if (shouldStopParsingMap(baseIndent)) break val line = lines[pos] val trimmed = line.trimStart() - - // Must be a map entry, not a list item - if (trimmed.startsWith("- ")) break - val colonIdx = findKeyColonIndex(trimmed) - if (colonIdx < 0) break val key = trimmed.substring(0, colonIdx).trim().unquoteYaml() val afterColon = trimmed.substring(colonIdx + 1).trim() @@ -97,17 +89,59 @@ private class YamlParser(input: String) { return JsonObject(entries) } + /** + * Returns true when [parseMap] should stop consuming lines at the current position. + * Extracted from the main loop to reduce jump count — preserves the original behaviour + * exactly: end-of-input, dedent to parent, indent into child, list item, or a line + * without a key colon all terminate the map. + */ + private fun shouldStopParsingMap(baseIndent: Int): Boolean { + if (pos >= lines.size) return true + val indent = currentIndent() + if (indent < baseIndent) return true + if (indent > baseIndent) return true // belongs to parent + val trimmed = lines[pos].trimStart() + if (trimmed.startsWith("- ")) return true // must be a map entry, not a list item + if (findKeyColonIndex(trimmed) < 0) return true + return false + } + + /** + * Returns true when [parseList] should stop consuming lines at the current position. + * Extracted from the main loop to reduce jump count — preserves the original behaviour + * exactly: end-of-input, any indent mismatch, or a line that is not a list item all + * terminate the list. + */ + private fun shouldStopParsingList(baseIndent: Int): Boolean { + if (pos >= lines.size) return true + if (currentIndent() != baseIndent) return true + val trimmed = lines[pos].trimStart() + if (!trimmed.startsWith("- ") && trimmed != "-") return true + return false + } + + /** + * Returns true when the continuation loop in [parseListItemMap] should stop at the + * current position. Extracted from the main loop to reduce jump count — preserves the + * original behaviour exactly: end-of-input, dedent below the content indent, next list + * item, or a line without a key colon all terminate the continuation. + */ + private fun shouldStopParsingListItemMap(contentIndent: Int): Boolean { + if (pos >= lines.size) return true + if (currentIndent() < contentIndent) return true + val line = lines[pos].trimStart() + if (line.startsWith("- ")) return true // next list item + if (findKeyColonIndex(line) < 0) return true + return false + } + private fun parseList(baseIndent: Int): JsonArray { val items = mutableListOf() while (pos < lines.size) { skipBlanksAndComments() - if (pos >= lines.size) break - val indent = currentIndent() - if (indent != baseIndent) break + if (shouldStopParsingList(baseIndent)) break val trimmed = lines[pos].trimStart() - if (!trimmed.startsWith("- ") && trimmed != "-") break - val afterDash = if (trimmed == "-") "" else trimmed.substring(2).trim() pos++ @@ -175,15 +209,11 @@ private class YamlParser(input: String) { // Continuation lines at contentIndent while (pos < lines.size) { skipBlanksAndComments() - if (pos >= lines.size) break + if (shouldStopParsingListItemMap(contentIndent)) break + val indent = currentIndent() - if (indent < contentIndent) break - val line = lines[pos].trimStart() - if (line.startsWith("- ")) break // next list item - val ci = findKeyColonIndex(line) - if (ci < 0) break val key = line.substring(0, ci).trim().unquoteYaml() val afterColon = line.substring(ci + 1).trim() diff --git a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/viewmodel/AgentDetailViewModel.kt b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/viewmodel/AgentDetailViewModel.kt index 6eaa69d..6933062 100644 --- a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/viewmodel/AgentDetailViewModel.kt +++ b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/viewmodel/AgentDetailViewModel.kt @@ -1,7 +1,6 @@ package com.garfiec.librechat.feature.agents.viewmodel import androidx.compose.runtime.Immutable -import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.garfiec.librechat.core.common.result.Result @@ -33,7 +32,6 @@ sealed interface AgentDetailEvent { } class AgentDetailViewModel( - savedStateHandle: SavedStateHandle, private val agentRepository: AgentRepository, private val serverDataStore: ServerDataStore, initialAgentId: String? = null, diff --git a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/viewmodel/AgentEditorViewModel.kt b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/viewmodel/AgentEditorViewModel.kt index 1f03c28..3705478 100644 --- a/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/viewmodel/AgentEditorViewModel.kt +++ b/feature/agents/src/commonMain/kotlin/com/garfiec/librechat/feature/agents/viewmodel/AgentEditorViewModel.kt @@ -1,10 +1,9 @@ package com.garfiec.librechat.feature.agents.viewmodel import androidx.compose.runtime.Immutable -import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.garfiec.librechat.feature.agents.util.ContentReader +import co.touchlab.kermit.Logger import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.data.repository.AgentRepository import com.garfiec.librechat.core.data.repository.ConfigRepository @@ -31,6 +30,7 @@ import com.garfiec.librechat.feature.agents.components.model.AgentSharingState import com.garfiec.librechat.feature.agents.components.model.AgentVersion import com.garfiec.librechat.feature.agents.components.model.AgentVisibility import com.garfiec.librechat.feature.agents.components.model.SupportContactState +import com.garfiec.librechat.feature.agents.util.ContentReader import com.garfiec.librechat.feature.agents.util.OpenApiSpecParser import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow @@ -46,7 +46,6 @@ import kotlinx.serialization.json.floatOrNull import kotlinx.serialization.json.intOrNull import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonPrimitive -import co.touchlab.kermit.Logger @Immutable data class AgentEditorUiState( @@ -103,7 +102,6 @@ sealed interface AgentEditorEvent { } class AgentEditorViewModel( - savedStateHandle: SavedStateHandle, private val agentRepository: AgentRepository, private val configRepository: ConfigRepository, private val mcpRepository: McpRepository, @@ -171,7 +169,8 @@ class AgentEditorViewModel( val agent = result.data Logger.d { "AgentEditor: Loaded agent fields BEFORE mapping - " + - "name=${agent.name}, description=${agent.description}, instructions=${agent.instructions}, model=${agent.model}, " + + "name=${agent.name}, description=${agent.description}, " + + "instructions=${agent.instructions}, model=${agent.model}, " + "provider=${agent.provider}, category=${agent.category}, tools=${agent.tools}, " + "conversationStarters=${agent.conversationStarters}, avatarUrl=${agent.avatarUrl}, " + "artifacts=${agent.artifacts}, recursionLimit=${agent.recursionLimit}, " + @@ -185,7 +184,8 @@ class AgentEditorViewModel( .copy(isLoading = false) Logger.d { "AgentEditor: UI state AFTER mapping - " + - "name=${newState.name}, description=${newState.description}, instructions=${newState.instructions}, model=${newState.model}, " + + "name=${newState.name}, description=${newState.description}, " + + "instructions=${newState.instructions}, model=${newState.model}, " + "provider=${newState.provider}, category=${newState.category}, selectedTools=${newState.selectedTools}, " + "conversationStarters=${newState.conversationStarters}, avatarUrl=${newState.avatarUrl}, " + "codeInterpreterEnabled=${newState.codeInterpreterEnabled}, fileSearchEnabled=${newState.fileSearchEnabled}, " + diff --git a/feature/agents/src/iosMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentAvatarPicker.ios.kt b/feature/agents/src/iosMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentAvatarPicker.ios.kt index 88f8384..674124e 100644 --- a/feature/agents/src/iosMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentAvatarPicker.ios.kt +++ b/feature/agents/src/iosMain/kotlin/com/garfiec/librechat/feature/agents/components/AgentAvatarPicker.ios.kt @@ -16,7 +16,7 @@ import androidx.compose.ui.unit.dp actual fun AgentAvatarPicker( avatarUrl: String?, agentName: String, - onImageSelected: (Any) -> Unit, + onImageSelect: (Any) -> Unit, modifier: Modifier, ) { // iOS: placeholder avatar display only (no image picker yet) diff --git a/feature/agents/src/iosMain/kotlin/com/garfiec/librechat/feature/agents/di/AgentsPlatformModule.ios.kt b/feature/agents/src/iosMain/kotlin/com/garfiec/librechat/feature/agents/di/AgentsPlatformModule.ios.kt index d6e7a1a..ff7a486 100644 --- a/feature/agents/src/iosMain/kotlin/com/garfiec/librechat/feature/agents/di/AgentsPlatformModule.ios.kt +++ b/feature/agents/src/iosMain/kotlin/com/garfiec/librechat/feature/agents/di/AgentsPlatformModule.ios.kt @@ -11,7 +11,6 @@ import org.koin.dsl.module import platform.Foundation.NSData import platform.Foundation.NSURL import platform.Foundation.dataWithContentsOfURL -import platform.Foundation.lastPathComponent import platform.Foundation.pathExtension import platform.posix.memcpy diff --git a/feature/auth/detekt-baseline.xml b/feature/auth/detekt-baseline.xml deleted file mode 100644 index e54f6e6..0000000 --- a/feature/auth/detekt-baseline.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - ComposableParamOrder:ResetPasswordScreen.kt$ResetPasswordScreen - ComposableParamOrder:TwoFactorScreen.kt$TwoFactorScreen - ComposableParamOrder:VerifyEmailScreen.kt$VerifyEmailScreen - DeprecatedKoinApi:AuthModule.kt$viewModel { params -> ResetPasswordViewModel( savedStateHandle = get(), authRepository = get(), initialUserId = params.getOrNull(), initialToken = params.getOrNull(), ) } - DeprecatedKoinApi:AuthModule.kt$viewModel { params -> TwoFactorViewModel( savedStateHandle = get(), authRepository = get(), initialTempToken = params.getOrNull(), ) } - DeprecatedKoinApi:AuthModule.kt$viewModel { params -> VerifyEmailViewModel( savedStateHandle = get(), userRepository = get(), initialEmail = params.getOrNull(), ) } - FunctionNaming:String0.commonMain.kt$@InternalResourceApi internal fun _collectCommonMainString0Resources(map: MutableMap<String, StringResource>) - ImportOrdering:ExpectResourceCollectors.kt$import kotlin.String import kotlin.collections.Map import org.jetbrains.compose.resources.DrawableResource import org.jetbrains.compose.resources.FontResource import org.jetbrains.compose.resources.PluralStringResource import org.jetbrains.compose.resources.StringArrayResource import org.jetbrains.compose.resources.StringResource - ImportOrdering:ForgotPasswordScreen.kt$import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material3.Button import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import librechat_mobile.feature.auth.generated.resources.Res import librechat_mobile.feature.auth.generated.resources.* import com.garfiec.librechat.feature.auth.viewmodel.ForgotPasswordViewModel import org.koin.compose.viewmodel.koinViewModel - ImportOrdering:LoginScreen.kt$import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material3.Button import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.lifecycle.Lifecycle import androidx.lifecycle.compose.LifecycleEventEffect import androidx.lifecycle.compose.collectAsStateWithLifecycle import librechat_mobile.feature.auth.generated.resources.Res import librechat_mobile.feature.auth.generated.resources.* import com.garfiec.librechat.feature.auth.viewmodel.LoginViewModel import org.koin.compose.viewmodel.koinViewModel - ImportOrdering:RegisterScreen.kt$import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Button import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import librechat_mobile.feature.auth.generated.resources.Res import librechat_mobile.feature.auth.generated.resources.* import com.garfiec.librechat.feature.auth.viewmodel.RegisterViewModel import org.koin.compose.viewmodel.koinViewModel - ImportOrdering:Res.kt$import kotlin.ByteArray import kotlin.OptIn import kotlin.String import kotlin.Suppress import org.jetbrains.compose.resources.InternalResourceApi import org.jetbrains.compose.resources.getResourceUri import org.jetbrains.compose.resources.readResourceBytes - ImportOrdering:ResetPasswordScreen.kt$import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material3.Button import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import librechat_mobile.feature.auth.generated.resources.Res import librechat_mobile.feature.auth.generated.resources.* import com.garfiec.librechat.feature.auth.viewmodel.ResetPasswordViewModel import org.koin.compose.viewmodel.koinViewModel import org.koin.core.parameter.parametersOf - ImportOrdering:ServerUrlScreen.kt$import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import librechat_mobile.feature.auth.generated.resources.Res import librechat_mobile.feature.auth.generated.resources.* import com.garfiec.librechat.feature.auth.viewmodel.ServerUrlViewModel import org.koin.compose.viewmodel.koinViewModel - ImportOrdering:String0.commonMain.kt$import kotlin.OptIn import kotlin.String import kotlin.collections.MutableMap import org.jetbrains.compose.resources.InternalResourceApi import org.jetbrains.compose.resources.ResourceContentHash import org.jetbrains.compose.resources.ResourceItem import org.jetbrains.compose.resources.StringResource - ImportOrdering:TermsScreen.kt$import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material3.Button import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import librechat_mobile.feature.auth.generated.resources.Res import librechat_mobile.feature.auth.generated.resources.* import com.garfiec.librechat.feature.auth.viewmodel.TermsViewModel import org.koin.compose.viewmodel.koinViewModel - ImportOrdering:TwoFactorScreen.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material3.Button import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import librechat_mobile.feature.auth.generated.resources.Res import librechat_mobile.feature.auth.generated.resources.* import com.garfiec.librechat.feature.auth.viewmodel.TwoFactorViewModel import org.koin.compose.viewmodel.koinViewModel import org.koin.core.parameter.parametersOf - ImportOrdering:VerifyEmailScreen.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material3.Button import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import librechat_mobile.feature.auth.generated.resources.Res import librechat_mobile.feature.auth.generated.resources.* import com.garfiec.librechat.feature.auth.viewmodel.VerifyEmailViewModel import org.koin.compose.viewmodel.koinViewModel import org.koin.core.parameter.parametersOf - LambdaParameterInRestartableEffect:LoginScreen.kt$onLoginSuccess - LambdaParameterInRestartableEffect:LoginScreen.kt$onNavigateToTwoFactor - LambdaParameterInRestartableEffect:RegisterScreen.kt$onRegistered - LambdaParameterInRestartableEffect:ServerUrlScreen.kt$onServerValidated - LambdaParameterInRestartableEffect:TermsScreen.kt$onAccepted - LambdaParameterInRestartableEffect:TwoFactorScreen.kt$onVerified - LambdaParameterInRestartableEffect:VerifyEmailScreen.kt$onVerified - MaxLineLength:Res.kt$Res$public suspend - MaxLineLength:TwoFactorScreen.kt$if (uiState.isBackupMode) stringResource(Res.string.use_authenticator_code) else stringResource(Res.string.use_backup_code) - ModifierNotUsedAtRoot:ForgotPasswordScreen.kt$modifier = modifier .fillMaxSize() .background(MaterialTheme.colorScheme.background) .padding(padding) .padding(24.dp) - NoBlankLineBeforeRbrace:ServerUrlViewModel.kt$ServerUrlViewModel$ - PackageName:ExpectResourceCollectors.kt$package librechat_mobile.feature.auth.generated.resources - PackageName:Res.kt$package librechat_mobile.feature.auth.generated.resources - PackageName:String0.commonMain.kt$package librechat_mobile.feature.auth.generated.resources - PackageNaming:ExpectResourceCollectors.kt$package librechat_mobile.feature.auth.generated.resources - PackageNaming:Res.kt$package librechat_mobile.feature.auth.generated.resources - PackageNaming:String0.commonMain.kt$package librechat_mobile.feature.auth.generated.resources - ParameterNaming:RegisterScreen.kt$onRegistered - ParameterNaming:ServerUrlScreen.kt$onServerValidated - ParameterNaming:TermsScreen.kt$onAccepted - ParameterNaming:TwoFactorScreen.kt$onCodeChanged - ParameterNaming:TwoFactorScreen.kt$onDigitChanged - ParameterNaming:TwoFactorScreen.kt$onVerified - ParameterNaming:VerifyEmailScreen.kt$onVerified - SpacingBetweenDeclarationsWithAnnotations:AuthNavigation.kt$ForgotPassword : AuthRoute - SpacingBetweenDeclarationsWithAnnotations:AuthNavigation.kt$Login : AuthRoute - SpacingBetweenDeclarationsWithAnnotations:AuthNavigation.kt$Register : AuthRoute - SpacingBetweenDeclarationsWithAnnotations:AuthNavigation.kt$ResetPassword : AuthRoute - SpacingBetweenDeclarationsWithAnnotations:AuthNavigation.kt$Terms : AuthRoute - SpacingBetweenDeclarationsWithAnnotations:AuthNavigation.kt$TwoFactor : AuthRoute - SpacingBetweenDeclarationsWithAnnotations:AuthNavigation.kt$VerifyEmail : AuthRoute - UnusedPrivateProperty:ResetPasswordViewModel.kt$ResetPasswordViewModel$savedStateHandle: SavedStateHandle - UnusedPrivateProperty:TwoFactorViewModel.kt$TwoFactorViewModel$savedStateHandle: SavedStateHandle - UnusedPrivateProperty:VerifyEmailViewModel.kt$VerifyEmailViewModel$savedStateHandle: SavedStateHandle - - diff --git a/feature/auth/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/auth/di/AuthModuleVerificationTest.kt b/feature/auth/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/auth/di/AuthModuleVerificationTest.kt index 297ea6b..423b99d 100644 --- a/feature/auth/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/auth/di/AuthModuleVerificationTest.kt +++ b/feature/auth/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/auth/di/AuthModuleVerificationTest.kt @@ -2,7 +2,6 @@ package com.garfiec.librechat.feature.auth.di import android.app.Application import android.content.Context -import androidx.lifecycle.SavedStateHandle import com.garfiec.librechat.core.data.datastore.ServerDataStore import com.garfiec.librechat.core.data.repository.AuthRepository import com.garfiec.librechat.core.data.repository.ConfigRepository @@ -19,7 +18,6 @@ class AuthModuleVerificationTest { extraTypes = listOf( Context::class, Application::class, - SavedStateHandle::class, ServerDataStore::class, AuthRepository::class, ConfigRepository::class, diff --git a/feature/auth/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/auth/viewmodel/LoginViewModelTest.kt b/feature/auth/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/auth/viewmodel/LoginViewModelTest.kt index 6c62fd4..76e8400 100644 --- a/feature/auth/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/auth/viewmodel/LoginViewModelTest.kt +++ b/feature/auth/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/auth/viewmodel/LoginViewModelTest.kt @@ -1,14 +1,14 @@ package com.garfiec.librechat.feature.auth.viewmodel -import com.google.common.truth.Truth.assertThat import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.data.datastore.ServerDataStore import com.garfiec.librechat.core.data.repository.AuthRepository import com.garfiec.librechat.core.data.repository.ConfigRepository import com.garfiec.librechat.core.model.LoginOutcome -import com.garfiec.librechat.core.model.config.StartupConfig import com.garfiec.librechat.core.model.User +import com.garfiec.librechat.core.model.config.StartupConfig import com.garfiec.librechat.feature.auth.oauth.OAuthLauncher +import com.google.common.truth.Truth.assertThat import io.mockk.coEvery import io.mockk.every import io.mockk.mockk diff --git a/feature/auth/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/auth/viewmodel/RegisterViewModelTest.kt b/feature/auth/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/auth/viewmodel/RegisterViewModelTest.kt index 2994d4c..618df95 100644 --- a/feature/auth/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/auth/viewmodel/RegisterViewModelTest.kt +++ b/feature/auth/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/auth/viewmodel/RegisterViewModelTest.kt @@ -1,10 +1,10 @@ package com.garfiec.librechat.feature.auth.viewmodel -import com.google.common.truth.Truth.assertThat import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.data.repository.AuthRepository import com.garfiec.librechat.core.data.repository.ConfigRepository import com.garfiec.librechat.core.model.config.StartupConfig +import com.google.common.truth.Truth.assertThat import io.mockk.coEvery import io.mockk.coVerify import io.mockk.every diff --git a/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/di/AuthModule.kt b/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/di/AuthModule.kt index 27d7a6e..eb15a49 100644 --- a/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/di/AuthModule.kt +++ b/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/di/AuthModule.kt @@ -20,25 +20,31 @@ val authModule = module { viewModelOf(::ServerUrlViewModel) viewModelOf(::LoginViewModel) viewModelOf(::RegisterViewModel) + // Koin's constructor-DSL (`viewModelOf`) wires every argument via `get()` and cannot read + // values passed through `parametersOf`. The VMs below receive initial seeds (email, user + // id, token, temp token) from the navigation layer via `parametersOf`, so the lambda-form + // `viewModel { params -> ... }` is the only DSL that works here. Detekt's `DeprecatedKoinApi` + // is a blanket stylistic rule, not a real `@Deprecated` API, so we suppress it in the + // narrow places it applies. + @Suppress("DeprecatedKoinApi") viewModel { params -> VerifyEmailViewModel( - savedStateHandle = get(), userRepository = get(), initialEmail = params.getOrNull(), ) } viewModelOf(::ForgotPasswordViewModel) + @Suppress("DeprecatedKoinApi") viewModel { params -> ResetPasswordViewModel( - savedStateHandle = get(), authRepository = get(), initialUserId = params.getOrNull(), initialToken = params.getOrNull(), ) } + @Suppress("DeprecatedKoinApi") viewModel { params -> TwoFactorViewModel( - savedStateHandle = get(), authRepository = get(), initialTempToken = params.getOrNull(), ) diff --git a/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/navigation/AuthNavigation.kt b/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/navigation/AuthNavigation.kt index 1a81623..2269f59 100644 --- a/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/navigation/AuthNavigation.kt +++ b/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/navigation/AuthNavigation.kt @@ -18,12 +18,19 @@ import kotlinx.serialization.modules.subclass @Serializable sealed interface AuthRoute : NavKey @Serializable data object ServerUrl : AuthRoute + @Serializable data object Login : AuthRoute + @Serializable data object Register : AuthRoute + @Serializable data object ForgotPassword : AuthRoute + @Serializable data class TwoFactor(val tempToken: String) : AuthRoute + @Serializable data class VerifyEmail(val email: String) : AuthRoute + @Serializable data object Terms : AuthRoute + @Serializable data class ResetPassword(val userId: String, val token: String) : AuthRoute fun EntryProviderScope.authEntries( @@ -33,7 +40,7 @@ fun EntryProviderScope.authEntries( ) { entry { ServerUrlScreen( - onServerValidated = { onNavigate(Login) }, + onServerValidate = { onNavigate(Login) }, ) } entry { @@ -48,7 +55,7 @@ fun EntryProviderScope.authEntries( } entry { RegisterScreen( - onRegistered = onBack, + onRegister = onBack, onNavigateToLogin = onBack, ) } @@ -59,21 +66,21 @@ fun EntryProviderScope.authEntries( } entry { key -> TwoFactorScreen( - onVerified = onAuthComplete, + onVerify = onAuthComplete, onBack = onBack, tempToken = key.tempToken, ) } entry { key -> VerifyEmailScreen( - onVerified = onBack, + onVerify = onBack, onBack = onBack, email = key.email, ) } entry { TermsScreen( - onAccepted = onAuthComplete, + onAccept = onAuthComplete, onBack = onBack, ) } diff --git a/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/ForgotPasswordScreen.kt b/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/ForgotPasswordScreen.kt index 9694690..4c0eaf7 100644 --- a/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/ForgotPasswordScreen.kt +++ b/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/ForgotPasswordScreen.kt @@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material3.Button @@ -24,16 +25,15 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics -import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import librechat_mobile.feature.auth.generated.resources.Res -import librechat_mobile.feature.auth.generated.resources.* +import com.garfiec.librechat.feature.auth.resources.* +import com.garfiec.librechat.feature.auth.resources.Res import com.garfiec.librechat.feature.auth.viewmodel.ForgotPasswordViewModel +import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel @OptIn(ExperimentalMaterial3Api::class) @@ -46,6 +46,7 @@ fun ForgotPasswordScreen( val uiState by viewModel.uiState.collectAsStateWithLifecycle() Scaffold( + modifier = modifier, containerColor = MaterialTheme.colorScheme.background, topBar = { TopAppBar( @@ -59,7 +60,7 @@ fun ForgotPasswordScreen( }, ) { padding -> Column( - modifier = modifier + modifier = Modifier .fillMaxSize() .background(MaterialTheme.colorScheme.background) .padding(padding) diff --git a/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/LoginScreen.kt b/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/LoginScreen.kt index 1d69d67..8f32d8f 100644 --- a/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/LoginScreen.kt +++ b/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/LoginScreen.kt @@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.Button import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.HorizontalDivider @@ -19,21 +20,21 @@ import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics -import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.lifecycle.Lifecycle import androidx.lifecycle.compose.LifecycleEventEffect import androidx.lifecycle.compose.collectAsStateWithLifecycle -import librechat_mobile.feature.auth.generated.resources.Res -import librechat_mobile.feature.auth.generated.resources.* +import com.garfiec.librechat.feature.auth.resources.* +import com.garfiec.librechat.feature.auth.resources.Res import com.garfiec.librechat.feature.auth.viewmodel.LoginViewModel +import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel @Composable @@ -46,6 +47,8 @@ fun LoginScreen( viewModel: LoginViewModel = koinViewModel(), ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val currentOnLoginSuccess by rememberUpdatedState(onLoginSuccess) + val currentOnNavigateToTwoFactor by rememberUpdatedState(onNavigateToTwoFactor) // Check for OAuth result when returning from Chrome Custom Tab LifecycleEventEffect(Lifecycle.Event.ON_RESUME) { @@ -54,14 +57,14 @@ fun LoginScreen( LaunchedEffect(uiState.isLoggedIn) { if (uiState.isLoggedIn) { - onLoginSuccess() + currentOnLoginSuccess() } } LaunchedEffect(uiState.twoFactorTempToken) { val tempToken = uiState.twoFactorTempToken if (tempToken != null) { - onNavigateToTwoFactor(tempToken) + currentOnNavigateToTwoFactor(tempToken) } } diff --git a/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/RegisterScreen.kt b/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/RegisterScreen.kt index 6f2e51d..19f678c 100644 --- a/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/RegisterScreen.kt +++ b/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/RegisterScreen.kt @@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Button import androidx.compose.material3.CircularProgressIndicator @@ -19,32 +20,33 @@ import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics -import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import librechat_mobile.feature.auth.generated.resources.Res -import librechat_mobile.feature.auth.generated.resources.* +import com.garfiec.librechat.feature.auth.resources.* +import com.garfiec.librechat.feature.auth.resources.Res import com.garfiec.librechat.feature.auth.viewmodel.RegisterViewModel +import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel @Composable fun RegisterScreen( - onRegistered: () -> Unit, + onRegister: () -> Unit, onNavigateToLogin: () -> Unit, modifier: Modifier = Modifier, viewModel: RegisterViewModel = koinViewModel(), ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val currentOnRegister by rememberUpdatedState(onRegister) LaunchedEffect(uiState.isRegistered) { if (uiState.isRegistered) { - onRegistered() + currentOnRegister() } } diff --git a/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/ResetPasswordScreen.kt b/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/ResetPasswordScreen.kt index 4cc0ee8..40464c1 100644 --- a/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/ResetPasswordScreen.kt +++ b/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/ResetPasswordScreen.kt @@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material3.Button @@ -24,16 +25,15 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics -import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import librechat_mobile.feature.auth.generated.resources.Res -import librechat_mobile.feature.auth.generated.resources.* +import com.garfiec.librechat.feature.auth.resources.* +import com.garfiec.librechat.feature.auth.resources.Res import com.garfiec.librechat.feature.auth.viewmodel.ResetPasswordViewModel +import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel import org.koin.core.parameter.parametersOf @@ -42,9 +42,9 @@ import org.koin.core.parameter.parametersOf fun ResetPasswordScreen( onResetComplete: () -> Unit, onBack: () -> Unit, + modifier: Modifier = Modifier, userId: String? = null, token: String? = null, - modifier: Modifier = Modifier, viewModel: ResetPasswordViewModel = koinViewModel { parametersOf(userId, token) }, ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() diff --git a/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/ServerUrlScreen.kt b/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/ServerUrlScreen.kt index d07f3f0..b9b85c8 100644 --- a/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/ServerUrlScreen.kt +++ b/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/ServerUrlScreen.kt @@ -18,29 +18,31 @@ import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import librechat_mobile.feature.auth.generated.resources.Res -import librechat_mobile.feature.auth.generated.resources.* +import com.garfiec.librechat.feature.auth.resources.* +import com.garfiec.librechat.feature.auth.resources.Res import com.garfiec.librechat.feature.auth.viewmodel.ServerUrlViewModel +import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel @Composable fun ServerUrlScreen( - onServerValidated: () -> Unit, + onServerValidate: () -> Unit, modifier: Modifier = Modifier, viewModel: ServerUrlViewModel = koinViewModel(), ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val currentOnServerValidated by rememberUpdatedState(onServerValidate) LaunchedEffect(uiState.isValidated) { if (uiState.isValidated) { - onServerValidated() + currentOnServerValidated() } } diff --git a/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/TermsScreen.kt b/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/TermsScreen.kt index ee3fcd1..69ce4ed 100644 --- a/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/TermsScreen.kt +++ b/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/TermsScreen.kt @@ -24,34 +24,36 @@ import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import librechat_mobile.feature.auth.generated.resources.Res -import librechat_mobile.feature.auth.generated.resources.* +import com.garfiec.librechat.feature.auth.resources.* +import com.garfiec.librechat.feature.auth.resources.Res import com.garfiec.librechat.feature.auth.viewmodel.TermsViewModel +import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel /** Displays server terms of service loaded from the backend; gates navigation on user acceptance. */ @OptIn(ExperimentalMaterial3Api::class) @Composable fun TermsScreen( - onAccepted: () -> Unit, + onAccept: () -> Unit, onBack: () -> Unit, modifier: Modifier = Modifier, viewModel: TermsViewModel = koinViewModel(), ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val currentOnAccepted by rememberUpdatedState(onAccept) LaunchedEffect(uiState.isAccepted) { if (uiState.isAccepted) { viewModel.consumeAccepted() - onAccepted() + currentOnAccepted() } } diff --git a/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/TwoFactorScreen.kt b/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/TwoFactorScreen.kt index 92c6b68..8982d6f 100644 --- a/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/TwoFactorScreen.kt +++ b/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/TwoFactorScreen.kt @@ -27,36 +27,38 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import librechat_mobile.feature.auth.generated.resources.Res -import librechat_mobile.feature.auth.generated.resources.* +import com.garfiec.librechat.feature.auth.resources.* +import com.garfiec.librechat.feature.auth.resources.Res import com.garfiec.librechat.feature.auth.viewmodel.TwoFactorViewModel +import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel import org.koin.core.parameter.parametersOf @OptIn(ExperimentalMaterial3Api::class) @Composable fun TwoFactorScreen( - onVerified: () -> Unit, + onVerify: () -> Unit, onBack: () -> Unit, - tempToken: String? = null, modifier: Modifier = Modifier, + tempToken: String? = null, viewModel: TwoFactorViewModel = koinViewModel { parametersOf(tempToken) }, ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val currentOnVerify by rememberUpdatedState(onVerify) LaunchedEffect(uiState.isVerified) { - if (uiState.isVerified) onVerified() + if (uiState.isVerified) currentOnVerify() } Scaffold( @@ -111,13 +113,13 @@ fun TwoFactorScreen( if (uiState.isBackupMode) { BackupCodeInput( code = uiState.backupCode, - onCodeChanged = viewModel::onBackupCodeChanged, + onCodeChange = viewModel::onBackupCodeChanged, enabled = !uiState.isLoading, ) } else { DigitBoxes( digits = uiState.digits, - onDigitChanged = viewModel::onDigitChanged, + onDigitChange = viewModel::onDigitChanged, enabled = !uiState.isLoading, ) } @@ -155,7 +157,11 @@ fun TwoFactorScreen( TextButton(onClick = viewModel::toggleBackupMode) { Text( - if (uiState.isBackupMode) stringResource(Res.string.use_authenticator_code) else stringResource(Res.string.use_backup_code), + if (uiState.isBackupMode) { + stringResource(Res.string.use_authenticator_code) + } else { + stringResource(Res.string.use_backup_code) + }, ) } } @@ -165,7 +171,7 @@ fun TwoFactorScreen( @Composable private fun DigitBoxes( digits: List, - onDigitChanged: (Int, String) -> Unit, + onDigitChange: (Int, String) -> Unit, enabled: Boolean, modifier: Modifier = Modifier, ) { @@ -181,7 +187,7 @@ private fun DigitBoxes( value = digit, onValueChange = { value -> val filtered = value.filter { it.isDigit() }.take(1) - onDigitChanged(index, filtered) + onDigitChange(index, filtered) if (filtered.isNotEmpty() && index < 5) { focusRequesters[index + 1].requestFocus() } @@ -208,13 +214,13 @@ private fun DigitBoxes( @Composable private fun BackupCodeInput( code: String, - onCodeChanged: (String) -> Unit, + onCodeChange: (String) -> Unit, enabled: Boolean, modifier: Modifier = Modifier, ) { OutlinedTextField( value = code, - onValueChange = onCodeChanged, + onValueChange = onCodeChange, modifier = modifier.fillMaxWidth(), enabled = enabled, singleLine = true, diff --git a/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/VerifyEmailScreen.kt b/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/VerifyEmailScreen.kt index 31af0f3..8a31455 100644 --- a/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/VerifyEmailScreen.kt +++ b/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/screen/VerifyEmailScreen.kt @@ -22,36 +22,38 @@ import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import librechat_mobile.feature.auth.generated.resources.Res -import librechat_mobile.feature.auth.generated.resources.* +import com.garfiec.librechat.feature.auth.resources.* +import com.garfiec.librechat.feature.auth.resources.Res import com.garfiec.librechat.feature.auth.viewmodel.VerifyEmailViewModel +import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel import org.koin.core.parameter.parametersOf @OptIn(ExperimentalMaterial3Api::class) @Composable fun VerifyEmailScreen( - onVerified: () -> Unit, + onVerify: () -> Unit, onBack: () -> Unit, - email: String? = null, modifier: Modifier = Modifier, + email: String? = null, viewModel: VerifyEmailViewModel = koinViewModel { parametersOf(email) }, ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() - val email = uiState.email + val displayEmail = uiState.email + val currentOnVerify by rememberUpdatedState(onVerify) LaunchedEffect(uiState.isVerified) { if (uiState.isVerified) { viewModel.consumeVerified() - onVerified() + currentOnVerify() } } @@ -94,10 +96,10 @@ fun VerifyEmailScreen( textAlign = TextAlign.Center, ) - if (email.isNotBlank()) { + if (displayEmail.isNotBlank()) { Spacer(modifier = Modifier.height(4.dp)) Text( - text = email, + text = displayEmail, style = MaterialTheme.typography.bodyLarge, color = MaterialTheme.colorScheme.primary, textAlign = TextAlign.Center, diff --git a/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/viewmodel/ResetPasswordViewModel.kt b/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/viewmodel/ResetPasswordViewModel.kt index 650cbcf..dc351dc 100644 --- a/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/viewmodel/ResetPasswordViewModel.kt +++ b/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/viewmodel/ResetPasswordViewModel.kt @@ -1,7 +1,6 @@ package com.garfiec.librechat.feature.auth.viewmodel import androidx.compose.runtime.Immutable -import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.garfiec.librechat.core.common.result.Result @@ -21,7 +20,6 @@ data class ResetPasswordUiState( ) class ResetPasswordViewModel( - savedStateHandle: SavedStateHandle, private val authRepository: AuthRepository, initialUserId: String? = null, initialToken: String? = null, diff --git a/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/viewmodel/ServerUrlViewModel.kt b/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/viewmodel/ServerUrlViewModel.kt index 7f33bea..ecb2041 100644 --- a/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/viewmodel/ServerUrlViewModel.kt +++ b/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/viewmodel/ServerUrlViewModel.kt @@ -106,5 +106,4 @@ class ServerUrlViewModel( } } } - } diff --git a/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/viewmodel/TwoFactorViewModel.kt b/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/viewmodel/TwoFactorViewModel.kt index 2b429de..448104c 100644 --- a/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/viewmodel/TwoFactorViewModel.kt +++ b/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/viewmodel/TwoFactorViewModel.kt @@ -1,7 +1,6 @@ package com.garfiec.librechat.feature.auth.viewmodel import androidx.compose.runtime.Immutable -import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.garfiec.librechat.core.common.result.Result @@ -22,7 +21,6 @@ data class TwoFactorUiState( ) class TwoFactorViewModel( - savedStateHandle: SavedStateHandle, private val authRepository: AuthRepository, initialTempToken: String? = null, ) : ViewModel() { diff --git a/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/viewmodel/VerifyEmailViewModel.kt b/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/viewmodel/VerifyEmailViewModel.kt index 016f001..f7a0a50 100644 --- a/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/viewmodel/VerifyEmailViewModel.kt +++ b/feature/auth/src/commonMain/kotlin/com/garfiec/librechat/feature/auth/viewmodel/VerifyEmailViewModel.kt @@ -1,7 +1,6 @@ package com.garfiec.librechat.feature.auth.viewmodel import androidx.compose.runtime.Immutable -import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.garfiec.librechat.core.common.result.Result @@ -24,7 +23,6 @@ data class VerifyEmailUiState( ) class VerifyEmailViewModel( - savedStateHandle: SavedStateHandle, private val userRepository: UserRepository, initialEmail: String? = null, ) : ViewModel() { diff --git a/feature/auth/src/iosMain/kotlin/com/garfiec/librechat/feature/auth/oauth/IosOAuthLauncher.kt b/feature/auth/src/iosMain/kotlin/com/garfiec/librechat/feature/auth/oauth/IosOAuthLauncher.kt index 2421dd0..6a5db37 100644 --- a/feature/auth/src/iosMain/kotlin/com/garfiec/librechat/feature/auth/oauth/IosOAuthLauncher.kt +++ b/feature/auth/src/iosMain/kotlin/com/garfiec/librechat/feature/auth/oauth/IosOAuthLauncher.kt @@ -56,6 +56,7 @@ class IosOAuthLauncher : OAuthLauncher { override fun extractTokenFromCookies(serverUrl: String): String? { val url = NSURL.URLWithString(serverUrl) ?: return null val cookies = NSHTTPCookieStorage.sharedHTTPCookieStorage.cookiesForURL(url) ?: return null + @Suppress("UNCHECKED_CAST") val cookieList = cookies as List return cookieList.firstOrNull { it.name == "refreshToken" }?.value @@ -64,6 +65,7 @@ class IosOAuthLauncher : OAuthLauncher { override fun clearOAuthCookie(serverUrl: String) { val url = NSURL.URLWithString(serverUrl) ?: return val cookies = NSHTTPCookieStorage.sharedHTTPCookieStorage.cookiesForURL(url) ?: return + @Suppress("UNCHECKED_CAST") val cookieList = cookies as List cookieList.filter { it.name == "refreshToken" }.forEach { diff --git a/feature/chat/detekt-baseline.xml b/feature/chat/detekt-baseline.xml deleted file mode 100644 index 80459c3..0000000 --- a/feature/chat/detekt-baseline.xml +++ /dev/null @@ -1,118 +0,0 @@ - - - - - ComposableParamOrder:CommonChatInputCore.kt$CommonChatInputCore - DeprecatedKoinApi:ChatModule.kt$viewModel { params -> PromptEditorViewModel( promptRepository = get(), savedStateHandle = get(), initialGroupId = params.getOrNull(), ) } - FunctionNaming:String0.commonMain.kt$@InternalResourceApi internal fun _collectCommonMainString0Resources(map: MutableMap<String, StringResource>) - FunctionNaming:String1.commonMain.kt$@InternalResourceApi internal fun _collectCommonMainString1Resources(map: MutableMap<String, StringResource>) - FunctionNaming:String2.commonMain.kt$@InternalResourceApi internal fun _collectCommonMainString2Resources(map: MutableMap<String, StringResource>) - ImportOrdering:AgentHandoffCard.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.SmartToy import androidx.compose.material.icons.filled.SwapHoriz import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - ImportOrdering:ArtifactButton.kt$import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.Article import androidx.compose.material.icons.automirrored.filled.OpenInNew import androidx.compose.material.icons.filled.AccountTree import androidx.compose.material.icons.filled.Code import androidx.compose.material.icons.filled.Image import androidx.compose.material.icons.filled.Web import androidx.compose.material.icons.filled.Widgets import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - ImportOrdering:ArtifactVersionNav.kt$import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - ImportOrdering:AttachmentChipsRow.kt$import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.expandVertically import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.shrinkVertically import androidx.compose.foundation.background import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.InsertDriveFile import androidx.compose.material.icons.filled.AttachFile import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Code import androidx.compose.material.icons.filled.Extension import androidx.compose.material.icons.filled.FindInPage import androidx.compose.material.icons.filled.TravelExplore import androidx.compose.material3.AssistChip import androidx.compose.material3.AssistChipDefaults import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.IconButtonDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.ContentScale import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.semantics import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import coil3.compose.AsyncImage import com.garfiec.librechat.core.common.ToolConstants import com.garfiec.librechat.feature.chat.model.McpServerDisplayData import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - ImportOrdering:ChatInputToolbar.kt$import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Code import androidx.compose.material.icons.filled.FindInPage import androidx.compose.material.icons.filled.MoreHoriz import androidx.compose.material.icons.filled.Search import androidx.compose.material3.FilterChip import androidx.compose.material3.FilterChipDefaults import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.common.ToolConstants import com.garfiec.librechat.feature.chat.model.McpServerDisplayData import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - ImportOrdering:ChatToolsBottomSheet.kt$import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight import androidx.compose.material.icons.filled.AttachFile import androidx.compose.material.icons.filled.Code import androidx.compose.material.icons.filled.Extension import androidx.compose.material.icons.filled.FindInPage import androidx.compose.material.icons.filled.PhotoCamera import androidx.compose.material.icons.filled.PhotoLibrary import androidx.compose.material.icons.filled.Search import androidx.compose.material.icons.filled.SmartToy import androidx.compose.material.icons.filled.Tune import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.Checkbox import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.Switch import androidx.compose.material3.SwitchDefaults import androidx.compose.material3.Text import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.common.ToolConstants import com.garfiec.librechat.feature.chat.model.McpServerDisplayData import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - ImportOrdering:ChatViewModel.kt$import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.garfiec.librechat.core.common.EndpointConstants import com.garfiec.librechat.core.common.ToolConstants import com.garfiec.librechat.core.common.network.ConnectivityObserver import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.common.result.getOrNull import com.garfiec.librechat.core.data.datastore.LatexRenderer import com.garfiec.librechat.core.data.datastore.ServerDataStore import com.garfiec.librechat.core.data.datastore.SettingsDataStore import com.garfiec.librechat.core.data.repository.AgentRepository import com.garfiec.librechat.core.data.repository.ChatRepository import com.garfiec.librechat.core.data.repository.ConfigRepository import com.garfiec.librechat.core.data.repository.ConversationRepository import com.garfiec.librechat.core.data.repository.DraftRepository import com.garfiec.librechat.core.data.repository.McpRepository import com.garfiec.librechat.core.data.repository.MessageRepository import com.garfiec.librechat.core.data.repository.PresetRepository import com.garfiec.librechat.core.data.repository.PromptRepository import com.garfiec.librechat.core.data.repository.ShareRepository import com.garfiec.librechat.core.data.repository.UserRepository import com.garfiec.librechat.core.model.Attachment import com.garfiec.librechat.core.model.EModelEndpoint import com.garfiec.librechat.core.model.Message import com.garfiec.librechat.core.model.Preset import com.garfiec.librechat.core.model.StreamEvent import com.garfiec.librechat.core.model.request.EphemeralAgent import com.garfiec.librechat.core.ui.components.ModelParameters import com.garfiec.librechat.feature.chat.model.PresetDisplayData import com.garfiec.librechat.feature.chat.model.PromptMentionDisplayData import com.garfiec.librechat.feature.chat.components.AttachedFile import com.garfiec.librechat.feature.chat.util.NEW_CHAT_DRAFT_KEY import com.garfiec.librechat.feature.chat.util.buildActiveMessagePath import com.garfiec.librechat.feature.chat.viewmodel.delegate.ConversationActionsDelegate import com.garfiec.librechat.feature.chat.viewmodel.delegate.InConversationSearchDelegate import com.garfiec.librechat.feature.chat.viewmodel.delegate.ModelSelectionDelegate import com.garfiec.librechat.feature.chat.viewmodel.delegate.PlatformDelegateFactory import com.garfiec.librechat.feature.chat.viewmodel.delegate.PresetPromptDelegate import com.garfiec.librechat.feature.chat.viewmodel.delegate.toSerialName import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import co.touchlab.kermit.Logger import kotlin.time.Clock import kotlin.uuid.ExperimentalUuidApi import kotlin.uuid.Uuid - ImportOrdering:CitationChip.kt$import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.ClickableText import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.OpenInNew import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalUriHandler import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.withStyle import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.window.Popup import androidx.compose.ui.window.PopupProperties import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - ImportOrdering:CodeBlock.kt$import androidx.compose.animation.AnimatedContent import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.togetherWith import androidx.compose.foundation.background import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.filled.ContentCopy import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import com.garfiec.librechat.feature.chat.util.copyToClipboard import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.withStyle import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* import kotlinx.coroutines.delay - ImportOrdering:CodeExecutionCard.kt$import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.expandVertically import androidx.compose.animation.shrinkVertically import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Cancel import androidx.compose.material.icons.filled.CheckCircle import androidx.compose.material.icons.filled.Code import androidx.compose.material.icons.filled.ExpandLess import androidx.compose.material.icons.filled.ExpandMore import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.SuggestionChip import androidx.compose.material3.SuggestionChipDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.unit.dp import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - ImportOrdering:ComparisonDualPane.kt$import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.VerticalDivider import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - ImportOrdering:ComparisonTabBar.kt$import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Tab import androidx.compose.material3.TabRow import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* import kotlinx.coroutines.launch - ImportOrdering:ExpectResourceCollectors.kt$import kotlin.String import kotlin.collections.Map import org.jetbrains.compose.resources.DrawableResource import org.jetbrains.compose.resources.FontResource import org.jetbrains.compose.resources.PluralStringResource import org.jetbrains.compose.resources.StringArrayResource import org.jetbrains.compose.resources.StringResource - ImportOrdering:FeedbackCommentDialog.kt$import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.AlertDialog import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.unit.dp import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - ImportOrdering:ForkOptionsBottomSheet.kt$import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.CallSplit import androidx.compose.material.icons.filled.AccountTree import androidx.compose.material.icons.filled.LinearScale import androidx.compose.material3.Checkbox import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.Text import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.model.request.ForkOption import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - ImportOrdering:ImageGenCard.kt$import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.BrokenImage import androidx.compose.material.icons.filled.Image import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.ContentScale import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import coil3.compose.SubcomposeAsyncImage import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - ImportOrdering:InConvoSearchBar.kt$import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.KeyboardArrowDown import androidx.compose.material.icons.filled.KeyboardArrowUp import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalSoftwareKeyboardController import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.unit.dp import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.filter - ImportOrdering:InlineEditInput.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.Button import androidx.compose.material3.FilledTonalButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - ImportOrdering:LandingContent.kt$import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ChatBubbleOutline import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* import kotlin.time.Clock import kotlinx.datetime.DayOfWeek import kotlinx.datetime.TimeZone import kotlinx.datetime.toLocalDateTime - ImportOrdering:LogContentCard.kt$import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.expandVertically import androidx.compose.animation.shrinkVertically import androidx.compose.foundation.clickable import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ExpandLess import androidx.compose.material.icons.filled.ExpandMore import androidx.compose.material.icons.filled.Terminal import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.unit.dp import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - ImportOrdering:McpResourceCarousel.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Extension import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - ImportOrdering:McpServerSelector.kt$import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Hub import androidx.compose.material.icons.filled.KeyboardArrowDown import androidx.compose.material3.Checkbox import androidx.compose.material3.DropdownMenu import androidx.compose.material3.FilterChip import androidx.compose.material3.FilterChipDefaults import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.garfiec.librechat.feature.chat.model.McpServerDisplayData import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - ImportOrdering:MemoryArtifactCard.kt$import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.SuggestionChip import androidx.compose.material3.SuggestionChipDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - ImportOrdering:MessageContentAndActions.kt$import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.CallSplit import androidx.compose.material.icons.automirrored.filled.VolumeUp import androidx.compose.material.icons.filled.ContentCopy import androidx.compose.material.icons.filled.Edit import androidx.compose.material.icons.filled.Refresh import androidx.compose.material.icons.filled.Stop import androidx.compose.material.icons.filled.ThumbDown import androidx.compose.material.icons.filled.ThumbUp import androidx.compose.material.icons.outlined.ThumbDown import androidx.compose.material.icons.outlined.ThumbUp import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.layout.LayoutCoordinates import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.model.Message import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* import org.jetbrains.compose.resources.stringResource - ImportOrdering:MessageFiles.kt$import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.InsertDriveFile import androidx.compose.material.icons.filled.AttachFile import androidx.compose.material.icons.filled.BrokenImage import androidx.compose.material.icons.filled.Description import androidx.compose.material.icons.filled.PictureAsPdf import androidx.compose.material.icons.filled.TableChart import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.ContentScale import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import coil3.compose.SubcomposeAsyncImage import com.garfiec.librechat.core.model.FileReference import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - ImportOrdering:MessageList.kt$import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.foundation.gestures.animateScrollBy import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.KeyboardArrowDown import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.FloatingActionButtonDefaults import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.SmallFloatingActionButton import androidx.compose.material3.pulltorefresh.PullToRefreshBox import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberUpdatedState import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.input.pointer.PointerEventPass import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.layout.boundsInRoot import androidx.compose.ui.platform.LocalDensity import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.common.ChatLayoutConstants import com.garfiec.librechat.core.model.FeedbackRating import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* import com.garfiec.librechat.feature.chat.util.MessageNode import com.garfiec.librechat.feature.chat.viewmodel.ActiveToolCall import com.garfiec.librechat.feature.chat.viewmodel.SearchMatch import kotlinx.coroutines.delay import kotlinx.coroutines.launch - ImportOrdering:ModelSelectionDelegate.kt$import com.garfiec.librechat.core.common.EndpointConstants import com.garfiec.librechat.core.common.ToolConstants import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.data.datastore.SettingsDataStore import com.garfiec.librechat.core.data.repository.AgentRepository import com.garfiec.librechat.core.data.repository.ConfigRepository import com.garfiec.librechat.core.data.repository.McpRepository import com.garfiec.librechat.core.model.EModelEndpoint import com.garfiec.librechat.core.model.mcp.McpServer import com.garfiec.librechat.core.model.request.AddedConversation import com.garfiec.librechat.core.ui.components.ModelParameters import com.garfiec.librechat.feature.chat.model.McpServerDisplayData import com.garfiec.librechat.feature.chat.viewmodel.ChatScreenState import com.garfiec.librechat.feature.chat.viewmodel.ChatStateHandle import com.garfiec.librechat.feature.chat.viewmodel.ComparisonState import kotlinx.coroutines.launch import co.touchlab.kermit.Logger - ImportOrdering:ModelSelectorButton.kt$import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowDropDown import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - ImportOrdering:ModelSelectorSheet.kt$import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyItemScope import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.filled.Clear import androidx.compose.material.icons.filled.ExpandLess import androidx.compose.material.icons.filled.ExpandMore import androidx.compose.material.icons.outlined.AutoAwesome import androidx.compose.material.icons.outlined.Create import androidx.compose.material.icons.outlined.Public import androidx.compose.material.icons.outlined.SmartToy import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateMapOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.unit.dp import coil3.compose.AsyncImage import com.garfiec.librechat.core.common.EndpointConstants import com.garfiec.librechat.core.model.Agent import com.garfiec.librechat.core.model.EndpointConfig import com.garfiec.librechat.core.ui.components.endpointIconPainter import com.garfiec.librechat.core.ui.components.isMonochromeEndpointIcon import com.garfiec.librechat.feature.chat.util.FuzzyMatch import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* import org.jetbrains.compose.resources.stringResource - ImportOrdering:PlatformFileHandler.kt$import com.garfiec.librechat.feature.chat.components.AttachedFile import com.garfiec.librechat.core.model.FileReference import kotlinx.coroutines.Job import kotlinx.coroutines.flow.StateFlow - ImportOrdering:PresetPicker.kt$import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Edit import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.Text import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.garfiec.librechat.feature.chat.model.PresetDisplayData import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - ImportOrdering:PresetPromptDelegate.kt$import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.data.repository.PresetRepository import com.garfiec.librechat.core.data.repository.PromptRepository import com.garfiec.librechat.core.model.EModelEndpoint import com.garfiec.librechat.core.model.Preset import com.garfiec.librechat.core.model.PromptGroup import com.garfiec.librechat.feature.chat.model.PresetDisplayData import com.garfiec.librechat.feature.chat.model.PromptMentionDisplayData import com.garfiec.librechat.feature.chat.viewmodel.ChatStateHandle import kotlinx.coroutines.launch import co.touchlab.kermit.Logger - ImportOrdering:PromptDetailScreen.kt$import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Edit import androidx.compose.material.icons.filled.Share import androidx.compose.material.icons.outlined.Description import androidx.compose.material3.Button import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.ui.components.LibreChatTopBar import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* import com.garfiec.librechat.feature.chat.prompts.components.PromptPreviewPanel - ImportOrdering:PromptEditorScreen.kt$import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.History import androidx.compose.material3.Button import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.garfiec.librechat.core.ui.components.LoadingIndicator import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* import org.koin.compose.viewmodel.koinViewModel import org.koin.core.parameter.parametersOf - ImportOrdering:PromptFilterSheet.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.FilterChip import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.SheetState import androidx.compose.material3.Text import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - ImportOrdering:PromptPreviewPanel.kt$import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - ImportOrdering:PromptShareDialog.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ContentCopy import androidx.compose.material3.AlertDialog import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.RadioButton import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import com.garfiec.librechat.feature.chat.util.copyToClipboard import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - ImportOrdering:PromptVariablesSection.kt$import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - ImportOrdering:PromptVersionsSheet.kt$import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material3.Badge import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.model.Prompt import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - ImportOrdering:PromptsLibraryScreen.kt$import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.FilterList import androidx.compose.material.icons.filled.Share import androidx.compose.material.icons.outlined.Description import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.FilterChip import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.material3.pulltorefresh.PullToRefreshBox import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.garfiec.librechat.core.ui.components.EmptyState import com.garfiec.librechat.core.ui.components.ErrorBanner import com.garfiec.librechat.core.ui.components.LibreChatTopBar import com.garfiec.librechat.core.ui.components.LoadingIndicator import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* import com.garfiec.librechat.feature.chat.prompts.components.PromptFilterSheet import com.garfiec.librechat.feature.chat.prompts.components.PromptShareDialog import com.garfiec.librechat.feature.chat.prompts.components.PromptSortOrder import com.garfiec.librechat.feature.chat.prompts.components.VariableInputDialog import org.koin.compose.viewmodel.koinViewModel - ImportOrdering:PromptsViewModel.kt$import androidx.compose.runtime.Immutable import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.data.repository.PromptRepository import com.garfiec.librechat.core.model.PromptGroup import com.garfiec.librechat.core.model.request.AddPromptToGroupRequest import com.garfiec.librechat.core.model.request.CreatePromptData import com.garfiec.librechat.core.model.request.CreatePromptGroupData import com.garfiec.librechat.core.model.request.CreatePromptRequest import com.garfiec.librechat.core.model.request.UpdatePromptGroupRequest import com.garfiec.librechat.core.model.request.UpdatePromptTagRequest import com.garfiec.librechat.feature.chat.prompts.components.PromptSortOrder import com.garfiec.librechat.feature.chat.prompts.components.extractVariables import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import co.touchlab.kermit.Logger - ImportOrdering:Res.kt$import kotlin.ByteArray import kotlin.OptIn import kotlin.String import kotlin.Suppress import org.jetbrains.compose.resources.InternalResourceApi import org.jetbrains.compose.resources.getResourceUri import org.jetbrains.compose.resources.readResourceBytes - ImportOrdering:SavePresetDialog.kt$import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.material3.AlertDialog import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - ImportOrdering:SecondaryMessageList.kt$import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.common.ChatLayoutConstants import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* import com.garfiec.librechat.feature.chat.util.MessageNode import com.garfiec.librechat.feature.chat.viewmodel.ActiveToolCall - ImportOrdering:SharedContentParts.kt$import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.expandVertically import androidx.compose.animation.shrinkVertically import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.BrokenImage import androidx.compose.material.icons.filled.Build import androidx.compose.material.icons.filled.ExpandLess import androidx.compose.material.icons.filled.ExpandMore import androidx.compose.material.icons.filled.Psychology import androidx.compose.material.icons.filled.Videocam import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.LayoutCoordinates import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import coil3.compose.SubcomposeAsyncImage import com.garfiec.librechat.core.common.ToolConstants import com.garfiec.librechat.core.model.Attachment import com.garfiec.librechat.core.model.ContentType import com.garfiec.librechat.core.model.content.MessageContentPart import com.garfiec.librechat.feature.chat.components.artifact.Artifact import com.garfiec.librechat.feature.chat.components.artifact.ArtifactButton import com.garfiec.librechat.feature.chat.components.artifact.ArtifactPanel import com.garfiec.librechat.feature.chat.components.artifact.ArtifactSegment import com.garfiec.librechat.feature.chat.components.artifact.detectArtifacts import com.garfiec.librechat.feature.chat.components.artifact.groupArtifactVersions import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* import org.jetbrains.compose.resources.stringResource - ImportOrdering:SiblingNavigator.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.stateDescription import androidx.compose.ui.unit.dp import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - ImportOrdering:StreamingIndicator.kt$import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.RepeatMode import androidx.compose.animation.core.animateFloat import androidx.compose.animation.core.infiniteRepeatable import androidx.compose.animation.core.rememberInfiniteTransition import androidx.compose.animation.core.tween import androidx.compose.foundation.layout.padding import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - ImportOrdering:StreamingToolCallCard.kt$import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.expandVertically import androidx.compose.animation.shrinkVertically import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Build import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.filled.ExpandLess import androidx.compose.material.icons.filled.ExpandMore import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* import com.garfiec.librechat.feature.chat.viewmodel.ActiveToolCall - ImportOrdering:String0.commonMain.kt$import kotlin.OptIn import kotlin.String import kotlin.collections.MutableMap import org.jetbrains.compose.resources.InternalResourceApi import org.jetbrains.compose.resources.ResourceContentHash import org.jetbrains.compose.resources.ResourceItem import org.jetbrains.compose.resources.StringResource - ImportOrdering:String1.commonMain.kt$import kotlin.OptIn import kotlin.String import kotlin.collections.MutableMap import org.jetbrains.compose.resources.InternalResourceApi import org.jetbrains.compose.resources.ResourceContentHash import org.jetbrains.compose.resources.ResourceItem import org.jetbrains.compose.resources.StringResource - ImportOrdering:String2.commonMain.kt$import kotlin.OptIn import kotlin.String import kotlin.collections.MutableMap import org.jetbrains.compose.resources.InternalResourceApi import org.jetbrains.compose.resources.ResourceContentHash import org.jetbrains.compose.resources.ResourceItem import org.jetbrains.compose.resources.StringResource - ImportOrdering:ToolCallParsing.kt$import com.garfiec.librechat.core.model.content.AgentToolCall import com.garfiec.librechat.core.model.Attachment import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.contentOrNull import kotlinx.serialization.json.intOrNull import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonPrimitive import co.touchlab.kermit.Logger - ImportOrdering:ToolsDropdownMenu.kt$import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.filled.Code import androidx.compose.material.icons.filled.Image import androidx.compose.material.icons.filled.Search import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import org.jetbrains.compose.resources.stringResource import com.garfiec.librechat.core.common.ToolConstants import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - ImportOrdering:VariableInputDialog.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.AlertDialog import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateMapOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - ImportOrdering:WebSearchResultCard.kt$import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Language import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.platform.LocalUriHandler import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import coil3.compose.SubcomposeAsyncImage import librechat_mobile.feature.chat.generated.resources.Res import librechat_mobile.feature.chat.generated.resources.* - LambdaParameterInRestartableEffect:MessageList.kt$onSearchScrollHandled - LambdaParameterInRestartableEffect:PromptEditorScreen.kt$onBack - MaxLineLength:ChatViewModel.kt$ChatViewModel$Logger.d { "sendMessage: webSearch=$webSearchEnabled, endpoint=${_uiState.value.selectedEndpoint}, model=${_uiState.value.selectedModel}, files=${fileRefs.size}, ephemeralAgent=$ephemeralAgent" } - MaxLineLength:ModelSelectorSheet.kt$contentDescription = stringResource(if (isExpanded) Res.string.cd_collapse_section else Res.string.cd_expand_section, displayLabel) - MaxLineLength:Res.kt$Res$public suspend - MaxLineLength:SharedContentParts.kt$Icon(Icons.Default.BrokenImage, stringResource(Res.string.cd_failed_to_load_image), Modifier.size(32.dp), tint = MaterialTheme.colorScheme.onSurfaceVariant) - MaxLineLength:SharedContentParts.kt$Icon(Icons.Default.Build, stringResource(Res.string.cd_tool_call), Modifier.size(16.dp), tint = MaterialTheme.colorScheme.onSurfaceVariant) - MaxLineLength:SharedContentParts.kt$Icon(Icons.Default.Psychology, stringResource(Res.string.cd_thinking_indicator), Modifier.size(18.dp), tint = MaterialTheme.colorScheme.primary) - MaxLineLength:SharedContentParts.kt$Icon(Icons.Filled.Videocam, contentDescription = null, tint = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.size(18.dp)) - MaxLineLength:SharedContentParts.kt$MarkdownContent(segment.text, Modifier.fillMaxWidth(), fontSizeMultiplier, useKatex, searchQuery, searchFocusedOccurrence, onFocusedOccurrencePositioned) - MaxLineLength:SharedContentParts.kt$MarkdownContent(thinkingText, fontSizeMultiplier = fontSizeMultiplier, useKatex = useKatex, searchQuery = searchQuery, searchFocusedOccurrence = searchFocusedOccurrence, onFocusedOccurrencePositioned = onFocusedOccurrencePositioned) - MaxLineLength:SharedContentParts.kt$Text(stringResource(Res.string.label_input), style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant) - MaxLineLength:SharedContentParts.kt$Text(stringResource(Res.string.label_output), style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant) - MaxLineLength:SharedContentParts.kt$Text(stringResource(Res.string.label_thinking), style = MaterialTheme.typography.titleSmall, color = MaterialTheme.colorScheme.primary, modifier = Modifier.weight(1f)) - MaxLineLength:SharedContentParts.kt$Text(stringResource(Res.string.video_not_supported), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant) - MaxLineLength:SharedContentParts.kt$Text(toolName, style = MaterialTheme.typography.titleSmall, color = MaterialTheme.colorScheme.onSurface, modifier = Modifier.weight(1f)) - ModifierMissing:CommonChatInputCore.kt$ChatInputPlaceholder - ModifierWithoutDefault:SharedContentParts.kt$modifier - NoConsecutiveBlankLines:MarkdownParsing.kt$ - PackageName:ExpectResourceCollectors.kt$package librechat_mobile.feature.chat.generated.resources - PackageName:Res.kt$package librechat_mobile.feature.chat.generated.resources - PackageName:String0.commonMain.kt$package librechat_mobile.feature.chat.generated.resources - PackageName:String1.commonMain.kt$package librechat_mobile.feature.chat.generated.resources - PackageName:String2.commonMain.kt$package librechat_mobile.feature.chat.generated.resources - PackageNaming:ExpectResourceCollectors.kt$package librechat_mobile.feature.chat.generated.resources - PackageNaming:Res.kt$package librechat_mobile.feature.chat.generated.resources - PackageNaming:String0.commonMain.kt$package librechat_mobile.feature.chat.generated.resources - PackageNaming:String1.commonMain.kt$package librechat_mobile.feature.chat.generated.resources - PackageNaming:String2.commonMain.kt$package librechat_mobile.feature.chat.generated.resources - ParameterNaming:ComparisonTabBar.kt$onTabChanged - ParameterNaming:InConvoSearchBar.kt$onQueryChanged - ParameterNaming:InlineEditInput.kt$onTextChanged - ParameterNaming:MessageContentAndActions.kt$onEditTextChanged - ParameterNaming:MessageContentAndActions.kt$onFocusedOccurrencePositioned - ParameterNaming:MessageList.kt$onEditTextChanged - ParameterNaming:MessageList.kt$onSearchScrollHandled - ParameterNaming:ModelSelectorSheet.kt$onModelSelected - ParameterNaming:PlatformChatComponents.kt$onEditTextChanged - ParameterNaming:PlatformChatComponents.kt$onFocusedOccurrencePositioned - ParameterNaming:PlatformScreens.kt$onConversationStarted - ParameterNaming:PresetPicker.kt$onPresetSelected - ParameterNaming:PromptFilterSheet.kt$onCategorySelected - ParameterNaming:PromptFilterSheet.kt$onSortOrderChanged - ParameterNaming:PromptShareDialog.kt$onShareToggled - ParameterNaming:PromptVariablesSection.kt$onVariableChanged - ParameterNaming:SharedContentParts.kt$onFocusedOccurrencePositioned - ParameterNaming:SlashCommandMenu.kt$onCommandSelected - SpacingBetweenDeclarationsWithAnnotations:ChatNavigation.kt$Chat : ChatRoute - SpacingBetweenDeclarationsWithAnnotations:ChatNavigation.kt$PromptEditor : ChatRoute - SpacingBetweenDeclarationsWithAnnotations:ChatNavigation.kt$PromptsLibrary : ChatRoute - UnusedPrivateProperty:ChatViewModel.kt$ChatViewModel$savedStateHandle: SavedStateHandle - UnusedPrivateProperty:PromptEditorViewModel.kt$PromptEditorViewModel$savedStateHandle: SavedStateHandle - - diff --git a/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/AudioContentPlayer.kt b/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/AudioContentPlayer.kt index dbd7877..731afff 100644 --- a/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/AudioContentPlayer.kt +++ b/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/AudioContentPlayer.kt @@ -32,12 +32,12 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* -import kotlinx.coroutines.delay import co.touchlab.kermit.Logger +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import kotlinx.coroutines.delay +import org.jetbrains.compose.resources.stringResource import java.io.File import java.util.Locale diff --git a/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/ChatInput.kt b/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/ChatInput.kt index 155531c..dba7834 100644 --- a/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/ChatInput.kt +++ b/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/ChatInput.kt @@ -40,7 +40,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.platform.LocalContext -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.role @@ -53,8 +52,9 @@ import androidx.core.content.ContextCompat import androidx.core.content.FileProvider import com.garfiec.librechat.feature.chat.model.McpServerDisplayData import com.garfiec.librechat.feature.chat.model.PromptMentionDisplayData -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource import java.io.File @Composable @@ -371,7 +371,7 @@ fun ChatInput( // Slash command dropdown SlashCommandMenu( filteredCommands = filteredSlashCommands, - onCommandSelected = onSlashCommandSelected, + onCommandSelect = onSlashCommandSelected, ) } }, diff --git a/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/ContentPartRenderer.kt b/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/ContentPartRenderer.kt index 3616c56..4b9fa16 100644 --- a/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/ContentPartRenderer.kt +++ b/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/ContentPartRenderer.kt @@ -17,7 +17,7 @@ actual fun ContentPartRenderer( showImageDescriptions: Boolean, searchQuery: String?, searchFocusedOccurrence: Int, - onFocusedOccurrencePositioned: ((LayoutCoordinates) -> Unit)?, + onFocusedOccurrencePosition: ((LayoutCoordinates) -> Unit)?, ) { ContentPartDispatcher( part = part, @@ -29,6 +29,6 @@ actual fun ContentPartRenderer( showImageDescriptions = showImageDescriptions, searchQuery = searchQuery, searchFocusedOccurrence = searchFocusedOccurrence, - onFocusedOccurrencePositioned = onFocusedOccurrencePositioned, + onFocusedOccurrencePosition = onFocusedOccurrencePosition, ) } diff --git a/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/FullscreenImageViewer.kt b/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/FullscreenImageViewer.kt index 6650d3e..b9f13dd 100644 --- a/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/FullscreenImageViewer.kt +++ b/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/FullscreenImageViewer.kt @@ -43,21 +43,21 @@ import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import androidx.core.content.ContextCompat import androidx.core.content.FileProvider -import coil3.compose.AsyncImage import coil3.SingletonImageLoader +import coil3.compose.AsyncImage import coil3.request.ImageRequest import coil3.toBitmap -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import org.jetbrains.compose.resources.stringResource import java.io.File @Composable diff --git a/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/MarkdownContent.kt b/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/MarkdownContent.kt index 6c2a064..20f7841 100644 --- a/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/MarkdownContent.kt +++ b/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/MarkdownContent.kt @@ -44,7 +44,6 @@ import androidx.compose.ui.layout.LayoutCoordinates import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalUriHandler -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.TextStyle @@ -60,11 +59,12 @@ import androidx.compose.ui.unit.isSpecified import androidx.compose.ui.unit.sp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res import com.mikepenz.markdown.m3.Markdown import com.mikepenz.markdown.m3.markdownColor import com.mikepenz.markdown.m3.markdownTypography +import org.jetbrains.compose.resources.stringResource /** * Markdown content rendering with full CommonMark support. Uses a hybrid approach: @@ -82,7 +82,7 @@ import com.mikepenz.markdown.m3.markdownTypography * @param searchFocusedOccurrence When >= 0, the occurrence at this index (counted * across all text segments in this message, 0-based) is highlighted in orange * instead of yellow to indicate the currently focused search result. - * @param onFocusedOccurrencePositioned Callback invoked with the [LayoutCoordinates] + * @param onFocusedOccurrencePosition Callback invoked with the [LayoutCoordinates] * of the text segment containing the focused search occurrence, after it has been * laid out. Used by the parent to fine-tune scroll position within a long message. */ @@ -94,7 +94,7 @@ actual fun MarkdownContent( useKatex: Boolean, searchQuery: String?, searchFocusedOccurrence: Int, - onFocusedOccurrencePositioned: ((LayoutCoordinates) -> Unit)?, + onFocusedOccurrencePosition: ((LayoutCoordinates) -> Unit)?, ) { val segments = remember(text) { parseMarkdownSegments(text) } val isSearchActive = !searchQuery.isNullOrBlank() @@ -155,7 +155,7 @@ actual fun MarkdownContent( searchQuery = searchQuery, focusedOccurrence = focusedInSegment, fontSizeMultiplier = fontSizeMultiplier, - onPositioned = if (hasFocus) onFocusedOccurrencePositioned else null, + onPositioned = if (hasFocus) onFocusedOccurrencePosition else null, ) occurrenceOffset += segmentOccurrences } else { @@ -201,7 +201,7 @@ actual fun MarkdownContent( searchQuery = searchQuery, focusedOccurrence = focusedInSegment, fontSizeMultiplier = fontSizeMultiplier, - onPositioned = if (hasFocus) onFocusedOccurrencePositioned else null, + onPositioned = if (hasFocus) onFocusedOccurrencePosition else null, ) occurrenceOffset += segmentOccurrences } else { @@ -326,7 +326,6 @@ private fun MarkdownTextSegment( } } - /** * Wraps a [MarkdownTable] in a [Box] with a fullscreen expand button overlaid on * the top-right corner. Tapping the button opens a [FullscreenTableDialog]. @@ -590,4 +589,3 @@ private fun TableCell( ) } } - diff --git a/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/MermaidDiagram.kt b/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/MermaidDiagram.kt index 7c2cc43..374ec52 100644 --- a/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/MermaidDiagram.kt +++ b/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/MermaidDiagram.kt @@ -42,14 +42,14 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.toArgb -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* import co.touchlab.kermit.Logger +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource @Composable actual fun MermaidDiagram( diff --git a/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/MessageBubble.kt b/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/MessageBubble.kt index d146494..d5c7358 100644 --- a/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/MessageBubble.kt +++ b/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/MessageBubble.kt @@ -23,7 +23,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.compositeOver import androidx.compose.ui.layout.LayoutCoordinates -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.common.ChatLayoutConstants @@ -31,9 +30,10 @@ import com.garfiec.librechat.core.model.Message import com.garfiec.librechat.core.ui.components.AvatarImage import com.garfiec.librechat.core.ui.components.endpointIconPainter import com.garfiec.librechat.core.ui.components.isMonochromeEndpointIcon -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res import kotlinx.coroutines.delay +import org.jetbrains.compose.resources.stringResource private const val ACTION_AUTO_HIDE_MILLIS = 30_000L @@ -57,7 +57,7 @@ actual fun MessageBubble( currentFeedback: String?, isEditing: Boolean, editText: String, - onEditTextChanged: ((String) -> Unit)?, + onEditTextChange: ((String) -> Unit)?, onEditSaveAndSubmit: (() -> Unit)?, onEditSaveOnly: (() -> Unit)?, onEditCancel: (() -> Unit)?, @@ -70,7 +70,7 @@ actual fun MessageBubble( isSearchMatch: Boolean, isCurrentSearchMatch: Boolean, searchFocusedOccurrence: Int, - onFocusedOccurrencePositioned: ((LayoutCoordinates) -> Unit)?, + onFocusedOccurrencePosition: ((LayoutCoordinates) -> Unit)?, useKatex: Boolean, chatLayoutStyle: String, showAvatars: Boolean, @@ -97,7 +97,7 @@ actual fun MessageBubble( currentFeedback = currentFeedback, isEditing = isEditing, editText = editText, - onEditTextChanged = onEditTextChanged, + onEditTextChange = onEditTextChange, onEditSaveAndSubmit = onEditSaveAndSubmit, onEditSaveOnly = onEditSaveOnly, onEditCancel = onEditCancel, @@ -110,7 +110,7 @@ actual fun MessageBubble( isSearchMatch = isSearchMatch, isCurrentSearchMatch = isCurrentSearchMatch, searchFocusedOccurrence = searchFocusedOccurrence, - onFocusedOccurrencePositioned = onFocusedOccurrencePositioned, + onFocusedOccurrencePosition = onFocusedOccurrencePosition, showAvatars = showAvatars, showBubbles = showBubbles, ) @@ -135,7 +135,7 @@ actual fun MessageBubble( currentFeedback = currentFeedback, isEditing = isEditing, editText = editText, - onEditTextChanged = onEditTextChanged, + onEditTextChange = onEditTextChange, onEditSaveAndSubmit = onEditSaveAndSubmit, onEditSaveOnly = onEditSaveOnly, onEditCancel = onEditCancel, @@ -148,7 +148,7 @@ actual fun MessageBubble( isSearchMatch = isSearchMatch, isCurrentSearchMatch = isCurrentSearchMatch, searchFocusedOccurrence = searchFocusedOccurrence, - onFocusedOccurrencePositioned = onFocusedOccurrencePositioned, + onFocusedOccurrencePosition = onFocusedOccurrencePosition, showAvatars = showAvatars, showBubbles = showBubbles, ) @@ -179,7 +179,7 @@ private fun ThreadMessageBubble( currentFeedback: String?, isEditing: Boolean, editText: String, - onEditTextChanged: ((String) -> Unit)?, + onEditTextChange: ((String) -> Unit)?, onEditSaveAndSubmit: (() -> Unit)?, onEditSaveOnly: (() -> Unit)?, onEditCancel: (() -> Unit)?, @@ -192,7 +192,7 @@ private fun ThreadMessageBubble( isSearchMatch: Boolean, isCurrentSearchMatch: Boolean, searchFocusedOccurrence: Int, - onFocusedOccurrencePositioned: ((LayoutCoordinates) -> Unit)?, + onFocusedOccurrencePosition: ((LayoutCoordinates) -> Unit)?, showAvatars: Boolean, showBubbles: Boolean, ) { @@ -326,7 +326,7 @@ private fun ThreadMessageBubble( isUser = isUser, isEditing = isEditing, editText = editText, - onEditTextChanged = onEditTextChanged, + onEditTextChange = onEditTextChange, onEditSaveAndSubmit = onEditSaveAndSubmit, onEditSaveOnly = onEditSaveOnly, onEditCancel = onEditCancel, @@ -338,7 +338,7 @@ private fun ThreadMessageBubble( isSearchMatch = isSearchMatch, isCurrentSearchMatch = isCurrentSearchMatch, searchFocusedOccurrence = searchFocusedOccurrence, - onFocusedOccurrencePositioned = onFocusedOccurrencePositioned, + onFocusedOccurrencePosition = onFocusedOccurrencePosition, showActions = showActions, siblingIndex = siblingIndex, siblingCount = siblingCount, @@ -382,7 +382,7 @@ private fun TwoSidedMessageBubble( currentFeedback: String?, isEditing: Boolean, editText: String, - onEditTextChanged: ((String) -> Unit)?, + onEditTextChange: ((String) -> Unit)?, onEditSaveAndSubmit: (() -> Unit)?, onEditSaveOnly: (() -> Unit)?, onEditCancel: (() -> Unit)?, @@ -395,7 +395,7 @@ private fun TwoSidedMessageBubble( isSearchMatch: Boolean, isCurrentSearchMatch: Boolean, searchFocusedOccurrence: Int, - onFocusedOccurrencePositioned: ((LayoutCoordinates) -> Unit)?, + onFocusedOccurrencePosition: ((LayoutCoordinates) -> Unit)?, showAvatars: Boolean, showBubbles: Boolean, ) { @@ -538,7 +538,7 @@ private fun TwoSidedMessageBubble( isUser = isUser, isEditing = isEditing, editText = editText, - onEditTextChanged = onEditTextChanged, + onEditTextChange = onEditTextChange, onEditSaveAndSubmit = onEditSaveAndSubmit, onEditSaveOnly = onEditSaveOnly, onEditCancel = onEditCancel, @@ -550,7 +550,7 @@ private fun TwoSidedMessageBubble( isSearchMatch = isSearchMatch, isCurrentSearchMatch = isCurrentSearchMatch, searchFocusedOccurrence = searchFocusedOccurrence, - onFocusedOccurrencePositioned = onFocusedOccurrencePositioned, + onFocusedOccurrencePosition = onFocusedOccurrencePosition, showActions = showActions, siblingIndex = siblingIndex, siblingCount = siblingCount, @@ -580,4 +580,3 @@ private fun TwoSidedMessageBubble( } } } - diff --git a/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/VideoContent.kt b/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/VideoContent.kt index 303f8e7..3066596 100644 --- a/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/VideoContent.kt +++ b/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/VideoContent.kt @@ -23,14 +23,14 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.platform.LocalContext -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import androidx.media3.common.MediaItem import androidx.media3.exoplayer.ExoPlayer import androidx.media3.ui.PlayerView -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource @Composable actual fun VideoContent( diff --git a/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/VideoContentPlayer.kt b/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/VideoContentPlayer.kt index 9afcbaa..7a75a81 100644 --- a/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/VideoContentPlayer.kt +++ b/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/VideoContentPlayer.kt @@ -24,15 +24,15 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import androidx.media3.common.MediaItem import androidx.media3.common.Player import androidx.media3.exoplayer.ExoPlayer import androidx.media3.ui.PlayerView -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource /** Plays video via ExoPlayer (media3) in a 16:9 card. Releases player on dispose via DisposableEffect. */ @Composable diff --git a/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/artifact/ArtifactPanel.kt b/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/artifact/ArtifactPanel.kt index 4a199e9..79bf148 100644 --- a/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/artifact/ArtifactPanel.kt +++ b/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/components/artifact/ArtifactPanel.kt @@ -58,16 +58,16 @@ import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollSource import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* -import com.garfiec.librechat.feature.chat.components.CodeBlock -import kotlinx.coroutines.launch import co.touchlab.kermit.Logger +import com.garfiec.librechat.feature.chat.components.CodeBlock +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import kotlinx.coroutines.launch +import org.jetbrains.compose.resources.stringResource @OptIn(ExperimentalMaterial3Api::class) @Composable diff --git a/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/di/ChatPlatformModule.android.kt b/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/di/ChatPlatformModule.android.kt index c93240d..e4d12b9 100644 --- a/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/di/ChatPlatformModule.android.kt +++ b/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/di/ChatPlatformModule.android.kt @@ -20,7 +20,6 @@ actual val chatPlatformModule: Module = module { viewModel { params -> ChatViewModel( - savedStateHandle = get(), initialConversationId = params.getOrNull(), agentRepository = get(), chatRepository = get(), diff --git a/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/screen/ChatScreen.kt b/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/screen/ChatScreen.kt index 412ae49..1cfff72 100644 --- a/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/screen/ChatScreen.kt +++ b/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/screen/ChatScreen.kt @@ -64,7 +64,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalSoftwareKeyboardController -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.core.content.ContextCompat @@ -78,8 +77,6 @@ import com.garfiec.librechat.core.model.ContentType import com.garfiec.librechat.core.model.content.MessageContentPart import com.garfiec.librechat.core.ui.components.LoadingIndicator import com.garfiec.librechat.core.ui.components.ModelParameterSheet -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* import com.garfiec.librechat.feature.chat.components.ChatInput import com.garfiec.librechat.feature.chat.components.ComparisonDualPane import com.garfiec.librechat.feature.chat.components.ComparisonTabBar @@ -93,10 +90,13 @@ import com.garfiec.librechat.feature.chat.components.PresetPicker import com.garfiec.librechat.feature.chat.components.SavePresetDialog import com.garfiec.librechat.feature.chat.components.SecondaryMessageList import com.garfiec.librechat.feature.chat.components.TempChatToggle +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res import com.garfiec.librechat.feature.chat.util.MessageNode import com.garfiec.librechat.feature.chat.viewmodel.ChatScreenState import com.garfiec.librechat.feature.chat.viewmodel.ChatViewModel import kotlinx.coroutines.launch +import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel import org.koin.core.parameter.parametersOf @@ -105,7 +105,7 @@ import org.koin.core.parameter.parametersOf actual fun ChatScreen( modifier: Modifier, conversationId: String?, - onConversationStarted: ((String) -> Unit)?, + onConversationStart: ((String) -> Unit)?, onNavigateToConversation: ((String) -> Unit)?, onOpenDrawer: (() -> Unit)?, onNavigateToPromptsLibrary: (() -> Unit)?, @@ -241,8 +241,8 @@ actual fun ChatScreen( // onPendingNavigationHandled() resets this ViewModel to a fresh landing state. LaunchedEffect(uiState.pendingNavigationConversationId) { val pendingId = uiState.pendingNavigationConversationId - if (pendingId != null && onConversationStarted != null) { - onConversationStarted(pendingId) + if (pendingId != null && onConversationStart != null) { + onConversationStart(pendingId) viewModel.onPendingNavigationHandled() } } @@ -270,8 +270,8 @@ actual fun ChatScreen( viewModel.onForkedConversationHandled() if (onNavigateToConversation != null) { onNavigateToConversation(forkId) - } else if (onConversationStarted != null) { - onConversationStarted(forkId) + } else if (onConversationStart != null) { + onConversationStart(forkId) } } } @@ -283,8 +283,8 @@ actual fun ChatScreen( viewModel.onDuplicatedConversationHandled() if (onNavigateToConversation != null) { onNavigateToConversation(dupId) - } else if (onConversationStarted != null) { - onConversationStarted(dupId) + } else if (onConversationStart != null) { + onConversationStart(dupId) } } } @@ -338,7 +338,7 @@ actual fun ChatScreen( if (uiState.isSearchOpen) { InConvoSearchBar( query = uiState.searchQuery, - onQueryChanged = viewModel::onSearchQueryChanged, + onQueryChange = viewModel::onSearchQueryChanged, currentMatchIndex = uiState.currentSearchMatchIndex, totalMatches = uiState.searchMatchIndices.size, onPreviousMatch = viewModel::previousSearchMatch, @@ -453,7 +453,7 @@ actual fun ChatScreen( currentlyReadingMessageId = uiState.currentlyReadingMessageId, editingMessageId = uiState.editingMessageId, editingText = uiState.editingText, - onEditTextChanged = viewModel::onEditTextChanged, + onEditTextChange = viewModel::onEditTextChanged, onEditSaveAndSubmit = viewModel::submitEdit, onEditSaveOnly = viewModel::saveEditOnly, onEditCancel = viewModel::cancelEditing, @@ -474,7 +474,7 @@ actual fun ChatScreen( searchMatchIndices = uiState.searchMatchIndices, currentSearchMatchIndex = uiState.currentSearchMatchIndex, searchScrollToIndex = uiState.searchScrollToIndex, - onSearchScrollHandled = viewModel::onSearchScrollHandled, + onSearchScrollHandle = viewModel::onSearchScrollHandled, modifier = Modifier.fillMaxSize(), ) } @@ -545,7 +545,7 @@ actual fun ChatScreen( secondaryContent = secondaryMessageList, onContinueWithPrimary = onContinuePrimary, onContinueWithSecondary = onContinueSecondary, - onTabChanged = { activeComparisonTab = it }, + onTabChange = { activeComparisonTab = it }, modifier = Modifier.weight(1f), ) } @@ -573,7 +573,7 @@ actual fun ChatScreen( currentlyReadingMessageId = uiState.currentlyReadingMessageId, editingMessageId = uiState.editingMessageId, editingText = uiState.editingText, - onEditTextChanged = viewModel::onEditTextChanged, + onEditTextChange = viewModel::onEditTextChanged, onEditSaveAndSubmit = viewModel::submitEdit, onEditSaveOnly = viewModel::saveEditOnly, onEditCancel = viewModel::cancelEditing, @@ -601,7 +601,7 @@ actual fun ChatScreen( searchMatchIndices = uiState.searchMatchIndices, currentSearchMatchIndex = uiState.currentSearchMatchIndex, searchScrollToIndex = uiState.searchScrollToIndex, - onSearchScrollHandled = viewModel::onSearchScrollHandled, + onSearchScrollHandle = viewModel::onSearchScrollHandled, modifier = Modifier.weight(1f), ) } @@ -663,7 +663,7 @@ actual fun ChatScreen( if (showPresetPicker) { PresetPicker( presets = uiState.presets, - onPresetSelected = { preset -> + onPresetSelect = { preset -> viewModel.loadPreset(preset) showPresetPicker = false }, @@ -706,7 +706,7 @@ actual fun ChatScreen( if (uiState.showModelParameters) { ModelParameterSheet( parameters = uiState.modelParameters, - onParametersChanged = viewModel::updateModelParameters, + onParametersChange = viewModel::updateModelParameters, onDismiss = viewModel::hideModelParameters, selectedEndpoint = uiState.selectedEndpoint, ) @@ -735,7 +735,7 @@ actual fun ChatScreen( agents = uiState.agents, selectedEndpoint = uiState.selectedEndpoint, selectedModel = uiState.selectedModel, - onModelSelected = { endpoint, model -> + onModelSelect = { endpoint, model -> viewModel.onModelSelected(endpoint, model) showModelSheet = false }, @@ -752,7 +752,7 @@ actual fun ChatScreen( agents = uiState.agents, selectedEndpoint = uiState.comparisonState.secondaryEndpoint, selectedModel = uiState.comparisonState.secondaryModel, - onModelSelected = { endpoint, model -> + onModelSelect = { endpoint, model -> viewModel.setSecondaryModel(endpoint, model) showSecondaryModelSheet = false }, diff --git a/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/screen/NewChatScreen.kt b/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/screen/NewChatScreen.kt index 279ee9f..129a4b9 100644 --- a/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/screen/NewChatScreen.kt +++ b/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/screen/NewChatScreen.kt @@ -5,20 +5,20 @@ import androidx.compose.ui.Modifier /** * Thin wrapper that shows ChatScreen with no conversationId. - * When a conversation starts via streaming, the [onConversationStarted] + * When a conversation starts via streaming, the [onConversationStart] * callback is invoked with the new conversationId, allowing navigation * to the full chat route. */ @Composable actual fun NewChatScreen( - onConversationStarted: (String) -> Unit, + onConversationStart: (String) -> Unit, modifier: Modifier, onOpenDrawer: (() -> Unit)?, onNavigateToPromptsLibrary: (() -> Unit)?, ) { ChatScreen( modifier = modifier, - onConversationStarted = onConversationStarted, + onConversationStart = onConversationStart, onOpenDrawer = onOpenDrawer, onNavigateToPromptsLibrary = onNavigateToPromptsLibrary, ) diff --git a/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/delegate/AndroidFileHandler.kt b/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/delegate/AndroidFileHandler.kt index 752b242..71cf993 100644 --- a/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/delegate/AndroidFileHandler.kt +++ b/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/delegate/AndroidFileHandler.kt @@ -1,8 +1,8 @@ package com.garfiec.librechat.feature.chat.viewmodel.delegate import android.net.Uri -import com.garfiec.librechat.feature.chat.components.AttachedFile import com.garfiec.librechat.core.model.FileReference +import com.garfiec.librechat.feature.chat.components.AttachedFile import kotlinx.coroutines.Job import kotlinx.coroutines.flow.StateFlow diff --git a/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/delegate/FileAttachmentDelegate.kt b/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/delegate/FileAttachmentDelegate.kt index 5871d5b..67ecf2b 100644 --- a/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/delegate/FileAttachmentDelegate.kt +++ b/feature/chat/src/androidMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/delegate/FileAttachmentDelegate.kt @@ -3,6 +3,7 @@ package com.garfiec.librechat.feature.chat.viewmodel.delegate import android.content.Context import android.graphics.BitmapFactory import android.net.Uri +import co.touchlab.kermit.Logger import com.garfiec.librechat.core.common.EndpointConstants import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.data.repository.FileRepository @@ -21,7 +22,6 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import co.touchlab.kermit.Logger import java.util.UUID class FileAttachmentDelegate( @@ -143,7 +143,7 @@ class FileAttachmentDelegate( imageWidth = options.outWidth imageHeight = options.outHeight } - Logger.d { "uploadFile: image dimensions ${imageWidth}x${imageHeight} for $uploadFilename" } + Logger.d { "uploadFile: image dimensions ${imageWidth}x$imageHeight for $uploadFilename" } } catch (e: Exception) { Logger.w(e) { "uploadFile: could not read image dimensions for $uploadFilename" } } diff --git a/feature/chat/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/chat/di/ChatModuleVerificationTest.kt b/feature/chat/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/chat/di/ChatModuleVerificationTest.kt index 804b381..9bb5d54 100644 --- a/feature/chat/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/chat/di/ChatModuleVerificationTest.kt +++ b/feature/chat/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/chat/di/ChatModuleVerificationTest.kt @@ -2,7 +2,6 @@ package com.garfiec.librechat.feature.chat.di import android.app.Application import android.content.Context -import androidx.lifecycle.SavedStateHandle import com.garfiec.librechat.core.common.network.ConnectivityObserver import com.garfiec.librechat.core.data.datastore.ServerDataStore import com.garfiec.librechat.core.data.datastore.SettingsDataStore @@ -29,7 +28,6 @@ class ChatModuleVerificationTest { extraTypes = listOf( Context::class, Application::class, - SavedStateHandle::class, AgentRepository::class, ChatRepository::class, MessageRepository::class, diff --git a/feature/chat/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/chat/util/MessageTreeTest.kt b/feature/chat/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/chat/util/MessageTreeTest.kt index 80adfc5..4c6aff3 100644 --- a/feature/chat/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/chat/util/MessageTreeTest.kt +++ b/feature/chat/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/chat/util/MessageTreeTest.kt @@ -1,7 +1,7 @@ package com.garfiec.librechat.feature.chat.util -import com.google.common.truth.Truth.assertThat import com.garfiec.librechat.core.model.Message +import com.google.common.truth.Truth.assertThat import org.junit.Test class MessageTreeTest { diff --git a/feature/chat/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/chat/viewmodel/DetectMimeTypeTest.kt b/feature/chat/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/chat/viewmodel/DetectMimeTypeTest.kt index c131d2a..bf89cc7 100644 --- a/feature/chat/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/chat/viewmodel/DetectMimeTypeTest.kt +++ b/feature/chat/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/chat/viewmodel/DetectMimeTypeTest.kt @@ -1,7 +1,7 @@ package com.garfiec.librechat.feature.chat.viewmodel -import com.google.common.truth.Truth.assertThat import com.garfiec.librechat.feature.chat.util.detectMimeTypeFromBytes +import com.google.common.truth.Truth.assertThat import org.junit.Test class DetectMimeTypeTest { diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/AgentHandoffCard.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/AgentHandoffCard.kt index 93f64cf..8681fea 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/AgentHandoffCard.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/AgentHandoffCard.kt @@ -21,14 +21,14 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource /** * Data class representing an agent handoff event. diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/AttachmentChipsRow.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/AttachmentChipsRow.kt index 0167dca..eb4e996 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/AttachmentChipsRow.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/AttachmentChipsRow.kt @@ -42,20 +42,20 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.ContentScale -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.semantics -import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import coil3.compose.AsyncImage import com.garfiec.librechat.core.common.ToolConstants import com.garfiec.librechat.feature.chat.model.McpServerDisplayData -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource /** * Floating row of Material 3 chips above the chat input field. diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ChatInputToolbar.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ChatInputToolbar.kt index 57ea795..c373142 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ChatInputToolbar.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ChatInputToolbar.kt @@ -30,14 +30,14 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.common.ToolConstants import com.garfiec.librechat.feature.chat.model.McpServerDisplayData -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource data class ToolToggle( val id: String, diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ChatToolsBottomSheet.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ChatToolsBottomSheet.kt index 195cb22..988d238 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ChatToolsBottomSheet.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ChatToolsBottomSheet.kt @@ -46,7 +46,6 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.role @@ -55,8 +54,9 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.common.ToolConstants import com.garfiec.librechat.feature.chat.model.McpServerDisplayData -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource @OptIn(ExperimentalMaterial3Api::class) @Composable diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/CitationChip.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/CitationChip.kt index baddf88..28fc145 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/CitationChip.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/CitationChip.kt @@ -23,7 +23,6 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalUriHandler -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.buildAnnotatedString @@ -35,8 +34,9 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.window.Popup import androidx.compose.ui.window.PopupProperties -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource /** * Parsed citation found in message text. diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/CodeBlock.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/CodeBlock.kt index 577b217..de48a75 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/CodeBlock.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/CodeBlock.kt @@ -32,8 +32,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color -import com.garfiec.librechat.feature.chat.util.copyToClipboard -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.AnnotatedString @@ -44,9 +42,11 @@ import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.withStyle import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import com.garfiec.librechat.feature.chat.util.copyToClipboard import kotlinx.coroutines.delay +import org.jetbrains.compose.resources.stringResource @Composable fun CodeBlock( diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/CodeExecutionCard.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/CodeExecutionCard.kt index 7a8b586..cedbd04 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/CodeExecutionCard.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/CodeExecutionCard.kt @@ -35,15 +35,15 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.unit.dp -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource /** * Data class representing a code execution result parsed from tool call output. diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/CommonChatInputCore.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/CommonChatInputCore.kt index 88b42b7..30118f5 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/CommonChatInputCore.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/CommonChatInputCore.kt @@ -43,13 +43,13 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.garfiec.librechat.feature.chat.model.McpServerDisplayData -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.cd_send_message -import librechat_mobile.feature.chat.generated.resources.cd_start_voice_recording -import librechat_mobile.feature.chat.generated.resources.cd_stop_generation -import librechat_mobile.feature.chat.generated.resources.hint_message -import librechat_mobile.feature.chat.generated.resources.hint_message_model -import librechat_mobile.feature.chat.generated.resources.recording +import com.garfiec.librechat.feature.chat.resources.Res +import com.garfiec.librechat.feature.chat.resources.cd_send_message +import com.garfiec.librechat.feature.chat.resources.cd_start_voice_recording +import com.garfiec.librechat.feature.chat.resources.cd_stop_generation +import com.garfiec.librechat.feature.chat.resources.hint_message +import com.garfiec.librechat.feature.chat.resources.hint_message_model +import com.garfiec.librechat.feature.chat.resources.recording import org.jetbrains.compose.resources.stringResource @Immutable @@ -81,9 +81,9 @@ fun CommonChatInputCore( onRemoveFile: (AttachedFile) -> Unit, modifier: Modifier = Modifier, leadingButtons: @Composable RowScope.() -> Unit = {}, - textFieldContent: @Composable RowScope.() -> Unit, trailingSpacer: @Composable RowScope.() -> Unit = {}, bottomContent: @Composable BoxScope.() -> Unit = {}, + textFieldContent: @Composable RowScope.() -> Unit, ) { val surfaceColor = MaterialTheme.colorScheme.surface Box( @@ -255,6 +255,7 @@ fun VoiceMicIndicator( fun ChatInputPlaceholder( isRecording: Boolean, selectedModelDisplay: String?, + modifier: Modifier = Modifier, ) { Text( text = if (isRecording) { @@ -268,5 +269,6 @@ fun ChatInputPlaceholder( color = MaterialTheme.colorScheme.onSurfaceVariant, maxLines = 1, overflow = TextOverflow.Ellipsis, + modifier = modifier, ) } diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ComparisonDualPane.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ComparisonDualPane.kt index f84fbdd..bbe986c 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ComparisonDualPane.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ComparisonDualPane.kt @@ -15,10 +15,10 @@ import androidx.compose.material3.VerticalDivider import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource /** * Tablet-layout comparison view with two side-by-side panes. diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ComparisonTabBar.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ComparisonTabBar.kt index ef43550..23d9474 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ComparisonTabBar.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ComparisonTabBar.kt @@ -19,12 +19,12 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res import kotlinx.coroutines.launch +import org.jetbrains.compose.resources.stringResource /** * Phone-layout comparison view with tabs and a horizontal pager. @@ -46,14 +46,14 @@ fun ComparisonTabBar( modifier: Modifier = Modifier, onContinueWithPrimary: (() -> Unit)? = null, onContinueWithSecondary: (() -> Unit)? = null, - onTabChanged: ((Int) -> Unit)? = null, + onTabChange: ((Int) -> Unit)? = null, ) { val pagerState = rememberPagerState(pageCount = { 2 }) val coroutineScope = rememberCoroutineScope() LaunchedEffect(pagerState) { snapshotFlow { pagerState.currentPage }.collect { page -> - onTabChanged?.invoke(page) + onTabChange?.invoke(page) } } diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/FeedbackCommentDialog.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/FeedbackCommentDialog.kt index 7249639..73cf409 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/FeedbackCommentDialog.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/FeedbackCommentDialog.kt @@ -16,11 +16,11 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.unit.dp -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource /** * Dialog shown when a user taps thumbs-down on an AI message. diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ForkOptionsBottomSheet.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ForkOptionsBottomSheet.kt index ec2b400..b39cc41 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ForkOptionsBottomSheet.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ForkOptionsBottomSheet.kt @@ -28,11 +28,11 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.model.request.ForkOption -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource @OptIn(ExperimentalMaterial3Api::class) @Composable diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ImageGenCard.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ImageGenCard.kt index 068f9f9..23f72d8 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ImageGenCard.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ImageGenCard.kt @@ -31,15 +31,15 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.ContentScale -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import coil3.compose.SubcomposeAsyncImage -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource data class ImageGenResult( val imageUrl: String? = null, diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/InConvoSearchBar.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/InConvoSearchBar.kt index b49756a..fb1e658 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/InConvoSearchBar.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/InConvoSearchBar.kt @@ -25,16 +25,16 @@ import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalSoftwareKeyboardController -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.unit.dp -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.filter +import org.jetbrains.compose.resources.stringResource /** * Search overlay bar for finding text within the current conversation. @@ -44,7 +44,7 @@ import kotlinx.coroutines.flow.filter @Composable fun InConvoSearchBar( query: String, - onQueryChanged: (String) -> Unit, + onQueryChange: (String) -> Unit, currentMatchIndex: Int, totalMatches: Int, onPreviousMatch: () -> Unit, @@ -77,7 +77,7 @@ fun InConvoSearchBar( val searchCd = stringResource(Res.string.cd_search_in_conversation) OutlinedTextField( value = query, - onValueChange = onQueryChanged, + onValueChange = onQueryChange, modifier = Modifier .weight(1f) .height(48.dp) diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/InlineEditInput.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/InlineEditInput.kt index f47a43d..38b2950 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/InlineEditInput.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/InlineEditInput.kt @@ -20,17 +20,17 @@ import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource @Composable fun InlineEditInput( text: String, - onTextChanged: (String) -> Unit, + onTextChange: (String) -> Unit, onSaveAndSubmit: () -> Unit, onSaveOnly: () -> Unit, onCancel: () -> Unit, @@ -39,7 +39,7 @@ fun InlineEditInput( Column(modifier = modifier.fillMaxWidth()) { OutlinedTextField( value = text, - onValueChange = onTextChanged, + onValueChange = onTextChange, modifier = Modifier .fillMaxWidth() .heightIn(min = 56.dp, max = 200.dp), diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/LandingContent.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/LandingContent.kt index c5aea36..24e7b82 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/LandingContent.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/LandingContent.kt @@ -20,18 +20,18 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* -import kotlin.time.Clock +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res import kotlinx.datetime.DayOfWeek import kotlinx.datetime.TimeZone import kotlinx.datetime.toLocalDateTime +import org.jetbrains.compose.resources.stringResource +import kotlin.time.Clock @Composable fun LandingContent( diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/LogContentCard.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/LogContentCard.kt index 11fa4dc..72a3ecc 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/LogContentCard.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/LogContentCard.kt @@ -31,15 +31,15 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.unit.dp -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource data class LogContent( val title: String = "Log Output", diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/MarkdownParsing.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/MarkdownParsing.kt index 7d948ed..e5307c1 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/MarkdownParsing.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/MarkdownParsing.kt @@ -325,5 +325,3 @@ internal fun parseAlignments(separatorLine: String, columnCount: Int): List Unit)?, + onEditTextChange: ((String) -> Unit)?, onEditSaveAndSubmit: (() -> Unit)?, onEditSaveOnly: (() -> Unit)?, onEditCancel: (() -> Unit)?, @@ -178,7 +178,7 @@ internal fun MessageContentAndActions( isSearchMatch: Boolean, isCurrentSearchMatch: Boolean, searchFocusedOccurrence: Int, - onFocusedOccurrencePositioned: ((LayoutCoordinates) -> Unit)?, + onFocusedOccurrencePosition: ((LayoutCoordinates) -> Unit)?, showActions: Boolean, siblingIndex: Int, siblingCount: Int, @@ -194,10 +194,10 @@ internal fun MessageContentAndActions( currentFeedback: String?, onShowFeedbackDialog: () -> Unit, ) { - if (isEditing && onEditTextChanged != null && onEditSaveAndSubmit != null && onEditSaveOnly != null && onEditCancel != null) { + if (isEditing && onEditTextChange != null && onEditSaveAndSubmit != null && onEditSaveOnly != null && onEditCancel != null) { InlineEditInput( text = editText, - onTextChanged = onEditTextChanged, + onTextChange = onEditTextChange, onSaveAndSubmit = onEditSaveAndSubmit, onSaveOnly = onEditSaveOnly, onCancel = onEditCancel, @@ -225,7 +225,7 @@ internal fun MessageContentAndActions( showImageDescriptions = showImageDescriptions, searchQuery = if (isSearchMatch) searchQuery else null, searchFocusedOccurrence = if (isCurrentSearchMatch) searchFocusedOccurrence else -1, - onFocusedOccurrencePositioned = if (isCurrentSearchMatch) onFocusedOccurrencePositioned else null, + onFocusedOccurrencePosition = if (isCurrentSearchMatch) onFocusedOccurrencePosition else null, modifier = Modifier.padding(vertical = 2.dp), ) } @@ -236,7 +236,7 @@ internal fun MessageContentAndActions( useKatex = useKatex, searchQuery = if (isSearchMatch) searchQuery else null, searchFocusedOccurrence = if (isCurrentSearchMatch) searchFocusedOccurrence else -1, - onFocusedOccurrencePositioned = if (isCurrentSearchMatch) onFocusedOccurrencePositioned else null, + onFocusedOccurrencePosition = if (isCurrentSearchMatch) onFocusedOccurrencePosition else null, ) } } diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/MessageFiles.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/MessageFiles.kt index 7cc2098..2354000 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/MessageFiles.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/MessageFiles.kt @@ -38,7 +38,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.ContentScale -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.role @@ -47,8 +46,9 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import coil3.compose.SubcomposeAsyncImage import com.garfiec.librechat.core.model.FileReference -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource /** * Renders files attached to a message. Splits files into images (shown as diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/MessageList.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/MessageList.kt index 1e97e28..8e84ea7 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/MessageList.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/MessageList.kt @@ -35,17 +35,17 @@ import androidx.compose.ui.input.pointer.PointerEventPass import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.layout.boundsInRoot import androidx.compose.ui.platform.LocalDensity -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.common.ChatLayoutConstants import com.garfiec.librechat.core.model.FeedbackRating -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res import com.garfiec.librechat.feature.chat.util.MessageNode import com.garfiec.librechat.feature.chat.viewmodel.ActiveToolCall import com.garfiec.librechat.feature.chat.viewmodel.SearchMatch import kotlinx.coroutines.delay import kotlinx.coroutines.launch +import org.jetbrains.compose.resources.stringResource @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -66,7 +66,7 @@ fun MessageList( currentlyReadingMessageId: String? = null, editingMessageId: String? = null, editingText: String = "", - onEditTextChanged: (String) -> Unit = {}, + onEditTextChange: (String) -> Unit = {}, onEditSaveAndSubmit: () -> Unit = {}, onEditSaveOnly: () -> Unit = {}, onEditCancel: () -> Unit = {}, @@ -87,7 +87,7 @@ fun MessageList( searchMatchIndices: List = emptyList(), currentSearchMatchIndex: Int = 0, searchScrollToIndex: Int? = null, - onSearchScrollHandled: () -> Unit = {}, + onSearchScrollHandle: () -> Unit = {}, ) { val listState = rememberLazyListState() val coroutineScope = rememberCoroutineScope() @@ -171,6 +171,7 @@ fun MessageList( // When the focused occurrence's HighlightedTextSegment reports its layout position, // we compare it against the viewport and animateScrollBy the delta if needed. var pendingFineTuneScroll by remember { mutableStateOf(false) } + val currentOnSearchScrollHandled by rememberUpdatedState(onSearchScrollHandle) // Scroll to search match when navigating prev/next LaunchedEffect(searchScrollToIndex) { @@ -180,7 +181,7 @@ fun MessageList( listState.animateScrollToItem(index) // After scroll completes, the focused segment will report its position // via onGloballyPositioned, and the fine-tune scroll will happen there. - onSearchScrollHandled() + currentOnSearchScrollHandled() } } @@ -369,7 +370,7 @@ fun MessageList( currentFeedback = currentFeedbackStr, isEditing = editingMessageId == node.message.messageId, editText = if (editingMessageId == node.message.messageId) editingText else "", - onEditTextChanged = onEditTextChanged, + onEditTextChange = onEditTextChange, onEditSaveAndSubmit = onEditSaveAndSubmit, onEditSaveOnly = onEditSaveOnly, onEditCancel = onEditCancel, @@ -385,7 +386,7 @@ fun MessageList( isSearchMatch = isMatch, isCurrentSearchMatch = isCurrent, searchFocusedOccurrence = focusedOccurrenceInMessage, - onFocusedOccurrencePositioned = if (isCurrent) { + onFocusedOccurrencePosition = if (isCurrent) { { coordinates -> if (!pendingFineTuneScroll) return@MessageBubble pendingFineTuneScroll = false diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ModelSelectorButton.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ModelSelectorButton.kt index 1b3726f..903a3ce 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ModelSelectorButton.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ModelSelectorButton.kt @@ -13,11 +13,11 @@ import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource @Composable fun ModelSelectorButton( diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ModelSelectorSheet.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ModelSelectorSheet.kt index 9e24e0e..fa3c96e 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ModelSelectorSheet.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ModelSelectorSheet.kt @@ -50,9 +50,9 @@ import com.garfiec.librechat.core.model.Agent import com.garfiec.librechat.core.model.EndpointConfig import com.garfiec.librechat.core.ui.components.endpointIconPainter import com.garfiec.librechat.core.ui.components.isMonochromeEndpointIcon +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res import com.garfiec.librechat.feature.chat.util.FuzzyMatch -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* import org.jetbrains.compose.resources.stringResource private val IconSize = 20.dp @@ -92,7 +92,7 @@ fun ModelSelectorSheet( agents: List, selectedEndpoint: String?, selectedModel: String?, - onModelSelected: (endpoint: String, model: String) -> Unit, + onModelSelect: (endpoint: String, model: String) -> Unit, onDismiss: () -> Unit, modifier: Modifier = Modifier, serverUrl: String = "", @@ -193,7 +193,7 @@ fun ModelSelectorSheet( agent = agent, isSelected = selectedEndpoint == EndpointConstants.AGENTS && agent.id == selectedModel, serverUrl = serverUrl, - onClick = { onModelSelected(EndpointConstants.AGENTS, agent.id) }, + onClick = { onModelSelect(EndpointConstants.AGENTS, agent.id) }, ) } } @@ -232,7 +232,7 @@ fun ModelSelectorSheet( Row( modifier = Modifier .fillMaxWidth() - .clickable { onModelSelected(endpointName, model) } + .clickable { onModelSelect(endpointName, model) } .padding(vertical = 12.dp, horizontal = 8.dp) .animateItem(), verticalAlignment = Alignment.CenterVertically, @@ -289,7 +289,10 @@ private fun EndpointGroupHeader( ) Icon( imageVector = if (isExpanded) Icons.Default.ExpandLess else Icons.Default.ExpandMore, - contentDescription = stringResource(if (isExpanded) Res.string.cd_collapse_section else Res.string.cd_expand_section, displayLabel), + contentDescription = stringResource( + if (isExpanded) Res.string.cd_collapse_section else Res.string.cd_expand_section, + displayLabel, + ), tint = MaterialTheme.colorScheme.onSurface, ) } diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/PlatformChatComponents.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/PlatformChatComponents.kt index defbf9f..1d4f471 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/PlatformChatComponents.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/PlatformChatComponents.kt @@ -29,7 +29,7 @@ expect fun MessageBubble( currentFeedback: String? = null, isEditing: Boolean = false, editText: String = "", - onEditTextChanged: ((String) -> Unit)? = null, + onEditTextChange: ((String) -> Unit)? = null, onEditSaveAndSubmit: (() -> Unit)? = null, onEditSaveOnly: (() -> Unit)? = null, onEditCancel: (() -> Unit)? = null, @@ -42,7 +42,7 @@ expect fun MessageBubble( isSearchMatch: Boolean = false, isCurrentSearchMatch: Boolean = false, searchFocusedOccurrence: Int = -1, - onFocusedOccurrencePositioned: ((LayoutCoordinates) -> Unit)? = null, + onFocusedOccurrencePosition: ((LayoutCoordinates) -> Unit)? = null, useKatex: Boolean = false, chatLayoutStyle: String = ChatLayoutConstants.THREAD, showAvatars: Boolean = true, @@ -61,7 +61,7 @@ expect fun ContentPartRenderer( showImageDescriptions: Boolean = true, searchQuery: String? = null, searchFocusedOccurrence: Int = -1, - onFocusedOccurrencePositioned: ((LayoutCoordinates) -> Unit)? = null, + onFocusedOccurrencePosition: ((LayoutCoordinates) -> Unit)? = null, ) /** Platform-specific markdown content rendering. */ @@ -73,5 +73,5 @@ expect fun MarkdownContent( useKatex: Boolean = false, searchQuery: String? = null, searchFocusedOccurrence: Int = -1, - onFocusedOccurrencePositioned: ((LayoutCoordinates) -> Unit)? = null, + onFocusedOccurrencePosition: ((LayoutCoordinates) -> Unit)? = null, ) diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/PresetPicker.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/PresetPicker.kt index 6ee9f44..5b797e9 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/PresetPicker.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/PresetPicker.kt @@ -25,18 +25,18 @@ import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.garfiec.librechat.feature.chat.model.PresetDisplayData -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource @OptIn(ExperimentalMaterial3Api::class) @Composable fun PresetPicker( presets: List, - onPresetSelected: (PresetDisplayData) -> Unit, + onPresetSelect: (PresetDisplayData) -> Unit, onDismiss: () -> Unit, modifier: Modifier = Modifier, onEditPreset: (PresetDisplayData) -> Unit = {}, @@ -74,7 +74,7 @@ fun PresetPicker( items(presets, key = { it.presetId ?: it.title }, contentType = { "preset" }) { preset -> PresetItem( preset = preset, - onClick = { onPresetSelected(preset) }, + onClick = { onPresetSelect(preset) }, onEdit = { onEditPreset(preset) }, onDelete = { onDeletePreset(preset) }, ) diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/SavePresetDialog.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/SavePresetDialog.kt index c3678cf..2b45c89 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/SavePresetDialog.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/SavePresetDialog.kt @@ -15,10 +15,10 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource @Composable fun SavePresetDialog( diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/SecondaryMessageList.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/SecondaryMessageList.kt index 6e8979a..021799a 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/SecondaryMessageList.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/SecondaryMessageList.kt @@ -13,13 +13,13 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.common.ChatLayoutConstants -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res import com.garfiec.librechat.feature.chat.util.MessageNode import com.garfiec.librechat.feature.chat.viewmodel.ActiveToolCall +import org.jetbrains.compose.resources.stringResource /** * Simplified message list for the secondary comparison pane. diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/SharedContentParts.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/SharedContentParts.kt index 12b9d26..966aa12 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/SharedContentParts.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/SharedContentParts.kt @@ -55,8 +55,8 @@ import com.garfiec.librechat.feature.chat.components.artifact.ArtifactPanel import com.garfiec.librechat.feature.chat.components.artifact.ArtifactSegment import com.garfiec.librechat.feature.chat.components.artifact.detectArtifacts import com.garfiec.librechat.feature.chat.components.artifact.groupArtifactVersions -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res import org.jetbrains.compose.resources.stringResource // ─── ContentPartDispatcher ────────────────────────────────────────── @@ -77,7 +77,7 @@ internal fun ContentPartDispatcher( showImageDescriptions: Boolean = true, searchQuery: String? = null, searchFocusedOccurrence: Int = -1, - onFocusedOccurrencePositioned: ((LayoutCoordinates) -> Unit)? = null, + onFocusedOccurrencePosition: ((LayoutCoordinates) -> Unit)? = null, ) { val mod = modifier.fillMaxWidth() when (part.type) { @@ -89,7 +89,7 @@ internal fun ContentPartDispatcher( useKatex = useKatex, searchQuery = searchQuery, searchFocusedOccurrence = searchFocusedOccurrence, - onFocusedOccurrencePositioned = onFocusedOccurrencePositioned, + onFocusedOccurrencePosition = onFocusedOccurrencePosition, ) } ContentType.THINK -> { @@ -100,7 +100,7 @@ internal fun ContentPartDispatcher( useKatex = useKatex, searchQuery = searchQuery, searchFocusedOccurrence = searchFocusedOccurrence, - onFocusedOccurrencePositioned = onFocusedOccurrencePositioned, + onFocusedOccurrencePosition = onFocusedOccurrencePosition, ) } ContentType.TOOL_CALL -> { @@ -134,9 +134,18 @@ internal fun ContentPartDispatcher( VideoContent(url = videoUrl, modifier = mod) } else { Row(verticalAlignment = Alignment.CenterVertically, modifier = mod) { - Icon(Icons.Filled.Videocam, contentDescription = null, tint = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.size(18.dp)) + Icon( + Icons.Filled.Videocam, + contentDescription = null, + tint = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.size(18.dp), + ) Spacer(modifier = Modifier.width(6.dp)) - Text(stringResource(Res.string.video_not_supported), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant) + Text( + stringResource(Res.string.video_not_supported), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) } } } @@ -170,10 +179,10 @@ internal fun ContentPartDispatcher( @Composable private fun ToolCallDispatcher( part: MessageContentPart, - modifier: Modifier, baseUrl: String, attachments: List, showImageDescriptions: Boolean, + modifier: Modifier = Modifier, ) { val toolCall = part.toolCall val toolName = toolCall?.name ?: toolCall?.function?.name ?: "Tool Call" @@ -234,12 +243,12 @@ private fun ToolCallDispatcher( @Composable private fun TextContentPart( text: String, - modifier: Modifier, + modifier: Modifier = Modifier, fontSizeMultiplier: Float = 1.0f, useKatex: Boolean = false, searchQuery: String? = null, searchFocusedOccurrence: Int = -1, - onFocusedOccurrencePositioned: ((LayoutCoordinates) -> Unit)? = null, + onFocusedOccurrencePosition: ((LayoutCoordinates) -> Unit)? = null, ) { if (text.isBlank()) return @@ -247,7 +256,7 @@ private fun TextContentPart( val hasArtifacts = remember(segments) { segments.any { it is ArtifactSegment.ArtifactReference } } if (!hasArtifacts) { - MarkdownContent(text, modifier, fontSizeMultiplier, useKatex, searchQuery, searchFocusedOccurrence, onFocusedOccurrencePositioned) + MarkdownContent(text, modifier, fontSizeMultiplier, useKatex, searchQuery, searchFocusedOccurrence, onFocusedOccurrencePosition) } else { val versionMap = remember(segments) { groupArtifactVersions(segments) } var activeArtifact by remember { @@ -257,7 +266,15 @@ private fun TextContentPart( segments.forEach { segment -> when (segment) { is ArtifactSegment.Text -> { - MarkdownContent(segment.text, Modifier.fillMaxWidth(), fontSizeMultiplier, useKatex, searchQuery, searchFocusedOccurrence, onFocusedOccurrencePositioned) + MarkdownContent( + segment.text, + Modifier.fillMaxWidth(), + fontSizeMultiplier, + useKatex, + searchQuery, + searchFocusedOccurrence, + onFocusedOccurrencePosition, + ) } is ArtifactSegment.ArtifactReference -> { val versions = versionMap[segment.artifact.identifier] ?: listOf(segment.artifact) @@ -288,12 +305,12 @@ private fun TextContentPart( @Composable private fun ThinkingContentPart( thinkingText: String, - modifier: Modifier, + modifier: Modifier = Modifier, fontSizeMultiplier: Float = 1.0f, useKatex: Boolean = false, searchQuery: String? = null, searchFocusedOccurrence: Int = -1, - onFocusedOccurrencePositioned: ((LayoutCoordinates) -> Unit)? = null, + onFocusedOccurrencePosition: ((LayoutCoordinates) -> Unit)? = null, ) { var isExpanded by remember { mutableStateOf(false) } val thinkingToggleCd = @@ -317,9 +334,19 @@ private fun ThinkingContentPart( }, verticalAlignment = Alignment.CenterVertically, ) { - Icon(Icons.Default.Psychology, stringResource(Res.string.cd_thinking_indicator), Modifier.size(18.dp), tint = MaterialTheme.colorScheme.primary) + Icon( + Icons.Default.Psychology, + stringResource(Res.string.cd_thinking_indicator), + Modifier.size(18.dp), + tint = MaterialTheme.colorScheme.primary, + ) Spacer(modifier = Modifier.width(8.dp)) - Text(stringResource(Res.string.label_thinking), style = MaterialTheme.typography.titleSmall, color = MaterialTheme.colorScheme.primary, modifier = Modifier.weight(1f)) + Text( + stringResource(Res.string.label_thinking), + style = MaterialTheme.typography.titleSmall, + color = MaterialTheme.colorScheme.primary, + modifier = Modifier.weight(1f), + ) Icon( if (isExpanded) Icons.Default.ExpandLess else Icons.Default.ExpandMore, stringResource(if (isExpanded) Res.string.cd_collapse else Res.string.cd_expand), @@ -330,7 +357,14 @@ private fun ThinkingContentPart( AnimatedVisibility(visible = isExpanded, enter = expandVertically(), exit = shrinkVertically()) { Column(modifier = Modifier.padding(start = 12.dp, end = 12.dp, bottom = 12.dp)) { Spacer(modifier = Modifier.height(8.dp)) - MarkdownContent(thinkingText, fontSizeMultiplier = fontSizeMultiplier, useKatex = useKatex, searchQuery = searchQuery, searchFocusedOccurrence = searchFocusedOccurrence, onFocusedOccurrencePositioned = onFocusedOccurrencePositioned) + MarkdownContent( + thinkingText, + fontSizeMultiplier = fontSizeMultiplier, + useKatex = useKatex, + searchQuery = searchQuery, + searchFocusedOccurrence = searchFocusedOccurrence, + onFocusedOccurrencePosition = onFocusedOccurrencePosition, + ) } } } @@ -365,9 +399,19 @@ internal fun GenericToolCallCard( }, verticalAlignment = Alignment.CenterVertically, ) { - Icon(Icons.Default.Build, stringResource(Res.string.cd_tool_call), Modifier.size(16.dp), tint = MaterialTheme.colorScheme.onSurfaceVariant) + Icon( + Icons.Default.Build, + stringResource(Res.string.cd_tool_call), + Modifier.size(16.dp), + tint = MaterialTheme.colorScheme.onSurfaceVariant, + ) Spacer(modifier = Modifier.width(8.dp)) - Text(toolName, style = MaterialTheme.typography.titleSmall, color = MaterialTheme.colorScheme.onSurface, modifier = Modifier.weight(1f)) + Text( + toolName, + style = MaterialTheme.typography.titleSmall, + color = MaterialTheme.colorScheme.onSurface, + modifier = Modifier.weight(1f), + ) Icon( if (isExpanded) Icons.Default.ExpandLess else Icons.Default.ExpandMore, stringResource(if (isExpanded) Res.string.cd_collapse else Res.string.cd_expand), @@ -379,13 +423,21 @@ internal fun GenericToolCallCard( Column { if (!args.isNullOrBlank()) { Spacer(modifier = Modifier.height(8.dp)) - Text(stringResource(Res.string.label_input), style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant) + Text( + stringResource(Res.string.label_input), + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) Spacer(modifier = Modifier.height(4.dp)) CodeBlock(code = args, language = "json") } if (!output.isNullOrBlank()) { Spacer(modifier = Modifier.height(8.dp)) - Text(stringResource(Res.string.label_output), style = MaterialTheme.typography.labelSmall, color = MaterialTheme.colorScheme.onSurfaceVariant) + Text( + stringResource(Res.string.label_output), + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) Spacer(modifier = Modifier.height(4.dp)) CodeBlock(code = output, language = null) } @@ -435,7 +487,12 @@ internal fun ImageContentPart( .background(MaterialTheme.colorScheme.surfaceContainerHigh, RoundedCornerShape(12.dp)), contentAlignment = Alignment.Center, ) { - Icon(Icons.Default.BrokenImage, stringResource(Res.string.cd_failed_to_load_image), Modifier.size(32.dp), tint = MaterialTheme.colorScheme.onSurfaceVariant) + Icon( + Icons.Default.BrokenImage, + stringResource(Res.string.cd_failed_to_load_image), + Modifier.size(32.dp), + tint = MaterialTheme.colorScheme.onSurfaceVariant, + ) } }, ) diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/SiblingNavigator.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/SiblingNavigator.kt index 31c4c0c..f07caee 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/SiblingNavigator.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/SiblingNavigator.kt @@ -13,12 +13,12 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.stateDescription import androidx.compose.ui.unit.dp -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource @Composable fun SiblingNavigator( diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/SlashCommandMenu.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/SlashCommandMenu.kt index 89bf3bf..e2246ff 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/SlashCommandMenu.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/SlashCommandMenu.kt @@ -20,7 +20,7 @@ import com.garfiec.librechat.feature.chat.model.PromptMentionDisplayData @Composable fun SlashCommandMenu( filteredCommands: List, - onCommandSelected: (PromptMentionDisplayData) -> Unit, + onCommandSelect: (PromptMentionDisplayData) -> Unit, modifier: Modifier = Modifier, ) { DropdownMenu( @@ -48,7 +48,7 @@ fun SlashCommandMenu( } } }, - onClick = { onCommandSelected(group) }, + onClick = { onCommandSelect(group) }, ) } } diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/StreamingIndicator.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/StreamingIndicator.kt index 6e6b336..f6df039 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/StreamingIndicator.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/StreamingIndicator.kt @@ -13,14 +13,14 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource /** * Blinking cursor indicator shown during streaming. Displays a pipe character (|) diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/StreamingToolCallCard.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/StreamingToolCallCard.kt index d2892d1..a59302e 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/StreamingToolCallCard.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/StreamingToolCallCard.kt @@ -31,11 +31,11 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res import com.garfiec.librechat.feature.chat.viewmodel.ActiveToolCall +import org.jetbrains.compose.resources.stringResource @Composable fun StreamingToolCallCard( diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ToolCallParsing.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ToolCallParsing.kt index 2e15b36..4270fe4 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ToolCallParsing.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ToolCallParsing.kt @@ -1,7 +1,8 @@ package com.garfiec.librechat.feature.chat.components -import com.garfiec.librechat.core.model.content.AgentToolCall +import co.touchlab.kermit.Logger import com.garfiec.librechat.core.model.Attachment +import com.garfiec.librechat.core.model.content.AgentToolCall import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonObject @@ -11,7 +12,6 @@ import kotlinx.serialization.json.intOrNull import kotlinx.serialization.json.jsonArray import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonPrimitive -import co.touchlab.kermit.Logger private val log = Logger.withTag("ToolCallParsing") diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ToolsDropdownMenu.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ToolsDropdownMenu.kt index 130a42c..0dd40c7 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ToolsDropdownMenu.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/ToolsDropdownMenu.kt @@ -14,10 +14,10 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector -import org.jetbrains.compose.resources.stringResource import com.garfiec.librechat.core.common.ToolConstants -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource private data class ToolMenuItem( val id: String, diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/WebSearchResultCard.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/WebSearchResultCard.kt index 6c7f380..22e63e2 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/WebSearchResultCard.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/WebSearchResultCard.kt @@ -27,7 +27,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.platform.LocalUriHandler -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.role @@ -36,8 +35,9 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import coil3.compose.SubcomposeAsyncImage -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource /** * Data class representing a single web search result parsed from tool call output. diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/artifact/ArtifactButton.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/artifact/ArtifactButton.kt index 2f81ae3..3dc073c 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/artifact/ArtifactButton.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/artifact/ArtifactButton.kt @@ -28,12 +28,12 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource @Composable fun ArtifactButton( diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/artifact/ArtifactVersionNav.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/artifact/ArtifactVersionNav.kt index bdfc48f..fac1eb6 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/artifact/ArtifactVersionNav.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/components/artifact/ArtifactVersionNav.kt @@ -14,10 +14,10 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource /** Prev/next version navigation for artifacts. [currentIndex] is 0-based; display shows 1-based "v1/N". */ @Composable diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/di/ChatModule.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/di/ChatModule.kt index a9b2593..1084438 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/di/ChatModule.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/di/ChatModule.kt @@ -10,10 +10,15 @@ import org.koin.dsl.module val chatModule = module { includes(chatPlatformModule) viewModelOf(::PromptsViewModel) + // Koin's constructor-DSL (`viewModelOf`) wires every argument via `get()` and cannot read + // values passed through `parametersOf`. This VM receives its `initialGroupId` from the + // navigation layer via `parametersOf`, so the lambda-form `viewModel { params -> ... }` is + // the only DSL that works here. Detekt's `DeprecatedKoinApi` is a blanket stylistic rule, + // not a real `@Deprecated` API, so we suppress it in the narrow place it applies. + @Suppress("DeprecatedKoinApi") viewModel { params -> PromptEditorViewModel( promptRepository = get(), - savedStateHandle = get(), initialGroupId = params.getOrNull(), ) } diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/navigation/ChatNavigation.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/navigation/ChatNavigation.kt index 2267513..e572002 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/navigation/ChatNavigation.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/navigation/ChatNavigation.kt @@ -14,8 +14,11 @@ import kotlinx.serialization.modules.subclass @Serializable sealed interface ChatRoute : NavKey @Serializable data object NewChat : ChatRoute + @Serializable data class Chat(val conversationId: String? = null) : ChatRoute + @Serializable data object PromptsLibrary : ChatRoute + @Serializable data class PromptEditor(val groupId: String? = null) : ChatRoute fun EntryProviderScope.chatEntries( @@ -26,7 +29,7 @@ fun EntryProviderScope.chatEntries( ) { entry { NewChatScreen( - onConversationStarted = { conversationId -> + onConversationStart = { conversationId -> onNavigateToChat(conversationId) }, onOpenDrawer = onOpenDrawer, diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/PromptDetailScreen.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/PromptDetailScreen.kt index ef99716..bf66925 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/PromptDetailScreen.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/PromptDetailScreen.kt @@ -28,12 +28,12 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.ui.components.LibreChatTopBar -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* import com.garfiec.librechat.feature.chat.prompts.components.PromptPreviewPanel +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource @OptIn(ExperimentalMaterial3Api::class) @Composable diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/PromptEditorScreen.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/PromptEditorScreen.kt index d9cae53..c3cf156 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/PromptEditorScreen.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/PromptEditorScreen.kt @@ -29,14 +29,15 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.garfiec.librechat.core.ui.components.LoadingIndicator -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel import org.koin.core.parameter.parametersOf @@ -50,6 +51,7 @@ fun PromptEditorScreen( ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() val snackbarHostState = remember { SnackbarHostState() } + val currentOnBack by rememberUpdatedState(onBack) LaunchedEffect(uiState.error) { val error = uiState.error @@ -62,7 +64,7 @@ fun PromptEditorScreen( LaunchedEffect(uiState.saved) { if (uiState.saved) { viewModel.consumeSaved() - onBack() + currentOnBack() } } @@ -180,7 +182,7 @@ fun PromptEditorScreen( PromptVariablesSection( promptText = uiState.promptText, variableValues = uiState.variableValues, - onVariableChanged = viewModel::updateVariable, + onVariableChange = viewModel::updateVariable, modifier = Modifier.fillMaxWidth(), ) } diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/PromptEditorViewModel.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/PromptEditorViewModel.kt index 84e9c35..e984500 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/PromptEditorViewModel.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/PromptEditorViewModel.kt @@ -1,7 +1,6 @@ package com.garfiec.librechat.feature.chat.prompts import androidx.compose.runtime.Immutable -import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.garfiec.librechat.core.common.result.Result @@ -39,7 +38,6 @@ data class PromptEditorUiState( class PromptEditorViewModel( private val promptRepository: PromptRepository, - savedStateHandle: SavedStateHandle, initialGroupId: String? = null, ) : ViewModel() { diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/PromptVariablesSection.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/PromptVariablesSection.kt index 82c77c7..89ef9bd 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/PromptVariablesSection.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/PromptVariablesSection.kt @@ -13,10 +13,10 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource private val VARIABLE_REGEX = Regex("\\{\\{\\s*(\\w+)\\s*\\}\\}") @@ -51,7 +51,7 @@ fun substituteVariables(promptText: String, variableValues: Map) fun PromptVariablesSection( promptText: String, variableValues: Map, - onVariableChanged: (name: String, value: String) -> Unit, + onVariableChange: (name: String, value: String) -> Unit, modifier: Modifier = Modifier, ) { val variables = remember(promptText) { extractVariables(promptText) } @@ -68,7 +68,7 @@ fun PromptVariablesSection( variables.forEach { varName -> OutlinedTextField( value = variableValues[varName] ?: "", - onValueChange = { onVariableChanged(varName, it) }, + onValueChange = { onVariableChange(varName, it) }, label = { Text(varName) }, singleLine = true, modifier = Modifier diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/PromptVersionsSheet.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/PromptVersionsSheet.kt index 60b09da..12f967e 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/PromptVersionsSheet.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/PromptVersionsSheet.kt @@ -22,12 +22,12 @@ import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.model.Prompt -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource /** * A ModalBottomSheet that shows the version history of prompts within a group. diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/PromptsLibraryScreen.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/PromptsLibraryScreen.kt index 8fa6c1d..13f9798 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/PromptsLibraryScreen.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/PromptsLibraryScreen.kt @@ -41,7 +41,6 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -49,12 +48,13 @@ import com.garfiec.librechat.core.ui.components.EmptyState import com.garfiec.librechat.core.ui.components.ErrorBanner import com.garfiec.librechat.core.ui.components.LibreChatTopBar import com.garfiec.librechat.core.ui.components.LoadingIndicator -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* import com.garfiec.librechat.feature.chat.prompts.components.PromptFilterSheet import com.garfiec.librechat.feature.chat.prompts.components.PromptShareDialog import com.garfiec.librechat.feature.chat.prompts.components.PromptSortOrder import com.garfiec.librechat.feature.chat.prompts.components.VariableInputDialog +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel @OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class) @@ -117,7 +117,7 @@ fun PromptsLibraryScreen( PromptShareDialog( promptName = selectedGroup.name, isCurrentlyShared = false, - onShareToggled = { _, _ -> viewModel.dismissShareDialog() }, + onShareToggle = { _, _ -> viewModel.dismissShareDialog() }, onDismiss = viewModel::dismissShareDialog, ) } @@ -130,9 +130,9 @@ fun PromptsLibraryScreen( PromptFilterSheet( categories = uiState.availableCategories, selectedCategory = uiState.selectedCategory, - onCategorySelected = viewModel::onCategorySelected, + onCategorySelect = viewModel::onCategorySelected, sortOrder = uiState.sortOrder, - onSortOrderChanged = viewModel::onSortOrderChanged, + onSortOrderChange = viewModel::onSortOrderChanged, onDismiss = viewModel::dismissFilterSheet, ) } @@ -269,7 +269,7 @@ fun PromptsLibraryScreen( PromptShareDialog( promptName = shareGroup?.name ?: "", isCurrentlyShared = false, - onShareToggled = { _, _ -> viewModel.dismissShareDialog() }, + onShareToggle = { _, _ -> viewModel.dismissShareDialog() }, onDismiss = viewModel::dismissShareDialog, ) } diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/PromptsViewModel.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/PromptsViewModel.kt index 39f6b99..76ef068 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/PromptsViewModel.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/PromptsViewModel.kt @@ -3,6 +3,7 @@ package com.garfiec.librechat.feature.chat.prompts import androidx.compose.runtime.Immutable import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import co.touchlab.kermit.Logger import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.data.repository.PromptRepository import com.garfiec.librechat.core.model.PromptGroup @@ -18,7 +19,6 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch -import co.touchlab.kermit.Logger @Immutable data class PromptsUiState( diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/components/PromptFilterSheet.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/components/PromptFilterSheet.kt index 0dc80cb..99dcffa 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/components/PromptFilterSheet.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/components/PromptFilterSheet.kt @@ -18,10 +18,10 @@ import androidx.compose.material3.Text import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource enum class PromptSortOrder(val label: String) { RECENT("Recent"), @@ -34,9 +34,9 @@ enum class PromptSortOrder(val label: String) { fun PromptFilterSheet( categories: List, selectedCategory: String?, - onCategorySelected: (String?) -> Unit, + onCategorySelect: (String?) -> Unit, sortOrder: PromptSortOrder, - onSortOrderChanged: (PromptSortOrder) -> Unit, + onSortOrderChange: (PromptSortOrder) -> Unit, onDismiss: () -> Unit, modifier: Modifier = Modifier, sheetState: SheetState = rememberModalBottomSheetState(), @@ -72,14 +72,14 @@ fun PromptFilterSheet( ) { FilterChip( selected = selectedCategory == null, - onClick = { onCategorySelected(null) }, + onClick = { onCategorySelect(null) }, label = { Text(stringResource(Res.string.label_all)) }, ) categories.forEach { category -> FilterChip( selected = selectedCategory == category, onClick = { - onCategorySelected( + onCategorySelect( if (selectedCategory == category) null else category, ) }, @@ -105,7 +105,7 @@ fun PromptFilterSheet( PromptSortOrder.entries.forEach { order -> FilterChip( selected = sortOrder == order, - onClick = { onSortOrderChanged(order) }, + onClick = { onSortOrderChange(order) }, label = { Text(order.label) }, ) } diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/components/PromptPreviewPanel.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/components/PromptPreviewPanel.kt index a71cb25..b05e9ab 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/components/PromptPreviewPanel.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/components/PromptPreviewPanel.kt @@ -9,10 +9,10 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource @Composable fun PromptPreviewPanel( diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/components/PromptShareDialog.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/components/PromptShareDialog.kt index d770a7c..04d2df6 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/components/PromptShareDialog.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/components/PromptShareDialog.kt @@ -24,11 +24,11 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res import com.garfiec.librechat.feature.chat.util.copyToClipboard import org.jetbrains.compose.resources.stringResource -import androidx.compose.ui.unit.dp -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* enum class SharePermission(val label: String) { VIEW_ONLY("View only"), @@ -39,7 +39,7 @@ enum class SharePermission(val label: String) { fun PromptShareDialog( promptName: String, isCurrentlyShared: Boolean, - onShareToggled: (shared: Boolean, permission: SharePermission) -> Unit, + onShareToggle: (shared: Boolean, permission: SharePermission) -> Unit, onDismiss: () -> Unit, modifier: Modifier = Modifier, ) { @@ -117,7 +117,7 @@ fun PromptShareDialog( }, confirmButton = { TextButton( - onClick = { onShareToggled(isShared, permission) }, + onClick = { onShareToggle(isShared, permission) }, ) { Text(stringResource(Res.string.save)) } diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/components/VariableInputDialog.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/components/VariableInputDialog.kt index fe4fd0c..89c693e 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/components/VariableInputDialog.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/prompts/components/VariableInputDialog.kt @@ -26,10 +26,10 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res +import org.jetbrains.compose.resources.stringResource private val VARIABLE_PATTERN = Regex("\\{\\{(\\w+)\\}\\}") diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/screen/PlatformScreens.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/screen/PlatformScreens.kt index f6939b1..1368679 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/screen/PlatformScreens.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/screen/PlatformScreens.kt @@ -8,7 +8,7 @@ import androidx.compose.ui.Modifier expect fun ChatScreen( modifier: Modifier = Modifier, conversationId: String? = null, - onConversationStarted: ((String) -> Unit)? = null, + onConversationStart: ((String) -> Unit)? = null, onNavigateToConversation: ((String) -> Unit)? = null, onOpenDrawer: (() -> Unit)? = null, onNavigateToPromptsLibrary: (() -> Unit)? = null, @@ -18,7 +18,7 @@ expect fun ChatScreen( /** Platform-specific new chat screen. */ @Composable expect fun NewChatScreen( - onConversationStarted: (String) -> Unit, + onConversationStart: (String) -> Unit, modifier: Modifier = Modifier, onOpenDrawer: (() -> Unit)? = null, onNavigateToPromptsLibrary: (() -> Unit)? = null, diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/ChatViewModel.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/ChatViewModel.kt index a45d27e..a6eb534 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/ChatViewModel.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/ChatViewModel.kt @@ -1,8 +1,8 @@ package com.garfiec.librechat.feature.chat.viewmodel -import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import co.touchlab.kermit.Logger import com.garfiec.librechat.core.common.EndpointConstants import com.garfiec.librechat.core.common.ToolConstants import com.garfiec.librechat.core.common.network.ConnectivityObserver @@ -29,9 +29,9 @@ import com.garfiec.librechat.core.model.Preset import com.garfiec.librechat.core.model.StreamEvent import com.garfiec.librechat.core.model.request.EphemeralAgent import com.garfiec.librechat.core.ui.components.ModelParameters +import com.garfiec.librechat.feature.chat.components.AttachedFile import com.garfiec.librechat.feature.chat.model.PresetDisplayData import com.garfiec.librechat.feature.chat.model.PromptMentionDisplayData -import com.garfiec.librechat.feature.chat.components.AttachedFile import com.garfiec.librechat.feature.chat.util.NEW_CHAT_DRAFT_KEY import com.garfiec.librechat.feature.chat.util.buildActiveMessagePath import com.garfiec.librechat.feature.chat.viewmodel.delegate.ConversationActionsDelegate @@ -54,13 +54,11 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.isActive import kotlinx.coroutines.launch -import co.touchlab.kermit.Logger import kotlin.time.Clock import kotlin.uuid.ExperimentalUuidApi import kotlin.uuid.Uuid class ChatViewModel( - savedStateHandle: SavedStateHandle, initialConversationId: String? = null, private val agentRepository: AgentRepository, private val chatRepository: ChatRepository, @@ -509,7 +507,13 @@ class ChatViewModel( val isAgent = _uiState.value.selectedEndpoint == EndpointConstants.AGENTS val webSearchEnabled = _uiState.value.modelParameters.webSearch val ephemeralAgent = buildEphemeralAgent() - Logger.d { "sendMessage: webSearch=$webSearchEnabled, endpoint=${_uiState.value.selectedEndpoint}, model=${_uiState.value.selectedModel}, files=${fileRefs.size}, ephemeralAgent=$ephemeralAgent" } + Logger.d { + "sendMessage: webSearch=$webSearchEnabled, " + + "endpoint=${_uiState.value.selectedEndpoint}, " + + "model=${_uiState.value.selectedModel}, " + + "files=${fileRefs.size}, " + + "ephemeralAgent=$ephemeralAgent" + } // Build addedConvo if comparison mode is enabled val addedConvo = if (_uiState.value.comparisonState.isEnabled) { diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/delegate/ModelSelectionDelegate.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/delegate/ModelSelectionDelegate.kt index 9306312..f660b3e 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/delegate/ModelSelectionDelegate.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/delegate/ModelSelectionDelegate.kt @@ -1,5 +1,6 @@ package com.garfiec.librechat.feature.chat.viewmodel.delegate +import co.touchlab.kermit.Logger import com.garfiec.librechat.core.common.EndpointConstants import com.garfiec.librechat.core.common.ToolConstants import com.garfiec.librechat.core.common.result.Result @@ -16,7 +17,6 @@ import com.garfiec.librechat.feature.chat.viewmodel.ChatScreenState import com.garfiec.librechat.feature.chat.viewmodel.ChatStateHandle import com.garfiec.librechat.feature.chat.viewmodel.ComparisonState import kotlinx.coroutines.launch -import co.touchlab.kermit.Logger class ModelSelectionDelegate( private val stateHandle: ChatStateHandle, diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/delegate/PlatformFileHandler.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/delegate/PlatformFileHandler.kt index 2ed0925..05c4ace 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/delegate/PlatformFileHandler.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/delegate/PlatformFileHandler.kt @@ -1,7 +1,7 @@ package com.garfiec.librechat.feature.chat.viewmodel.delegate -import com.garfiec.librechat.feature.chat.components.AttachedFile import com.garfiec.librechat.core.model.FileReference +import com.garfiec.librechat.feature.chat.components.AttachedFile import kotlinx.coroutines.Job import kotlinx.coroutines.flow.StateFlow diff --git a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/delegate/PresetPromptDelegate.kt b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/delegate/PresetPromptDelegate.kt index 9f1a1a7..24b122b 100644 --- a/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/delegate/PresetPromptDelegate.kt +++ b/feature/chat/src/commonMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/delegate/PresetPromptDelegate.kt @@ -1,5 +1,6 @@ package com.garfiec.librechat.feature.chat.viewmodel.delegate +import co.touchlab.kermit.Logger import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.data.repository.PresetRepository import com.garfiec.librechat.core.data.repository.PromptRepository @@ -10,7 +11,6 @@ import com.garfiec.librechat.feature.chat.model.PresetDisplayData import com.garfiec.librechat.feature.chat.model.PromptMentionDisplayData import com.garfiec.librechat.feature.chat.viewmodel.ChatStateHandle import kotlinx.coroutines.launch -import co.touchlab.kermit.Logger class PresetPromptDelegate( private val stateHandle: ChatStateHandle, diff --git a/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/components/IosChatInput.kt b/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/components/IosChatInput.kt index 838ca67..5c518cb 100644 --- a/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/components/IosChatInput.kt +++ b/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/components/IosChatInput.kt @@ -19,17 +19,17 @@ import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.garfiec.librechat.feature.chat.model.McpServerDisplayData -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.cd_attach_file -import librechat_mobile.feature.chat.generated.resources.cd_paste_image +import com.garfiec.librechat.feature.chat.resources.Res +import com.garfiec.librechat.feature.chat.resources.cd_attach_file +import com.garfiec.librechat.feature.chat.resources.cd_paste_image import org.jetbrains.compose.resources.stringResource @Composable diff --git a/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/components/PlatformChatComponents.ios.kt b/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/components/PlatformChatComponents.ios.kt index 321eeec..f683430 100644 --- a/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/components/PlatformChatComponents.ios.kt +++ b/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/components/PlatformChatComponents.ios.kt @@ -28,9 +28,9 @@ import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.IconButtonDefaults import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults -import androidx.compose.material3.Text import androidx.compose.material3.VerticalDivider import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -66,17 +66,17 @@ import com.garfiec.librechat.core.model.content.MessageContentPart import com.garfiec.librechat.core.ui.components.AvatarImage import com.garfiec.librechat.core.ui.components.endpointIconPainter import com.garfiec.librechat.core.ui.components.isMonochromeEndpointIcon +import com.garfiec.librechat.feature.chat.resources.Res +import com.garfiec.librechat.feature.chat.resources.cd_close +import com.garfiec.librechat.feature.chat.resources.cd_expand_table +import com.garfiec.librechat.feature.chat.resources.dialog_table +import com.garfiec.librechat.feature.chat.resources.sender_assistant +import com.garfiec.librechat.feature.chat.resources.sender_you import com.mikepenz.markdown.m3.Markdown import com.mikepenz.markdown.m3.markdownColor import com.mikepenz.markdown.m3.markdownTypography -import org.intellij.markdown.flavours.gfm.GFMFlavourDescriptor import kotlinx.coroutines.delay -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.cd_expand_table -import librechat_mobile.feature.chat.generated.resources.cd_close -import librechat_mobile.feature.chat.generated.resources.dialog_table -import librechat_mobile.feature.chat.generated.resources.sender_assistant -import librechat_mobile.feature.chat.generated.resources.sender_you +import org.intellij.markdown.flavours.gfm.GFMFlavourDescriptor import org.jetbrains.compose.resources.stringResource private const val ACTION_AUTO_HIDE_MILLIS = 30_000L @@ -105,7 +105,7 @@ actual fun MessageBubble( currentFeedback: String?, isEditing: Boolean, editText: String, - onEditTextChanged: ((String) -> Unit)?, + onEditTextChange: ((String) -> Unit)?, onEditSaveAndSubmit: (() -> Unit)?, onEditSaveOnly: (() -> Unit)?, onEditCancel: (() -> Unit)?, @@ -118,7 +118,7 @@ actual fun MessageBubble( isSearchMatch: Boolean, isCurrentSearchMatch: Boolean, searchFocusedOccurrence: Int, - onFocusedOccurrencePositioned: ((LayoutCoordinates) -> Unit)?, + onFocusedOccurrencePosition: ((LayoutCoordinates) -> Unit)?, useKatex: Boolean, chatLayoutStyle: String, showAvatars: Boolean, @@ -131,18 +131,18 @@ actual fun MessageBubble( TwoSidedBubble( message, modifier, siblingIndex, siblingCount, onSiblingNavigation, onEdit, onRegenerate, onCopy, onFeedback, onContinue, onReadAloud, onFork, baseUrl, fontSizeMultiplier, useKatex, isReading, currentFeedback, - isEditing, editText, onEditTextChanged, onEditSaveAndSubmit, onEditSaveOnly, onEditCancel, + isEditing, editText, onEditTextChange, onEditSaveAndSubmit, onEditSaveOnly, onEditCancel, userAvatarUrl, userName, resolvedEndpoint, tintEndpointIcon, showImageDescriptions, showActionsInitially, - searchQuery, isSearchMatch, isCurrentSearchMatch, searchFocusedOccurrence, onFocusedOccurrencePositioned, + searchQuery, isSearchMatch, isCurrentSearchMatch, searchFocusedOccurrence, onFocusedOccurrencePosition, showAvatars, showBubbles, ) } else { ThreadBubble( message, modifier, siblingIndex, siblingCount, onSiblingNavigation, onEdit, onRegenerate, onCopy, onFeedback, onContinue, onReadAloud, onFork, baseUrl, fontSizeMultiplier, useKatex, isReading, currentFeedback, - isEditing, editText, onEditTextChanged, onEditSaveAndSubmit, onEditSaveOnly, onEditCancel, + isEditing, editText, onEditTextChange, onEditSaveAndSubmit, onEditSaveOnly, onEditCancel, userAvatarUrl, userName, resolvedEndpoint, tintEndpointIcon, showImageDescriptions, showActionsInitially, - searchQuery, isSearchMatch, isCurrentSearchMatch, searchFocusedOccurrence, onFocusedOccurrencePositioned, + searchQuery, isSearchMatch, isCurrentSearchMatch, searchFocusedOccurrence, onFocusedOccurrencePosition, showAvatars, showBubbles, ) } @@ -156,12 +156,12 @@ private fun ThreadBubble( onCopy: (() -> Unit)?, onFeedback: ((String?) -> Unit)?, onContinue: (() -> Unit)?, onReadAloud: (() -> Unit)?, onFork: (() -> Unit)?, baseUrl: String, fontSizeMultiplier: Float, useKatex: Boolean, isReading: Boolean, currentFeedback: String?, isEditing: Boolean, editText: String, - onEditTextChanged: ((String) -> Unit)?, onEditSaveAndSubmit: (() -> Unit)?, onEditSaveOnly: (() -> Unit)?, + onEditTextChange: ((String) -> Unit)?, onEditSaveAndSubmit: (() -> Unit)?, onEditSaveOnly: (() -> Unit)?, onEditCancel: (() -> Unit)?, userAvatarUrl: String?, userName: String?, resolvedEndpoint: String?, tintEndpointIcon: Boolean, showImageDescriptions: Boolean, showActionsInitially: Boolean, searchQuery: String?, isSearchMatch: Boolean, isCurrentSearchMatch: Boolean, searchFocusedOccurrence: Int, - onFocusedOccurrencePositioned: ((LayoutCoordinates) -> Unit)?, showAvatars: Boolean, showBubbles: Boolean, + onFocusedOccurrencePosition: ((LayoutCoordinates) -> Unit)?, showAvatars: Boolean, showBubbles: Boolean, ) { val isUser = message.isCreatedByUser var showActions by remember(message.messageId) { mutableStateOf(showActionsInitially) } @@ -192,8 +192,11 @@ private fun ThreadBubble( if (showAvatars) { AvatarImage( imageUrl = if (isUser) userAvatarUrl else message.iconURL, - fallbackText = if (isUser) userName ?: stringResource(Res.string.sender_you) - else message.sender ?: stringResource(Res.string.sender_assistant), + fallbackText = if (isUser) { + userName ?: stringResource(Res.string.sender_you) + } else { + message.sender ?: stringResource(Res.string.sender_assistant) + }, fallbackIconPainter = if (!isUser && message.iconURL == null) endpointIconPainter(resolvedEndpoint) else null, showPersonIcon = isUser && userAvatarUrl == null, tintIcon = if (!isUser && message.iconURL == null) tintEndpointIcon else false, @@ -202,8 +205,11 @@ private fun ThreadBubble( Spacer(Modifier.width(8.dp)) } Text( - text = if (isUser) userName ?: stringResource(Res.string.sender_you) - else message.sender ?: stringResource(Res.string.sender_assistant), + text = if (isUser) { + userName ?: stringResource(Res.string.sender_you) + } else { + message.sender ?: stringResource(Res.string.sender_assistant) + }, style = MaterialTheme.typography.titleSmall.copy(fontWeight = FontWeight.SemiBold), color = MaterialTheme.colorScheme.onSurface, ) @@ -215,7 +221,9 @@ private fun ThreadBubble( val contentPad = if (showAvatars) 36.dp else 0.dp val bubbleBg = if (showBubbles) { if (isUser) MaterialTheme.colorScheme.secondaryContainer else MaterialTheme.colorScheme.surfaceVariant - } else null + } else { + null + } Column( modifier = Modifier.padding(start = contentPad).then( @@ -223,9 +231,9 @@ private fun ThreadBubble( ), ) { MessageContentAndActions( - message, isUser, isEditing, editText, onEditTextChanged, onEditSaveAndSubmit, onEditSaveOnly, onEditCancel, + message, isUser, isEditing, editText, onEditTextChange, onEditSaveAndSubmit, onEditSaveOnly, onEditCancel, baseUrl, fontSizeMultiplier, useKatex, showImageDescriptions, searchQuery, isSearchMatch, - isCurrentSearchMatch, searchFocusedOccurrence, onFocusedOccurrencePositioned, showActions, + isCurrentSearchMatch, searchFocusedOccurrence, onFocusedOccurrencePosition, showActions, siblingIndex, siblingCount, onSiblingNavigation, onEdit, onRegenerate, onCopy, onFeedback, onContinue, onReadAloud, onFork, isReading, currentFeedback, { showFeedbackDialog = true }, ) @@ -241,12 +249,12 @@ private fun TwoSidedBubble( onCopy: (() -> Unit)?, onFeedback: ((String?) -> Unit)?, onContinue: (() -> Unit)?, onReadAloud: (() -> Unit)?, onFork: (() -> Unit)?, baseUrl: String, fontSizeMultiplier: Float, useKatex: Boolean, isReading: Boolean, currentFeedback: String?, isEditing: Boolean, editText: String, - onEditTextChanged: ((String) -> Unit)?, onEditSaveAndSubmit: (() -> Unit)?, onEditSaveOnly: (() -> Unit)?, + onEditTextChange: ((String) -> Unit)?, onEditSaveAndSubmit: (() -> Unit)?, onEditSaveOnly: (() -> Unit)?, onEditCancel: (() -> Unit)?, userAvatarUrl: String?, userName: String?, resolvedEndpoint: String?, tintEndpointIcon: Boolean, showImageDescriptions: Boolean, showActionsInitially: Boolean, searchQuery: String?, isSearchMatch: Boolean, isCurrentSearchMatch: Boolean, searchFocusedOccurrence: Int, - onFocusedOccurrencePositioned: ((LayoutCoordinates) -> Unit)?, showAvatars: Boolean, showBubbles: Boolean, + onFocusedOccurrencePosition: ((LayoutCoordinates) -> Unit)?, showAvatars: Boolean, showBubbles: Boolean, ) { val isUser = message.isCreatedByUser var showActions by remember(message.messageId) { mutableStateOf(showActionsInitially) } @@ -268,9 +276,14 @@ private fun TwoSidedBubble( } val bubbleBg = if (showBubbles) { if (isUser) MaterialTheme.colorScheme.secondaryContainer else MaterialTheme.colorScheme.surfaceVariant - } else null - val effectiveBg = if (searchBg != null && bubbleBg != null) searchBg.compositeOver(bubbleBg) - else searchBg ?: bubbleBg + } else { + null + } + val effectiveBg = if (searchBg != null && bubbleBg != null) { + searchBg.compositeOver(bubbleBg) + } else { + searchBg ?: bubbleBg + } Row( modifier = modifier.fillMaxWidth() @@ -292,28 +305,36 @@ private fun TwoSidedBubble( Column( modifier = Modifier.weight(1f).then( - if (effectiveBg != null) Modifier.background(effectiveBg, BubbleShape).padding(12.dp) - else Modifier.padding(horizontal = 4.dp, vertical = 8.dp), + if (effectiveBg != null) { + Modifier.background(effectiveBg, BubbleShape).padding(12.dp) + } else { + Modifier.padding(horizontal = 4.dp, vertical = 8.dp) + }, ), horizontalAlignment = if (isUser) Alignment.End else Alignment.Start, ) { Row(verticalAlignment = Alignment.CenterVertically) { Text( - text = if (isUser) userName ?: stringResource(Res.string.sender_you) - else message.sender ?: stringResource(Res.string.sender_assistant), + text = if (isUser) { + userName ?: stringResource(Res.string.sender_you) + } else { + message.sender ?: stringResource(Res.string.sender_assistant) + }, style = MaterialTheme.typography.labelSmall.copy(fontWeight = FontWeight.SemiBold), color = if (showBubbles) { if (isUser) MaterialTheme.colorScheme.onSecondaryContainer else MaterialTheme.colorScheme.onSurfaceVariant - } else MaterialTheme.colorScheme.onSurface, + } else { + MaterialTheme.colorScheme.onSurface + }, ) message.createdAt?.let { ts -> Spacer(Modifier.width(6.dp)); MessageTimestamp(isoTimestamp = ts) } } Spacer(Modifier.height(4.dp)) MessageContentAndActions( - message, isUser, isEditing, editText, onEditTextChanged, onEditSaveAndSubmit, onEditSaveOnly, onEditCancel, + message, isUser, isEditing, editText, onEditTextChange, onEditSaveAndSubmit, onEditSaveOnly, onEditCancel, baseUrl, fontSizeMultiplier, useKatex, showImageDescriptions, searchQuery, isSearchMatch, - isCurrentSearchMatch, searchFocusedOccurrence, onFocusedOccurrencePositioned, showActions, + isCurrentSearchMatch, searchFocusedOccurrence, onFocusedOccurrencePosition, showActions, siblingIndex, siblingCount, onSiblingNavigation, onEdit, onRegenerate, onCopy, onFeedback, onContinue, onReadAloud, onFork, isReading, currentFeedback, { showFeedbackDialog = true }, ) @@ -331,7 +352,6 @@ private fun TwoSidedBubble( } } - // ─── ContentPartRenderer ───────────────────────────────────────────── @Composable @@ -339,7 +359,7 @@ actual fun ContentPartRenderer( part: MessageContentPart, modifier: Modifier, baseUrl: String, fontSizeMultiplier: Float, useKatex: Boolean, attachments: List, showImageDescriptions: Boolean, searchQuery: String?, searchFocusedOccurrence: Int, - onFocusedOccurrencePositioned: ((LayoutCoordinates) -> Unit)?, + onFocusedOccurrencePosition: ((LayoutCoordinates) -> Unit)?, ) { ContentPartDispatcher( part = part, @@ -351,7 +371,7 @@ actual fun ContentPartRenderer( showImageDescriptions = showImageDescriptions, searchQuery = searchQuery, searchFocusedOccurrence = searchFocusedOccurrence, - onFocusedOccurrencePositioned = onFocusedOccurrencePositioned, + onFocusedOccurrencePosition = onFocusedOccurrencePosition, ) } @@ -361,7 +381,7 @@ actual fun ContentPartRenderer( actual fun MarkdownContent( text: String, modifier: Modifier, fontSizeMultiplier: Float, useKatex: Boolean, searchQuery: String?, searchFocusedOccurrence: Int, - onFocusedOccurrencePositioned: ((LayoutCoordinates) -> Unit)?, + onFocusedOccurrencePosition: ((LayoutCoordinates) -> Unit)?, ) { val segments = remember(text) { parseMarkdownSegments(text) } @@ -656,4 +676,3 @@ private fun TextStyle.scale(m: Float): TextStyle { lineHeight = if (lineHeight.isSpecified) (lineHeight.value * m).sp else lineHeight, ) } - diff --git a/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/components/PlatformMediaComponents.ios.kt b/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/components/PlatformMediaComponents.ios.kt index 42efc8a..87c2014 100644 --- a/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/components/PlatformMediaComponents.ios.kt +++ b/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/components/PlatformMediaComponents.ios.kt @@ -1,6 +1,11 @@ package com.garfiec.librechat.feature.chat.components +import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.togetherWith import androidx.compose.foundation.background +import androidx.compose.foundation.gestures.detectTransformGestures import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -11,6 +16,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons @@ -21,10 +27,12 @@ import androidx.compose.material.icons.filled.Image import androidx.compose.material.icons.filled.MusicNote import androidx.compose.material.icons.filled.Pause import androidx.compose.material.icons.filled.PlayArrow +import androidx.compose.material.icons.filled.Share import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.Icon import androidx.compose.material3.IconButton +import androidx.compose.material3.IconButtonDefaults import androidx.compose.material3.LinearProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text @@ -40,34 +48,38 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.interop.UIKitView -import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import co.touchlab.kermit.Logger import coil3.compose.AsyncImage +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res import kotlinx.cinterop.BetaInteropApi import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.cinterop.addressOf import kotlinx.cinterop.cValue +import kotlinx.cinterop.usePinned import kotlinx.coroutines.delay +import org.jetbrains.compose.resources.stringResource import platform.AVFAudio.AVAudioPlayer import platform.AVFoundation.AVLayerVideoGravityResizeAspect import platform.AVFoundation.AVPlayer -import platform.AVFoundation.AVPlayerItem import platform.AVFoundation.AVPlayerLayer +import platform.AVFoundation.AVPlayerTimeControlStatusPlaying import platform.AVFoundation.currentItem +import platform.AVFoundation.currentTime import platform.AVFoundation.duration import platform.AVFoundation.pause import platform.AVFoundation.play -import platform.AVFoundation.currentTime -import platform.AVFoundation.seekToTime import platform.AVFoundation.timeControlStatus -import platform.AVFoundation.AVPlayerTimeControlStatusPlaying -import platform.CoreMedia.CMTimeMakeWithSeconds import platform.CoreMedia.CMTimeGetSeconds import platform.Foundation.NSData import platform.Foundation.NSFileManager @@ -75,9 +87,8 @@ import platform.Foundation.NSTemporaryDirectory import platform.Foundation.NSURL import platform.Foundation.create import platform.Foundation.writeToFile -import kotlinx.cinterop.addressOf -import kotlinx.cinterop.usePinned -import platform.QuartzCore.CALayer +import platform.UIKit.UIActivityViewController +import platform.UIKit.UIApplication import platform.UIKit.UIColor import platform.UIKit.UIView import platform.UIKit.UIViewController @@ -87,24 +98,6 @@ import platform.WebKit.WKNavigationDelegateProtocol import platform.WebKit.WKWebView import platform.WebKit.WKWebViewConfiguration import platform.darwin.NSObject -import org.jetbrains.compose.resources.stringResource -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* -import androidx.compose.animation.AnimatedContent -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut -import androidx.compose.animation.togetherWith -import androidx.compose.foundation.gestures.detectTransformGestures -import androidx.compose.foundation.layout.statusBarsPadding -import androidx.compose.material.icons.filled.Share -import androidx.compose.material.icons.outlined.SaveAlt -import androidx.compose.material3.IconButtonDefaults -import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.graphics.graphicsLayer -import androidx.compose.ui.input.pointer.pointerInput -import androidx.compose.ui.layout.ContentScale -import platform.UIKit.UIActivityViewController -import platform.UIKit.UIApplication @OptIn(ExperimentalForeignApi::class, BetaInteropApi::class) @Composable diff --git a/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/components/artifact/PlatformArtifactPanel.ios.kt b/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/components/artifact/PlatformArtifactPanel.ios.kt index 601dec6..1dc2164 100644 --- a/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/components/artifact/PlatformArtifactPanel.ios.kt +++ b/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/components/artifact/PlatformArtifactPanel.ios.kt @@ -4,16 +4,13 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Share -import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme @@ -21,7 +18,6 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment diff --git a/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/di/ChatPlatformModule.ios.kt b/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/di/ChatPlatformModule.ios.kt index fa18e03..477784d 100644 --- a/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/di/ChatPlatformModule.ios.kt +++ b/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/di/ChatPlatformModule.ios.kt @@ -18,7 +18,6 @@ actual val chatPlatformModule: Module = module { viewModel { params -> ChatViewModel( - savedStateHandle = get(), initialConversationId = params.getOrNull(), agentRepository = get(), chatRepository = get(), diff --git a/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/screen/PlatformScreens.ios.kt b/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/screen/PlatformScreens.ios.kt index ff660ea..98222da 100644 --- a/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/screen/PlatformScreens.ios.kt +++ b/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/screen/PlatformScreens.ios.kt @@ -8,6 +8,8 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size @@ -27,13 +29,9 @@ import androidx.compose.material.icons.outlined.Edit import androidx.compose.material.icons.outlined.FileOpen import androidx.compose.material.icons.outlined.SaveAs import androidx.compose.material.icons.outlined.Share -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.material3.AlertDialog import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.DropdownMenu -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider @@ -42,6 +40,8 @@ import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBar @@ -70,6 +70,8 @@ import com.garfiec.librechat.feature.chat.components.ModelSelectorSheet import com.garfiec.librechat.feature.chat.components.PresetPicker import com.garfiec.librechat.feature.chat.components.SavePresetDialog import com.garfiec.librechat.feature.chat.components.TempChatToggle +import com.garfiec.librechat.feature.chat.resources.* +import com.garfiec.librechat.feature.chat.resources.Res import com.garfiec.librechat.feature.chat.util.clipboardHasImage import com.garfiec.librechat.feature.chat.util.openCamera import com.garfiec.librechat.feature.chat.util.openDocumentPicker @@ -77,8 +79,6 @@ import com.garfiec.librechat.feature.chat.util.openPhotoPicker import com.garfiec.librechat.feature.chat.util.readClipboardImage import com.garfiec.librechat.feature.chat.viewmodel.ChatScreenState import com.garfiec.librechat.feature.chat.viewmodel.ChatViewModel -import librechat_mobile.feature.chat.generated.resources.Res -import librechat_mobile.feature.chat.generated.resources.* import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel import org.koin.core.parameter.parametersOf @@ -88,7 +88,7 @@ import org.koin.core.parameter.parametersOf actual fun ChatScreen( modifier: Modifier, conversationId: String?, - onConversationStarted: ((String) -> Unit)?, + onConversationStart: ((String) -> Unit)?, onNavigateToConversation: ((String) -> Unit)?, onOpenDrawer: (() -> Unit)?, onNavigateToPromptsLibrary: (() -> Unit)?, @@ -121,11 +121,11 @@ actual fun ChatScreen( // Navigate when a new conversation is created from landing page. // Navigate first, then reset — matches Android order so the new // ViewModel can resume the active stream before the old one cancels it. - if (onConversationStarted != null) { + if (onConversationStart != null) { LaunchedEffect(uiState.pendingNavigationConversationId) { val navId = uiState.pendingNavigationConversationId if (navId != null) { - onConversationStarted(navId) + onConversationStart(navId) viewModel.onPendingNavigationHandled() } } @@ -375,7 +375,7 @@ actual fun ChatScreen( ) { InConvoSearchBar( query = uiState.searchQuery, - onQueryChanged = viewModel::onSearchQueryChanged, + onQueryChange = viewModel::onSearchQueryChanged, currentMatchIndex = uiState.currentSearchMatchIndex, totalMatches = uiState.searchMatchIndices.size, onPreviousMatch = viewModel::previousSearchMatch, @@ -428,7 +428,7 @@ actual fun ChatScreen( currentlyReadingMessageId = uiState.currentlyReadingMessageId, editingMessageId = uiState.editingMessageId, editingText = uiState.editingText, - onEditTextChanged = viewModel::onEditTextChanged, + onEditTextChange = viewModel::onEditTextChanged, onEditSaveAndSubmit = viewModel::submitEdit, onEditSaveOnly = viewModel::saveEditOnly, onEditCancel = viewModel::cancelEditing, @@ -456,7 +456,7 @@ actual fun ChatScreen( searchMatchIndices = uiState.searchMatchIndices, currentSearchMatchIndex = uiState.currentSearchMatchIndex, searchScrollToIndex = uiState.searchScrollToIndex, - onSearchScrollHandled = viewModel::onSearchScrollHandled, + onSearchScrollHandle = viewModel::onSearchScrollHandled, modifier = Modifier.fillMaxSize(), ) } @@ -529,7 +529,7 @@ actual fun ChatScreen( agents = uiState.agents, selectedEndpoint = uiState.selectedEndpoint, selectedModel = uiState.selectedModel, - onModelSelected = { endpoint, model -> + onModelSelect = { endpoint, model -> viewModel.onModelSelected(endpoint, model) showModelSheet = false }, @@ -542,7 +542,7 @@ actual fun ChatScreen( if (showPresetPicker) { PresetPicker( presets = uiState.presets, - onPresetSelected = { preset -> + onPresetSelect = { preset -> viewModel.loadPreset(preset) showPresetPicker = false }, @@ -610,14 +610,14 @@ actual fun ChatScreen( @Composable actual fun NewChatScreen( - onConversationStarted: (String) -> Unit, + onConversationStart: (String) -> Unit, modifier: Modifier, onOpenDrawer: (() -> Unit)?, onNavigateToPromptsLibrary: (() -> Unit)?, ) { ChatScreen( modifier = modifier, - onConversationStarted = onConversationStarted, + onConversationStart = onConversationStart, onOpenDrawer = onOpenDrawer, onNavigateToPromptsLibrary = onNavigateToPromptsLibrary, ) diff --git a/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/util/IosClipboardImageReader.kt b/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/util/IosClipboardImageReader.kt index f9f414f..048dee1 100644 --- a/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/util/IosClipboardImageReader.kt +++ b/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/util/IosClipboardImageReader.kt @@ -42,7 +42,7 @@ fun readClipboardImage(): IosImageData? { return IosImageData( bytes = bytes, - filename = "clipboard_${timestamp}.png", + filename = "clipboard_$timestamp.png", mimeType = "image/png", width = width, height = height, diff --git a/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/util/IosFilePicker.kt b/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/util/IosFilePicker.kt index 1ffd240..b192bb2 100644 --- a/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/util/IosFilePicker.kt +++ b/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/util/IosFilePicker.kt @@ -219,7 +219,9 @@ private class PhotoPickerDelegate( width = cgImage?.let { CGImageGetWidth(it).toInt() }, height = cgImage?.let { CGImageGetHeight(it).toInt() }, ) - } else null + } else { + null + } } if (imageData == null) { Logger.e { "PHPicker: failed to load image: ${error?.localizedDescription}" } @@ -321,4 +323,3 @@ private fun guessMimeType(filename: String): String { else -> "application/octet-stream" } } - diff --git a/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/util/TimestampFormatter.ios.kt b/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/util/TimestampFormatter.ios.kt index a3b8fdc..20e19ea 100644 --- a/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/util/TimestampFormatter.ios.kt +++ b/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/util/TimestampFormatter.ios.kt @@ -1,12 +1,12 @@ package com.garfiec.librechat.feature.chat.util -import platform.Foundation.NSDateFormatter import platform.Foundation.NSDate +import platform.Foundation.NSDateFormatter import platform.Foundation.NSLocale import platform.Foundation.NSTimeZone +import platform.Foundation.localeWithLocaleIdentifier import platform.Foundation.timeIntervalSince1970 import platform.Foundation.timeZoneWithName -import platform.Foundation.localeWithLocaleIdentifier actual fun formatRelativeTimestamp(isoTimestamp: String): String { val date = parseTimestamp(isoTimestamp) ?: return "" diff --git a/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/delegate/IosFileHandler.kt b/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/delegate/IosFileHandler.kt index 495ac59..a06e985 100644 --- a/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/delegate/IosFileHandler.kt +++ b/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/delegate/IosFileHandler.kt @@ -91,7 +91,9 @@ class IosFileHandler( width = fileObject.width, height = fileObject.height, ) - } else f + } else { + f + } } } } @@ -167,7 +169,9 @@ class IosFileHandler( filepath = fileObject.filepath, type = fileObject.type, ) - } else f + } else { + f + } } } } diff --git a/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/delegate/IosVoiceInput.kt b/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/delegate/IosVoiceInput.kt index 7231379..94d2fa7 100644 --- a/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/delegate/IosVoiceInput.kt +++ b/feature/chat/src/iosMain/kotlin/com/garfiec/librechat/feature/chat/viewmodel/delegate/IosVoiceInput.kt @@ -1,5 +1,6 @@ package com.garfiec.librechat.feature.chat.viewmodel.delegate +import co.touchlab.kermit.Logger import com.garfiec.librechat.feature.chat.viewmodel.ChatStateHandle import kotlinx.cinterop.ExperimentalForeignApi import kotlinx.coroutines.launch @@ -16,7 +17,6 @@ import platform.Speech.SFSpeechAudioBufferRecognitionRequest import platform.Speech.SFSpeechRecognitionTask import platform.Speech.SFSpeechRecognizer import platform.Speech.SFSpeechRecognizerAuthorizationStatus -import co.touchlab.kermit.Logger /** * iOS implementation of [PlatformVoiceInput] using AVAudioEngine + SFSpeechRecognizer diff --git a/feature/conversations/detekt-baseline.xml b/feature/conversations/detekt-baseline.xml deleted file mode 100644 index 331af8b..0000000 --- a/feature/conversations/detekt-baseline.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - FunctionNaming:String0.commonMain.kt$@InternalResourceApi internal fun _collectCommonMainString0Resources(map: MutableMap<String, StringResource>) - ImportOrdering:ArchivedConversationsScreen.kt$import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.Archive import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Unarchive import androidx.compose.material3.AlertDialog import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBar import androidx.compose.material3.pulltorefresh.PullToRefreshBox import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.garfiec.librechat.core.ui.components.EmptyState import com.garfiec.librechat.core.ui.components.ErrorBanner import com.garfiec.librechat.core.ui.components.LoadingIndicator import com.garfiec.librechat.feature.conversations.ArchivedConversationDisplayData import librechat_mobile.feature.conversations.generated.resources.Res import librechat_mobile.feature.conversations.generated.resources.* import com.garfiec.librechat.feature.conversations.viewmodel.ArchivedConversationsEvent import com.garfiec.librechat.feature.conversations.viewmodel.ArchivedConversationsViewModel import org.koin.compose.viewmodel.koinViewModel - ImportOrdering:ArchivedConversationsViewModel.kt$import androidx.compose.runtime.Immutable import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.data.repository.ConversationRepository import com.garfiec.librechat.core.model.Conversation import com.garfiec.librechat.feature.conversations.ArchivedConversationDisplayData import com.garfiec.librechat.feature.conversations.toArchivedDisplayData import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import co.touchlab.kermit.Logger - ImportOrdering:ConversationActions.kt$import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Archive import androidx.compose.material.icons.filled.Bookmark import androidx.compose.material.icons.filled.BookmarkBorder import androidx.compose.material.icons.filled.ContentCopy import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Edit import androidx.compose.material.icons.filled.FileDownload import androidx.compose.material.icons.filled.Share import androidx.compose.material3.AlertDialog import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.model.Conversation import librechat_mobile.feature.conversations.generated.resources.Res import librechat_mobile.feature.conversations.generated.resources.* - ImportOrdering:ConversationExporter.kt$import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.data.repository.ConversationRepository import com.garfiec.librechat.core.data.repository.MessageRepository import com.garfiec.librechat.core.model.ConversationExport import com.garfiec.librechat.core.model.Message import kotlin.time.Clock import kotlinx.datetime.TimeZone import kotlinx.datetime.toLocalDateTime import kotlinx.serialization.json.Json - ImportOrdering:ConversationItem.kt$import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Bookmark import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material.icons.filled.SmartToy import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.common.extensions.toInstantOrNull import com.garfiec.librechat.core.model.EModelEndpoint import com.garfiec.librechat.core.ui.components.endpointIconPainter import com.garfiec.librechat.core.ui.components.isMonochromeIcon import librechat_mobile.feature.conversations.generated.resources.Res import librechat_mobile.feature.conversations.generated.resources.* import kotlin.time.Clock import kotlin.time.Instant import kotlinx.datetime.TimeZone import kotlinx.datetime.toLocalDateTime - ImportOrdering:ConversationListScreen.kt$import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Archive import androidx.compose.material.icons.filled.Forum import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.pulltorefresh.PullToRefreshBox import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.garfiec.librechat.core.model.Conversation import com.garfiec.librechat.core.ui.components.EmptyState import com.garfiec.librechat.core.ui.components.ErrorBanner import com.garfiec.librechat.core.ui.components.LoadingIndicator import librechat_mobile.feature.conversations.generated.resources.Res import librechat_mobile.feature.conversations.generated.resources.* import com.garfiec.librechat.feature.conversations.components.ConversationActions import com.garfiec.librechat.feature.conversations.components.ConversationItem import com.garfiec.librechat.feature.conversations.components.ConversationSearchBar import com.garfiec.librechat.feature.conversations.components.DateGroupHeader import com.garfiec.librechat.feature.conversations.components.TagFilterBar import com.garfiec.librechat.feature.conversations.components.TagPicker import com.garfiec.librechat.feature.conversations.export.ExportFormat import com.garfiec.librechat.feature.conversations.export.ExportFormatPicker import com.garfiec.librechat.feature.conversations.platform.FileSaver import com.garfiec.librechat.feature.conversations.platform.copyToClipboard import com.garfiec.librechat.feature.conversations.platform.showToast import com.garfiec.librechat.feature.conversations.viewmodel.ConversationListEvent import com.garfiec.librechat.feature.conversations.viewmodel.ConversationListViewModel import org.koin.compose.viewmodel.koinViewModel - ImportOrdering:ConversationListViewModel.kt$import androidx.compose.runtime.Immutable import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.garfiec.librechat.core.common.extensions.toInstantOrNull import com.garfiec.librechat.core.common.extensions.toRelativeDateGroup import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.data.datastore.SettingsDataStore import com.garfiec.librechat.core.data.repository.ConversationRepository import com.garfiec.librechat.core.data.repository.SearchRepository import com.garfiec.librechat.core.data.repository.ShareRepository import com.garfiec.librechat.core.data.repository.TagRepository import com.garfiec.librechat.core.model.Conversation import com.garfiec.librechat.core.model.ConversationTag import com.garfiec.librechat.feature.conversations.components.ConversationDisplayData import com.garfiec.librechat.feature.conversations.components.toDisplayData import com.garfiec.librechat.feature.conversations.export.ConversationExporter import com.garfiec.librechat.feature.conversations.export.ConversationImporter import com.garfiec.librechat.feature.conversations.export.ExportFormat import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import co.touchlab.kermit.Logger - ImportOrdering:ConversationSearchBar.kt$import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Search import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TextField import androidx.compose.material3.TextFieldDefaults import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import librechat_mobile.feature.conversations.generated.resources.Res import librechat_mobile.feature.conversations.generated.resources.* - ImportOrdering:ExpectResourceCollectors.kt$import kotlin.String import kotlin.collections.Map import org.jetbrains.compose.resources.DrawableResource import org.jetbrains.compose.resources.FontResource import org.jetbrains.compose.resources.PluralStringResource import org.jetbrains.compose.resources.StringArrayResource import org.jetbrains.compose.resources.StringResource - ImportOrdering:ExportFormatPicker.kt$import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Code import androidx.compose.material.icons.filled.Description import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.Text import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import librechat_mobile.feature.conversations.generated.resources.Res import librechat_mobile.feature.conversations.generated.resources.* - ImportOrdering:Res.kt$import kotlin.ByteArray import kotlin.OptIn import kotlin.String import kotlin.Suppress import org.jetbrains.compose.resources.InternalResourceApi import org.jetbrains.compose.resources.getResourceUri import org.jetbrains.compose.resources.readResourceBytes - ImportOrdering:String0.commonMain.kt$import kotlin.OptIn import kotlin.String import kotlin.collections.MutableMap import org.jetbrains.compose.resources.InternalResourceApi import org.jetbrains.compose.resources.ResourceContentHash import org.jetbrains.compose.resources.ResourceItem import org.jetbrains.compose.resources.StringResource - ImportOrdering:TagFilterBar.kt$import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.expandVertically import androidx.compose.animation.shrinkVertically import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.BookmarkBorder import androidx.compose.material.icons.filled.Close import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.FilterChip import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.model.ConversationTag import librechat_mobile.feature.conversations.generated.resources.Res import librechat_mobile.feature.conversations.generated.resources.* - ImportOrdering:TagPicker.kt$import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import com.garfiec.librechat.core.model.ConversationTag import com.garfiec.librechat.core.ui.components.FilterChipBottomSheet import librechat_mobile.feature.conversations.generated.resources.Res import librechat_mobile.feature.conversations.generated.resources.* import org.jetbrains.compose.resources.stringResource - LambdaParameterInRestartableEffect:ConversationListScreen.kt$onConversationClick - MaxLineLength:ConversationExporter.kt$ConversationExporter$val exportDate = "${now.year}-${now.monthNumber.toString().padStart(2, '0')}-${now.dayOfMonth.toString().padStart(2, '0')} ${now.hour.toString().padStart(2, '0')}:${now.minute.toString().padStart(2, '0')}" - MaxLineLength:Res.kt$Res$public - MaxLineLength:Res.kt$Res$public suspend - PackageName:ExpectResourceCollectors.kt$package librechat_mobile.feature.conversations.generated.resources - PackageName:Res.kt$package librechat_mobile.feature.conversations.generated.resources - PackageName:String0.commonMain.kt$package librechat_mobile.feature.conversations.generated.resources - PackageNaming:ExpectResourceCollectors.kt$package librechat_mobile.feature.conversations.generated.resources - PackageNaming:Res.kt$package librechat_mobile.feature.conversations.generated.resources - PackageNaming:String0.commonMain.kt$package librechat_mobile.feature.conversations.generated.resources - ParameterNaming:ConversationListScreen.kt$onNavigateToArchived - ParameterNaming:ConversationSearchBar.kt$onQueryChanged - ParameterNaming:ExportFormatPicker.kt$onFormatSelected - ParameterNaming:TagPicker.kt$onTagsChanged - SpacingBetweenDeclarationsWithAnnotations:ConversationsNavigation.kt$ArchivedConversations : ConversationsRoute - - diff --git a/feature/conversations/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/conversations/di/ConversationsModuleVerificationTest.kt b/feature/conversations/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/conversations/di/ConversationsModuleVerificationTest.kt index 007f513..dcc0520 100644 --- a/feature/conversations/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/conversations/di/ConversationsModuleVerificationTest.kt +++ b/feature/conversations/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/conversations/di/ConversationsModuleVerificationTest.kt @@ -2,7 +2,6 @@ package com.garfiec.librechat.feature.conversations.di import android.app.Application import android.content.Context -import androidx.lifecycle.SavedStateHandle import com.garfiec.librechat.core.data.datastore.ServerDataStore import com.garfiec.librechat.core.data.datastore.SettingsDataStore import com.garfiec.librechat.core.data.repository.ConfigRepository @@ -21,7 +20,6 @@ class ConversationsModuleVerificationTest { extraTypes = listOf( Context::class, Application::class, - SavedStateHandle::class, ConversationRepository::class, MessageRepository::class, TagRepository::class, diff --git a/feature/conversations/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/conversations/viewmodel/ConversationListViewModelTest.kt b/feature/conversations/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/conversations/viewmodel/ConversationListViewModelTest.kt index 7f188b7..24a5d7b 100644 --- a/feature/conversations/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/conversations/viewmodel/ConversationListViewModelTest.kt +++ b/feature/conversations/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/conversations/viewmodel/ConversationListViewModelTest.kt @@ -1,6 +1,5 @@ package com.garfiec.librechat.feature.conversations.viewmodel -import com.google.common.truth.Truth.assertThat import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.data.datastore.SettingsDataStore import com.garfiec.librechat.core.data.repository.ConversationRepository @@ -11,6 +10,7 @@ import com.garfiec.librechat.core.model.Conversation import com.garfiec.librechat.core.model.ConversationTag import com.garfiec.librechat.feature.conversations.export.ConversationExporter import com.garfiec.librechat.feature.conversations.export.ConversationImporter +import com.google.common.truth.Truth.assertThat import io.mockk.coEvery import io.mockk.coVerify import io.mockk.every diff --git a/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/components/ConversationActions.kt b/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/components/ConversationActions.kt index 6e041ca..ca237f4 100644 --- a/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/components/ConversationActions.kt +++ b/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/components/ConversationActions.kt @@ -35,11 +35,11 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.model.Conversation -import librechat_mobile.feature.conversations.generated.resources.Res -import librechat_mobile.feature.conversations.generated.resources.* +import com.garfiec.librechat.feature.conversations.resources.* +import com.garfiec.librechat.feature.conversations.resources.Res +import org.jetbrains.compose.resources.stringResource @OptIn(ExperimentalMaterial3Api::class) @Composable diff --git a/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/components/ConversationItem.kt b/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/components/ConversationItem.kt index 5e705eb..3c5f4d6 100644 --- a/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/components/ConversationItem.kt +++ b/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/components/ConversationItem.kt @@ -21,20 +21,19 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color - -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.common.extensions.toInstantOrNull import com.garfiec.librechat.core.model.EModelEndpoint import com.garfiec.librechat.core.ui.components.endpointIconPainter import com.garfiec.librechat.core.ui.components.isMonochromeIcon -import librechat_mobile.feature.conversations.generated.resources.Res -import librechat_mobile.feature.conversations.generated.resources.* -import kotlin.time.Clock -import kotlin.time.Instant +import com.garfiec.librechat.feature.conversations.resources.* +import com.garfiec.librechat.feature.conversations.resources.Res import kotlinx.datetime.TimeZone import kotlinx.datetime.toLocalDateTime +import org.jetbrains.compose.resources.stringResource +import kotlin.time.Clock +import kotlin.time.Instant @Composable fun ConversationItem( diff --git a/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/components/ConversationSearchBar.kt b/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/components/ConversationSearchBar.kt index 1ec8591..deaa92d 100644 --- a/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/components/ConversationSearchBar.kt +++ b/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/components/ConversationSearchBar.kt @@ -16,20 +16,20 @@ import androidx.compose.material3.TextFieldDefaults import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp -import librechat_mobile.feature.conversations.generated.resources.Res -import librechat_mobile.feature.conversations.generated.resources.* +import com.garfiec.librechat.feature.conversations.resources.* +import com.garfiec.librechat.feature.conversations.resources.Res +import org.jetbrains.compose.resources.stringResource @Composable fun ConversationSearchBar( query: String, - onQueryChanged: (String) -> Unit, + onQueryChange: (String) -> Unit, modifier: Modifier = Modifier, ) { TextField( value = query, - onValueChange = onQueryChanged, + onValueChange = onQueryChange, leadingIcon = { Icon( imageVector = Icons.Default.Search, @@ -39,7 +39,7 @@ fun ConversationSearchBar( }, trailingIcon = { if (query.isNotEmpty()) { - IconButton(onClick = { onQueryChanged("") }) { + IconButton(onClick = { onQueryChange("") }) { Icon( imageVector = Icons.Default.Close, contentDescription = stringResource(Res.string.cd_clear_search), diff --git a/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/components/TagFilterBar.kt b/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/components/TagFilterBar.kt index 704b62e..3ee7170 100644 --- a/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/components/TagFilterBar.kt +++ b/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/components/TagFilterBar.kt @@ -26,11 +26,11 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.model.ConversationTag -import librechat_mobile.feature.conversations.generated.resources.Res -import librechat_mobile.feature.conversations.generated.resources.* +import com.garfiec.librechat.feature.conversations.resources.* +import com.garfiec.librechat.feature.conversations.resources.Res +import org.jetbrains.compose.resources.stringResource @OptIn(ExperimentalMaterial3Api::class) @Composable diff --git a/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/components/TagPicker.kt b/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/components/TagPicker.kt index 3818e22..c3331d8 100644 --- a/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/components/TagPicker.kt +++ b/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/components/TagPicker.kt @@ -5,15 +5,15 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import com.garfiec.librechat.core.model.ConversationTag import com.garfiec.librechat.core.ui.components.FilterChipBottomSheet -import librechat_mobile.feature.conversations.generated.resources.Res -import librechat_mobile.feature.conversations.generated.resources.* +import com.garfiec.librechat.feature.conversations.resources.* +import com.garfiec.librechat.feature.conversations.resources.Res import org.jetbrains.compose.resources.stringResource @Composable fun TagPicker( availableTags: List, currentTags: List, - onTagsChanged: (List) -> Unit, + onTagsChange: (List) -> Unit, onDismiss: () -> Unit, modifier: Modifier = Modifier, ) { @@ -27,7 +27,7 @@ fun TagPicker( FilterChipBottomSheet( items = allTagStrings, selectedItems = currentTags.toSet(), - onSelectionChanged = { onTagsChanged(it.toList()) }, + onSelectionChange = { onTagsChange(it.toList()) }, label = { it }, onDismiss = onDismiss, title = stringResource(Res.string.tags), diff --git a/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/export/ConversationExporter.kt b/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/export/ConversationExporter.kt index 935bcf9..1976784 100644 --- a/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/export/ConversationExporter.kt +++ b/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/export/ConversationExporter.kt @@ -5,10 +5,10 @@ import com.garfiec.librechat.core.data.repository.ConversationRepository import com.garfiec.librechat.core.data.repository.MessageRepository import com.garfiec.librechat.core.model.ConversationExport import com.garfiec.librechat.core.model.Message -import kotlin.time.Clock import kotlinx.datetime.TimeZone import kotlinx.datetime.toLocalDateTime import kotlinx.serialization.json.Json +import kotlin.time.Clock class ConversationExporter( private val conversationRepository: ConversationRepository, @@ -52,7 +52,11 @@ class ConversationExporter( } val now = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()) - val exportDate = "${now.year}-${now.monthNumber.toString().padStart(2, '0')}-${now.dayOfMonth.toString().padStart(2, '0')} ${now.hour.toString().padStart(2, '0')}:${now.minute.toString().padStart(2, '0')}" + val month = now.monthNumber.toString().padStart(2, '0') + val day = now.dayOfMonth.toString().padStart(2, '0') + val hour = now.hour.toString().padStart(2, '0') + val minute = now.minute.toString().padStart(2, '0') + val exportDate = "${now.year}-$month-$day $hour:$minute" val sb = StringBuilder() sb.appendLine("# ${conversation.title ?: "Untitled Conversation"}") diff --git a/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/export/ExportFormatPicker.kt b/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/export/ExportFormatPicker.kt index d4e4304..5b0f395 100644 --- a/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/export/ExportFormatPicker.kt +++ b/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/export/ExportFormatPicker.kt @@ -20,15 +20,15 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp -import librechat_mobile.feature.conversations.generated.resources.Res -import librechat_mobile.feature.conversations.generated.resources.* +import com.garfiec.librechat.feature.conversations.resources.* +import com.garfiec.librechat.feature.conversations.resources.Res +import org.jetbrains.compose.resources.stringResource @OptIn(ExperimentalMaterial3Api::class) @Composable fun ExportFormatPicker( - onFormatSelected: (ExportFormat) -> Unit, + onFormatSelect: (ExportFormat) -> Unit, onDismiss: () -> Unit, modifier: Modifier = Modifier, ) { @@ -55,7 +55,7 @@ fun ExportFormatPicker( description = stringResource(Res.string.format_json_description), onClick = { onDismiss() - onFormatSelected(ExportFormat.JSON) + onFormatSelect(ExportFormat.JSON) }, ) @@ -65,7 +65,7 @@ fun ExportFormatPicker( description = stringResource(Res.string.format_markdown_description), onClick = { onDismiss() - onFormatSelected(ExportFormat.MARKDOWN) + onFormatSelect(ExportFormat.MARKDOWN) }, ) } diff --git a/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/navigation/ConversationsNavigation.kt b/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/navigation/ConversationsNavigation.kt index d02b101..dae126b 100644 --- a/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/navigation/ConversationsNavigation.kt +++ b/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/navigation/ConversationsNavigation.kt @@ -12,17 +12,18 @@ import kotlinx.serialization.modules.subclass @Serializable sealed interface ConversationsRoute : NavKey @Serializable data object Conversations : ConversationsRoute + @Serializable data object ArchivedConversations : ConversationsRoute fun EntryProviderScope.conversationsEntries( onConversationClick: (String) -> Unit, - onNavigateToArchived: () -> Unit = {}, + onNavigateToArchive: () -> Unit = {}, onBack: () -> Unit = {}, ) { entry { ConversationListScreen( onConversationClick = onConversationClick, - onNavigateToArchived = onNavigateToArchived, + onNavigateToArchive = onNavigateToArchive, ) } entry { diff --git a/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/screen/ArchivedConversationsScreen.kt b/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/screen/ArchivedConversationsScreen.kt index 7b4e918..e64908e 100644 --- a/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/screen/ArchivedConversationsScreen.kt +++ b/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/screen/ArchivedConversationsScreen.kt @@ -35,7 +35,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -43,10 +42,11 @@ import com.garfiec.librechat.core.ui.components.EmptyState import com.garfiec.librechat.core.ui.components.ErrorBanner import com.garfiec.librechat.core.ui.components.LoadingIndicator import com.garfiec.librechat.feature.conversations.ArchivedConversationDisplayData -import librechat_mobile.feature.conversations.generated.resources.Res -import librechat_mobile.feature.conversations.generated.resources.* +import com.garfiec.librechat.feature.conversations.resources.* +import com.garfiec.librechat.feature.conversations.resources.Res import com.garfiec.librechat.feature.conversations.viewmodel.ArchivedConversationsEvent import com.garfiec.librechat.feature.conversations.viewmodel.ArchivedConversationsViewModel +import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel @OptIn(ExperimentalMaterial3Api::class) diff --git a/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/screen/ConversationListScreen.kt b/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/screen/ConversationListScreen.kt index 289fcbf..5cdc633 100644 --- a/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/screen/ConversationListScreen.kt +++ b/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/screen/ConversationListScreen.kt @@ -31,19 +31,17 @@ import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.garfiec.librechat.core.model.Conversation import com.garfiec.librechat.core.ui.components.EmptyState import com.garfiec.librechat.core.ui.components.ErrorBanner import com.garfiec.librechat.core.ui.components.LoadingIndicator -import librechat_mobile.feature.conversations.generated.resources.Res -import librechat_mobile.feature.conversations.generated.resources.* import com.garfiec.librechat.feature.conversations.components.ConversationActions import com.garfiec.librechat.feature.conversations.components.ConversationItem import com.garfiec.librechat.feature.conversations.components.ConversationSearchBar @@ -55,8 +53,11 @@ import com.garfiec.librechat.feature.conversations.export.ExportFormatPicker import com.garfiec.librechat.feature.conversations.platform.FileSaver import com.garfiec.librechat.feature.conversations.platform.copyToClipboard import com.garfiec.librechat.feature.conversations.platform.showToast +import com.garfiec.librechat.feature.conversations.resources.* +import com.garfiec.librechat.feature.conversations.resources.Res import com.garfiec.librechat.feature.conversations.viewmodel.ConversationListEvent import com.garfiec.librechat.feature.conversations.viewmodel.ConversationListViewModel +import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel @OptIn(ExperimentalMaterial3Api::class) @@ -65,7 +66,7 @@ fun ConversationListScreen( onConversationClick: (String) -> Unit, modifier: Modifier = Modifier, onNewChatClick: () -> Unit = {}, - onNavigateToArchived: () -> Unit = {}, + onNavigateToArchive: () -> Unit = {}, viewModel: ConversationListViewModel = koinViewModel(), ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() @@ -81,6 +82,7 @@ fun ConversationListScreen( var pendingExportContent by remember { mutableStateOf(null) } val snackbarHostState = remember { SnackbarHostState() } + val currentOnConversationClick by rememberUpdatedState(onConversationClick) val copyOfPrefix = stringResource(Res.string.copy_of) val newChatLabel = stringResource(Res.string.new_chat) @@ -114,7 +116,7 @@ fun ConversationListScreen( snackbarHostState.showSnackbar(linkCopiedMsg) } is ConversationListEvent.NavigateToConversation -> { - onConversationClick(event.conversationId) + currentOnConversationClick(event.conversationId) } is ConversationListEvent.ShowError -> { snackbarHostState.showSnackbar(event.message) @@ -188,10 +190,10 @@ fun ConversationListScreen( ) { ConversationSearchBar( query = uiState.searchQuery, - onQueryChanged = viewModel::onSearchQueryChanged, + onQueryChange = viewModel::onSearchQueryChanged, modifier = Modifier.weight(1f), ) - IconButton(onClick = onNavigateToArchived) { + IconButton(onClick = onNavigateToArchive) { Icon( imageVector = Icons.Default.Archive, contentDescription = stringResource(Res.string.cd_archived_conversations), @@ -382,7 +384,7 @@ fun ConversationListScreen( TagPicker( availableTags = uiState.tags, currentTags = tagPickerConversation?.tags ?: emptyList(), - onTagsChanged = { newTags -> + onTagsChange = { newTags -> tagPickerConversation?.conversationId?.let { id -> viewModel.updateConversationTags(id, newTags) } @@ -397,7 +399,7 @@ fun ConversationListScreen( // Export format picker if (showExportFormatPicker && exportConversation != null) { ExportFormatPicker( - onFormatSelected = { format -> + onFormatSelect = { format -> exportConversation?.conversationId?.let { id -> viewModel.exportConversation(id, exportConversation?.title, format) } diff --git a/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/viewmodel/ArchivedConversationsViewModel.kt b/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/viewmodel/ArchivedConversationsViewModel.kt index 1929a86..d6f4bb5 100644 --- a/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/viewmodel/ArchivedConversationsViewModel.kt +++ b/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/viewmodel/ArchivedConversationsViewModel.kt @@ -3,6 +3,7 @@ package com.garfiec.librechat.feature.conversations.viewmodel import androidx.compose.runtime.Immutable import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import co.touchlab.kermit.Logger import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.data.repository.ConversationRepository import com.garfiec.librechat.core.model.Conversation @@ -15,7 +16,6 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch -import co.touchlab.kermit.Logger @Immutable data class ArchivedConversationsUiState( diff --git a/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/viewmodel/ConversationListViewModel.kt b/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/viewmodel/ConversationListViewModel.kt index 68f61e5..d746966 100644 --- a/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/viewmodel/ConversationListViewModel.kt +++ b/feature/conversations/src/commonMain/kotlin/com/garfiec/librechat/feature/conversations/viewmodel/ConversationListViewModel.kt @@ -3,6 +3,7 @@ package com.garfiec.librechat.feature.conversations.viewmodel import androidx.compose.runtime.Immutable import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import co.touchlab.kermit.Logger import com.garfiec.librechat.core.common.extensions.toInstantOrNull import com.garfiec.librechat.core.common.extensions.toRelativeDateGroup import com.garfiec.librechat.core.common.result.Result @@ -27,7 +28,6 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch -import co.touchlab.kermit.Logger @Immutable data class ConversationListUiState( diff --git a/feature/files/detekt-baseline.xml b/feature/files/detekt-baseline.xml deleted file mode 100644 index 57577fa..0000000 --- a/feature/files/detekt-baseline.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - Filename:FilePicker.kt$com.garfiec.librechat.feature.files.platform.FilePicker.kt - FunctionNaming:String0.commonMain.kt$@InternalResourceApi internal fun _collectCommonMainString0Resources(map: MutableMap<String, StringResource>) - ImportOrdering:ExpectResourceCollectors.kt$import kotlin.String import kotlin.collections.Map import org.jetbrains.compose.resources.DrawableResource import org.jetbrains.compose.resources.FontResource import org.jetbrains.compose.resources.PluralStringResource import org.jetbrains.compose.resources.StringArrayResource import org.jetbrains.compose.resources.StringResource - ImportOrdering:FilePreviewDialog.kt$import androidx.compose.foundation.gestures.rememberTransformableState import androidx.compose.foundation.gestures.transformable import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.AudioFile import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Description import androidx.compose.material.icons.filled.ErrorOutline import androidx.compose.material.icons.filled.Image import androidx.compose.material.icons.filled.PictureAsPdf import androidx.compose.material.icons.filled.VideoFile import androidx.compose.material3.Card import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import coil3.compose.AsyncImage import co.touchlab.kermit.Logger import com.garfiec.librechat.feature.files.FilePreviewDisplayData import com.garfiec.librechat.feature.files.platform.PdfPreview import org.jetbrains.compose.resources.stringResource import librechat_mobile.feature.files.generated.resources.Res import librechat_mobile.feature.files.generated.resources.* - ImportOrdering:FileSortMenu.kt$import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowDownward import androidx.compose.material.icons.filled.ArrowUpward import androidx.compose.material.icons.filled.Check import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import org.jetbrains.compose.resources.stringResource import librechat_mobile.feature.files.generated.resources.Res import librechat_mobile.feature.files.generated.resources.* import com.garfiec.librechat.feature.files.viewmodel.FileSortField import com.garfiec.librechat.feature.files.viewmodel.FileSortOrder - ImportOrdering:FilesScreen.kt$import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.items import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.InsertDriveFile import androidx.compose.material.icons.automirrored.filled.Sort import androidx.compose.material.icons.automirrored.filled.ViewList import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.AudioFile import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Code import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Description import androidx.compose.material.icons.filled.Edit import androidx.compose.material.icons.filled.Folder import androidx.compose.material.icons.filled.GridView import androidx.compose.material.icons.filled.Image import androidx.compose.material.icons.filled.PictureAsPdf import androidx.compose.material.icons.filled.SelectAll import androidx.compose.material.icons.filled.VideoFile import androidx.compose.material3.AlertDialog import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.Checkbox import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.ScrollableTabRow import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Tab import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBar import androidx.compose.material3.pulltorefresh.PullToRefreshBox import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import coil3.compose.AsyncImage import com.garfiec.librechat.core.ui.components.EmptyState import com.garfiec.librechat.core.ui.components.ErrorBanner import com.garfiec.librechat.feature.files.FileDisplayData import com.garfiec.librechat.feature.files.components.UploadProgressCard import com.garfiec.librechat.feature.files.platform.rememberFilePickerLauncher import com.garfiec.librechat.feature.files.viewmodel.FileTypeFilter import com.garfiec.librechat.feature.files.viewmodel.FileViewMode import com.garfiec.librechat.feature.files.viewmodel.FilesViewModel import org.jetbrains.compose.resources.stringResource import librechat_mobile.feature.files.generated.resources.Res import librechat_mobile.feature.files.generated.resources.* import org.koin.compose.viewmodel.koinViewModel - ImportOrdering:FilesViewModel.kt$import androidx.compose.runtime.Immutable import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.data.datastore.ServerDataStore import com.garfiec.librechat.core.data.repository.FileRepository import com.garfiec.librechat.core.model.FileObject import com.garfiec.librechat.core.model.request.DeleteFileEntry import com.garfiec.librechat.feature.files.FileDisplayData import com.garfiec.librechat.feature.files.FilePreviewDisplayData import com.garfiec.librechat.feature.files.platform.FileReader import com.garfiec.librechat.feature.files.platform.formatFileSize import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import co.touchlab.kermit.Logger import kotlin.uuid.ExperimentalUuidApi import kotlin.uuid.Uuid - ImportOrdering:Res.kt$import kotlin.ByteArray import kotlin.OptIn import kotlin.String import kotlin.Suppress import org.jetbrains.compose.resources.InternalResourceApi import org.jetbrains.compose.resources.getResourceUri import org.jetbrains.compose.resources.readResourceBytes - ImportOrdering:String0.commonMain.kt$import kotlin.OptIn import kotlin.String import kotlin.collections.MutableMap import org.jetbrains.compose.resources.InternalResourceApi import org.jetbrains.compose.resources.ResourceContentHash import org.jetbrains.compose.resources.ResourceItem import org.jetbrains.compose.resources.StringResource - ImportOrdering:UploadProgressCard.kt$import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideOutVertically import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.UploadFile import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.LinearProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import org.jetbrains.compose.resources.stringResource import librechat_mobile.feature.files.generated.resources.Res import librechat_mobile.feature.files.generated.resources.* - MaxLineLength:Res.kt$Res$public suspend - PackageName:ExpectResourceCollectors.kt$package librechat_mobile.feature.files.generated.resources - PackageName:Res.kt$package librechat_mobile.feature.files.generated.resources - PackageName:String0.commonMain.kt$package librechat_mobile.feature.files.generated.resources - PackageNaming:ExpectResourceCollectors.kt$package librechat_mobile.feature.files.generated.resources - PackageNaming:Res.kt$package librechat_mobile.feature.files.generated.resources - PackageNaming:String0.commonMain.kt$package librechat_mobile.feature.files.generated.resources - ParameterNaming:FilePicker.kt$onFilePicked - ParameterNaming:FileSortMenu.kt$onSortSelected - - diff --git a/feature/files/src/androidMain/kotlin/com/garfiec/librechat/feature/files/platform/FilePicker.android.kt b/feature/files/src/androidMain/kotlin/com/garfiec/librechat/feature/files/platform/FilePickerLauncher.android.kt similarity index 91% rename from feature/files/src/androidMain/kotlin/com/garfiec/librechat/feature/files/platform/FilePicker.android.kt rename to feature/files/src/androidMain/kotlin/com/garfiec/librechat/feature/files/platform/FilePickerLauncher.android.kt index 854ae5d..db397ef 100644 --- a/feature/files/src/androidMain/kotlin/com/garfiec/librechat/feature/files/platform/FilePicker.android.kt +++ b/feature/files/src/androidMain/kotlin/com/garfiec/librechat/feature/files/platform/FilePickerLauncher.android.kt @@ -7,13 +7,13 @@ import androidx.compose.runtime.remember @Composable actual fun rememberFilePickerLauncher( - onFilePicked: (fileRef: Any) -> Unit, + onFilePick: (fileRef: Any) -> Unit, ): FilePickerLauncher { val launcher = rememberLauncherForActivityResult( contract = ActivityResultContracts.GetContent(), ) { uri -> if (uri != null) { - onFilePicked(uri) + onFilePick(uri) } } return remember(launcher) { diff --git a/feature/files/src/androidMain/kotlin/com/garfiec/librechat/feature/files/platform/PdfPreview.android.kt b/feature/files/src/androidMain/kotlin/com/garfiec/librechat/feature/files/platform/PdfPreview.android.kt index 315d07e..65686a3 100644 --- a/feature/files/src/androidMain/kotlin/com/garfiec/librechat/feature/files/platform/PdfPreview.android.kt +++ b/feature/files/src/androidMain/kotlin/com/garfiec/librechat/feature/files/platform/PdfPreview.android.kt @@ -10,7 +10,6 @@ import androidx.compose.foundation.gestures.transformable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size @@ -43,10 +42,10 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import co.touchlab.kermit.Logger import com.garfiec.librechat.feature.files.FilePreviewDisplayData +import com.garfiec.librechat.feature.files.resources.* +import com.garfiec.librechat.feature.files.resources.Res import com.garfiec.librechat.feature.files.screen.InfoRow import org.jetbrains.compose.resources.stringResource -import librechat_mobile.feature.files.generated.resources.Res -import librechat_mobile.feature.files.generated.resources.* import java.io.File private sealed interface PdfLoadState { diff --git a/feature/files/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/files/di/FilesModuleVerificationTest.kt b/feature/files/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/files/di/FilesModuleVerificationTest.kt index 5223e4e..1edeccd 100644 --- a/feature/files/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/files/di/FilesModuleVerificationTest.kt +++ b/feature/files/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/files/di/FilesModuleVerificationTest.kt @@ -2,7 +2,6 @@ package com.garfiec.librechat.feature.files.di import android.app.Application import android.content.Context -import androidx.lifecycle.SavedStateHandle import com.garfiec.librechat.core.data.datastore.ServerDataStore import com.garfiec.librechat.core.data.repository.FileRepository import com.garfiec.librechat.feature.files.platform.FileReader @@ -16,7 +15,6 @@ class FilesModuleVerificationTest { extraTypes = listOf( Context::class, Application::class, - SavedStateHandle::class, FileRepository::class, ServerDataStore::class, FileReader::class, diff --git a/feature/files/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/files/viewmodel/FilesViewModelTest.kt b/feature/files/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/files/viewmodel/FilesViewModelTest.kt index e24bfdd..0282473 100644 --- a/feature/files/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/files/viewmodel/FilesViewModelTest.kt +++ b/feature/files/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/files/viewmodel/FilesViewModelTest.kt @@ -1,11 +1,11 @@ package com.garfiec.librechat.feature.files.viewmodel -import com.google.common.truth.Truth.assertThat import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.data.datastore.ServerDataStore import com.garfiec.librechat.core.data.repository.FileRepository import com.garfiec.librechat.core.model.FileObject import com.garfiec.librechat.feature.files.platform.FileReader +import com.google.common.truth.Truth.assertThat import io.mockk.coEvery import io.mockk.coVerify import io.mockk.every diff --git a/feature/files/src/commonMain/kotlin/com/garfiec/librechat/feature/files/components/UploadProgressCard.kt b/feature/files/src/commonMain/kotlin/com/garfiec/librechat/feature/files/components/UploadProgressCard.kt index 190b8a4..a2c4ffa 100644 --- a/feature/files/src/commonMain/kotlin/com/garfiec/librechat/feature/files/components/UploadProgressCard.kt +++ b/feature/files/src/commonMain/kotlin/com/garfiec/librechat/feature/files/components/UploadProgressCard.kt @@ -27,9 +27,9 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp +import com.garfiec.librechat.feature.files.resources.* +import com.garfiec.librechat.feature.files.resources.Res import org.jetbrains.compose.resources.stringResource -import librechat_mobile.feature.files.generated.resources.Res -import librechat_mobile.feature.files.generated.resources.* /** Animated card showing upload filename, progress bar, and cancel button with slide/fade visibility transitions. */ @Composable diff --git a/feature/files/src/commonMain/kotlin/com/garfiec/librechat/feature/files/platform/FilePicker.kt b/feature/files/src/commonMain/kotlin/com/garfiec/librechat/feature/files/platform/FilePickerLauncher.kt similarity index 75% rename from feature/files/src/commonMain/kotlin/com/garfiec/librechat/feature/files/platform/FilePicker.kt rename to feature/files/src/commonMain/kotlin/com/garfiec/librechat/feature/files/platform/FilePickerLauncher.kt index 86bd60e..458cfcc 100644 --- a/feature/files/src/commonMain/kotlin/com/garfiec/librechat/feature/files/platform/FilePicker.kt +++ b/feature/files/src/commonMain/kotlin/com/garfiec/librechat/feature/files/platform/FilePickerLauncher.kt @@ -5,12 +5,12 @@ import androidx.compose.runtime.Composable /** * Platform file picker composable. * When [launch] is called, shows the platform's native file picker. - * On file selection, calls [onFilePicked] with a platform-specific file reference + * On file selection, calls [onFilePick] with a platform-specific file reference * (Android Uri, iOS NSURL). */ @Composable expect fun rememberFilePickerLauncher( - onFilePicked: (fileRef: Any) -> Unit, + onFilePick: (fileRef: Any) -> Unit, ): FilePickerLauncher expect class FilePickerLauncher { diff --git a/feature/files/src/commonMain/kotlin/com/garfiec/librechat/feature/files/screen/FilePreviewDialog.kt b/feature/files/src/commonMain/kotlin/com/garfiec/librechat/feature/files/screen/FilePreviewDialog.kt index 65a29b8..b46ad55 100644 --- a/feature/files/src/commonMain/kotlin/com/garfiec/librechat/feature/files/screen/FilePreviewDialog.kt +++ b/feature/files/src/commonMain/kotlin/com/garfiec/librechat/feature/files/screen/FilePreviewDialog.kt @@ -53,13 +53,13 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties -import coil3.compose.AsyncImage import co.touchlab.kermit.Logger +import coil3.compose.AsyncImage import com.garfiec.librechat.feature.files.FilePreviewDisplayData import com.garfiec.librechat.feature.files.platform.PdfPreview +import com.garfiec.librechat.feature.files.resources.* +import com.garfiec.librechat.feature.files.resources.Res import org.jetbrains.compose.resources.stringResource -import librechat_mobile.feature.files.generated.resources.Res -import librechat_mobile.feature.files.generated.resources.* @OptIn(ExperimentalMaterial3Api::class) @Composable diff --git a/feature/files/src/commonMain/kotlin/com/garfiec/librechat/feature/files/screen/FileSortMenu.kt b/feature/files/src/commonMain/kotlin/com/garfiec/librechat/feature/files/screen/FileSortMenu.kt index d6df39d..f4fc2f4 100644 --- a/feature/files/src/commonMain/kotlin/com/garfiec/librechat/feature/files/screen/FileSortMenu.kt +++ b/feature/files/src/commonMain/kotlin/com/garfiec/librechat/feature/files/screen/FileSortMenu.kt @@ -16,18 +16,18 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import org.jetbrains.compose.resources.stringResource -import librechat_mobile.feature.files.generated.resources.Res -import librechat_mobile.feature.files.generated.resources.* +import com.garfiec.librechat.feature.files.resources.* +import com.garfiec.librechat.feature.files.resources.Res import com.garfiec.librechat.feature.files.viewmodel.FileSortField import com.garfiec.librechat.feature.files.viewmodel.FileSortOrder +import org.jetbrains.compose.resources.stringResource @Composable fun FileSortMenu( expanded: Boolean, currentSortField: FileSortField, currentSortOrder: FileSortOrder, - onSortSelected: (FileSortField, FileSortOrder) -> Unit, + onSortSelect: (FileSortField, FileSortOrder) -> Unit, onDismiss: () -> Unit, modifier: Modifier = Modifier, ) { @@ -64,9 +64,9 @@ fun FileSortMenu( } else { FileSortOrder.ASCENDING } - onSortSelected(field, newOrder) + onSortSelect(field, newOrder) } else { - onSortSelected(field, FileSortOrder.DESCENDING) + onSortSelect(field, FileSortOrder.DESCENDING) } onDismiss() }, diff --git a/feature/files/src/commonMain/kotlin/com/garfiec/librechat/feature/files/screen/FilesScreen.kt b/feature/files/src/commonMain/kotlin/com/garfiec/librechat/feature/files/screen/FilesScreen.kt index 975c7bb..e753623 100644 --- a/feature/files/src/commonMain/kotlin/com/garfiec/librechat/feature/files/screen/FilesScreen.kt +++ b/feature/files/src/commonMain/kotlin/com/garfiec/librechat/feature/files/screen/FilesScreen.kt @@ -79,12 +79,12 @@ import com.garfiec.librechat.core.ui.components.ErrorBanner import com.garfiec.librechat.feature.files.FileDisplayData import com.garfiec.librechat.feature.files.components.UploadProgressCard import com.garfiec.librechat.feature.files.platform.rememberFilePickerLauncher +import com.garfiec.librechat.feature.files.resources.* +import com.garfiec.librechat.feature.files.resources.Res import com.garfiec.librechat.feature.files.viewmodel.FileTypeFilter import com.garfiec.librechat.feature.files.viewmodel.FileViewMode import com.garfiec.librechat.feature.files.viewmodel.FilesViewModel import org.jetbrains.compose.resources.stringResource -import librechat_mobile.feature.files.generated.resources.Res -import librechat_mobile.feature.files.generated.resources.* import org.koin.compose.viewmodel.koinViewModel @OptIn(ExperimentalMaterial3Api::class) @@ -101,7 +101,7 @@ fun FilesScreen( var showSortMenu by remember { mutableStateOf(false) } val filePickerLauncher = rememberFilePickerLauncher( - onFilePicked = { fileRef -> viewModel.uploadFile(fileRef) }, + onFilePick = { fileRef -> viewModel.uploadFile(fileRef) }, ) LaunchedEffect(uiState.error) { @@ -205,7 +205,7 @@ fun FilesScreen( expanded = showSortMenu, currentSortField = uiState.sortField, currentSortOrder = uiState.sortOrder, - onSortSelected = { field, order -> + onSortSelect = { field, order -> viewModel.setSort(field, order) }, onDismiss = { showSortMenu = false }, diff --git a/feature/files/src/commonMain/kotlin/com/garfiec/librechat/feature/files/viewmodel/FilesViewModel.kt b/feature/files/src/commonMain/kotlin/com/garfiec/librechat/feature/files/viewmodel/FilesViewModel.kt index 6a66e7e..f2d8831 100644 --- a/feature/files/src/commonMain/kotlin/com/garfiec/librechat/feature/files/viewmodel/FilesViewModel.kt +++ b/feature/files/src/commonMain/kotlin/com/garfiec/librechat/feature/files/viewmodel/FilesViewModel.kt @@ -3,6 +3,7 @@ package com.garfiec.librechat.feature.files.viewmodel import androidx.compose.runtime.Immutable import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import co.touchlab.kermit.Logger import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.data.datastore.ServerDataStore import com.garfiec.librechat.core.data.repository.FileRepository @@ -19,7 +20,6 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch -import co.touchlab.kermit.Logger import kotlin.uuid.ExperimentalUuidApi import kotlin.uuid.Uuid diff --git a/feature/files/src/iosMain/kotlin/com/garfiec/librechat/feature/files/platform/FilePicker.ios.kt b/feature/files/src/iosMain/kotlin/com/garfiec/librechat/feature/files/platform/FilePickerLauncher.ios.kt similarity index 92% rename from feature/files/src/iosMain/kotlin/com/garfiec/librechat/feature/files/platform/FilePicker.ios.kt rename to feature/files/src/iosMain/kotlin/com/garfiec/librechat/feature/files/platform/FilePickerLauncher.ios.kt index 45ee289..29569a4 100644 --- a/feature/files/src/iosMain/kotlin/com/garfiec/librechat/feature/files/platform/FilePicker.ios.kt +++ b/feature/files/src/iosMain/kotlin/com/garfiec/librechat/feature/files/platform/FilePickerLauncher.ios.kt @@ -5,7 +5,7 @@ import androidx.compose.runtime.remember @Composable actual fun rememberFilePickerLauncher( - onFilePicked: (fileRef: Any) -> Unit, + onFilePick: (fileRef: Any) -> Unit, ): FilePickerLauncher { // iOS file picker — stub for now. // A proper implementation would use UIDocumentPickerViewController. diff --git a/feature/settings/detekt-baseline.xml b/feature/settings/detekt-baseline.xml deleted file mode 100644 index 3e33ea6..0000000 --- a/feature/settings/detekt-baseline.xml +++ /dev/null @@ -1,97 +0,0 @@ - - - - - DeprecatedKoinApi:SettingsModule.kt$viewModel { SettingsViewModel( contentReader = get(), cacheCleaner = get(), userRepository = get(), authRepository = get(), conversationRepository = get(), themeDataStore = get(), serverDataStore = get(), settingsDataStore = get(), mcpRepository = get(), memoryRepository = get(), speechSettingsFactory = get(), balanceRepository = get(), shareRepository = get(), keyRepository = get(), ) } - FunctionNaming:String0.commonMain.kt$@InternalResourceApi internal fun _collectCommonMainString0Resources(map: MutableMap<String, StringResource>) - FunctionNaming:String1.commonMain.kt$@InternalResourceApi internal fun _collectCommonMainString1Resources(map: MutableMap<String, StringResource>) - FunctionNaming:String2.commonMain.kt$@InternalResourceApi internal fun _collectCommonMainString2Resources(map: MutableMap<String, StringResource>) - ImportOrdering:AccountSection.kt$import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.CameraAlt import androidx.compose.material.icons.filled.Person import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.ContentScale import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import coil3.compose.AsyncImage import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* - ImportOrdering:AccountSettingsScreen.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight import androidx.compose.material.icons.filled.CameraAlt import androidx.compose.material.icons.filled.Key import androidx.compose.material.icons.filled.Person import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarResult import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.ContentScale import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import coil3.compose.AsyncImage import com.garfiec.librechat.core.ui.components.ErrorBanner import com.garfiec.librechat.core.ui.components.LoadingIndicator import com.garfiec.librechat.core.ui.components.OtpVerificationDialog import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* import com.garfiec.librechat.feature.settings.screen.sections.BackupCodesDialog import com.garfiec.librechat.feature.settings.screen.sections.TwoFactorCodeDialog import com.garfiec.librechat.feature.settings.screen.sections.TwoFactorSetupDialog import com.garfiec.librechat.feature.settings.viewmodel.SettingsViewModel import org.koin.compose.viewmodel.koinViewModel - ImportOrdering:ApiKeyCreateDialog.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ContentCopy import androidx.compose.material3.AlertDialog import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import com.garfiec.librechat.feature.settings.util.copyToClipboard import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.model.ApiKey import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* - ImportOrdering:ApiKeysScreen.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Key import androidx.compose.material3.AlertDialog import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBar import androidx.compose.material3.pulltorefresh.PullToRefreshBox import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.garfiec.librechat.core.model.ApiKey import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* import com.garfiec.librechat.feature.settings.viewmodel.ApiKeysViewModel import org.koin.compose.viewmodel.koinViewModel - ImportOrdering:AppearanceSection.kt$import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.selection.selectable import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Tablet import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.RadioButton import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.data.datastore.ThemeMode import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* - ImportOrdering:BalanceSection.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.AccountBalanceWallet import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* - ImportOrdering:ChatPreferencesSection.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* - ImportOrdering:ChatSettingsScreen.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.Chat import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight import androidx.compose.material.icons.filled.Brush import androidx.compose.material.icons.filled.Terminal import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* import com.garfiec.librechat.feature.settings.viewmodel.SettingsViewModel import org.koin.compose.viewmodel.koinViewModel - ImportOrdering:ChatSettingsSection.kt$import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.selection.selectable import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.MaterialTheme import androidx.compose.material3.RadioButton import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.common.ChatLayoutConstants import com.garfiec.librechat.core.data.datastore.ChatFontSize import com.garfiec.librechat.core.data.datastore.LatexRenderer import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* - ImportOrdering:CommandsConfigScreen.kt$import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* - ImportOrdering:DataManagementDelegate.kt$import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.feature.settings.util.PlatformCacheCleaner import com.garfiec.librechat.core.data.repository.ConversationRepository import com.garfiec.librechat.core.data.repository.KeyRepository import com.garfiec.librechat.core.data.repository.ShareRepository import com.garfiec.librechat.core.model.SharedLink import com.garfiec.librechat.feature.settings.model.SharedLinkDisplayData import com.garfiec.librechat.feature.settings.viewmodel.SettingsStateHandle import kotlinx.coroutines.launch - ImportOrdering:DataManagementSection.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* - ImportOrdering:DataSettingsScreen.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight import androidx.compose.material3.AlertDialog import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* import com.garfiec.librechat.feature.settings.viewmodel.SettingsViewModel import org.koin.compose.viewmodel.koinViewModel - ImportOrdering:DataSettingsSection.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight import androidx.compose.material.icons.filled.Archive import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* - ImportOrdering:ExpectResourceCollectors.kt$import kotlin.String import kotlin.collections.Map import org.jetbrains.compose.resources.DrawableResource import org.jetbrains.compose.resources.FontResource import org.jetbrains.compose.resources.PluralStringResource import org.jetbrains.compose.resources.StringArrayResource import org.jetbrains.compose.resources.StringResource - ImportOrdering:ForkSettingsDialog.kt$import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.selection.selectable import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.AlertDialog import androidx.compose.material3.MaterialTheme import androidx.compose.material3.RadioButton import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.model.request.ForkOption import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* - ImportOrdering:GeneralSettingsScreen.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.selection.selectable import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight import androidx.compose.material.icons.filled.Language import androidx.compose.material.icons.filled.Person import androidx.compose.material.icons.filled.Tablet import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.RadioButton import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.vector.ImageVector import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.garfiec.librechat.core.data.datastore.ThemeMode import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* import com.garfiec.librechat.feature.settings.viewmodel.SettingsViewModel import org.koin.compose.viewmodel.koinViewModel - ImportOrdering:LanguageSelectorDialog.kt$import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Check import androidx.compose.material3.AlertDialog import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* - ImportOrdering:McpServerDelegate.kt$import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.data.repository.McpRepository import com.garfiec.librechat.core.model.mcp.McpApiKeyConfig import com.garfiec.librechat.core.model.mcp.McpOAuthConfig import com.garfiec.librechat.core.model.mcp.McpServer import com.garfiec.librechat.core.model.mcp.McpServerType import com.garfiec.librechat.feature.settings.viewmodel.SettingsStateHandle import kotlinx.coroutines.launch import co.touchlab.kermit.Logger - ImportOrdering:McpServersScreen.kt$import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Build import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Edit import androidx.compose.material.icons.filled.Refresh import androidx.compose.material3.AlertDialog import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarResult import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBar import androidx.compose.material3.pulltorefresh.PullToRefreshBox import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.garfiec.librechat.core.model.mcp.McpServer import com.garfiec.librechat.core.model.mcp.McpServerStatus import com.garfiec.librechat.core.ui.components.ErrorBanner import com.garfiec.librechat.core.ui.components.LoadingIndicator import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* import com.garfiec.librechat.feature.settings.viewmodel.McpViewModel import org.koin.compose.viewmodel.koinViewModel - ImportOrdering:McpSettingsSection.kt$import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Edit import androidx.compose.material.icons.filled.Refresh import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.model.mcp.McpServer import com.garfiec.librechat.core.model.mcp.McpServerStatus import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* - ImportOrdering:McpToolList.kt$import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.expandVertically import androidx.compose.animation.shrinkVertically import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Build import androidx.compose.material.icons.filled.KeyboardArrowDown import androidx.compose.material.icons.filled.KeyboardArrowUp import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.model.mcp.McpTool import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* - ImportOrdering:McpToolsSheet.kt$import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.model.mcp.McpTool import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* - ImportOrdering:McpViewModel.kt$import androidx.compose.runtime.Immutable import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.data.repository.McpRepository import com.garfiec.librechat.core.model.mcp.McpApiKeyConfig import com.garfiec.librechat.core.model.mcp.McpOAuthConfig import com.garfiec.librechat.core.model.mcp.McpServer import com.garfiec.librechat.core.model.mcp.McpServerStatus import com.garfiec.librechat.core.model.mcp.McpServerType import com.garfiec.librechat.core.model.mcp.McpTool import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import co.touchlab.kermit.Logger - ImportOrdering:MemoriesScreen.kt$import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Edit import androidx.compose.material3.AlertDialog import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarResult import androidx.compose.material3.Surface import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBar import androidx.compose.material3.pulltorefresh.PullToRefreshBox import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.garfiec.librechat.core.model.Memory import com.garfiec.librechat.core.ui.components.ErrorBanner import com.garfiec.librechat.core.ui.components.LoadingIndicator import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* import com.garfiec.librechat.feature.settings.viewmodel.MemoriesViewModel import org.koin.compose.viewmodel.koinViewModel - ImportOrdering:MemoriesSettingsSection.kt$import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Edit import androidx.compose.material3.AlertDialog import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.model.Memory import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* - ImportOrdering:MemoryEditDialog.kt$import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.material3.AlertDialog import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.model.Memory import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* - ImportOrdering:MemoryManagementDelegate.kt$import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.data.repository.MemoryRepository import com.garfiec.librechat.core.model.Memory import com.garfiec.librechat.core.model.request.CreateMemoryRequest import com.garfiec.librechat.core.model.request.UpdateMemoryPreferencesRequest import com.garfiec.librechat.core.model.request.UpdateMemoryRequest import com.garfiec.librechat.feature.settings.viewmodel.SettingsStateHandle import kotlinx.coroutines.launch import co.touchlab.kermit.Logger - ImportOrdering:PersonalizationDialog.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.width import androidx.compose.material3.AlertDialog import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* - ImportOrdering:PresetManagerScreen.kt$import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Tune import androidx.compose.material3.AlertDialog import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBar import androidx.compose.material3.pulltorefresh.PullToRefreshBox import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.garfiec.librechat.core.ui.components.EmptyState import com.garfiec.librechat.core.ui.components.LoadingIndicator import com.garfiec.librechat.feature.settings.model.PresetManagerDisplayData import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* import com.garfiec.librechat.feature.settings.viewmodel.PresetManagerViewModel import org.koin.compose.viewmodel.koinViewModel - ImportOrdering:Res.kt$import kotlin.ByteArray import kotlin.OptIn import kotlin.String import kotlin.Suppress import org.jetbrains.compose.resources.InternalResourceApi import org.jetbrains.compose.resources.getResourceUri import org.jetbrains.compose.resources.readResourceBytes - ImportOrdering:SecuritySection.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.CheckCircle import androidx.compose.material.icons.filled.Warning import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* - ImportOrdering:SecuritySection.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.material3.AlertDialog import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.unit.dp import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* - ImportOrdering:SettingsScreen.kt$import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.Chat import androidx.compose.material.icons.filled.Key import androidx.compose.material.icons.filled.Language import androidx.compose.material.icons.filled.Person import androidx.compose.material.icons.filled.Terminal import androidx.compose.material3.AlertDialog import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarResult import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.garfiec.librechat.core.ui.components.ErrorBanner import com.garfiec.librechat.core.ui.components.LoadingIndicator import com.garfiec.librechat.core.ui.components.OtpVerificationDialog import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* import com.garfiec.librechat.feature.settings.screen.sections.AboutInfo import com.garfiec.librechat.feature.settings.screen.sections.AccountInfo import com.garfiec.librechat.feature.settings.screen.sections.BackupCodesDialog import com.garfiec.librechat.feature.settings.screen.sections.DangerZone import com.garfiec.librechat.feature.settings.screen.sections.DataExtraActions import com.garfiec.librechat.feature.settings.screen.sections.SettingsRow import com.garfiec.librechat.feature.settings.screen.sections.SpeechDetailButtons import com.garfiec.librechat.feature.settings.screen.sections.TabletSidebarGestureToggle import com.garfiec.librechat.feature.settings.screen.sections.ThemeSelector import com.garfiec.librechat.feature.settings.screen.sections.TwoFactorCodeDialog import com.garfiec.librechat.feature.settings.screen.sections.TwoFactorSetupDialog import com.garfiec.librechat.feature.settings.viewmodel.SettingsViewModel import org.koin.compose.viewmodel.koinViewModel - ImportOrdering:SettingsViewModel.kt$import androidx.compose.runtime.Immutable import com.garfiec.librechat.feature.settings.util.ContentReader import com.garfiec.librechat.feature.settings.util.PlatformCacheCleaner import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.garfiec.librechat.core.common.ChatLayoutConstants import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.data.datastore.ChatFontSize import com.garfiec.librechat.core.data.datastore.LatexRenderer import com.garfiec.librechat.core.data.datastore.ServerDataStore import com.garfiec.librechat.core.data.datastore.SettingsDataStore import com.garfiec.librechat.core.data.datastore.ThemeDataStore import com.garfiec.librechat.core.data.datastore.ThemeMode import com.garfiec.librechat.core.data.repository.AuthRepository import com.garfiec.librechat.core.data.repository.BalanceRepository import com.garfiec.librechat.core.data.repository.ConversationRepository import com.garfiec.librechat.core.data.repository.KeyRepository import com.garfiec.librechat.core.data.repository.McpRepository import com.garfiec.librechat.core.data.repository.MemoryRepository import com.garfiec.librechat.core.data.repository.ShareRepository import com.garfiec.librechat.core.data.repository.SpeechRepository import com.garfiec.librechat.core.data.repository.UserRepository import com.garfiec.librechat.core.model.Memory import com.garfiec.librechat.core.model.User import com.garfiec.librechat.core.model.mcp.McpApiKeyConfig import com.garfiec.librechat.core.model.mcp.McpOAuthConfig import com.garfiec.librechat.core.model.mcp.McpServer import com.garfiec.librechat.core.model.mcp.McpServerStatus import com.garfiec.librechat.core.model.mcp.McpServerType import com.garfiec.librechat.core.model.speech.TtsVoice import com.garfiec.librechat.feature.settings.model.SharedLinkDisplayData import com.garfiec.librechat.feature.settings.model.UserDisplayData import com.garfiec.librechat.feature.settings.screen.DeviceVoiceInfo import com.garfiec.librechat.feature.settings.viewmodel.delegate.DataManagementDelegate import com.garfiec.librechat.feature.settings.viewmodel.delegate.McpServerDelegate import com.garfiec.librechat.feature.settings.viewmodel.delegate.MemoryManagementDelegate import com.garfiec.librechat.feature.settings.viewmodel.delegate.SpeechSettingsFactory import com.garfiec.librechat.feature.settings.viewmodel.delegate.TwoFactorSecurityDelegate import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import co.touchlab.kermit.Logger - ImportOrdering:SharedLinksScreen.kt$import com.garfiec.librechat.feature.settings.util.copyToClipboard import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.ContentCopy import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Link import androidx.compose.material.icons.filled.Visibility import androidx.compose.material.icons.filled.VisibilityOff import androidx.compose.material3.AlertDialog import androidx.compose.material3.Card import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.ui.components.EmptyState import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* import com.garfiec.librechat.feature.settings.model.SharedLinkDisplayData - ImportOrdering:SpeechDetailDialogs.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.PlayArrow import androidx.compose.material.icons.filled.Stop import androidx.compose.material3.AlertDialog import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExposedDropdownMenuBox import androidx.compose.material3.ExposedDropdownMenuDefaults import androidx.compose.material3.FilledTonalButton import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MenuAnchorType import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Slider import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* - ImportOrdering:SpeechSection.kt$import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* - ImportOrdering:SpeechSettingsSection.kt$import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.material3.Button import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExposedDropdownMenuBox import androidx.compose.material3.ExposedDropdownMenuDefaults import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MenuAnchorType import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.model.speech.TtsVoice import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* - ImportOrdering:String0.commonMain.kt$import kotlin.OptIn import kotlin.String import kotlin.collections.MutableMap import org.jetbrains.compose.resources.InternalResourceApi import org.jetbrains.compose.resources.ResourceContentHash import org.jetbrains.compose.resources.ResourceItem import org.jetbrains.compose.resources.StringResource - ImportOrdering:String1.commonMain.kt$import kotlin.OptIn import kotlin.String import kotlin.collections.MutableMap import org.jetbrains.compose.resources.InternalResourceApi import org.jetbrains.compose.resources.ResourceContentHash import org.jetbrains.compose.resources.ResourceItem import org.jetbrains.compose.resources.StringResource - ImportOrdering:String2.commonMain.kt$import kotlin.OptIn import kotlin.String import kotlin.collections.MutableMap import org.jetbrains.compose.resources.InternalResourceApi import org.jetbrains.compose.resources.ResourceContentHash import org.jetbrains.compose.resources.ResourceItem import org.jetbrains.compose.resources.StringResource - ImportOrdering:TabbedSettingsScreen.kt$import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.Scaffold import androidx.compose.material3.SecondaryTabRow import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Tab import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import org.jetbrains.compose.resources.stringResource import librechat_mobile.feature.settings.generated.resources.Res import librechat_mobile.feature.settings.generated.resources.* import com.garfiec.librechat.feature.settings.viewmodel.SettingsViewModel import kotlinx.coroutines.launch import org.koin.compose.viewmodel.koinViewModel - ImportOrdering:TwoFactorSecurityDelegate.kt$import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.feature.settings.viewmodel.isHttpStatus import com.garfiec.librechat.core.data.repository.AuthRepository import com.garfiec.librechat.feature.settings.viewmodel.SettingsStateHandle import kotlinx.coroutines.launch - LambdaParameterInRestartableEffect:AccountSettingsScreen.kt$onLogout - LambdaParameterInRestartableEffect:SettingsScreen.kt$onLogout - LambdaParameterInRestartableEffect:SharedLinksScreen.kt$onLoadMore - MaxLineLength:Res.kt$Res$public suspend - ModifierNotUsedAtRoot:AccountSettingsScreen.kt$modifier = modifier - ModifierNotUsedAtRoot:AccountSettingsScreen.kt$modifier = modifier.fillMaxSize() - ModifierNotUsedAtRoot:ChatSettingsScreen.kt$modifier = modifier.fillMaxSize() - ModifierNotUsedAtRoot:DataSettingsScreen.kt$modifier = modifier.fillMaxSize() - ModifierNotUsedAtRoot:GeneralSettingsScreen.kt$modifier = modifier.fillMaxSize() - NoUnusedImports:SettingsViewModel.kt$com.garfiec.librechat.feature.settings.viewmodel.SettingsViewModel.kt - PackageName:ExpectResourceCollectors.kt$package librechat_mobile.feature.settings.generated.resources - PackageName:Res.kt$package librechat_mobile.feature.settings.generated.resources - PackageName:String0.commonMain.kt$package librechat_mobile.feature.settings.generated.resources - PackageName:String1.commonMain.kt$package librechat_mobile.feature.settings.generated.resources - PackageName:String2.commonMain.kt$package librechat_mobile.feature.settings.generated.resources - PackageNaming:ExpectResourceCollectors.kt$package librechat_mobile.feature.settings.generated.resources - PackageNaming:Res.kt$package librechat_mobile.feature.settings.generated.resources - PackageNaming:String0.commonMain.kt$package librechat_mobile.feature.settings.generated.resources - PackageNaming:String1.commonMain.kt$package librechat_mobile.feature.settings.generated.resources - PackageNaming:String2.commonMain.kt$package librechat_mobile.feature.settings.generated.resources - ParameterNaming:DataSettingsScreen.kt$onNavigateToArchived - ParameterNaming:DataSettingsSection.kt$onViewArchived - ParameterNaming:ForkSettingsDialog.kt$onModeSelected - ParameterNaming:LanguageSelectorDialog.kt$onLanguageSelected - ParameterNaming:MemoriesSettingsSection.kt$onToggleEnabled - ParameterNaming:SettingsScreen.kt$onNavigateToArchived - ParameterNaming:SpeechSettingsSection.kt$onVoiceSelected - ParameterNaming:TabbedSettingsScreen.kt$onNavigateToArchived - SpacingBetweenDeclarationsWithAnnotations:SettingsNavigation.kt$ApiKeys : SettingsRoute - SpacingBetweenDeclarationsWithAnnotations:SettingsNavigation.kt$PresetManager : SettingsRoute - SpacingBetweenDeclarationsWithAnnotations:SettingsNavigation.kt$SettingsAccount : SettingsRoute - SpacingBetweenDeclarationsWithAnnotations:SettingsNavigation.kt$SettingsChat : SettingsRoute - SpacingBetweenDeclarationsWithAnnotations:SettingsNavigation.kt$SettingsData : SettingsRoute - SpacingBetweenDeclarationsWithAnnotations:SettingsNavigation.kt$SettingsGeneral : SettingsRoute - SpacingBetweenDeclarationsWithAnnotations:SettingsNavigation.kt$SharedLinks : SettingsRoute - ViewModelForwarding:AccountSettingsScreen.kt$AccountSettingsContent( onLogout = onLogout, onNavigateToApiKeys = onNavigateToApiKeys, snackbarHostState = snackbarHostState, modifier = Modifier .fillMaxSize() .padding(innerPadding), viewModel = viewModel, ) - ViewModelForwarding:ChatSettingsScreen.kt$ChatSettingsContent( onNavigateToPresets = onNavigateToPresets, modifier = Modifier .fillMaxSize() .padding(innerPadding), viewModel = viewModel, ) - ViewModelForwarding:DataSettingsScreen.kt$DataSettingsContent( onNavigateToArchived = onNavigateToArchived, onNavigateToSharedLinks = onNavigateToSharedLinks, snackbarHostState = snackbarHostState, modifier = Modifier .fillMaxSize() .padding(innerPadding), viewModel = viewModel, ) - ViewModelForwarding:GeneralSettingsScreen.kt$GeneralSettingsContent( modifier = Modifier .fillMaxSize() .padding(innerPadding), viewModel = viewModel, ) - ViewModelForwarding:TabbedSettingsScreen.kt$AccountSettingsContent( onLogout = onLogout, onNavigateToApiKeys = onNavigateToApiKeys, snackbarHostState = snackbarHostState, modifier = Modifier.fillMaxSize(), viewModel = viewModel, ) - ViewModelForwarding:TabbedSettingsScreen.kt$ChatSettingsContent( onNavigateToPresets = onNavigateToPresets, modifier = Modifier.fillMaxSize(), viewModel = viewModel, ) - ViewModelForwarding:TabbedSettingsScreen.kt$DataSettingsContent( onNavigateToArchived = onNavigateToArchived, onNavigateToSharedLinks = onNavigateToSharedLinks, snackbarHostState = snackbarHostState, modifier = Modifier.fillMaxSize(), viewModel = viewModel, ) - ViewModelForwarding:TabbedSettingsScreen.kt$GeneralSettingsContent( modifier = Modifier.fillMaxSize(), viewModel = viewModel, ) - - diff --git a/feature/settings/src/androidMain/kotlin/com/garfiec/librechat/feature/settings/screen/AvatarUploadDialog.kt b/feature/settings/src/androidMain/kotlin/com/garfiec/librechat/feature/settings/screen/AvatarUploadDialog.kt index 21d8518..b2ba3ad 100644 --- a/feature/settings/src/androidMain/kotlin/com/garfiec/librechat/feature/settings/screen/AvatarUploadDialog.kt +++ b/feature/settings/src/androidMain/kotlin/com/garfiec/librechat/feature/settings/screen/AvatarUploadDialog.kt @@ -30,13 +30,13 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.ContentScale -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import coil3.compose.AsyncImage -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res +import org.jetbrains.compose.resources.stringResource @Composable internal actual fun AvatarUploadDialog( diff --git a/feature/settings/src/androidMain/kotlin/com/garfiec/librechat/feature/settings/util/PlatformClipboard.android.kt b/feature/settings/src/androidMain/kotlin/com/garfiec/librechat/feature/settings/util/PlatformClipboard.android.kt index 4798218..fe64f49 100644 --- a/feature/settings/src/androidMain/kotlin/com/garfiec/librechat/feature/settings/util/PlatformClipboard.android.kt +++ b/feature/settings/src/androidMain/kotlin/com/garfiec/librechat/feature/settings/util/PlatformClipboard.android.kt @@ -3,8 +3,6 @@ package com.garfiec.librechat.feature.settings.util import android.content.ClipData import android.content.ClipboardManager import android.content.Context -import org.koin.core.component.KoinComponent -import org.koin.core.component.inject import org.koin.mp.KoinPlatformTools actual fun copyToClipboard(text: String, label: String) { diff --git a/feature/settings/src/androidMain/kotlin/com/garfiec/librechat/feature/settings/viewmodel/delegate/SpeechSettingsDelegate.kt b/feature/settings/src/androidMain/kotlin/com/garfiec/librechat/feature/settings/viewmodel/delegate/SpeechSettingsDelegate.kt index c272bb6..a633063 100644 --- a/feature/settings/src/androidMain/kotlin/com/garfiec/librechat/feature/settings/viewmodel/delegate/SpeechSettingsDelegate.kt +++ b/feature/settings/src/androidMain/kotlin/com/garfiec/librechat/feature/settings/viewmodel/delegate/SpeechSettingsDelegate.kt @@ -4,6 +4,7 @@ import android.content.Context import android.media.MediaPlayer import android.speech.tts.TextToSpeech import android.speech.tts.UtteranceProgressListener +import co.touchlab.kermit.Logger import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.data.datastore.SettingsDataStore import com.garfiec.librechat.core.data.repository.SpeechRepository @@ -11,7 +12,6 @@ import com.garfiec.librechat.core.model.speech.TtsVoice import com.garfiec.librechat.feature.settings.screen.DeviceVoiceInfo import com.garfiec.librechat.feature.settings.viewmodel.SettingsStateHandle import kotlinx.coroutines.launch -import co.touchlab.kermit.Logger import java.io.File /** diff --git a/feature/settings/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/settings/di/SettingsModuleVerificationTest.kt b/feature/settings/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/settings/di/SettingsModuleVerificationTest.kt index 8de0844..0fc47d7 100644 --- a/feature/settings/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/settings/di/SettingsModuleVerificationTest.kt +++ b/feature/settings/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/settings/di/SettingsModuleVerificationTest.kt @@ -2,7 +2,6 @@ package com.garfiec.librechat.feature.settings.di import android.app.Application import android.content.Context -import androidx.lifecycle.SavedStateHandle import com.garfiec.librechat.core.data.datastore.ServerDataStore import com.garfiec.librechat.core.data.datastore.SettingsDataStore import com.garfiec.librechat.core.data.datastore.ThemeDataStore @@ -30,7 +29,6 @@ class SettingsModuleVerificationTest { extraTypes = listOf( Context::class, Application::class, - SavedStateHandle::class, UserRepository::class, AuthRepository::class, ConversationRepository::class, diff --git a/feature/settings/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/settings/viewmodel/SettingsViewModelTest.kt b/feature/settings/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/settings/viewmodel/SettingsViewModelTest.kt index f1aa865..a08a215 100644 --- a/feature/settings/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/settings/viewmodel/SettingsViewModelTest.kt +++ b/feature/settings/src/androidUnitTest/kotlin/com/garfiec/librechat/feature/settings/viewmodel/SettingsViewModelTest.kt @@ -1,10 +1,5 @@ package com.garfiec.librechat.feature.settings.viewmodel -import com.google.common.truth.Truth.assertThat -import com.garfiec.librechat.feature.settings.util.ContentReader -import com.garfiec.librechat.feature.settings.util.PlatformCacheCleaner -import com.garfiec.librechat.feature.settings.viewmodel.delegate.SpeechSettingsContract -import com.garfiec.librechat.feature.settings.viewmodel.delegate.SpeechSettingsFactory import com.garfiec.librechat.core.common.ChatLayoutConstants import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.data.datastore.ChatFontSize @@ -23,6 +18,11 @@ import com.garfiec.librechat.core.data.repository.ShareRepository import com.garfiec.librechat.core.data.repository.SpeechRepository import com.garfiec.librechat.core.data.repository.UserRepository import com.garfiec.librechat.core.model.User +import com.garfiec.librechat.feature.settings.util.ContentReader +import com.garfiec.librechat.feature.settings.util.PlatformCacheCleaner +import com.garfiec.librechat.feature.settings.viewmodel.delegate.SpeechSettingsContract +import com.garfiec.librechat.feature.settings.viewmodel.delegate.SpeechSettingsFactory +import com.google.common.truth.Truth.assertThat import io.mockk.Ordering import io.mockk.coEvery import io.mockk.coVerify diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/di/SettingsModule.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/di/SettingsModule.kt index 39438d6..76c1ae8 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/di/SettingsModule.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/di/SettingsModule.kt @@ -6,7 +6,6 @@ import com.garfiec.librechat.feature.settings.viewmodel.MemoriesViewModel import com.garfiec.librechat.feature.settings.viewmodel.PresetManagerViewModel import com.garfiec.librechat.feature.settings.viewmodel.SettingsViewModel import org.koin.core.module.Module -import org.koin.core.module.dsl.viewModel import org.koin.core.module.dsl.viewModelOf import org.koin.dsl.module @@ -15,24 +14,7 @@ expect val settingsPlatformModule: Module val settingsModule = module { includes(settingsPlatformModule) - viewModel { - SettingsViewModel( - contentReader = get(), - cacheCleaner = get(), - userRepository = get(), - authRepository = get(), - conversationRepository = get(), - themeDataStore = get(), - serverDataStore = get(), - settingsDataStore = get(), - mcpRepository = get(), - memoryRepository = get(), - speechSettingsFactory = get(), - balanceRepository = get(), - shareRepository = get(), - keyRepository = get(), - ) - } + viewModelOf(::SettingsViewModel) viewModelOf(::ApiKeysViewModel) viewModelOf(::MemoriesViewModel) viewModelOf(::McpViewModel) diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/navigation/SettingsNavigation.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/navigation/SettingsNavigation.kt index 3db073d..0349a5d 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/navigation/SettingsNavigation.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/navigation/SettingsNavigation.kt @@ -22,25 +22,32 @@ import org.koin.compose.viewmodel.koinViewModel @Serializable sealed interface SettingsRoute : NavKey @Serializable data object SettingsTabbed : SettingsRoute + @Serializable data object SettingsGeneral : SettingsRoute + @Serializable data object SettingsChat : SettingsRoute + @Serializable data object SettingsAccount : SettingsRoute + @Serializable data object SettingsData : SettingsRoute + @Serializable data object SharedLinks : SettingsRoute + @Serializable data object PresetManager : SettingsRoute + @Serializable data object ApiKeys : SettingsRoute fun EntryProviderScope.settingsEntries( onNavigate: (NavKey) -> Unit, onBack: () -> Unit, onLogout: () -> Unit, - onNavigateToArchived: () -> Unit = {}, + onNavigateToArchive: () -> Unit = {}, ) { entry { TabbedSettingsScreen( onNavigateBack = onBack, onLogout = onLogout, - onNavigateToArchived = onNavigateToArchived, + onNavigateToArchive = onNavigateToArchive, onNavigateToSharedLinks = { onNavigate(SharedLinks) }, onNavigateToPresets = { onNavigate(PresetManager) }, onNavigateToApiKeys = { onNavigate(ApiKeys) }, @@ -67,7 +74,7 @@ fun EntryProviderScope.settingsEntries( entry { DataSettingsScreen( onNavigateBack = onBack, - onNavigateToArchived = onNavigateToArchived, + onNavigateToArchive = onNavigateToArchive, onNavigateToSharedLinks = { onNavigate(SharedLinks) }, ) } diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/AccountSettingsScreen.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/AccountSettingsScreen.kt index e5dd1dc..50ae947 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/AccountSettingsScreen.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/AccountSettingsScreen.kt @@ -40,13 +40,13 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.ContentScale -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextOverflow @@ -56,12 +56,13 @@ import coil3.compose.AsyncImage import com.garfiec.librechat.core.ui.components.ErrorBanner import com.garfiec.librechat.core.ui.components.LoadingIndicator import com.garfiec.librechat.core.ui.components.OtpVerificationDialog -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res import com.garfiec.librechat.feature.settings.screen.sections.BackupCodesDialog import com.garfiec.librechat.feature.settings.screen.sections.TwoFactorCodeDialog import com.garfiec.librechat.feature.settings.screen.sections.TwoFactorSetupDialog import com.garfiec.librechat.feature.settings.viewmodel.SettingsViewModel +import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel @OptIn(ExperimentalMaterial3Api::class) @@ -71,7 +72,6 @@ fun AccountSettingsScreen( onNavigateBack: () -> Unit, onNavigateToApiKeys: () -> Unit, modifier: Modifier = Modifier, - viewModel: SettingsViewModel = koinViewModel(), ) { val snackbarHostState = remember { SnackbarHostState() } @@ -99,7 +99,6 @@ fun AccountSettingsScreen( modifier = Modifier .fillMaxSize() .padding(innerPadding), - viewModel = viewModel, ) } } @@ -117,6 +116,7 @@ fun AccountSettingsContent( viewModel: SettingsViewModel = koinViewModel(), ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val currentOnLogout by rememberUpdatedState(onLogout) var showDeleteDialog by remember { mutableStateOf(false) } var showLogoutDialog by remember { mutableStateOf(false) } @@ -135,22 +135,21 @@ fun AccountSettingsContent( LaunchedEffect(uiState.isLoggedOut, uiState.isAccountDeleted) { if (uiState.isLoggedOut || uiState.isAccountDeleted) { - onLogout() + currentOnLogout() } } - Column { + Column(modifier = modifier) { if (uiState.isLoading && uiState.user == null) { LoadingIndicator() } else if (uiState.error != null && uiState.user == null) { ErrorBanner( message = uiState.error ?: stringResource(Res.string.error_could_not_load_settings), - modifier = modifier, onRetry = { viewModel.retry() }, ) } else { LazyColumn( - modifier = modifier.fillMaxSize(), + modifier = Modifier.fillMaxSize(), ) { // Account section item(key = "account_header") { diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/ApiKeyCreateDialog.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/ApiKeyCreateDialog.kt index f193ff9..09840bc 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/ApiKeyCreateDialog.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/ApiKeyCreateDialog.kt @@ -22,14 +22,14 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource -import com.garfiec.librechat.feature.settings.util.copyToClipboard import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.model.ApiKey -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res +import com.garfiec.librechat.feature.settings.util.copyToClipboard +import org.jetbrains.compose.resources.stringResource /** * Two-phase API key creation dialog. diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/ApiKeysScreen.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/ApiKeysScreen.kt index 0cc6db9..3bad53e 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/ApiKeysScreen.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/ApiKeysScreen.kt @@ -20,6 +20,7 @@ import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Key import androidx.compose.material3.AlertDialog +import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.CircularProgressIndicator @@ -31,7 +32,6 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState -import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBar @@ -44,14 +44,14 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.garfiec.librechat.core.model.ApiKey -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res import com.garfiec.librechat.feature.settings.viewmodel.ApiKeysViewModel +import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel /** Lists user API keys with create (FAB), delete, and pull-to-refresh. */ diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/BalanceSection.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/BalanceSection.kt index 3833628..f353eb1 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/BalanceSection.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/BalanceSection.kt @@ -20,12 +20,12 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res +import org.jetbrains.compose.resources.stringResource @Composable internal fun BalanceSection( diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/ChatSettingsScreen.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/ChatSettingsScreen.kt index 066ff9f..49392cf 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/ChatSettingsScreen.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/ChatSettingsScreen.kt @@ -33,14 +33,14 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res import com.garfiec.librechat.feature.settings.viewmodel.SettingsViewModel +import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel @OptIn(ExperimentalMaterial3Api::class) @@ -49,7 +49,6 @@ fun ChatSettingsScreen( onNavigateBack: () -> Unit, onNavigateToPresets: () -> Unit, modifier: Modifier = Modifier, - viewModel: SettingsViewModel = koinViewModel(), ) { Scaffold( modifier = modifier, @@ -72,7 +71,6 @@ fun ChatSettingsScreen( modifier = Modifier .fillMaxSize() .padding(innerPadding), - viewModel = viewModel, ) } } @@ -89,9 +87,9 @@ fun ChatSettingsContent( ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() - Box { + Box(modifier = modifier) { LazyColumn( - modifier = modifier.fillMaxSize(), + modifier = Modifier.fillMaxSize(), ) { // Chat Preferences section item(key = "chat_header") { @@ -167,7 +165,7 @@ fun ChatSettingsContent( ttsSource = uiState.ttsSource, onAutoSendAfterSttChange = viewModel::setAutoSendAfterStt, onAutoReadChange = viewModel::setAutoReadEnabled, - onVoiceSelected = viewModel::selectVoice, + onVoiceSelect = viewModel::selectVoice, onTestVoice = viewModel::testVoice, ) } @@ -186,7 +184,7 @@ fun ChatSettingsContent( if (uiState.showForkSettingsDialog) { ForkSettingsDialog( selectedMode = ForkMode.fromApiValue(uiState.forkMode), - onModeSelected = { mode -> + onModeSelect = { mode -> viewModel.setForkMode(mode.apiValue) }, onDismiss = viewModel::dismissForkSettingsDialog, diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/ChatSettingsSection.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/ChatSettingsSection.kt index 5c638eb..f197ea0 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/ChatSettingsSection.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/ChatSettingsSection.kt @@ -18,14 +18,14 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.common.ChatLayoutConstants import com.garfiec.librechat.core.data.datastore.ChatFontSize import com.garfiec.librechat.core.data.datastore.LatexRenderer -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res +import org.jetbrains.compose.resources.stringResource @Composable internal fun ChatSettingsSection( diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/CommandsConfigScreen.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/CommandsConfigScreen.kt index f41e346..084c007 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/CommandsConfigScreen.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/CommandsConfigScreen.kt @@ -23,10 +23,10 @@ import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res +import org.jetbrains.compose.resources.stringResource data class CommandConfig( val name: String, diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/DataSettingsScreen.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/DataSettingsScreen.kt index ea3ce11..a6220b3 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/DataSettingsScreen.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/DataSettingsScreen.kt @@ -35,24 +35,23 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res import com.garfiec.librechat.feature.settings.viewmodel.SettingsViewModel +import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel @OptIn(ExperimentalMaterial3Api::class) @Composable fun DataSettingsScreen( onNavigateBack: () -> Unit, - onNavigateToArchived: () -> Unit, + onNavigateToArchive: () -> Unit, onNavigateToSharedLinks: () -> Unit, modifier: Modifier = Modifier, - viewModel: SettingsViewModel = koinViewModel(), ) { val snackbarHostState = remember { SnackbarHostState() } @@ -74,13 +73,12 @@ fun DataSettingsScreen( }, ) { innerPadding -> DataSettingsContent( - onNavigateToArchived = onNavigateToArchived, + onNavigateToArchive = onNavigateToArchive, onNavigateToSharedLinks = onNavigateToSharedLinks, snackbarHostState = snackbarHostState, modifier = Modifier .fillMaxSize() .padding(innerPadding), - viewModel = viewModel, ) } } @@ -91,7 +89,7 @@ fun DataSettingsScreen( */ @Composable fun DataSettingsContent( - onNavigateToArchived: () -> Unit, + onNavigateToArchive: () -> Unit, onNavigateToSharedLinks: () -> Unit, modifier: Modifier = Modifier, snackbarHostState: SnackbarHostState = remember { SnackbarHostState() }, @@ -121,9 +119,9 @@ fun DataSettingsContent( viewModel.dismissMcpReinitializeMessage() } - Column { + Column(modifier = modifier) { LazyColumn( - modifier = modifier.fillMaxSize(), + modifier = Modifier.fillMaxSize(), ) { // Conversations section item(key = "conversations_header") { @@ -134,7 +132,7 @@ fun DataSettingsContent( archivedCount = uiState.archivedCount, isClearing = uiState.isClearing, onClearAllChats = viewModel::clearAllChats, - onViewArchived = onNavigateToArchived, + onViewArchive = onNavigateToArchive, onExportAllData = viewModel::exportAllData, ) } @@ -158,7 +156,7 @@ fun DataSettingsContent( memoriesEnabled = uiState.memoriesEnabled, showMemoryDialog = uiState.showMemoryDialog, editingMemory = uiState.editingMemory, - onToggleEnabled = viewModel::toggleMemoriesEnabled, + onToggleEnable = viewModel::toggleMemoriesEnabled, onAddMemory = viewModel::showAddMemoryDialog, onEditMemory = viewModel::showEditMemoryDialog, onDeleteMemory = viewModel::deleteMemory, diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/DataSettingsSection.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/DataSettingsSection.kt index 6666e18..36dd3e5 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/DataSettingsSection.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/DataSettingsSection.kt @@ -27,17 +27,17 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res +import org.jetbrains.compose.resources.stringResource @Composable internal fun DataSettingsSection( archivedCount: Int, isClearing: Boolean, onClearAllChats: () -> Unit, - onViewArchived: () -> Unit, + onViewArchive: () -> Unit, onExportAllData: () -> Unit, modifier: Modifier = Modifier, ) { @@ -65,7 +65,7 @@ internal fun DataSettingsSection( // Archived conversations OutlinedButton( - onClick = onViewArchived, + onClick = onViewArchive, modifier = Modifier.fillMaxWidth(), ) { Row( diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/ForkSettingsDialog.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/ForkSettingsDialog.kt index 448022b..6d8d8b5 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/ForkSettingsDialog.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/ForkSettingsDialog.kt @@ -21,12 +21,12 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.model.request.ForkOption -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res +import org.jetbrains.compose.resources.stringResource enum class ForkMode(val label: String, val description: String, val apiValue: String) { DIRECT_PATH( @@ -54,7 +54,7 @@ enum class ForkMode(val label: String, val description: String, val apiValue: St @Composable internal fun ForkSettingsDialog( selectedMode: ForkMode, - onModeSelected: (ForkMode) -> Unit, + onModeSelect: (ForkMode) -> Unit, onDismiss: () -> Unit, modifier: Modifier = Modifier, ) { @@ -100,7 +100,7 @@ internal fun ForkSettingsDialog( } }, confirmButton = { - TextButton(onClick = { onModeSelected(currentMode) }) { + TextButton(onClick = { onModeSelect(currentMode) }) { Text(stringResource(Res.string.action_save)) } }, diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/GeneralSettingsScreen.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/GeneralSettingsScreen.kt index 1e4a171..233ee8e 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/GeneralSettingsScreen.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/GeneralSettingsScreen.kt @@ -36,7 +36,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.vector.ImageVector -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics @@ -44,9 +43,10 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.garfiec.librechat.core.data.datastore.ThemeMode -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res import com.garfiec.librechat.feature.settings.viewmodel.SettingsViewModel +import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel @OptIn(ExperimentalMaterial3Api::class) @@ -54,7 +54,6 @@ import org.koin.compose.viewmodel.koinViewModel fun GeneralSettingsScreen( onNavigateBack: () -> Unit, modifier: Modifier = Modifier, - viewModel: SettingsViewModel = koinViewModel(), ) { Scaffold( modifier = modifier, @@ -76,7 +75,6 @@ fun GeneralSettingsScreen( modifier = Modifier .fillMaxSize() .padding(innerPadding), - viewModel = viewModel, ) } } @@ -92,9 +90,9 @@ fun GeneralSettingsContent( ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() - Column { + Column(modifier = modifier) { LazyColumn( - modifier = modifier.fillMaxSize(), + modifier = Modifier.fillMaxSize(), ) { // Appearance section item(key = "appearance_header") { @@ -164,7 +162,7 @@ fun GeneralSettingsContent( if (uiState.showLanguageDialog) { LanguageSelectorDialog( selectedLanguage = uiState.selectedLanguage, - onLanguageSelected = viewModel::setLanguage, + onLanguageSelect = viewModel::setLanguage, onDismiss = viewModel::dismissLanguageDialog, ) } diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/LanguageSelectorDialog.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/LanguageSelectorDialog.kt index 93b4e15..944ee5d 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/LanguageSelectorDialog.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/LanguageSelectorDialog.kt @@ -25,10 +25,10 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res +import org.jetbrains.compose.resources.stringResource data class LanguageOption( val code: String, @@ -80,7 +80,7 @@ private val SUPPORTED_LANGUAGES = listOf( @Composable internal fun LanguageSelectorDialog( selectedLanguage: String, - onLanguageSelected: (String) -> Unit, + onLanguageSelect: (String) -> Unit, onDismiss: () -> Unit, modifier: Modifier = Modifier, ) { @@ -120,7 +120,7 @@ internal fun LanguageSelectorDialog( Row( modifier = Modifier .fillMaxWidth() - .clickable { onLanguageSelected(language.code) } + .clickable { onLanguageSelect(language.code) } .padding(vertical = 12.dp, horizontal = 4.dp), verticalAlignment = Alignment.CenterVertically, ) { diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/McpServerDialog.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/McpServerDialog.kt index ad9f597..ca7cc51 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/McpServerDialog.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/McpServerDialog.kt @@ -37,8 +37,8 @@ import com.garfiec.librechat.core.model.mcp.McpAuthorizationType import com.garfiec.librechat.core.model.mcp.McpOAuthConfig import com.garfiec.librechat.core.model.mcp.McpServer import com.garfiec.librechat.core.model.mcp.McpServerType -import librechat_mobile.feature.settings.generated.resources.* -import librechat_mobile.feature.settings.generated.resources.Res +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res import org.jetbrains.compose.resources.stringResource /** Add/edit MCP server dialog with server type dropdown and auth configuration. */ diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/McpServersScreen.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/McpServersScreen.kt index 22ec819..953f572 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/McpServersScreen.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/McpServersScreen.kt @@ -45,7 +45,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -53,9 +52,10 @@ import com.garfiec.librechat.core.model.mcp.McpServer import com.garfiec.librechat.core.model.mcp.McpServerStatus import com.garfiec.librechat.core.ui.components.ErrorBanner import com.garfiec.librechat.core.ui.components.LoadingIndicator -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res import com.garfiec.librechat.feature.settings.viewmodel.McpViewModel +import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel /** Manages MCP server connections with status indicators, CRUD, and tool browsing. */ diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/McpSettingsSection.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/McpSettingsSection.kt index d62a26c..44a5255 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/McpSettingsSection.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/McpSettingsSection.kt @@ -25,13 +25,13 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.model.mcp.McpServer import com.garfiec.librechat.core.model.mcp.McpServerStatus -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res +import org.jetbrains.compose.resources.stringResource @Composable internal fun McpSettingsSection( diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/McpToolList.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/McpToolList.kt index 289dda4..6137518 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/McpToolList.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/McpToolList.kt @@ -27,11 +27,11 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.model.mcp.McpTool -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res +import org.jetbrains.compose.resources.stringResource @Composable internal fun McpToolList( diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/McpToolsSheet.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/McpToolsSheet.kt index 0601ddf..fffbd45 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/McpToolsSheet.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/McpToolsSheet.kt @@ -16,13 +16,13 @@ import androidx.compose.material3.Text import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.model.mcp.McpTool -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res +import org.jetbrains.compose.resources.stringResource /** Bottom sheet listing MCP tools grouped by server; optional serverFilter narrows to one server. */ @OptIn(ExperimentalMaterial3Api::class) diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/MemoriesScreen.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/MemoriesScreen.kt index 39dabef..a56bad4 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/MemoriesScreen.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/MemoriesScreen.kt @@ -43,7 +43,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextOverflow @@ -52,9 +51,10 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.garfiec.librechat.core.model.Memory import com.garfiec.librechat.core.ui.components.ErrorBanner import com.garfiec.librechat.core.ui.components.LoadingIndicator -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res import com.garfiec.librechat.feature.settings.viewmodel.MemoriesViewModel +import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel /** Full memory CRUD screen with PullToRefresh and dedicated MemoriesViewModel. */ diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/MemoriesSettingsSection.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/MemoriesSettingsSection.kt index db65c7a..870cad2 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/MemoriesSettingsSection.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/MemoriesSettingsSection.kt @@ -31,14 +31,14 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.model.Memory -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res +import org.jetbrains.compose.resources.stringResource @Composable internal fun MemoriesSettingsSection( @@ -46,7 +46,7 @@ internal fun MemoriesSettingsSection( memoriesEnabled: Boolean, showMemoryDialog: Boolean, editingMemory: Memory?, - onToggleEnabled: (Boolean) -> Unit, + onToggleEnable: (Boolean) -> Unit, onAddMemory: () -> Unit, onEditMemory: (Memory) -> Unit, onDeleteMemory: (String) -> Unit, @@ -81,7 +81,7 @@ internal fun MemoriesSettingsSection( val toggleMemoriesCd = stringResource(Res.string.cd_toggle_memories) Switch( checked = memoriesEnabled, - onCheckedChange = onToggleEnabled, + onCheckedChange = onToggleEnable, modifier = Modifier.semantics { contentDescription = toggleMemoriesCd }, diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/MemoryEditDialog.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/MemoryEditDialog.kt index 2d530ba..1d0d3cb 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/MemoryEditDialog.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/MemoryEditDialog.kt @@ -14,11 +14,11 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.model.Memory -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res +import org.jetbrains.compose.resources.stringResource /** Add/edit memory dialog; key field is immutable when editing an existing memory. */ @Composable diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/PersonalizationDialog.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/PersonalizationDialog.kt index 00e1186..5ebee6d 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/PersonalizationDialog.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/PersonalizationDialog.kt @@ -20,10 +20,10 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res +import org.jetbrains.compose.resources.stringResource /** "About you" and "Response style" text areas with enable toggle; fields disabled when off. */ @Composable diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/PresetManagerScreen.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/PresetManagerScreen.kt index d6b9242..bf8920f 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/PresetManagerScreen.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/PresetManagerScreen.kt @@ -35,16 +35,16 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.garfiec.librechat.core.ui.components.EmptyState import com.garfiec.librechat.core.ui.components.LoadingIndicator import com.garfiec.librechat.feature.settings.model.PresetManagerDisplayData -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res import com.garfiec.librechat.feature.settings.viewmodel.PresetManagerViewModel +import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel /** Lists saved presets with delete-only management; editing reuses SavePresetDialog in chat. */ diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/SecuritySection.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/SecuritySection.kt index 7c79632..52361b6 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/SecuritySection.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/SecuritySection.kt @@ -20,10 +20,10 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res +import org.jetbrains.compose.resources.stringResource @Composable internal fun SecuritySection( diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/SettingsScreen.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/SettingsScreen.kt index 9947a4e..a16dae8 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/SettingsScreen.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/SettingsScreen.kt @@ -30,9 +30,9 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp @@ -40,8 +40,8 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.garfiec.librechat.core.ui.components.ErrorBanner import com.garfiec.librechat.core.ui.components.LoadingIndicator import com.garfiec.librechat.core.ui.components.OtpVerificationDialog -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res import com.garfiec.librechat.feature.settings.screen.sections.AboutInfo import com.garfiec.librechat.feature.settings.screen.sections.AccountInfo import com.garfiec.librechat.feature.settings.screen.sections.BackupCodesDialog @@ -54,6 +54,7 @@ import com.garfiec.librechat.feature.settings.screen.sections.ThemeSelector import com.garfiec.librechat.feature.settings.screen.sections.TwoFactorCodeDialog import com.garfiec.librechat.feature.settings.screen.sections.TwoFactorSetupDialog import com.garfiec.librechat.feature.settings.viewmodel.SettingsViewModel +import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel @OptIn(ExperimentalMaterial3Api::class) @@ -61,13 +62,14 @@ import org.koin.compose.viewmodel.koinViewModel fun SettingsScreen( onLogout: () -> Unit, onNavigateBack: () -> Unit, - onNavigateToArchived: () -> Unit, + onNavigateToArchive: () -> Unit, modifier: Modifier = Modifier, onNavigateToSharedLinks: () -> Unit = {}, onNavigateToApiKeys: () -> Unit = {}, viewModel: SettingsViewModel = koinViewModel(), ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val currentOnLogout by rememberUpdatedState(onLogout) var showDeleteDialog by remember { mutableStateOf(false) } var showLogoutDialog by remember { mutableStateOf(false) } @@ -102,7 +104,7 @@ fun SettingsScreen( LaunchedEffect(uiState.isLoggedOut, uiState.isAccountDeleted) { if (uiState.isLoggedOut || uiState.isAccountDeleted) { - onLogout() + currentOnLogout() } } @@ -269,7 +271,7 @@ fun SettingsScreen( ttsSource = uiState.ttsSource, onAutoSendAfterSttChange = viewModel::setAutoSendAfterStt, onAutoReadChange = viewModel::setAutoReadEnabled, - onVoiceSelected = viewModel::selectVoice, + onVoiceSelect = viewModel::selectVoice, onTestVoice = viewModel::testVoice, ) } @@ -290,7 +292,7 @@ fun SettingsScreen( memoriesEnabled = uiState.memoriesEnabled, showMemoryDialog = uiState.showMemoryDialog, editingMemory = uiState.editingMemory, - onToggleEnabled = viewModel::toggleMemoriesEnabled, + onToggleEnable = viewModel::toggleMemoriesEnabled, onAddMemory = viewModel::showAddMemoryDialog, onEditMemory = viewModel::showEditMemoryDialog, onDeleteMemory = viewModel::deleteMemory, @@ -308,7 +310,7 @@ fun SettingsScreen( archivedCount = uiState.archivedCount, isClearing = uiState.isClearing, onClearAllChats = viewModel::clearAllChats, - onViewArchived = onNavigateToArchived, + onViewArchive = onNavigateToArchive, onExportAllData = viewModel::exportAllData, ) } @@ -634,7 +636,7 @@ fun SettingsScreen( if (uiState.showLanguageDialog) { LanguageSelectorDialog( selectedLanguage = uiState.selectedLanguage, - onLanguageSelected = viewModel::setLanguage, + onLanguageSelect = viewModel::setLanguage, onDismiss = viewModel::dismissLanguageDialog, ) } @@ -643,7 +645,7 @@ fun SettingsScreen( if (uiState.showForkSettingsDialog) { ForkSettingsDialog( selectedMode = ForkMode.fromApiValue(uiState.forkMode), - onModeSelected = { mode -> + onModeSelect = { mode -> viewModel.setForkMode(mode.apiValue) }, onDismiss = viewModel::dismissForkSettingsDialog, diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/SharedLinksScreen.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/SharedLinksScreen.kt index d60c156..60b94db 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/SharedLinksScreen.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/SharedLinksScreen.kt @@ -1,6 +1,5 @@ package com.garfiec.librechat.feature.settings.screen -import com.garfiec.librechat.feature.settings.util.copyToClipboard import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -41,17 +40,19 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.ui.components.EmptyState -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* import com.garfiec.librechat.feature.settings.model.SharedLinkDisplayData +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res +import com.garfiec.librechat.feature.settings.util.copyToClipboard +import org.jetbrains.compose.resources.stringResource @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -69,6 +70,7 @@ fun SharedLinksScreen( val snackbarHostState = remember { SnackbarHostState() } val listState = rememberLazyListState() var deleteTarget by remember { mutableStateOf(null) } + val currentOnLoadMore by rememberUpdatedState(onLoadMore) // Pagination: load more when near the end LaunchedEffect(listState) { @@ -79,7 +81,7 @@ fun SharedLinksScreen( lastVisible >= totalItems - 3 }.collect { shouldLoad -> if (shouldLoad && hasNextPage && !isLoading) { - onLoadMore() + currentOnLoadMore() } } } diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/SpeechDetailDialogs.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/SpeechDetailDialogs.kt index d05f00d..181c904 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/SpeechDetailDialogs.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/SpeechDetailDialogs.kt @@ -33,12 +33,12 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res +import org.jetbrains.compose.resources.stringResource @OptIn(ExperimentalMaterial3Api::class) @Composable diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/SpeechSettingsSection.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/SpeechSettingsSection.kt index b698cba..b7eb664 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/SpeechSettingsSection.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/SpeechSettingsSection.kt @@ -25,13 +25,13 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.model.speech.TtsVoice -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res +import org.jetbrains.compose.resources.stringResource @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -43,7 +43,7 @@ internal fun SpeechSettingsSection( ttsSource: String, onAutoSendAfterSttChange: (Boolean) -> Unit, onAutoReadChange: (Boolean) -> Unit, - onVoiceSelected: (TtsVoice) -> Unit, + onVoiceSelect: (TtsVoice) -> Unit, onTestVoice: () -> Unit, modifier: Modifier = Modifier, ) { @@ -162,7 +162,7 @@ internal fun SpeechSettingsSection( } }, onClick = { - onVoiceSelected(voice) + onVoiceSelect(voice) expanded = false }, ) diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/TabbedSettingsScreen.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/TabbedSettingsScreen.kt index 01d96cc..f56f06b 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/TabbedSettingsScreen.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/TabbedSettingsScreen.kt @@ -22,12 +22,10 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* -import com.garfiec.librechat.feature.settings.viewmodel.SettingsViewModel +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res import kotlinx.coroutines.launch -import org.koin.compose.viewmodel.koinViewModel +import org.jetbrains.compose.resources.stringResource private val SettingsTabs = listOf("General", "Chat", "Account", "Data") @@ -41,12 +39,11 @@ private val SettingsTabs = listOf("General", "Chat", "Account", "Data") fun TabbedSettingsScreen( onNavigateBack: () -> Unit, onLogout: () -> Unit, - onNavigateToArchived: () -> Unit, + onNavigateToArchive: () -> Unit, onNavigateToSharedLinks: () -> Unit, onNavigateToPresets: () -> Unit, onNavigateToApiKeys: () -> Unit, modifier: Modifier = Modifier, - viewModel: SettingsViewModel = koinViewModel(), ) { val pagerState = rememberPagerState(pageCount = { SettingsTabs.size }) val scope = rememberCoroutineScope() @@ -97,26 +94,22 @@ fun TabbedSettingsScreen( when (page) { 0 -> GeneralSettingsContent( modifier = Modifier.fillMaxSize(), - viewModel = viewModel, ) 1 -> ChatSettingsContent( onNavigateToPresets = onNavigateToPresets, modifier = Modifier.fillMaxSize(), - viewModel = viewModel, ) 2 -> AccountSettingsContent( onLogout = onLogout, onNavigateToApiKeys = onNavigateToApiKeys, snackbarHostState = snackbarHostState, modifier = Modifier.fillMaxSize(), - viewModel = viewModel, ) 3 -> DataSettingsContent( - onNavigateToArchived = onNavigateToArchived, + onNavigateToArchive = onNavigateToArchive, onNavigateToSharedLinks = onNavigateToSharedLinks, snackbarHostState = snackbarHostState, modifier = Modifier.fillMaxSize(), - viewModel = viewModel, ) } } diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/sections/AccountSection.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/sections/AccountSection.kt index a45320f..6efd945 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/sections/AccountSection.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/sections/AccountSection.kt @@ -22,12 +22,12 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.ContentScale -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import coil3.compose.AsyncImage -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res +import org.jetbrains.compose.resources.stringResource @Composable internal fun AccountInfo( diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/sections/AppearanceSection.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/sections/AppearanceSection.kt index 3fa45fb..676976d 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/sections/AppearanceSection.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/sections/AppearanceSection.kt @@ -21,12 +21,12 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.unit.dp import com.garfiec.librechat.core.data.datastore.ThemeMode -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res +import org.jetbrains.compose.resources.stringResource @Composable internal fun ThemeSelector( diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/sections/ChatPreferencesSection.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/sections/ChatPreferencesSection.kt index e4b6418..2fbde6b 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/sections/ChatPreferencesSection.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/sections/ChatPreferencesSection.kt @@ -23,11 +23,11 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res +import org.jetbrains.compose.resources.stringResource @Composable internal fun AboutInfo(serverUrl: String) { diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/sections/DataManagementSection.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/sections/DataManagementSection.kt index 59f6cba..fcfbf19 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/sections/DataManagementSection.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/sections/DataManagementSection.kt @@ -17,10 +17,10 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res +import org.jetbrains.compose.resources.stringResource @Composable internal fun DataExtraActions( diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/sections/SecuritySection.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/sections/SecuritySection.kt index 7f563bd..9f8ace7 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/sections/SecuritySection.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/sections/SecuritySection.kt @@ -19,11 +19,11 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.unit.dp -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res +import org.jetbrains.compose.resources.stringResource @Composable internal fun TwoFactorSetupDialog( diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/sections/SpeechSection.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/sections/SpeechSection.kt index 0af7a78..6820f3f 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/sections/SpeechSection.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/screen/sections/SpeechSection.kt @@ -15,10 +15,10 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp -import librechat_mobile.feature.settings.generated.resources.Res -import librechat_mobile.feature.settings.generated.resources.* +import com.garfiec.librechat.feature.settings.resources.* +import com.garfiec.librechat.feature.settings.resources.Res +import org.jetbrains.compose.resources.stringResource @Composable internal fun SpeechDetailButtons( diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/viewmodel/McpViewModel.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/viewmodel/McpViewModel.kt index 7c40be4..cfe00a6 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/viewmodel/McpViewModel.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/viewmodel/McpViewModel.kt @@ -3,6 +3,7 @@ package com.garfiec.librechat.feature.settings.viewmodel import androidx.compose.runtime.Immutable import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import co.touchlab.kermit.Logger import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.data.repository.McpRepository import com.garfiec.librechat.core.model.mcp.McpApiKeyConfig @@ -15,7 +16,6 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch -import co.touchlab.kermit.Logger @Immutable data class McpUiState( diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/viewmodel/SettingsViewModel.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/viewmodel/SettingsViewModel.kt index 1b1b414..213a186 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/viewmodel/SettingsViewModel.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/viewmodel/SettingsViewModel.kt @@ -1,10 +1,9 @@ package com.garfiec.librechat.feature.settings.viewmodel import androidx.compose.runtime.Immutable -import com.garfiec.librechat.feature.settings.util.ContentReader -import com.garfiec.librechat.feature.settings.util.PlatformCacheCleaner import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import co.touchlab.kermit.Logger import com.garfiec.librechat.core.common.ChatLayoutConstants import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.data.datastore.ChatFontSize @@ -20,7 +19,6 @@ import com.garfiec.librechat.core.data.repository.KeyRepository import com.garfiec.librechat.core.data.repository.McpRepository import com.garfiec.librechat.core.data.repository.MemoryRepository import com.garfiec.librechat.core.data.repository.ShareRepository -import com.garfiec.librechat.core.data.repository.SpeechRepository import com.garfiec.librechat.core.data.repository.UserRepository import com.garfiec.librechat.core.model.Memory import com.garfiec.librechat.core.model.User @@ -33,6 +31,8 @@ import com.garfiec.librechat.core.model.speech.TtsVoice import com.garfiec.librechat.feature.settings.model.SharedLinkDisplayData import com.garfiec.librechat.feature.settings.model.UserDisplayData import com.garfiec.librechat.feature.settings.screen.DeviceVoiceInfo +import com.garfiec.librechat.feature.settings.util.ContentReader +import com.garfiec.librechat.feature.settings.util.PlatformCacheCleaner import com.garfiec.librechat.feature.settings.viewmodel.delegate.DataManagementDelegate import com.garfiec.librechat.feature.settings.viewmodel.delegate.McpServerDelegate import com.garfiec.librechat.feature.settings.viewmodel.delegate.MemoryManagementDelegate @@ -45,7 +45,6 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import co.touchlab.kermit.Logger data class SettingsCommand( val name: String, diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/viewmodel/delegate/DataManagementDelegate.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/viewmodel/delegate/DataManagementDelegate.kt index 7533235..2e92087 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/viewmodel/delegate/DataManagementDelegate.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/viewmodel/delegate/DataManagementDelegate.kt @@ -1,12 +1,12 @@ package com.garfiec.librechat.feature.settings.viewmodel.delegate import com.garfiec.librechat.core.common.result.Result -import com.garfiec.librechat.feature.settings.util.PlatformCacheCleaner import com.garfiec.librechat.core.data.repository.ConversationRepository import com.garfiec.librechat.core.data.repository.KeyRepository import com.garfiec.librechat.core.data.repository.ShareRepository import com.garfiec.librechat.core.model.SharedLink import com.garfiec.librechat.feature.settings.model.SharedLinkDisplayData +import com.garfiec.librechat.feature.settings.util.PlatformCacheCleaner import com.garfiec.librechat.feature.settings.viewmodel.SettingsStateHandle import kotlinx.coroutines.launch diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/viewmodel/delegate/McpServerDelegate.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/viewmodel/delegate/McpServerDelegate.kt index d8a2b10..2566685 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/viewmodel/delegate/McpServerDelegate.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/viewmodel/delegate/McpServerDelegate.kt @@ -1,5 +1,6 @@ package com.garfiec.librechat.feature.settings.viewmodel.delegate +import co.touchlab.kermit.Logger import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.data.repository.McpRepository import com.garfiec.librechat.core.model.mcp.McpApiKeyConfig @@ -8,7 +9,6 @@ import com.garfiec.librechat.core.model.mcp.McpServer import com.garfiec.librechat.core.model.mcp.McpServerType import com.garfiec.librechat.feature.settings.viewmodel.SettingsStateHandle import kotlinx.coroutines.launch -import co.touchlab.kermit.Logger /** * Handles MCP server management, connection status, and reinitialization. diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/viewmodel/delegate/MemoryManagementDelegate.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/viewmodel/delegate/MemoryManagementDelegate.kt index 961c3b0..1727cec 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/viewmodel/delegate/MemoryManagementDelegate.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/viewmodel/delegate/MemoryManagementDelegate.kt @@ -1,5 +1,6 @@ package com.garfiec.librechat.feature.settings.viewmodel.delegate +import co.touchlab.kermit.Logger import com.garfiec.librechat.core.common.result.Result import com.garfiec.librechat.core.data.repository.MemoryRepository import com.garfiec.librechat.core.model.Memory @@ -8,7 +9,6 @@ import com.garfiec.librechat.core.model.request.UpdateMemoryPreferencesRequest import com.garfiec.librechat.core.model.request.UpdateMemoryRequest import com.garfiec.librechat.feature.settings.viewmodel.SettingsStateHandle import kotlinx.coroutines.launch -import co.touchlab.kermit.Logger /** * Handles memory CRUD operations and memory preferences. diff --git a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/viewmodel/delegate/TwoFactorSecurityDelegate.kt b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/viewmodel/delegate/TwoFactorSecurityDelegate.kt index fcbb1b3..0d88913 100644 --- a/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/viewmodel/delegate/TwoFactorSecurityDelegate.kt +++ b/feature/settings/src/commonMain/kotlin/com/garfiec/librechat/feature/settings/viewmodel/delegate/TwoFactorSecurityDelegate.kt @@ -1,9 +1,9 @@ package com.garfiec.librechat.feature.settings.viewmodel.delegate import com.garfiec.librechat.core.common.result.Result -import com.garfiec.librechat.feature.settings.viewmodel.isHttpStatus import com.garfiec.librechat.core.data.repository.AuthRepository import com.garfiec.librechat.feature.settings.viewmodel.SettingsStateHandle +import com.garfiec.librechat.feature.settings.viewmodel.isHttpStatus import kotlinx.coroutines.launch /** diff --git a/shared/detekt-baseline.xml b/shared/detekt-baseline.xml deleted file mode 100644 index 248b25b..0000000 --- a/shared/detekt-baseline.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - ComposableParamOrder:LibreChatNavHost.kt$MainNavDisplay - FunctionNaming:String0.commonMain.kt$@InternalResourceApi internal fun _collectCommonMainString0Resources(map: MutableMap<String, StringResource>) - ImportOrdering:DrawerDisplayMapping.kt$import com.garfiec.librechat.core.common.extensions.toInstantOrNull import com.garfiec.librechat.core.common.extensions.formatMonthAbbrev import com.garfiec.librechat.core.model.Conversation import kotlin.time.Clock import kotlin.time.Instant import kotlinx.datetime.TimeZone import kotlinx.datetime.toLocalDateTime - ImportOrdering:ExpectResourceCollectors.kt$import kotlin.String import kotlin.collections.Map import org.jetbrains.compose.resources.DrawableResource import org.jetbrains.compose.resources.FontResource import org.jetbrains.compose.resources.PluralStringResource import org.jetbrains.compose.resources.StringArrayResource import org.jetbrains.compose.resources.StringResource - ImportOrdering:LibreChatNavHost.kt$import androidx.compose.animation.core.FastOutSlowInEasing import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.scaleIn import androidx.compose.animation.scaleOut import androidx.compose.animation.slideInHorizontally import androidx.compose.animation.slideOutHorizontally import androidx.compose.animation.togetherWith import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.material3.AlertDialog import androidx.compose.material3.DrawerValue import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalDrawerSheet import androidx.compose.material3.ModalNavigationDrawer import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.rememberDrawerState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation3.runtime.NavKey import androidx.navigation3.runtime.entryProvider import androidx.navigation3.runtime.rememberNavBackStack import androidx.navigation3.ui.NavDisplay import androidx.navigation3.runtime.rememberSaveableStateHolderNavEntryDecorator import androidx.lifecycle.viewmodel.navigation3.rememberViewModelStoreNavEntryDecorator import com.garfiec.librechat.core.ui.components.BannerDisplay import com.garfiec.librechat.feature.agents.navigation.AgentMarketplace import com.garfiec.librechat.feature.agents.navigation.agentsEntries import com.garfiec.librechat.feature.auth.navigation.AuthRoute import com.garfiec.librechat.feature.auth.navigation.ServerUrl import com.garfiec.librechat.feature.auth.navigation.authEntries import com.garfiec.librechat.feature.chat.navigation.Chat import com.garfiec.librechat.feature.chat.navigation.NewChat import com.garfiec.librechat.feature.chat.navigation.chatEntries import com.garfiec.librechat.feature.conversations.navigation.ArchivedConversations import com.garfiec.librechat.feature.conversations.navigation.conversationsEntries import com.garfiec.librechat.feature.files.navigation.Files import com.garfiec.librechat.feature.files.navigation.filesEntries import com.garfiec.librechat.feature.settings.navigation.SettingsTabbed import com.garfiec.librechat.feature.settings.navigation.memoriesEntry import com.garfiec.librechat.feature.settings.navigation.mcpServersEntry import com.garfiec.librechat.feature.settings.navigation.settingsEntries import kotlinx.coroutines.launch import librechat_mobile.shared.generated.resources.Res import librechat_mobile.shared.generated.resources.dismiss import librechat_mobile.shared.generated.resources.dont_warn_again import librechat_mobile.shared.generated.resources.version_mismatch_message import librechat_mobile.shared.generated.resources.version_mismatch_title import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel - ImportOrdering:NavHostViewModel.kt$import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.garfiec.librechat.core.data.repository.AuthRepository import com.garfiec.librechat.core.data.repository.BannerRepository import com.garfiec.librechat.core.data.datastore.SettingsDataStore import com.garfiec.librechat.core.data.repository.ConfigRepository import com.garfiec.librechat.core.data.repository.ConversationRepository import com.garfiec.librechat.core.model.Banner import com.garfiec.librechat.core.network.client.TokenManager import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import co.touchlab.kermit.Logger import com.garfiec.librechat.core.common.extensions.firstBlocking - ImportOrdering:Res.kt$import kotlin.ByteArray import kotlin.OptIn import kotlin.String import kotlin.Suppress import org.jetbrains.compose.resources.InternalResourceApi import org.jetbrains.compose.resources.getResourceUri import org.jetbrains.compose.resources.readResourceBytes - ImportOrdering:String0.commonMain.kt$import kotlin.OptIn import kotlin.String import kotlin.collections.MutableMap import org.jetbrains.compose.resources.InternalResourceApi import org.jetbrains.compose.resources.ResourceContentHash import org.jetbrains.compose.resources.ResourceItem import org.jetbrains.compose.resources.StringResource - LambdaParameterInRestartableEffect:DrawerContent.kt$onLoadMore - MaxLineLength:NavHostViewModel.kt$NavHostViewModel$private val favoritesStateHolder = FavoritesStateHolder(settingsDataStore, conversationListStateHolder.recentConversations, viewModelScope) - MaxLineLength:Res.kt$Res$public suspend - NoUnusedImports:LibreChatNavHost.kt$com.garfiec.librechat.shared.navigation.LibreChatNavHost.kt - PackageName:ExpectResourceCollectors.kt$package librechat_mobile.shared.generated.resources - PackageName:Res.kt$package librechat_mobile.shared.generated.resources - PackageName:String0.commonMain.kt$package librechat_mobile.shared.generated.resources - PackageNaming:ExpectResourceCollectors.kt$package librechat_mobile.shared.generated.resources - PackageNaming:Res.kt$package librechat_mobile.shared.generated.resources - PackageNaming:String0.commonMain.kt$package librechat_mobile.shared.generated.resources - ParameterNaming:DrawerContent.kt$onSearchQueryChanged - ParameterNaming:SettingsSidebarContent.kt$onCategorySelected - ParameterNaming:SidebarScaffold.kt$onSettingsCategorySelected - PropertyWrapping:NavHostViewModel.kt$NavHostViewModel$private val favoritesStateHolder = FavoritesStateHolder(settingsDataStore, conversationListStateHolder.recentConversations, viewModelScope) - ViewModelForwarding:LibreChatNavHost.kt$MainNavDisplay( navigator = navigator, navHostViewModel = navHostViewModel, onMenuClick = { scope.launch { drawerState.open() } }, modifier = Modifier.fillMaxSize(), ) - ViewModelForwarding:LibreChatNavHost.kt$PhoneLayout( navigator = navigator, navHostViewModel = navHostViewModel, modifier = modifier, ) - ViewModelForwarding:LibreChatNavHost.kt$SidebarScaffold( viewModel = navHostViewModel, onNewChat = { scope.launch { drawerState.close() } if (navigator.currentRoute !is NewChat) { navigator.navigateToTopLevel(NewChat) } }, onConversationClick = { conversationId -> scope.launch { drawerState.close() } navigator.navigateToChat(conversationId) }, onSettingsClick = { scope.launch { drawerState.close() } navigator.navigate(SettingsTabbed) }, onSettingsCategorySelected = { category -> navigator.navigate(category.toRoute()) }, onAgentsClick = { scope.launch { drawerState.close() } navigator.navigate(AgentMarketplace) }, onFilesClick = { scope.launch { drawerState.close() } navigator.navigate(Files) }, ) - ViewModelForwarding:SidebarScaffold.kt$DrawerContent( viewModel = viewModel, onNewChat = onNewChat, onConversationClick = onConversationClick, onSettingsClick = onSettingsClick, onAgentsClick = onAgentsClick, onFilesClick = onFilesClick, ) - - diff --git a/shared/src/commonMain/kotlin/com/garfiec/librechat/shared/navigation/DrawerContent.kt b/shared/src/commonMain/kotlin/com/garfiec/librechat/shared/navigation/DrawerContent.kt index 926b01b..83480a7 100644 --- a/shared/src/commonMain/kotlin/com/garfiec/librechat/shared/navigation/DrawerContent.kt +++ b/shared/src/commonMain/kotlin/com/garfiec/librechat/shared/navigation/DrawerContent.kt @@ -42,6 +42,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -53,19 +54,20 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.garfiec.librechat.core.ui.components.endpointIconPainter import com.garfiec.librechat.core.ui.components.isMonochromeIcon -import librechat_mobile.shared.generated.resources.Res -import librechat_mobile.shared.generated.resources.agents -import librechat_mobile.shared.generated.resources.bookmark -import librechat_mobile.shared.generated.resources.cd_clear_search -import librechat_mobile.shared.generated.resources.cd_search -import librechat_mobile.shared.generated.resources.favorites -import librechat_mobile.shared.generated.resources.files -import librechat_mobile.shared.generated.resources.new_chat -import librechat_mobile.shared.generated.resources.no_conversations_found -import librechat_mobile.shared.generated.resources.remove_bookmark -import librechat_mobile.shared.generated.resources.search_conversations_placeholder -import librechat_mobile.shared.generated.resources.settings +import com.garfiec.librechat.shared.resources.Res +import com.garfiec.librechat.shared.resources.agents +import com.garfiec.librechat.shared.resources.bookmark +import com.garfiec.librechat.shared.resources.cd_clear_search +import com.garfiec.librechat.shared.resources.cd_search +import com.garfiec.librechat.shared.resources.favorites +import com.garfiec.librechat.shared.resources.files +import com.garfiec.librechat.shared.resources.new_chat +import com.garfiec.librechat.shared.resources.no_conversations_found +import com.garfiec.librechat.shared.resources.remove_bookmark +import com.garfiec.librechat.shared.resources.search_conversations_placeholder +import com.garfiec.librechat.shared.resources.settings import org.jetbrains.compose.resources.stringResource +import org.koin.compose.viewmodel.koinViewModel // Pre-computed shapes to avoid creating new ones per item per frame private val ItemShape = RoundedCornerShape(8.dp) @@ -76,18 +78,18 @@ private val ActiveIndicatorShape = RoundedCornerShape(2.dp) */ @Composable fun DrawerContent( - viewModel: NavHostViewModel, onNewChat: () -> Unit, onConversationClick: (String) -> Unit, onSettingsClick: () -> Unit, onAgentsClick: () -> Unit, onFilesClick: () -> Unit, modifier: Modifier = Modifier, + viewModel: NavHostViewModel = koinViewModel(), ) { val uiState by viewModel.drawerUiState.collectAsStateWithLifecycle() DrawerContent( uiState = uiState, - onSearchQueryChanged = viewModel::onSearchQueryChanged, + onSearchQueryChange = viewModel::onSearchQueryChanged, onNewChat = onNewChat, onConversationClick = onConversationClick, onSettingsClick = onSettingsClick, @@ -104,7 +106,7 @@ fun DrawerContent( @Composable fun DrawerContent( uiState: DrawerUiState, - onSearchQueryChanged: (String) -> Unit, + onSearchQueryChange: (String) -> Unit, onNewChat: () -> Unit, onConversationClick: (String) -> Unit, onSettingsClick: () -> Unit, @@ -154,7 +156,7 @@ fun DrawerContent( // Search bar OutlinedTextField( value = uiState.searchQuery, - onValueChange = onSearchQueryChanged, + onValueChange = onSearchQueryChange, leadingIcon = { Icon( imageVector = Icons.Default.Search, @@ -165,7 +167,7 @@ fun DrawerContent( }, trailingIcon = { if (uiState.searchQuery.isNotEmpty()) { - IconButton(onClick = { onSearchQueryChanged("") }) { + IconButton(onClick = { onSearchQueryChange("") }) { Icon( imageVector = Icons.Default.Close, contentDescription = stringResource(Res.string.cd_clear_search), @@ -192,6 +194,7 @@ fun DrawerContent( // Conversation list with favorites section and date groups val listState = rememberLazyListState() + val currentOnLoadMore by rememberUpdatedState(onLoadMore) val shouldLoadMore = remember { derivedStateOf { @@ -203,7 +206,7 @@ fun DrawerContent( LaunchedEffect(shouldLoadMore.value) { if (shouldLoadMore.value && uiState.hasMore && !uiState.isLoadingMore) { - onLoadMore() + currentOnLoadMore() } } diff --git a/shared/src/commonMain/kotlin/com/garfiec/librechat/shared/navigation/DrawerDisplayMapping.kt b/shared/src/commonMain/kotlin/com/garfiec/librechat/shared/navigation/DrawerDisplayMapping.kt index 643c470..41ecbf1 100644 --- a/shared/src/commonMain/kotlin/com/garfiec/librechat/shared/navigation/DrawerDisplayMapping.kt +++ b/shared/src/commonMain/kotlin/com/garfiec/librechat/shared/navigation/DrawerDisplayMapping.kt @@ -1,12 +1,12 @@ package com.garfiec.librechat.shared.navigation -import com.garfiec.librechat.core.common.extensions.toInstantOrNull import com.garfiec.librechat.core.common.extensions.formatMonthAbbrev +import com.garfiec.librechat.core.common.extensions.toInstantOrNull import com.garfiec.librechat.core.model.Conversation -import kotlin.time.Clock -import kotlin.time.Instant import kotlinx.datetime.TimeZone import kotlinx.datetime.toLocalDateTime +import kotlin.time.Clock +import kotlin.time.Instant internal data class DrawerDataSnapshot( val grouped: List>>, diff --git a/shared/src/commonMain/kotlin/com/garfiec/librechat/shared/navigation/LibreChatNavHost.kt b/shared/src/commonMain/kotlin/com/garfiec/librechat/shared/navigation/LibreChatNavHost.kt index 51725b9..4e91974 100644 --- a/shared/src/commonMain/kotlin/com/garfiec/librechat/shared/navigation/LibreChatNavHost.kt +++ b/shared/src/commonMain/kotlin/com/garfiec/librechat/shared/navigation/LibreChatNavHost.kt @@ -29,17 +29,14 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.navigation3.runtime.NavKey +import androidx.lifecycle.viewmodel.navigation3.rememberViewModelStoreNavEntryDecorator import androidx.navigation3.runtime.entryProvider import androidx.navigation3.runtime.rememberNavBackStack -import androidx.navigation3.ui.NavDisplay import androidx.navigation3.runtime.rememberSaveableStateHolderNavEntryDecorator -import androidx.lifecycle.viewmodel.navigation3.rememberViewModelStoreNavEntryDecorator +import androidx.navigation3.ui.NavDisplay import com.garfiec.librechat.core.ui.components.BannerDisplay import com.garfiec.librechat.feature.agents.navigation.AgentMarketplace import com.garfiec.librechat.feature.agents.navigation.agentsEntries -import com.garfiec.librechat.feature.auth.navigation.AuthRoute -import com.garfiec.librechat.feature.auth.navigation.ServerUrl import com.garfiec.librechat.feature.auth.navigation.authEntries import com.garfiec.librechat.feature.chat.navigation.Chat import com.garfiec.librechat.feature.chat.navigation.NewChat @@ -49,15 +46,15 @@ import com.garfiec.librechat.feature.conversations.navigation.conversationsEntri import com.garfiec.librechat.feature.files.navigation.Files import com.garfiec.librechat.feature.files.navigation.filesEntries import com.garfiec.librechat.feature.settings.navigation.SettingsTabbed -import com.garfiec.librechat.feature.settings.navigation.memoriesEntry import com.garfiec.librechat.feature.settings.navigation.mcpServersEntry +import com.garfiec.librechat.feature.settings.navigation.memoriesEntry import com.garfiec.librechat.feature.settings.navigation.settingsEntries +import com.garfiec.librechat.shared.resources.Res +import com.garfiec.librechat.shared.resources.dismiss +import com.garfiec.librechat.shared.resources.dont_warn_again +import com.garfiec.librechat.shared.resources.version_mismatch_message +import com.garfiec.librechat.shared.resources.version_mismatch_title import kotlinx.coroutines.launch -import librechat_mobile.shared.generated.resources.Res -import librechat_mobile.shared.generated.resources.dismiss -import librechat_mobile.shared.generated.resources.dont_warn_again -import librechat_mobile.shared.generated.resources.version_mismatch_message -import librechat_mobile.shared.generated.resources.version_mismatch_title import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel @@ -106,7 +103,6 @@ fun LibreChatNavHost( } else { PhoneLayout( navigator = navigator, - navHostViewModel = navHostViewModel, modifier = modifier, ) } @@ -161,8 +157,8 @@ private fun VersionMismatchDialog( @Composable fun PhoneLayout( navigator: Navigator, - navHostViewModel: NavHostViewModel, modifier: Modifier = Modifier, + navHostViewModel: NavHostViewModel = koinViewModel(), ) { val drawerState = rememberDrawerState(DrawerValue.Closed) val scope = rememberCoroutineScope() @@ -182,7 +178,6 @@ fun PhoneLayout( drawerContent = { ModalDrawerSheet { SidebarScaffold( - viewModel = navHostViewModel, onNewChat = { scope.launch { drawerState.close() } if (navigator.currentRoute !is NewChat) { @@ -197,7 +192,7 @@ fun PhoneLayout( scope.launch { drawerState.close() } navigator.navigate(SettingsTabbed) }, - onSettingsCategorySelected = { category -> + onSettingsCategorySelect = { category -> navigator.navigate(category.toRoute()) }, onAgentsClick = { @@ -223,7 +218,6 @@ fun PhoneLayout( } MainNavDisplay( navigator = navigator, - navHostViewModel = navHostViewModel, onMenuClick = { scope.launch { drawerState.open() } }, modifier = Modifier.fillMaxSize(), ) @@ -235,9 +229,9 @@ fun PhoneLayout( @Composable fun MainNavDisplay( navigator: Navigator, - navHostViewModel: NavHostViewModel, - onMenuClick: (() -> Unit)? = null, modifier: Modifier = Modifier, + onMenuClick: (() -> Unit)? = null, + navHostViewModel: NavHostViewModel = koinViewModel(), ) { NavDisplay( backStack = navigator.backStack, @@ -290,7 +284,7 @@ fun MainNavDisplay( ) conversationsEntries( onConversationClick = { navigator.navigateToChat(it) }, - onNavigateToArchived = { navigator.navigate(ArchivedConversations) }, + onNavigateToArchive = { navigator.navigate(ArchivedConversations) }, onBack = { navigator.goBack() }, ) agentsEntries( @@ -310,7 +304,7 @@ fun MainNavDisplay( navHostViewModel.logout() navigator.navigateToAuth() }, - onNavigateToArchived = { navigator.navigate(ArchivedConversations) }, + onNavigateToArchive = { navigator.navigate(ArchivedConversations) }, ) memoriesEntry( onBack = { navigator.goBack() }, diff --git a/shared/src/commonMain/kotlin/com/garfiec/librechat/shared/navigation/NavHostViewModel.kt b/shared/src/commonMain/kotlin/com/garfiec/librechat/shared/navigation/NavHostViewModel.kt index 7c13c04..3384fe7 100644 --- a/shared/src/commonMain/kotlin/com/garfiec/librechat/shared/navigation/NavHostViewModel.kt +++ b/shared/src/commonMain/kotlin/com/garfiec/librechat/shared/navigation/NavHostViewModel.kt @@ -2,9 +2,11 @@ package com.garfiec.librechat.shared.navigation import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import co.touchlab.kermit.Logger +import com.garfiec.librechat.core.common.extensions.firstBlocking +import com.garfiec.librechat.core.data.datastore.SettingsDataStore import com.garfiec.librechat.core.data.repository.AuthRepository import com.garfiec.librechat.core.data.repository.BannerRepository -import com.garfiec.librechat.core.data.datastore.SettingsDataStore import com.garfiec.librechat.core.data.repository.ConfigRepository import com.garfiec.librechat.core.data.repository.ConversationRepository import com.garfiec.librechat.core.model.Banner @@ -17,8 +19,6 @@ import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch -import co.touchlab.kermit.Logger -import com.garfiec.librechat.core.common.extensions.firstBlocking class NavHostViewModel( private val authRepository: AuthRepository, @@ -32,7 +32,8 @@ class NavHostViewModel( private val bannerStateHolder = BannerStateHolder(bannerRepository, viewModelScope) private val versionCheckStateHolder = VersionCheckStateHolder(configRepository, settingsDataStore, viewModelScope) private val conversationListStateHolder = ConversationListStateHolder(conversationRepository, viewModelScope) - private val favoritesStateHolder = FavoritesStateHolder(settingsDataStore, conversationListStateHolder.recentConversations, viewModelScope) + private val favoritesStateHolder = + FavoritesStateHolder(settingsDataStore, conversationListStateHolder.recentConversations, viewModelScope) private val _isLoggedIn = MutableStateFlow(tokenManager.isAuthenticated) val isLoggedIn: StateFlow = _isLoggedIn.asStateFlow() diff --git a/shared/src/commonMain/kotlin/com/garfiec/librechat/shared/navigation/SettingsSidebarContent.kt b/shared/src/commonMain/kotlin/com/garfiec/librechat/shared/navigation/SettingsSidebarContent.kt index bdf4669..bcedde6 100644 --- a/shared/src/commonMain/kotlin/com/garfiec/librechat/shared/navigation/SettingsSidebarContent.kt +++ b/shared/src/commonMain/kotlin/com/garfiec/librechat/shared/navigation/SettingsSidebarContent.kt @@ -29,9 +29,9 @@ import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.semantics.heading import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp -import librechat_mobile.shared.generated.resources.Res -import librechat_mobile.shared.generated.resources.cd_back_to_conversations -import librechat_mobile.shared.generated.resources.settings +import com.garfiec.librechat.shared.resources.Res +import com.garfiec.librechat.shared.resources.cd_back_to_conversations +import com.garfiec.librechat.shared.resources.settings import org.jetbrains.compose.resources.stringResource private val CategoryItemShape = RoundedCornerShape(12.dp) @@ -43,7 +43,7 @@ private val CategoryItemShape = RoundedCornerShape(12.dp) fun SettingsSidebarContent( selectedCategory: SettingsCategory?, onBackToConversations: () -> Unit, - onCategorySelected: (SettingsCategory) -> Unit, + onCategorySelect: (SettingsCategory) -> Unit, modifier: Modifier = Modifier, ) { Column( @@ -80,25 +80,25 @@ fun SettingsSidebarContent( icon = Icons.Default.Settings, category = SettingsCategory.GENERAL, isSelected = selectedCategory == SettingsCategory.GENERAL, - onClick = { onCategorySelected(SettingsCategory.GENERAL) }, + onClick = { onCategorySelect(SettingsCategory.GENERAL) }, ) SettingsCategoryItem( icon = Icons.AutoMirrored.Filled.Chat, category = SettingsCategory.CHAT, isSelected = selectedCategory == SettingsCategory.CHAT, - onClick = { onCategorySelected(SettingsCategory.CHAT) }, + onClick = { onCategorySelect(SettingsCategory.CHAT) }, ) SettingsCategoryItem( icon = Icons.Default.AccountCircle, category = SettingsCategory.ACCOUNT, isSelected = selectedCategory == SettingsCategory.ACCOUNT, - onClick = { onCategorySelected(SettingsCategory.ACCOUNT) }, + onClick = { onCategorySelect(SettingsCategory.ACCOUNT) }, ) SettingsCategoryItem( icon = Icons.Default.Storage, category = SettingsCategory.DATA, isSelected = selectedCategory == SettingsCategory.DATA, - onClick = { onCategorySelected(SettingsCategory.DATA) }, + onClick = { onCategorySelect(SettingsCategory.DATA) }, ) Spacer(modifier = Modifier.weight(1f)) diff --git a/shared/src/commonMain/kotlin/com/garfiec/librechat/shared/navigation/SidebarScaffold.kt b/shared/src/commonMain/kotlin/com/garfiec/librechat/shared/navigation/SidebarScaffold.kt index c74edbd..25342fa 100644 --- a/shared/src/commonMain/kotlin/com/garfiec/librechat/shared/navigation/SidebarScaffold.kt +++ b/shared/src/commonMain/kotlin/com/garfiec/librechat/shared/navigation/SidebarScaffold.kt @@ -8,6 +8,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.lifecycle.compose.collectAsStateWithLifecycle +import org.koin.compose.viewmodel.koinViewModel /** * Sidebar scaffold that switches between Conversations and Settings modes. @@ -15,14 +16,14 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle */ @Composable fun SidebarScaffold( - viewModel: NavHostViewModel, onNewChat: () -> Unit, onConversationClick: (String) -> Unit, onSettingsClick: () -> Unit, - onSettingsCategorySelected: (SettingsCategory) -> Unit, + onSettingsCategorySelect: (SettingsCategory) -> Unit, onAgentsClick: () -> Unit, onFilesClick: () -> Unit, modifier: Modifier = Modifier, + viewModel: NavHostViewModel = koinViewModel(), ) { val sidebarMode by viewModel.sidebarMode.collectAsStateWithLifecycle() val selectedCategory by viewModel.selectedSettingsCategory.collectAsStateWithLifecycle() @@ -44,7 +45,6 @@ fun SidebarScaffold( when (mode) { is SidebarMode.Conversations -> { DrawerContent( - viewModel = viewModel, onNewChat = onNewChat, onConversationClick = onConversationClick, onSettingsClick = onSettingsClick, @@ -58,9 +58,9 @@ fun SidebarScaffold( onBackToConversations = { viewModel.setSidebarMode(SidebarMode.Conversations) }, - onCategorySelected = { category -> + onCategorySelect = { category -> viewModel.selectSettingsCategory(category) - onSettingsCategorySelected(category) + onSettingsCategorySelect(category) }, ) } diff --git a/shared/src/iosMain/kotlin/com/garfiec/librechat/shared/IosCrashReporting.kt b/shared/src/iosMain/kotlin/com/garfiec/librechat/shared/IosCrashReporting.kt index 049243d..3f3910a 100644 --- a/shared/src/iosMain/kotlin/com/garfiec/librechat/shared/IosCrashReporting.kt +++ b/shared/src/iosMain/kotlin/com/garfiec/librechat/shared/IosCrashReporting.kt @@ -1,9 +1,9 @@ package com.garfiec.librechat.shared import co.touchlab.kermit.Logger -import kotlin.experimental.ExperimentalNativeApi import platform.Foundation.NSException import platform.Foundation.NSLog +import kotlin.experimental.ExperimentalNativeApi private val log = Logger.withTag("CrashReporting") diff --git a/shared/src/iosMain/kotlin/com/garfiec/librechat/shared/IosKoinAccessor.kt b/shared/src/iosMain/kotlin/com/garfiec/librechat/shared/IosKoinAccessor.kt index ef14beb..4f6a807 100644 --- a/shared/src/iosMain/kotlin/com/garfiec/librechat/shared/IosKoinAccessor.kt +++ b/shared/src/iosMain/kotlin/com/garfiec/librechat/shared/IosKoinAccessor.kt @@ -3,8 +3,8 @@ package com.garfiec.librechat.shared import com.garfiec.librechat.core.common.di.KoinQualifiers import com.garfiec.librechat.core.data.datastore.ServerDataStore import com.garfiec.librechat.core.data.repository.AuthRepository -import com.garfiec.librechat.core.data.repository.FileRepository import com.garfiec.librechat.core.data.repository.ConfigRepository +import com.garfiec.librechat.core.data.repository.FileRepository import io.ktor.client.HttpClient import org.koin.core.Koin diff --git a/shared/src/iosMain/kotlin/com/garfiec/librechat/shared/IosKoinHelper.kt b/shared/src/iosMain/kotlin/com/garfiec/librechat/shared/IosKoinHelper.kt index d8e1983..fe6eb1f 100644 --- a/shared/src/iosMain/kotlin/com/garfiec/librechat/shared/IosKoinHelper.kt +++ b/shared/src/iosMain/kotlin/com/garfiec/librechat/shared/IosKoinHelper.kt @@ -1,8 +1,8 @@ package com.garfiec.librechat.shared +import co.touchlab.kermit.LogWriter import co.touchlab.kermit.Logger import co.touchlab.kermit.Severity -import co.touchlab.kermit.LogWriter import com.garfiec.librechat.shared.navigation.sharedAppModule import org.koin.core.context.startKoin import platform.Foundation.NSLog diff --git a/shared/src/iosMain/kotlin/com/garfiec/librechat/shared/IosSharedModule.kt b/shared/src/iosMain/kotlin/com/garfiec/librechat/shared/IosSharedModule.kt index 7b566f5..398ce21 100644 --- a/shared/src/iosMain/kotlin/com/garfiec/librechat/shared/IosSharedModule.kt +++ b/shared/src/iosMain/kotlin/com/garfiec/librechat/shared/IosSharedModule.kt @@ -3,12 +3,6 @@ package com.garfiec.librechat.shared import com.garfiec.librechat.core.common.di.KoinQualifiers import com.garfiec.librechat.core.common.di.commonModule import com.garfiec.librechat.core.data.di.dataModule -import com.garfiec.librechat.feature.agents.di.agentsModule -import com.garfiec.librechat.feature.files.di.filesModule -import com.garfiec.librechat.feature.auth.di.authModule -import com.garfiec.librechat.feature.chat.di.chatModule -import com.garfiec.librechat.feature.conversations.di.conversationsModule -import com.garfiec.librechat.feature.settings.di.settingsModule import com.garfiec.librechat.core.network.api.AgentsApi import com.garfiec.librechat.core.network.api.ApiKeysApi import com.garfiec.librechat.core.network.api.AuthApi @@ -35,6 +29,12 @@ import com.garfiec.librechat.core.network.client.LibreChatHttpClient import com.garfiec.librechat.core.network.client.ServerUrlProvider import com.garfiec.librechat.core.network.client.TokenManager import com.garfiec.librechat.core.network.sse.SseClient +import com.garfiec.librechat.feature.agents.di.agentsModule +import com.garfiec.librechat.feature.auth.di.authModule +import com.garfiec.librechat.feature.chat.di.chatModule +import com.garfiec.librechat.feature.conversations.di.conversationsModule +import com.garfiec.librechat.feature.files.di.filesModule +import com.garfiec.librechat.feature.settings.di.settingsModule import io.ktor.client.HttpClient import io.ktor.client.engine.darwin.Darwin import io.ktor.client.plugins.HttpTimeout