update scaffolds
This commit is contained in:
+1
-2
@@ -17,7 +17,7 @@ import ru.shadowsparky.vbox.shared.presentation.nav.Route
|
||||
|
||||
@Composable
|
||||
fun createNavigationList(): List<NavigationEntry<Route>> {
|
||||
val list = listOf(
|
||||
return listOf(
|
||||
NavigationEntry(
|
||||
Route.default,
|
||||
stringResource(Res.string.recommendations),
|
||||
@@ -44,7 +44,6 @@ fun createNavigationList(): List<NavigationEntry<Route>> {
|
||||
painterResource(Res.drawable.settings)
|
||||
)
|
||||
)
|
||||
return list
|
||||
}
|
||||
|
||||
fun List<NavigationEntry<*>>.findTitle(route: Route): String? {
|
||||
|
||||
+3
-7
@@ -29,7 +29,7 @@ fun MainScreen(route: Route, child: Child, root: VBoxRootComponent) {
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun BaseMainScreen(
|
||||
fun MainScreenScaffold(
|
||||
appBar: @Composable () -> Unit,
|
||||
route: Route,
|
||||
onNavigate: (Route) -> Unit,
|
||||
@@ -47,13 +47,9 @@ fun BaseMainScreen(
|
||||
@Composable
|
||||
private fun MainScreenInternal(route: Route, child: Child, onNavigate: (Route) -> Unit) {
|
||||
val navList = createNavigationList()
|
||||
BaseMainScreen(
|
||||
MainScreenScaffold(
|
||||
appBar = {
|
||||
navList.findTitle(route)?.let { title ->
|
||||
TopAppBar(
|
||||
title = { Text(title) }
|
||||
)
|
||||
}
|
||||
navList.findTitle(route)?.let { title -> TopAppBar(title = { Text(title) }) }
|
||||
},
|
||||
route = route,
|
||||
onNavigate = onNavigate,
|
||||
|
||||
-29
@@ -1,15 +1,9 @@
|
||||
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.CompositionLocalProvider
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.seiko.imageloader.LocalImageLoader
|
||||
import ru.shadowsparky.koin
|
||||
import ru.shadowsparky.ui.nav.Nav
|
||||
import ru.shadowsparky.updater.presentation.UpdateDialog
|
||||
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.tag.TagScreen
|
||||
|
||||
@Composable
|
||||
fun Modifier.imePaddingInternal(): Modifier {
|
||||
return koin.get<UiConfiguration>().imePadding(this)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Nav(root: VBoxRootComponent, onAttach: @Composable () -> Unit = {}) {
|
||||
CompositionLocalProvider(
|
||||
@@ -74,21 +63,3 @@ private fun NavInternal(root: VBoxRootComponent, onAttach: @Composable () -> Uni
|
||||
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() }
|
||||
)
|
||||
}
|
||||
|
||||
-13
@@ -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
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -11,14 +11,14 @@ import org.jetbrains.compose.resources.stringResource
|
||||
import ru.shadowsparky.chat.presentation.ChatComponent
|
||||
import ru.shadowsparky.chat.presentation.ChatContent
|
||||
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
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ChatScreen(component: ChatComponent, route: Route, onNavigate: (Route) -> Unit) {
|
||||
val state by component.state.subscribeAsState()
|
||||
BaseMainScreen(
|
||||
MainScreenScaffold(
|
||||
appBar = {
|
||||
TopAppBar(title = { Text(stringResource(Res.string.chat_title_app_bar)) })
|
||||
},
|
||||
|
||||
+1
-1
@@ -39,12 +39,12 @@ import androidx.compose.ui.unit.dp
|
||||
import com.seiko.imageloader.rememberImagePainter
|
||||
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.LazyVerticalGrid
|
||||
import ru.shadowsparky.ui.components.Loading
|
||||
import ru.shadowsparky.ui.theme.focusBorder
|
||||
import ru.shadowsparky.vbox.shared.domain.model.VideoItem
|
||||
import ru.shadowsparky.vbox.shared.presentation.AppScaffold
|
||||
import ru.shadowsparky.vbox.shared.presentation.search.AppBarWithSearch
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
|
||||
+1
-1
@@ -5,8 +5,8 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import ru.shadowsparky.ui.AppScaffold
|
||||
import ru.shadowsparky.ui.components.Loading
|
||||
import ru.shadowsparky.vbox.shared.presentation.AppScaffold
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
|
||||
+1
-1
@@ -25,7 +25,6 @@ import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
@@ -45,6 +44,7 @@ import org.jetbrains.compose.resources.stringResource
|
||||
import ru.shadowsparky.ui.AppScaffold
|
||||
import ru.shadowsparky.ui.components.BackButton
|
||||
import ru.shadowsparky.ui.components.ExpressiveLazyColumn
|
||||
import ru.shadowsparky.ui.components.IconButton
|
||||
import ru.shadowsparky.ui.components.Loading
|
||||
import ru.shadowsparky.vbox.shared.domain.EpisodeOfflineVideo
|
||||
import ru.shadowsparky.vbox.shared.domain.OfflineState
|
||||
|
||||
+2
-2
@@ -41,7 +41,6 @@ import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
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
|
||||
@@ -68,13 +67,14 @@ import com.seiko.imageloader.rememberImagePainter
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import ru.shadowsparky.domain.Clip
|
||||
import ru.shadowsparky.ui.AppScaffold
|
||||
import ru.shadowsparky.ui.components.BackButton
|
||||
import ru.shadowsparky.ui.components.ErrorContent
|
||||
import ru.shadowsparky.ui.components.IconButton
|
||||
import ru.shadowsparky.ui.components.LazyColumn
|
||||
import ru.shadowsparky.ui.components.Loading
|
||||
import ru.shadowsparky.ui.components.TopAppBar
|
||||
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.settings.tag.LinkTagBottomSheet
|
||||
|
||||
|
||||
+2
-2
@@ -24,7 +24,6 @@ import androidx.compose.material3.CircularWavyProgressIndicator
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Text
|
||||
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.stringResource
|
||||
import ru.shadowsparky.domain.Clip
|
||||
import ru.shadowsparky.ui.AppScaffold
|
||||
import ru.shadowsparky.ui.components.BackButton
|
||||
import ru.shadowsparky.ui.components.ErrorContent
|
||||
import ru.shadowsparky.ui.components.ExpressiveLazyColumn
|
||||
import ru.shadowsparky.ui.components.IconButton
|
||||
import ru.shadowsparky.ui.components.Loading
|
||||
import ru.shadowsparky.ui.components.TopAppBar
|
||||
import ru.shadowsparky.vbox.shared.domain.OfflineState
|
||||
import ru.shadowsparky.vbox.shared.domain.OfflineVideo
|
||||
import ru.shadowsparky.vbox.shared.domain.model.Episode
|
||||
import ru.shadowsparky.vbox.shared.presentation.AppScaffold
|
||||
import ru.shadowsparky.vbox.shared.presentation.getClipboardText
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
|
||||
+1
-1
@@ -20,13 +20,13 @@ import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import ru.shadowsparky.ui.AppScaffold
|
||||
import ru.shadowsparky.ui.components.BackButton
|
||||
import ru.shadowsparky.ui.components.ErrorContent
|
||||
import ru.shadowsparky.ui.components.ExpressiveLazyColumn
|
||||
import ru.shadowsparky.ui.components.Loading
|
||||
import ru.shadowsparky.ui.components.TopAppBar
|
||||
import ru.shadowsparky.vbox.shared.domain.model.Season
|
||||
import ru.shadowsparky.vbox.shared.presentation.AppScaffold
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
|
||||
+3
-3
@@ -15,7 +15,6 @@ import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
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
|
||||
@@ -30,10 +29,11 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import ru.shadowsparky.ui.components.AlertContent
|
||||
import ru.shadowsparky.ui.components.IconButton
|
||||
import ru.shadowsparky.ui.components.LazyColumn
|
||||
import ru.shadowsparky.ui.components.TopAppBar
|
||||
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.nav.Route
|
||||
|
||||
@@ -42,7 +42,7 @@ import ru.shadowsparky.vbox.shared.presentation.nav.Route
|
||||
fun SavedMovieScreen(comp: SavedMovieComponent, route: Route, onNavigate: (Route) -> Unit) {
|
||||
val tags by comp.userTags.collectAsStateWithLifecycle(null)
|
||||
var filterBottomSheetVisible by rememberSaveable { mutableStateOf(false) }
|
||||
BaseMainScreen(
|
||||
MainScreenScaffold(
|
||||
appBar = {
|
||||
TopAppBar(
|
||||
title = { Text(stringResource(Res.string.saved_movies)) },
|
||||
|
||||
+4
-6
@@ -24,7 +24,6 @@ import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.LinearWavyProgressIndicator
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
@@ -65,8 +64,8 @@ import org.jetbrains.compose.resources.painterResource
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import ru.shadowsparky.ui.components.AppBarWithSearch
|
||||
import ru.shadowsparky.ui.components.ExpressiveLazyColumn
|
||||
import ru.shadowsparky.vbox.shared.presentation.BaseMainScreen
|
||||
import ru.shadowsparky.vbox.shared.presentation.imePaddingInternal
|
||||
import ru.shadowsparky.ui.components.IconButton
|
||||
import ru.shadowsparky.vbox.shared.presentation.MainScreenScaffold
|
||||
import ru.shadowsparky.vbox.shared.presentation.nav.Route
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@@ -80,7 +79,7 @@ fun SearchScreen(
|
||||
var textFieldValue by rememberSaveable(stateSaver = TextFieldValue.Saver) {
|
||||
mutableStateOf(TextFieldValue())
|
||||
}
|
||||
BaseMainScreen(
|
||||
MainScreenScaffold(
|
||||
appBar = {
|
||||
SearchAppBar(
|
||||
textFieldValue = textFieldValue,
|
||||
@@ -153,8 +152,7 @@ fun OldSearchInfo(
|
||||
val keyboardController = LocalSoftwareKeyboardController.current
|
||||
val nestedScrollConnection = remember { HideKeyboardConnection { keyboardController } }
|
||||
ExpressiveLazyColumn(
|
||||
modifier = Modifier.nestedScroll(nestedScrollConnection)
|
||||
.imePaddingInternal(),
|
||||
modifier = Modifier.nestedScroll(nestedScrollConnection),
|
||||
contentPadding = contentPaddingValues,
|
||||
content = {
|
||||
section {
|
||||
|
||||
+1
-1
@@ -35,6 +35,7 @@ import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import ru.shadowsparky.ui.AppScaffold
|
||||
import ru.shadowsparky.ui.components.BackButton
|
||||
import ru.shadowsparky.ui.components.ErrorAlert
|
||||
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.EmptyPasswordException
|
||||
import ru.shadowsparky.vbox.shared.domain.model.LoginException
|
||||
import ru.shadowsparky.vbox.shared.presentation.AppScaffold
|
||||
|
||||
@Composable
|
||||
fun AuthScreen(comp: AuthComponent) {
|
||||
|
||||
+1
-1
@@ -32,10 +32,10 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import ru.shadowsparky.ui.AppScaffold
|
||||
import ru.shadowsparky.ui.components.BackButton
|
||||
import ru.shadowsparky.ui.components.Loading
|
||||
import ru.shadowsparky.ui.components.PasswordTextField
|
||||
import ru.shadowsparky.vbox.shared.presentation.AppScaffold
|
||||
import ru.shadowsparky.vbox.shared.presentation.settings.auth.AuthState
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
|
||||
+2
-2
@@ -11,7 +11,7 @@ import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
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.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -34,10 +34,10 @@ import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import ru.shadowsparky.ui.AppScaffold
|
||||
import ru.shadowsparky.ui.components.BackButton
|
||||
import ru.shadowsparky.ui.components.Loading
|
||||
import ru.shadowsparky.ui.components.TopAppBar
|
||||
import ru.shadowsparky.vbox.shared.presentation.AppScaffold
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class)
|
||||
@Composable
|
||||
|
||||
+1
-1
@@ -33,7 +33,6 @@ import androidx.compose.material3.Button
|
||||
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.OutlinedTextField
|
||||
@@ -76,6 +75,7 @@ import ru.shadowsparky.chat.domain.ChatRoles
|
||||
import ru.shadowsparky.chat.domain.Message
|
||||
import ru.shadowsparky.chat.domain.TextToken
|
||||
import ru.shadowsparky.ui.components.AlertContent
|
||||
import ru.shadowsparky.ui.components.IconButton
|
||||
import ru.shadowsparky.ui.components.LazyColumn
|
||||
import ru.shadowsparky.ui.components.Loading
|
||||
import ru.shadowsparky.ui.components.TextPreference
|
||||
|
||||
+4
-11
@@ -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.replay_24px
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.focusGroup
|
||||
import androidx.compose.foundation.focusable
|
||||
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.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.CircularWavyProgressIndicator
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Slider
|
||||
import androidx.compose.material3.Text
|
||||
@@ -59,7 +58,9 @@ import androidx.compose.ui.unit.dp
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
import ru.shadowsparky.ui.components.IconButton
|
||||
import ru.shadowsparky.ui.components.isTv
|
||||
import ru.shadowsparky.ui.theme.focusBorder
|
||||
import ru.shadowsparky.videoplayer.AudioTrackInfo
|
||||
import ru.shadowsparky.videoplayer.ControlsState
|
||||
import ru.shadowsparky.videoplayer.PlayerController
|
||||
@@ -391,13 +392,5 @@ private fun Modifier.focusableWithBorder(requester: FocusRequester): Modifier {
|
||||
var isFocused by remember { mutableStateOf(false) }
|
||||
return this.focusRequester(requester)
|
||||
.onFocusChanged { isFocused = it.isFocused }
|
||||
.border(
|
||||
width = 2.dp,
|
||||
color = if (isFocused) {
|
||||
MaterialTheme.colorScheme.primary
|
||||
} else {
|
||||
Color.Transparent
|
||||
},
|
||||
shape = RoundedCornerShape(24.dp)
|
||||
)
|
||||
.focusBorder(false, CircleShape)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
[versions]
|
||||
activity-compose = "1.13.0"
|
||||
|
||||
appcompat = "1.7.1"
|
||||
material3-compose = "1.12.0-alpha03"
|
||||
adaptiveLayout = "1.3.0-beta02"
|
||||
appcompat = "1.8.0"
|
||||
coil-compose = "3.5.0"
|
||||
componentsResources = "1.11.1"
|
||||
compose-material-version = "1.11.0-alpha03"
|
||||
compose-version = "1.11.1"
|
||||
desugar_jdk_libs = "2.1.5"
|
||||
foundation = "1.11.1"
|
||||
@@ -19,7 +19,7 @@ decompose-version = "3.5.0"
|
||||
image-loader = "1.10.0"
|
||||
junit = "4.13.2"
|
||||
lifecycleCoroutines = "2.5.0"
|
||||
material = "1.11.4"
|
||||
material = "1.12.0"
|
||||
materialVersion = "1.14.0"
|
||||
media3 = "1.11.0"
|
||||
mockk = "1.14.11"
|
||||
@@ -29,7 +29,7 @@ kotlinx-coroutines-core = "1.11.0"
|
||||
kotlinx-serialization-json = "1.11.0"
|
||||
ktor-plugin = "3.5.2"
|
||||
kxml2 = "2.4.1"
|
||||
logback-classic = "1.6.1"
|
||||
logback-classic = "1.6.3"
|
||||
multiplatform-settings = "1.3.0"
|
||||
postgresql = "42.7.13"
|
||||
runner = "1.7.0"
|
||||
@@ -53,6 +53,7 @@ krpc = "0.10.3"
|
||||
core = "1.19.0"
|
||||
|
||||
[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-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastore-preferences-core" }
|
||||
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-websockets-jvm = { module = "io.ktor:ktor-server-websockets-jvm" }
|
||||
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" }
|
||||
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-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-components-resources = { module = "org.jetbrains.compose.components:components-resources", version.ref = "componentsResources" }
|
||||
compose-foundation = { module = "org.jetbrains.compose.foundation:foundation", version.ref = "foundation" }
|
||||
|
||||
@@ -13,6 +13,8 @@ kotlin {
|
||||
implementation(libs.haze)
|
||||
implementation(libs.haze.materials)
|
||||
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.layout.Box
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
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.navigationBars
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||
@@ -19,13 +17,17 @@ import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.NavigationBar
|
||||
import androidx.compose.material3.NavigationBarDefaults
|
||||
import androidx.compose.material3.NavigationBarItem
|
||||
import androidx.compose.material3.NavigationRail
|
||||
import androidx.compose.material3.NavigationRailItem
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
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.CompositionLocalProvider
|
||||
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.painter.Painter
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ru.shadowsparky.ui.nav.Route
|
||||
import ru.shadowsparky.ui.theme.focusBorder
|
||||
|
||||
@Immutable
|
||||
data class NavigationEntry<out T : Route>(
|
||||
@@ -64,11 +66,15 @@ fun AppScaffold(
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
|
||||
@OptIn(
|
||||
ExperimentalMaterial3Api::class,
|
||||
ExperimentalMaterial3ExpressiveApi::class,
|
||||
)
|
||||
@Composable
|
||||
fun <T : Route> AppScaffold(
|
||||
modifier: Modifier = Modifier,
|
||||
scrollBehavior: TopAppBarScrollBehavior? = TopAppBarDefaults.pinnedScrollBehavior(),
|
||||
scrollBehavior: TopAppBarScrollBehavior? =
|
||||
TopAppBarDefaults.pinnedScrollBehavior(),
|
||||
snackbarState: SnackbarHostState? = null,
|
||||
currentRoute: T? = null,
|
||||
navigationEntries: List<NavigationEntry<T>>? = null,
|
||||
@@ -76,39 +82,110 @@ fun <T : Route> AppScaffold(
|
||||
appBar: @Composable (scroll: TopAppBarScrollBehavior?) -> Unit,
|
||||
content: @Composable (padding: PaddingValues) -> Unit,
|
||||
) {
|
||||
val windowType = currentWindowType()
|
||||
val navigationSuiteType = when {
|
||||
navigationEntries.isNullOrEmpty() -> NavigationSuiteType.None
|
||||
else -> { NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo(currentWindowAdaptiveInfoV2()) }
|
||||
}
|
||||
val blurState = rememberBlurState()
|
||||
CompositionLocalProvider(LocalBlurState provides blurState) {
|
||||
Scaffold(
|
||||
bottomBar = {
|
||||
if (windowType.isCompact) {
|
||||
BottomBar(navigationEntries, currentRoute, onSelectNavigation)
|
||||
when (navigationSuiteType) {
|
||||
NavigationSuiteType.NavigationBar -> {
|
||||
BottomBarScaffold(
|
||||
modifier,
|
||||
navigationEntries,
|
||||
currentRoute,
|
||||
appBar,
|
||||
content,
|
||||
scrollBehavior,
|
||||
onSelectNavigation,
|
||||
snackbarState
|
||||
)
|
||||
}
|
||||
},
|
||||
topBar = {
|
||||
appBar(scrollBehavior)
|
||||
}, content = {
|
||||
if (windowType.isExpanded && navigationEntries?.isNotEmpty() == true) {
|
||||
ExpandedContent(
|
||||
it,
|
||||
else -> {
|
||||
DynamicNavigationScaffold(
|
||||
modifier,
|
||||
navigationSuiteType,
|
||||
navigationEntries,
|
||||
currentRoute,
|
||||
onSelectNavigation,
|
||||
scrollBehavior,
|
||||
appBar,
|
||||
snackbarState,
|
||||
content
|
||||
)
|
||||
} else {
|
||||
content(it)
|
||||
}
|
||||
}, modifier = if (scrollBehavior != null) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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(
|
||||
modifier = if (scrollBehavior != null) {
|
||||
modifier.nestedScroll(scrollBehavior.nestedScrollConnection)
|
||||
} else {
|
||||
modifier
|
||||
},
|
||||
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
|
||||
private fun <T : Route> BottomBar(
|
||||
@@ -121,11 +198,8 @@ private fun <T : Route> BottomBar(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(
|
||||
brush = Brush.verticalGradient(
|
||||
colors = listOf(
|
||||
Color.Transparent,
|
||||
MaterialTheme.colorScheme.surfaceContainer
|
||||
)
|
||||
Brush.verticalGradient(
|
||||
listOf(Color.Transparent, MaterialTheme.colorScheme.surfaceContainer)
|
||||
)
|
||||
)
|
||||
.padding(8.dp)
|
||||
@@ -155,37 +229,3 @@ private fun navBarContentColor(): Color {
|
||||
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 androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.IconButtonDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
import ru.shadowsparky.ui.theme.focusBorder
|
||||
|
||||
@Composable
|
||||
fun BackButton(doBack: () -> Unit) {
|
||||
@@ -20,7 +21,8 @@ fun BackButton(doBack: () -> Unit) {
|
||||
containerColor = MaterialTheme.colorScheme.primaryContainer.copy(
|
||||
0.1f
|
||||
)
|
||||
)
|
||||
),
|
||||
modifier = Modifier.focusBorder(shape = CircleShape)
|
||||
) { 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.KeyboardOptions
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
|
||||
@@ -17,6 +17,7 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.onFocusChanged
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@@ -25,7 +26,8 @@ object ComponentDefaults {
|
||||
@Composable
|
||||
internal fun focusBorder(
|
||||
modifier: Modifier,
|
||||
needScale: Boolean
|
||||
needScale: Boolean,
|
||||
borderShape: Shape
|
||||
): Modifier {
|
||||
var isFocused by remember { mutableStateOf(false) }
|
||||
val borderColor by animateColorAsState(
|
||||
@@ -48,7 +50,7 @@ object ComponentDefaults {
|
||||
scaleX = scale
|
||||
scaleY = scale
|
||||
clip = true
|
||||
shape = RoundedCornerShape(12.dp)
|
||||
shape = borderShape
|
||||
}
|
||||
} else {
|
||||
modifier
|
||||
@@ -57,12 +59,19 @@ object ComponentDefaults {
|
||||
.border(
|
||||
width = borderWidth,
|
||||
color = borderColor,
|
||||
shape = RoundedCornerShape(12.dp)
|
||||
shape = borderShape
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Modifier.focusBorder(needScale: Boolean = true): Modifier {
|
||||
return ComponentDefaults.focusBorder(this, needScale)
|
||||
fun Modifier.focusBorder(
|
||||
needScale: Boolean = true,
|
||||
shape: Shape = RoundedCornerShape(12.dp)
|
||||
): Modifier {
|
||||
return ComponentDefaults.focusBorder(
|
||||
this,
|
||||
needScale,
|
||||
shape
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user