feat: add basic support for file upload via blossom #32

Merged
reya merged 3 commits from feat/image-upload into master 2026-06-30 08:11:20 +00:00
2 changed files with 43 additions and 33 deletions
Showing only changes of commit 01e10f4680 - Show all commits

View File

@@ -36,7 +36,8 @@
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"
android:theme="@style/Theme.App.Starting"> android:theme="@style/Theme.App.Starting"
android:windowSoftInputMode="adjustResize">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />

View File

@@ -7,10 +7,13 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.ime
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.union
import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
@@ -19,6 +22,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Badge import androidx.compose.material3.Badge
import androidx.compose.material3.BadgedBox import androidx.compose.material3.BadgedBox
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.FilledTonalButton import androidx.compose.material3.FilledTonalButton
import androidx.compose.material3.FilledTonalIconButton import androidx.compose.material3.FilledTonalIconButton
@@ -29,6 +33,7 @@ import androidx.compose.material3.LoadingIndicator
import androidx.compose.material3.MaterialShapes import androidx.compose.material3.MaterialShapes
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.ScaffoldDefaults
import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
@@ -81,6 +86,7 @@ import su.reya.coop.shared.nameFlow
import su.reya.coop.shared.pictureFlow import su.reya.coop.shared.pictureFlow
import su.reya.coop.short import su.reya.coop.short
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable @Composable
fun ChatScreen(id: Long, screening: Boolean = false) { fun ChatScreen(id: Long, screening: Boolean = false) {
val snackbarHostState = LocalSnackbarHostState.current val snackbarHostState = LocalSnackbarHostState.current
@@ -165,6 +171,7 @@ fun ChatScreen(id: Long, screening: Boolean = false) {
} }
Scaffold( Scaffold(
contentWindowInsets = ScaffoldDefaults.contentWindowInsets.union(WindowInsets.ime),
containerColor = MaterialTheme.colorScheme.surfaceContainer, containerColor = MaterialTheme.colorScheme.surfaceContainer,
snackbarHost = { SnackbarHost(snackbarHostState) }, snackbarHost = { SnackbarHost(snackbarHostState) },
topBar = { topBar = {
@@ -291,12 +298,14 @@ fun ChatScreen(id: Long, screening: Boolean = false) {
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(16.dp), .padding(horizontal = 16.dp, vertical = 8.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp), horizontalArrangement = Arrangement.spacedBy(8.dp),
) { ) {
Button( Button(
onClick = { navigator.goBack() }, onClick = { navigator.goBack() },
modifier = Modifier.weight(1f) modifier = Modifier
.weight(1f)
.size(ButtonDefaults.MediumContainerHeight)
) { ) {
Text( Text(
text = "Reject", text = "Reject",
@@ -305,7 +314,9 @@ fun ChatScreen(id: Long, screening: Boolean = false) {
} }
FilledTonalButton( FilledTonalButton(
onClick = { requireScreening = false }, onClick = { requireScreening = false },
modifier = Modifier.weight(1f) modifier = Modifier
.weight(1f)
.size(ButtonDefaults.MediumContainerHeight)
) { ) {
Text( Text(
text = "Accept", text = "Accept",
@@ -534,36 +545,34 @@ fun ChatInput(
onValueChange: (String) -> Unit, onValueChange: (String) -> Unit,
onSend: () -> Unit onSend: () -> Unit
) { ) {
Surface(modifier = Modifier.fillMaxWidth()) { Row(
Row( modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp),
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp), verticalAlignment = Alignment.Bottom
verticalAlignment = Alignment.Bottom ) {
) { TextField(
TextField( value = value,
value = value, onValueChange = onValueChange,
onValueChange = onValueChange, placeholder = { Text("Message") },
placeholder = { Text("Message") }, shape = RoundedCornerShape(28.dp),
shape = RoundedCornerShape(28.dp), colors = TextFieldDefaults.colors(
colors = TextFieldDefaults.colors( focusedIndicatorColor = Color.Transparent,
focusedIndicatorColor = Color.Transparent, unfocusedIndicatorColor = Color.Transparent
unfocusedIndicatorColor = Color.Transparent ),
), modifier = Modifier.weight(1f)
modifier = Modifier.weight(1f) )
Spacer(modifier = Modifier.size(8.dp))
FilledTonalIconButton(
onClick = onSend,
modifier = Modifier.size(56.dp),
colors = IconButtonDefaults.filledTonalIconButtonColors(
containerColor = MaterialTheme.colorScheme.surfaceVariant,
contentColor = MaterialTheme.colorScheme.onSurfaceVariant
)
) {
Icon(
painter = painterResource(Res.drawable.ic_send),
contentDescription = "Send"
) )
Spacer(modifier = Modifier.size(8.dp))
FilledTonalIconButton(
onClick = onSend,
modifier = Modifier.size(56.dp),
colors = IconButtonDefaults.filledTonalIconButtonColors(
containerColor = MaterialTheme.colorScheme.surfaceVariant,
contentColor = MaterialTheme.colorScheme.onSurfaceVariant
)
) {
Icon(
painter = painterResource(Res.drawable.ic_send),
contentDescription = "Send"
)
}
} }
} }
} }