Add viewer count and list to 'All Signal Connections'.

fork-5.53.8
Alex Hart 2022-10-07 09:40:10 -03:00 zatwierdzone przez Greyson Parrelli
rodzic c239ba1e35
commit 842626e96c
20 zmienionych plików z 408 dodań i 27 usunięć

Wyświetl plik

@ -11,6 +11,7 @@ import android.util.AttributeSet;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import org.signal.core.util.BreakIteratorCompat;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.emoji.SimpleEmojiTextView;
@ -19,6 +20,7 @@ import org.thoughtcrime.securesms.util.ContextUtil;
import org.thoughtcrime.securesms.util.SpanUtil;
import org.thoughtcrime.securesms.util.ViewUtil;
import java.util.Iterator;
import java.util.Objects;
public class FromTextView extends SimpleEmojiTextView {

Wyświetl plik

@ -52,7 +52,8 @@ class ContactSearchConfiguration private constructor(
val includeSelf: Boolean,
val transportType: TransportType,
override val includeHeader: Boolean,
override val expandConfig: ExpandConfig? = null
override val expandConfig: ExpandConfig? = null,
val includeLetterHeaders: Boolean = false
) : Section(SectionKey.INDIVIDUALS)
/**

Wyświetl plik

@ -23,7 +23,11 @@ sealed class ContactSearchData(val contactSearchKey: ContactSearchKey) {
/**
* A row displaying a known recipient.
*/
data class KnownRecipient(val recipient: Recipient, val shortSummary: Boolean = false) : ContactSearchData(ContactSearchKey.RecipientSearchKey.KnownRecipient(recipient.id))
data class KnownRecipient(
val recipient: Recipient,
val shortSummary: Boolean = false,
val headerLetter: String? = null
) : ContactSearchData(ContactSearchKey.RecipientSearchKey.KnownRecipient(recipient.id))
/**
* A row containing a title for a given section

Wyświetl plik

@ -11,6 +11,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.contacts.LetterHeaderDecoration
import org.thoughtcrime.securesms.database.model.DistributionListPrivacyMode
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.recipients.Recipient
@ -226,7 +227,10 @@ object ContactSearchItems {
}
}
private class KnownRecipientViewHolder(itemView: View, displayCheckBox: Boolean, onClick: RecipientClickListener) : BaseRecipientViewHolder<RecipientModel, ContactSearchData.KnownRecipient>(itemView, displayCheckBox, onClick) {
private class KnownRecipientViewHolder(itemView: View, displayCheckBox: Boolean, onClick: RecipientClickListener) : BaseRecipientViewHolder<RecipientModel, ContactSearchData.KnownRecipient>(itemView, displayCheckBox, onClick), LetterHeaderDecoration.LetterHeaderItem {
private var headerLetter: String? = null
override fun isSelected(model: RecipientModel): Boolean = model.isSelected
override fun getData(model: RecipientModel): ContactSearchData.KnownRecipient = model.knownRecipient
override fun getRecipient(model: RecipientModel): Recipient = model.knownRecipient.recipient
@ -235,10 +239,16 @@ object ContactSearchItems {
if (model.shortSummary && recipient.isGroup) {
val count = recipient.participantIds.size
number.setText(context.resources.getQuantityString(R.plurals.ContactSearchItems__group_d_members, count, count))
number.text = context.resources.getQuantityString(R.plurals.ContactSearchItems__group_d_members, count, count)
} else {
super.bindNumberField(model)
}
headerLetter = model.knownRecipient.headerLetter
}
override fun getHeaderLetter(): String? {
return headerLetter
}
}

Wyświetl plik

@ -11,6 +11,7 @@ import org.thoughtcrime.securesms.database.model.DistributionListPrivacyMode
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.keyvalue.StorySend
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientId
import java.util.concurrent.TimeUnit
/**
@ -129,6 +130,13 @@ class ContactSearchPagedDataSource(
}
}
private fun getNonGroupHeaderLetterMap(section: ContactSearchConfiguration.Section.Individuals, query: String?): Map<RecipientId, String> {
return when (section.transportType) {
ContactSearchConfiguration.TransportType.PUSH -> contactSearchPagedDataSourceRepository.querySignalContactLetterHeaders(query, section.includeSelf)
else -> error("This has only been implemented for push recipients.")
}
}
private fun getStoriesSearchIterator(query: String?): ContactSearchIterator<Cursor> {
return CursorSearchIterator(contactSearchPagedDataSourceRepository.getStories(query))
}
@ -193,6 +201,12 @@ class ContactSearchPagedDataSource(
}
private fun getNonGroupContactsData(section: ContactSearchConfiguration.Section.Individuals, query: String?, startIndex: Int, endIndex: Int): List<ContactSearchData> {
val headerMap: Map<RecipientId, String> = if (section.includeLetterHeaders) {
getNonGroupHeaderLetterMap(section, query)
} else {
emptyMap()
}
return getNonGroupSearchIterator(section, query).use { records ->
readContactData(
records = records,
@ -201,7 +215,8 @@ class ContactSearchPagedDataSource(
startIndex = startIndex,
endIndex = endIndex,
recordMapper = {
ContactSearchData.KnownRecipient(contactSearchPagedDataSourceRepository.getRecipientFromRecipientCursor(it))
val recipient = contactSearchPagedDataSourceRepository.getRecipientFromRecipientCursor(it)
ContactSearchData.KnownRecipient(recipient, headerLetter = headerMap[recipient.id])
}
)
}

Wyświetl plik

@ -36,6 +36,10 @@ open class ContactSearchPagedDataSourceRepository(
return contactRepository.querySignalContacts(query ?: "", includeSelf)
}
open fun querySignalContactLetterHeaders(query: String?, includeSelf: Boolean): Map<RecipientId, String> {
return SignalDatabase.recipients.querySignalContactLetterHeaders(query ?: "", includeSelf)
}
open fun queryNonSignalContacts(query: String?): Cursor? {
return contactRepository.queryNonSignalContacts(query ?: "")
}

Wyświetl plik

@ -3112,6 +3112,44 @@ open class RecipientDatabase(context: Context, databaseHelper: SignalDatabase) :
return readableDatabase.query(TABLE_NAME, SEARCH_PROJECTION, selection, args, null, null, orderBy)
}
fun querySignalContactLetterHeaders(inputQuery: String, includeSelf: Boolean): Map<RecipientId, String> {
val searchSelection = ContactSearchSelection.Builder()
.withRegistered(true)
.withGroups(false)
.excludeId(if (includeSelf) null else Recipient.self().id)
.withSearchQuery(inputQuery)
.build()
return readableDatabase.query(
"""
SELECT
_id,
UPPER(SUBSTR($SORT_NAME, 0, 2)) AS letter_header
FROM (
SELECT ${SEARCH_PROJECTION.joinToString(", ")}
FROM recipient
WHERE ${searchSelection.where}
ORDER BY $SORT_NAME, $SYSTEM_JOINED_NAME, $SEARCH_PROFILE_NAME, $PHONE
)
GROUP BY letter_header
""".trimIndent(),
searchSelection.args
).use { cursor ->
if (cursor.count == 0) {
emptyMap()
} else {
val resultsMap = mutableMapOf<RecipientId, String>()
while (cursor.moveToNext()) {
cursor.requireString("letter_header")?.let {
resultsMap[RecipientId.from(cursor.requireLong(ID))] = it
}
}
resultsMap
}
}
}
fun getNonSignalContacts(): Cursor? {
val searchSelection = ContactSearchSelection.Builder().withNonRegistered(true)
.withGroups(false)

Wyświetl plik

@ -0,0 +1,60 @@
package org.thoughtcrime.securesms.stories.settings.connections
import android.os.Bundle
import android.view.View
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.ViewBinderDelegate
import org.thoughtcrime.securesms.components.WrapperDialogFragment
import org.thoughtcrime.securesms.contacts.LetterHeaderDecoration
import org.thoughtcrime.securesms.contacts.paged.ContactSearchConfiguration
import org.thoughtcrime.securesms.contacts.paged.ContactSearchMediator
import org.thoughtcrime.securesms.databinding.ViewAllSignalConnectionsFragmentBinding
import org.thoughtcrime.securesms.groups.SelectionLimits
class ViewAllSignalConnectionsFragment : Fragment(R.layout.view_all_signal_connections_fragment) {
private val binding by ViewBinderDelegate(ViewAllSignalConnectionsFragmentBinding::bind)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
binding.recycler.addItemDecoration(LetterHeaderDecoration(requireContext()) { false })
binding.toolbar.setNavigationOnClickListener {
requireActivity().onBackPressedDispatcher.onBackPressed()
}
ContactSearchMediator(
fragment = this,
recyclerView = binding.recycler,
selectionLimits = SelectionLimits(0, 0),
displayCheckBox = false,
mapStateToConfiguration = { getConfiguration() },
performSafetyNumberChecks = false
)
}
private fun getConfiguration(): ContactSearchConfiguration {
return ContactSearchConfiguration.build {
addSection(
ContactSearchConfiguration.Section.Individuals(
includeHeader = false,
includeSelf = false,
includeLetterHeaders = true,
transportType = ContactSearchConfiguration.TransportType.PUSH
)
)
}
}
class Dialog : WrapperDialogFragment() {
override fun getWrappedFragment(): Fragment {
return ViewAllSignalConnectionsFragment()
}
companion object {
fun show(fragmentManager: FragmentManager) {
Dialog().show(fragmentManager, null)
}
}
}
}

Wyświetl plik

@ -0,0 +1,70 @@
package org.thoughtcrime.securesms.stories.settings.my
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.databinding.AllSignalConnectionsRowItemBinding
import org.thoughtcrime.securesms.util.adapter.mapping.BindingFactory
import org.thoughtcrime.securesms.util.adapter.mapping.BindingViewHolder
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.adapter.mapping.MappingModel
import org.thoughtcrime.securesms.util.visible
/**
* AllSignalConnections privacy setting row item with "View" support
*/
object AllSignalConnectionsRowItem {
private const val IS_CHECKED = 0
private const val IS_COUNT = 1
fun register(mappingAdapter: MappingAdapter) {
mappingAdapter.registerFactory(Model::class.java, BindingFactory(::ViewHolder, AllSignalConnectionsRowItemBinding::inflate))
}
class Model(
val isChecked: Boolean,
val count: Int,
val onRowClicked: () -> Unit,
val onViewClicked: () -> Unit
) : MappingModel<Model> {
override fun areItemsTheSame(newItem: Model): Boolean = true
override fun areContentsTheSame(newItem: Model): Boolean = isChecked == newItem.isChecked && count == newItem.count
override fun getChangePayload(newItem: Model): Any? {
val isCheckedDifferent = isChecked != newItem.isChecked
val isCountDifferent = count != newItem.count
return when {
isCheckedDifferent && !isCountDifferent -> IS_CHECKED
!isCheckedDifferent && isCountDifferent -> IS_COUNT
else -> null
}
}
}
private class ViewHolder(binding: AllSignalConnectionsRowItemBinding) : BindingViewHolder<Model, AllSignalConnectionsRowItemBinding>(binding) {
override fun bind(model: Model) {
binding.root.setOnClickListener { model.onRowClicked() }
binding.view.setOnClickListener { model.onViewClicked() }
when {
payload.contains(IS_COUNT) -> presentCount(model.count)
payload.contains(IS_CHECKED) -> presentSelected(model.isChecked)
else -> {
presentCount(model.count)
presentSelected(model.isChecked)
}
}
}
private fun presentCount(count: Int) {
binding.count.visible = count > 0
binding.count.text = context.resources.getQuantityString(R.plurals.MyStorySettingsFragment__viewers, count, count)
}
private fun presentSelected(isChecked: Boolean) {
binding.radio.isChecked = isChecked
}
}
}

Wyświetl plik

@ -14,6 +14,7 @@ import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
import org.thoughtcrime.securesms.components.settings.configure
import org.thoughtcrime.securesms.database.model.DistributionListPrivacyMode
import org.thoughtcrime.securesms.stories.settings.connections.ViewAllSignalConnectionsFragment
import org.thoughtcrime.securesms.util.LifecycleDisposable
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.navigation.safeNavigate
@ -38,6 +39,7 @@ class MyStorySettingsFragment : DSLSettingsFragment(
}
override fun bindAdapter(adapter: MappingAdapter) {
AllSignalConnectionsRowItem.register(adapter)
viewModel.state.observe(viewLifecycleOwner) { state ->
adapter.submitList(getConfiguration(state).toMappingModelList())
}
@ -47,14 +49,18 @@ class MyStorySettingsFragment : DSLSettingsFragment(
return configure {
sectionHeaderPref(R.string.MyStorySettingsFragment__who_can_view_this_story)
radioPref(
title = DSLSettingsText.from(R.string.MyStorySettingsFragment__all_signal_connections),
summary = DSLSettingsText.from(R.string.MyStorySettingsFragment__share_with_all_connections),
isChecked = state.myStoryPrivacyState.privacyMode == DistributionListPrivacyMode.ALL,
onClick = {
lifecycleDisposable += viewModel.setMyStoryPrivacyMode(DistributionListPrivacyMode.ALL)
.subscribe()
}
customPref(
AllSignalConnectionsRowItem.Model(
isChecked = state.myStoryPrivacyState.privacyMode == DistributionListPrivacyMode.ALL,
count = state.allSignalConnectionsCount,
onRowClicked = {
lifecycleDisposable += viewModel.setMyStoryPrivacyMode(DistributionListPrivacyMode.ALL)
.subscribe()
},
onViewClicked = {
ViewAllSignalConnectionsFragment.Dialog.show(parentFragmentManager)
}
)
)
val exceptText = if (state.myStoryPrivacyState.privacyMode == DistributionListPrivacyMode.ALL_EXCEPT) {

Wyświetl plik

@ -22,11 +22,15 @@ class MyStorySettingsRepository {
}
fun observeChooseInitialPrivacy(): Observable<ChooseInitialMyStoryMembershipState> {
return Single.fromCallable { SignalDatabase.distributionLists.getRecipientId(DistributionListId.MY_STORY)!! }
return Single
.fromCallable { SignalDatabase.distributionLists.getRecipientId(DistributionListId.MY_STORY)!! }
.subscribeOn(Schedulers.io())
.flatMapObservable { recipientId ->
Recipient.observable(recipientId)
val allSignalConnectionsCount = getAllSignalConnectionsCount().toObservable()
val stateWithoutCount = Recipient.observable(recipientId)
.flatMap { Observable.just(ChooseInitialMyStoryMembershipState(recipientId = recipientId, privacyState = getStoryPrivacyState())) }
Observable.combineLatest(allSignalConnectionsCount, stateWithoutCount) { count, state -> state.copy(allSignalConnectionsCount = count) }
}
}
@ -50,6 +54,12 @@ class MyStorySettingsRepository {
}.subscribeOn(Schedulers.io())
}
fun getAllSignalConnectionsCount(): Single<Int> {
return Single.fromCallable {
SignalDatabase.recipients.getSignalContactsCount(false)
}.subscribeOn(Schedulers.io())
}
@WorkerThread
private fun getStoryPrivacyState(): MyStoryPrivacyState {
val privacyData: DistributionListPrivacyData = SignalDatabase.distributionLists.getPrivacyData(DistributionListId.MY_STORY)

Wyświetl plik

@ -2,5 +2,6 @@ package org.thoughtcrime.securesms.stories.settings.my
data class MyStorySettingsState(
val myStoryPrivacyState: MyStoryPrivacyState = MyStoryPrivacyState(),
val areRepliesAndReactionsEnabled: Boolean = false
val areRepliesAndReactionsEnabled: Boolean = false,
val allSignalConnectionsCount: Int = 0
)

Wyświetl plik

@ -25,6 +25,8 @@ class MyStorySettingsViewModel @JvmOverloads constructor(private val repository:
.subscribe { myStoryPrivacyState -> store.update { it.copy(myStoryPrivacyState = myStoryPrivacyState) } }
disposables += repository.getRepliesAndReactionsEnabled()
.subscribe { repliesAndReactionsEnabled -> store.update { it.copy(areRepliesAndReactionsEnabled = repliesAndReactionsEnabled) } }
disposables += repository.getAllSignalConnectionsCount()
.subscribe { allSignalConnectionsCount -> store.update { it.copy(allSignalConnectionsCount = allSignalConnectionsCount) } }
}
fun setRepliesAndReactionsEnabled(repliesAndReactionsEnabled: Boolean) {

Wyświetl plik

@ -14,6 +14,7 @@ import org.thoughtcrime.securesms.components.FixedRoundedCornerBottomSheetDialog
import org.thoughtcrime.securesms.components.WrapperDialogFragment
import org.thoughtcrime.securesms.database.model.DistributionListPrivacyMode
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.stories.settings.connections.ViewAllSignalConnectionsFragment
import org.thoughtcrime.securesms.stories.settings.select.BaseStoryRecipientSelectionFragment
import org.thoughtcrime.securesms.util.BottomSheetUtil
import org.thoughtcrime.securesms.util.LifecycleDisposable
@ -42,9 +43,12 @@ class ChooseInitialMyStoryMembershipBottomSheetDialogFragment :
private lateinit var allExceptRadio: MaterialRadioButton
private lateinit var onlyWitRadio: MaterialRadioButton
private lateinit var allCount: TextView
private lateinit var allExceptCount: TextView
private lateinit var onlyWithCount: TextView
private lateinit var allView: View
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.choose_initial_my_story_membership_fragment, container, false)
}
@ -58,9 +62,15 @@ class ChooseInitialMyStoryMembershipBottomSheetDialogFragment :
allExceptRadio = view.findViewById(R.id.choose_initial_my_story_all_signal_connnections_except_radio)
onlyWitRadio = view.findViewById(R.id.choose_initial_my_story_only_share_with_radio)
allCount = view.findViewById(R.id.choose_initial_my_story_all_signal_connnections_count)
allExceptCount = view.findViewById(R.id.choose_initial_my_story_all_signal_connnections_except_count)
onlyWithCount = view.findViewById(R.id.choose_initial_my_story_only_share_with_count)
allView = view.findViewById(R.id.choose_initial_my_story_all_signal_connnections_view)
allView.setOnClickListener {
ViewAllSignalConnectionsFragment.Dialog.show(parentFragmentManager)
}
val save = view.findViewById<View>(R.id.choose_initial_my_story_save).apply {
isEnabled = false
}
@ -76,6 +86,9 @@ class ChooseInitialMyStoryMembershipBottomSheetDialogFragment :
allExceptCount.visible = allExceptRadio.isChecked
onlyWithCount.visible = onlyWitRadio.isChecked
allCount.visible = state.allSignalConnectionsCount > 0
allCount.text = resources.getQuantityString(R.plurals.MyStorySettingsFragment__viewers, state.allSignalConnectionsCount, state.allSignalConnectionsCount)
when (state.privacyState.privacyMode) {
DistributionListPrivacyMode.ALL_EXCEPT -> allExceptCount.text = resources.getQuantityString(R.plurals.MyStorySettingsFragment__d_people_excluded, state.privacyState.connectionCount, state.privacyState.connectionCount)
DistributionListPrivacyMode.ONLY_WITH -> onlyWithCount.text = resources.getQuantityString(R.plurals.MyStorySettingsFragment__d_people, state.privacyState.connectionCount, state.privacyState.connectionCount)

Wyświetl plik

@ -3,4 +3,8 @@ package org.thoughtcrime.securesms.stories.settings.privacy
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.stories.settings.my.MyStoryPrivacyState
data class ChooseInitialMyStoryMembershipState(val recipientId: RecipientId? = null, val privacyState: MyStoryPrivacyState = MyStoryPrivacyState())
data class ChooseInitialMyStoryMembershipState(
val recipientId: RecipientId? = null,
val privacyState: MyStoryPrivacyState = MyStoryPrivacyState(),
val allSignalConnectionsCount: Int = 0
)

Wyświetl plik

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/row"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:background="?selectableItemBackground"
android:gravity="center_vertical"
android:minHeight="56dp"
android:orientation="horizontal"
android:paddingStart="@dimen/dsl_settings_gutter">
<RadioButton
android:id="@+id/radio"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:theme="@style/Signal.Widget.CompoundButton.RadioButton"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/message"
style="@style/Signal.Text.BodyLarge"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:text="@string/ChooseInitialMyStoryMembershipFragment__all_signal_connections"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toTopOf="@+id/count"
app:layout_constraintEnd_toStartOf="@id/view"
app:layout_constraintStart_toEndOf="@id/radio"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />
<TextView
android:id="@+id/count"
style="@style/Signal.Text.BodyMedium"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textColor="@color/signal_colorOnSurfaceVariant"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/message"
app:layout_constraintStart_toStartOf="@+id/message"
app:layout_constraintTop_toBottomOf="@+id/message"
tools:text="Asdf"
tools:visibility="visible" />
<com.google.android.material.button.MaterialButton
android:id="@+id/view"
style="@style/Widget.Signal.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/MyStorySettingsFragment__view"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

Wyświetl plik

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:viewBindingIgnore="true"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
tools:viewBindingIgnore="true">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
@ -41,7 +41,7 @@
android:text="@string/ChooseInitialMyStoryMembershipFragment__choose_who_can_see_posts_to_my_story_you_can_always_make_changes_in_settings"
android:textColor="@color/signal_colorOnSurfaceVariant" />
<androidx.appcompat.widget.LinearLayoutCompat
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/choose_initial_my_story_all_signal_connnections_row"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -50,22 +50,56 @@
android:gravity="center_vertical"
android:minHeight="56dp"
android:orientation="horizontal"
android:paddingHorizontal="24dp">
android:paddingStart="@dimen/dsl_settings_gutter">
<com.google.android.material.radiobutton.MaterialRadioButton
android:id="@+id/choose_initial_my_story_all_signal_connnections_radio"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false" />
android:clickable="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/choose_initial_my_story_all_signal_connnections_message"
style="@style/Signal.Text.BodyLarge"
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:text="@string/ChooseInitialMyStoryMembershipFragment__all_signal_connections" />
android:text="@string/ChooseInitialMyStoryMembershipFragment__all_signal_connections"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toTopOf="@+id/choose_initial_my_story_all_signal_connnections_count"
app:layout_constraintEnd_toStartOf="@id/choose_initial_my_story_all_signal_connnections_view"
app:layout_constraintStart_toEndOf="@id/choose_initial_my_story_all_signal_connnections_radio"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />
</androidx.appcompat.widget.LinearLayoutCompat>
<TextView
android:id="@+id/choose_initial_my_story_all_signal_connnections_count"
style="@style/Signal.Text.BodyMedium"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textColor="@color/signal_colorOnSurfaceVariant"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/choose_initial_my_story_all_signal_connnections_message"
app:layout_constraintStart_toStartOf="@+id/choose_initial_my_story_all_signal_connnections_message"
app:layout_constraintTop_toBottomOf="@+id/choose_initial_my_story_all_signal_connnections_message"
tools:text="Asdf"
tools:visibility="visible" />
<com.google.android.material.button.MaterialButton
android:id="@+id/choose_initial_my_story_all_signal_connnections_view"
style="@style/Widget.Signal.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/MyStorySettingsFragment__view"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/choose_initial_my_story_all_signal_connnections_except_row"
@ -97,7 +131,8 @@
app:layout_constraintBottom_toTopOf="@+id/choose_initial_my_story_all_signal_connnections_except_count"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/choose_initial_my_story_all_signal_connnections_except_radio"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />
<TextView
android:id="@+id/choose_initial_my_story_all_signal_connnections_except_count"
@ -145,7 +180,8 @@
app:layout_constraintBottom_toTopOf="@+id/choose_initial_my_story_only_share_with_count"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/choose_initial_my_story_only_share_with_radio"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />
<TextView
android:id="@+id/choose_initial_my_story_only_share_with_count"

Wyświetl plik

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<org.thoughtcrime.securesms.util.views.DarkOverflowToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="@dimen/signal_m3_toolbar_height"
android:background="@null"
android:minHeight="@dimen/signal_m3_toolbar_height"
android:theme="?attr/settingsToolbarStyle"
app:navigationContentDescription="@string/DSLSettingsToolbar__navigate_up"
app:navigationIcon="@drawable/ic_arrow_left_24"
app:title="@string/MyStorySettingsFragment__all_signal_connections"
app:titleTextAppearance="@style/Signal.Text.TitleLarge" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/stories_recipient_item" />
</LinearLayout>

Wyświetl plik

@ -4849,6 +4849,13 @@
<string name="StoryGroupReplyItem__delete">Delete</string>
<!-- Page title for My Story options -->
<string name="MyStorySettingsFragment__my_story">My Story</string>
<!-- Number of total signal connections displayed in "All connections" row item -->
<plurals name="MyStorySettingsFragment__viewers">
<item quantity="one">%1$d viewer</item>
<item quantity="other">%1$d viewers</item>
</plurals>
<!-- Button on all signal connections row to view all signal connections. Please keep as short as possible. -->
<string name="MyStorySettingsFragment__view">View</string>
<!-- Section heading for story visibility -->
<string name="MyStorySettingsFragment__who_can_view_this_story">Who can view this story</string>
<!-- Clickable option for selecting people to hide your story from -->

Wyświetl plik

@ -17,6 +17,11 @@
</style>
<style name="Widget.Signal.Button.TextButton" parent="Widget.Material3.Button.TextButton">
<item name="materialThemeOverlay">@style/ThemeOverlay.Signal.Button.TextButton</item>
</style>
<style name="ThemeOverlay.Signal.Button.TextButton" parent="ThemeOverlay.Material3.Button.TextButton">
<item name="colorOnContainer">@color/signal_colorPrimary</item>
</style>
<style name="NoAnimation.Theme.BlackScreen" parent="Theme.AppCompat.NoActionBar">