update scaffolds

This commit is contained in:
2026-08-15 12:25:09 +03:00
parent 236ebb1462
commit 4f7d3dc6bc
26 changed files with 201 additions and 201 deletions
@@ -17,7 +17,7 @@ import ru.shadowsparky.vbox.shared.presentation.nav.Route
@Composable @Composable
fun createNavigationList(): List<NavigationEntry<Route>> { fun createNavigationList(): List<NavigationEntry<Route>> {
val list = listOf( return listOf(
NavigationEntry( NavigationEntry(
Route.default, Route.default,
stringResource(Res.string.recommendations), stringResource(Res.string.recommendations),
@@ -44,7 +44,6 @@ fun createNavigationList(): List<NavigationEntry<Route>> {
painterResource(Res.drawable.settings) painterResource(Res.drawable.settings)
) )
) )
return list
} }
fun List<NavigationEntry<*>>.findTitle(route: Route): String? { fun List<NavigationEntry<*>>.findTitle(route: Route): String? {
@@ -29,7 +29,7 @@ fun MainScreen(route: Route, child: Child, root: VBoxRootComponent) {
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun BaseMainScreen( fun MainScreenScaffold(
appBar: @Composable () -> Unit, appBar: @Composable () -> Unit,
route: Route, route: Route,
onNavigate: (Route) -> Unit, onNavigate: (Route) -> Unit,
@@ -47,13 +47,9 @@ fun BaseMainScreen(
@Composable @Composable
private fun MainScreenInternal(route: Route, child: Child, onNavigate: (Route) -> Unit) { private fun MainScreenInternal(route: Route, child: Child, onNavigate: (Route) -> Unit) {
val navList = createNavigationList() val navList = createNavigationList()
BaseMainScreen( MainScreenScaffold(
appBar = { appBar = {
navList.findTitle(route)?.let { title -> navList.findTitle(route)?.let { title -> TopAppBar(title = { Text(title) }) }
TopAppBar(
title = { Text(title) }
)
}
}, },
route = route, route = route,
onNavigate = onNavigate, onNavigate = onNavigate,
@@ -1,15 +1,9 @@
package ru.shadowsparky.vbox.shared.presentation package ru.shadowsparky.vbox.shared.presentation
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import com.seiko.imageloader.LocalImageLoader import com.seiko.imageloader.LocalImageLoader
import ru.shadowsparky.koin
import ru.shadowsparky.ui.nav.Nav import ru.shadowsparky.ui.nav.Nav
import ru.shadowsparky.updater.presentation.UpdateDialog import ru.shadowsparky.updater.presentation.UpdateDialog
import ru.shadowsparky.vbox.shared.presentation.list.VideoScreen import ru.shadowsparky.vbox.shared.presentation.list.VideoScreen
@@ -27,11 +21,6 @@ import ru.shadowsparky.vbox.shared.presentation.settings.register.RegisterScreen
import ru.shadowsparky.vbox.shared.presentation.settings.serv.EditServScreen import ru.shadowsparky.vbox.shared.presentation.settings.serv.EditServScreen
import ru.shadowsparky.vbox.shared.presentation.settings.tag.TagScreen import ru.shadowsparky.vbox.shared.presentation.settings.tag.TagScreen
@Composable
fun Modifier.imePaddingInternal(): Modifier {
return koin.get<UiConfiguration>().imePadding(this)
}
@Composable @Composable
fun Nav(root: VBoxRootComponent, onAttach: @Composable () -> Unit = {}) { fun Nav(root: VBoxRootComponent, onAttach: @Composable () -> Unit = {}) {
CompositionLocalProvider( CompositionLocalProvider(
@@ -74,21 +63,3 @@ private fun NavInternal(root: VBoxRootComponent, onAttach: @Composable () -> Uni
UpdateDialog(root.updateComponent) UpdateDialog(root.updateComponent)
} }
} }
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AppScaffold(
scrollBehavior: TopAppBarScrollBehavior? = null,
snackbarState: SnackbarHostState? = null,
modifier: Modifier = Modifier,
content: @Composable (padding: PaddingValues) -> Unit,
appBar: @Composable () -> Unit
) {
ru.shadowsparky.ui.AppScaffold(
modifier,
scrollBehavior,
snackbarState,
content = content,
appBar = { appBar() }
)
}
@@ -1,13 +0,0 @@
package ru.shadowsparky.vbox.shared.presentation
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import org.koin.core.annotation.Single
@Single
class UiConfiguration {
@Composable
fun imePadding(modifier: Modifier): Modifier {
return modifier
}
}
@@ -11,14 +11,14 @@ import org.jetbrains.compose.resources.stringResource
import ru.shadowsparky.chat.presentation.ChatComponent import ru.shadowsparky.chat.presentation.ChatComponent
import ru.shadowsparky.chat.presentation.ChatContent import ru.shadowsparky.chat.presentation.ChatContent
import ru.shadowsparky.ui.components.TopAppBar import ru.shadowsparky.ui.components.TopAppBar
import ru.shadowsparky.vbox.shared.presentation.BaseMainScreen import ru.shadowsparky.vbox.shared.presentation.MainScreenScaffold
import ru.shadowsparky.vbox.shared.presentation.nav.Route import ru.shadowsparky.vbox.shared.presentation.nav.Route
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun ChatScreen(component: ChatComponent, route: Route, onNavigate: (Route) -> Unit) { fun ChatScreen(component: ChatComponent, route: Route, onNavigate: (Route) -> Unit) {
val state by component.state.subscribeAsState() val state by component.state.subscribeAsState()
BaseMainScreen( MainScreenScaffold(
appBar = { appBar = {
TopAppBar(title = { Text(stringResource(Res.string.chat_title_app_bar)) }) TopAppBar(title = { Text(stringResource(Res.string.chat_title_app_bar)) })
}, },
@@ -39,12 +39,12 @@ import androidx.compose.ui.unit.dp
import com.seiko.imageloader.rememberImagePainter import com.seiko.imageloader.rememberImagePainter
import org.jetbrains.compose.resources.StringResource import org.jetbrains.compose.resources.StringResource
import org.jetbrains.compose.resources.stringResource import org.jetbrains.compose.resources.stringResource
import ru.shadowsparky.ui.AppScaffold
import ru.shadowsparky.ui.components.ErrorContent import ru.shadowsparky.ui.components.ErrorContent
import ru.shadowsparky.ui.components.LazyVerticalGrid import ru.shadowsparky.ui.components.LazyVerticalGrid
import ru.shadowsparky.ui.components.Loading import ru.shadowsparky.ui.components.Loading
import ru.shadowsparky.ui.theme.focusBorder import ru.shadowsparky.ui.theme.focusBorder
import ru.shadowsparky.vbox.shared.domain.model.VideoItem import ru.shadowsparky.vbox.shared.domain.model.VideoItem
import ru.shadowsparky.vbox.shared.presentation.AppScaffold
import ru.shadowsparky.vbox.shared.presentation.search.AppBarWithSearch import ru.shadowsparky.vbox.shared.presentation.search.AppBarWithSearch
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@@ -5,8 +5,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import ru.shadowsparky.ui.AppScaffold
import ru.shadowsparky.ui.components.Loading import ru.shadowsparky.ui.components.Loading
import ru.shadowsparky.vbox.shared.presentation.AppScaffold
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
@@ -25,7 +25,6 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
@@ -45,6 +44,7 @@ import org.jetbrains.compose.resources.stringResource
import ru.shadowsparky.ui.AppScaffold import ru.shadowsparky.ui.AppScaffold
import ru.shadowsparky.ui.components.BackButton import ru.shadowsparky.ui.components.BackButton
import ru.shadowsparky.ui.components.ExpressiveLazyColumn import ru.shadowsparky.ui.components.ExpressiveLazyColumn
import ru.shadowsparky.ui.components.IconButton
import ru.shadowsparky.ui.components.Loading import ru.shadowsparky.ui.components.Loading
import ru.shadowsparky.vbox.shared.domain.EpisodeOfflineVideo import ru.shadowsparky.vbox.shared.domain.EpisodeOfflineVideo
import ru.shadowsparky.vbox.shared.domain.OfflineState import ru.shadowsparky.vbox.shared.domain.OfflineState
@@ -41,7 +41,6 @@ import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -68,13 +67,14 @@ import com.seiko.imageloader.rememberImagePainter
import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.resources.stringResource import org.jetbrains.compose.resources.stringResource
import ru.shadowsparky.domain.Clip import ru.shadowsparky.domain.Clip
import ru.shadowsparky.ui.AppScaffold
import ru.shadowsparky.ui.components.BackButton import ru.shadowsparky.ui.components.BackButton
import ru.shadowsparky.ui.components.ErrorContent import ru.shadowsparky.ui.components.ErrorContent
import ru.shadowsparky.ui.components.IconButton
import ru.shadowsparky.ui.components.LazyColumn import ru.shadowsparky.ui.components.LazyColumn
import ru.shadowsparky.ui.components.Loading import ru.shadowsparky.ui.components.Loading
import ru.shadowsparky.ui.components.TopAppBar import ru.shadowsparky.ui.components.TopAppBar
import ru.shadowsparky.vbox.shared.domain.model.VideoDetails import ru.shadowsparky.vbox.shared.domain.model.VideoDetails
import ru.shadowsparky.vbox.shared.presentation.AppScaffold
import ru.shadowsparky.vbox.shared.presentation.getClipboardText import ru.shadowsparky.vbox.shared.presentation.getClipboardText
import ru.shadowsparky.vbox.shared.presentation.settings.tag.LinkTagBottomSheet import ru.shadowsparky.vbox.shared.presentation.settings.tag.LinkTagBottomSheet
@@ -24,7 +24,6 @@ import androidx.compose.material3.CircularWavyProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -44,15 +43,16 @@ import androidx.compose.ui.unit.dp
import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.resources.stringResource import org.jetbrains.compose.resources.stringResource
import ru.shadowsparky.domain.Clip import ru.shadowsparky.domain.Clip
import ru.shadowsparky.ui.AppScaffold
import ru.shadowsparky.ui.components.BackButton import ru.shadowsparky.ui.components.BackButton
import ru.shadowsparky.ui.components.ErrorContent import ru.shadowsparky.ui.components.ErrorContent
import ru.shadowsparky.ui.components.ExpressiveLazyColumn import ru.shadowsparky.ui.components.ExpressiveLazyColumn
import ru.shadowsparky.ui.components.IconButton
import ru.shadowsparky.ui.components.Loading import ru.shadowsparky.ui.components.Loading
import ru.shadowsparky.ui.components.TopAppBar import ru.shadowsparky.ui.components.TopAppBar
import ru.shadowsparky.vbox.shared.domain.OfflineState import ru.shadowsparky.vbox.shared.domain.OfflineState
import ru.shadowsparky.vbox.shared.domain.OfflineVideo import ru.shadowsparky.vbox.shared.domain.OfflineVideo
import ru.shadowsparky.vbox.shared.domain.model.Episode import ru.shadowsparky.vbox.shared.domain.model.Episode
import ru.shadowsparky.vbox.shared.presentation.AppScaffold
import ru.shadowsparky.vbox.shared.presentation.getClipboardText import ru.shadowsparky.vbox.shared.presentation.getClipboardText
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@@ -20,13 +20,13 @@ import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import org.jetbrains.compose.resources.stringResource import org.jetbrains.compose.resources.stringResource
import ru.shadowsparky.ui.AppScaffold
import ru.shadowsparky.ui.components.BackButton import ru.shadowsparky.ui.components.BackButton
import ru.shadowsparky.ui.components.ErrorContent import ru.shadowsparky.ui.components.ErrorContent
import ru.shadowsparky.ui.components.ExpressiveLazyColumn import ru.shadowsparky.ui.components.ExpressiveLazyColumn
import ru.shadowsparky.ui.components.Loading import ru.shadowsparky.ui.components.Loading
import ru.shadowsparky.ui.components.TopAppBar import ru.shadowsparky.ui.components.TopAppBar
import ru.shadowsparky.vbox.shared.domain.model.Season import ru.shadowsparky.vbox.shared.domain.model.Season
import ru.shadowsparky.vbox.shared.presentation.AppScaffold
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
@@ -15,7 +15,6 @@ import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Checkbox import androidx.compose.material3.Checkbox
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -30,10 +29,11 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.resources.stringResource import org.jetbrains.compose.resources.stringResource
import ru.shadowsparky.ui.components.AlertContent import ru.shadowsparky.ui.components.AlertContent
import ru.shadowsparky.ui.components.IconButton
import ru.shadowsparky.ui.components.LazyColumn import ru.shadowsparky.ui.components.LazyColumn
import ru.shadowsparky.ui.components.TopAppBar import ru.shadowsparky.ui.components.TopAppBar
import ru.shadowsparky.vbox.shared.domain.tag.TagInfo import ru.shadowsparky.vbox.shared.domain.tag.TagInfo
import ru.shadowsparky.vbox.shared.presentation.BaseMainScreen import ru.shadowsparky.vbox.shared.presentation.MainScreenScaffold
import ru.shadowsparky.vbox.shared.presentation.list.VideoScreenContent import ru.shadowsparky.vbox.shared.presentation.list.VideoScreenContent
import ru.shadowsparky.vbox.shared.presentation.nav.Route import ru.shadowsparky.vbox.shared.presentation.nav.Route
@@ -42,7 +42,7 @@ import ru.shadowsparky.vbox.shared.presentation.nav.Route
fun SavedMovieScreen(comp: SavedMovieComponent, route: Route, onNavigate: (Route) -> Unit) { fun SavedMovieScreen(comp: SavedMovieComponent, route: Route, onNavigate: (Route) -> Unit) {
val tags by comp.userTags.collectAsStateWithLifecycle(null) val tags by comp.userTags.collectAsStateWithLifecycle(null)
var filterBottomSheetVisible by rememberSaveable { mutableStateOf(false) } var filterBottomSheetVisible by rememberSaveable { mutableStateOf(false) }
BaseMainScreen( MainScreenScaffold(
appBar = { appBar = {
TopAppBar( TopAppBar(
title = { Text(stringResource(Res.string.saved_movies)) }, title = { Text(stringResource(Res.string.saved_movies)) },
@@ -24,7 +24,6 @@ import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.LinearWavyProgressIndicator import androidx.compose.material3.LinearWavyProgressIndicator
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
@@ -65,8 +64,8 @@ import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.resources.stringResource import org.jetbrains.compose.resources.stringResource
import ru.shadowsparky.ui.components.AppBarWithSearch import ru.shadowsparky.ui.components.AppBarWithSearch
import ru.shadowsparky.ui.components.ExpressiveLazyColumn import ru.shadowsparky.ui.components.ExpressiveLazyColumn
import ru.shadowsparky.vbox.shared.presentation.BaseMainScreen import ru.shadowsparky.ui.components.IconButton
import ru.shadowsparky.vbox.shared.presentation.imePaddingInternal import ru.shadowsparky.vbox.shared.presentation.MainScreenScaffold
import ru.shadowsparky.vbox.shared.presentation.nav.Route import ru.shadowsparky.vbox.shared.presentation.nav.Route
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@@ -80,7 +79,7 @@ fun SearchScreen(
var textFieldValue by rememberSaveable(stateSaver = TextFieldValue.Saver) { var textFieldValue by rememberSaveable(stateSaver = TextFieldValue.Saver) {
mutableStateOf(TextFieldValue()) mutableStateOf(TextFieldValue())
} }
BaseMainScreen( MainScreenScaffold(
appBar = { appBar = {
SearchAppBar( SearchAppBar(
textFieldValue = textFieldValue, textFieldValue = textFieldValue,
@@ -153,8 +152,7 @@ fun OldSearchInfo(
val keyboardController = LocalSoftwareKeyboardController.current val keyboardController = LocalSoftwareKeyboardController.current
val nestedScrollConnection = remember { HideKeyboardConnection { keyboardController } } val nestedScrollConnection = remember { HideKeyboardConnection { keyboardController } }
ExpressiveLazyColumn( ExpressiveLazyColumn(
modifier = Modifier.nestedScroll(nestedScrollConnection) modifier = Modifier.nestedScroll(nestedScrollConnection),
.imePaddingInternal(),
contentPadding = contentPaddingValues, contentPadding = contentPaddingValues,
content = { content = {
section { section {
@@ -35,6 +35,7 @@ import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import org.jetbrains.compose.resources.stringResource import org.jetbrains.compose.resources.stringResource
import ru.shadowsparky.ui.AppScaffold
import ru.shadowsparky.ui.components.BackButton import ru.shadowsparky.ui.components.BackButton
import ru.shadowsparky.ui.components.ErrorAlert import ru.shadowsparky.ui.components.ErrorAlert
import ru.shadowsparky.ui.components.Loading import ru.shadowsparky.ui.components.Loading
@@ -42,7 +43,6 @@ import ru.shadowsparky.ui.components.PasswordTextField
import ru.shadowsparky.vbox.shared.domain.model.EmptyLoginException import ru.shadowsparky.vbox.shared.domain.model.EmptyLoginException
import ru.shadowsparky.vbox.shared.domain.model.EmptyPasswordException import ru.shadowsparky.vbox.shared.domain.model.EmptyPasswordException
import ru.shadowsparky.vbox.shared.domain.model.LoginException import ru.shadowsparky.vbox.shared.domain.model.LoginException
import ru.shadowsparky.vbox.shared.presentation.AppScaffold
@Composable @Composable
fun AuthScreen(comp: AuthComponent) { fun AuthScreen(comp: AuthComponent) {
@@ -32,10 +32,10 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.jetbrains.compose.resources.stringResource import org.jetbrains.compose.resources.stringResource
import ru.shadowsparky.ui.AppScaffold
import ru.shadowsparky.ui.components.BackButton import ru.shadowsparky.ui.components.BackButton
import ru.shadowsparky.ui.components.Loading import ru.shadowsparky.ui.components.Loading
import ru.shadowsparky.ui.components.PasswordTextField import ru.shadowsparky.ui.components.PasswordTextField
import ru.shadowsparky.vbox.shared.presentation.AppScaffold
import ru.shadowsparky.vbox.shared.presentation.settings.auth.AuthState import ru.shadowsparky.vbox.shared.presentation.settings.auth.AuthState
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@@ -11,7 +11,7 @@ import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import ru.shadowsparky.ui.components.IconButton
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -34,10 +34,10 @@ import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.resources.stringResource import org.jetbrains.compose.resources.stringResource
import ru.shadowsparky.ui.AppScaffold
import ru.shadowsparky.ui.components.BackButton import ru.shadowsparky.ui.components.BackButton
import ru.shadowsparky.ui.components.Loading import ru.shadowsparky.ui.components.Loading
import ru.shadowsparky.ui.components.TopAppBar import ru.shadowsparky.ui.components.TopAppBar
import ru.shadowsparky.vbox.shared.presentation.AppScaffold
@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class) @OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class)
@Composable @Composable
@@ -33,7 +33,6 @@ import androidx.compose.material3.Button
import androidx.compose.material3.Card import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.LinearProgressIndicator import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
@@ -76,6 +75,7 @@ import ru.shadowsparky.chat.domain.ChatRoles
import ru.shadowsparky.chat.domain.Message import ru.shadowsparky.chat.domain.Message
import ru.shadowsparky.chat.domain.TextToken import ru.shadowsparky.chat.domain.TextToken
import ru.shadowsparky.ui.components.AlertContent import ru.shadowsparky.ui.components.AlertContent
import ru.shadowsparky.ui.components.IconButton
import ru.shadowsparky.ui.components.LazyColumn import ru.shadowsparky.ui.components.LazyColumn
import ru.shadowsparky.ui.components.Loading import ru.shadowsparky.ui.components.Loading
import ru.shadowsparky.ui.components.TextPreference import ru.shadowsparky.ui.components.TextPreference
@@ -8,7 +8,6 @@ import androiddev.feature.video_player.generated.resources.pause_24px
import androiddev.feature.video_player.generated.resources.play_arrow_24px import androiddev.feature.video_player.generated.resources.play_arrow_24px
import androiddev.feature.video_player.generated.resources.replay_24px import androiddev.feature.video_player.generated.resources.replay_24px
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.focusGroup import androidx.compose.foundation.focusGroup
import androidx.compose.foundation.focusable import androidx.compose.foundation.focusable
import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.gestures.detectTapGestures
@@ -23,13 +22,13 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.CircularWavyProgressIndicator import androidx.compose.material3.CircularWavyProgressIndicator
import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Slider import androidx.compose.material3.Slider
import androidx.compose.material3.Text import androidx.compose.material3.Text
@@ -59,7 +58,9 @@ import androidx.compose.ui.unit.dp
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.resources.painterResource
import ru.shadowsparky.ui.components.IconButton
import ru.shadowsparky.ui.components.isTv import ru.shadowsparky.ui.components.isTv
import ru.shadowsparky.ui.theme.focusBorder
import ru.shadowsparky.videoplayer.AudioTrackInfo import ru.shadowsparky.videoplayer.AudioTrackInfo
import ru.shadowsparky.videoplayer.ControlsState import ru.shadowsparky.videoplayer.ControlsState
import ru.shadowsparky.videoplayer.PlayerController import ru.shadowsparky.videoplayer.PlayerController
@@ -391,13 +392,5 @@ private fun Modifier.focusableWithBorder(requester: FocusRequester): Modifier {
var isFocused by remember { mutableStateOf(false) } var isFocused by remember { mutableStateOf(false) }
return this.focusRequester(requester) return this.focusRequester(requester)
.onFocusChanged { isFocused = it.isFocused } .onFocusChanged { isFocused = it.isFocused }
.border( .focusBorder(false, CircleShape)
width = 2.dp,
color = if (isFocused) {
MaterialTheme.colorScheme.primary
} else {
Color.Transparent
},
shape = RoundedCornerShape(24.dp)
)
} }
+8 -6
View File
@@ -1,10 +1,10 @@
[versions] [versions]
activity-compose = "1.13.0" activity-compose = "1.13.0"
material3-compose = "1.12.0-alpha03"
appcompat = "1.7.1" adaptiveLayout = "1.3.0-beta02"
appcompat = "1.8.0"
coil-compose = "3.5.0" coil-compose = "3.5.0"
componentsResources = "1.11.1" componentsResources = "1.11.1"
compose-material-version = "1.11.0-alpha03"
compose-version = "1.11.1" compose-version = "1.11.1"
desugar_jdk_libs = "2.1.5" desugar_jdk_libs = "2.1.5"
foundation = "1.11.1" foundation = "1.11.1"
@@ -19,7 +19,7 @@ decompose-version = "3.5.0"
image-loader = "1.10.0" image-loader = "1.10.0"
junit = "4.13.2" junit = "4.13.2"
lifecycleCoroutines = "2.5.0" lifecycleCoroutines = "2.5.0"
material = "1.11.4" material = "1.12.0"
materialVersion = "1.14.0" materialVersion = "1.14.0"
media3 = "1.11.0" media3 = "1.11.0"
mockk = "1.14.11" mockk = "1.14.11"
@@ -29,7 +29,7 @@ kotlinx-coroutines-core = "1.11.0"
kotlinx-serialization-json = "1.11.0" kotlinx-serialization-json = "1.11.0"
ktor-plugin = "3.5.2" ktor-plugin = "3.5.2"
kxml2 = "2.4.1" kxml2 = "2.4.1"
logback-classic = "1.6.1" logback-classic = "1.6.3"
multiplatform-settings = "1.3.0" multiplatform-settings = "1.3.0"
postgresql = "42.7.13" postgresql = "42.7.13"
runner = "1.7.0" runner = "1.7.0"
@@ -53,6 +53,7 @@ krpc = "0.10.3"
core = "1.19.0" core = "1.19.0"
[libraries] [libraries]
adaptive-layout = { module = "org.jetbrains.compose.material3.adaptive:adaptive-layout", version.ref = "adaptiveLayout" }
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastore-preferences-core" } androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastore-preferences-core" }
androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" } androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" }
@@ -85,10 +86,11 @@ ktor-server-host-common-jvm = { module = "io.ktor:ktor-server-host-common-jvm" }
ktor-server-core-jvm = { module = "io.ktor:ktor-server-core-jvm" } ktor-server-core-jvm = { module = "io.ktor:ktor-server-core-jvm" }
ktor-server-websockets-jvm = { module = "io.ktor:ktor-server-websockets-jvm" } ktor-server-websockets-jvm = { module = "io.ktor:ktor-server-websockets-jvm" }
material = { module = "com.google.android.material:material", version.ref = "materialVersion" } material = { module = "com.google.android.material:material", version.ref = "materialVersion" }
material3-adaptive-navigation-suite = { module = "org.jetbrains.compose.material3:material3-adaptive-navigation-suite", version.ref = "material3-compose" }
multiplatform-settings = { module = "com.russhwolf:multiplatform-settings", version.ref = "multiplatform-settings" } multiplatform-settings = { module = "com.russhwolf:multiplatform-settings", version.ref = "multiplatform-settings" }
activity-compose = { module = "androidx.activity:activity-compose", version.ref = "activity-compose" } activity-compose = { module = "androidx.activity:activity-compose", version.ref = "activity-compose" }
compose-gradle-plugin = { module = "org.jetbrains.compose:compose-gradle-plugin", version.ref = "compose-version" } compose-gradle-plugin = { module = "org.jetbrains.compose:compose-gradle-plugin", version.ref = "compose-version" }
compose-material3 = { module = "org.jetbrains.compose.material3:material3", version.ref = "compose-material-version" } compose-material3 = { module = "org.jetbrains.compose.material3:material3", version.ref = "material3-compose" }
compose-runtime = { module = "org.jetbrains.compose.runtime:runtime", version.ref = "compose-version" } compose-runtime = { module = "org.jetbrains.compose.runtime:runtime", version.ref = "compose-version" }
compose-components-resources = { module = "org.jetbrains.compose.components:components-resources", version.ref = "componentsResources" } compose-components-resources = { module = "org.jetbrains.compose.components:components-resources", version.ref = "componentsResources" }
compose-foundation = { module = "org.jetbrains.compose.foundation:foundation", version.ref = "foundation" } compose-foundation = { module = "org.jetbrains.compose.foundation:foundation", version.ref = "foundation" }
+2
View File
@@ -13,6 +13,8 @@ kotlin {
implementation(libs.haze) implementation(libs.haze)
implementation(libs.haze.materials) implementation(libs.haze.materials)
implementation(libs.ui.tooling.preview) implementation(libs.ui.tooling.preview)
implementation(libs.adaptive.layout)
implementation(libs.material3.adaptive.navigation.suite)
} }
} }
} }
@@ -3,14 +3,12 @@ package ru.shadowsparky.ui
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.calculateEndPadding
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
@@ -19,13 +17,17 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.NavigationBar import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarDefaults import androidx.compose.material3.NavigationBarDefaults
import androidx.compose.material3.NavigationBarItem import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.NavigationRail
import androidx.compose.material3.NavigationRailItem
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfoV2
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteItem
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffold
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffoldDefaults
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteType
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.Immutable import androidx.compose.runtime.Immutable
@@ -35,9 +37,9 @@ import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import ru.shadowsparky.ui.nav.Route import ru.shadowsparky.ui.nav.Route
import ru.shadowsparky.ui.theme.focusBorder
@Immutable @Immutable
data class NavigationEntry<out T : Route>( data class NavigationEntry<out T : Route>(
@@ -64,11 +66,15 @@ fun AppScaffold(
) )
} }
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @OptIn(
ExperimentalMaterial3Api::class,
ExperimentalMaterial3ExpressiveApi::class,
)
@Composable @Composable
fun <T : Route> AppScaffold( fun <T : Route> AppScaffold(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
scrollBehavior: TopAppBarScrollBehavior? = TopAppBarDefaults.pinnedScrollBehavior(), scrollBehavior: TopAppBarScrollBehavior? =
TopAppBarDefaults.pinnedScrollBehavior(),
snackbarState: SnackbarHostState? = null, snackbarState: SnackbarHostState? = null,
currentRoute: T? = null, currentRoute: T? = null,
navigationEntries: List<NavigationEntry<T>>? = null, navigationEntries: List<NavigationEntry<T>>? = null,
@@ -76,40 +82,111 @@ fun <T : Route> AppScaffold(
appBar: @Composable (scroll: TopAppBarScrollBehavior?) -> Unit, appBar: @Composable (scroll: TopAppBarScrollBehavior?) -> Unit,
content: @Composable (padding: PaddingValues) -> Unit, content: @Composable (padding: PaddingValues) -> Unit,
) { ) {
val windowType = currentWindowType() val navigationSuiteType = when {
navigationEntries.isNullOrEmpty() -> NavigationSuiteType.None
else -> { NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo(currentWindowAdaptiveInfoV2()) }
}
val blurState = rememberBlurState() val blurState = rememberBlurState()
CompositionLocalProvider(LocalBlurState provides blurState) { CompositionLocalProvider(LocalBlurState provides blurState) {
when (navigationSuiteType) {
NavigationSuiteType.NavigationBar -> {
BottomBarScaffold(
modifier,
navigationEntries,
currentRoute,
appBar,
content,
scrollBehavior,
onSelectNavigation,
snackbarState
)
}
else -> {
DynamicNavigationScaffold(
modifier,
navigationSuiteType,
navigationEntries,
currentRoute,
onSelectNavigation,
scrollBehavior,
appBar,
snackbarState,
content
)
}
}
}
}
@Composable
private fun <T : Route> DynamicNavigationScaffold(
modifier: Modifier,
navigationSuiteType: NavigationSuiteType,
navigationEntries: List<NavigationEntry<T>>?,
currentRoute: T?,
onSelectNavigation: ((T) -> Unit)?,
scrollBehavior: TopAppBarScrollBehavior?,
appBar: @Composable ((TopAppBarScrollBehavior?) -> Unit),
snackbarState: SnackbarHostState?,
content: @Composable ((PaddingValues) -> Unit)
) {
NavigationSuiteScaffold(
navigationSuiteType = navigationSuiteType,
navigationItems = {
navigationEntries.orEmpty().forEach { entry ->
NavigationSuiteItem(
navigationSuiteType = navigationSuiteType,
selected = currentRoute == entry.route,
onClick = { onSelectNavigation?.invoke(entry.route) },
icon = { Icon(entry.painter, entry.title) },
label = {
when (navigationSuiteType) {
NavigationSuiteType.NavigationDrawer -> Text(entry.title)
}
},
modifier = Modifier.focusBorder(false, CircleShape)
)
}
}
) {
Scaffold( Scaffold(
bottomBar = { modifier = if (scrollBehavior != null) {
if (windowType.isCompact) {
BottomBar(navigationEntries, currentRoute, onSelectNavigation)
}
},
topBar = {
appBar(scrollBehavior)
}, content = {
if (windowType.isExpanded && navigationEntries?.isNotEmpty() == true) {
ExpandedContent(
it,
navigationEntries,
currentRoute,
onSelectNavigation,
content
)
} else {
content(it)
}
}, modifier = if (scrollBehavior != null) {
modifier.nestedScroll(scrollBehavior.nestedScrollConnection) modifier.nestedScroll(scrollBehavior.nestedScrollConnection)
} else { } else {
modifier modifier
}, snackbarHost = { },
snackbarState?.let { SnackbarHost(it) } topBar = { appBar(scrollBehavior) },
} snackbarHost = { snackbarState?.let { SnackbarHost(it) } },
content = content
) )
} }
} }
@Composable
private fun <T : Route> BottomBarScaffold(
modifier: Modifier,
navigationEntries: List<NavigationEntry<T>>?,
currentRoute: T?,
appBar: @Composable (scroll: TopAppBarScrollBehavior?) -> Unit,
content: @Composable (padding: PaddingValues) -> Unit,
scrollBehavior: TopAppBarScrollBehavior?,
onSelectNavigation: ((T) -> Unit)?,
snackbarState: SnackbarHostState?
) {
Scaffold(
bottomBar = { BottomBar(navigationEntries, currentRoute, onSelectNavigation) },
topBar = { appBar(scrollBehavior) },
modifier = if (scrollBehavior != null) {
modifier.nestedScroll(scrollBehavior.nestedScrollConnection)
} else {
modifier
}, snackbarHost = {
snackbarState?.let { SnackbarHost(it) }
},
content = content
)
}
@Composable @Composable
private fun <T : Route> BottomBar( private fun <T : Route> BottomBar(
navigationEntries: List<NavigationEntry<T>>?, navigationEntries: List<NavigationEntry<T>>?,
@@ -121,11 +198,8 @@ private fun <T : Route> BottomBar(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.background( .background(
brush = Brush.verticalGradient( Brush.verticalGradient(
colors = listOf( listOf(Color.Transparent, MaterialTheme.colorScheme.surfaceContainer)
Color.Transparent,
MaterialTheme.colorScheme.surfaceContainer
)
) )
) )
.padding(8.dp) .padding(8.dp)
@@ -155,37 +229,3 @@ private fun navBarContentColor(): Color {
NavigationBarDefaults.containerColor NavigationBarDefaults.containerColor
} }
} }
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun <T : Route> ExpandedContent(
values: PaddingValues,
navigationEntries: List<NavigationEntry<T>>,
currentRoute: T?,
onSelectNavigation: ((T) -> Unit)?,
content: @Composable ((PaddingValues) -> Unit)
) {
val topPadding = values.calculateTopPadding()
val bottomPadding = values.calculateBottomPadding()
val endPadding = values.calculateEndPadding(LayoutDirection.Ltr)
Row(modifier = Modifier.fillMaxSize()) {
NavigationRail(modifier = Modifier.padding(start = 4.dp, end = 4.dp, top = topPadding)) {
navigationEntries.forEach { entry ->
NavigationRailItem(
selected = currentRoute == entry.route,
onClick = { onSelectNavigation?.invoke(entry.route) },
icon = { Icon(entry.painter, contentDescription = entry.title) }
)
}
}
Box(modifier = Modifier.weight(1f)) {
content(
PaddingValues(
top = topPadding,
end = endPadding,
bottom = bottomPadding
)
)
}
}
}
@@ -1,30 +0,0 @@
package ru.shadowsparky.ui
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalWindowInfo
@Composable
private fun currentWindowWidthDp(): Int {
val info = LocalWindowInfo.current
val density = LocalDensity.current
return with(density) { info.containerSize.width.toDp().value.toInt() }
}
@Composable
fun currentWindowType(): WindowType {
return widthToSizeClass(currentWindowWidthDp())
}
sealed interface WindowType {
object Compact : WindowType
object Expanded : WindowType
}
val WindowType.isExpanded: Boolean get() = this is WindowType.Expanded
val WindowType.isCompact: Boolean get() = this is WindowType.Compact
private fun widthToSizeClass(widthDp: Int): WindowType = when {
widthDp >= 840 -> WindowType.Expanded
else -> WindowType.Compact
}
@@ -4,12 +4,13 @@ import androiddev.libs.ui.generated.resources.Res
import androiddev.libs.ui.generated.resources.back import androiddev.libs.ui.generated.resources.back
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.IconButtonDefaults import androidx.compose.material3.IconButtonDefaults
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.resources.painterResource
import ru.shadowsparky.ui.theme.focusBorder
@Composable @Composable
fun BackButton(doBack: () -> Unit) { fun BackButton(doBack: () -> Unit) {
@@ -20,7 +21,8 @@ fun BackButton(doBack: () -> Unit) {
containerColor = MaterialTheme.colorScheme.primaryContainer.copy( containerColor = MaterialTheme.colorScheme.primaryContainer.copy(
0.1f 0.1f
) )
) ),
modifier = Modifier.focusBorder(shape = CircleShape)
) { Icon(painterResource(Res.drawable.back), contentDescription = null) } ) { Icon(painterResource(Res.drawable.back), contentDescription = null) }
} }
@@ -0,0 +1,32 @@
package ru.shadowsparky.ui.components
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.IconButton
import androidx.compose.material3.IconButtonColors
import androidx.compose.material3.IconButtonDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Shape
import ru.shadowsparky.ui.theme.focusBorder
@Composable
fun IconButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
colors: IconButtonColors = IconButtonDefaults.iconButtonColors(),
interactionSource: MutableInteractionSource? = null,
shape: Shape = IconButtonDefaults.standardShape,
content: @Composable () -> Unit,
) {
IconButton(
onClick,
modifier.focusBorder(false, CircleShape),
enabled,
colors,
interactionSource,
shape,
content
)
}
@@ -7,7 +7,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -17,6 +17,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@@ -25,7 +26,8 @@ object ComponentDefaults {
@Composable @Composable
internal fun focusBorder( internal fun focusBorder(
modifier: Modifier, modifier: Modifier,
needScale: Boolean needScale: Boolean,
borderShape: Shape
): Modifier { ): Modifier {
var isFocused by remember { mutableStateOf(false) } var isFocused by remember { mutableStateOf(false) }
val borderColor by animateColorAsState( val borderColor by animateColorAsState(
@@ -48,7 +50,7 @@ object ComponentDefaults {
scaleX = scale scaleX = scale
scaleY = scale scaleY = scale
clip = true clip = true
shape = RoundedCornerShape(12.dp) shape = borderShape
} }
} else { } else {
modifier modifier
@@ -57,12 +59,19 @@ object ComponentDefaults {
.border( .border(
width = borderWidth, width = borderWidth,
color = borderColor, color = borderColor,
shape = RoundedCornerShape(12.dp) shape = borderShape
) )
} }
} }
@Composable @Composable
fun Modifier.focusBorder(needScale: Boolean = true): Modifier { fun Modifier.focusBorder(
return ComponentDefaults.focusBorder(this, needScale) needScale: Boolean = true,
shape: Shape = RoundedCornerShape(12.dp)
): Modifier {
return ComponentDefaults.focusBorder(
this,
needScale,
shape
)
} }