Skip to content

Commit 57ac7cb

Browse files
greyson-signalcody-signal
authored andcommitted
Show some more info in the about sheet.
1 parent 47cdc50 commit 57ac7cb

File tree

7 files changed

+251
-58
lines changed

7 files changed

+251
-58
lines changed

app/src/main/java/org/thoughtcrime/securesms/recipients/ui/about/AboutSheet.kt

Lines changed: 190 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
package org.thoughtcrime.securesms.recipients.ui.about
77

8+
import android.content.res.Configuration
89
import androidx.compose.foundation.clickable
910
import androidx.compose.foundation.layout.Box
1011
import androidx.compose.foundation.layout.Column
@@ -26,7 +27,6 @@ import androidx.compose.ui.Alignment
2627
import androidx.compose.ui.Modifier
2728
import androidx.compose.ui.draw.clip
2829
import androidx.compose.ui.graphics.painter.Painter
29-
import androidx.compose.ui.platform.LocalContext
3030
import androidx.compose.ui.res.painterResource
3131
import androidx.compose.ui.res.pluralStringResource
3232
import androidx.compose.ui.res.stringResource
@@ -38,6 +38,7 @@ import androidx.core.widget.TextViewCompat
3838
import org.signal.core.ui.BottomSheets
3939
import org.signal.core.ui.theme.SignalTheme
4040
import org.signal.core.util.getParcelableCompat
41+
import org.signal.core.util.isNotNullOrBlank
4142
import org.thoughtcrime.securesms.AvatarPreviewActivity
4243
import org.thoughtcrime.securesms.R
4344
import org.thoughtcrime.securesms.avatar.AvatarImage
@@ -81,11 +82,27 @@ class AboutSheet : ComposeBottomSheetDialogFragment() {
8182
override fun SheetContent() {
8283
val recipient by viewModel.recipient
8384
val groupsInCommonCount by viewModel.groupsInCommonCount
85+
val verified by viewModel.verified
8486

8587
if (recipient.isPresent) {
86-
AboutSheetContent(
87-
recipient = recipient.get(),
88-
groupsInCommonCount = groupsInCommonCount,
88+
Content(
89+
model = AboutModel(
90+
isSelf = recipient.get().isSelf,
91+
hasAvatar = recipient.get().profileAvatarFileDetails.hasFile(),
92+
displayName = recipient.get().getDisplayName(requireContext()),
93+
shortName = recipient.get().getShortDisplayName(requireContext()),
94+
about = recipient.get().about,
95+
verified = verified,
96+
recipientForAvatar = recipient.get(),
97+
formattedE164 = if (recipient.get().hasE164() && recipient.get().shouldShowE164()) {
98+
PhoneNumberFormatter.get(requireContext()).prettyPrintFormat(recipient.get().requireE164())
99+
} else {
100+
null
101+
},
102+
groupsInCommon = groupsInCommonCount,
103+
profileSharing = recipient.get().isProfileSharing,
104+
systemContact = recipient.get().isSystemContact
105+
),
89106
onClickSignalConnections = this::openSignalConnectionsSheet,
90107
onAvatarClicked = this::openProfilePhotoViewer
91108
)
@@ -102,25 +119,23 @@ class AboutSheet : ComposeBottomSheetDialogFragment() {
102119
}
103120
}
104121

105-
@Preview
106-
@Composable
107-
private fun AboutSheetContentPreview() {
108-
SignalTheme {
109-
Surface {
110-
AboutSheetContent(
111-
recipient = Recipient.UNKNOWN,
112-
groupsInCommonCount = 0,
113-
onClickSignalConnections = {},
114-
onAvatarClicked = {}
115-
)
116-
}
117-
}
118-
}
122+
private data class AboutModel(
123+
val isSelf: Boolean,
124+
val displayName: String,
125+
val shortName: String,
126+
val about: String?,
127+
val verified: Boolean,
128+
val hasAvatar: Boolean,
129+
val recipientForAvatar: Recipient,
130+
val formattedE164: String?,
131+
val profileSharing: Boolean,
132+
val systemContact: Boolean,
133+
val groupsInCommon: Int
134+
)
119135

120136
@Composable
121-
private fun AboutSheetContent(
122-
recipient: Recipient,
123-
groupsInCommonCount: Int,
137+
private fun Content(
138+
model: AboutModel,
124139
onClickSignalConnections: () -> Unit,
125140
onAvatarClicked: () -> Unit
126141
) {
@@ -131,8 +146,8 @@ private fun AboutSheetContent(
131146
BottomSheets.Handle(modifier = Modifier.padding(top = 6.dp))
132147
}
133148

134-
val avatarOnClick = remember(recipient.profileAvatarFileDetails.hasFile()) {
135-
if (recipient.profileAvatarFileDetails.hasFile()) {
149+
val avatarOnClick = remember(model.hasAvatar) {
150+
if (model.hasAvatar) {
136151
onAvatarClicked
137152
} else {
138153
{ }
@@ -141,7 +156,7 @@ private fun AboutSheetContent(
141156

142157
Column(horizontalAlignment = Alignment.CenterHorizontally) {
143158
AvatarImage(
144-
recipient = recipient,
159+
recipient = model.recipientForAvatar,
145160
modifier = Modifier
146161
.padding(top = 56.dp)
147162
.size(240.dp)
@@ -150,30 +165,27 @@ private fun AboutSheetContent(
150165
)
151166

152167
Text(
153-
text = stringResource(id = if (recipient.isSelf) R.string.AboutSheet__you else R.string.AboutSheet__about),
168+
text = stringResource(id = if (model.isSelf) R.string.AboutSheet__you else R.string.AboutSheet__about),
154169
style = MaterialTheme.typography.headlineMedium,
155170
modifier = Modifier
156171
.fillMaxWidth()
157172
.padding(horizontal = 32.dp)
158173
.padding(top = 20.dp, bottom = 14.dp)
159174
)
160175

161-
val context = LocalContext.current
162-
val displayName = remember(recipient) { recipient.getDisplayName(context) }
163-
164176
AboutRow(
165177
startIcon = painterResource(R.drawable.symbol_person_24),
166-
text = displayName,
178+
text = model.displayName,
167179
modifier = Modifier.fillMaxWidth()
168180
)
169181

170-
if (!recipient.about.isNullOrBlank()) {
182+
if (model.about.isNotNullOrBlank()) {
171183
AboutRow(
172184
startIcon = painterResource(R.drawable.symbol_edit_24),
173185
text = {
174186
Row {
175187
AndroidView(factory = ::EmojiTextView) {
176-
it.text = recipient.combinedAboutAndEmoji
188+
it.text = model.about
177189

178190
TextViewCompat.setTextAppearance(it, R.style.Signal_Text_BodyLarge)
179191
}
@@ -183,44 +195,55 @@ private fun AboutSheetContent(
183195
)
184196
}
185197

186-
if (recipient.isProfileSharing) {
198+
if (model.verified) {
199+
AboutRow(
200+
startIcon = painterResource(id = R.drawable.check),
201+
text = stringResource(id = R.string.AboutSheet__verified),
202+
modifier = Modifier.align(alignment = Alignment.Start),
203+
onClick = onClickSignalConnections
204+
)
205+
}
206+
207+
if (model.profileSharing || model.systemContact) {
187208
AboutRow(
188209
startIcon = painterResource(id = R.drawable.symbol_connections_24),
189210
text = stringResource(id = R.string.AboutSheet__signal_connection),
190211
endIcon = painterResource(id = R.drawable.symbol_chevron_right_compact_bold_16),
191212
modifier = Modifier.align(alignment = Alignment.Start),
192213
onClick = onClickSignalConnections
193214
)
215+
} else {
216+
AboutRow(
217+
startIcon = painterResource(id = R.drawable.chat_x),
218+
text = stringResource(id = R.string.AboutSheet__no_direct_message, model.shortName),
219+
modifier = Modifier.align(alignment = Alignment.Start),
220+
onClick = onClickSignalConnections
221+
)
194222
}
195223

196-
val shortName = remember(recipient) { recipient.getShortDisplayName(context) }
197-
if (recipient.isSystemContact) {
224+
if (model.systemContact) {
198225
AboutRow(
199226
startIcon = painterResource(id = R.drawable.symbol_person_circle_24),
200-
text = stringResource(id = R.string.AboutSheet__s_is_in_your_system_contacts, shortName),
227+
text = stringResource(id = R.string.AboutSheet__s_is_in_your_system_contacts, model.shortName),
201228
modifier = Modifier.fillMaxWidth()
202229
)
203230
}
204231

205-
if (recipient.e164.isPresent && recipient.shouldShowE164()) {
206-
val e164 = remember(recipient.e164.get()) {
207-
PhoneNumberFormatter.get(context).prettyPrintFormat(recipient.e164.get())
208-
}
209-
232+
if (model.formattedE164.isNotNullOrBlank()) {
210233
AboutRow(
211234
startIcon = painterResource(R.drawable.symbol_phone_24),
212-
text = e164,
235+
text = model.formattedE164,
213236
modifier = Modifier.fillMaxWidth()
214237
)
215238
}
216239

217-
val groupsInCommonText = if (recipient.hasGroupsInCommon()) {
218-
pluralStringResource(id = R.plurals.AboutSheet__d_groups_in, groupsInCommonCount, groupsInCommonCount)
240+
val groupsInCommonText = if (model.groupsInCommon > 0) {
241+
pluralStringResource(id = R.plurals.AboutSheet__d_groups_in, model.groupsInCommon, model.groupsInCommon)
219242
} else {
220243
stringResource(id = R.string.AboutSheet__you_have_no_groups_in_common)
221244
}
222245

223-
val groupsInCommonIcon = if (!recipient.isProfileSharing && groupsInCommonCount == 0) {
246+
val groupsInCommonIcon = if (!model.profileSharing && model.groupsInCommon == 0) {
224247
painterResource(R.drawable.symbol_error_circle_24)
225248
} else {
226249
painterResource(R.drawable.symbol_group_24)
@@ -236,20 +259,6 @@ private fun AboutSheetContent(
236259
}
237260
}
238261

239-
@Preview
240-
@Composable
241-
private fun AboutRowPreview() {
242-
SignalTheme {
243-
Surface {
244-
AboutRow(
245-
startIcon = painterResource(R.drawable.symbol_person_24),
246-
text = "Maya Johnson",
247-
endIcon = painterResource(id = R.drawable.symbol_chevron_right_compact_bold_16)
248-
)
249-
}
250-
}
251-
}
252-
253262
@Composable
254263
private fun AboutRow(
255264
startIcon: Painter,
@@ -318,3 +327,126 @@ private fun AboutRow(
318327
}
319328
}
320329
}
330+
331+
@Preview(name = "Light Theme", group = "content", uiMode = Configuration.UI_MODE_NIGHT_NO)
332+
@Preview(name = "Dark Theme", group = "content", uiMode = Configuration.UI_MODE_NIGHT_YES)
333+
@Composable
334+
private fun ContentPreviewDefault() {
335+
SignalTheme {
336+
Surface {
337+
Content(
338+
model = AboutModel(
339+
isSelf = false,
340+
hasAvatar = true,
341+
displayName = "Peter Parker",
342+
shortName = "Peter",
343+
about = "Photographer for the Daily Bugle.",
344+
verified = true,
345+
recipientForAvatar = Recipient.UNKNOWN,
346+
formattedE164 = "(123) 456-7890",
347+
profileSharing = true,
348+
systemContact = true,
349+
groupsInCommon = 0
350+
),
351+
onClickSignalConnections = {},
352+
onAvatarClicked = {}
353+
)
354+
}
355+
}
356+
}
357+
358+
@Preview(name = "Light Theme", group = "content", uiMode = Configuration.UI_MODE_NIGHT_NO)
359+
@Preview(name = "Dark Theme", group = "content", uiMode = Configuration.UI_MODE_NIGHT_YES)
360+
@Composable
361+
private fun ContentPreviewInContactsNotProfileSharing() {
362+
SignalTheme {
363+
Surface {
364+
Content(
365+
model = AboutModel(
366+
isSelf = false,
367+
hasAvatar = true,
368+
displayName = "Peter Parker",
369+
shortName = "Peter",
370+
about = "Photographer for the Daily Bugle.",
371+
verified = false,
372+
recipientForAvatar = Recipient.UNKNOWN,
373+
formattedE164 = null,
374+
profileSharing = false,
375+
systemContact = true,
376+
groupsInCommon = 3
377+
),
378+
onClickSignalConnections = {},
379+
onAvatarClicked = {}
380+
)
381+
}
382+
}
383+
}
384+
385+
@Preview(name = "Light Theme", group = "content", uiMode = Configuration.UI_MODE_NIGHT_NO)
386+
@Preview(name = "Dark Theme", group = "content", uiMode = Configuration.UI_MODE_NIGHT_YES)
387+
@Composable
388+
private fun ContentPreviewGroupsInCommonNoE164() {
389+
SignalTheme {
390+
Surface {
391+
Content(
392+
model = AboutModel(
393+
isSelf = false,
394+
hasAvatar = true,
395+
displayName = "Peter Parker",
396+
shortName = "Peter",
397+
about = "Photographer for the Daily Bugle.",
398+
verified = false,
399+
recipientForAvatar = Recipient.UNKNOWN,
400+
formattedE164 = null,
401+
profileSharing = true,
402+
systemContact = false,
403+
groupsInCommon = 3
404+
),
405+
onClickSignalConnections = {},
406+
onAvatarClicked = {}
407+
)
408+
}
409+
}
410+
}
411+
412+
@Preview(name = "Light Theme", group = "content", uiMode = Configuration.UI_MODE_NIGHT_NO)
413+
@Preview(name = "Dark Theme", group = "content", uiMode = Configuration.UI_MODE_NIGHT_YES)
414+
@Composable
415+
private fun ContentPreviewNotAConnection() {
416+
SignalTheme {
417+
Surface {
418+
Content(
419+
model = AboutModel(
420+
isSelf = false,
421+
hasAvatar = true,
422+
displayName = "Peter Parker",
423+
shortName = "Peter",
424+
about = "Photographer for the Daily Bugle.",
425+
verified = false,
426+
recipientForAvatar = Recipient.UNKNOWN,
427+
formattedE164 = null,
428+
profileSharing = false,
429+
systemContact = false,
430+
groupsInCommon = 3
431+
),
432+
onClickSignalConnections = {},
433+
onAvatarClicked = {}
434+
)
435+
}
436+
}
437+
}
438+
439+
@Preview(name = "Light Theme", group = "about row", uiMode = Configuration.UI_MODE_NIGHT_NO)
440+
@Preview(name = "Dark Theme", group = "about row", uiMode = Configuration.UI_MODE_NIGHT_YES)
441+
@Composable
442+
private fun AboutRowPreview() {
443+
SignalTheme {
444+
Surface {
445+
AboutRow(
446+
startIcon = painterResource(R.drawable.symbol_person_24),
447+
text = "Maya Johnson",
448+
endIcon = painterResource(id = R.drawable.symbol_chevron_right_compact_bold_16)
449+
)
450+
}
451+
}
452+
}

app/src/main/java/org/thoughtcrime/securesms/recipients/ui/about/AboutSheetRepository.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ package org.thoughtcrime.securesms.recipients.ui.about
77

88
import io.reactivex.rxjava3.core.Single
99
import io.reactivex.rxjava3.schedulers.Schedulers
10+
import org.thoughtcrime.securesms.database.IdentityTable
1011
import org.thoughtcrime.securesms.database.SignalDatabase
12+
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
1113
import org.thoughtcrime.securesms.recipients.RecipientId
1214

1315
class AboutSheetRepository {
@@ -16,4 +18,11 @@ class AboutSheetRepository {
1618
SignalDatabase.groups.getPushGroupsContainingMember(recipientId).size
1719
}.subscribeOn(Schedulers.io())
1820
}
21+
22+
fun getVerified(recipientId: RecipientId): Single<Boolean> {
23+
return Single.fromCallable {
24+
val identityRecord = ApplicationDependencies.getProtocolStore().aci().identities().getIdentityRecord(recipientId)
25+
identityRecord.isPresent && identityRecord.get().verifiedStatus == IdentityTable.VerifiedStatus.VERIFIED
26+
}.subscribeOn(Schedulers.io())
27+
}
1928
}

0 commit comments

Comments
 (0)