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.SnackbarHostState
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
@@ -14,6 +13,7 @@ import androidx.compose.ui.Modifier
|
||||
import com.seiko.imageloader.LocalImageLoader
|
||||
import ru.shadowsparky.koin
|
||||
import ru.shadowsparky.ui.components.BackButton
|
||||
import ru.shadowsparky.ui.components.TopAppBar
|
||||
import ru.shadowsparky.ui.nav.Nav
|
||||
import ru.shadowsparky.updater.presentation.UpdateDialog
|
||||
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.material3.ExperimentalMaterial3Api
|
||||
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.CompositionLocalProvider
|
||||
import androidx.compose.ui.Modifier
|
||||
import ru.shadowsparky.ui.AppScaffold
|
||||
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.theme.ComponentDefaults
|
||||
import ru.shadowsparky.vbox.shared.presentation.chat.ChatScreen
|
||||
import ru.shadowsparky.vbox.shared.presentation.list.VideoContent
|
||||
import ru.shadowsparky.vbox.shared.presentation.nav.Child
|
||||
@@ -40,7 +35,6 @@ fun MainScreen(route: Route, child: Child, root: VBoxRootComponent) {
|
||||
fun BaseMainScreen(
|
||||
appBar: @Composable () -> Unit,
|
||||
route: Route,
|
||||
scrollBehavior: TopAppBarScrollBehavior,
|
||||
onNavigate: (Route) -> Unit,
|
||||
content: @Composable (PaddingValues) -> Unit
|
||||
) {
|
||||
@@ -51,8 +45,7 @@ fun BaseMainScreen(
|
||||
currentRoute = route,
|
||||
onSelectNavigation = { onNavigate(it) },
|
||||
navigationEntries = createNavigationList(),
|
||||
colorScheme = getColorScheme(),
|
||||
scrollBehavior = scrollBehavior
|
||||
colorScheme = getColorScheme()
|
||||
) { padding ->
|
||||
content(padding)
|
||||
}
|
||||
@@ -63,20 +56,15 @@ fun BaseMainScreen(
|
||||
@Composable
|
||||
private fun MainScreenInternal(route: Route, child: Child, onNavigate: (Route) -> Unit) {
|
||||
val navList = createNavigationList()
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
|
||||
BaseMainScreen(
|
||||
appBar = {
|
||||
navList.findTitle(route)?.let { title ->
|
||||
TopAppBar(
|
||||
title = { Text(title) },
|
||||
scrollBehavior = scrollBehavior,
|
||||
modifier = Modifier.applyBlurEffect(LocalBlurState.current),
|
||||
colors = ComponentDefaults.topAppBarColors()
|
||||
title = { Text(title) }
|
||||
)
|
||||
}
|
||||
},
|
||||
route = route,
|
||||
scrollBehavior = scrollBehavior,
|
||||
onNavigate = onNavigate,
|
||||
content = { padding ->
|
||||
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 androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.arkivanov.decompose.extensions.compose.subscribeAsState
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import ru.shadowsparky.chat.presentation.ChatComponent
|
||||
import ru.shadowsparky.chat.presentation.ChatContent
|
||||
import ru.shadowsparky.ui.LocalBlurState
|
||||
import ru.shadowsparky.ui.applyBlurEffect
|
||||
import ru.shadowsparky.ui.theme.ComponentDefaults
|
||||
import ru.shadowsparky.ui.components.TopAppBar
|
||||
import ru.shadowsparky.vbox.shared.presentation.BaseMainScreen
|
||||
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()
|
||||
BaseMainScreen(
|
||||
appBar = {
|
||||
TopAppBar(
|
||||
title = { Text(stringResource(Res.string.chat_title_app_bar)) },
|
||||
colors = ComponentDefaults.topAppBarColors(),
|
||||
modifier = Modifier.applyBlurEffect(LocalBlurState.current)
|
||||
)
|
||||
TopAppBar(title = { Text(stringResource(Res.string.chat_title_app_bar)) })
|
||||
},
|
||||
route,
|
||||
onNavigate = onNavigate,
|
||||
scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(),
|
||||
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.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
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.rememberLazyGridState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
@@ -57,19 +54,17 @@ import org.jetbrains.compose.resources.StringResource
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import ru.shadowsparky.ui.LocalBlurState
|
||||
import ru.shadowsparky.ui.applyBlurSource
|
||||
import ru.shadowsparky.ui.components.ErrorContent
|
||||
import ru.shadowsparky.ui.components.LazyVerticalGrid
|
||||
import ru.shadowsparky.ui.components.Loading
|
||||
import ru.shadowsparky.ui.rememberBlurState
|
||||
import ru.shadowsparky.vbox.shared.domain.model.VideoItem
|
||||
import ru.shadowsparky.vbox.shared.presentation.BaseScreen
|
||||
import ru.shadowsparky.vbox.shared.presentation.search.AppBarWithSearch
|
||||
import ru.shadowsparky.vbox.shared.presentation.state.rememberTopAppBarStateByHolder
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun VideoScreen(component: VideoScreenComponent) {
|
||||
val appBarState = rememberTopAppBarStateByHolder(component.topAppBarStateHolder)
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(appBarState)
|
||||
val error by component.errorCode.collectAsState(null)
|
||||
val items by component.items.collectAsState()
|
||||
val blurState = rememberBlurState()
|
||||
@@ -93,8 +88,7 @@ fun VideoScreen(component: VideoScreenComponent) {
|
||||
isDefault = title == appName,
|
||||
onBack = { component.doBack() }
|
||||
)
|
||||
},
|
||||
scrollBehavior = scrollBehavior
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -123,9 +117,10 @@ fun VideoScreenContent(
|
||||
onShowOverview: (Long) -> Unit
|
||||
) {
|
||||
if (error != null) {
|
||||
ErrorAndRetry(error) {
|
||||
onRefresh()
|
||||
}
|
||||
ErrorContent(
|
||||
error,
|
||||
buttonText = stringResource(Res.string.retry)
|
||||
) { onRefresh() }
|
||||
} else if (items != null) {
|
||||
AnimatedContent(
|
||||
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
|
||||
fun VideosNotFound(emptyResource: StringResource) {
|
||||
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.Route
|
||||
import ru.shadowsparky.vbox.shared.presentation.nav.RouteIds
|
||||
import ru.shadowsparky.vbox.shared.presentation.state.TopAppBarStateHolder
|
||||
|
||||
class VideoScreenComponent(
|
||||
private val context: ComponentContext,
|
||||
private val videoApi: VideoApi,
|
||||
private val dispatcherProvider: DispatcherProvider,
|
||||
val topAppBarStateHolder: TopAppBarStateHolder,
|
||||
val search: String? = null,
|
||||
val showOverview: (Long) -> Unit,
|
||||
val doBack: () -> Unit
|
||||
@@ -53,7 +51,6 @@ class VideoScreenComponent(
|
||||
@Factory
|
||||
@Named(RouteIds.VIDEOS)
|
||||
class VideosChildFactory(
|
||||
private val topAppBarStateHolder: TopAppBarStateHolder,
|
||||
private val videoApi: VideoApi,
|
||||
private val dispatcherProvider: DispatcherProvider
|
||||
) : ComponentFactory<Child.VideosChild, Route.Videos, Route> {
|
||||
@@ -66,7 +63,6 @@ class VideosChildFactory(
|
||||
child,
|
||||
videoApi,
|
||||
dispatcherProvider,
|
||||
topAppBarStateHolder,
|
||||
route.request,
|
||||
showOverview = { root.nav(Route.Overview(it)) },
|
||||
doBack = { root.onBack() }
|
||||
|
||||
+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.components.Loading
|
||||
import ru.shadowsparky.vbox.shared.presentation.BaseScreen
|
||||
import ru.shadowsparky.vbox.shared.presentation.list.Loading
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@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.offline_remove
|
||||
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.star
|
||||
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.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
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.CompositionLocalProvider
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
@@ -72,26 +69,23 @@ import org.jetbrains.compose.resources.painterResource
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import ru.shadowsparky.domain.Clip
|
||||
import ru.shadowsparky.ui.LocalBlurState
|
||||
import ru.shadowsparky.ui.applyBlurEffect
|
||||
import ru.shadowsparky.ui.applyBlurSource
|
||||
import ru.shadowsparky.ui.components.BackButton
|
||||
import ru.shadowsparky.ui.components.ErrorContent
|
||||
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.theme.ComponentDefaults
|
||||
import ru.shadowsparky.vbox.shared.domain.model.VideoDetails
|
||||
import ru.shadowsparky.vbox.shared.presentation.BaseScreen
|
||||
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
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun OverviewScreen(component: OverviewComponent) {
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
|
||||
val errorState by component.errorCode.collectAsState(initial = null)
|
||||
val details by component.details.collectAsState()
|
||||
val snackbarState = remember { SnackbarHostState() }
|
||||
val blurState = rememberBlurState()
|
||||
var tagsBottomSheetVisible by rememberSaveable { mutableStateOf(false) }
|
||||
CompositionLocalProvider(LocalBlurState provides blurState) {
|
||||
@@ -101,17 +95,15 @@ fun OverviewScreen(component: OverviewComponent) {
|
||||
component.offlineSupport,
|
||||
details,
|
||||
component,
|
||||
scrollBehavior,
|
||||
tagsRequest = { tagsBottomSheetVisible = true }
|
||||
)
|
||||
},
|
||||
scrollBehavior = scrollBehavior,
|
||||
snackbarState = snackbarState,
|
||||
content = { padding ->
|
||||
when {
|
||||
|
||||
errorState != null -> ErrorAndRetry(
|
||||
errorMsg = errorState!!
|
||||
errorState != null -> ErrorContent(
|
||||
errorState!!,
|
||||
buttonText = stringResource(Res.string.retry)
|
||||
) { component.loadDetailsIfNeeded() }
|
||||
|
||||
details != null -> DetailsInfo(
|
||||
@@ -145,12 +137,10 @@ private fun OverviewAppBar(
|
||||
offlineSupport: Boolean,
|
||||
details: VideoDetails?,
|
||||
component: OverviewComponent,
|
||||
scrollBehavior: TopAppBarScrollBehavior,
|
||||
tagsRequest: () -> Unit
|
||||
) {
|
||||
val isSaved by component.isSaved.collectAsStateWithLifecycle(null)
|
||||
val offlineItem by component.offlineItem.collectAsStateWithLifecycle(null)
|
||||
val blur = LocalBlurState.current
|
||||
TopAppBar(
|
||||
title = {
|
||||
details?.title?.let {
|
||||
@@ -162,7 +152,6 @@ private fun OverviewAppBar(
|
||||
}
|
||||
},
|
||||
navigationIcon = { BackButton { component.doBack() } },
|
||||
colors = ComponentDefaults.topAppBarColors(),
|
||||
actions = {
|
||||
details?.let {
|
||||
if (component.shareManager.canShare()) {
|
||||
@@ -192,9 +181,7 @@ private fun OverviewAppBar(
|
||||
tagsRequest
|
||||
) { 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.folder_check
|
||||
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.select_all
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
@@ -26,8 +27,6 @@ import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
@@ -47,19 +46,18 @@ import org.jetbrains.compose.resources.painterResource
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import ru.shadowsparky.domain.Clip
|
||||
import ru.shadowsparky.ui.LocalBlurState
|
||||
import ru.shadowsparky.ui.applyBlurEffect
|
||||
import ru.shadowsparky.ui.applyBlurSource
|
||||
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.ui.rememberBlurState
|
||||
import ru.shadowsparky.ui.theme.ComponentDefaults
|
||||
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.BaseScreen
|
||||
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)
|
||||
@Composable
|
||||
@@ -96,7 +94,6 @@ fun EpisodesOverviewContent(
|
||||
startOffline: () -> Unit,
|
||||
commitOffline: (Boolean) -> Unit
|
||||
) {
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
|
||||
val snackbarState = remember { SnackbarHostState() }
|
||||
val blurState = rememberBlurState()
|
||||
var isSaveMode by rememberSaveable { mutableStateOf(false) }
|
||||
@@ -133,9 +130,6 @@ fun EpisodesOverviewContent(
|
||||
}
|
||||
}
|
||||
},
|
||||
scrollBehavior = scrollBehavior,
|
||||
colors = ComponentDefaults.topAppBarColors(),
|
||||
modifier = Modifier.applyBlurEffect(blurState),
|
||||
actions = {
|
||||
if (offlineSupport) {
|
||||
IconButton(
|
||||
@@ -165,8 +159,7 @@ fun EpisodesOverviewContent(
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
scrollBehavior = scrollBehavior
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -184,7 +177,10 @@ fun EpisodesOverviewList(
|
||||
onOfflineClicked: (EpisodeWithOfflineInfo) -> Unit
|
||||
) {
|
||||
if (errorCode != null) {
|
||||
ErrorAndRetry(errorMsg = errorCode) { loadLinks() }
|
||||
ErrorContent(
|
||||
errorCode,
|
||||
buttonText = stringResource(Res.string.retry)
|
||||
) { loadLinks() }
|
||||
} else if (episodes != null) {
|
||||
val blur = LocalBlurState.current
|
||||
val requester = remember { FocusRequester() }
|
||||
|
||||
+2
@@ -34,6 +34,8 @@ class SeasonOverviewComponent(
|
||||
val error = _error.asSharedFlow()
|
||||
private val exceptionHandler = createExceptionHandler(componentScope) { _error.emit(it) }
|
||||
|
||||
init { load() }
|
||||
|
||||
fun load() {
|
||||
componentScope.launch(dispatchers.main + exceptionHandler) {
|
||||
_error.emit(null)
|
||||
|
||||
+10
-15
@@ -1,6 +1,7 @@
|
||||
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.retry
|
||||
import androiddev.apps.vbox.client.shared.generated.resources.seasons_overview
|
||||
import androidx.compose.foundation.clickable
|
||||
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.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
@@ -22,22 +21,19 @@ import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import ru.shadowsparky.ui.LocalBlurState
|
||||
import ru.shadowsparky.ui.applyBlurEffect
|
||||
import ru.shadowsparky.ui.applyBlurSource
|
||||
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.ui.rememberBlurState
|
||||
import ru.shadowsparky.ui.theme.ComponentDefaults
|
||||
import ru.shadowsparky.vbox.shared.domain.model.Season
|
||||
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)
|
||||
@Composable
|
||||
fun SeasonOverviewScreen(component: SeasonOverviewComponent) {
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
|
||||
LaunchedEffect(null) { component.load() }
|
||||
val blurState = rememberBlurState()
|
||||
CompositionLocalProvider(LocalBlurState provides blurState) {
|
||||
BaseScreen(
|
||||
@@ -45,9 +41,10 @@ fun SeasonOverviewScreen(component: SeasonOverviewComponent) {
|
||||
val seasons = component.season.collectAsState(null)
|
||||
val err = component.error.collectAsState(null)
|
||||
if (err.value != null) {
|
||||
ErrorAndRetry(err.value!!) {
|
||||
component.load()
|
||||
}
|
||||
ErrorContent(
|
||||
err.value!!,
|
||||
buttonText = stringResource(Res.string.retry)
|
||||
) { component.load() }
|
||||
} else if (seasons.value != null) {
|
||||
SeasonsInfo(
|
||||
seasons.value!!, it
|
||||
@@ -61,11 +58,9 @@ fun SeasonOverviewScreen(component: SeasonOverviewComponent) {
|
||||
Text(stringResource(Res.string.seasons_overview))
|
||||
}, navigationIcon = {
|
||||
BackButton { component.doBack() }
|
||||
}, scrollBehavior = scrollBehavior,
|
||||
colors = ComponentDefaults.topAppBarColors(),
|
||||
modifier = Modifier.applyBlurEffect(blurState)
|
||||
}
|
||||
)
|
||||
}, scrollBehavior = scrollBehavior
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+6
-7
@@ -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.next_episode
|
||||
import androiddev.apps.vbox.client.shared.generated.resources.retry
|
||||
import androiddev.apps.vbox.client.shared.generated.resources.start_from
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.fadeIn
|
||||
@@ -9,7 +10,6 @@ import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.slideInHorizontally
|
||||
import androidx.compose.animation.slideOutHorizontally
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
@@ -28,8 +28,8 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import ru.shadowsparky.ui.AppScaffold
|
||||
import ru.shadowsparky.ui.components.ErrorContent
|
||||
import ru.shadowsparky.ui.components.Loading
|
||||
import ru.shadowsparky.vbox.shared.presentation.list.ErrorAndRetry
|
||||
import ru.shadowsparky.videoplayer.PlayerEvent
|
||||
import ru.shadowsparky.videoplayer.ui.VideoPlayer
|
||||
|
||||
@@ -47,12 +47,11 @@ fun PlayerScreen(component: PlayerComponent) {
|
||||
when (val state = e.state) {
|
||||
is PlayerEvent.Idle -> Loading(Modifier.fillMaxSize())
|
||||
is PlayerEvent.Error -> {
|
||||
Column(modifier = Modifier.fillMaxSize().padding(it)) {
|
||||
ErrorAndRetry(
|
||||
ErrorContent(
|
||||
state.message,
|
||||
retry = { component.load() }
|
||||
)
|
||||
}
|
||||
modifier = Modifier.padding(it),
|
||||
buttonText = stringResource(Res.string.retry),
|
||||
) { component.load() }
|
||||
}
|
||||
|
||||
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.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
@@ -31,11 +29,9 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
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.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.presentation.BaseMainScreen
|
||||
import ru.shadowsparky.vbox.shared.presentation.list.VideoScreenContent
|
||||
@@ -59,13 +55,10 @@ fun SavedMovieScreen(comp: SavedMovieComponent, route: Route, onNavigate: (Route
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
},
|
||||
colors = ComponentDefaults.topAppBarColors(),
|
||||
modifier = Modifier.applyBlurEffect(LocalBlurState.current)
|
||||
}
|
||||
)
|
||||
},
|
||||
route = route,
|
||||
scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(),
|
||||
onNavigate = onNavigate,
|
||||
content = {
|
||||
if (filterBottomSheetVisible) {
|
||||
|
||||
-1
@@ -103,7 +103,6 @@ fun SearchScreen(
|
||||
) { textFieldValue = it }
|
||||
},
|
||||
route = route,
|
||||
scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(),
|
||||
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.empty_login
|
||||
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 androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
@@ -38,13 +34,14 @@ 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.components.ErrorAlert
|
||||
import ru.shadowsparky.ui.components.Loading
|
||||
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.BaseScreen
|
||||
import ru.shadowsparky.vbox.shared.presentation.SimpleAppBar
|
||||
import ru.shadowsparky.vbox.shared.presentation.list.Loading
|
||||
|
||||
@Composable
|
||||
fun AuthScreen(comp: AuthComponent) {
|
||||
@@ -107,17 +104,9 @@ fun BaseLogin(
|
||||
modifier = Modifier.padding(8.dp)
|
||||
) {
|
||||
if (errorInfo != null && state is AuthState.Error) {
|
||||
AlertDialog(
|
||||
onDismissRequest = { errorInfo = null },
|
||||
title = { Text(stringResource(Res.string.error_title)) },
|
||||
text = { Text(errorInfo!!.toMessage()) },
|
||||
confirmButton = {
|
||||
Text(
|
||||
text = stringResource(Res.string.okay),
|
||||
modifier = Modifier.padding(8.dp)
|
||||
.clickable { errorInfo = null }
|
||||
)
|
||||
},
|
||||
ErrorAlert(
|
||||
errorInfo!!.toMessage(),
|
||||
onClick = { errorInfo = null }
|
||||
)
|
||||
}
|
||||
OutlinedTextField(
|
||||
|
||||
+1
-1
@@ -31,10 +31,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.components.Loading
|
||||
import ru.shadowsparky.ui.components.PasswordTextField
|
||||
import ru.shadowsparky.vbox.shared.presentation.BaseScreen
|
||||
import ru.shadowsparky.vbox.shared.presentation.SimpleAppBar
|
||||
import ru.shadowsparky.vbox.shared.presentation.list.Loading
|
||||
import ru.shadowsparky.vbox.shared.presentation.settings.auth.AuthState
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
|
||||
+7
-10
@@ -14,7 +14,6 @@ import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
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.stringResource
|
||||
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.list.Loading
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class)
|
||||
@Composable
|
||||
fun EditServScreen(comp: EditServComponent) {
|
||||
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)
|
||||
LaunchedEffect(state) {
|
||||
if (state is EditServState.Succeed) comp.doBack()
|
||||
}
|
||||
val keyboardController = LocalSoftwareKeyboardController.current
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
BaseScreen(
|
||||
@@ -98,5 +94,6 @@ fun EditServScreen(comp: EditServComponent) {
|
||||
} else {
|
||||
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 -> {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Text(
|
||||
text = stringResource(Res.string.chat_load_error),
|
||||
color = MaterialTheme.colorScheme.error
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
#Tue Jun 23 20:20:20 MSK 2026
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
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
|
||||
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.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import ru.shadowsparky.ui.LocalBlurState
|
||||
import ru.shadowsparky.ui.applyBlurSource
|
||||
|
||||
@Composable
|
||||
expect fun isTv(): Boolean
|
||||
@@ -123,7 +125,11 @@ fun LazyColumn(
|
||||
) {
|
||||
val isTv = isTv()
|
||||
androidx.compose.foundation.lazy.LazyColumn(
|
||||
if (isTv) modifier.padding(contentPadding) else modifier,
|
||||
if (isTv) {
|
||||
modifier.padding(contentPadding)
|
||||
} else {
|
||||
modifier.applyBlurSource(LocalBlurState.current)
|
||||
},
|
||||
state,
|
||||
if (isTv) PaddingValues(0.dp) else contentPadding,
|
||||
reverseLayout,
|
||||
|
||||
@@ -14,6 +14,8 @@ import androidx.compose.foundation.rememberOverscrollEffect
|
||||
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.applyBlurSource
|
||||
|
||||
@Composable
|
||||
fun LazyVerticalGrid(
|
||||
@@ -33,7 +35,11 @@ fun LazyVerticalGrid(
|
||||
val isTv = isTv()
|
||||
androidx.compose.foundation.lazy.grid.LazyVerticalGrid(
|
||||
columns,
|
||||
if (isTv) modifier.padding(contentPadding) else modifier,
|
||||
if (isTv) {
|
||||
modifier.padding(contentPadding)
|
||||
} else {
|
||||
modifier.applyBlurSource(LocalBlurState.current)
|
||||
},
|
||||
state,
|
||||
if (isTv) PaddingValues(0.dp) else contentPadding,
|
||||
reverseLayout,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package ru.shadowsparky.ui.components
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||
import androidx.compose.material3.LoadingIndicator
|
||||
@@ -12,7 +13,7 @@ import androidx.compose.ui.unit.dp
|
||||
|
||||
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
|
||||
@Composable
|
||||
fun Loading(modifier: Modifier) {
|
||||
fun Loading(modifier: Modifier = Modifier.fillMaxSize()) {
|
||||
Box(modifier, contentAlignment = Alignment.Center) {
|
||||
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