Skip to content

Commit

Permalink
update: latest udpate screen
Browse files Browse the repository at this point in the history
  • Loading branch information
muedsa committed Nov 3, 2023
1 parent 900d5bf commit adae148
Show file tree
Hide file tree
Showing 5 changed files with 230 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ data class DanEpisode(
@SerialName("episodeTitle") val episodeTitle: String,
@SerialName("episodeNumber") val episodeNumber: String,
@SerialName("lastWatched") val lastWatched: String? = null,
@SerialName("airDate") val airDate: String
@SerialName("airDate") val airDate: String? = null,
)
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import androidx.tv.material3.TabRow
import androidx.tv.material3.TabRowDefaults
import androidx.tv.material3.Text
import com.muedsa.agetv.ui.features.home.catalog.CatalogScreen
import com.muedsa.agetv.ui.features.home.latest.LatestUpdateScreen
import com.muedsa.agetv.ui.features.home.main.MainScreen
import com.muedsa.agetv.ui.features.home.rank.RankScreen
import com.muedsa.agetv.ui.features.home.search.SearchScreen
Expand All @@ -39,6 +40,7 @@ import kotlin.time.Duration.Companion.milliseconds
val tabs = listOf(
HomeNavTabs.Main,
HomeNavTabs.Rank,
HomeNavTabs.Latest,
HomeNavTabs.Search,
HomeNavTabs.Catalog
)
Expand Down Expand Up @@ -140,13 +142,19 @@ fun HomeContent(
onNavigate = onNavigate
)

