Skip to content

Commit 4047847

Browse files
Merge pull request #3
Add conversation view
2 parents 09366c0 + 6eecdab commit 4047847

File tree

7 files changed

+248
-2
lines changed

7 files changed

+248
-2
lines changed

app/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ dependencies {
5050
implementation(libs.androidx.ui.tooling.preview)
5151
implementation(libs.androidx.material3)
5252
implementation(libs.androidx.navigation.compose)
53+
implementation(libs.androidx.material.icons.extended)
5354
testImplementation(libs.junit)
5455
androidTestImplementation(libs.androidx.junit)
5556
androidTestImplementation(libs.androidx.espresso.core)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package org.vonderheidt.hips.data
2+
3+
/**
4+
* Class that represents a chat message in a conversation.
5+
*/
6+
data class Message (
7+
val senderID: Int,
8+
val receiverID: Int,
9+
val timestamp: Long,
10+
val content: String
11+
) {
12+
/**
13+
* Some sample messages for the conversation screen.
14+
*/
15+
companion object {
16+
val Samples = listOf(
17+
Message(1, 0, System.currentTimeMillis() - 5982341, "Oi, Lionel! What a match today! I honestly thought we were done for at halftime being 2-0 down, but that second half was brilliant! We really pulled it together, didn’t we?"),
18+
Message(0, 1, System.currentTimeMillis() - 4553793, "Absolutely, Cristiano! That comeback was mental! Your goal really got everyone buzzing. And that assist I had? Proper chuffed to finally chip in like that! But can we talk about the ref? What a wanker!"),
19+
Message(1, 0, System.currentTimeMillis() - 3163455, "Right? I mean, some of those calls were ridiculous! I thought he was going to cost us the game. Thank goodness we managed to turn it around despite him!"),
20+
Message(0, 1, System.currentTimeMillis() - 2398574, "No doubt about it! I reckon we’re finally starting to gel as a team, but we need to work on our communication a bit. I lost track of you a couple of times out there!"),
21+
Message(1, 0, System.currentTimeMillis() - 1637465, "Totally agree! Let’s sort out a practice this week to work on that. And afterwards, we should grab a bite and find a pub that shows the highlights! What do you reckon?")
22+
)
23+
}
24+
}

app/src/main/java/org/vonderheidt/hips/navigation/NavGraph.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import androidx.navigation.NavHostController
66
import androidx.navigation.compose.NavHost
77
import androidx.navigation.compose.composable
88
import androidx.navigation.compose.rememberNavController
9+
import org.vonderheidt.hips.ui.screens.ConversationScreen
910
import org.vonderheidt.hips.ui.screens.HomeScreen
1011
import org.vonderheidt.hips.ui.screens.SettingsScreen
1112

@@ -22,5 +23,6 @@ fun SetupNavGraph(modifier: Modifier) {
2223
) {
2324
composable(Screen.Home.route) { HomeScreen(navController, modifier) }
2425
composable(Screen.Settings.route) { SettingsScreen(navController, modifier) }
26+
composable(Screen.Conversation.route) { ConversationScreen(navController, modifier) }
2527
}
2628
}

