Skip to content

Commit 1b945c5

Browse files
committed
add thread icons, improve ColorGenerator and add tests
Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
1 parent 87e0a72 commit 1b945c5

5 files changed

Lines changed: 162 additions & 107 deletions

File tree

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Nextcloud Talk - Android Client
3+
*
4+
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
5+
* SPDX-FileCopyrightText: 2025 Marcel Hibbe <dev@mhibbe.de>
6+
* SPDX-License-Identifier: GPL-3.0-or-later
7+
*/
8+
9+
package com.nextcloud.talk.utils
10+
11+
import android.graphics.Color
12+
import org.junit.Assert
13+
import org.junit.Test
14+
15+
class ColorGeneratorTest {
16+
17+
@Test
18+
fun testUsernameToColor() {
19+
usernameToColorHexHelper("", "#0082c9")
20+
usernameToColorHexHelper(",", "#1e78c1")
21+
usernameToColorHexHelper(".", "#c98879")
22+
usernameToColorHexHelper("admin", "#d09e6d")
23+
usernameToColorHexHelper("123e4567-e89b-12d3-a456-426614174000", "#bc5c91")
24+
usernameToColorHexHelper("Akeel Robertson", "#9750a4")
25+
usernameToColorHexHelper("Brayden Truong", "#d09e6d")
26+
usernameToColorHexHelper("Daphne Roy", "#9750a4")
27+
usernameToColorHexHelper("Ellena Wright Frederic Conway", "#c37285")
28+
usernameToColorHexHelper("Gianluca Hills", "#d6b461")
29+
usernameToColorHexHelper("Haseeb Stephens", "#d6b461")
30+
usernameToColorHexHelper("Idris Mac", "#9750a4")
31+
usernameToColorHexHelper("Kristi Fisher", "#0082c9")
32+
usernameToColorHexHelper("Lillian Wall", "#bc5c91")
33+
usernameToColorHexHelper("Lorelai Taylor", "#ddcb55")
34+
usernameToColorHexHelper("Madina Knight", "#9750a4")
35+
usernameToColorHexHelper("Meeting", "#c98879")
36+
usernameToColorHexHelper("Private Circle", "#c37285")
37+
usernameToColorHexHelper("Rae Hope", "#795aab")
38+
usernameToColorHexHelper("Santiago Singleton", "#bc5c91")
39+
usernameToColorHexHelper("Sid Combs", "#d09e6d")
40+
usernameToColorHexHelper("TestCircle", "#499aa2")
41+
usernameToColorHexHelper("Tom Mörtel", "#248eb5")
42+
usernameToColorHexHelper("Vivienne Jacobs", "#1e78c1")
43+
usernameToColorHexHelper("Zaki Cortes", "#6ea68f")
44+
usernameToColorHexHelper("a user", "#5b64b3")
45+
usernameToColorHexHelper("admin@cloud.example.com", "#9750a4")
46+
usernameToColorHexHelper("another user", "#ddcb55")
47+
usernameToColorHexHelper("asd", "#248eb5")
48+
usernameToColorHexHelper("bar", "#0082c9")
49+
usernameToColorHexHelper("foo", "#d09e6d")
50+
usernameToColorHexHelper("wasd", "#b6469d")
51+
usernameToColorHexHelper("مرحبا بالعالم", "#c98879")
52+
usernameToColorHexHelper("🙈", "#b6469d")
53+
}
54+
55+
private fun usernameToColorHexHelper(username: String, expectedHexColor: String) {
56+
val userColorInt = ColorGenerator.usernameToColor(username) // returns Int
57+
val userHexColor = intToHex(userColorInt)
58+
59+
Assert.assertEquals(expectedHexColor.lowercase(), userHexColor.lowercase())
60+
}
61+
62+
private fun intToHex(colorInt: Int): String {
63+
val r = Color.red(colorInt)
64+
val g = Color.green(colorInt)
65+
val b = Color.blue(colorInt)
66+
return String.format("#%02x%02x%02x", r, g, b)
67+
}
68+
}

