调整细节
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
@@ -16,8 +18,9 @@
|
||||
android:theme="@style/Theme.RiderPro"
|
||||
android:usesCleartextTraffic="true"
|
||||
tools:targetApi="31">
|
||||
<meta-data android:name="com.google.android.geo.API_KEY"
|
||||
android:value="AIzaSyBM9xMcybq9IbFSFVneZ4nAqQ0ZmTnHGO4"/>
|
||||
<meta-data
|
||||
android:name="com.google.android.geo.API_KEY"
|
||||
android:value="AIzaSyBM9xMcybq9IbFSFVneZ4nAqQ0ZmTnHGO4" />
|
||||
<meta-data
|
||||
android:name="com.google.firebase.messaging.default_notification_icon"
|
||||
android:resource="@drawable/googleg_standard_color_18" />
|
||||
@@ -49,6 +52,17 @@
|
||||
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="com.aiosman.riderpro.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_paths" />
|
||||
</provider>
|
||||
</application>
|
||||
|
||||
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,278 @@
|
||||
package com.aiosman.riderpro.ui.composables
|
||||
|
||||
import androidx.compose.animation.core.Animatable
|
||||
import androidx.compose.animation.core.Spring
|
||||
import androidx.compose.animation.core.VectorConverter
|
||||
import androidx.compose.animation.core.VisibilityThreshold
|
||||
import androidx.compose.animation.core.spring
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.gestures.detectDragGesturesAfterLongPress
|
||||
import androidx.compose.foundation.gestures.scrollBy
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.LazyGridItemInfo
|
||||
import androidx.compose.foundation.lazy.grid.LazyGridItemScope
|
||||
import androidx.compose.foundation.lazy.grid.LazyGridState
|
||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.foundation.lazy.grid.itemsIndexed
|
||||
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.IntSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.toOffset
|
||||
import androidx.compose.ui.unit.toSize
|
||||
import androidx.compose.ui.zIndex
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun <T : Any> DraggableGrid(
|
||||
items: List<T>,
|
||||
onMove: (Int, Int) -> Unit,
|
||||
onDragModeStart: () -> Unit, // New parameter for drag start
|
||||
onDragModeEnd: () -> Unit, // New parameter for drag end,
|
||||
additionalItems: List<@Composable () -> Unit> = emptyList(), // New parameter for additional items
|
||||
lockedIndices: List<Int> = emptyList(), // New parameter for locked indices
|
||||
content: @Composable (T, Boolean) -> Unit,
|
||||
) {
|
||||
|
||||
val gridState = rememberLazyGridState()
|
||||
val dragDropState =
|
||||
rememberGridDragDropState(gridState, onMove, onDragModeStart, onDragModeEnd, lockedIndices)
|
||||
LazyVerticalGrid(
|
||||
columns = GridCells.Fixed(3),
|
||||
modifier = Modifier.dragContainer(dragDropState),
|
||||
state = gridState,
|
||||
contentPadding = PaddingValues(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||
|
||||
) {
|
||||
itemsIndexed(items, key = { _, item -> item }) { index, item ->
|
||||
DraggableItem(dragDropState, index) { isDragging ->
|
||||
content(item, isDragging)
|
||||
}
|
||||
}
|
||||
additionalItems.forEach { additionalItem ->
|
||||
item {
|
||||
additionalItem()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fun Modifier.dragContainer(dragDropState: GridDragDropState): Modifier {
|
||||
return pointerInput(dragDropState) {
|
||||
detectDragGesturesAfterLongPress(
|
||||
onDrag = { change, offset ->
|
||||
change.consume()
|
||||
dragDropState.onDrag(offset = offset)
|
||||
},
|
||||
onDragStart = { offset -> dragDropState.onDragStart(offset) },
|
||||
onDragEnd = { dragDropState.onDragInterrupted() },
|
||||
onDragCancel = { dragDropState.onDragInterrupted() }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ExperimentalFoundationApi
|
||||
@Composable
|
||||
fun LazyGridItemScope.DraggableItem(
|
||||
dragDropState: GridDragDropState,
|
||||
index: Int,
|
||||
modifier: Modifier = Modifier,
|
||||
content: @Composable (isDragging: Boolean) -> Unit,
|
||||
) {
|
||||
val dragging = index == dragDropState.draggingItemIndex
|
||||
val draggingModifier = if (dragging) {
|
||||
Modifier
|
||||
.zIndex(1f)
|
||||
.graphicsLayer {
|
||||
translationX = dragDropState.draggingItemOffset.x
|
||||
translationY = dragDropState.draggingItemOffset.y
|
||||
}
|
||||
} else if (index == dragDropState.previousIndexOfDraggedItem) {
|
||||
Modifier
|
||||
.zIndex(1f)
|
||||
.graphicsLayer {
|
||||
translationX = dragDropState.previousItemOffset.value.x
|
||||
translationY = dragDropState.previousItemOffset.value.y
|
||||
}
|
||||
} else {
|
||||
Modifier.animateItemPlacement()
|
||||
}
|
||||
Box(modifier = modifier.then(draggingModifier), propagateMinConstraints = true) {
|
||||
content(dragging)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun rememberGridDragDropState(
|
||||
gridState: LazyGridState,
|
||||
onMove: (Int, Int) -> Unit,
|
||||
onDragModeStart: () -> Unit,
|
||||
onDragModeEnd: () -> Unit,
|
||||
lockedIndices: List<Int> // New parameter for locked indices
|
||||
): GridDragDropState {
|
||||
val scope = rememberCoroutineScope()
|
||||
val state = remember(gridState) {
|
||||
GridDragDropState(
|
||||
state = gridState,
|
||||
onMove = onMove,
|
||||
scope = scope,
|
||||
onDragModeStart = onDragModeStart,
|
||||
onDragModeEnd = onDragModeEnd,
|
||||
lockedIndices = lockedIndices // Pass the locked indices
|
||||
)
|
||||
}
|
||||
LaunchedEffect(state) {
|
||||
while (true) {
|
||||
val diff = state.scrollChannel.receive()
|
||||
gridState.scrollBy(diff)
|
||||
}
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
class GridDragDropState internal constructor(
|
||||
private val state: LazyGridState,
|
||||
private val scope: CoroutineScope,
|
||||
private val onMove: (Int, Int) -> Unit,
|
||||
private val onDragModeStart: () -> Unit,
|
||||
private val onDragModeEnd: () -> Unit,
|
||||
private val lockedIndices: List<Int> // New parameter for locked indices
|
||||
) {
|
||||
var draggingItemIndex by mutableStateOf<Int?>(null)
|
||||
private set
|
||||
|
||||
internal val scrollChannel = Channel<Float>()
|
||||
|
||||
private var draggingItemDraggedDelta by mutableStateOf(Offset.Zero)
|
||||
private var draggingItemInitialOffset by mutableStateOf(Offset.Zero)
|
||||
internal val draggingItemOffset: Offset
|
||||
get() = draggingItemLayoutInfo?.let { item ->
|
||||
draggingItemInitialOffset + draggingItemDraggedDelta - item.offset.toOffset()
|
||||
} ?: Offset.Zero
|
||||
|
||||
private val draggingItemLayoutInfo: LazyGridItemInfo?
|
||||
get() = state.layoutInfo.visibleItemsInfo
|
||||
.firstOrNull { it.index == draggingItemIndex }
|
||||
|
||||
internal var previousIndexOfDraggedItem by mutableStateOf<Int?>(null)
|
||||
private set
|
||||
internal var previousItemOffset = Animatable(Offset.Zero, Offset.VectorConverter)
|
||||
private set
|
||||
|
||||
internal fun onDragStart(offset: Offset) {
|
||||
state.layoutInfo.visibleItemsInfo
|
||||
.firstOrNull { item ->
|
||||
offset.x.toInt() in item.offset.x..item.offsetEnd.x &&
|
||||
offset.y.toInt() in item.offset.y..item.offsetEnd.y
|
||||
}?.also {
|
||||
if (it.index !in lockedIndices) { // Check if the item is not locked
|
||||
draggingItemIndex = it.index
|
||||
draggingItemInitialOffset = it.offset.toOffset()
|
||||
onDragModeStart() // Notify drag start
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun onDragInterrupted() {
|
||||
if (draggingItemIndex != null) {
|
||||
previousIndexOfDraggedItem = draggingItemIndex
|
||||
val startOffset = draggingItemOffset
|
||||
scope.launch {
|
||||
previousItemOffset.snapTo(startOffset)
|
||||
previousItemOffset.animateTo(
|
||||
Offset.Zero,
|
||||
spring(
|
||||
stiffness = Spring.StiffnessMediumLow,
|
||||
visibilityThreshold = Offset.VisibilityThreshold
|
||||
)
|
||||
)
|
||||
previousIndexOfDraggedItem = null
|
||||
}
|
||||
}
|
||||
draggingItemDraggedDelta = Offset.Zero
|
||||
draggingItemIndex = null
|
||||
draggingItemInitialOffset = Offset.Zero
|
||||
onDragModeEnd() // Notify drag end
|
||||
}
|
||||
|
||||
internal fun onDrag(offset: Offset) {
|
||||
draggingItemDraggedDelta += offset
|
||||
|
||||
val draggingItem = draggingItemLayoutInfo ?: return
|
||||
val startOffset = draggingItem.offset.toOffset() + draggingItemOffset
|
||||
val endOffset = startOffset + draggingItem.size.toSize()
|
||||
val middleOffset = startOffset + (endOffset - startOffset) / 2f
|
||||
|
||||
val targetItem = state.layoutInfo.visibleItemsInfo.find { item ->
|
||||
middleOffset.x.toInt() in item.offset.x..item.offsetEnd.x &&
|
||||
middleOffset.y.toInt() in item.offset.y..item.offsetEnd.y &&
|
||||
draggingItem.index != item.index &&
|
||||
item.index !in lockedIndices // Check if the target item is not locked
|
||||
}
|
||||
if (targetItem != null) {
|
||||
val scrollToIndex = if (targetItem.index == state.firstVisibleItemIndex) {
|
||||
draggingItem.index
|
||||
} else if (draggingItem.index == state.firstVisibleItemIndex) {
|
||||
targetItem.index
|
||||
} else {
|
||||
null
|
||||
}
|
||||
if (scrollToIndex != null) {
|
||||
scope.launch {
|
||||
state.scrollToItem(scrollToIndex, state.firstVisibleItemScrollOffset)
|
||||
onMove.invoke(draggingItem.index, targetItem.index)
|
||||
}
|
||||
} else {
|
||||
onMove.invoke(draggingItem.index, targetItem.index)
|
||||
}
|
||||
draggingItemIndex = targetItem.index
|
||||
} else {
|
||||
val overscroll = when {
|
||||
draggingItemDraggedDelta.y > 0 ->
|
||||
(endOffset.y - state.layoutInfo.viewportEndOffset).coerceAtLeast(0f)
|
||||
|
||||
draggingItemDraggedDelta.y < 0 ->
|
||||
(startOffset.y - state.layoutInfo.viewportStartOffset).coerceAtMost(0f)
|
||||
|
||||
else -> 0f
|
||||
}
|
||||
if (overscroll != 0f) {
|
||||
scrollChannel.trySend(overscroll)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val LazyGridItemInfo.offsetEnd: IntOffset
|
||||
get() = this.offset + this.size
|
||||
}
|
||||
|
||||
operator fun IntOffset.plus(size: IntSize): IntOffset {
|
||||
return IntOffset(x + size.width, y + size.height)
|
||||
}
|
||||
|
||||
operator fun Offset.plus(size: Size): Offset {
|
||||
return Offset(x + size.width, y + size.height)
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
package com.aiosman.riderpro.ui.post
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import android.net.Uri
|
||||
import android.widget.Toast
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.core.animateDpAsState
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
@@ -14,10 +14,10 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||
import androidx.compose.foundation.layout.FlowRow
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
@@ -25,9 +25,12 @@ import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.BasicTextField
|
||||
import androidx.compose.material.LinearProgressIndicator
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.Text
|
||||
@@ -36,12 +39,15 @@ import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.graphics.PathEffect
|
||||
import androidx.compose.ui.graphics.drawscope.Stroke
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
@@ -50,17 +56,24 @@ import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import coil.compose.AsyncImage
|
||||
import com.aiosman.riderpro.LocalNavController
|
||||
import com.aiosman.riderpro.R
|
||||
import com.aiosman.riderpro.ui.NavigationRoute
|
||||
import com.aiosman.riderpro.ui.composables.CustomAsyncImage
|
||||
import com.aiosman.riderpro.ui.composables.DraggableGrid
|
||||
import com.aiosman.riderpro.ui.composables.RelPostCard
|
||||
import com.aiosman.riderpro.ui.composables.StatusBarMaskLayout
|
||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||
import kotlinx.coroutines.launch
|
||||
import org.burnoutcrew.reorderable.NoDragCancelledAnimation
|
||||
import org.burnoutcrew.reorderable.ReorderableItem
|
||||
import org.burnoutcrew.reorderable.detectReorderAfterLongPress
|
||||
import org.burnoutcrew.reorderable.rememberReorderableLazyGridState
|
||||
import org.burnoutcrew.reorderable.reorderable
|
||||
import java.io.File
|
||||
|
||||
|
||||
@Preview
|
||||
@@ -76,7 +89,9 @@ fun NewPostScreen() {
|
||||
}
|
||||
StatusBarMaskLayout(
|
||||
darkIcons = true,
|
||||
modifier = Modifier.fillMaxSize().background(Color.White)
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(Color.White)
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
@@ -94,14 +109,19 @@ fun NewPostScreen() {
|
||||
NewPostTextField("Share your adventure…", NewPostViewModel.textContent) {
|
||||
NewPostViewModel.textContent = it
|
||||
}
|
||||
Column (
|
||||
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp)
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
model.relMoment?.let {
|
||||
Text("Share with")
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Box(
|
||||
modifier = Modifier.clip(RoundedCornerShape(8.dp)).background(color = Color(0xFFEEEEEE)).padding(24.dp)
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(8.dp))
|
||||
.background(color = Color(0xFFEEEEEE))
|
||||
.padding(24.dp)
|
||||
) {
|
||||
RelPostCard(
|
||||
momentEntity = it,
|
||||
@@ -188,6 +208,7 @@ fun NewPostTopBar(onSendClick: () -> Unit = {}) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun NewPostTextField(hint: String, value: String, onValueChange: (String) -> Unit) {
|
||||
|
||||
@@ -211,7 +232,48 @@ fun NewPostTextField(hint: String, value: String, onValueChange: (String) -> Uni
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
private fun VerticalGrid(
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
var data by remember { mutableStateOf((0 until 20).toList()) }
|
||||
val state = rememberReorderableLazyGridState(onMove = { from, to ->
|
||||
data = data.toMutableList().apply {
|
||||
add(to.index, removeAt(from.index))
|
||||
}
|
||||
})
|
||||
|
||||
LazyVerticalGrid(
|
||||
columns = GridCells.Fixed(4),
|
||||
state = state.gridState,
|
||||
contentPadding = PaddingValues(horizontal = 8.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
modifier = modifier.reorderable(state)
|
||||
) {
|
||||
items(data.size, { it }) { item ->
|
||||
val imageItem = data[item]
|
||||
ReorderableItem(state, item) { isDragging ->
|
||||
val elevation = animateDpAsState(if (isDragging) 8.dp else 0.dp)
|
||||
Box(
|
||||
contentAlignment = Alignment.Center,
|
||||
modifier = Modifier
|
||||
.detectReorderAfterLongPress(state)
|
||||
.shadow(elevation.value)
|
||||
.aspectRatio(1f)
|
||||
.background(MaterialTheme.colors.primary)
|
||||
) {
|
||||
Text(
|
||||
text = imageItem.toString(),
|
||||
color = Color.White
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun AddImageGrid() {
|
||||
val navController = LocalNavController.current
|
||||
@@ -226,44 +288,104 @@ fun AddImageGrid() {
|
||||
}
|
||||
}
|
||||
|
||||
val takePictureLauncher = rememberLauncherForActivityResult(
|
||||
contract = ActivityResultContracts.TakePicture()
|
||||
) { success ->
|
||||
if (success) {
|
||||
model.imageUriList += model.currentPhotoUri.toString()
|
||||
}
|
||||
}
|
||||
val state =
|
||||
rememberReorderableLazyGridState(
|
||||
onMove = { from, to ->
|
||||
model.imageUriList = model.imageUriList.toMutableList().apply {
|
||||
add(to.index, removeAt(from.index))
|
||||
}
|
||||
})
|
||||
|
||||
val stroke = Stroke(
|
||||
width = 2f,
|
||||
pathEffect = PathEffect.dashPathEffect(floatArrayOf(10f, 10f), 0f)
|
||||
)
|
||||
Box(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
FlowRow(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(18.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
model.imageUriList.forEach {
|
||||
CustomAsyncImage(
|
||||
context,
|
||||
it,
|
||||
contentDescription = "Image",
|
||||
modifier = Modifier
|
||||
.size(110.dp)
|
||||
DraggableGrid(
|
||||
items = NewPostViewModel.imageUriList,
|
||||
onMove = { from, to ->
|
||||
NewPostViewModel.imageUriList = NewPostViewModel.imageUriList.toMutableList().apply {
|
||||
add(to, removeAt(from))
|
||||
}
|
||||
},
|
||||
lockedIndices = listOf(
|
||||
|
||||
.drawBehind {
|
||||
drawRoundRect(color = Color(0xFF999999), style = stroke)
|
||||
}.noRippleClickable {
|
||||
navController.navigate(NavigationRoute.NewPostImageGrid.route)
|
||||
},
|
||||
contentScale = ContentScale.Crop
|
||||
),
|
||||
onDragModeEnd = {},
|
||||
onDragModeStart = {},
|
||||
additionalItems = listOf(
|
||||
|
||||
),
|
||||
|
||||
) { item, isDrag ->
|
||||
Box(
|
||||
modifier = Modifier
|
||||
) {
|
||||
CustomAsyncImage(
|
||||
LocalContext.current,
|
||||
item,
|
||||
contentDescription = "Image",
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.aspectRatio(1f)
|
||||
.noRippleClickable {
|
||||
navController.navigate(NavigationRoute.NewPostImageGrid.route)
|
||||
},
|
||||
contentScale = ContentScale.Crop
|
||||
)
|
||||
if (isDrag) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(Color(0x66000000))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
LazyVerticalGrid(
|
||||
columns = GridCells.Fixed(3),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(18.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
// items(model.imageUriList.size) { index ->
|
||||
// val uri = model.imageUriList[index]
|
||||
// Box(
|
||||
// modifier = Modifier
|
||||
// .drawBehind {
|
||||
// drawRoundRect(color = Color(0xFF999999), style = stroke)
|
||||
// }
|
||||
// ) {
|
||||
// CustomAsyncImage(
|
||||
// context,
|
||||
// uri,
|
||||
// contentDescription = "Image",
|
||||
// modifier = Modifier
|
||||
// .fillMaxWidth().aspectRatio(1f)
|
||||
// .noRippleClickable {
|
||||
// navController.navigate(NavigationRoute.NewPostImageGrid.route)
|
||||
// },
|
||||
// contentScale = ContentScale.Crop
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
item {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(110.dp)
|
||||
|
||||
.fillMaxWidth()
|
||||
.aspectRatio(1f)
|
||||
.drawBehind {
|
||||
drawRoundRect(color = Color(0xFF999999), style = stroke)
|
||||
}
|
||||
.noRippleClickable{
|
||||
.noRippleClickable {
|
||||
pickImagesLauncher.launch("image/*")
|
||||
},
|
||||
) {
|
||||
@@ -275,10 +397,37 @@ fun AddImageGrid() {
|
||||
.align(Alignment.Center)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
item {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.aspectRatio(1f)
|
||||
.drawBehind {
|
||||
drawRoundRect(color = Color(0xFF999999), style = stroke)
|
||||
}
|
||||
.noRippleClickable {
|
||||
val photoFile = File(context.cacheDir, "photo.jpg")
|
||||
val photoUri: Uri = FileProvider.getUriForFile(
|
||||
context,
|
||||
"${context.packageName}.fileprovider",
|
||||
photoFile
|
||||
)
|
||||
model.currentPhotoUri = photoUri
|
||||
takePictureLauncher.launch(photoUri)
|
||||
},
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.rider_pro_camera),
|
||||
contentDescription = "Take Photo",
|
||||
modifier = Modifier
|
||||
.size(48.dp)
|
||||
.align(Alignment.Center),
|
||||
colorFilter = ColorFilter.tint(Color.Gray)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
|
||||
@@ -29,6 +29,7 @@ object NewPostViewModel : ViewModel() {
|
||||
var imageUriList by mutableStateOf(listOf<String>())
|
||||
var relPostId by mutableStateOf<Int?>(null)
|
||||
var relMoment by mutableStateOf<MomentEntity?>(null)
|
||||
var currentPhotoUri: Uri? = null
|
||||
fun asNewPost() {
|
||||
textContent = ""
|
||||
searchPlaceAddressResult = null
|
||||
|
||||
Reference in New Issue
Block a user