dm-159
This commit is contained in:
parent
83523c4db4
commit
ee474675ac
1 changed files with 121 additions and 43 deletions
|
|
@ -9,7 +9,6 @@ import androidx.compose.foundation.border
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
|
@ -31,9 +30,6 @@ import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
|
||||||
import androidx.compose.foundation.lazy.LazyRow
|
|
||||||
import androidx.compose.foundation.lazy.items
|
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
|
|
@ -45,22 +41,60 @@ import androidx.core.content.ContextCompat
|
||||||
import coil.compose.AsyncImage // 建議使用 Coil 來載入本地圖片 Uri,效能極佳
|
import coil.compose.AsyncImage // 建議使用 Coil 來載入本地圖片 Uri,效能極佳
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.aspectRatio
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.lazy.LazyRow
|
||||||
|
import androidx.compose.foundation.lazy.grid.GridCells
|
||||||
|
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||||
|
import androidx.compose.foundation.lazy.grid.items
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.material.icons.filled.Add
|
import androidx.compose.material.icons.filled.Add
|
||||||
|
import androidx.compose.material.icons.filled.Audiotrack
|
||||||
|
import androidx.compose.material.icons.filled.ContactPage
|
||||||
|
import androidx.compose.material.icons.filled.Description
|
||||||
|
import androidx.compose.material.icons.filled.Image
|
||||||
|
import androidx.compose.material.icons.filled.LocationOn
|
||||||
|
import androidx.compose.material3.Divider
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.mutableStateListOf
|
import androidx.compose.runtime.mutableStateListOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
|
||||||
|
|
||||||
|
// 🎯 定義底部功能按鈕的資料結構
|
||||||
|
data class AttachmentOption(
|
||||||
|
val title: String,
|
||||||
|
val icon: ImageVector,
|
||||||
|
val onClick: () -> Unit
|
||||||
|
)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MessageAttachmentBar(
|
fun MessageAttachmentBar(
|
||||||
onImageSelected: (Uri) -> Unit,
|
onImageSelected: (Uri) -> Unit,
|
||||||
onCancel: () -> Unit
|
onCancel: () -> Unit,
|
||||||
|
onAudioClick: () -> Unit = {},
|
||||||
|
onDocumentClick: () -> Unit = {},
|
||||||
|
onLocationClick: () -> Unit = {},
|
||||||
|
onContactClick: () -> Unit = {}
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val localImages = remember { mutableStateListOf<Uri>() }
|
val localImages = remember { mutableStateListOf<Uri>() }
|
||||||
var refreshTrigger by remember { mutableStateOf(0) }
|
var refreshTrigger by remember { mutableStateOf(0) }
|
||||||
|
|
||||||
|
//attachment menu
|
||||||
|
val attachmentOptions = remember {
|
||||||
|
listOf(
|
||||||
|
AttachmentOption("圖片", Icons.Default.Image, { /* 已在網格處理,這裡可做其他事 */ }),
|
||||||
|
AttachmentOption("音訊", Icons.Default.Audiotrack, onAudioClick),
|
||||||
|
AttachmentOption("文件", Icons.Default.Description, onDocumentClick),
|
||||||
|
AttachmentOption("位置", Icons.Default.LocationOn, onLocationClick),
|
||||||
|
AttachmentOption("聯絡人", Icons.Default.ContactPage, onContactClick)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
val isPartialAccess by remember(refreshTrigger) {
|
val isPartialAccess by remember(refreshTrigger) {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||||
|
|
@ -90,7 +124,7 @@ fun MessageAttachmentBar(
|
||||||
)?.use { cursor ->
|
)?.use { cursor ->
|
||||||
val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
|
val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
|
||||||
var count = 0
|
var count = 0
|
||||||
while (cursor.moveToNext() && count < 20) {
|
while (cursor.moveToNext() && count < 24) { // 🎯 調整為 24 張
|
||||||
val id = cursor.getLong(idColumn)
|
val id = cursor.getLong(idColumn)
|
||||||
val contentUri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id)
|
val contentUri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id)
|
||||||
imageUris.add(contentUri)
|
imageUris.add(contentUri)
|
||||||
|
|
@ -155,19 +189,31 @@ fun MessageAttachmentBar(
|
||||||
}
|
}
|
||||||
|
|
||||||
// 中部列:放大後的媒體檢視器
|
// 中部列:放大後的媒體檢視器
|
||||||
LazyRow(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.height(110.dp), // 🎯 高度從 70dp 顯著提升到 110dp,預覽更大更清晰
|
.height(240.dp) // 🎯 顯著拉高 Attachment Bar 容器
|
||||||
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
) {
|
||||||
// Android 14+ 管理選取範圍按鈕
|
if (localImages.isEmpty() && !isPartialAccess) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Text(text = "無最近媒體檔案", color = Color.White.copy(alpha = 0.5f))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LazyVerticalGrid(
|
||||||
|
columns = GridCells.Fixed(3), // 🎯 固定 3 直欄網格(你也可以改成 4)
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
|
) {
|
||||||
|
// Android 14+ 管理選取範圍按鈕 (在網格的第一格)
|
||||||
if (isPartialAccess) {
|
if (isPartialAccess) {
|
||||||
item {
|
item {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(110.dp) // 同步放大為正方形
|
.aspectRatio(1f) // 確保正方形
|
||||||
.clip(RoundedCornerShape(12.dp))
|
.clip(RoundedCornerShape(12.dp))
|
||||||
.background(Color.White.copy(alpha = 0.1f))
|
.background(Color.White.copy(alpha = 0.1f))
|
||||||
.clickable {
|
.clickable {
|
||||||
|
|
@ -185,22 +231,13 @@ fun MessageAttachmentBar(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (localImages.isEmpty()) {
|
// 渲染相片列表
|
||||||
item {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier.fillParentMaxWidth().height(110.dp),
|
|
||||||
contentAlignment = Alignment.Center
|
|
||||||
) {
|
|
||||||
Text(text = "無最近媒體檔案", color = Color.White.copy(alpha = 0.5f))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
items(localImages) { uri ->
|
items(localImages) { uri ->
|
||||||
AsyncImage(
|
AsyncImage(
|
||||||
model = uri,
|
model = uri,
|
||||||
contentDescription = "媒體預覽",
|
contentDescription = "媒體預覽",
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(110.dp) // 🎯 同步放大
|
.aspectRatio(1f) // 🎯 強制圖片縮圖為完美的正方形
|
||||||
.clip(RoundedCornerShape(12.dp))
|
.clip(RoundedCornerShape(12.dp))
|
||||||
.clickable { onImageSelected(uri) },
|
.clickable { onImageSelected(uri) },
|
||||||
contentScale = androidx.compose.ui.layout.ContentScale.Crop
|
contentScale = androidx.compose.ui.layout.ContentScale.Crop
|
||||||
|
|
@ -208,8 +245,49 @@ fun MessageAttachmentBar(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Divider(color = Color.White.copy(alpha = 0.15f), thickness = 1.dp) // 加一條細緻的分割線
|
||||||
|
|
||||||
|
LazyRow(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(20.dp), // 按鈕之間的間距
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
items(attachmentOptions) { option ->
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.width(60.dp)
|
||||||
|
.clickable { option.onClick() },
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.spacedBy(6.dp)
|
||||||
|
) {
|
||||||
|
// 圖示圓圈背景
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(44.dp)
|
||||||
|
.clip(CircleShape)
|
||||||
|
.background(Color.White.copy(alpha = 0.12f)),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = option.icon,
|
||||||
|
contentDescription = option.title,
|
||||||
|
tint = Color.White,
|
||||||
|
modifier = Modifier.size(20.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 功能文字
|
||||||
|
Text(
|
||||||
|
text = option.title,
|
||||||
|
color = Color.White.copy(alpha = 0.8f),
|
||||||
|
style = MaterialTheme.typography.labelSmall
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 💡 提示:這裡可以作為未來的第三列空間,比如放置「文件、位置、名片」等其他 Icon 按鈕。
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in a new issue