create new common components
This commit is contained in:
-20
@@ -1,20 +0,0 @@
|
|||||||
package ru.shadowsparky.videobox.multiplatform.preview
|
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
|
||||||
import ru.shadowsparky.vbox.shared.presentation.list.ErrorAndRetry
|
|
||||||
import ru.shadowsparky.vbox.shared.presentation.list.Loading
|
|
||||||
|
|
||||||
@Preview
|
|
||||||
@Composable
|
|
||||||
fun ErrorPreview() {
|
|
||||||
ErrorAndRetry(
|
|
||||||
errorMsg = "Неизвестная ошибка"
|
|
||||||
) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Preview
|
|
||||||
@Composable
|
|
||||||
fun LoadingPreview() {
|
|
||||||
Loading()
|
|
||||||
}
|
|
||||||
+1
-1
@@ -5,7 +5,6 @@ import androidx.compose.material3.ColorScheme
|
|||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.SnackbarHostState
|
import androidx.compose.material3.SnackbarHostState
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBar
|
|
||||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
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
|
||||||
@@ -14,6 +13,7 @@ import androidx.compose.ui.Modifier
|
|||||||
import com.seiko.imageloader.LocalImageLoader
|
import com.seiko.imageloader.LocalImageLoader
|
||||||
import ru.shadowsparky.koin
|
import ru.shadowsparky.koin
|
||||||
import ru.shadowsparky.ui.components.BackButton
|
import ru.shadowsparky.ui.components.BackButton
|
||||||
|
import ru.shadowsparky.ui.components.TopAppBar
|
||||||
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
|
||||||
|
|||||||
+3
-15
@@ -3,17 +3,12 @@ package ru.shadowsparky.vbox.shared.presentation
|
|||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBar
|
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
|
||||||
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.ui.Modifier
|
|
||||||
import ru.shadowsparky.ui.AppScaffold
|
import ru.shadowsparky.ui.AppScaffold
|
||||||
import ru.shadowsparky.ui.LocalBlurState
|
import ru.shadowsparky.ui.LocalBlurState
|
||||||
import ru.shadowsparky.ui.applyBlurEffect
|
import ru.shadowsparky.ui.components.TopAppBar
|
||||||
import ru.shadowsparky.ui.rememberBlurState
|
import ru.shadowsparky.ui.rememberBlurState
|
||||||
import ru.shadowsparky.ui.theme.ComponentDefaults
|
|
||||||
import ru.shadowsparky.vbox.shared.presentation.chat.ChatScreen
|
import ru.shadowsparky.vbox.shared.presentation.chat.ChatScreen
|
||||||
import ru.shadowsparky.vbox.shared.presentation.list.VideoContent
|
import ru.shadowsparky.vbox.shared.presentation.list.VideoContent
|
||||||
import ru.shadowsparky.vbox.shared.presentation.nav.Child
|
import ru.shadowsparky.vbox.shared.presentation.nav.Child
|
||||||
@@ -40,7 +35,6 @@ fun MainScreen(route: Route, child: Child, root: VBoxRootComponent) {
|
|||||||
fun BaseMainScreen(
|
fun BaseMainScreen(
|
||||||
appBar: @Composable () -> Unit,
|
appBar: @Composable () -> Unit,
|
||||||
route: Route,
|
route: Route,
|
||||||
scrollBehavior: TopAppBarScrollBehavior,
|
|
||||||
onNavigate: (Route) -> Unit,
|
onNavigate: (Route) -> Unit,
|
||||||
content: @Composable (PaddingValues) -> Unit
|
content: @Composable (PaddingValues) -> Unit
|
||||||
) {
|
) {
|
||||||
@@ -51,8 +45,7 @@ fun BaseMainScreen(
|
|||||||
currentRoute = route,
|
currentRoute = route,
|
||||||
onSelectNavigation = { onNavigate(it) },
|
onSelectNavigation = { onNavigate(it) },
|
||||||
navigationEntries = createNavigationList(),
|
navigationEntries = createNavigationList(),
|
||||||
colorScheme = getColorScheme(),
|
colorScheme = getColorScheme()
|
||||||
scrollBehavior = scrollBehavior
|
|
||||||
) { padding ->
|
) { padding ->
|
||||||
content(padding)
|
content(padding)
|
||||||
}
|
}
|
||||||
@@ -63,20 +56,15 @@ 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()
|
||||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
|
|
||||||
BaseMainScreen(
|
BaseMainScreen(
|
||||||
appBar = {
|
appBar = {
|
||||||
navList.findTitle(route)?.let { title ->
|
navList.findTitle(route)?.let { title ->
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
title = { Text(title) },
|
title = { Text(title) }
|
||||||
scrollBehavior = scrollBehavior,
|
|
||||||
modifier = Modifier.applyBlurEffect(LocalBlurState.current),
|
|
||||||
colors = ComponentDefaults.topAppBarColors()
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
route = route,
|
route = route,
|
||||||
scrollBehavior = scrollBehavior,
|
|
||||||
onNavigate = onNavigate,
|
onNavigate = onNavigate,
|
||||||
content = { padding ->
|
content = { padding ->
|
||||||
when (child) {
|
when (child) {
|
||||||
|
|||||||
+2
-12
@@ -4,18 +4,13 @@ import androiddev.apps.vbox.client.shared.generated.resources.Res
|
|||||||
import androiddev.apps.vbox.client.shared.generated.resources.chat_title_app_bar
|
import androiddev.apps.vbox.client.shared.generated.resources.chat_title_app_bar
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBar
|
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
||||||
import org.jetbrains.compose.resources.stringResource
|
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.LocalBlurState
|
import ru.shadowsparky.ui.components.TopAppBar
|
||||||
import ru.shadowsparky.ui.applyBlurEffect
|
|
||||||
import ru.shadowsparky.ui.theme.ComponentDefaults
|
|
||||||
import ru.shadowsparky.vbox.shared.presentation.BaseMainScreen
|
import ru.shadowsparky.vbox.shared.presentation.BaseMainScreen
|
||||||
import ru.shadowsparky.vbox.shared.presentation.nav.Route
|
import ru.shadowsparky.vbox.shared.presentation.nav.Route
|
||||||
|
|
||||||
@@ -25,15 +20,10 @@ fun ChatScreen(component: ChatComponent, route: Route, onNavigate: (Route) -> Un
|
|||||||
val state by component.state.subscribeAsState()
|
val state by component.state.subscribeAsState()
|
||||||
BaseMainScreen(
|
BaseMainScreen(
|
||||||
appBar = {
|
appBar = {
|
||||||
TopAppBar(
|
TopAppBar(title = { Text(stringResource(Res.string.chat_title_app_bar)) })
|
||||||
title = { Text(stringResource(Res.string.chat_title_app_bar)) },
|
|
||||||
colors = ComponentDefaults.topAppBarColors(),
|
|
||||||
modifier = Modifier.applyBlurEffect(LocalBlurState.current)
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
route,
|
route,
|
||||||
onNavigate = onNavigate,
|
onNavigate = onNavigate,
|
||||||
scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(),
|
|
||||||
content = { ChatContent(component, it, state) }
|
content = { ChatContent(component, it, state) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-39
@@ -17,7 +17,6 @@ import androidx.compose.foundation.border
|
|||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.aspectRatio
|
import androidx.compose.foundation.layout.aspectRatio
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
@@ -26,11 +25,9 @@ import androidx.compose.foundation.lazy.grid.GridCells
|
|||||||
import androidx.compose.foundation.lazy.grid.itemsIndexed
|
import androidx.compose.foundation.lazy.grid.itemsIndexed
|
||||||
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
|
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.Button
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
@@ -57,19 +54,17 @@ import org.jetbrains.compose.resources.StringResource
|
|||||||
import org.jetbrains.compose.resources.stringResource
|
import org.jetbrains.compose.resources.stringResource
|
||||||
import ru.shadowsparky.ui.LocalBlurState
|
import ru.shadowsparky.ui.LocalBlurState
|
||||||
import ru.shadowsparky.ui.applyBlurSource
|
import ru.shadowsparky.ui.applyBlurSource
|
||||||
|
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.rememberBlurState
|
import ru.shadowsparky.ui.rememberBlurState
|
||||||
import ru.shadowsparky.vbox.shared.domain.model.VideoItem
|
import ru.shadowsparky.vbox.shared.domain.model.VideoItem
|
||||||
import ru.shadowsparky.vbox.shared.presentation.BaseScreen
|
import ru.shadowsparky.vbox.shared.presentation.BaseScreen
|
||||||
import ru.shadowsparky.vbox.shared.presentation.search.AppBarWithSearch
|
import ru.shadowsparky.vbox.shared.presentation.search.AppBarWithSearch
|
||||||
import ru.shadowsparky.vbox.shared.presentation.state.rememberTopAppBarStateByHolder
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun VideoScreen(component: VideoScreenComponent) {
|
fun VideoScreen(component: VideoScreenComponent) {
|
||||||
val appBarState = rememberTopAppBarStateByHolder(component.topAppBarStateHolder)
|
|
||||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(appBarState)
|
|
||||||
val error by component.errorCode.collectAsState(null)
|
val error by component.errorCode.collectAsState(null)
|
||||||
val items by component.items.collectAsState()
|
val items by component.items.collectAsState()
|
||||||
val blurState = rememberBlurState()
|
val blurState = rememberBlurState()
|
||||||
@@ -93,8 +88,7 @@ fun VideoScreen(component: VideoScreenComponent) {
|
|||||||
isDefault = title == appName,
|
isDefault = title == appName,
|
||||||
onBack = { component.doBack() }
|
onBack = { component.doBack() }
|
||||||
)
|
)
|
||||||
},
|
}
|
||||||
scrollBehavior = scrollBehavior
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,9 +117,10 @@ fun VideoScreenContent(
|
|||||||
onShowOverview: (Long) -> Unit
|
onShowOverview: (Long) -> Unit
|
||||||
) {
|
) {
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
ErrorAndRetry(error) {
|
ErrorContent(
|
||||||
onRefresh()
|
error,
|
||||||
}
|
buttonText = stringResource(Res.string.retry)
|
||||||
|
) { onRefresh() }
|
||||||
} else if (items != null) {
|
} else if (items != null) {
|
||||||
AnimatedContent(
|
AnimatedContent(
|
||||||
items,
|
items,
|
||||||
@@ -259,29 +254,6 @@ fun Poster(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun ErrorAndRetry(errorMsg: String, retry: () -> Unit) {
|
|
||||||
Column(
|
|
||||||
verticalArrangement = Arrangement.Center,
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
modifier = Modifier.fillMaxSize()
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = errorMsg,
|
|
||||||
style = MaterialTheme.typography.titleMedium,
|
|
||||||
modifier = Modifier.padding(bottom = 4.dp),
|
|
||||||
textAlign = TextAlign.Center
|
|
||||||
)
|
|
||||||
Button(onClick = { retry() }) {
|
|
||||||
Text(
|
|
||||||
text = stringResource(Res.string.retry),
|
|
||||||
style = MaterialTheme.typography.bodyMedium
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun VideosNotFound(emptyResource: StringResource) {
|
fun VideosNotFound(emptyResource: StringResource) {
|
||||||
Box(
|
Box(
|
||||||
@@ -296,8 +268,3 @@ fun VideosNotFound(emptyResource: StringResource) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun Loading() {
|
|
||||||
Loading(Modifier.fillMaxSize())
|
|
||||||
}
|
|
||||||
|
|||||||
-4
@@ -19,13 +19,11 @@ import ru.shadowsparky.vbox.shared.presentation.createExceptionHandler
|
|||||||
import ru.shadowsparky.vbox.shared.presentation.nav.Child
|
import ru.shadowsparky.vbox.shared.presentation.nav.Child
|
||||||
import ru.shadowsparky.vbox.shared.presentation.nav.Route
|
import ru.shadowsparky.vbox.shared.presentation.nav.Route
|
||||||
import ru.shadowsparky.vbox.shared.presentation.nav.RouteIds
|
import ru.shadowsparky.vbox.shared.presentation.nav.RouteIds
|
||||||
import ru.shadowsparky.vbox.shared.presentation.state.TopAppBarStateHolder
|
|
||||||
|
|
||||||
class VideoScreenComponent(
|
class VideoScreenComponent(
|
||||||
private val context: ComponentContext,
|
private val context: ComponentContext,
|
||||||
private val videoApi: VideoApi,
|
private val videoApi: VideoApi,
|
||||||
private val dispatcherProvider: DispatcherProvider,
|
private val dispatcherProvider: DispatcherProvider,
|
||||||
val topAppBarStateHolder: TopAppBarStateHolder,
|
|
||||||
val search: String? = null,
|
val search: String? = null,
|
||||||
val showOverview: (Long) -> Unit,
|
val showOverview: (Long) -> Unit,
|
||||||
val doBack: () -> Unit
|
val doBack: () -> Unit
|
||||||
@@ -53,7 +51,6 @@ class VideoScreenComponent(
|
|||||||
@Factory
|
@Factory
|
||||||
@Named(RouteIds.VIDEOS)
|
@Named(RouteIds.VIDEOS)
|
||||||
class VideosChildFactory(
|
class VideosChildFactory(
|
||||||
private val topAppBarStateHolder: TopAppBarStateHolder,
|
|
||||||
private val videoApi: VideoApi,
|
private val videoApi: VideoApi,
|
||||||
private val dispatcherProvider: DispatcherProvider
|
private val dispatcherProvider: DispatcherProvider
|
||||||
) : ComponentFactory<Child.VideosChild, Route.Videos, Route> {
|
) : ComponentFactory<Child.VideosChild, Route.Videos, Route> {
|
||||||
@@ -66,7 +63,6 @@ class VideosChildFactory(
|
|||||||
child,
|
child,
|
||||||
videoApi,
|
videoApi,
|
||||||
dispatcherProvider,
|
dispatcherProvider,
|
||||||
topAppBarStateHolder,
|
|
||||||
route.request,
|
route.request,
|
||||||
showOverview = { root.nav(Route.Overview(it)) },
|
showOverview = { root.nav(Route.Overview(it)) },
|
||||||
doBack = { root.onBack() }
|
doBack = { root.onBack() }
|
||||||
|
|||||||
+1
-1
@@ -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.components.Loading
|
||||||
import ru.shadowsparky.vbox.shared.presentation.BaseScreen
|
import ru.shadowsparky.vbox.shared.presentation.BaseScreen
|
||||||
import ru.shadowsparky.vbox.shared.presentation.list.Loading
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
|||||||
+8
-21
@@ -8,6 +8,7 @@ import androiddev.apps.vbox.client.shared.generated.resources.details_serial
|
|||||||
import androiddev.apps.vbox.client.shared.generated.resources.more
|
import androiddev.apps.vbox.client.shared.generated.resources.more
|
||||||
import androiddev.apps.vbox.client.shared.generated.resources.offline_remove
|
import androiddev.apps.vbox.client.shared.generated.resources.offline_remove
|
||||||
import androiddev.apps.vbox.client.shared.generated.resources.offline_save
|
import androiddev.apps.vbox.client.shared.generated.resources.offline_save
|
||||||
|
import androiddev.apps.vbox.client.shared.generated.resources.retry
|
||||||
import androiddev.apps.vbox.client.shared.generated.resources.share
|
import androiddev.apps.vbox.client.shared.generated.resources.share
|
||||||
import androiddev.apps.vbox.client.shared.generated.resources.star
|
import androiddev.apps.vbox.client.shared.generated.resources.star
|
||||||
import androiddev.apps.vbox.client.shared.generated.resources.star_unchecked
|
import androiddev.apps.vbox.client.shared.generated.resources.star_unchecked
|
||||||
@@ -41,11 +42,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api
|
|||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.SnackbarHostState
|
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBar
|
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
|
||||||
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.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
@@ -72,26 +69,23 @@ 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.LocalBlurState
|
import ru.shadowsparky.ui.LocalBlurState
|
||||||
import ru.shadowsparky.ui.applyBlurEffect
|
|
||||||
import ru.shadowsparky.ui.applyBlurSource
|
import ru.shadowsparky.ui.applyBlurSource
|
||||||
import ru.shadowsparky.ui.components.BackButton
|
import ru.shadowsparky.ui.components.BackButton
|
||||||
|
import ru.shadowsparky.ui.components.ErrorContent
|
||||||
import ru.shadowsparky.ui.components.LazyColumn
|
import ru.shadowsparky.ui.components.LazyColumn
|
||||||
|
import ru.shadowsparky.ui.components.Loading
|
||||||
|
import ru.shadowsparky.ui.components.TopAppBar
|
||||||
import ru.shadowsparky.ui.rememberBlurState
|
import ru.shadowsparky.ui.rememberBlurState
|
||||||
import ru.shadowsparky.ui.theme.ComponentDefaults
|
|
||||||
import ru.shadowsparky.vbox.shared.domain.model.VideoDetails
|
import ru.shadowsparky.vbox.shared.domain.model.VideoDetails
|
||||||
import ru.shadowsparky.vbox.shared.presentation.BaseScreen
|
import ru.shadowsparky.vbox.shared.presentation.BaseScreen
|
||||||
import ru.shadowsparky.vbox.shared.presentation.getClipboardText
|
import ru.shadowsparky.vbox.shared.presentation.getClipboardText
|
||||||
import ru.shadowsparky.vbox.shared.presentation.list.ErrorAndRetry
|
|
||||||
import ru.shadowsparky.vbox.shared.presentation.list.Loading
|
|
||||||
import ru.shadowsparky.vbox.shared.presentation.settings.tag.LinkTagBottomSheet
|
import ru.shadowsparky.vbox.shared.presentation.settings.tag.LinkTagBottomSheet
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun OverviewScreen(component: OverviewComponent) {
|
fun OverviewScreen(component: OverviewComponent) {
|
||||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
|
|
||||||
val errorState by component.errorCode.collectAsState(initial = null)
|
val errorState by component.errorCode.collectAsState(initial = null)
|
||||||
val details by component.details.collectAsState()
|
val details by component.details.collectAsState()
|
||||||
val snackbarState = remember { SnackbarHostState() }
|
|
||||||
val blurState = rememberBlurState()
|
val blurState = rememberBlurState()
|
||||||
var tagsBottomSheetVisible by rememberSaveable { mutableStateOf(false) }
|
var tagsBottomSheetVisible by rememberSaveable { mutableStateOf(false) }
|
||||||
CompositionLocalProvider(LocalBlurState provides blurState) {
|
CompositionLocalProvider(LocalBlurState provides blurState) {
|
||||||
@@ -101,17 +95,15 @@ fun OverviewScreen(component: OverviewComponent) {
|
|||||||
component.offlineSupport,
|
component.offlineSupport,
|
||||||
details,
|
details,
|
||||||
component,
|
component,
|
||||||
scrollBehavior,
|
|
||||||
tagsRequest = { tagsBottomSheetVisible = true }
|
tagsRequest = { tagsBottomSheetVisible = true }
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
scrollBehavior = scrollBehavior,
|
|
||||||
snackbarState = snackbarState,
|
|
||||||
content = { padding ->
|
content = { padding ->
|
||||||
when {
|
when {
|
||||||
|
|
||||||
errorState != null -> ErrorAndRetry(
|
errorState != null -> ErrorContent(
|
||||||
errorMsg = errorState!!
|
errorState!!,
|
||||||
|
buttonText = stringResource(Res.string.retry)
|
||||||
) { component.loadDetailsIfNeeded() }
|
) { component.loadDetailsIfNeeded() }
|
||||||
|
|
||||||
details != null -> DetailsInfo(
|
details != null -> DetailsInfo(
|
||||||
@@ -145,12 +137,10 @@ private fun OverviewAppBar(
|
|||||||
offlineSupport: Boolean,
|
offlineSupport: Boolean,
|
||||||
details: VideoDetails?,
|
details: VideoDetails?,
|
||||||
component: OverviewComponent,
|
component: OverviewComponent,
|
||||||
scrollBehavior: TopAppBarScrollBehavior,
|
|
||||||
tagsRequest: () -> Unit
|
tagsRequest: () -> Unit
|
||||||
) {
|
) {
|
||||||
val isSaved by component.isSaved.collectAsStateWithLifecycle(null)
|
val isSaved by component.isSaved.collectAsStateWithLifecycle(null)
|
||||||
val offlineItem by component.offlineItem.collectAsStateWithLifecycle(null)
|
val offlineItem by component.offlineItem.collectAsStateWithLifecycle(null)
|
||||||
val blur = LocalBlurState.current
|
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
title = {
|
title = {
|
||||||
details?.title?.let {
|
details?.title?.let {
|
||||||
@@ -162,7 +152,6 @@ private fun OverviewAppBar(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
navigationIcon = { BackButton { component.doBack() } },
|
navigationIcon = { BackButton { component.doBack() } },
|
||||||
colors = ComponentDefaults.topAppBarColors(),
|
|
||||||
actions = {
|
actions = {
|
||||||
details?.let {
|
details?.let {
|
||||||
if (component.shareManager.canShare()) {
|
if (component.shareManager.canShare()) {
|
||||||
@@ -192,9 +181,7 @@ private fun OverviewAppBar(
|
|||||||
tagsRequest
|
tagsRequest
|
||||||
) { component.updateOffline(offlineItem) }
|
) { component.updateOffline(offlineItem) }
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
scrollBehavior = scrollBehavior,
|
|
||||||
modifier = Modifier.applyBlurEffect(blur)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+9
-13
@@ -7,6 +7,7 @@ import androiddev.apps.vbox.client.shared.generated.resources.episodes_overview
|
|||||||
import androiddev.apps.vbox.client.shared.generated.resources.eye
|
import androiddev.apps.vbox.client.shared.generated.resources.eye
|
||||||
import androiddev.apps.vbox.client.shared.generated.resources.folder_check
|
import androiddev.apps.vbox.client.shared.generated.resources.folder_check
|
||||||
import androiddev.apps.vbox.client.shared.generated.resources.pending
|
import androiddev.apps.vbox.client.shared.generated.resources.pending
|
||||||
|
import androiddev.apps.vbox.client.shared.generated.resources.retry
|
||||||
import androiddev.apps.vbox.client.shared.generated.resources.save_as
|
import androiddev.apps.vbox.client.shared.generated.resources.save_as
|
||||||
import androiddev.apps.vbox.client.shared.generated.resources.select_all
|
import androiddev.apps.vbox.client.shared.generated.resources.select_all
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
@@ -26,8 +27,6 @@ import androidx.compose.material3.Icon
|
|||||||
import androidx.compose.material3.IconButton
|
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.material3.TopAppBar
|
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
@@ -47,19 +46,18 @@ 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.LocalBlurState
|
import ru.shadowsparky.ui.LocalBlurState
|
||||||
import ru.shadowsparky.ui.applyBlurEffect
|
|
||||||
import ru.shadowsparky.ui.applyBlurSource
|
import ru.shadowsparky.ui.applyBlurSource
|
||||||
import ru.shadowsparky.ui.components.BackButton
|
import ru.shadowsparky.ui.components.BackButton
|
||||||
|
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.TopAppBar
|
||||||
import ru.shadowsparky.ui.rememberBlurState
|
import ru.shadowsparky.ui.rememberBlurState
|
||||||
import ru.shadowsparky.ui.theme.ComponentDefaults
|
|
||||||
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.BaseScreen
|
import ru.shadowsparky.vbox.shared.presentation.BaseScreen
|
||||||
import ru.shadowsparky.vbox.shared.presentation.getClipboardText
|
import ru.shadowsparky.vbox.shared.presentation.getClipboardText
|
||||||
import ru.shadowsparky.vbox.shared.presentation.list.ErrorAndRetry
|
|
||||||
import ru.shadowsparky.vbox.shared.presentation.list.Loading
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
@@ -96,7 +94,6 @@ fun EpisodesOverviewContent(
|
|||||||
startOffline: () -> Unit,
|
startOffline: () -> Unit,
|
||||||
commitOffline: (Boolean) -> Unit
|
commitOffline: (Boolean) -> Unit
|
||||||
) {
|
) {
|
||||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
|
|
||||||
val snackbarState = remember { SnackbarHostState() }
|
val snackbarState = remember { SnackbarHostState() }
|
||||||
val blurState = rememberBlurState()
|
val blurState = rememberBlurState()
|
||||||
var isSaveMode by rememberSaveable { mutableStateOf(false) }
|
var isSaveMode by rememberSaveable { mutableStateOf(false) }
|
||||||
@@ -133,9 +130,6 @@ fun EpisodesOverviewContent(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
scrollBehavior = scrollBehavior,
|
|
||||||
colors = ComponentDefaults.topAppBarColors(),
|
|
||||||
modifier = Modifier.applyBlurEffect(blurState),
|
|
||||||
actions = {
|
actions = {
|
||||||
if (offlineSupport) {
|
if (offlineSupport) {
|
||||||
IconButton(
|
IconButton(
|
||||||
@@ -165,8 +159,7 @@ fun EpisodesOverviewContent(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
}
|
||||||
scrollBehavior = scrollBehavior
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,7 +177,10 @@ fun EpisodesOverviewList(
|
|||||||
onOfflineClicked: (EpisodeWithOfflineInfo) -> Unit
|
onOfflineClicked: (EpisodeWithOfflineInfo) -> Unit
|
||||||
) {
|
) {
|
||||||
if (errorCode != null) {
|
if (errorCode != null) {
|
||||||
ErrorAndRetry(errorMsg = errorCode) { loadLinks() }
|
ErrorContent(
|
||||||
|
errorCode,
|
||||||
|
buttonText = stringResource(Res.string.retry)
|
||||||
|
) { loadLinks() }
|
||||||
} else if (episodes != null) {
|
} else if (episodes != null) {
|
||||||
val blur = LocalBlurState.current
|
val blur = LocalBlurState.current
|
||||||
val requester = remember { FocusRequester() }
|
val requester = remember { FocusRequester() }
|
||||||
|
|||||||
+2
@@ -34,6 +34,8 @@ class SeasonOverviewComponent(
|
|||||||
val error = _error.asSharedFlow()
|
val error = _error.asSharedFlow()
|
||||||
private val exceptionHandler = createExceptionHandler(componentScope) { _error.emit(it) }
|
private val exceptionHandler = createExceptionHandler(componentScope) { _error.emit(it) }
|
||||||
|
|
||||||
|
init { load() }
|
||||||
|
|
||||||
fun load() {
|
fun load() {
|
||||||
componentScope.launch(dispatchers.main + exceptionHandler) {
|
componentScope.launch(dispatchers.main + exceptionHandler) {
|
||||||
_error.emit(null)
|
_error.emit(null)
|
||||||
|
|||||||
+10
-15
@@ -1,6 +1,7 @@
|
|||||||
package ru.shadowsparky.vbox.shared.presentation.overview.season
|
package ru.shadowsparky.vbox.shared.presentation.overview.season
|
||||||
|
|
||||||
import androiddev.apps.vbox.client.shared.generated.resources.Res
|
import androiddev.apps.vbox.client.shared.generated.resources.Res
|
||||||
|
import androiddev.apps.vbox.client.shared.generated.resources.retry
|
||||||
import androiddev.apps.vbox.client.shared.generated.resources.seasons_overview
|
import androiddev.apps.vbox.client.shared.generated.resources.seasons_overview
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
@@ -8,8 +9,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
|||||||
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.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBar
|
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
@@ -22,22 +21,19 @@ 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.LocalBlurState
|
import ru.shadowsparky.ui.LocalBlurState
|
||||||
import ru.shadowsparky.ui.applyBlurEffect
|
|
||||||
import ru.shadowsparky.ui.applyBlurSource
|
import ru.shadowsparky.ui.applyBlurSource
|
||||||
import ru.shadowsparky.ui.components.BackButton
|
import ru.shadowsparky.ui.components.BackButton
|
||||||
|
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.TopAppBar
|
||||||
import ru.shadowsparky.ui.rememberBlurState
|
import ru.shadowsparky.ui.rememberBlurState
|
||||||
import ru.shadowsparky.ui.theme.ComponentDefaults
|
|
||||||
import ru.shadowsparky.vbox.shared.domain.model.Season
|
import ru.shadowsparky.vbox.shared.domain.model.Season
|
||||||
import ru.shadowsparky.vbox.shared.presentation.BaseScreen
|
import ru.shadowsparky.vbox.shared.presentation.BaseScreen
|
||||||
import ru.shadowsparky.vbox.shared.presentation.list.ErrorAndRetry
|
|
||||||
import ru.shadowsparky.vbox.shared.presentation.list.Loading
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun SeasonOverviewScreen(component: SeasonOverviewComponent) {
|
fun SeasonOverviewScreen(component: SeasonOverviewComponent) {
|
||||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
|
|
||||||
LaunchedEffect(null) { component.load() }
|
|
||||||
val blurState = rememberBlurState()
|
val blurState = rememberBlurState()
|
||||||
CompositionLocalProvider(LocalBlurState provides blurState) {
|
CompositionLocalProvider(LocalBlurState provides blurState) {
|
||||||
BaseScreen(
|
BaseScreen(
|
||||||
@@ -45,9 +41,10 @@ fun SeasonOverviewScreen(component: SeasonOverviewComponent) {
|
|||||||
val seasons = component.season.collectAsState(null)
|
val seasons = component.season.collectAsState(null)
|
||||||
val err = component.error.collectAsState(null)
|
val err = component.error.collectAsState(null)
|
||||||
if (err.value != null) {
|
if (err.value != null) {
|
||||||
ErrorAndRetry(err.value!!) {
|
ErrorContent(
|
||||||
component.load()
|
err.value!!,
|
||||||
}
|
buttonText = stringResource(Res.string.retry)
|
||||||
|
) { component.load() }
|
||||||
} else if (seasons.value != null) {
|
} else if (seasons.value != null) {
|
||||||
SeasonsInfo(
|
SeasonsInfo(
|
||||||
seasons.value!!, it
|
seasons.value!!, it
|
||||||
@@ -61,11 +58,9 @@ fun SeasonOverviewScreen(component: SeasonOverviewComponent) {
|
|||||||
Text(stringResource(Res.string.seasons_overview))
|
Text(stringResource(Res.string.seasons_overview))
|
||||||
}, navigationIcon = {
|
}, navigationIcon = {
|
||||||
BackButton { component.doBack() }
|
BackButton { component.doBack() }
|
||||||
}, scrollBehavior = scrollBehavior,
|
}
|
||||||
colors = ComponentDefaults.topAppBarColors(),
|
|
||||||
modifier = Modifier.applyBlurEffect(blurState)
|
|
||||||
)
|
)
|
||||||
}, scrollBehavior = scrollBehavior
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-8
@@ -2,6 +2,7 @@ package ru.shadowsparky.vbox.shared.presentation.player
|
|||||||
|
|
||||||
import androiddev.apps.vbox.client.shared.generated.resources.Res
|
import androiddev.apps.vbox.client.shared.generated.resources.Res
|
||||||
import androiddev.apps.vbox.client.shared.generated.resources.next_episode
|
import androiddev.apps.vbox.client.shared.generated.resources.next_episode
|
||||||
|
import androiddev.apps.vbox.client.shared.generated.resources.retry
|
||||||
import androiddev.apps.vbox.client.shared.generated.resources.start_from
|
import androiddev.apps.vbox.client.shared.generated.resources.start_from
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.animation.fadeIn
|
import androidx.compose.animation.fadeIn
|
||||||
@@ -9,7 +10,6 @@ import androidx.compose.animation.fadeOut
|
|||||||
import androidx.compose.animation.slideInHorizontally
|
import androidx.compose.animation.slideInHorizontally
|
||||||
import androidx.compose.animation.slideOutHorizontally
|
import androidx.compose.animation.slideOutHorizontally
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
@@ -28,8 +28,8 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||||||
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.AppScaffold
|
||||||
|
import ru.shadowsparky.ui.components.ErrorContent
|
||||||
import ru.shadowsparky.ui.components.Loading
|
import ru.shadowsparky.ui.components.Loading
|
||||||
import ru.shadowsparky.vbox.shared.presentation.list.ErrorAndRetry
|
|
||||||
import ru.shadowsparky.videoplayer.PlayerEvent
|
import ru.shadowsparky.videoplayer.PlayerEvent
|
||||||
import ru.shadowsparky.videoplayer.ui.VideoPlayer
|
import ru.shadowsparky.videoplayer.ui.VideoPlayer
|
||||||
|
|
||||||
@@ -47,12 +47,11 @@ fun PlayerScreen(component: PlayerComponent) {
|
|||||||
when (val state = e.state) {
|
when (val state = e.state) {
|
||||||
is PlayerEvent.Idle -> Loading(Modifier.fillMaxSize())
|
is PlayerEvent.Idle -> Loading(Modifier.fillMaxSize())
|
||||||
is PlayerEvent.Error -> {
|
is PlayerEvent.Error -> {
|
||||||
Column(modifier = Modifier.fillMaxSize().padding(it)) {
|
ErrorContent(
|
||||||
ErrorAndRetry(
|
state.message,
|
||||||
state.message,
|
modifier = Modifier.padding(it),
|
||||||
retry = { component.load() }
|
buttonText = stringResource(Res.string.retry),
|
||||||
)
|
) { component.load() }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is PlayerEvent.Ended -> component.requestNextEpisode()
|
is PlayerEvent.Ended -> component.requestNextEpisode()
|
||||||
|
|||||||
+2
-9
@@ -18,8 +18,6 @@ import androidx.compose.material3.Icon
|
|||||||
import androidx.compose.material3.IconButton
|
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.TopAppBarDefaults
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
@@ -31,11 +29,9 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
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.LocalBlurState
|
|
||||||
import ru.shadowsparky.ui.applyBlurEffect
|
|
||||||
import ru.shadowsparky.ui.components.AlertContent
|
import ru.shadowsparky.ui.components.AlertContent
|
||||||
import ru.shadowsparky.ui.components.LazyColumn
|
import ru.shadowsparky.ui.components.LazyColumn
|
||||||
import ru.shadowsparky.ui.theme.ComponentDefaults
|
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.BaseMainScreen
|
||||||
import ru.shadowsparky.vbox.shared.presentation.list.VideoScreenContent
|
import ru.shadowsparky.vbox.shared.presentation.list.VideoScreenContent
|
||||||
@@ -59,13 +55,10 @@ fun SavedMovieScreen(comp: SavedMovieComponent, route: Route, onNavigate: (Route
|
|||||||
contentDescription = null
|
contentDescription = null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
colors = ComponentDefaults.topAppBarColors(),
|
|
||||||
modifier = Modifier.applyBlurEffect(LocalBlurState.current)
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
route = route,
|
route = route,
|
||||||
scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(),
|
|
||||||
onNavigate = onNavigate,
|
onNavigate = onNavigate,
|
||||||
content = {
|
content = {
|
||||||
if (filterBottomSheetVisible) {
|
if (filterBottomSheetVisible) {
|
||||||
|
|||||||
-1
@@ -103,7 +103,6 @@ fun SearchScreen(
|
|||||||
) { textFieldValue = it }
|
) { textFieldValue = it }
|
||||||
},
|
},
|
||||||
route = route,
|
route = route,
|
||||||
scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(),
|
|
||||||
onNavigate = onNavigate
|
onNavigate = onNavigate
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-16
@@ -7,17 +7,13 @@ import androiddev.apps.vbox.client.shared.generated.resources.account_password
|
|||||||
import androiddev.apps.vbox.client.shared.generated.resources.account_reg_hint
|
import androiddev.apps.vbox.client.shared.generated.resources.account_reg_hint
|
||||||
import androiddev.apps.vbox.client.shared.generated.resources.empty_login
|
import androiddev.apps.vbox.client.shared.generated.resources.empty_login
|
||||||
import androiddev.apps.vbox.client.shared.generated.resources.empty_pass
|
import androiddev.apps.vbox.client.shared.generated.resources.empty_pass
|
||||||
import androiddev.apps.vbox.client.shared.generated.resources.error_title
|
|
||||||
import androiddev.apps.vbox.client.shared.generated.resources.okay
|
|
||||||
import androiddev.apps.vbox.client.shared.generated.resources.unknown_error
|
import androiddev.apps.vbox.client.shared.generated.resources.unknown_error
|
||||||
import androidx.compose.foundation.clickable
|
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
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.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.material3.AlertDialog
|
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.OutlinedButton
|
import androidx.compose.material3.OutlinedButton
|
||||||
@@ -38,13 +34,14 @@ 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.components.ErrorAlert
|
||||||
|
import ru.shadowsparky.ui.components.Loading
|
||||||
import ru.shadowsparky.ui.components.PasswordTextField
|
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.BaseScreen
|
import ru.shadowsparky.vbox.shared.presentation.BaseScreen
|
||||||
import ru.shadowsparky.vbox.shared.presentation.SimpleAppBar
|
import ru.shadowsparky.vbox.shared.presentation.SimpleAppBar
|
||||||
import ru.shadowsparky.vbox.shared.presentation.list.Loading
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AuthScreen(comp: AuthComponent) {
|
fun AuthScreen(comp: AuthComponent) {
|
||||||
@@ -107,17 +104,9 @@ fun BaseLogin(
|
|||||||
modifier = Modifier.padding(8.dp)
|
modifier = Modifier.padding(8.dp)
|
||||||
) {
|
) {
|
||||||
if (errorInfo != null && state is AuthState.Error) {
|
if (errorInfo != null && state is AuthState.Error) {
|
||||||
AlertDialog(
|
ErrorAlert(
|
||||||
onDismissRequest = { errorInfo = null },
|
errorInfo!!.toMessage(),
|
||||||
title = { Text(stringResource(Res.string.error_title)) },
|
onClick = { errorInfo = null }
|
||||||
text = { Text(errorInfo!!.toMessage()) },
|
|
||||||
confirmButton = {
|
|
||||||
Text(
|
|
||||||
text = stringResource(Res.string.okay),
|
|
||||||
modifier = Modifier.padding(8.dp)
|
|
||||||
.clickable { errorInfo = null }
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
|||||||
+1
-1
@@ -31,10 +31,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.components.Loading
|
||||||
import ru.shadowsparky.ui.components.PasswordTextField
|
import ru.shadowsparky.ui.components.PasswordTextField
|
||||||
import ru.shadowsparky.vbox.shared.presentation.BaseScreen
|
import ru.shadowsparky.vbox.shared.presentation.BaseScreen
|
||||||
import ru.shadowsparky.vbox.shared.presentation.SimpleAppBar
|
import ru.shadowsparky.vbox.shared.presentation.SimpleAppBar
|
||||||
import ru.shadowsparky.vbox.shared.presentation.list.Loading
|
|
||||||
import ru.shadowsparky.vbox.shared.presentation.settings.auth.AuthState
|
import ru.shadowsparky.vbox.shared.presentation.settings.auth.AuthState
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
|||||||
+7
-10
@@ -14,7 +14,6 @@ import androidx.compose.material3.Icon
|
|||||||
import androidx.compose.material3.IconButton
|
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.material3.TopAppBar
|
|
||||||
import androidx.compose.runtime.Composable
|
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
|
||||||
@@ -36,21 +35,18 @@ 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.components.BackButton
|
import ru.shadowsparky.ui.components.BackButton
|
||||||
|
import ru.shadowsparky.ui.components.Loading
|
||||||
|
import ru.shadowsparky.ui.components.TopAppBar
|
||||||
import ru.shadowsparky.vbox.shared.presentation.BaseScreen
|
import ru.shadowsparky.vbox.shared.presentation.BaseScreen
|
||||||
import ru.shadowsparky.vbox.shared.presentation.list.Loading
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class)
|
@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun EditServScreen(comp: EditServComponent) {
|
fun EditServScreen(comp: EditServComponent) {
|
||||||
val url by comp.serverUrl.collectAsState(null)
|
val url by comp.serverUrl.collectAsState(null)
|
||||||
LaunchedEffect(null) {
|
|
||||||
comp.state.collect {
|
|
||||||
if (it is EditServState.Succeed) {
|
|
||||||
comp.doBack()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val state by comp.state.collectAsState(null)
|
val state by comp.state.collectAsState(null)
|
||||||
|
LaunchedEffect(state) {
|
||||||
|
if (state is EditServState.Succeed) comp.doBack()
|
||||||
|
}
|
||||||
val keyboardController = LocalSoftwareKeyboardController.current
|
val keyboardController = LocalSoftwareKeyboardController.current
|
||||||
val focusRequester = remember { FocusRequester() }
|
val focusRequester = remember { FocusRequester() }
|
||||||
BaseScreen(
|
BaseScreen(
|
||||||
@@ -98,5 +94,6 @@ fun EditServScreen(comp: EditServComponent) {
|
|||||||
} else {
|
} else {
|
||||||
Loading()
|
Loading()
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
-35
@@ -1,35 +0,0 @@
|
|||||||
package ru.shadowsparky.vbox.shared.presentation.state
|
|
||||||
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
||||||
import androidx.compose.material3.TopAppBarState
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.DisposableEffect
|
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
|
||||||
import org.koin.core.annotation.Factory
|
|
||||||
|
|
||||||
@Factory
|
|
||||||
class TopAppBarStateHolder {
|
|
||||||
var heightOffsetLimit: Float = -Float.MAX_VALUE
|
|
||||||
var heightOffset: Float = 0f
|
|
||||||
var contentOffset: Float = 0f
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
@Composable
|
|
||||||
fun rememberTopAppBarStateByHolder(holder: TopAppBarStateHolder): TopAppBarState {
|
|
||||||
val state = rememberSaveable(saver = TopAppBarState.Saver) {
|
|
||||||
TopAppBarState(
|
|
||||||
holder.heightOffsetLimit,
|
|
||||||
holder.heightOffset,
|
|
||||||
holder.contentOffset
|
|
||||||
)
|
|
||||||
}
|
|
||||||
DisposableEffect(Unit) {
|
|
||||||
onDispose {
|
|
||||||
holder.heightOffsetLimit = state.heightOffsetLimit
|
|
||||||
holder.heightOffset = state.heightOffset
|
|
||||||
holder.contentOffset = state.contentOffset
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
+1
-3
@@ -92,9 +92,7 @@ fun ChatContent(
|
|||||||
}
|
}
|
||||||
|
|
||||||
is ChatState.Error -> {
|
is ChatState.Error -> {
|
||||||
Column(
|
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
) {
|
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(Res.string.chat_load_error),
|
text = stringResource(Res.string.chat_load_error),
|
||||||
color = MaterialTheme.colorScheme.error
|
color = MaterialTheme.colorScheme.error
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
#Tue Jun 23 20:20:20 MSK 2026
|
#Tue Jun 23 20:20:20 MSK 2026
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.0-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
<resources>
|
||||||
|
<string name="error_title">Произошла ошибка</string>
|
||||||
|
<string name="ok">Понятно</string>
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
package ru.shadowsparky.ui.components
|
||||||
|
|
||||||
|
import androiddev.libs.ui.generated.resources.Res
|
||||||
|
import androiddev.libs.ui.generated.resources.error_title
|
||||||
|
import androiddev.libs.ui.generated.resources.ok
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import org.jetbrains.compose.resources.stringResource
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ErrorContent(
|
||||||
|
message: String,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
buttonModifier: Modifier = Modifier,
|
||||||
|
buttonText: String = stringResource(Res.string.ok),
|
||||||
|
onClick: () -> Unit
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
modifier = modifier.fillMaxSize().padding(4.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(Res.string.error_title),
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
Spacer(Modifier.height(2.dp))
|
||||||
|
Text(
|
||||||
|
text = message,
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
Spacer(Modifier.height(8.dp))
|
||||||
|
Button(modifier = buttonModifier, onClick = { onClick() }) {
|
||||||
|
Text(
|
||||||
|
text = buttonText,
|
||||||
|
style = MaterialTheme.typography.bodyMedium
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ErrorAlert(
|
||||||
|
message: String,
|
||||||
|
buttonText: String = stringResource(Res.string.ok),
|
||||||
|
onClick: () -> Unit,
|
||||||
|
onSkip: () -> Unit = onClick
|
||||||
|
) {
|
||||||
|
AlertContent(onSkip) {
|
||||||
|
ErrorContent(
|
||||||
|
message,
|
||||||
|
Modifier,
|
||||||
|
Modifier.fillMaxWidth(),
|
||||||
|
buttonText,
|
||||||
|
onClick
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun ErrorContentPreview() {
|
||||||
|
ErrorContent("что-то пошло не так") {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun ErrorAlertPreview() {
|
||||||
|
ErrorAlert(
|
||||||
|
"Увы... Что-то опять идет не так...",
|
||||||
|
onClick = {
|
||||||
|
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -14,6 +14,8 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import ru.shadowsparky.ui.LocalBlurState
|
||||||
|
import ru.shadowsparky.ui.applyBlurSource
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
expect fun isTv(): Boolean
|
expect fun isTv(): Boolean
|
||||||
@@ -123,7 +125,11 @@ fun LazyColumn(
|
|||||||
) {
|
) {
|
||||||
val isTv = isTv()
|
val isTv = isTv()
|
||||||
androidx.compose.foundation.lazy.LazyColumn(
|
androidx.compose.foundation.lazy.LazyColumn(
|
||||||
if (isTv) modifier.padding(contentPadding) else modifier,
|
if (isTv) {
|
||||||
|
modifier.padding(contentPadding)
|
||||||
|
} else {
|
||||||
|
modifier.applyBlurSource(LocalBlurState.current)
|
||||||
|
},
|
||||||
state,
|
state,
|
||||||
if (isTv) PaddingValues(0.dp) else contentPadding,
|
if (isTv) PaddingValues(0.dp) else contentPadding,
|
||||||
reverseLayout,
|
reverseLayout,
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ import androidx.compose.foundation.rememberOverscrollEffect
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import ru.shadowsparky.ui.LocalBlurState
|
||||||
|
import ru.shadowsparky.ui.applyBlurSource
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun LazyVerticalGrid(
|
fun LazyVerticalGrid(
|
||||||
@@ -33,7 +35,11 @@ fun LazyVerticalGrid(
|
|||||||
val isTv = isTv()
|
val isTv = isTv()
|
||||||
androidx.compose.foundation.lazy.grid.LazyVerticalGrid(
|
androidx.compose.foundation.lazy.grid.LazyVerticalGrid(
|
||||||
columns,
|
columns,
|
||||||
if (isTv) modifier.padding(contentPadding) else modifier,
|
if (isTv) {
|
||||||
|
modifier.padding(contentPadding)
|
||||||
|
} else {
|
||||||
|
modifier.applyBlurSource(LocalBlurState.current)
|
||||||
|
},
|
||||||
state,
|
state,
|
||||||
if (isTv) PaddingValues(0.dp) else contentPadding,
|
if (isTv) PaddingValues(0.dp) else contentPadding,
|
||||||
reverseLayout,
|
reverseLayout,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package ru.shadowsparky.ui.components
|
package ru.shadowsparky.ui.components
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||||
import androidx.compose.material3.LoadingIndicator
|
import androidx.compose.material3.LoadingIndicator
|
||||||
@@ -12,7 +13,7 @@ import androidx.compose.ui.unit.dp
|
|||||||
|
|
||||||
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
|
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun Loading(modifier: Modifier) {
|
fun Loading(modifier: Modifier = Modifier.fillMaxSize()) {
|
||||||
Box(modifier, contentAlignment = Alignment.Center) {
|
Box(modifier, contentAlignment = Alignment.Center) {
|
||||||
LoadingIndicator(Modifier.size(96.dp))
|
LoadingIndicator(Modifier.size(96.dp))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package ru.shadowsparky.ui.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.RowScope
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
|
import androidx.compose.material3.TopAppBarColors
|
||||||
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
|
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
import ru.shadowsparky.ui.LocalBlurState
|
||||||
|
import ru.shadowsparky.ui.applyBlurEffect
|
||||||
|
import ru.shadowsparky.ui.theme.ComponentDefaults
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun TopAppBar(
|
||||||
|
title: @Composable () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
navigationIcon: @Composable () -> Unit = {},
|
||||||
|
actions: @Composable RowScope.() -> Unit = {},
|
||||||
|
expandedHeight: Dp = TopAppBarDefaults.TopAppBarExpandedHeight,
|
||||||
|
windowInsets: WindowInsets = TopAppBarDefaults.windowInsets,
|
||||||
|
colors: TopAppBarColors = ComponentDefaults.topAppBarColors(),
|
||||||
|
scrollBehavior: TopAppBarScrollBehavior? = null,
|
||||||
|
contentPadding: PaddingValues = TopAppBarDefaults.ContentPadding
|
||||||
|
) {
|
||||||
|
TopAppBar(
|
||||||
|
title = title,
|
||||||
|
modifier = modifier.applyBlurEffect(LocalBlurState.current),
|
||||||
|
navigationIcon = navigationIcon,
|
||||||
|
actions = actions,
|
||||||
|
expandedHeight = expandedHeight,
|
||||||
|
windowInsets = windowInsets,
|
||||||
|
colors = colors,
|
||||||
|
scrollBehavior = scrollBehavior,
|
||||||
|
contentPadding = contentPadding
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user