diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index 8d19633..4964a9f 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -57,6 +57,7 @@ kotlin { implementation(compose.components.uiToolingPreview) implementation(libs.androidx.lifecycle.viewmodel) implementation(libs.androidx.lifecycle.runtime.compose) + implementation(libs.navigation.compose) } desktopMain.dependencies { implementation(compose.desktop.currentOs) diff --git a/composeApp/src/commonMain/composeResources/drawable/citto_48.png b/composeApp/src/commonMain/composeResources/drawable/citto_48.png new file mode 100644 index 0000000..feed9d0 Binary files /dev/null and b/composeApp/src/commonMain/composeResources/drawable/citto_48.png differ diff --git a/composeApp/src/commonMain/composeResources/drawable/logo_48.png b/composeApp/src/commonMain/composeResources/drawable/tularegion_48.png similarity index 100% rename from composeApp/src/commonMain/composeResources/drawable/logo_48.png rename to composeApp/src/commonMain/composeResources/drawable/tularegion_48.png diff --git a/composeApp/src/commonMain/kotlin/ru/tularegion/corp/App.kt b/composeApp/src/commonMain/kotlin/ru/tularegion/corp/App.kt index d9dd42c..110326f 100644 --- a/composeApp/src/commonMain/kotlin/ru/tularegion/corp/App.kt +++ b/composeApp/src/commonMain/kotlin/ru/tularegion/corp/App.kt @@ -7,7 +7,6 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxHeight 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 @@ -16,57 +15,55 @@ import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.NavigationRail import androidx.compose.material3.NavigationRailItem -import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Surface -import androidx.compose.material3.Text import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.unit.dp +import androidx.navigation.NavDestination.Companion.hierarchy +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.currentBackStackEntryAsState +import androidx.navigation.compose.rememberNavController import corp_tularegion_extension.composeapp.generated.resources.Res -import corp_tularegion_extension.composeapp.generated.resources.logo_48 +import corp_tularegion_extension.composeapp.generated.resources.tularegion_48 import corp_tularegion_extension.composeapp.generated.resources.round_info_24 import corp_tularegion_extension.composeapp.generated.resources.round_open_in_new_24 import corp_tularegion_extension.composeapp.generated.resources.round_settings_24 import org.jetbrains.compose.resources.DrawableResource import org.jetbrains.compose.resources.painterResource -import ru.tularegion.corp.backend.JsCallbacks -import ru.tularegion.corp.backend.setAutoAuthLogin -import ru.tularegion.corp.backend.setAutoAuthMode -import ru.tularegion.corp.backend.setAutoAuthPassword -import ru.tularegion.corp.backend.setCopyMode -import ru.tularegion.corp.backend.setRedirectMode -import ru.tularegion.corp.ui.components.CopyMode -import ru.tularegion.corp.ui.components.DropdownSelect -import ru.tularegion.corp.ui.components.RedirectMode -import ru.tularegion.corp.ui.components.SwitchSpoiler +import ru.tularegion.corp.backend.openCorpPortal +import ru.tularegion.corp.screens.AboutScreen +import ru.tularegion.corp.screens.SettingsScreen import ru.tularegion.corp.ui.theme.darkScheme enum class Screen( - val title: String, + val route: String, + val label: String, val icon: DrawableResource, ) { Settings( - title = "Настройки", + route = "settings", + label = "Открыть вкладку «Настройки»", icon = Res.drawable.round_settings_24, ), About( - title = "О расширении", + route = "about", + label = "Открыть вкладку «О расширении»", icon = Res.drawable.round_info_24, ), } @Composable fun App() { + val navController = rememberNavController() + val navBackStackEntry = navController.currentBackStackEntryAsState() + MaterialTheme( colorScheme = darkScheme, ) { Surface { Row { - val navigationState = remember { - mutableStateOf(Screen.Settings) - } NavigationRail( containerColor = MaterialTheme.colorScheme.surfaceContainerLow, ) { @@ -87,21 +84,25 @@ fun App() { .height(8.dp), ) Image( - painter = painterResource(Res.drawable.logo_48), - contentDescription = null, + painter = painterResource(Res.drawable.tularegion_48), + contentDescription = "Герб Тульской области", ) Spacer( modifier = Modifier .height(24.dp), ) - Screen.entries.forEach { + Screen.entries.forEach { screen -> NavigationRailItem( - selected = it == navigationState.value, - onClick = {}, + selected = navBackStackEntry.value?.destination?.hierarchy?.any { + it.route == screen.route + } == true, + onClick = { + navController.navigate(screen.route) + }, icon = { Icon( - painter = painterResource(it.icon), - contentDescription = null, + painter = painterResource(screen.icon), + contentDescription = screen.label, ) }, ) @@ -109,18 +110,22 @@ fun App() { } NavigationRailItem( selected = false, - onClick = {}, + onClick = { + openCorpPortal() + }, icon = { Icon( painter = painterResource(Res.drawable.round_open_in_new_24), - contentDescription = null, + contentDescription = "Открыть Корпоративный портал", ) }, ) } } - Column( + NavHost( + navController = navController, + startDestination = Screen.Settings.route, modifier = Modifier .verticalScroll( state = rememberScrollState(), @@ -130,112 +135,11 @@ fun App() { ) .fillMaxSize(), ) { - Column( - modifier = Modifier - .padding(16.dp), - verticalArrangement = Arrangement.spacedBy(16.dp), - ) { - val redirectModeState = remember { - mutableStateOf(RedirectMode.NO_REDIRECT) - } - JsCallbacks.redirectMode = { value -> - redirectModeState.value = RedirectMode.entries.find { - it.id == value - } ?: RedirectMode.NO_REDIRECT - } - DropdownSelect( - title = "Перенаправление между RU и LOCAL", - caption = "Перенаправлять все страницы на RU, либо на LOCAL", - items = RedirectMode.entries, - valueState = redirectModeState, - onValueChange = { - setRedirectMode(it) - }, - ) - - val copyModeState = remember { - mutableStateOf(CopyMode.NO_REPLACE) - } - JsCallbacks.copyMode = { value -> - copyModeState.value = CopyMode.entries.find { - it.id == value - } ?: CopyMode.NO_REPLACE - } - DropdownSelect( - title = "Замена ссылок при копировании", - caption = "Заменять все ссылки при копировании на RU, либо на LOCAL", - items = CopyMode.entries, - valueState = copyModeState, - onValueChange = { - setCopyMode(it) - }, - ) + composable(Screen.Settings.route) { + SettingsScreen() } - - val autoAuthModeState = remember { - mutableStateOf(false) - } - JsCallbacks.autoAuthMode = { - autoAuthModeState.value = it - } - SwitchSpoiler( - title = "Автоматический вход", - caption = "Выполнять вход на портал автоматически", - enabledState = autoAuthModeState, - onValueChange = { - setAutoAuthMode(it) - }, - ) { - Column( - modifier = Modifier - .padding(16.dp), - verticalArrangement = Arrangement.spacedBy(16.dp), - ) { - val loginState = remember { - mutableStateOf("") - } - JsCallbacks.autoAuthLogin = { - loginState.value = it - } - OutlinedTextField( - value = loginState.value, - onValueChange = { - setAutoAuthLogin(it) - loginState.value = it - }, - modifier = Modifier - .fillMaxWidth(), - label = { - Text( - text = "Логин", - ) - }, - singleLine = true, - ) - - val passwordState = remember { - mutableStateOf("") - } - JsCallbacks.autoAuthPassword = { - passwordState.value = it - } - OutlinedTextField( - value = passwordState.value, - onValueChange = { - setAutoAuthPassword(it) - passwordState.value = it - }, - modifier = Modifier - .fillMaxWidth(), - label = { - Text( - text = "Пароль", - ) - }, - visualTransformation = PasswordVisualTransformation(), - singleLine = true, - ) - } + composable(Screen.About.route) { + AboutScreen() } } } diff --git a/composeApp/src/commonMain/kotlin/ru/tularegion/corp/backend/api.kt b/composeApp/src/commonMain/kotlin/ru/tularegion/corp/backend/api.kt index 221fd37..36f503f 100644 --- a/composeApp/src/commonMain/kotlin/ru/tularegion/corp/backend/api.kt +++ b/composeApp/src/commonMain/kotlin/ru/tularegion/corp/backend/api.kt @@ -86,3 +86,6 @@ fun autoAuthPasswordCallback( external fun setAutoAuthPassword( value: String, ) + +@JsName("openCorpPortal") +external fun openCorpPortal() diff --git a/composeApp/src/commonMain/kotlin/ru/tularegion/corp/screens/AboutScreen.kt b/composeApp/src/commonMain/kotlin/ru/tularegion/corp/screens/AboutScreen.kt new file mode 100644 index 0000000..1dafaa3 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/ru/tularegion/corp/screens/AboutScreen.kt @@ -0,0 +1,23 @@ +package ru.tularegion.corp.screens + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import corp_tularegion_extension.composeapp.generated.resources.Res +import corp_tularegion_extension.composeapp.generated.resources.citto_48 +import org.jetbrains.compose.resources.painterResource + +@Composable +fun AboutScreen() { + Column { + Image( + painter = painterResource(Res.drawable.citto_48), + contentDescription = "Логотип ГАУ ТО «ЦИТ»", + modifier = Modifier + .padding(16.dp), + ) + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ru/tularegion/corp/screens/SettingsScreen.kt b/composeApp/src/commonMain/kotlin/ru/tularegion/corp/screens/SettingsScreen.kt new file mode 100644 index 0000000..9b1dff1 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/ru/tularegion/corp/screens/SettingsScreen.kt @@ -0,0 +1,140 @@ +package ru.tularegion.corp.screens + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.input.PasswordVisualTransformation +import androidx.compose.ui.unit.dp +import ru.tularegion.corp.backend.JsCallbacks +import ru.tularegion.corp.backend.setAutoAuthLogin +import ru.tularegion.corp.backend.setAutoAuthMode +import ru.tularegion.corp.backend.setAutoAuthPassword +import ru.tularegion.corp.backend.setCopyMode +import ru.tularegion.corp.backend.setRedirectMode +import ru.tularegion.corp.ui.components.CopyMode +import ru.tularegion.corp.ui.components.DropdownSelect +import ru.tularegion.corp.ui.components.RedirectMode +import ru.tularegion.corp.ui.components.SwitchSpoiler + +@Composable +fun SettingsScreen() { + val redirectModeState = remember { + mutableStateOf(RedirectMode.NO_REDIRECT) + } + JsCallbacks.redirectMode = { value -> + redirectModeState.value = RedirectMode.entries.find { + it.id == value + } ?: RedirectMode.NO_REDIRECT + } + + val copyModeState = remember { + mutableStateOf(CopyMode.NO_REPLACE) + } + JsCallbacks.copyMode = { value -> + copyModeState.value = CopyMode.entries.find { + it.id == value + } ?: CopyMode.NO_REPLACE + } + + val autoAuthModeState = remember { + mutableStateOf(false) + } + JsCallbacks.autoAuthMode = { + autoAuthModeState.value = it + } + + val loginState = remember { + mutableStateOf("") + } + JsCallbacks.autoAuthLogin = { + loginState.value = it + } + + val passwordState = remember { + mutableStateOf("") + } + JsCallbacks.autoAuthPassword = { + passwordState.value = it + } + + Column { + Column( + modifier = Modifier + .padding(16.dp), + verticalArrangement = Arrangement.spacedBy(16.dp), + ) { + DropdownSelect( + title = "Перенаправление между RU и LOCAL", + caption = "Перенаправлять все страницы на RU, либо на LOCAL", + items = RedirectMode.entries, + valueState = redirectModeState, + onValueChange = { + setRedirectMode(it) + }, + ) + DropdownSelect( + title = "Замена ссылок при копировании", + caption = "Заменять все ссылки при копировании на RU, либо на LOCAL", + items = CopyMode.entries, + valueState = copyModeState, + onValueChange = { + setCopyMode(it) + }, + ) + } + + SwitchSpoiler( + title = "Автоматический вход", + caption = "Выполнять вход на портал автоматически", + enabledState = autoAuthModeState, + onValueChange = { + setAutoAuthMode(it) + }, + ) { + Column( + modifier = Modifier + .padding(16.dp), + verticalArrangement = Arrangement.spacedBy(16.dp), + ) { + OutlinedTextField( + value = loginState.value, + onValueChange = { + setAutoAuthLogin(it) + loginState.value = it + }, + modifier = Modifier + .fillMaxWidth(), + label = { + Text( + text = "Логин", + ) + }, + singleLine = true, + ) + OutlinedTextField( + value = passwordState.value, + onValueChange = { + setAutoAuthPassword(it) + passwordState.value = it + }, + modifier = Modifier + .fillMaxWidth(), + label = { + Text( + text = "Пароль", + ) + }, + visualTransformation = PasswordVisualTransformation(), + singleLine = true, + ) + } + } + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/ru/tularegion/corp/ui/components/DropdownSelect.kt b/composeApp/src/commonMain/kotlin/ru/tularegion/corp/ui/components/DropdownSelect.kt index 359d0ec..45b1eea 100644 --- a/composeApp/src/commonMain/kotlin/ru/tularegion/corp/ui/components/DropdownSelect.kt +++ b/composeApp/src/commonMain/kotlin/ru/tularegion/corp/ui/components/DropdownSelect.kt @@ -36,8 +36,8 @@ enum class CopyMode( override val title: String, ) : DropdownSelect { NO_REPLACE(0, "Отключить"), - LOCAL_TO_RU(1, "Заменять LOCAL на RU"), - RU_TO_LOCAL(2, "Заменять RU на LOCAL"), +// RU_TO_LOCAL(1, "Заменять RU на LOCAL"), +// LOCAL_TO_RU(2, "Заменять LOCAL на RU"), } @OptIn(ExperimentalMaterial3Api::class) diff --git a/composeApp/src/commonMain/kotlin/ru/tularegion/corp/ui/components/SwitchSpoiler.kt b/composeApp/src/commonMain/kotlin/ru/tularegion/corp/ui/components/SwitchSpoiler.kt index e808efb..335f11e 100644 --- a/composeApp/src/commonMain/kotlin/ru/tularegion/corp/ui/components/SwitchSpoiler.kt +++ b/composeApp/src/commonMain/kotlin/ru/tularegion/corp/ui/components/SwitchSpoiler.kt @@ -8,11 +8,8 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope 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.CardColors @@ -23,8 +20,6 @@ import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color diff --git a/composeApp/src/wasmJsMain/resources/api.js b/composeApp/src/wasmJsMain/resources/api.js index 8239816..d2c8f15 100644 --- a/composeApp/src/wasmJsMain/resources/api.js +++ b/composeApp/src/wasmJsMain/resources/api.js @@ -25,3 +25,17 @@ function setAutoAuthLogin(value) { function setAutoAuthPassword(value) { chrome.storage.local.set({ autoAuthPassword: value }) } + +function openCorpPortal() { + chrome.storage.local.get(['redirectMode']).then((data) => { + switch (data.redirectMode) { + case 1: + window.open('https://corp.tularegion.local/') + break + + default: + window.open('https://corp.tularegion.ru/') + break + } + }) +} diff --git a/composeApp/src/wasmJsMain/resources/index.html b/composeApp/src/wasmJsMain/resources/index.html index 367adb3..a00f2d3 100644 --- a/composeApp/src/wasmJsMain/resources/index.html +++ b/composeApp/src/wasmJsMain/resources/index.html @@ -2,13 +2,14 @@ + Расширение Корпоративного портала - - - + + + - + diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index cdc71f1..5e3bea2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,6 +15,7 @@ compose-multiplatform = "1.7.0" junit = "4.13.2" kotlin = "2.1.0" kotlinx-coroutines = "1.9.0" +navigationComposeVersion = "2.7.0-alpha07" [libraries] kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } @@ -30,6 +31,7 @@ androidx-activity-compose = { module = "androidx.activity:activity-compose", ver androidx-lifecycle-viewmodel = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-viewmodel", version.ref = "androidx-lifecycle" } androidx-lifecycle-runtime-compose = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "androidx-lifecycle" } kotlinx-coroutines-swing = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-swing", version.ref = "kotlinx-coroutines" } +navigation-compose = { module = "org.jetbrains.androidx.navigation:navigation-compose", version.ref = "navigationComposeVersion" } [plugins] androidApplication = { id = "com.android.application", version.ref = "agp" }