@@ -11,9 +11,11 @@ import androidx.compose.material3.MaterialTheme.shapes
1111import androidx.compose.material3.MaterialTheme.typography
1212import androidx.compose.material3.Text
1313import androidx.compose.runtime.Composable
14+ import androidx.compose.runtime.remember
1415import androidx.compose.ui.Alignment
1516import androidx.compose.ui.Modifier
1617import androidx.compose.ui.draw.clip
18+ import androidx.compose.ui.graphics.Shape
1719import androidx.compose.ui.layout.ContentScale
1820import androidx.compose.ui.platform.LocalUriHandler
1921import androidx.compose.ui.text.font.FontWeight
@@ -32,69 +34,122 @@ import org.nsh07.nsh07.network.Repo
3234fun ProjectCard (
3335 project : Repo ,
3436 cardPadding : Dp ,
37+ wide : Boolean ,
3538 modifier : Modifier = Modifier ,
3639 imageUri : String? = null,
3740 description : String? = null,
3841) {
39- val colorScheme = colorScheme
42+ val shapes = shapes
4043 val uriHandler = LocalUriHandler .current
4144
45+ val imageShape = remember(wide) { if (wide) shapes.medium else shapes.large }
46+
4247 Box (
4348 modifier
4449 .clip(shapes.largeIncreased)
4550 .clickable { uriHandler.openUri(project.htmlUrl) }
4651 ) {
47- Row (Modifier .fillMaxWidth().padding(cardPadding)) {
48- SubcomposeAsyncImage (
49- model = imageUri
50- ? : " https://raw.githubusercontent.com/${project.fullName} /refs/heads/main/fastlane/metadata/android/en-US/images/featureGraphic.png" ,
51- contentDescription = null ,
52- contentScale = ContentScale .Crop ,
53- modifier = Modifier .padding(top = 4 .dp, end = 16 .dp).weight(1f ).clip(shapes.large),
54- loading = {
55- Box (Modifier .fillMaxWidth().aspectRatio(2f )) {
56- CircularWavyProgressIndicator (Modifier .align(Alignment .Center ))
57- }
58- },
59- error = {
60- Box (Modifier .fillMaxWidth().aspectRatio(2f ).border(1 .dp, colorScheme.outline, shapes.large))
61- }
62- )
63- Column (Modifier .weight(3f )) {
64- FlowRow (itemVerticalAlignment = Alignment .CenterVertically ) {
65- Text (project.name, style = typography.bodyLarge, fontWeight = FontWeight .Medium )
66- Icon (
67- painterResource(Res .drawable.open_in_browser),
68- null ,
69- modifier = Modifier .padding(start = 4 .dp).size(16 .dp)
70- )
71- }
72- Text (
73- description ? : project.description,
74- style = typography.bodyMedium,
75- color = colorScheme.onSurfaceVariant,
76- modifier = Modifier .padding(top = 8 .dp)
52+ if (wide) {
53+ Row (Modifier .fillMaxWidth().padding(cardPadding)) {
54+ ProjectThumbnail (
55+ project,
56+ imageShape,
57+ wide,
58+ Modifier .weight(1f ),
59+ imageUri
60+ )
61+ ProjectMainContent (
62+ project,
63+ description,
64+ Modifier .weight(3f )
7765 )
78- Row (
79- verticalAlignment = Alignment .CenterVertically ,
80- horizontalArrangement = Arrangement .spacedBy(4 .dp),
81- modifier = Modifier .padding(top = 8 .dp)
82- ) {
83- Icon (
84- painterResource(Res .drawable.star),
85- null
86- )
87- Text (project.stargazersCount.toString(), style = typography.labelLarge)
88- Spacer (Modifier .width(8 .dp))
89- Icon (
90- painterResource(Res .drawable.fork),
91- null ,
92- modifier = Modifier .size(20 .dp)
93- )
94- Text (project.forksCount.toString(), style = typography.labelLarge)
95- }
96- LabelRow (project.topics, Modifier .padding(top = 16 .dp))
9766 }
67+ } else {
68+ Column (Modifier .fillMaxWidth().padding(cardPadding)) {
69+ ProjectThumbnail (
70+ project,
71+ imageShape,
72+ wide,
73+ imageUri = imageUri
74+ )
75+ ProjectMainContent (project, description)
76+ }
77+ }
78+ }
79+ }
80+
81+ @OptIn(ExperimentalMaterial3ExpressiveApi ::class )
82+ @Composable
83+ fun ProjectThumbnail (
84+ project : Repo ,
85+ imageShape : Shape ,
86+ wide : Boolean ,
87+ modifier : Modifier = Modifier ,
88+ imageUri : String? = null
89+ ) {
90+ SubcomposeAsyncImage (
91+ model = imageUri
92+ ? : " https://raw.githubusercontent.com/${project.fullName} /refs/heads/main/fastlane/metadata/android/en-US/images/featureGraphic.png" ,
93+ contentDescription = null ,
94+ contentScale = ContentScale .Crop ,
95+ modifier = Modifier
96+ .padding(
97+ top = if (wide) 4 .dp else 0 .dp,
98+ end = if (wide) 16 .dp else 0 .dp,
99+ bottom = if (! wide) 8 .dp else 0 .dp
100+ )
101+ .then(modifier)
102+ .clip(imageShape),
103+ loading = {
104+ Box (Modifier .fillMaxWidth().aspectRatio(2f )) {
105+ CircularWavyProgressIndicator (Modifier .align(Alignment .Center ))
106+ }
107+ },
108+ error = {
109+ if (wide) Box (Modifier .fillMaxWidth().aspectRatio(2f ).border(1 .dp, colorScheme.outline, imageShape))
110+ }
111+ )
112+ }
113+
114+ @Composable
115+ fun ProjectMainContent (
116+ project : Repo ,
117+ description : String? = null,
118+ modifier : Modifier = Modifier
119+ ) {
120+ Column (modifier) {
121+ FlowRow (itemVerticalAlignment = Alignment .CenterVertically ) {
122+ Text (project.name, style = typography.bodyLarge, fontWeight = FontWeight .Medium )
123+ Icon (
124+ painterResource(Res .drawable.open_in_browser),
125+ null ,
126+ modifier = Modifier .padding(start = 4 .dp).size(16 .dp)
127+ )
128+ }
129+ Text (
130+ description ? : project.description,
131+ style = typography.bodyMedium,
132+ color = colorScheme.onSurfaceVariant,
133+ modifier = Modifier .padding(top = 8 .dp)
134+ )
135+ Row (
136+ verticalAlignment = Alignment .CenterVertically ,
137+ horizontalArrangement = Arrangement .spacedBy(4 .dp),
138+ modifier = Modifier .padding(top = 8 .dp)
139+ ) {
140+ Icon (
141+ painterResource(Res .drawable.star),
142+ null
143+ )
144+ Text (project.stargazersCount.toString(), style = typography.labelLarge)
145+ Spacer (Modifier .width(8 .dp))
146+ Icon (
147+ painterResource(Res .drawable.fork),
148+ null ,
149+ modifier = Modifier .size(20 .dp)
150+ )
151+ Text (project.forksCount.toString(), style = typography.labelLarge)
98152 }
153+ LabelRow (project.topics, Modifier .padding(top = 16 .dp))
99154 }
100- }
155+ }
0 commit comments