1+ package dev.aaa1115910.bv.mobile.screen
2+
3+ import android.app.Activity
4+ import androidx.compose.foundation.layout.Arrangement
5+ import androidx.compose.foundation.layout.Column
6+ import androidx.compose.foundation.layout.PaddingValues
7+ import androidx.compose.foundation.layout.padding
8+ import androidx.compose.foundation.lazy.grid.GridCells
9+ import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
10+ import androidx.compose.foundation.lazy.grid.itemsIndexed
11+ import androidx.compose.foundation.lazy.grid.rememberLazyGridState
12+ import androidx.compose.material.icons.Icons
13+ import androidx.compose.material.icons.automirrored.filled.ArrowBack
14+ import androidx.compose.material3.ExperimentalMaterial3Api
15+ import androidx.compose.material3.Icon
16+ import androidx.compose.material3.IconButton
17+ import androidx.compose.material3.LargeTopAppBar
18+ import androidx.compose.material3.PrimaryTabRow
19+ import androidx.compose.material3.Scaffold
20+ import androidx.compose.material3.Tab
21+ import androidx.compose.material3.Text
22+ import androidx.compose.material3.TopAppBarDefaults
23+ import androidx.compose.material3.rememberTopAppBarState
24+ import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
25+ import androidx.compose.material3.windowsizeclass.WindowSizeClass
26+ import androidx.compose.runtime.Composable
27+ import androidx.compose.runtime.mutableStateOf
28+ import androidx.compose.runtime.remember
29+ import androidx.compose.runtime.getValue
30+ import androidx.compose.runtime.setValue
31+ import androidx.compose.ui.Modifier
32+ import androidx.compose.ui.input.nestedscroll.nestedScroll
33+ import androidx.compose.ui.platform.LocalContext
34+ import androidx.compose.ui.tooling.preview.Preview
35+ import androidx.compose.ui.unit.dp
36+ import dev.aaa1115910.biliapi.entity.season.FollowingSeasonType
37+ import dev.aaa1115910.bv.entity.carddata.SeasonCardData
38+ import dev.aaa1115910.bv.mobile.component.videocard.SeasonCard
39+ import dev.aaa1115910.bv.mobile.theme.BVMobileTheme
40+ import dev.aaa1115910.bv.util.OnBottomReached
41+ import dev.aaa1115910.bv.util.calculateWindowSizeClassInPreview
42+ import dev.aaa1115910.bv.util.getDisplayName
43+ import dev.aaa1115910.bv.viewmodel.user.FollowingSeasonViewModel
44+ import org.koin.androidx.compose.koinViewModel
45+
46+ @Composable
47+ fun FollowingSeasonScreen (
48+ modifier : Modifier = Modifier ,
49+ windowSize : WindowSizeClass ,
50+ followingSeasonViewModel : FollowingSeasonViewModel = koinViewModel()
51+ ) {
52+ val context = LocalContext .current
53+ val listState = rememberLazyGridState()
54+
55+ listState.OnBottomReached (
56+ loading = followingSeasonViewModel.updating
57+ ) {
58+ if (followingSeasonViewModel.noMore) return @OnBottomReached
59+ followingSeasonViewModel.loadMore()
60+ }
61+
62+ FollowingSeasonContent (
63+ modifier = modifier,
64+ windowSize = windowSize,
65+ type = followingSeasonViewModel.followingSeasonType,
66+ seasons = followingSeasonViewModel.followingSeasons.map(SeasonCardData ::fromFollowingSeason),
67+ onBack = { (context as Activity ).finish() },
68+ onTypeChange = {
69+ followingSeasonViewModel.followingSeasonType = it
70+ followingSeasonViewModel.clearData()
71+ followingSeasonViewModel.loadMore()
72+ },
73+ onClickSeason = {}
74+ )
75+ }
76+
77+ @OptIn(ExperimentalMaterial3Api ::class )
78+ @Composable
79+ private fun FollowingSeasonContent (
80+ modifier : Modifier = Modifier ,
81+ windowSize : WindowSizeClass ,
82+ type : FollowingSeasonType ,
83+ seasons : List <SeasonCardData >,
84+ onBack : () -> Unit ,
85+ onTypeChange : (FollowingSeasonType ) -> Unit ,
86+ onClickSeason : (SeasonCardData ) -> Unit ,
87+ ) {
88+ val context = LocalContext .current
89+ val scrollBehavior =
90+ TopAppBarDefaults .exitUntilCollapsedScrollBehavior(rememberTopAppBarState())
91+
92+ Scaffold (
93+ modifier = modifier
94+ .nestedScroll(scrollBehavior.nestedScrollConnection),
95+ topBar = {
96+ Column {
97+ LargeTopAppBar (
98+ title = { Text (text = " 我的追番" ) },
99+ navigationIcon = {
100+ IconButton (onClick = onBack) {
101+ Icon (
102+ imageVector = Icons .AutoMirrored .Default .ArrowBack ,
103+ contentDescription = null
104+ )
105+ }
106+ },
107+ scrollBehavior = scrollBehavior
108+ )
109+ PrimaryTabRow (
110+ selectedTabIndex = type.ordinal,
111+ ) {
112+ FollowingSeasonType .entries.forEach { seasonType ->
113+ Tab (
114+ selected = type == seasonType,
115+ text = { Text (text = seasonType.getDisplayName(context)) },
116+ onClick = { onTypeChange(seasonType) }
117+ )
118+ }
119+ }
120+ }
121+ },
122+ ) { innerPadding ->
123+ LazyVerticalGrid (
124+ modifier = Modifier .padding(top = innerPadding.calculateTopPadding()),
125+ columns = GridCells .Adaptive (100 .dp),
126+ contentPadding = PaddingValues (12 .dp),
127+ verticalArrangement = Arrangement .spacedBy(12 .dp),
128+ horizontalArrangement = Arrangement .spacedBy(12 .dp)
129+ ) {
130+ itemsIndexed(seasons) { index, season ->
131+ SeasonCard (
132+ data = season,
133+ onClick = { onClickSeason(season) }
134+ )
135+ }
136+ }
137+ }
138+ }
139+
140+ @OptIn(ExperimentalMaterial3WindowSizeClassApi ::class )
141+ @Preview
142+ @Composable
143+ private fun FollowingSeasonContentPreview () {
144+ val windowSize = calculateWindowSizeClassInPreview()
145+ var selectedType by remember { mutableStateOf(FollowingSeasonType .Bangumi ) }
146+
147+ val seasons = (1 .. 50 ).map {
148+ SeasonCardData (
149+ seasonId = it,
150+ title = " Title $it " ,
151+ cover = " http://i0.hdslb.com/bfs/bangumi/image/8d211c396aad084d6fa413015200dda6ed260768.png" ,
152+ rating = " 8.6"
153+ )
154+ }
155+
156+ BVMobileTheme {
157+ FollowingSeasonContent (
158+ windowSize = windowSize,
159+ type = selectedType,
160+ seasons = seasons,
161+ onBack = {},
162+ onTypeChange = { selectedType = it },
163+ onClickSeason = {}
164+ )
165+ }
166+ }
0 commit comments