Skip to content

Commit 5ab5fcc

Browse files
committed
feat: add selected view in the preview screens
1 parent 80f03d8 commit 5ab5fcc

File tree

5 files changed

+207
-45
lines changed

5 files changed

+207
-45
lines changed

app/src/main/java/com/huhx/picker/AppRoute.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ fun AppRoute(
2020
) {
2121
NavHost(
2222
navController = navController,
23-
startDestination = "moment_list",
23+
startDestination = "asset_picker",
2424
) {
2525
composable("moment_list") {
2626
MomentListScreen(viewModel) { navController.navigate("moment_add") }

app/src/main/java/com/huhx/picker/MainActivity.kt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import com.huhx.picker.model.AssetInfo
3737
import com.huhx.picker.model.AssetResourceType
3838
import com.huhx.picker.ui.theme.Compose_image_pickerTheme
3939
import com.huhx.picker.view.AssetImageIndicator
40+
import com.huhx.picker.view.SelectorBottomBar
4041

4142
class MainActivity : ComponentActivity() {
4243

@@ -165,6 +166,29 @@ fun AssetImageIndicatorPreview() {
165166
assetSelected = list
166167
)
167168
}
169+
}
168170

171+
@Preview
172+
@Composable
173+
fun AssetPreviewScreenPreview() {
174+
val assetInfo = AssetInfo(
175+
id = 8L,
176+
filepath = "https://huhx-family.oss-cn-beijing.aliyuncs.com/20220116082003904824.jpg",
177+
uriString = "https://huhx-family.oss-cn-beijing.aliyuncs.com/20220116082003904824.jpg",
178+
filename = "test.jpeg",
179+
directory = "Picture",
180+
mediaType = 1,
181+
size = 1150260,
182+
mimeType = "img/jpeg",
183+
duration = 16000,
184+
date = 23423434433
185+
)
186+
val list = listOf(assetInfo, assetInfo)
187+
val selectedList = SnapshotStateList<AssetInfo>()
188+
selectedList.add(assetInfo)
189+
selectedList.add(assetInfo)
169190

191+
Compose_image_pickerTheme {
192+
SelectorBottomBar(assetInfo = assetInfo, selectedList = selectedList, onClick = {}, onSelectedClick = {})
193+
}
170194
}

compose_image_picker/src/main/java/com/huhx/picker/component/AssetImageItem.kt

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package com.huhx.picker.component
22

3+
import androidx.compose.foundation.BorderStroke
34
import androidx.compose.foundation.ExperimentalFoundationApi
45
import androidx.compose.foundation.background
6+
import androidx.compose.foundation.border
7+
import androidx.compose.foundation.clickable
58
import androidx.compose.foundation.combinedClickable
69
import androidx.compose.foundation.layout.Box
710
import androidx.compose.foundation.layout.Column
@@ -31,6 +34,7 @@ import coil.compose.AsyncImagePainter
3134
import coil.decode.VideoFrameDecoder
3235
import coil.request.ImageRequest
3336
import com.huhx.picker.R
37+
import com.huhx.picker.model.AssetInfo
3438
import com.huhx.picker.model.AssetResourceType
3539

3640
@OptIn(ExperimentalFoundationApi::class)
@@ -110,6 +114,75 @@ fun AssetImageItem(
110114
}
111115
}
112116

117+
if (resourceType == AssetResourceType.GIF) {
118+
Box(
119+
modifier = Modifier
120+
.padding(bottom = 4.dp, end = 6.dp)
121+
.background(
122+
color = Color(0F, 0F, 0F, 0.4F),
123+
shape = RoundedCornerShape(8.dp)
124+
)
125+
) {
126+
Text(
127+
modifier = Modifier.padding(horizontal = 6.dp, vertical = 1.dp),
128+
text = stringResource(R.string.text_gif),
129+
color = Color.White,
130+
fontSize = 10.sp
131+
)
132+
}
133+
}
134+
}
135+
}
136+
137+
@Composable
138+
fun SelectedAssetImageItem(
139+
assetInfo: AssetInfo,
140+
isSelected: Boolean,
141+
modifier: Modifier = Modifier,
142+
resourceType: AssetResourceType = AssetResourceType.IMAGE,
143+
durationString: String? = null,
144+
filterQuality: FilterQuality = FilterQuality.None,
145+
onClick: (AssetInfo) -> Unit,
146+
) {
147+
val (backgroundColor, alpha) = if (isSelected) {
148+
Pair(Color.Black, 0.6F)
149+
} else {
150+
Pair(Color.Transparent, 1F)
151+
}
152+
val context = LocalContext.current
153+
154+
Box(
155+
modifier = modifier
156+
.background(backgroundColor)
157+
.alpha(alpha),
158+
) {
159+
AsyncImage(
160+
model = ImageRequest.Builder(context)
161+
.data(assetInfo.uriString)
162+
.decoderFactory(VideoFrameDecoder.Factory())
163+
.crossfade(true)
164+
.build(),
165+
modifier = modifier
166+
.aspectRatio(1.0F)
167+
.then(if (isSelected) Modifier.border(BorderStroke(width = 1.dp, color = Color.Red)) else Modifier)
168+
.padding(horizontal = 3.dp, vertical = 2.dp)
169+
.clickable { onClick(assetInfo) },
170+
filterQuality = filterQuality,
171+
contentScale = ContentScale.Crop,
172+
contentDescription = null
173+
)
174+
175+
if (resourceType == AssetResourceType.VIDEO) {
176+
Column(modifier = Modifier.align(Alignment.BottomEnd)) {
177+
Text(
178+
modifier = Modifier.padding(bottom = 3.dp, end = 3.dp),
179+
text = durationString ?: "00:00",
180+
color = Color.White,
181+
fontSize = 10.sp
182+
)
183+
}
184+
}
185+
113186
if (resourceType == AssetResourceType.GIF) {
114187
Box(
115188
modifier = Modifier

compose_image_picker/src/main/java/com/huhx/picker/model/AssetInfo.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import android.graphics.Bitmap
44
import android.graphics.BitmapFactory
55
import android.provider.MediaStore
66
import com.huhx.picker.util.StringUtil
7+
import java.time.Instant
78
import java.time.LocalDateTime
9+
import java.time.ZoneId
810
import java.time.format.DateTimeFormatter
911

1012
data class AssetInfo(
@@ -35,6 +37,11 @@ data class AssetInfo(
3537
return BitmapFactory.decodeFile(uriString)
3638
}
3739

40+
val dateString: String get() {
41+
val instant = Instant.ofEpochMilli(date)
42+
return instant.atZone(ZoneId.systemDefault()).toLocalDate().toString()
43+
}
44+
3845
val resourceType: AssetResourceType = AssetResourceType.fromFileName(filename)
3946

4047
// todo: 这种方式还是存在问题

compose_image_picker/src/main/java/com/huhx/picker/view/AssetPreviewScreen.kt

Lines changed: 102 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,24 @@
1+
@file:OptIn(ExperimentalMaterial3Api::class)
2+
13
package com.huhx.picker.view
24

35
import android.os.Build
46
import androidx.compose.foundation.background
57
import androidx.compose.foundation.layout.Arrangement
68
import androidx.compose.foundation.layout.Box
9+
import androidx.compose.foundation.layout.Column
710
import androidx.compose.foundation.layout.PaddingValues
811
import androidx.compose.foundation.layout.Row
912
import androidx.compose.foundation.layout.Spacer
1013
import androidx.compose.foundation.layout.defaultMinSize
1114
import androidx.compose.foundation.layout.fillMaxSize
1215
import androidx.compose.foundation.layout.fillMaxWidth
1316
import androidx.compose.foundation.layout.padding
17+
import androidx.compose.foundation.layout.size
1418
import androidx.compose.foundation.layout.statusBarsPadding
1519
import androidx.compose.foundation.layout.width
20+
import androidx.compose.foundation.lazy.LazyRow
21+
import androidx.compose.foundation.lazy.itemsIndexed
1622
import androidx.compose.foundation.pager.HorizontalPager
1723
import androidx.compose.foundation.pager.PagerState
1824
import androidx.compose.foundation.pager.rememberPagerState
@@ -24,12 +30,14 @@ import androidx.compose.material3.CenterAlignedTopAppBar
2430
import androidx.compose.material3.ExperimentalMaterial3Api
2531
import androidx.compose.material3.Icon
2632
import androidx.compose.material3.IconButton
33+
import androidx.compose.material3.MaterialTheme
2734
import androidx.compose.material3.Scaffold
2835
import androidx.compose.material3.Text
2936
import androidx.compose.material3.TopAppBarDefaults
3037
import androidx.compose.runtime.Composable
3138
import androidx.compose.runtime.DisposableEffect
3239
import androidx.compose.runtime.remember
40+
import androidx.compose.runtime.rememberCoroutineScope
3341
import androidx.compose.runtime.snapshots.SnapshotStateList
3442
import androidx.compose.ui.Alignment
3543
import androidx.compose.ui.Modifier
@@ -52,22 +60,64 @@ import coil.decode.GifDecoder
5260
import coil.decode.ImageDecoderDecoder
5361
import coil.request.ImageRequest
5462
import com.huhx.picker.R
63+
import com.huhx.picker.component.SelectedAssetImageItem
5564
import com.huhx.picker.model.AssetInfo
65+
import kotlinx.coroutines.launch
5666

5767
@UnstableApi
5868
@Composable
59-
internal fun AssetPreviewScreen(
69+
fun AssetPreviewScreen(
6070
index: Int,
6171
assets: List<AssetInfo>,
6272
navigateUp: () -> Unit,
6373
selectedList: SnapshotStateList<AssetInfo>,
6474
) {
6575
val pageState = rememberPagerState(initialPage = index, pageCount = assets::size)
76+
val scope = rememberCoroutineScope()
77+
val titleString = if (assets[pageState.currentPage].isImage()) "图片" else "视频"
6678

6779
Scaffold(
68-
topBar = { PreviewTopAppBar(navigateUp = navigateUp) },
80+
topBar = {
81+
CenterAlignedTopAppBar(
82+
modifier = Modifier.statusBarsPadding(),
83+
title = {
84+
Column(horizontalAlignment = Alignment.CenterHorizontally) {
85+
Text(
86+
text = titleString,
87+
style = MaterialTheme.typography.bodyLarge.copy(fontSize = 18.sp, color = Color.White)
88+
)
89+
Text(
90+
text = assets[pageState.currentPage].dateString,
91+
style = MaterialTheme.typography.bodyMedium.copy(color = Color.Gray)
92+
)
93+
}
94+
},
95+
colors = TopAppBarDefaults.centerAlignedTopAppBarColors(containerColor = Color.Black),
96+
navigationIcon = {
97+
IconButton(onClick = navigateUp) {
98+
Icon(Icons.AutoMirrored.Filled.ArrowBack, tint = Color.White, contentDescription = "")
99+
}
100+
},
101+
actions = {
102+
Text(
103+
modifier = Modifier.padding(horizontal = 4.dp),
104+
text = "${pageState.currentPage + 1}/${assets.size}",
105+
style = MaterialTheme.typography.bodyLarge.copy(fontSize = 18.sp, color = Color.White)
106+
)
107+
},
108+
)
109+
},
69110
bottomBar = {
70-
SelectorBottomBar(selectedList = selectedList, assetInfo = assets[pageState.currentPage]) {
111+
SelectorBottomBar(
112+
selectedList = selectedList,
113+
assetInfo = assets[pageState.currentPage],
114+
onSelectedClick = { asset ->
115+
val selectedIndex = assets.indexOfFirst { it.id == asset.id }
116+
scope.launch {
117+
pageState.animateScrollToPage(selectedIndex)
118+
}
119+
}
120+
) {
71121
navigateUp()
72122
if (selectedList.isEmpty()) selectedList.add(it)
73123
}
@@ -83,54 +133,62 @@ internal fun AssetPreviewScreen(
83133
}
84134
}
85135

86-
@OptIn(ExperimentalMaterial3Api::class)
87-
@Composable
88-
private fun PreviewTopAppBar(navigateUp: () -> Unit) {
89-
CenterAlignedTopAppBar(
90-
modifier = Modifier.statusBarsPadding(),
91-
title = {},
92-
colors = TopAppBarDefaults.centerAlignedTopAppBarColors(containerColor = Color.Black),
93-
navigationIcon = {
94-
IconButton(onClick = navigateUp) {
95-
Icon(Icons.AutoMirrored.Filled.ArrowBack, tint = Color.White, contentDescription = "")
96-
}
97-
}
98-
)
99-
}
100-
136+
@UnstableApi
101137
@Composable
102-
private fun SelectorBottomBar(
138+
fun SelectorBottomBar(
103139
assetInfo: AssetInfo,
104140
selectedList: SnapshotStateList<AssetInfo>,
141+
onSelectedClick: (AssetInfo) -> Unit,
105142
onClick: (AssetInfo) -> Unit,
106143
) {
107-
Row(
108-
modifier = Modifier
109-
.fillMaxWidth()
110-
.background(color = Color.Black.copy(alpha = 0.9F))
111-
.padding(horizontal = 10.dp, vertical = 8.dp),
112-
horizontalArrangement = Arrangement.SpaceBetween,
113-
verticalAlignment = Alignment.CenterVertically
114-
) {
115-
Row(verticalAlignment = Alignment.CenterVertically) {
116-
AssetImageIndicator(
117-
assetInfo = assetInfo,
118-
selected = selectedList.any { it == assetInfo },
119-
assetSelected = selectedList,
120-
fontSize = 14.sp,
121-
size = 22.dp
122-
)
123-
Spacer(modifier = Modifier.width(6.dp))
124-
Text(text = stringResource(R.string.text_asset_select), color = Color.White, fontSize = 14.sp)
144+
Column {
145+
if (selectedList.isNotEmpty()) {
146+
LazyRow(
147+
modifier = Modifier
148+
.fillMaxWidth()
149+
.background(Color.Black.copy(alpha = 0.8F))
150+
.padding(horizontal = 2.dp, vertical = 2.dp)
151+
) {
152+
itemsIndexed(selectedList) { _, resource ->
153+
SelectedAssetImageItem(
154+
assetInfo = resource,
155+
isSelected = resource.id == assetInfo.id,
156+
resourceType = resource.resourceType,
157+
modifier = Modifier.size(64.dp),
158+
onClick = onSelectedClick
159+
)
160+
}
161+
}
125162
}
126-
Button(
127-
modifier = Modifier.defaultMinSize(minHeight = 1.dp, minWidth = 1.dp),
128-
shape = RoundedCornerShape(5.dp),
129-
enabled = true,
130-
contentPadding = PaddingValues(horizontal = 20.dp, vertical = 6.dp),
131-
onClick = { onClick(assetInfo) }
163+
164+
Row(
165+
modifier = Modifier
166+
.fillMaxWidth()
167+
.background(color = Color.Black.copy(alpha = 0.9F))
168+
.padding(horizontal = 10.dp, vertical = 8.dp),
169+
horizontalArrangement = Arrangement.SpaceBetween,
170+
verticalAlignment = Alignment.CenterVertically
132171
) {
133-
Text(stringResource(R.string.text_done), color = Color.White, fontSize = 15.sp)
172+
Row(verticalAlignment = Alignment.CenterVertically) {
173+
AssetImageIndicator(
174+
assetInfo = assetInfo,
175+
selected = selectedList.any { it == assetInfo },
176+
assetSelected = selectedList,
177+
fontSize = 14.sp,
178+
size = 22.dp
179+
)
180+
Spacer(modifier = Modifier.width(6.dp))
181+
Text(text = stringResource(R.string.text_asset_select), color = Color.White, fontSize = 14.sp)
182+
}
183+
Button(
184+
modifier = Modifier.defaultMinSize(minHeight = 1.dp, minWidth = 1.dp),
185+
shape = RoundedCornerShape(5.dp),
186+
enabled = true,
187+
contentPadding = PaddingValues(horizontal = 20.dp, vertical = 6.dp),
188+
onClick = { onClick(assetInfo) }
189+
) {
190+
Text(stringResource(R.string.text_done), color = Color.White, fontSize = 15.sp)
191+
}
134192
}
135193
}
136194
}

0 commit comments

Comments
 (0)