mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-26 03:40:56 +01:00
Story privacy screen updates.
This commit is contained in:
committed by
Cody Henthorne
parent
15e52a8b88
commit
f341e02fb7
@@ -1,6 +1,7 @@
|
||||
package org.thoughtcrime.securesms.contacts.paged
|
||||
|
||||
import org.thoughtcrime.securesms.contacts.HeaderAction
|
||||
import org.thoughtcrime.securesms.database.model.DistributionListPrivacyMode
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
|
||||
/**
|
||||
@@ -12,7 +13,7 @@ sealed class ContactSearchData(val contactSearchKey: ContactSearchKey) {
|
||||
*
|
||||
* Note that if the recipient is a group, it's participant list size is used instead of viewerCount.
|
||||
*/
|
||||
data class Story(val recipient: Recipient, val viewerCount: Int) : ContactSearchData(ContactSearchKey.RecipientSearchKey.Story(recipient.id))
|
||||
data class Story(val recipient: Recipient, val viewerCount: Int, val privacyMode: DistributionListPrivacyMode) : ContactSearchData(ContactSearchKey.RecipientSearchKey.Story(recipient.id))
|
||||
|
||||
/**
|
||||
* A row displaying a known recipient.
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.thoughtcrime.securesms.components.AvatarImageView
|
||||
import org.thoughtcrime.securesms.components.FromTextView
|
||||
import org.thoughtcrime.securesms.components.menu.ActionItem
|
||||
import org.thoughtcrime.securesms.components.menu.SignalContextMenu
|
||||
import org.thoughtcrime.securesms.database.model.DistributionListPrivacyMode
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.util.adapter.mapping.LayoutFactory
|
||||
@@ -26,6 +27,26 @@ private typealias RecipientClickListener = (View, ContactSearchData.KnownRecipie
|
||||
* Mapping Models and View Holders for ContactSearchData
|
||||
*/
|
||||
object ContactSearchItems {
|
||||
|
||||
fun registerStoryItems(
|
||||
mappingAdapter: MappingAdapter,
|
||||
displayCheckBox: Boolean = false,
|
||||
storyListener: StoryClickListener,
|
||||
storyContextMenuCallbacks: StoryContextMenuCallbacks? = null
|
||||
) {
|
||||
mappingAdapter.registerFactory(
|
||||
StoryModel::class.java,
|
||||
LayoutFactory({ StoryViewHolder(it, displayCheckBox, storyListener, storyContextMenuCallbacks) }, R.layout.contact_search_item)
|
||||
)
|
||||
}
|
||||
|
||||
fun registerHeaders(mappingAdapter: MappingAdapter) {
|
||||
mappingAdapter.registerFactory(
|
||||
HeaderModel::class.java,
|
||||
LayoutFactory({ HeaderViewHolder(it) }, R.layout.contact_search_section_header)
|
||||
)
|
||||
}
|
||||
|
||||
fun register(
|
||||
mappingAdapter: MappingAdapter,
|
||||
displayCheckBox: Boolean,
|
||||
@@ -34,18 +55,12 @@ object ContactSearchItems {
|
||||
storyContextMenuCallbacks: StoryContextMenuCallbacks,
|
||||
expandListener: (ContactSearchData.Expand) -> Unit
|
||||
) {
|
||||
mappingAdapter.registerFactory(
|
||||
StoryModel::class.java,
|
||||
LayoutFactory({ StoryViewHolder(it, displayCheckBox, storyListener, storyContextMenuCallbacks) }, R.layout.contact_search_item)
|
||||
)
|
||||
registerStoryItems(mappingAdapter, displayCheckBox, storyListener, storyContextMenuCallbacks)
|
||||
mappingAdapter.registerFactory(
|
||||
RecipientModel::class.java,
|
||||
LayoutFactory({ KnownRecipientViewHolder(it, displayCheckBox, recipientListener) }, R.layout.contact_search_item)
|
||||
)
|
||||
mappingAdapter.registerFactory(
|
||||
HeaderModel::class.java,
|
||||
LayoutFactory({ HeaderViewHolder(it) }, R.layout.contact_search_section_header)
|
||||
)
|
||||
registerHeaders(mappingAdapter)
|
||||
mappingAdapter.registerFactory(
|
||||
ExpandModel::class.java,
|
||||
LayoutFactory({ ExpandViewHolder(it, expandListener) }, R.layout.contacts_expand_item)
|
||||
@@ -92,7 +107,12 @@ object ContactSearchItems {
|
||||
}
|
||||
}
|
||||
|
||||
private class StoryViewHolder(itemView: View, displayCheckBox: Boolean, onClick: StoryClickListener, private val storyContextMenuCallbacks: StoryContextMenuCallbacks) : BaseRecipientViewHolder<StoryModel, ContactSearchData.Story>(itemView, displayCheckBox, onClick) {
|
||||
private class StoryViewHolder(
|
||||
itemView: View,
|
||||
displayCheckBox: Boolean,
|
||||
onClick: StoryClickListener,
|
||||
private val storyContextMenuCallbacks: StoryContextMenuCallbacks?
|
||||
) : BaseRecipientViewHolder<StoryModel, ContactSearchData.Story>(itemView, displayCheckBox, onClick) {
|
||||
override fun isSelected(model: StoryModel): Boolean = model.isSelected
|
||||
override fun getData(model: StoryModel): ContactSearchData.Story = model.story
|
||||
override fun getRecipient(model: StoryModel): Recipient = model.story.recipient
|
||||
@@ -109,13 +129,11 @@ object ContactSearchItems {
|
||||
if (model.story.recipient.isMyStory && !model.hasBeenNotified) {
|
||||
number.setText(R.string.ContactSearchItems__tap_to_choose_your_viewers)
|
||||
} else {
|
||||
val pluralId = when {
|
||||
model.story.recipient.isGroup -> R.plurals.ContactSearchItems__group_story_d_viewers
|
||||
model.story.recipient.isMyStory -> R.plurals.SelectViewersFragment__d_viewers
|
||||
else -> R.plurals.ContactSearchItems__private_story_d_viewers
|
||||
number.text = when {
|
||||
model.story.recipient.isGroup -> context.resources.getQuantityString(R.plurals.ContactSearchItems__group_story_d_viewers, count, count)
|
||||
model.story.recipient.isMyStory -> context.resources.getQuantityString(R.plurals.ContactSearchItems__my_story_s_dot_d_viewers, count, presentPrivacyMode(model.story.privacyMode), count)
|
||||
else -> context.resources.getQuantityString(R.plurals.ContactSearchItems__private_story_d_viewers, count, count)
|
||||
}
|
||||
|
||||
number.text = context.resources.getQuantityString(pluralId, count, count)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,11 +146,15 @@ object ContactSearchItems {
|
||||
}
|
||||
|
||||
override fun bindLongPress(model: StoryModel) {
|
||||
if (storyContextMenuCallbacks == null) {
|
||||
return
|
||||
}
|
||||
|
||||
itemView.setOnLongClickListener {
|
||||
val actions: List<ActionItem> = when {
|
||||
model.story.recipient.isMyStory -> getMyStoryContextMenuActions(model)
|
||||
model.story.recipient.isGroup -> getGroupStoryContextMenuActions(model)
|
||||
model.story.recipient.isDistributionList -> getPrivateStoryContextMenuActions(model)
|
||||
model.story.recipient.isMyStory -> getMyStoryContextMenuActions(model, storyContextMenuCallbacks)
|
||||
model.story.recipient.isGroup -> getGroupStoryContextMenuActions(model, storyContextMenuCallbacks)
|
||||
model.story.recipient.isDistributionList -> getPrivateStoryContextMenuActions(model, storyContextMenuCallbacks)
|
||||
else -> error("Unsupported story target. Not a group or distribution list.")
|
||||
}
|
||||
|
||||
@@ -144,32 +166,40 @@ object ContactSearchItems {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMyStoryContextMenuActions(model: StoryModel): List<ActionItem> {
|
||||
private fun getMyStoryContextMenuActions(model: StoryModel, callbacks: StoryContextMenuCallbacks): List<ActionItem> {
|
||||
return listOf(
|
||||
ActionItem(R.drawable.ic_settings_24, context.getString(R.string.ContactSearchItems__story_settings)) {
|
||||
storyContextMenuCallbacks.onOpenStorySettings(model.story)
|
||||
callbacks.onOpenStorySettings(model.story)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun getGroupStoryContextMenuActions(model: StoryModel): List<ActionItem> {
|
||||
private fun getGroupStoryContextMenuActions(model: StoryModel, callbacks: StoryContextMenuCallbacks): List<ActionItem> {
|
||||
return listOf(
|
||||
ActionItem(R.drawable.ic_minus_circle_20, context.getString(R.string.ContactSearchItems__remove_story)) {
|
||||
storyContextMenuCallbacks.onRemoveGroupStory(model.story, model.isSelected)
|
||||
callbacks.onRemoveGroupStory(model.story, model.isSelected)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun getPrivateStoryContextMenuActions(model: StoryModel): List<ActionItem> {
|
||||
private fun getPrivateStoryContextMenuActions(model: StoryModel, callbacks: StoryContextMenuCallbacks): List<ActionItem> {
|
||||
return listOf(
|
||||
ActionItem(R.drawable.ic_settings_24, context.getString(R.string.ContactSearchItems__story_settings)) {
|
||||
storyContextMenuCallbacks.onOpenStorySettings(model.story)
|
||||
callbacks.onOpenStorySettings(model.story)
|
||||
},
|
||||
ActionItem(R.drawable.ic_delete_24, context.getString(R.string.ContactSearchItems__delete_story), R.color.signal_colorError) {
|
||||
storyContextMenuCallbacks.onDeletePrivateStory(model.story, model.isSelected)
|
||||
callbacks.onDeletePrivateStory(model.story, model.isSelected)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun presentPrivacyMode(privacyMode: DistributionListPrivacyMode): String {
|
||||
return when (privacyMode) {
|
||||
DistributionListPrivacyMode.ONLY_WITH -> context.getString(R.string.ChooseInitialMyStoryMembershipFragment__only_share_with)
|
||||
DistributionListPrivacyMode.ALL_EXCEPT -> context.getString(R.string.ChooseInitialMyStoryMembershipFragment__all_signal_connections_except)
|
||||
DistributionListPrivacyMode.ALL -> context.getString(R.string.ChooseInitialMyStoryMembershipFragment__all_signal_connections)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.contacts.paged
|
||||
|
||||
import android.database.Cursor
|
||||
import org.signal.paging.PagedDataSource
|
||||
import org.thoughtcrime.securesms.database.model.DistributionListPrivacyMode
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.keyvalue.StorySend
|
||||
import java.util.concurrent.TimeUnit
|
||||
@@ -157,7 +158,9 @@ class ContactSearchPagedDataSource(
|
||||
endIndex = endIndex,
|
||||
cursorRowToData = {
|
||||
val recipient = contactSearchPagedDataSourceRepository.getRecipientFromDistributionListCursor(it)
|
||||
ContactSearchData.Story(recipient, contactSearchPagedDataSourceRepository.getDistributionListMembershipCount(recipient))
|
||||
val count = contactSearchPagedDataSourceRepository.getDistributionListMembershipCount(recipient)
|
||||
val privacyMode = contactSearchPagedDataSourceRepository.getPrivacyModeFromDistributionListCursor(it)
|
||||
ContactSearchData.Story(recipient, count, privacyMode)
|
||||
},
|
||||
extraData = getFilteredGroupStories(section, query)
|
||||
)
|
||||
@@ -201,7 +204,7 @@ class ContactSearchPagedDataSource(
|
||||
endIndex = endIndex,
|
||||
cursorRowToData = {
|
||||
if (section.returnAsGroupStories) {
|
||||
ContactSearchData.Story(contactSearchPagedDataSourceRepository.getRecipientFromGroupCursor(cursor), 0)
|
||||
ContactSearchData.Story(contactSearchPagedDataSourceRepository.getRecipientFromGroupCursor(cursor), 0, DistributionListPrivacyMode.ALL)
|
||||
} else {
|
||||
ContactSearchData.KnownRecipient(contactSearchPagedDataSourceRepository.getRecipientFromGroupCursor(cursor))
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.thoughtcrime.securesms.database.DistributionListDatabase
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||
import org.thoughtcrime.securesms.database.ThreadDatabase
|
||||
import org.thoughtcrime.securesms.database.model.DistributionListPrivacyMode
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.keyvalue.StorySend
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
@@ -76,6 +77,10 @@ open class ContactSearchPagedDataSourceRepository(
|
||||
return Recipient.resolved(RecipientId.from(CursorUtil.requireLong(cursor, DistributionListDatabase.RECIPIENT_ID)))
|
||||
}
|
||||
|
||||
open fun getPrivacyModeFromDistributionListCursor(cursor: Cursor): DistributionListPrivacyMode {
|
||||
return DistributionListPrivacyMode.deserialize(CursorUtil.requireLong(cursor, DistributionListDatabase.PRIVACY_MODE))
|
||||
}
|
||||
|
||||
open fun getRecipientFromThreadCursor(cursor: Cursor): Recipient {
|
||||
return Recipient.resolved(RecipientId.from(CursorUtil.requireLong(cursor, ThreadDatabase.RECIPIENT_ID)))
|
||||
}
|
||||
@@ -95,7 +100,7 @@ open class ContactSearchPagedDataSourceRepository(
|
||||
open fun getGroupStories(): Set<ContactSearchData.Story> {
|
||||
return SignalDatabase.groups.groupsToDisplayAsStories.map {
|
||||
val recipient = Recipient.resolved(SignalDatabase.recipients.getOrInsertFromGroupId(it))
|
||||
ContactSearchData.Story(recipient, recipient.participantIds.size)
|
||||
ContactSearchData.Story(recipient, recipient.participantIds.size, DistributionListPrivacyMode.ALL)
|
||||
}.toSet()
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.signal.paging.LivePagedData
|
||||
import org.signal.paging.PagedData
|
||||
import org.signal.paging.PagingConfig
|
||||
import org.signal.paging.PagingController
|
||||
import org.thoughtcrime.securesms.database.model.DistributionListPrivacyMode
|
||||
import org.thoughtcrime.securesms.groups.SelectionLimits
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.util.livedata.Store
|
||||
@@ -98,7 +99,7 @@ class ContactSearchViewModel(
|
||||
state.copy(
|
||||
groupStories = state.groupStories + groupStories.map {
|
||||
val recipient = Recipient.resolved(it.recipientId)
|
||||
ContactSearchData.Story(recipient, recipient.participantIds.size)
|
||||
ContactSearchData.Story(recipient, recipient.participantIds.size, DistributionListPrivacyMode.ALL)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user