app/src/main/java/org/vonderheidt/hips/navigation/Screen.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ package org.vonderheidt.hips.navigation
66
sealed class Screen(val route: String) {
77
object Home: Screen("home")
88
object Settings: Screen("settings")
9+
object Conversation: Screen("conversation")
910
}
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
package org.vonderheidt.hips.ui.screens
2+
3+
import androidx.compose.foundation.background
4+
import androidx.compose.foundation.layout.Arrangement
5+
import androidx.compose.foundation.layout.Box
6+
import androidx.compose.foundation.layout.Column
7+
import androidx.compose.foundation.layout.Row
8+
import androidx.compose.foundation.layout.Spacer
9+
import androidx.compose.foundation.layout.fillMaxSize
10+
import androidx.compose.foundation.layout.fillMaxWidth
11+
import androidx.compose.foundation.layout.height
12+
import androidx.compose.foundation.layout.padding
13+
import androidx.compose.foundation.layout.size
14+
import androidx.compose.foundation.layout.width
15+
import androidx.compose.foundation.lazy.LazyColumn
16+
import androidx.compose.foundation.lazy.items
17+
import androidx.compose.foundation.shape.CircleShape
18+
import androidx.compose.foundation.shape.RoundedCornerShape
19+
import androidx.compose.material.icons.Icons
20+
import androidx.compose.material.icons.automirrored.outlined.ArrowForward
21+
import androidx.compose.material.icons.automirrored.outlined.Send
22+
import androidx.compose.material.icons.outlined.Person
23+
import androidx.compose.material3.Icon
24+
import androidx.compose.material3.IconButton
25+
import androidx.compose.material3.OutlinedTextField
26+
import androidx.compose.material3.Text
27+
import androidx.compose.runtime.Composable
28+
import androidx.compose.runtime.getValue
29+
import androidx.compose.runtime.mutableStateOf
30+
import androidx.compose.runtime.saveable.rememberSaveable
31+
import androidx.compose.runtime.setValue
32+
import androidx.compose.ui.Alignment
33+
import androidx.compose.ui.Modifier
34+
import androidx.compose.ui.graphics.Color
35+
import androidx.compose.ui.tooling.preview.Preview
36+
import androidx.compose.ui.unit.dp
37+
import androidx.compose.ui.unit.sp
38+
import androidx.navigation.NavController
39+
import androidx.navigation.NavHostController
40+
import androidx.navigation.compose.rememberNavController
41+
import org.vonderheidt.hips.data.Message
42+
import org.vonderheidt.hips.navigation.Screen
43+
import org.vonderheidt.hips.ui.theme.HiPSTheme
44+
45+
/**
46+
* Function that defines the conversation screen.
47+
*/
48+
@Composable
49+
fun ConversationScreen(navController: NavController, modifier: Modifier) {
50+
// State variables
51+
var messages by rememberSaveable { mutableStateOf(listOf<Message>()) }
52+
var newMessage by rememberSaveable { mutableStateOf("") }
53+
var sender by rememberSaveable { mutableStateOf(true) }
54+
55+
// UI components
56+
Column(
57+
modifier = modifier.fillMaxSize(),
58+
horizontalAlignment = Alignment.CenterHorizontally
59+
) {
60+
// Back button
61+
Row(
62+
modifier = modifier.fillMaxWidth(),
63+
horizontalArrangement = Arrangement.End
64+
) {
65+
IconButton(
66+
onClick = {
67+
// Navigate back to home screen
68+
navController.navigate(Screen.Home.route) {
69+
// Empty back stack, including home screen
70+
// Otherwise app won't close when user goes back once more via the phone's back button
71+
popUpTo(Screen.Home.route) {
72+
inclusive = true
73+
}
74+
}
75+
}
76+
) {
77+
Icon(
78+
imageVector = Icons.AutoMirrored.Outlined.ArrowForward,
79+
contentDescription = "Go back to home screen"
80+
)
81+
}
82+
}
83+
84+
// Chat partner
85+
Row (
86+
modifier = modifier.fillMaxWidth(0.95f),
87+
verticalAlignment = Alignment.CenterVertically
88+
){
89+
// Profile picture
90+
Icon(
91+
imageVector = Icons.Outlined.Person,
92+
contentDescription = "Profile picture",
93+
modifier = modifier.size(24.dp)
94+
)
95+
96+
Spacer(modifier = modifier.width(8.dp))
97+
98+
// Name
99+
Text(
100+
text = "Demo",
101+
fontSize = 24.sp,
102+
)
103+
}
104+
105+
Spacer(modifier = modifier.height(8.dp))
106+
107+
// Messages
108+
// Use LazyColumn as it only loads visible messages into memory, allowing for arbitrary number of messages
109+
LazyColumn(
110+
modifier = modifier
111+
.fillMaxWidth(0.95f)
112+
.weight(1f)
113+
) {
114+
// Current user (senderID == 0) is right aligned and green
115+
// Chat partners (senderID != 0) are left aligned and red
116+
items(messages) { message ->
117+
Row (
118+
modifier = modifier.fillMaxWidth(),
119+
horizontalArrangement = if (message.senderID == 0) Arrangement.End else Arrangement.Start
120+
) {
121+
Box(
122+
modifier = modifier
123+
.fillMaxWidth(0.9f)
124+
.background(
125+
color = if (message.senderID == 0) Color(0xFF2E7D32) else Color(0xFFB71C1C),
126+
shape = RoundedCornerShape(4.dp)
127+
)
128+
.padding(8.dp)
129+
) {
130+
Text(
131+
text = message.content,
132+
color = Color.White
133+
)
134+
}
135+
}
136+
137+
Spacer(modifier = modifier.height(8.dp))
138+
}
139+
}
140+
141+
Row(
142+
modifier = modifier.fillMaxWidth(0.95f),
143+
verticalAlignment = Alignment.Bottom
144+
) {
145+
// Input field for new message
146+
OutlinedTextField(
147+
value = newMessage,
148+
onValueChange = {newMessage = it},
149+
modifier = modifier.weight(1f),
150+
label = { Text(text = "New message") }
151+
)
152+
153+
Spacer(modifier = modifier.width(8.dp))
154+
155+
// Send button
156+
// Colour corresponds to user a new message is being sent as
157+
IconButton(
158+
onClick = {
159+
// Only send non-empty messages
160+
// Allows to switch user on button press
161+
if (newMessage != "") {
162+
messages += Message(
163+
senderID = if (sender) 0 else 1,
164+
receiverID = if (sender) 1 else 0,
165+
timestamp = System.currentTimeMillis(),
166+
content = newMessage
167+
)
168+
}
169+
170+
// Clear input field and change mode
171+
newMessage = ""
172+
sender = !sender
173+
},
174+
modifier = modifier
175+
.background(
176+
color = if (sender) Color(0xFF2E7D32) else Color(0xFFB71C1C),
177+
shape = CircleShape
178+
)
179+
) {
180+
Icon(
181+
imageVector = Icons.AutoMirrored.Outlined.Send,
182+
contentDescription = "Send message",
183+
tint = Color.White
184+
)
185+
}
186+
}
187+
188+
Spacer(modifier = modifier.height(8.dp))
189+
}
190+
}
191+
192+
/**
193+
* Function to show preview of the conversation screen in Android Studio.
194+
*/
195+
@Preview(showBackground = true)
196+
@Composable
197+
fun ConversationScreenPreview() {
198+
// No Scaffold, no innerPadding
199+
HiPSTheme {
200+
val modifier: Modifier = Modifier
201+
val navController: NavHostController = rememberNavController()
202+
203+
ConversationScreen(navController, modifier)
204+
}
205+
}

