Skip to content

Commit

Permalink
added search
Browse files Browse the repository at this point in the history
  • Loading branch information
DatL4g committed Mar 17, 2024
1 parent dbdede1 commit 712f65a
Show file tree
Hide file tree
Showing 14 changed files with 314 additions and 495 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ sealed interface Project {
val github: String?

data object PULZ : Project {
override val icon: ImageResource? = SharedRes.images.PulZ
override val icon: ImageResource = SharedRes.images.PulZ
override val title: StringResource = SharedRes.strings.pulz
override val subTitle: StringResource = SharedRes.strings.pulz_subtitle

override val `package`: String = "dev.datlag.pulz"
override val googlePlay: String? = "https://play.google.com/store/apps/details?id=$`package`"
override val github: String? = "https://github.com/DatL4g/PulZ"
override val googlePlay: String = "https://play.google.com/store/apps/details?id=$`package`"
override val github: String = "https://github.com/DatL4g/PulZ"
}

data object AniFlow : Project {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package dev.datlag.burningseries.shared.ui.custom

import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.text.KeyboardOptions
Expand Down Expand Up @@ -28,27 +30,44 @@ import kotlinx.coroutines.delay
fun FloatingSearchButton(
icon: ImageVector = Icons.Default.Search,
contentDescription: String? = stringResource(SharedRes.strings.search),
enabled: Boolean = true,
clearIcon: ImageVector = Icons.Default.Clear,
closeIcon: ImageVector = Icons.AutoMirrored.Default.KeyboardArrowRight,
modifier: Modifier = Modifier,
onClick: () -> Unit = { },
overrideOnClick: Boolean = false,
onTextChange: (String) -> Unit
) {
val focusRequester = remember { FocusRequester() }
var opened by remember { mutableStateOf(false) }
val textState = remember { mutableStateOf("") }
val enabledColor = if (enabled) {
MaterialTheme.colorScheme.primaryContainer
} else {
MaterialTheme.colorScheme.tertiaryContainer
}
val animatedColor by animateColorAsState(
targetValue = enabledColor,
animationSpec = tween()
)

Surface(
color = MaterialTheme.colorScheme.primaryContainer,
color = animatedColor,
modifier = modifier,
shape = FloatingActionButtonDefaults.shape,
shadowElevation = 6.dp,
onClick = {
if (!opened) {
opened = true
if (overrideOnClick) {
onClick()
} else {
focusRequester.requestFocus()
if (!opened) {
opened = true
} else {
focusRequester.requestFocus()
}
}
}
},
enabled = enabled
) {
AnimatedContent(targetState = opened) { expand ->
if (expand) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import dev.datlag.burningseries.shared.LocalDI
import dev.datlag.burningseries.shared.common.backAnimation
import dev.datlag.burningseries.shared.ui.screen.initial.InitialScreenComponent
import dev.datlag.burningseries.shared.ui.screen.video.VideoScreenComponent
import io.github.aakira.napier.Napier
import org.kodein.di.DI

class NavHostComponent(
Expand Down Expand Up @@ -49,7 +50,8 @@ class NavHostComponent(
stream.toList()
)
)
}
},
onBack = navigation::pop
)
is ScreenConfig.Video -> VideoScreenComponent(
componentContext = componentContext,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ import com.arkivanov.decompose.ExperimentalDecomposeApi
import com.arkivanov.decompose.router.pages.*
import com.arkivanov.decompose.value.Value
import com.arkivanov.decompose.value.operator.map
import com.arkivanov.essenty.backhandler.BackCallback
import dev.datlag.burningseries.model.Series
import dev.datlag.burningseries.model.Shortcut
import dev.datlag.burningseries.shared.LocalDI
import dev.datlag.burningseries.shared.SharedRes
import dev.datlag.burningseries.shared.ui.navigation.Component
import dev.datlag.burningseries.shared.ui.screen.initial.favorite.FavoriteScreenComponent
import dev.datlag.burningseries.shared.ui.screen.initial.home.HomeScreenComponent
import dev.datlag.burningseries.shared.ui.screen.initial.home.search.SearchScreenComponent
import dev.datlag.burningseries.shared.ui.screen.initial.sponsor.SponsorScreenComponent
import dev.datlag.skeo.Stream
import kotlinx.coroutines.flow.MutableStateFlow
Expand All @@ -30,7 +30,8 @@ class InitialScreenComponent(
componentContext: ComponentContext,
override val di: DI,
shortcutIntent: Shortcut.Intent,
private val watchVideo: (String, Series, Series.Episode, Collection<Stream>) -> Unit
private val watchVideo: (String, Series, Series.Episode, Collection<Stream>) -> Unit,
private val onBack: () -> Unit
) : InitialComponent, ComponentContext by componentContext {

override val pagerItems: List<InitialComponent.PagerItem> = listOf(
Expand Down Expand Up @@ -83,6 +84,14 @@ class InitialScreenComponent(
override val homeScrollEnabled = MutableStateFlow(true)
override val favoriteScrollEnabled = MutableStateFlow(true)

private val backCallback = BackCallback {
pageBack()
}

init {
backHandler.register(backCallback)
}

@Composable
override fun render() {
CompositionLocalProvider(
Expand Down Expand Up @@ -125,8 +134,15 @@ class InitialScreenComponent(
override fun selectPage(index: Int) {
pagesNavigation.select(index = index) { new, old ->
if (new.items[new.selectedIndex] == old.items[old.selectedIndex]) {
(pages.value.items[pages.value.selectedIndex].instance as? SeriesHolderComponent)?.dismissHoldingSeries()
pageBack()
}
}
}

@OptIn(ExperimentalDecomposeApi::class)
private fun pageBack() {
(pages.value.items[pages.value.selectedIndex].instance as? SeriesHolderComponent)
?.dismissHoldingSeries()
?: onBack()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package dev.datlag.burningseries.shared.ui.screen.initial.home

import com.arkivanov.decompose.router.slot.ChildSlot
import com.arkivanov.decompose.value.Value
import dev.datlag.burningseries.model.Genre
import dev.datlag.burningseries.model.Release
import dev.datlag.burningseries.model.state.HomeState
import dev.datlag.burningseries.model.state.SearchState
import dev.datlag.burningseries.shared.ui.navigation.Component
import dev.datlag.burningseries.shared.ui.navigation.DialogComponent
import dev.datlag.burningseries.shared.ui.screen.initial.SeriesHolderComponent
Expand All @@ -17,10 +19,14 @@ interface HomeComponent : SeriesHolderComponent {
val homeState: StateFlow<HomeState>
val release: StateFlow<Release?>

val searchState: StateFlow<SearchState>
val searchItems: StateFlow<List<Genre.Item>>

val onDeviceReachable: StateFlow<Boolean>

fun retryLoadingHome(): Any?
fun itemClicked(config: HomeConfig)

fun showDialog(config: DialogConfig)
fun searchQuery(text: String)
fun retryLoadingSearch()
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package dev.datlag.burningseries.shared.ui.screen.initial.home

import dev.datlag.burningseries.model.Genre
import dev.datlag.burningseries.model.Home
import kotlinx.serialization.Serializable

Expand All @@ -14,5 +15,6 @@ sealed class HomeConfig {
) : HomeConfig() {
constructor(series: Home.Series) : this(series.title, series.href, series.coverHref)
constructor(episode: Home.Episode) : this(episode.series ?: episode.fullTitle, episode.href, episode.coverHref)
constructor(item: Genre.Item) : this(item.title, item.href, null)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
import androidx.compose.material.icons.filled.Clear
import androidx.compose.material.icons.filled.Search
import androidx.compose.material.icons.filled.SearchOff
import androidx.compose.material.icons.filled.YoutubeSearchedFor
import androidx.compose.material3.*
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
Expand All @@ -24,12 +24,12 @@ import com.arkivanov.decompose.extensions.compose.subscribeAsState
import dev.chrisbanes.haze.haze
import dev.datlag.burningseries.model.Home
import dev.datlag.burningseries.model.state.HomeState
import dev.datlag.burningseries.model.state.SearchState
import dev.datlag.burningseries.shared.LocalHaze
import dev.datlag.burningseries.shared.SharedRes
import dev.datlag.burningseries.shared.common.LocalPadding
import dev.datlag.burningseries.shared.common.header
import dev.datlag.burningseries.shared.common.lifecycle.collectAsStateWithLifecycle
import dev.datlag.burningseries.shared.common.localPadding
import dev.datlag.burningseries.shared.common.mergedLocalPadding
import dev.datlag.burningseries.shared.other.StateSaver
import dev.datlag.burningseries.shared.rememberIsTv
Expand All @@ -38,9 +38,7 @@ import dev.datlag.burningseries.shared.ui.custom.VerticalScrollbar
import dev.datlag.burningseries.shared.ui.custom.rememberScrollbarAdapter
import dev.datlag.burningseries.shared.ui.custom.state.ErrorState
import dev.datlag.burningseries.shared.ui.custom.state.LoadingState
import dev.datlag.burningseries.shared.ui.screen.initial.home.component.DeviceContent
import dev.datlag.burningseries.shared.ui.screen.initial.home.component.EpisodeItem
import dev.datlag.burningseries.shared.ui.screen.initial.home.component.SeriesItem
import dev.datlag.burningseries.shared.ui.screen.initial.home.component.*
import dev.datlag.burningseries.shared.ui.theme.MaterialSymbols
import dev.icerock.moko.resources.compose.stringResource

Expand Down Expand Up @@ -133,93 +131,36 @@ private fun ExpandedView(home: Home, component: HomeComponent) {
@Composable
private fun MainView(home: Home, component: HomeComponent, modifier: Modifier = Modifier) {
Box(modifier = modifier) {
val searchState by component.searchState.collectAsStateWithLifecycle()

Row(
modifier = Modifier.fillMaxSize().padding(horizontal = 16.dp),
horizontalArrangement = Arrangement.spacedBy(2.dp)
) {
val state = rememberLazyGridState(
initialFirstVisibleItemIndex = StateSaver.homeGridIndex,
initialFirstVisibleItemScrollOffset = StateSaver.homeGridOffset
)
val searchItems by component.searchItems.collectAsStateWithLifecycle()

LazyVerticalGrid(
columns = GridCells.Adaptive(400.dp),
modifier = Modifier.weight(1F).haze(state = LocalHaze.current),
verticalArrangement = Arrangement.spacedBy(8.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp),
contentPadding = LocalPadding(),
state = state
) {
DeviceContent(component.release, component.onDeviceReachable)
header {
Row(
modifier = Modifier.padding(top = 16.dp).fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(16.dp)
) {
Text(
modifier = Modifier.weight(1F),
text = stringResource(SharedRes.strings.newest_episodes),
style = MaterialTheme.typography.headlineLarge,
fontWeight = FontWeight.Bold
)
if (!StateSaver.sekretLibraryLoaded) {
IconButton(
onClick = {
component.showDialog(DialogConfig.Sekret)
},
colors = IconButtonDefaults.filledIconButtonColors(
containerColor = MaterialTheme.colorScheme.errorContainer,
contentColor = MaterialTheme.colorScheme.onErrorContainer
)
) {
Icon(
imageVector = MaterialSymbols.rememberDeployedCodeAlert(),
contentDescription = stringResource(SharedRes.strings.sekret_unavailable_title)
)
}
}
}
}
items(home.episodes, key = {
it.href
}) { episode ->
EpisodeItem(episode) {
component.itemClicked(HomeConfig.Series(episode))
}
}
header {
Spacer(modifier = Modifier.size(48.dp))
}
header {
Text(
text = stringResource(SharedRes.strings.newest_series),
style = MaterialTheme.typography.headlineLarge,
fontWeight = FontWeight.Bold
)
}
items(home.series, key = {
it.href
}) { series ->
SeriesItem(series) {
component.itemClicked(HomeConfig.Series(series))
}
}
}
VerticalScrollbar(rememberScrollbarAdapter(state))

DisposableEffect(state) {
onDispose {
StateSaver.homeGridIndex = state.firstVisibleItemIndex
StateSaver.homeGridOffset = state.firstVisibleItemScrollOffset
}
if (searchItems.isEmpty()) {
HomeOverview(home, component)
} else {
SearchOverview(searchItems, component)
}
}
FloatingSearchButton(
modifier = Modifier.align(Alignment.BottomEnd).mergedLocalPadding(WindowInsets.ime.asPaddingValues(), 16.dp),
onTextChange = {

component.searchQuery(it)
},
enabled = searchState !is SearchState.Loading,
icon = when (searchState) {
is SearchState.Loading -> Icons.Default.YoutubeSearchedFor
is SearchState.Success -> Icons.Default.Search
is SearchState.Error -> Icons.Default.SearchOff
},
overrideOnClick = searchState !is SearchState.Success,
onClick = {
component.retryLoadingSearch()
}
)
}
}
}

Loading

0 comments on commit 712f65a

Please sign in to comment.