Implement story ring support.

This commit is contained in:
Alex Hart
2022-02-25 15:06:12 -04:00
parent fe088c39c7
commit 2d7655a6bb
20 changed files with 244 additions and 13 deletions

View File

@@ -266,6 +266,7 @@ class ConversationSettingsFragment : DSLSettingsFragment(
customPref(
AvatarPreference.Model(
recipient = state.recipient,
storyViewState = state.storyViewState,
onAvatarClick = { avatar ->
if (!state.recipient.isSelf) {
// startActivity(StoryViewerActivity.createIntent(requireContext(), state.recipient.id))

View File

@@ -4,6 +4,8 @@ import android.content.Context
import android.database.Cursor
import androidx.annotation.WorkerThread
import androidx.lifecycle.LiveData
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.schedulers.Schedulers
import org.signal.core.util.concurrent.SignalExecutors
import org.signal.core.util.logging.Log
import org.signal.storageservice.protos.groups.local.DecryptedGroup
@@ -13,6 +15,7 @@ import org.thoughtcrime.securesms.database.GroupDatabase
import org.thoughtcrime.securesms.database.MediaDatabase
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.database.model.IdentityRecord
import org.thoughtcrime.securesms.database.model.StoryViewState
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.groups.GroupId
import org.thoughtcrime.securesms.groups.GroupManager
@@ -44,6 +47,14 @@ class ConversationSettingsRepository(
}
}
fun getStoryViewState(groupId: GroupId): Observable<StoryViewState> {
return Observable.fromCallable {
SignalDatabase.recipients.getByGroupId(groupId)
}.flatMap {
StoryViewState.getForRecipientId(it.get())
}.observeOn(Schedulers.io())
}
fun getThreadId(recipientId: RecipientId, consumer: (Long) -> Unit) {
SignalExecutors.BOUNDED.execute {
consumer(SignalDatabase.threads.getThreadIdIfExistsFor(recipientId))

View File

@@ -4,12 +4,14 @@ import android.database.Cursor
import org.thoughtcrime.securesms.components.settings.conversation.preferences.ButtonStripPreference
import org.thoughtcrime.securesms.components.settings.conversation.preferences.LegacyGroupPreference
import org.thoughtcrime.securesms.database.model.IdentityRecord
import org.thoughtcrime.securesms.database.model.StoryViewState
import org.thoughtcrime.securesms.groups.GroupId
import org.thoughtcrime.securesms.groups.ui.GroupMemberEntry
import org.thoughtcrime.securesms.recipients.Recipient
data class ConversationSettingsState(
val threadId: Long = -1,
val storyViewState: StoryViewState = StoryViewState.NONE,
val recipient: Recipient = Recipient.UNKNOWN,
val buttonStripState: ButtonStripPreference.State = ButtonStripPreference.State(),
val disappearingMessagesLifespan: Int = 0,

View File

@@ -6,12 +6,15 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Transformations
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import org.signal.core.util.ThreadUtil
import org.signal.core.util.concurrent.SignalExecutors
import org.thoughtcrime.securesms.components.settings.conversation.preferences.ButtonStripPreference
import org.thoughtcrime.securesms.components.settings.conversation.preferences.LegacyGroupPreference
import org.thoughtcrime.securesms.database.AttachmentDatabase
import org.thoughtcrime.securesms.database.RecipientDatabase
import org.thoughtcrime.securesms.database.model.StoryViewState
import org.thoughtcrime.securesms.groups.GroupId
import org.thoughtcrime.securesms.groups.LiveGroup
import org.thoughtcrime.securesms.recipients.Recipient
@@ -46,6 +49,8 @@ sealed class ConversationSettingsViewModel(
val state: LiveData<ConversationSettingsState> = store.stateLiveData
val events: LiveData<ConversationSettingsEvent> = internalEvents
protected val disposable = CompositeDisposable()
init {
val threadId: LiveData<Long> = Transformations.distinctUntilChanged(Transformations.map(state) { it.threadId })
val updater: LiveData<Long> = LiveDataUtil.combineLatest(threadId, sharedMediaUpdateTrigger) { tId, _ -> tId }
@@ -105,6 +110,7 @@ sealed class ConversationSettingsViewModel(
cleared = true
openedMediaCursors.forEach { it.ensureClosed() }
store.clear()
disposable.clear()
}
private fun Cursor?.ensureClosed() {
@@ -126,6 +132,10 @@ sealed class ConversationSettingsViewModel(
private val liveRecipient = Recipient.live(recipientId)
init {
disposable += StoryViewState.getForRecipientId(recipientId).subscribe { storyViewState ->
store.update { it.copy(storyViewState = storyViewState) }
}
store.update(liveRecipient.liveData) { recipient, state ->
state.copy(
recipient = recipient,
@@ -240,6 +250,10 @@ sealed class ConversationSettingsViewModel(
private val liveGroup = LiveGroup(groupId)
init {
disposable += repository.getStoryViewState(groupId).subscribe { storyViewState ->
store.update { it.copy(storyViewState = storyViewState) }
}
val recipientAndIsActive = LiveDataUtil.combineLatest(liveGroup.groupRecipient, liveGroup.isActive) { r, a -> r to a }
store.update(recipientAndIsActive) { (recipient, isActive), state ->
state.copy(

View File

@@ -9,6 +9,7 @@ import org.thoughtcrime.securesms.badges.models.Badge
import org.thoughtcrime.securesms.components.settings.PreferenceModel
import org.thoughtcrime.securesms.contacts.avatars.FallbackContactPhoto
import org.thoughtcrime.securesms.contacts.avatars.FallbackPhoto
import org.thoughtcrime.securesms.database.model.StoryViewState
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.ViewUtil
import org.thoughtcrime.securesms.util.adapter.mapping.LayoutFactory
@@ -26,6 +27,7 @@ object AvatarPreference {
class Model(
val recipient: Recipient,
val storyViewState: StoryViewState,
val onAvatarClick: (View) -> Unit,
val onBadgeClick: (Badge) -> Unit
) : PreferenceModel<Model>() {
@@ -63,6 +65,7 @@ object AvatarPreference {
}
}
avatar.setStoryRingFromState(model.storyViewState)
avatar.displayChatAvatar(model.recipient)
avatar.disableQuickContact()
avatar.setOnClickListener { model.onAvatarClick(avatar) }