Make group subtitles auto-update as names change.

This commit is contained in:
Alex Hart 2024-07-02 15:50:35 -03:00 committed by Cody Henthorne
parent 69fd4f79db
commit 066892c11a
3 changed files with 48 additions and 11 deletions

View file

@ -15,8 +15,6 @@ import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout; import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import com.annimon.stream.Collectors;
import com.annimon.stream.Stream;
import com.bumptech.glide.RequestManager; import com.bumptech.glide.RequestManager;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
@ -176,6 +174,11 @@ public class ConversationTitleView extends ConstraintLayout {
updateVerifiedSubtitleVisibility(); updateVerifiedSubtitleVisibility();
} }
public void setGroupRecipientSubtitle(@Nullable String members) {
this.subtitle.setText(members);
updateSubtitleVisibility();
}
private void setComposeTitle() { private void setComposeTitle() {
this.title.setText(R.string.ConversationActivity_compose_message); this.title.setText(R.string.ConversationActivity_compose_message);
this.subtitle.setText(null); this.subtitle.setText(null);
@ -190,15 +193,6 @@ public class ConversationTitleView extends ConstraintLayout {
private void setGroupRecipientTitle(@NonNull Recipient recipient) { private void setGroupRecipientTitle(@NonNull Recipient recipient) {
this.title.setText(recipient.getDisplayName(getContext())); this.title.setText(recipient.getDisplayName(getContext()));
this.subtitle.setText(Stream.of(recipient.getParticipantIds())
.limit(10)
.map(Recipient::resolved)
.sorted((a, b) -> Boolean.compare(a.isSelf(), b.isSelf()))
.map(r -> r.isSelf() ? getResources().getString(R.string.ConversationTitleView_you)
: r.getDisplayName(getContext()))
.collect(Collectors.joining(", ")));
updateSubtitleVisibility();
} }
private void setSelfTitle() { private void setSelfTitle() {

View file

@ -581,6 +581,7 @@ class ConversationFragment :
presentWallpaper(args.wallpaper) presentWallpaper(args.wallpaper)
presentChatColors(args.chatColors) presentChatColors(args.chatColors)
presentConversationTitle(viewModel.recipientSnapshot) presentConversationTitle(viewModel.recipientSnapshot)
presentGroupConversationSubtitle(createGroupSubtitleString(viewModel.titleViewParticipantsSnapshot))
presentActionBarMenu() presentActionBarMenu()
presentStoryRing() presentStoryRing()
@ -865,6 +866,10 @@ class ConversationFragment :
//endregion //endregion
private fun createGroupSubtitleString(members: List<Recipient>): String {
return members.joinToString(", ") { r -> if (r.isSelf) getString(R.string.ConversationTitleView_you) else r.getDisplayName(requireContext()) }
}
private fun observeConversationThread() { private fun observeConversationThread() {
var firstRender = true var firstRender = true
disposables += viewModel disposables += viewModel
@ -924,6 +929,12 @@ class ConversationFragment :
.distinctUntilChanged { r1, r2 -> r1 === r2 || r1.hasSameContent(r2) } .distinctUntilChanged { r1, r2 -> r1 === r2 || r1.hasSameContent(r2) }
.subscribeBy(onNext = this::onRecipientChanged) .subscribeBy(onNext = this::onRecipientChanged)
disposables += viewModel.titleViewParticipants
.map { createGroupSubtitleString(it) }
.distinctUntilChanged()
.observeOn(AndroidSchedulers.mainThread())
.subscribeBy(onNext = this::presentGroupConversationSubtitle)
disposables += viewModel.scrollButtonState disposables += viewModel.scrollButtonState
.subscribeBy(onNext = this::presentScrollButtons) .subscribeBy(onNext = this::presentScrollButtons)
@ -1315,6 +1326,17 @@ class ConversationFragment :
} }
} }
private fun presentGroupConversationSubtitle(subtitle: String) {
val titleView = binding.conversationTitleView.root
if (subtitle.isBlank()) {
titleView.setGroupRecipientSubtitle(null)
return
}
titleView.setGroupRecipientSubtitle(subtitle)
}
private fun presentConversationTitle(recipient: Recipient?) { private fun presentConversationTitle(recipient: Recipient?) {
if (recipient == null) { if (recipient == null) {
return return
@ -1323,6 +1345,7 @@ class ConversationFragment :
val titleView = binding.conversationTitleView.root val titleView = binding.conversationTitleView.root
titleView.setTitle(Glide.with(this), recipient) titleView.setTitle(Glide.with(this), recipient)
if (recipient.expiresInSeconds > 0) { if (recipient.expiresInSeconds > 0) {
titleView.showExpiring(recipient) titleView.showExpiring(recipient)
} else { } else {

View file

@ -101,6 +101,17 @@ class ConversationViewModel(
get() = scrollButtonStateStore.state.unreadCount get() = scrollButtonStateStore.state.unreadCount
val recipient: Observable<Recipient> = recipientRepository.conversationRecipient val recipient: Observable<Recipient> = recipientRepository.conversationRecipient
val titleViewParticipants: Observable<List<Recipient>> = recipient.filter { it.isGroup }.switchMap { groupRecipient ->
val firstTenIds = groupRecipient.participantIds
.take(10)
.sortedBy { it == Recipient.self().id }
Observable.combineLatest(
firstTenIds.map { Recipient.observable(it) }
) { objects ->
objects.toList() as List<Recipient>
}
}
private val _conversationThreadState: Subject<ConversationThreadState> = BehaviorSubject.create() private val _conversationThreadState: Subject<ConversationThreadState> = BehaviorSubject.create()
val conversationThreadState: Single<ConversationThreadState> = _conversationThreadState.firstOrError() val conversationThreadState: Single<ConversationThreadState> = _conversationThreadState.firstOrError()
@ -122,6 +133,10 @@ class ConversationViewModel(
var recipientSnapshot: Recipient? = null var recipientSnapshot: Recipient? = null
private set private set
@Volatile
var titleViewParticipantsSnapshot: List<Recipient> = emptyList()
private set
val isPushAvailable: Boolean val isPushAvailable: Boolean
get() = recipientSnapshot?.isRegistered == true && Recipient.self().isRegistered get() = recipientSnapshot?.isRegistered == true && Recipient.self().isRegistered
@ -167,6 +182,11 @@ class ConversationViewModel(
recipientSnapshot = it recipientSnapshot = it
} }
disposables += titleViewParticipants
.subscribeBy {
titleViewParticipantsSnapshot = it
}
val chatColorsDataObservable: Observable<ChatColorsDrawable.ChatColorsData> = Observable.combineLatest( val chatColorsDataObservable: Observable<ChatColorsDrawable.ChatColorsData> = Observable.combineLatest(
recipient.map { it.chatColors }.distinctUntilChanged(), recipient.map { it.chatColors }.distinctUntilChanged(),
chatBounds.distinctUntilChanged() chatBounds.distinctUntilChanged()