11package org.vonderheidt.hips.ui.screens
22
3+ import android.widget.Toast
34import androidx.compose.foundation.background
45import androidx.compose.foundation.clickable
6+ import androidx.compose.foundation.gestures.detectTapGestures
57import androidx.compose.foundation.layout.Arrangement
68import androidx.compose.foundation.layout.Box
79import androidx.compose.foundation.layout.Column
@@ -21,6 +23,7 @@ import androidx.compose.material.icons.Icons
2123import androidx.compose.material.icons.automirrored.outlined.ArrowForward
2224import androidx.compose.material.icons.automirrored.outlined.Send
2325import androidx.compose.material.icons.outlined.Clear
26+ import androidx.compose.material.icons.outlined.Delete
2427import androidx.compose.material.icons.outlined.Person
2528import androidx.compose.material3.Icon
2629import androidx.compose.material3.IconButton
@@ -36,6 +39,9 @@ import androidx.compose.runtime.setValue
3639import androidx.compose.ui.Alignment
3740import androidx.compose.ui.Modifier
3841import androidx.compose.ui.graphics.Color
42+ import androidx.compose.ui.graphics.graphicsLayer
43+ import androidx.compose.ui.input.pointer.pointerInput
44+ import androidx.compose.ui.platform.LocalContext
3945import androidx.compose.ui.tooling.preview.Preview
4046import androidx.compose.ui.unit.dp
4147import androidx.compose.ui.unit.sp
@@ -60,8 +66,12 @@ fun ConversationScreen(navController: NavController, modifier: Modifier) {
6066 // Coroutines
6167 val coroutineScope = rememberCoroutineScope()
6268
69+ // Toasts
70+ val currentLocalContext = LocalContext .current
71+
6372 // State variables
6473 var messages by rememberSaveable { mutableStateOf(listOf<Message >()) }
74+ var selectedMessages by rememberSaveable { mutableStateOf(listOf<Message >()) }
6575 var newMessageContent by rememberSaveable { mutableStateOf(" " ) }
6676 var isSender by rememberSaveable { mutableStateOf(true ) }
6777
@@ -119,6 +129,37 @@ fun ConversationScreen(navController: NavController, modifier: Modifier) {
119129 text = " Demo" ,
120130 fontSize = 24 .sp,
121131 )
132+
133+ // Profile picture and name on the left, buttons on the right
134+ Spacer (modifier = modifier.weight(1f ))
135+
136+ if (selectedMessages.isNotEmpty()) {
137+ // Delete button
138+ IconButton (
139+ onClick = {
140+ // Only last messages of the conversation can be deleted, otherwise context would be corrupted
141+ if (messages.takeLast(selectedMessages.size) == selectedMessages) {
142+ // Update database
143+ // Inverse encapsulation of loop vs coroutine causes messages to not be deleted
144+ for (selectedMessage in selectedMessages) {
145+ coroutineScope.launch { db.messageDao.deleteMessage(selectedMessage) }
146+ }
147+
148+ // Update state variables
149+ messages = messages.dropLast(selectedMessages.size)
150+ selectedMessages = listOf ()
151+ }
152+ else {
153+ Toast .makeText(currentLocalContext, " Only messages at the end can be deleted" , Toast .LENGTH_LONG ).show()
154+ }
155+ }
156+ ) {
157+ Icon (
158+ imageVector = Icons .Outlined .Delete ,
159+ contentDescription = " Delete selected messages"
160+ )
161+ }
162+ }
122163 }
123164
124165 Spacer (modifier = modifier.height(8 .dp))
@@ -144,7 +185,26 @@ fun ConversationScreen(navController: NavController, modifier: Modifier) {
144185 color = if (message.senderID == 0 ) Color (0xFF2E7D32 ) else Color (0xFFB71C1C ),
145186 shape = RoundedCornerShape (4 .dp)
146187 )
188+ .graphicsLayer(
189+ alpha = if (selectedMessages.isEmpty()) { 1f }
190+ else {
191+ if (message in selectedMessages) { 1f }
192+ else { 0.25f }
193+ }
194+ )
147195 .padding(8 .dp)
196+ .pointerInput(Unit ) {
197+ detectTapGestures(
198+ onLongPress = {
199+ // List of selected messages has to be sorted because list of messages is sorted, otherwise couldn't be compared to its end
200+ selectedMessages + = message
201+ selectedMessages = selectedMessages.sortedBy { it.timestamp }
202+ },
203+ onTap = {
204+ selectedMessages - = message
205+ }
206+ )
207+ }
148208 ) {
149209 Text (
150210 text = message.content,
0 commit comments