app/src/main/java/com/nextcloud/talk/call/components/ParticipantTile.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ fun ParticipantTile(
5050
modifier: Modifier = Modifier,
5151
isVoiceOnlyCall: Boolean
5252
) {
53-
val colorInt = ColorGenerator.shared.usernameToColor(participantUiState.nick)
53+
val colorInt = ColorGenerator.usernameToColor(participantUiState.nick)
5454

5555
BoxWithConstraints(
5656
modifier = modifier

app/src/main/java/com/nextcloud/talk/threadsoverview/ThreadsOverviewActivity.kt

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,11 @@ import com.nextcloud.talk.chat.ChatActivity
4848
import com.nextcloud.talk.chat.ChatActivity.Companion.TAG
4949
import com.nextcloud.talk.components.ColoredStatusBar
5050
import com.nextcloud.talk.components.StandardAppBar
51-
import com.nextcloud.talk.contacts.loadImage
5251
import com.nextcloud.talk.data.database.mappers.asModel
5352
import com.nextcloud.talk.models.json.threads.ThreadInfo
5453
import com.nextcloud.talk.threadsoverview.components.ThreadRow
5554
import com.nextcloud.talk.threadsoverview.viewmodels.ThreadsOverviewViewModel
5655
import com.nextcloud.talk.users.UserManager
57-
import com.nextcloud.talk.utils.ApiUtils
5856
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
5957
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_THREAD_ID
6058
import javax.inject.Inject
@@ -206,14 +204,6 @@ fun ThreadsList(
206204
items = threads,
207205
key = { threadInfo -> threadInfo.thread!!.id }
208206
) { threadInfo ->
209-
val imageUri = ApiUtils.getUrlForAvatar(
210-
threadsOverviewViewModel.currentUser.baseUrl,
211-
threadInfo.first?.actorId,
212-
true
213-
)
214-
val errorPlaceholderImage: Int = R.drawable.account_circle_96dp
215-
val imageRequest = loadImage(imageUri, context, errorPlaceholderImage)
216-
217207
val messageJson = threadInfo.last ?: threadInfo.first
218208
val messageModel = messageJson?.asModel()
219209

@@ -229,7 +219,6 @@ fun ThreadsList(
229219
secondLineTitle = messageModel?.actorDisplayName?.substringBefore(space)?.let { "$it:" }.orEmpty(),
230220
secondLine = messageModel?.text.orEmpty(),
231221
date = getLastActivityDate(threadInfo), // replace with value from api when available
232-
imageRequest = imageRequest,
233222
onClick = onThreadClick
234223
)
235224
}

app/src/main/java/com/nextcloud/talk/threadsoverview/components/ThreadRow.kt

Lines changed: 56 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77

88
package com.nextcloud.talk.threadsoverview.components
99

10+
import android.content.res.Configuration
11+
import androidx.compose.foundation.background
1012
import androidx.compose.foundation.clickable
13+
import androidx.compose.foundation.layout.Box
1114
import androidx.compose.foundation.layout.Column
1215
import androidx.compose.foundation.layout.Row
1316
import androidx.compose.foundation.layout.Spacer
@@ -16,19 +19,23 @@ import androidx.compose.foundation.layout.height
1619
import androidx.compose.foundation.layout.padding
1720
import androidx.compose.foundation.layout.size
1821
import androidx.compose.foundation.layout.width
22+
import androidx.compose.foundation.shape.CircleShape
23+
import androidx.compose.material3.Icon
1924
import androidx.compose.material3.MaterialTheme
2025
import androidx.compose.material3.Text
2126
import androidx.compose.runtime.Composable
2227
import androidx.compose.ui.Alignment
2328
import androidx.compose.ui.Modifier
24-
import androidx.compose.ui.res.stringResource
29+
import androidx.compose.ui.draw.clip
30+
import androidx.compose.ui.graphics.Color
31+
import androidx.compose.ui.graphics.vector.ImageVector
32+
import androidx.compose.ui.res.vectorResource
2533
import androidx.compose.ui.text.font.FontWeight
2634
import androidx.compose.ui.text.style.TextOverflow
2735
import androidx.compose.ui.tooling.preview.Preview
2836
import androidx.compose.ui.unit.dp
29-
import coil.compose.AsyncImage
30-
import coil.request.ImageRequest
3137
import com.nextcloud.talk.R
38+
import com.nextcloud.talk.utils.ColorGenerator
3239

3340
@Suppress("LongParameterList", "Detekt.LongMethod")
3441
@Composable
@@ -40,7 +47,6 @@ fun ThreadRow(
4047
secondLine: String,
4148
numReplies: String,
4249
date: String,
43-
imageRequest: ImageRequest?,
4450
onClick: ((String, Int) -> Unit?)?
4551
) {
4652
Row(
@@ -52,11 +58,7 @@ fun ThreadRow(
5258
.padding(vertical = 8.dp, horizontal = 8.dp),
5359
verticalAlignment = Alignment.Companion.CenterVertically
5460
) {
55-
AsyncImage(
56-
model = imageRequest,
57-
contentDescription = stringResource(R.string.user_avatar),
58-
modifier = Modifier.Companion.size(48.dp)
59-
)
61+
ThreadsIcon(title)
6062

6163
Spacer(modifier = Modifier.Companion.width(12.dp))
6264

@@ -113,19 +115,56 @@ fun ThreadRow(
113115
}
114116
}
115117

118+
@Composable
119+
fun ThreadsIcon(title: String) {
120+
Box(
121+
modifier = Modifier
122+
.size(48.dp)
123+
.clip(CircleShape)
124+
.background(MaterialTheme.colorScheme.onPrimary),
125+
contentAlignment = Alignment.Center
126+
) {
127+
val baseColorInt = ColorGenerator.usernameToColor(title)
128+
129+
Icon(
130+
imageVector = ImageVector.vectorResource(R.drawable.outline_forum_24),
131+
contentDescription = null,
132+
tint = Color(baseColorInt),
133+
modifier = Modifier.size(32.dp)
134+
)
135+
}
136+
}
137+
116138
@Preview
117139
@Composable
118140
fun ThreadRowPreview() {
119141
ThreadRow(
120142
roomToken = "1234",
121143
threadId = 123,
122-
title = "title",
144+
title = "title1",
145+
secondLine = "last message",
146+
secondLineTitle = "Mia:",
147+
numReplies = "12 replies",
148+
date = "14 sec ago",
149+
onClick = null
150+
)
151+
}
152+
153+
@Preview(
154+
name = "Dark Mode",
155+
uiMode = Configuration.UI_MODE_NIGHT_YES
156+
)
157+
@Composable
158+
fun ThreadRowPreviewDark() {
159+
ThreadRow(
160+
roomToken = "1234",
161+
threadId = 123,
162+
title = "title2",
123163
secondLine = "last message",
124164
secondLineTitle = "Mia:",
125165
numReplies = "12 replies",
126166
date = "14 sec ago",
127-
onClick = null,
128-
imageRequest = null
167+
onClick = null
129168
)
130169
}
131170

@@ -135,13 +174,12 @@ fun ThreadRowUnreadMessagePreview() {
135174
ThreadRow(
136175
roomToken = "1234",
137176
threadId = 123,
138-
title = "title",
177+
title = "title3",
139178
secondLine = "last message",
140179
secondLineTitle = "Mia:",
141180
numReplies = "12 replies",
142181
date = "14 sec ago",
143-
onClick = null,
144-
imageRequest = null
182+
onClick = null
145183
)
146184
}
147185

@@ -151,13 +189,12 @@ fun ThreadRowMentionPreview() {
151189
ThreadRow(
152190
roomToken = "1234",
153191
threadId = 123,
154-
title = "title",
192+
title = "title3",
155193
secondLine = "last message",
156194
secondLineTitle = "Mia:",
157195
numReplies = "12 replies",
158196
date = "14 sec ago",
159-
onClick = null,
160-
imageRequest = null
197+
onClick = null
161198
)
162199
}
163200

@@ -172,7 +209,6 @@ fun ThreadRowDirectMentionPreview() {
172209
secondLineTitle = "Mia:",
173210
numReplies = "12 replies",
174211
date = "14 sec ago",
175-
onClick = null,
176-
imageRequest = null
212+
onClick = null
177213
)
178214
}

0 commit comments

Comments
 (0)