11package io.goooler.demoapp.detail.ui
22
3+ import androidx.compose.animation.core.Spring
4+ import androidx.compose.animation.core.animateDpAsState
5+ import androidx.compose.animation.core.spring
36import androidx.compose.foundation.clickable
47import androidx.compose.foundation.layout.Box
58import androidx.compose.foundation.layout.Column
69import androidx.compose.foundation.layout.Row
710import androidx.compose.foundation.layout.Spacer
8- import androidx.compose.foundation.layout.fillMaxSize
911import androidx.compose.foundation.layout.height
1012import androidx.compose.foundation.layout.padding
1113import androidx.compose.foundation.layout.size
1214import androidx.compose.foundation.layout.width
13- import androidx.compose.foundation.rememberScrollState
14- import androidx.compose.foundation.verticalScroll
15+ import androidx.compose.foundation.lazy.LazyColumn
16+ import androidx.compose.foundation.lazy.items
1517import androidx.compose.material.icons.Icons
1618import androidx.compose.material.icons.filled.Share
1719import androidx.compose.material.icons.filled.Star
@@ -20,6 +22,7 @@ import androidx.compose.material3.ButtonDefaults
2022import androidx.compose.material3.ExperimentalMaterial3Api
2123import androidx.compose.material3.Icon
2224import androidx.compose.material3.MaterialTheme
25+ import androidx.compose.material3.Surface
2326import androidx.compose.material3.Text
2427import androidx.compose.material3.pulltorefresh.PullToRefreshContainer
2528import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
@@ -28,12 +31,13 @@ import androidx.compose.runtime.LaunchedEffect
2831import androidx.compose.runtime.collectAsState
2932import androidx.compose.runtime.getValue
3033import androidx.compose.runtime.mutableStateOf
31- import androidx.compose.runtime.remember
34+ import androidx.compose.runtime.saveable.rememberSaveable
3235import androidx.compose.runtime.setValue
3336import androidx.compose.ui.Alignment
3437import androidx.compose.ui.Modifier
3538import androidx.compose.ui.input.nestedscroll.nestedScroll
3639import androidx.compose.ui.tooling.preview.Preview
40+ import androidx.compose.ui.unit.coerceAtLeast
3741import androidx.compose.ui.unit.dp
3842import androidx.lifecycle.viewmodel.compose.viewModel
3943import io.goooler.demoapp.common.util.getQuantityString
@@ -50,7 +54,6 @@ fun DetailPageWithSwipeRefresh(
5054) {
5155 val model by vm.repoDetailModel.collectAsState()
5256 val isRefreshing by vm.isRefreshing.collectAsState()
53-
5457 val refreshState = rememberPullToRefreshState()
5558
5659 if (refreshState.isRefreshing) {
@@ -63,29 +66,45 @@ fun DetailPageWithSwipeRefresh(
6366 }
6467 }
6568
66- Box (modifier.nestedScroll(refreshState.nestedScrollConnection)) {
67- DetailPage (model = model, onForkClick = vm::fork)
69+ Surface (
70+ color = MaterialTheme .colorScheme.surface,
71+ modifier = modifier.padding(horizontal = 10 .dp),
72+ ) {
73+ Box (Modifier .nestedScroll(refreshState.nestedScrollConnection)) {
74+ LazyColumn {
75+ val models = List (10 ) { model }
76+ items(models) { model ->
77+ DetailCard (model = model, onForkClick = vm::fork)
78+ }
79+ }
6880
69- PullToRefreshContainer (
70- modifier = Modifier .align(Alignment .TopCenter ),
71- state = refreshState,
72- )
81+ PullToRefreshContainer (
82+ modifier = Modifier .align(Alignment .TopCenter ),
83+ state = refreshState,
84+ )
85+ }
7386 }
7487}
7588
7689@Composable
77- fun DetailPage (
90+ fun DetailCard (
7891 model : RepoDetailModel ,
7992 modifier : Modifier = Modifier ,
8093 onForkClick : () -> Unit ,
8194) {
82- var isDescExpanded by remember { mutableStateOf(false ) }
95+ var isDescExpanded by rememberSaveable { mutableStateOf(false ) }
96+ val extraPadding by animateDpAsState(
97+ targetValue = if (isDescExpanded) 20 .dp else 0 .dp,
98+ label = " extraPadding" ,
99+ animationSpec = spring(
100+ dampingRatio = Spring .DampingRatioMediumBouncy ,
101+ stiffness = Spring .StiffnessLow ,
102+ ),
103+ )
83104
84105 Column (
85106 modifier = modifier
86- .padding(8 .dp)
87- .fillMaxSize()
88- .verticalScroll(rememberScrollState()),
107+ .padding(extraPadding.coerceAtLeast(0 .dp)),
89108 ) {
90109 Text (
91110 text = model.fullName,
@@ -95,17 +114,20 @@ fun DetailPage(
95114 Spacer (modifier = Modifier .height(5 .dp))
96115 Text (
97116 text = model.description,
98- style = MaterialTheme .typography.bodyMedium ,
99- maxLines = if (isDescExpanded) Int .MAX_VALUE else 2 ,
117+ style = MaterialTheme .typography.bodyLarge ,
118+ maxLines = if (isDescExpanded) Int .MAX_VALUE else 1 ,
100119 modifier = Modifier .clickable {
101120 isDescExpanded = ! isDescExpanded
102121 },
103122 )
104123 Spacer (modifier = Modifier .height(5 .dp))
105124 Row {
106- Button (onClick = {
107- R .plurals.detail_star_count_tip.getQuantityString(model.starsCount)?.showToast()
108- }) {
125+ Button (
126+ modifier = Modifier .weight(1f ),
127+ onClick = {
128+ R .plurals.detail_star_count_tip.getQuantityString(model.starsCount)?.showToast()
129+ },
130+ ) {
109131 Icon (
110132 Icons .Filled .Star ,
111133 contentDescription = " Star" ,
@@ -115,7 +137,10 @@ fun DetailPage(
115137 Text (model.starsCount.toString())
116138 }
117139 Spacer (modifier = Modifier .width(20 .dp))
118- Button (onClick = onForkClick) {
140+ Button (
141+ modifier = Modifier .weight(1f ),
142+ onClick = onForkClick,
143+ ) {
119144 Icon (
120145 Icons .Filled .Share ,
121146 contentDescription = " Fork" ,
@@ -143,5 +168,5 @@ private fun DetailPagePreview() {
143168 1 ,
144169 2 ,
145170 )
146- DetailPage (model) {}
171+ DetailCard (model) {}
147172}
0 commit comments