app/src/main/java/org/vonderheidt/hips/ui/screens/HomeScreen.kt

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import androidx.compose.foundation.verticalScroll
1818
import androidx.compose.material.icons.Icons
1919
import androidx.compose.material.icons.outlined.Clear
2020
import androidx.compose.material.icons.outlined.Email
21+
import androidx.compose.material.icons.outlined.Forum
2122
import androidx.compose.material.icons.outlined.Info
2223
import androidx.compose.material.icons.outlined.Lock
2324
import androidx.compose.material.icons.outlined.Settings
@@ -84,11 +85,21 @@ fun HomeScreen(navController: NavController, modifier: Modifier) {
8485
.verticalScroll(state = scrollState),
8586
horizontalAlignment = Alignment.CenterHorizontally
8687
) {
87-
// Settings icon
8888
Row(
8989
modifier = modifier.fillMaxWidth(),
90-
horizontalArrangement = Arrangement.End
90+
horizontalArrangement = Arrangement.SpaceBetween
9191
) {
92+
// Conversation icon
93+
IconButton(
94+
onClick = { navController.navigate(Screen.Conversation.route) }
95+
) {
96+
Icon(
97+
imageVector = Icons.Outlined.Forum,
98+
contentDescription = "Conversations"
99+
)
100+
}
101+
102+
// Settings icon
92103
IconButton(
93104
onClick = { navController.navigate(Screen.Settings.route) }
94105
) {

gradle/libs.versions.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ lifecycleRuntimeKtx = "2.8.7"
99
activityCompose = "1.9.3"
1010
composeBom = "2024.11.00"
1111
navigationCompose = "2.8.4"
12+
materialIconsExtended = "1.7.5"
1213

1314
[libraries]
1415
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
@@ -26,6 +27,7 @@ androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-man
2627
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
2728
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
2829
androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigationCompose" }
30+
androidx-material-icons-extended = { group = "androidx.compose.material", name = "material-icons-extended", version.ref = "materialIconsExtended" }
2931

3032
[plugins]
3133
android-application = { id = "com.android.application", version.ref = "agp" }

0 commit comments

Comments
 (0)