2 -> SearchScreen(
2 -> LatestUpdateScreen(
backgroundState = backgroundState,
errorMsgBoxState = errorMsgBoxState,
onNavigate = onNavigate
)

3 -> CatalogScreen(
3 -> SearchScreen(
backgroundState = backgroundState,
errorMsgBoxState = errorMsgBoxState,
onNavigate = onNavigate
)

4 -> CatalogScreen(
backgroundState = backgroundState,
errorMsgBoxState = errorMsgBoxState,
onNavigate = onNavigate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ package com.muedsa.agetv.ui.features.home

sealed class HomeNavTabs(val title: String) {
data object Main : HomeNavTabs("首页")

data object Rank : HomeNavTabs("排行")

data object Latest : HomeNavTabs("更新")
data object Search : HomeNavTabs("搜索")
data object Catalog : HomeNavTabs("目录")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
package com.muedsa.agetv.ui.features.home.latest

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusProperties
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.tv.foundation.lazy.grid.TvGridCells
import androidx.tv.foundation.lazy.grid.TvLazyVerticalGrid
import androidx.tv.foundation.lazy.grid.itemsIndexed
import androidx.tv.material3.Card
import androidx.tv.material3.ExperimentalTvMaterial3Api
import androidx.tv.material3.MaterialTheme
import androidx.tv.material3.Text
import com.muedsa.agetv.model.LazyType
import com.muedsa.agetv.ui.AgePosterSize
import com.muedsa.agetv.ui.navigation.NavigationItems
import com.muedsa.agetv.viewmodel.LatestUpdateViewModel
import com.muedsa.compose.tv.model.ContentModel
import com.muedsa.compose.tv.theme.CardContentPadding
import com.muedsa.compose.tv.theme.ImageCardRowCardPadding
import com.muedsa.compose.tv.theme.ScreenPaddingLeft
import com.muedsa.compose.tv.widget.CardType
import com.muedsa.compose.tv.widget.ErrorMessageBoxState
import com.muedsa.compose.tv.widget.ImageContentCard
import com.muedsa.compose.tv.widget.ScreenBackgroundState
import com.muedsa.compose.tv.widget.ScreenBackgroundType
import com.muedsa.uitl.LogUtil

@OptIn(ExperimentalComposeUiApi::class, ExperimentalTvMaterial3Api::class)
@Composable
fun LatestUpdateScreen(
viewModel: LatestUpdateViewModel = hiltViewModel(),
backgroundState: ScreenBackgroundState,
errorMsgBoxState: ErrorMessageBoxState,
onNavigate: (NavigationItems, List<String>?) -> Unit = { _, _ -> }
) {
val fontScale = LocalConfiguration.current.fontScale
val titleMediumFontSize = MaterialTheme.typography.titleMedium.fontSize.value
val bodyMediumFontSize = MaterialTheme.typography.bodyMedium.fontSize.value
val contentHeight = remember {
(titleMediumFontSize * fontScale + 0.5f).dp +
(bodyMediumFontSize * fontScale + 0.5f).dp +
CardContentPadding * 2
}

val latestUpdateLP by remember { viewModel.latestUpdateLPState }

LaunchedEffect(key1 = latestUpdateLP) {
if (latestUpdateLP.type == LazyType.FAILURE) {
errorMsgBoxState.error(latestUpdateLP.error)
}
}

Column(modifier = Modifier.padding(start = ScreenPaddingLeft)) {
Text(
text = "最近更新",
color = MaterialTheme.colorScheme.onBackground,
style = MaterialTheme.typography.titleLarge
)

if (latestUpdateLP.list.isNotEmpty()) {
val gridFocusRequester = remember { FocusRequester() }

TvLazyVerticalGrid(
modifier = Modifier
.padding(start = 0.dp, top = 20.dp, end = 20.dp, bottom = 20.dp)
.focusRequester(gridFocusRequester)
.focusProperties {
exit = { gridFocusRequester.saveFocusedChild(); FocusRequester.Default }
enter = {
if (gridFocusRequester.restoreFocusedChild()) {
LogUtil.d("grid restoreFocusedChild")
FocusRequester.Cancel
} else {
LogUtil.d("grid focused default child")
FocusRequester.Default
}
}
},
columns = TvGridCells.Adaptive(AgePosterSize.width + ImageCardRowCardPadding),
contentPadding = PaddingValues(
top = ImageCardRowCardPadding,
bottom = ImageCardRowCardPadding
)
) {
itemsIndexed(
items = latestUpdateLP.list,
key = { _, item -> item.aid }
) { index, item ->
val itemFocusRequester = remember {
FocusRequester()
}
ImageContentCard(
modifier = Modifier
.padding(end = ImageCardRowCardPadding)
.focusRequester(itemFocusRequester),
url = item.picSmall,
imageSize = AgePosterSize,
type = CardType.STANDARD,
model = ContentModel(
item.title,
subtitle = item.newTitle
),
onItemFocus = {
backgroundState.url = item.picSmall
backgroundState.type = ScreenBackgroundType.BLUR
},
onItemClick = {
LogUtil.d("Click $item")
onNavigate(NavigationItems.Detail, listOf(item.aid.toString()))
}
)

LaunchedEffect(key1 = Unit) {
if (latestUpdateLP.offset == index) {
itemFocusRequester.requestFocus()
}
}
}

if (latestUpdateLP.type != LazyType.LOADING && latestUpdateLP.hasNext) {
item {
Column {
Card(
modifier = Modifier
.size(AgePosterSize)
.padding(end = ImageCardRowCardPadding),
onClick = {
viewModel.fetchLatestUpdate()
}
) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "继续加载")
}
}
Spacer(modifier = Modifier.height(contentHeight))
}
}
}
}
}
}



LaunchedEffect(key1 = Unit) {
viewModel.fetchLatestUpdate()
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.muedsa.agetv.viewmodel

import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.muedsa.agetv.model.LazyPagedList
import com.muedsa.agetv.model.age.PosterAnimeModel
import com.muedsa.agetv.repository.AppRepository
import com.muedsa.uitl.LogUtil
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import javax.inject.Inject
import kotlin.math.ceil

@HiltViewModel
class LatestUpdateViewModel @Inject constructor(
private val repo: AppRepository
) : ViewModel() {

val latestUpdateLPState = mutableStateOf<LazyPagedList<PosterAnimeModel>>(LazyPagedList.new())

fun fetchLatestUpdate() {
val nextPage = latestUpdateLPState.value.nextPage
latestUpdateLPState.value = latestUpdateLPState.value.loadingNext()
viewModelScope.launch(context = Dispatchers.IO) {
try {
repo.update(nextPage, PAGE_SIZE).let {
latestUpdateLPState.value = latestUpdateLPState.value.successNext(
it.videos,
ceil(it.total.toDouble() / CatalogViewModel.PAGE_SIZE).toInt()
)
}
} catch (t: Throwable) {
withContext(Dispatchers.Main) {
latestUpdateLPState.value = latestUpdateLPState.value.failNext(t)
}
LogUtil.fb(t)
}
}
}

companion object {
const val PAGE_SIZE = 30
}
}

0 comments on commit adae148

Please sign in to comment.