Skip to content

Commit 6116629

Browse files
Merge pull request #6269 from nextcloud/backport/6268/stable-24.0
[stable-24.0] Card style unification and improvement
2 parents b1ddc46 + 0590e73 commit 6116629

17 files changed

Lines changed: 987 additions & 583 deletions

app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ package com.nextcloud.talk.activities
1111

1212
import android.app.KeyguardManager
1313
import android.content.Intent
14-
import android.net.Uri
1514
import android.os.Bundle
1615
import android.provider.ContactsContract
1716
import android.text.TextUtils
1817
import android.util.Log
1918
import android.widget.Toast
2019
import androidx.activity.OnBackPressedCallback
20+
import androidx.core.net.toUri
2121
import androidx.lifecycle.DefaultLifecycleObserver
2222
import androidx.lifecycle.LifecycleOwner
2323
import androidx.lifecycle.ProcessLifecycleOwner
@@ -39,8 +39,8 @@ import com.nextcloud.talk.utils.ApiUtils
3939
import com.nextcloud.talk.utils.ClosedInterfaceImpl
4040
import com.nextcloud.talk.utils.DeepLinkHandler
4141
import com.nextcloud.talk.utils.SecurityUtils
42-
import com.nextcloud.talk.utils.UnifiedPushUtils
4342
import com.nextcloud.talk.utils.ShortcutManagerHelper
43+
import com.nextcloud.talk.utils.UnifiedPushUtils
4444
import com.nextcloud.talk.utils.bundle.BundleKeys
4545
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
4646
import io.reactivex.SingleObserver
@@ -386,7 +386,7 @@ class MainActivity :
386386
* 3. Current active user as fallback (if server matches)
387387
*/
388388
private fun resolveTargetUser(users: List<User>, deepLinkResult: DeepLinkHandler.DeepLinkResult): User? {
389-
val deepLinkHost = Uri.parse(deepLinkResult.serverUrl).host?.lowercase()
389+
val deepLinkHost = deepLinkResult.serverUrl.toUri().host?.lowercase()
390390
if (deepLinkHost.isNullOrBlank()) {
391391
return currentUserProviderOld.currentUser.blockingGet()
392392
}
@@ -395,21 +395,21 @@ class MainActivity :
395395
val username = deepLinkResult.username
396396
val exactMatch = if (username != null) {
397397
users.find { user ->
398-
val userHost = user.baseUrl?.let { Uri.parse(it).host?.lowercase() }
398+
val userHost = user.baseUrl?.let { it.toUri().host?.lowercase() }
399399
userHost == deepLinkHost && user.username?.lowercase() == username.lowercase()
400400
}
401401
} else {
402402
null
403403
}
404404

405405
val serverMatch = users.find { user ->
406-
val userHost = user.baseUrl?.let { Uri.parse(it).host?.lowercase() }
406+
val userHost = user.baseUrl?.let { it.toUri().host?.lowercase() }
407407
userHost == deepLinkHost
408408
}
409409

410410
val currentUser = currentUserProviderOld.currentUser.blockingGet()
411411
val currentUserMatch = currentUser?.takeIf {
412-
it.baseUrl?.let { url -> Uri.parse(url).host?.lowercase() } == deepLinkHost
412+
it.baseUrl?.let { url -> url.toUri().host?.lowercase() } == deepLinkHost
413413
}
414414

415415
return exactMatch ?: serverMatch ?: currentUserMatch

app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt

Lines changed: 95 additions & 157 deletions
Large diffs are not rendered by default.

app/src/main/java/com/nextcloud/talk/ui/ComposeWaveformSeekbar.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import androidx.compose.ui.unit.dp
2828

2929
const val WAVEFORM_THUMB_SIZE = 20
3030
const val WAVEFORM_SIZE = 30
31+
const val MAX_HEIGHT = 100
3132
const val OVERLAP = 0.025
3233

3334
@OptIn(ExperimentalMaterial3Api::class)
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
/*
2+
* Nextcloud Talk - Android Client
3+
*
4+
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
5+
* SPDX-License-Identifier: GPL-3.0-or-later
6+
*/
7+
8+
package com.nextcloud.talk.ui
9+
10+
import androidx.compose.foundation.BorderStroke
11+
import androidx.compose.foundation.layout.Box
12+
import androidx.compose.foundation.layout.Column
13+
import androidx.compose.foundation.layout.Row
14+
import androidx.compose.foundation.layout.Spacer
15+
import androidx.compose.foundation.layout.fillMaxWidth
16+
import androidx.compose.foundation.layout.padding
17+
import androidx.compose.foundation.layout.size
18+
import androidx.compose.foundation.shape.RoundedCornerShape
19+
import androidx.compose.material3.Card
20+
import androidx.compose.material3.CardDefaults
21+
import androidx.compose.material3.DropdownMenu
22+
import androidx.compose.material3.DropdownMenuItem
23+
import androidx.compose.material3.Icon
24+
import androidx.compose.material3.IconButton
25+
import androidx.compose.material3.MaterialTheme
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.remember
31+
import androidx.compose.runtime.setValue
32+
import androidx.compose.ui.Modifier
33+
import androidx.compose.ui.graphics.vector.ImageVector
34+
import androidx.compose.ui.platform.LocalContext
35+
import androidx.compose.ui.res.pluralStringResource
36+
import androidx.compose.ui.res.stringResource
37+
import androidx.compose.ui.res.vectorResource
38+
import androidx.compose.ui.tooling.preview.Preview
39+
import androidx.compose.ui.unit.dp
40+
import com.nextcloud.talk.R
41+
import com.nextcloud.talk.ui.theme.ViewThemeUtils
42+
import com.nextcloud.talk.utils.preview.ComposePreviewUtils
43+
44+
@Composable
45+
fun ConversationDeleteNoticeView(
46+
data: ConversationDeleteNoticeViewData,
47+
viewThemeUtils: ViewThemeUtils,
48+
onDeleteNow: () -> Unit,
49+
onKeep: () -> Unit,
50+
onDismiss: () -> Unit
51+
) {
52+
val context = LocalContext.current
53+
val colorScheme = remember { viewThemeUtils.getColorScheme(context) }
54+
Card(
55+
modifier = Modifier.fillMaxWidth(),
56+
shape = RoundedCornerShape(4.dp),
57+
colors = CardDefaults.cardColors(containerColor = colorScheme.surface),
58+
border = BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant)
59+
) {
60+
Row(modifier = Modifier.padding(start = 8.dp, end = 0.dp)) {
61+
Icon(
62+
imageVector = ImageVector.vectorResource(R.drawable.baseline_info_24),
63+
contentDescription = null,
64+
modifier = Modifier
65+
.padding(top = 8.dp)
66+
.size(24.dp)
67+
)
68+
Spacer(modifier = Modifier.size(8.dp))
69+
Column(
70+
modifier = Modifier
71+
.weight(1f)
72+
.padding(top = 8.dp, bottom = 8.dp)
73+
) {
74+
Text(
75+
text = pluralStringResource(
76+
R.plurals.nc_conversation_auto_delete_info,
77+
data.retentionDays,
78+
data.retentionDays
79+
),
80+
style = MaterialTheme.typography.bodyMedium
81+
)
82+
}
83+
ConversationDeleteNoticeActions(
84+
isModeratorOrOwner = data.isModeratorOrOwner,
85+
onDeleteNow = onDeleteNow,
86+
onKeep = onKeep,
87+
onDismiss = onDismiss
88+
)
89+
}
90+
}
91+
}
92+
93+
@Composable
94+
private fun ConversationDeleteNoticeActions(
95+
isModeratorOrOwner: Boolean,
96+
onDeleteNow: () -> Unit,
97+
onKeep: () -> Unit,
98+
onDismiss: () -> Unit
99+
) {
100+
var expanded by remember { mutableStateOf(false) }
101+
Column {
102+
if (isModeratorOrOwner) {
103+
Box {
104+
IconButton(onClick = { expanded = true }) {
105+
Icon(
106+
imageVector = ImageVector.vectorResource(R.drawable.ic_more_vert_24px),
107+
contentDescription = null
108+
)
109+
}
110+
DropdownMenu(
111+
expanded = expanded,
112+
onDismissRequest = { expanded = false }
113+
) {
114+
DropdownMenuItem(
115+
text = { Text(stringResource(R.string.nc_delete_now)) },
116+
onClick = {
117+
expanded = false
118+
onDeleteNow()
119+
}
120+
)
121+
DropdownMenuItem(
122+
text = {
123+
Text(stringResource(R.string.nc_keep))
124+
},
125+
onClick = {
126+
expanded = false
127+
onKeep()
128+
}
129+
)
130+
}
131+
}
132+
} else {
133+
IconButton(onClick = onDismiss) {
134+
Icon(
135+
imageVector = ImageVector.vectorResource(R.drawable.ic_baseline_close_24),
136+
contentDescription = stringResource(R.string.nc_common_dismiss)
137+
)
138+
}
139+
}
140+
}
141+
}
142+
143+
data class ConversationDeleteNoticeViewData(val retentionDays: Int, val isModeratorOrOwner: Boolean)
144+
145+
@Preview(name = "Dark Mode", uiMode = android.content.res.Configuration.UI_MODE_NIGHT_YES)
146+
@Composable
147+
fun ConversationDeleteNoticePreviewDark() {
148+
ConversationDeleteNoticePreview()
149+
}
150+
151+
@Preview(name = "R-t-L", locale = "ar")
152+
@Composable
153+
fun ConversationDeleteNoticePreviewRtl() {
154+
ConversationDeleteNoticePreview()
155+
}
156+
157+
@Preview(name = "Light Mode / Read-only")
158+
@Composable
159+
fun ConversationDeleteNoticePreviewReadOnly() {
160+
ConversationDeleteNoticePreview(isModeratorOrOwner = false)
161+
}
162+
163+
@Preview(name = "Dark Mode / Read-only", uiMode = android.content.res.Configuration.UI_MODE_NIGHT_YES)
164+
@Composable
165+
fun ConversationDeleteNoticePreviewDarkReadOnly() {
166+
ConversationDeleteNoticePreview(isModeratorOrOwner = false)
167+
}
168+
169+
@Preview(name = "R-t-L / Read-only", locale = "ar")
170+
@Composable
171+
fun ConversationDeleteNoticePreviewRtlReadOnly() {
172+
ConversationDeleteNoticePreview(isModeratorOrOwner = false)
173+
}
174+
175+
@Suppress("MagicNumber")
176+
@Preview(name = "Light Mode")
177+
@Composable
178+
fun ConversationDeleteNoticePreview(retentionDays: Int = 7, isModeratorOrOwner: Boolean = true) {
179+
val context = LocalContext.current
180+
val previewUtils = ComposePreviewUtils.getInstance(context)
181+
val viewThemeUtils = previewUtils.viewThemeUtils
182+
val colorScheme = viewThemeUtils.getColorScheme(context)
183+
184+
MaterialTheme(colorScheme = colorScheme) {
185+
ConversationDeleteNoticeView(
186+
data = ConversationDeleteNoticeViewData(
187+
retentionDays = retentionDays,
188+
isModeratorOrOwner = isModeratorOrOwner
189+
),
190+
viewThemeUtils = viewThemeUtils,
191+
onDeleteNow = {},
192+
onKeep = {},
193+
onDismiss = {}
194+
)
195+
}
196+
}

0 commit comments

Comments
 (0)