Story privacy screen updates.

fork-5.53.8
Alex Hart 2022-08-18 10:11:42 -03:00 zatwierdzone przez Cody Henthorne
rodzic 15e52a8b88
commit f341e02fb7
74 zmienionych plików z 800 dodań i 423 usunięć

Wyświetl plik

@ -18,7 +18,6 @@ import org.thoughtcrime.securesms.components.InputAwareLayout
import org.thoughtcrime.securesms.components.emoji.EmojiEventListener
import org.thoughtcrime.securesms.components.emoji.MediaKeyboard
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
import org.thoughtcrime.securesms.components.settings.app.subscription.DonationEvent
@ -36,6 +35,7 @@ import org.thoughtcrime.securesms.keyboard.emoji.EmojiKeyboardPageFragment
import org.thoughtcrime.securesms.keyboard.emoji.search.EmojiSearchFragment
import org.thoughtcrime.securesms.util.Debouncer
import org.thoughtcrime.securesms.util.LifecycleDisposable
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.fragments.requireListener
/**
@ -75,7 +75,7 @@ class GiftFlowConfirmationFragment :
private val eventPublisher = PublishSubject.create<TextInput.TextInputEvent>()
private val debouncer = Debouncer(100L)
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
RecipientPreference.register(adapter)
GiftRowItem.register(adapter)

Wyświetl plik

@ -7,7 +7,6 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import org.signal.core.util.DimensionUnit
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
import org.thoughtcrime.securesms.components.settings.app.subscription.DonationPaymentComponent
@ -18,6 +17,7 @@ import org.thoughtcrime.securesms.components.settings.models.IndeterminateLoadin
import org.thoughtcrime.securesms.components.settings.models.SplashImage
import org.thoughtcrime.securesms.util.LifecycleDisposable
import org.thoughtcrime.securesms.util.ViewUtil
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.fragments.requireListener
import org.thoughtcrime.securesms.util.navigation.safeNavigate
@ -35,7 +35,7 @@ class GiftFlowStartFragment : DSLSettingsFragment(
private val lifecycleDisposable = LifecycleDisposable()
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
CurrencySelection.register(adapter)
GiftRowItem.register(adapter)
NetworkFailure.register(adapter)

Wyświetl plik

@ -13,11 +13,11 @@ import org.thoughtcrime.securesms.badges.Badges.displayBadges
import org.thoughtcrime.securesms.badges.models.Badge
import org.thoughtcrime.securesms.badges.models.BadgePreview
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.configure
import org.thoughtcrime.securesms.util.LifecycleDisposable
import org.thoughtcrime.securesms.util.Material3OnScrollHelper
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
/**
* Fragment which allows user to select one of their badges to be their "Featured" badge.
@ -50,7 +50,7 @@ class SelectFeaturedBadgeFragment : DSLSettingsFragment(
return Material3OnScrollHelper(requireActivity(), scrollShadow)
}
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
Badge.register(adapter) { badge, isSelected, _ ->
if (!isSelected) {
viewModel.setSelectedBadge(badge)

Wyświetl plik

@ -10,7 +10,6 @@ import org.thoughtcrime.securesms.badges.Badges.displayBadges
import org.thoughtcrime.securesms.badges.models.Badge
import org.thoughtcrime.securesms.badges.view.ViewBadgeBottomSheetDialogFragment
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
import org.thoughtcrime.securesms.components.settings.app.subscription.SubscriptionsRepository
@ -18,6 +17,7 @@ import org.thoughtcrime.securesms.components.settings.configure
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.LifecycleDisposable
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.navigation.safeNavigate
/**
@ -35,7 +35,7 @@ class BadgesOverviewFragment : DSLSettingsFragment(
}
)
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
Badge.register(adapter) { badge, _, isFaded ->
if (badge.isExpired() || isFaded) {
findNavController().safeNavigate(BadgesOverviewFragmentDirections.actionBadgeManageFragmentToExpiredBadgeDialog(badge, null, null))

Wyświetl plik

@ -12,10 +12,13 @@ import androidx.annotation.StringRes
import androidx.appcompat.widget.Toolbar
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.ConcatAdapter
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.util.Material3OnScrollHelper
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import java.lang.UnsupportedOperationException
abstract class DSLSettingsFragment(
@StringRes private val titleId: Int = -1,
@ -27,9 +30,11 @@ abstract class DSLSettingsFragment(
protected var recyclerView: RecyclerView? = null
private set
private var toolbar: Toolbar? = null
@CallSuper
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val toolbar: Toolbar? = view.findViewById(R.id.toolbar)
toolbar = view.findViewById(R.id.toolbar)
if (titleId != -1) {
toolbar?.setTitle(titleId)
@ -44,7 +49,13 @@ abstract class DSLSettingsFragment(
toolbar?.setOnMenuItemClickListener { onOptionsItemSelected(it) }
}
val settingsAdapter = DSLSettingsAdapter()
val config = ConcatAdapter.Config.Builder().setIsolateViewTypes(false).build()
val settingsAdapters = createAdapters()
val settingsAdapter: RecyclerView.Adapter<out RecyclerView.ViewHolder> = when {
settingsAdapters.size > 1 -> ConcatAdapter(config, *settingsAdapters)
settingsAdapters.size == 1 -> settingsAdapters.first()
else -> error("Require one or more settings adapters.")
}
recyclerView = view.findViewById<RecyclerView>(R.id.recycler).apply {
edgeEffectFactory = EdgeEffectFactory()
@ -56,7 +67,11 @@ abstract class DSLSettingsFragment(
}
}
bindAdapter(settingsAdapter)
when (settingsAdapter) {
is ConcatAdapter -> bindAdapters(settingsAdapter)
is MappingAdapter -> bindAdapter(settingsAdapter)
else -> error("Illegal adapter subtype: ${settingsAdapter.javaClass.simpleName}")
}
}
open fun getMaterial3OnScrollHelper(toolbar: Toolbar?): Material3OnScrollHelper? {
@ -76,7 +91,25 @@ abstract class DSLSettingsFragment(
recyclerView = null
}
abstract fun bindAdapter(adapter: DSLSettingsAdapter)
fun setTitle(@StringRes resId: Int) {
toolbar?.setTitle(resId)
}
fun setTitle(title: CharSequence) {
toolbar?.title = title
}
open fun createAdapters(): Array<MappingAdapter> {
return arrayOf(DSLSettingsAdapter())
}
open fun bindAdapter(adapter: MappingAdapter) {
throw UnsupportedOperationException("This method is not implemented.")
}
open fun bindAdapters(adapter: ConcatAdapter) {
throw UnsupportedOperationException("This method is not implemented.")
}
private class EdgeEffectFactory : RecyclerView.EdgeEffectFactory() {
override fun createEdgeEffect(view: RecyclerView, direction: Int): EdgeEffect {

Wyświetl plik

@ -9,7 +9,6 @@ import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.badges.BadgeImageView
import org.thoughtcrime.securesms.components.AvatarImageView
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.DSLSettingsIcon
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
@ -23,6 +22,7 @@ import org.thoughtcrime.securesms.util.FeatureFlags
import org.thoughtcrime.securesms.util.PlayServicesUtil
import org.thoughtcrime.securesms.util.Util
import org.thoughtcrime.securesms.util.adapter.mapping.LayoutFactory
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.adapter.mapping.MappingViewHolder
import org.thoughtcrime.securesms.util.navigation.safeNavigate
@ -30,7 +30,7 @@ class AppSettingsFragment : DSLSettingsFragment(R.string.text_secure_normal__men
private val viewModel: AppSettingsViewModel by viewModels()
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
adapter.registerFactory(BioPreference::class.java, LayoutFactory(::BioPreferenceViewHolder, R.layout.bio_preference_item))
adapter.registerFactory(PaymentsPreference::class.java, LayoutFactory(::PaymentsPreferenceViewHolder, R.layout.dsl_payments_preference))
adapter.registerFactory(SubscriptionPreference::class.java, LayoutFactory(::SubscriptionPreferenceViewHolder, R.layout.dsl_preference_item))

Wyświetl plik

@ -20,7 +20,6 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
import org.thoughtcrime.securesms.components.settings.configure
@ -33,6 +32,7 @@ import org.thoughtcrime.securesms.lock.v2.PinKeyboardType
import org.thoughtcrime.securesms.pin.RegistrationLockV2Dialog
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.ViewUtil
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.navigation.safeNavigate
class AccountSettingsFragment : DSLSettingsFragment(R.string.AccountSettingsFragment__account) {
@ -50,7 +50,7 @@ class AccountSettingsFragment : DSLSettingsFragment(R.string.AccountSettingsFrag
viewModel.refreshState()
}
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
viewModel = ViewModelProvider(this)[AccountSettingsViewModel::class.java]
viewModel.state.observe(viewLifecycleOwner) { state ->

Wyświetl plik

@ -4,11 +4,11 @@ import androidx.lifecycle.ViewModelProvider
import androidx.navigation.Navigation
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
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.keyvalue.SettingsValues
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.navigation.safeNavigate
class AppearanceSettingsFragment : DSLSettingsFragment(R.string.preferences__appearance) {
@ -24,7 +24,7 @@ class AppearanceSettingsFragment : DSLSettingsFragment(R.string.preferences__app
private val languageLabels by lazy { resources.getStringArray(R.array.language_entries) }
private val languageValues by lazy { resources.getStringArray(R.array.language_values) }
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
viewModel = ViewModelProvider(this)[AppearanceSettingsViewModel::class.java]
viewModel.state.observe(viewLifecycleOwner) { state ->

Wyświetl plik

@ -4,10 +4,10 @@ import androidx.lifecycle.ViewModelProvider
import androidx.navigation.Navigation
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
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.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.navigation.safeNavigate
class ChatsSettingsFragment : DSLSettingsFragment(R.string.preferences_chats__chats) {
@ -19,7 +19,7 @@ class ChatsSettingsFragment : DSLSettingsFragment(R.string.preferences_chats__ch
viewModel.refresh()
}
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
val repository = ChatsSettingsRepository()
val factory = ChatsSettingsViewModel.Factory(repository)
viewModel = ViewModelProvider(this, factory)[ChatsSettingsViewModel::class.java]

Wyświetl plik

@ -8,13 +8,13 @@ import androidx.lifecycle.ViewModelProvider
import androidx.navigation.Navigation
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
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.keyvalue.SignalStore
import org.thoughtcrime.securesms.util.SmsUtil
import org.thoughtcrime.securesms.util.Util
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.navigation.safeNavigate
private const val SMS_REQUEST_CODE: Short = 1234
@ -28,7 +28,7 @@ class SmsSettingsFragment : DSLSettingsFragment(R.string.preferences__sms_mms) {
viewModel.checkSmsEnabled()
}
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
viewModel = ViewModelProvider(this)[SmsSettingsViewModel::class.java]
viewModel.state.observe(viewLifecycleOwner) {

Wyświetl plik

@ -5,12 +5,12 @@ import androidx.navigation.Navigation
import androidx.preference.PreferenceManager
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
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.mms.SentMediaQuality
import org.thoughtcrime.securesms.util.Util
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.navigation.safeNavigate
import org.thoughtcrime.securesms.webrtc.CallBandwidthMode
import kotlin.math.abs
@ -31,7 +31,7 @@ class DataAndStorageSettingsFragment : DSLSettingsFragment(R.string.preferences_
viewModel.refresh()
}
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
val repository = DataAndStorageSettingsRepository()
val factory = DataAndStorageSettingsViewModel.Factory(preferences, repository)

Wyświetl plik

@ -4,15 +4,15 @@ import androidx.navigation.Navigation
import org.thoughtcrime.securesms.BuildConfig
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
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.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.navigation.safeNavigate
class HelpSettingsFragment : DSLSettingsFragment(R.string.preferences__help) {
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
adapter.submitList(getConfiguration().toMappingModelList())
}

Wyświetl plik

@ -15,7 +15,6 @@ import org.signal.ringrtc.CallManager
import org.thoughtcrime.securesms.BuildConfig
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
import org.thoughtcrime.securesms.components.settings.configure
@ -42,6 +41,7 @@ import org.thoughtcrime.securesms.payments.DataExportUtil
import org.thoughtcrime.securesms.storage.StorageSyncHelper
import org.thoughtcrime.securesms.util.ConversationUtil
import org.thoughtcrime.securesms.util.FeatureFlags
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.navigation.safeNavigate
import java.util.Optional
import java.util.concurrent.TimeUnit
@ -51,7 +51,7 @@ class InternalSettingsFragment : DSLSettingsFragment(R.string.preferences__inter
private lateinit var viewModel: InternalSettingsViewModel
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
val repository = InternalSettingsRepository(requireContext())
val factory = InternalSettingsViewModel.Factory(repository)
viewModel = ViewModelProvider(this, factory)[InternalSettingsViewModel::class.java]

Wyświetl plik

@ -5,19 +5,19 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import org.signal.donations.StripeDeclineCode
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
import org.thoughtcrime.securesms.components.settings.app.subscription.errors.UnexpectedSubscriptionCancellation
import org.thoughtcrime.securesms.components.settings.configure
import org.thoughtcrime.securesms.util.LifecycleDisposable
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
class DonorErrorConfigurationFragment : DSLSettingsFragment() {
private val viewModel: DonorErrorConfigurationViewModel by viewModels()
private val lifecycleDisposable = LifecycleDisposable()
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
lifecycleDisposable += viewModel.state.observeOn(AndroidSchedulers.mainThread()).subscribe { state ->
adapter.submitList(getConfiguration(state).toMappingModelList())
}

Wyświetl plik

@ -22,7 +22,6 @@ import androidx.preference.PreferenceManager
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
import org.thoughtcrime.securesms.components.settings.PreferenceModel
@ -35,6 +34,7 @@ import org.thoughtcrime.securesms.notifications.NotificationChannels
import org.thoughtcrime.securesms.util.RingtoneUtil
import org.thoughtcrime.securesms.util.ViewUtil
import org.thoughtcrime.securesms.util.adapter.mapping.LayoutFactory
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.navigation.safeNavigate
private const val MESSAGE_SOUND_SELECT: Int = 1
@ -70,7 +70,7 @@ class NotificationsSettingsFragment : DSLSettingsFragment(R.string.preferences__
}
}
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
adapter.registerFactory(
LedColorPreference::class.java,
LayoutFactory(::LedColorPreferenceViewHolder, R.layout.dsl_preference_item)

Wyświetl plik

@ -8,7 +8,6 @@ import com.google.android.material.snackbar.Snackbar
import io.reactivex.rxjava3.kotlin.subscribeBy
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.app.notifications.profiles.models.NotificationProfileAddMembers
import org.thoughtcrime.securesms.components.settings.app.notifications.profiles.models.NotificationProfileRecipient
@ -18,6 +17,7 @@ import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.util.LifecycleDisposable
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.navigation.safeNavigate
import org.thoughtcrime.securesms.util.views.CircularProgressMaterialButton
@ -42,7 +42,7 @@ class AddAllowedMembersFragment : DSLSettingsFragment(layoutId = R.layout.fragme
}
}
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
NotificationProfileAddMembers.register(adapter)
NotificationProfileRecipient.register(adapter)

Wyświetl plik

@ -17,7 +17,6 @@ import org.signal.core.util.BreakIteratorCompat
import org.signal.core.util.EditTextUtil
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.emoji.EmojiUtil
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.app.notifications.profiles.EditNotificationProfileViewModel.SaveNotificationProfileResult
import org.thoughtcrime.securesms.components.settings.app.notifications.profiles.models.NotificationProfileNamePreset
@ -25,6 +24,7 @@ import org.thoughtcrime.securesms.reactions.any.ReactWithAnyEmojiBottomSheetDial
import org.thoughtcrime.securesms.util.BottomSheetUtil
import org.thoughtcrime.securesms.util.LifecycleDisposable
import org.thoughtcrime.securesms.util.ViewUtil
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.navigation.safeNavigate
import org.thoughtcrime.securesms.util.text.AfterTextChanged
import org.thoughtcrime.securesms.util.views.CircularProgressMaterialButton
@ -131,7 +131,7 @@ class EditNotificationProfileFragment : DSLSettingsFragment(layoutId = R.layout.
this.emojiView = emojiView
}
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
NotificationProfileNamePreset.register(adapter)
val onClick = { preset: NotificationProfileNamePreset.Model ->

Wyświetl plik

@ -13,7 +13,6 @@ import io.reactivex.rxjava3.kotlin.subscribeBy
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.emoji.EmojiUtil
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.DSLSettingsIcon
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
@ -31,6 +30,7 @@ import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.util.LifecycleDisposable
import org.thoughtcrime.securesms.util.SpanUtil
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.formatHours
import org.thoughtcrime.securesms.util.navigation.safeNavigate
import org.thoughtcrime.securesms.util.orderOfDaysInWeek
@ -65,7 +65,7 @@ class NotificationProfileDetailsFragment : DSLSettingsFragment() {
toolbar = null
}
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
NotificationProfilePreference.register(adapter)
NotificationProfileAddMembers.register(adapter)
NotificationProfileRecipient.register(adapter)

Wyświetl plik

@ -8,7 +8,6 @@ import androidx.navigation.fragment.findNavController
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.emoji.EmojiUtil
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.DSLSettingsIcon
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
@ -20,6 +19,7 @@ import org.thoughtcrime.securesms.components.settings.conversation.preferences.L
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile
import org.thoughtcrime.securesms.notifications.profiles.NotificationProfiles
import org.thoughtcrime.securesms.util.LifecycleDisposable
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.navigation.safeNavigate
/**
@ -48,7 +48,7 @@ class NotificationProfilesFragment : DSLSettingsFragment() {
toolbar = null
}
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
NoNotificationProfiles.register(adapter)
LargeIconClickPreference.register(adapter)
NotificationProfilePreference.register(adapter)

Wyświetl plik

@ -20,14 +20,12 @@ import androidx.preference.PreferenceManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import mobi.upod.timedurationpicker.TimeDurationPicker
import mobi.upod.timedurationpicker.TimeDurationPickerDialog
import org.signal.core.util.DimensionUnit
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.PassphraseChangeActivity
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.ClickPreference
import org.thoughtcrime.securesms.components.settings.ClickPreferenceViewHolder
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
import org.thoughtcrime.securesms.components.settings.PreferenceModel
@ -36,12 +34,8 @@ import org.thoughtcrime.securesms.components.settings.configure
import org.thoughtcrime.securesms.crypto.MasterSecretUtil
import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues
import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues.PhoneNumberListingMode
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.service.KeyCachingService
import org.thoughtcrime.securesms.stories.Stories
import org.thoughtcrime.securesms.stories.settings.custom.PrivateStorySettingsFragmentArgs
import org.thoughtcrime.securesms.stories.settings.story.PrivateStoryItem
import org.thoughtcrime.securesms.util.CommunicationActions
import org.thoughtcrime.securesms.util.ConversationUtil
import org.thoughtcrime.securesms.util.ExpirationUtil
@ -50,6 +44,7 @@ import org.thoughtcrime.securesms.util.ServiceUtil
import org.thoughtcrime.securesms.util.SpanUtil
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.adapter.mapping.LayoutFactory
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.navigation.safeNavigate
import java.lang.Integer.max
import java.util.Locale
@ -76,9 +71,8 @@ class PrivacySettingsFragment : DSLSettingsFragment(R.string.preferences__privac
viewModel.refreshBlockedCount()
}
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
adapter.registerFactory(ValueClickPreference::class.java, LayoutFactory(::ValueClickPreferenceViewHolder, R.layout.value_click_preference_item))
PrivateStoryItem.register(adapter)
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
val repository = PrivacySettingsRepository()
@ -297,50 +291,13 @@ class PrivacySettingsFragment : DSLSettingsFragment(R.string.preferences__privac
)
if (Stories.isFeatureAvailable()) {
dividerPref()
sectionHeaderPref(R.string.ConversationListTabs__stories)
if (!SignalStore.storyValues().isFeatureDisabled) {
customPref(
PrivateStoryItem.RecipientModel(
recipient = Recipient.self(),
onClick = { findNavController().safeNavigate(R.id.action_privacySettings_to_myStorySettings) }
)
)
space(DimensionUnit.DP.toPixels(24f).toInt())
customPref(
PrivateStoryItem.NewModel(
onClick = {
findNavController().safeNavigate(R.id.action_privacySettings_to_newPrivateStory)
}
)
)
state.privateStories.forEach {
customPref(
PrivateStoryItem.PartialModel(
privateStoryItemData = it,
onClick = { model ->
findNavController().safeNavigate(
R.id.action_privacySettings_to_privateStorySettings,
PrivateStorySettingsFragmentArgs.Builder(model.privateStoryItemData.id).build().toBundle()
)
}
)
)
}
}
switchPref(
title = DSLSettingsText.from(R.string.PrivacySettingsFragment__share_and_view_stories),
summary = DSLSettingsText.from(R.string.PrivacySettingsFragment__you_will_no_longer_be_able),
isChecked = state.isStoriesEnabled,
clickPref(
title = DSLSettingsText.from(R.string.preferences__stories),
summary = DSLSettingsText.from(R.string.PrivacySettingsFragment__manage_your_stories),
onClick = {
viewModel.setStoriesEnabled(!state.isStoriesEnabled)
findNavController().safeNavigate(PrivacySettingsFragmentDirections.actionPrivacySettingsFragmentToStoryPrivacySettings(R.string.preferences__stories))
}
)
}

Wyświetl plik

@ -3,7 +3,6 @@ package org.thoughtcrime.securesms.components.settings.app.privacy
import android.content.Context
import org.signal.core.util.concurrent.SignalExecutors
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.database.model.DistributionListPartialRecord
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.jobs.MultiDeviceConfigurationUpdateJob
import org.thoughtcrime.securesms.keyvalue.SignalStore
@ -23,12 +22,6 @@ class PrivacySettingsRepository {
}
}
fun getPrivateStories(consumer: (List<DistributionListPartialRecord>) -> Unit) {
SignalExecutors.BOUNDED.execute {
consumer(SignalDatabase.distributionLists.getCustomListsForUi())
}
}
fun syncReadReceiptState() {
SignalExecutors.BOUNDED.execute {
SignalDatabase.recipients.markNeedsSync(Recipient.self().id)

Wyświetl plik

@ -1,6 +1,5 @@
package org.thoughtcrime.securesms.components.settings.app.privacy
import org.thoughtcrime.securesms.database.model.DistributionListPartialRecord
import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues
data class PrivacySettingsState(
@ -16,7 +15,5 @@ data class PrivacySettingsState(
val isObsoletePasswordEnabled: Boolean,
val isObsoletePasswordTimeoutEnabled: Boolean,
val obsoletePasswordTimeout: Int,
val universalExpireTimer: Int,
val privateStories: List<DistributionListPartialRecord>,
val isStoriesEnabled: Boolean
val universalExpireTimer: Int
)

Wyświetl plik

@ -27,11 +27,6 @@ class PrivacySettingsViewModel(
store.update { it.copy(blockedCount = count) }
refresh()
}
repository.getPrivateStories { privateStories ->
store.update { it.copy(privateStories = privateStories) }
refresh()
}
}
fun setReadReceiptsEnabled(enabled: Boolean) {
@ -89,11 +84,6 @@ class PrivacySettingsViewModel(
refresh()
}
fun setStoriesEnabled(isStoriesEnabled: Boolean) {
SignalStore.storyValues().isFeatureDisabled = !isStoriesEnabled
refresh()
}
fun refresh() {
store.update(this::updateState)
}
@ -112,14 +102,12 @@ class PrivacySettingsViewModel(
isObsoletePasswordEnabled = !TextSecurePreferences.isPasswordDisabled(ApplicationDependencies.getApplication()),
isObsoletePasswordTimeoutEnabled = TextSecurePreferences.isPassphraseTimeoutEnabled(ApplicationDependencies.getApplication()),
obsoletePasswordTimeout = TextSecurePreferences.getPassphraseTimeoutInterval(ApplicationDependencies.getApplication()),
universalExpireTimer = SignalStore.settings().universalExpireTimer,
privateStories = emptyList(),
isStoriesEnabled = !SignalStore.storyValues().isFeatureDisabled
universalExpireTimer = SignalStore.settings().universalExpireTimer
)
}
private fun updateState(state: PrivacySettingsState): PrivacySettingsState {
return getState().copy(blockedCount = state.blockedCount, privateStories = state.privateStories)
return getState().copy(blockedCount = state.blockedCount)
}
class Factory(

Wyświetl plik

@ -19,7 +19,6 @@ import androidx.preference.PreferenceManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
import org.thoughtcrime.securesms.components.settings.configure
@ -29,6 +28,7 @@ import org.thoughtcrime.securesms.registration.RegistrationNavigationActivity
import org.thoughtcrime.securesms.util.CommunicationActions
import org.thoughtcrime.securesms.util.SpanUtil
import org.thoughtcrime.securesms.util.ViewUtil
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
class AdvancedPrivacySettingsFragment : DSLSettingsFragment(R.string.preferences__advanced) {
@ -75,7 +75,7 @@ class AdvancedPrivacySettingsFragment : DSLSettingsFragment(R.string.preferences
unregisterNetworkReceiver()
}
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
val repository = AdvancedPrivacySettingsRepository(requireContext())
val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
val factory = AdvancedPrivacySettingsViewModel.Factory(preferences, repository)

Wyświetl plik

@ -10,7 +10,6 @@ import androidx.navigation.fragment.NavHostFragment
import androidx.recyclerview.widget.RecyclerView
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
import org.thoughtcrime.securesms.components.settings.configure
@ -18,6 +17,7 @@ import org.thoughtcrime.securesms.groups.ui.GroupChangeFailureReason
import org.thoughtcrime.securesms.groups.ui.GroupErrors
import org.thoughtcrime.securesms.util.ExpirationUtil
import org.thoughtcrime.securesms.util.ViewUtil
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.livedata.ProcessState
import org.thoughtcrime.securesms.util.livedata.distinctUntilChanged
import org.thoughtcrime.securesms.util.navigation.safeNavigate
@ -48,7 +48,7 @@ class ExpireTimerSettingsFragment : DSLSettingsFragment(
recycler.clipToPadding = false
}
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
val provider = ViewModelProvider(
NavHostFragment.findNavController(this).getViewModelStoreOwner(R.id.app_settings_expire_timer),
ExpireTimerSettingsViewModel.Factory(requireContext(), arguments.toConfig())

Wyświetl plik

@ -12,7 +12,6 @@ import org.thoughtcrime.securesms.badges.gifts.ExpiredGiftSheet
import org.thoughtcrime.securesms.badges.gifts.flow.GiftFlowActivity
import org.thoughtcrime.securesms.badges.models.BadgePreview
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.DSLSettingsIcon
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
@ -28,6 +27,7 @@ import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.subscription.Subscription
import org.thoughtcrime.securesms.util.FeatureFlags
import org.thoughtcrime.securesms.util.SpanUtil
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.navigation.safeNavigate
import org.whispersystems.signalservice.api.subscriptions.ActiveSubscription
import java.util.Currency
@ -60,7 +60,7 @@ class ManageDonationsFragment : DSLSettingsFragment(), ExpiredGiftSheet.Callback
viewModel.refresh()
}
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
ActiveSubscriptionPreference.register(adapter)
IndeterminateLoadingCircle.register(adapter)
BadgePreview.register(adapter)

Wyświetl plik

@ -17,7 +17,6 @@ import org.signal.core.util.concurrent.SimpleTask
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
import org.thoughtcrime.securesms.components.settings.configure
@ -26,6 +25,7 @@ import org.thoughtcrime.securesms.database.model.DonationReceiptRecord
import org.thoughtcrime.securesms.payments.FiatMoneyUtil
import org.thoughtcrime.securesms.providers.BlobProvider
import org.thoughtcrime.securesms.util.DateUtils
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import java.io.ByteArrayOutputStream
import java.util.Locale
@ -42,7 +42,7 @@ class DonationReceiptDetailFragment : DSLSettingsFragment(layoutId = R.layout.do
}
)
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
SplashImage.register(adapter)
val sharePngButton: MaterialButton = requireView().findViewById(R.id.share_png)

Wyświetl plik

@ -16,7 +16,6 @@ import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.badges.models.Badge
import org.thoughtcrime.securesms.badges.models.BadgePreview
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity
@ -37,6 +36,7 @@ import org.thoughtcrime.securesms.payments.FiatMoneyUtil
import org.thoughtcrime.securesms.subscription.Subscription
import org.thoughtcrime.securesms.util.LifecycleDisposable
import org.thoughtcrime.securesms.util.SpanUtil
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.fragments.requireListener
import org.thoughtcrime.securesms.util.navigation.safeNavigate
import org.thoughtcrime.securesms.util.visible
@ -82,7 +82,7 @@ class SubscribeFragment : DSLSettingsFragment(
viewModel.refreshActiveSubscription()
}
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
donationPaymentComponent = requireListener()
viewModel.refresh()

Wyświetl plik

@ -40,7 +40,6 @@ import org.thoughtcrime.securesms.badges.view.ViewBadgeBottomSheetDialogFragment
import org.thoughtcrime.securesms.components.AvatarImageView
import org.thoughtcrime.securesms.components.recyclerview.OnScrollAnimationHelper
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.DSLSettingsIcon
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
@ -85,6 +84,7 @@ import org.thoughtcrime.securesms.util.ExpirationUtil
import org.thoughtcrime.securesms.util.FeatureFlags
import org.thoughtcrime.securesms.util.Material3OnScrollHelper
import org.thoughtcrime.securesms.util.ViewUtil
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.navigation.safeNavigate
import org.thoughtcrime.securesms.util.views.SimpleProgressDialog
import org.thoughtcrime.securesms.verify.VerifyIdentityActivity
@ -202,7 +202,7 @@ class ConversationSettingsFragment : DSLSettingsFragment(
}
}
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
val args = ConversationSettingsFragmentArgs.fromBundle(requireArguments())
BioTextPreference.register(adapter)

Wyświetl plik

@ -12,7 +12,6 @@ import org.signal.core.util.concurrent.SignalExecutors
import org.thoughtcrime.securesms.MainActivity
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
import org.thoughtcrime.securesms.components.settings.configure
@ -27,6 +26,7 @@ import org.thoughtcrime.securesms.subscription.Subscriber
import org.thoughtcrime.securesms.util.Base64
import org.thoughtcrime.securesms.util.SpanUtil
import org.thoughtcrime.securesms.util.Util
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.livedata.Store
import org.whispersystems.signalservice.api.push.ServiceId
import java.util.Objects
@ -45,7 +45,7 @@ class InternalConversationSettingsFragment : DSLSettingsFragment(
}
)
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
viewModel.state.observe(viewLifecycleOwner) { state ->
adapter.submitList(getConfiguration(state).toMappingModelList())
}

Wyświetl plik

@ -5,12 +5,12 @@ import androidx.annotation.StringRes
import androidx.fragment.app.viewModels
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
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.groups.ParcelableGroupId
import org.thoughtcrime.securesms.groups.ui.GroupErrors
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
class PermissionsSettingsFragment : DSLSettingsFragment(
titleId = R.string.ConversationSettingsFragment__permissions
@ -30,7 +30,7 @@ class PermissionsSettingsFragment : DSLSettingsFragment(
}
)
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
viewModel.state.observe(viewLifecycleOwner) { state ->
adapter.submitList(getConfiguration(state).toMappingModelList())
}

Wyświetl plik

@ -6,7 +6,6 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.thoughtcrime.securesms.MuteDialog
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.DSLSettingsIcon
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
@ -14,6 +13,7 @@ import org.thoughtcrime.securesms.components.settings.configure
import org.thoughtcrime.securesms.components.settings.conversation.preferences.Utils.formatMutedUntil
import org.thoughtcrime.securesms.database.RecipientDatabase
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.navigation.safeNavigate
class SoundsAndNotificationsSettingsFragment : DSLSettingsFragment(
@ -38,7 +38,7 @@ class SoundsAndNotificationsSettingsFragment : DSLSettingsFragment(
viewModel.channelConsistencyCheck()
}
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
viewModel.state.observe(viewLifecycleOwner) { state ->
if (state.channelConsistencyCheckComplete && state.recipientId != Recipient.UNKNOWN.id) {
adapter.submitList(getConfiguration(state).toMappingModelList())

Wyświetl plik

@ -14,7 +14,6 @@ import androidx.fragment.app.viewModels
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
import org.thoughtcrime.securesms.components.settings.configure
@ -22,6 +21,7 @@ import org.thoughtcrime.securesms.database.RecipientDatabase
import org.thoughtcrime.securesms.notifications.NotificationChannels
import org.thoughtcrime.securesms.util.ConversationUtil
import org.thoughtcrime.securesms.util.RingtoneUtil
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
private val TAG = Log.tag(CustomNotificationsSettingsFragment::class.java)
@ -48,7 +48,7 @@ class CustomNotificationsSettingsFragment : DSLSettingsFragment(R.string.CustomN
viewModel.channelConsistencyCheck()
}
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
messageSoundResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
handleResult(result, viewModel::setMessageSound)
}

Wyświetl plik

@ -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.

Wyświetl plik

@ -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)
}
}
}
/**

Wyświetl plik

@ -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))
}

Wyświetl plik

@ -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()
}

Wyświetl plik

@ -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)
}
)
}

Wyświetl plik

@ -47,6 +47,7 @@ class DistributionListDatabase constructor(context: Context?, databaseHelper: Si
const val RECIPIENT_ID = ListTable.RECIPIENT_ID
const val DISTRIBUTION_ID = ListTable.DISTRIBUTION_ID
const val LIST_TABLE_NAME = ListTable.TABLE_NAME
const val PRIVACY_MODE = ListTable.PRIVACY_MODE
fun insertInitialDistributionListAtCreationTime(db: net.zetetic.database.sqlcipher.SQLiteDatabase) {
val recipientId = db.insert(

Wyświetl plik

@ -9,7 +9,7 @@ public final class ParcelableGroupId implements Parcelable {
private final GroupId groupId;
public static Parcelable from(@Nullable GroupId groupId) {
public static ParcelableGroupId from(@Nullable GroupId groupId) {
return new ParcelableGroupId(groupId);
}

Wyświetl plik

@ -19,6 +19,7 @@ import org.thoughtcrime.securesms.contacts.paged.ContactSearchConfiguration
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
import org.thoughtcrime.securesms.contacts.paged.ContactSearchMediator
import org.thoughtcrime.securesms.contacts.paged.ContactSearchSortOrder
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.sharing.ShareContact
import org.thoughtcrime.securesms.sharing.ShareSelectionAdapter
import org.thoughtcrime.securesms.sharing.ShareSelectionMappingModel
@ -157,4 +158,10 @@ class ChooseGroupStoryBottomSheet : FixedRoundedCornerBottomSheetDialogFragment(
)
dismissAllowingStateLoss()
}
object ResultContract {
fun getRecipientIds(bundle: Bundle): List<RecipientId> {
return bundle.getParcelableArrayList(RESULT_SET)!!
}
}
}

Wyświetl plik

@ -3,12 +3,12 @@ package org.thoughtcrime.securesms.profiles.edit.pnp
import androidx.fragment.app.viewModels
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
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.util.FeatureFlags
import org.thoughtcrime.securesms.util.LifecycleDisposable
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
/**
* Allows the user to select who can see their phone number during registration.
@ -18,7 +18,7 @@ class WhoCanSeeMyPhoneNumberFragment : DSLSettingsFragment(titleId = R.string.Wh
private val viewModel: WhoCanSeeMyPhoneNumberViewModel by viewModels()
private val lifecycleDisposable = LifecycleDisposable()
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
require(FeatureFlags.phoneNumberPrivacy())
lifecycleDisposable += viewModel.state.subscribe {

Wyświetl plik

@ -6,13 +6,13 @@ import androidx.fragment.app.viewModels
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.DSLSettingsIcon
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
import org.thoughtcrime.securesms.components.settings.configure
import org.thoughtcrime.securesms.groups.GroupId
import org.thoughtcrime.securesms.groups.v2.GroupLinkUrlAndStatus
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil
import org.thoughtcrime.securesms.util.views.SimpleProgressDialog
@ -36,7 +36,7 @@ class ShareableGroupLinkFragment : DSLSettingsFragment(
}
)
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
LiveDataUtil.combineLatest(viewModel.groupLink, viewModel.canEdit) { groupLink, canEdit ->
Pair(groupLink, canEdit)
}.observe(viewLifecycleOwner) { (groupLink, canEdit) ->

Wyświetl plik

@ -9,7 +9,6 @@ import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.WrapperDialogFragment
import org.thoughtcrime.securesms.components.menu.ActionItem
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
import org.thoughtcrime.securesms.components.settings.configure
@ -21,6 +20,7 @@ import org.thoughtcrime.securesms.safety.SafetyNumberBucket
import org.thoughtcrime.securesms.safety.SafetyNumberBucketRowItem
import org.thoughtcrime.securesms.safety.SafetyNumberRecipientRowItem
import org.thoughtcrime.securesms.util.LifecycleDisposable
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.verify.VerifyIdentityFragment
/**
@ -38,7 +38,7 @@ class SafetyNumberReviewConnectionsFragment : DSLSettingsFragment(
private val lifecycleDisposable = LifecycleDisposable()
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
SafetyNumberBucketRowItem.register(adapter)
SafetyNumberRecipientRowItem.register(adapter)
lifecycleDisposable.bindTo(viewLifecycleOwner)

Wyświetl plik

@ -62,11 +62,16 @@ object Stories {
return isFeatureAvailable() && !SignalStore.storyValues().isFeatureDisabled
}
fun getHeaderAction(fragmentManager: FragmentManager): HeaderAction {
fun getHeaderAction(onClick: () -> Unit): HeaderAction {
return HeaderAction(
R.string.ContactsCursorLoader_new_story,
R.drawable.ic_plus_20
) {
R.drawable.ic_plus_20,
onClick
)
}
fun getHeaderAction(fragmentManager: FragmentManager): HeaderAction {
return getHeaderAction {
ChooseStoryTypeBottomSheet().show(fragmentManager, BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG)
}
}

Wyświetl plik

@ -25,7 +25,6 @@ import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.kotlin.subscribeBy
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
import org.thoughtcrime.securesms.components.settings.configure
@ -49,6 +48,7 @@ import org.thoughtcrime.securesms.stories.tabs.ConversationListTab
import org.thoughtcrime.securesms.stories.tabs.ConversationListTabsViewModel
import org.thoughtcrime.securesms.stories.viewer.StoryViewerActivity
import org.thoughtcrime.securesms.util.LifecycleDisposable
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.fragments.requireListener
import org.thoughtcrime.securesms.util.visible
import java.util.concurrent.TimeUnit
@ -75,7 +75,7 @@ class StoriesLandingFragment : DSLSettingsFragment(layoutId = R.layout.stories_l
private val tabsViewModel: ConversationListTabsViewModel by viewModels(ownerProducer = { requireActivity() })
private lateinit var adapter: DSLSettingsAdapter
private lateinit var adapter: MappingAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -92,7 +92,7 @@ class StoriesLandingFragment : DSLSettingsFragment(layoutId = R.layout.stories_l
viewModel.isTransitioningToAnotherScreen = false
}
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
this.adapter = adapter
StoriesLandingItem.register(adapter)

Wyświetl plik

@ -9,7 +9,6 @@ import androidx.core.view.ViewCompat
import androidx.fragment.app.viewModels
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
import org.thoughtcrime.securesms.components.settings.configure
@ -26,6 +25,7 @@ import org.thoughtcrime.securesms.stories.dialogs.StoryDialogs
import org.thoughtcrime.securesms.stories.viewer.StoryViewerActivity
import org.thoughtcrime.securesms.util.LifecycleDisposable
import org.thoughtcrime.securesms.util.Util
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.visible
class MyStoriesFragment : DSLSettingsFragment(
@ -41,7 +41,7 @@ class MyStoriesFragment : DSLSettingsFragment(
}
)
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
MyStoriesItem.register(adapter)
requireActivity().onBackPressedDispatcher.addCallback(

Wyświetl plik

@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.stories.settings
import android.content.Context
import android.content.Intent
import androidx.core.os.bundleOf
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLSettingsActivity
@ -9,7 +10,8 @@ class StorySettingsActivity : DSLSettingsActivity() {
companion object {
fun getIntent(context: Context): Intent {
return Intent(context, StorySettingsActivity::class.java)
.putExtra(ARG_NAV_GRAPH, R.navigation.story_settings)
.putExtra(ARG_NAV_GRAPH, R.navigation.story_privacy_settings)
.putExtra(ARG_START_BUNDLE, bundleOf("title_id" to R.string.StoriesPrivacySettingsFragment__story_privacy))
}
}
}

Wyświetl plik

@ -7,11 +7,11 @@ import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.configure
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.util.adapter.mapping.LayoutFactory
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.fragments.findListener
import org.thoughtcrime.securesms.util.viewholders.RecipientMappingModel
import org.thoughtcrime.securesms.util.viewholders.RecipientViewHolder
@ -38,7 +38,7 @@ class CreateStoryWithViewersFragment : DSLSettingsFragment(
private val recipientIds: Array<RecipientId>
get() = CreateStoryWithViewersFragmentArgs.fromBundle(requireArguments()).recipients
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
adapter.registerFactory(RecipientMappingModel.RecipientIdMappingModel::class.java, LayoutFactory({ RecipientViewHolder(it, null) }, R.layout.stories_recipient_item))
CreateStoryNameFieldItem.register(adapter) {
viewModel.setLabel(it)

Wyświetl plik

@ -1,4 +1,4 @@
package org.thoughtcrime.securesms.stories.settings.story
package org.thoughtcrime.securesms.stories.settings.custom
import android.view.View
import android.widget.TextView
@ -15,17 +15,10 @@ import org.thoughtcrime.securesms.util.adapter.mapping.MappingViewHolder
object PrivateStoryItem {
fun register(mappingAdapter: MappingAdapter) {
mappingAdapter.registerFactory(NewModel::class.java, LayoutFactory(::NewViewHolder, R.layout.stories_private_story_new_item))
mappingAdapter.registerFactory(AddViewerModel::class.java, LayoutFactory(::AddViewerViewHolder, R.layout.stories_private_story_add_viewer_item))
mappingAdapter.registerFactory(RecipientModel::class.java, LayoutFactory(::RecipientViewHolder, R.layout.stories_private_story_recipient_item))
mappingAdapter.registerFactory(Model::class.java, LayoutFactory(::ViewHolder, R.layout.stories_private_story_item))
mappingAdapter.registerFactory(PartialModel::class.java, LayoutFactory(::PartialViewHolder, R.layout.stories_private_story_item))
}
class NewModel(
val onClick: () -> Unit
) : PreferenceModel<NewModel>() {
override fun areItemsTheSame(newItem: NewModel): Boolean = true
mappingAdapter.registerFactory(AddViewerModel::class.java, LayoutFactory(PrivateStoryItem::AddViewerViewHolder, R.layout.stories_private_story_add_viewer_item))
mappingAdapter.registerFactory(RecipientModel::class.java, LayoutFactory(PrivateStoryItem::RecipientViewHolder, R.layout.stories_private_story_recipient_item))
mappingAdapter.registerFactory(Model::class.java, LayoutFactory(PrivateStoryItem::ViewHolder, R.layout.stories_private_story_item))
mappingAdapter.registerFactory(PartialModel::class.java, LayoutFactory(PrivateStoryItem::PartialViewHolder, R.layout.stories_private_story_item))
}
class AddViewerModel(
@ -36,12 +29,14 @@ object PrivateStoryItem {
class RecipientModel(
val recipient: Recipient,
val onClick: (RecipientModel) -> Unit
val onClick: ((RecipientModel) -> Unit)? = null
) : PreferenceModel<RecipientModel>() {
override fun areItemsTheSame(newItem: RecipientModel): Boolean = newItem.recipient == recipient
override fun areContentsTheSame(newItem: RecipientModel): Boolean {
return newItem.recipient.hasSameContent(recipient) && super.areContentsTheSame(newItem)
return newItem.recipient.hasSameContent(recipient) &&
(newItem.onClick != null) == (onClick != null) &&
super.areContentsTheSame(newItem)
}
}
@ -79,7 +74,13 @@ object PrivateStoryItem {
private val avatar: AvatarImageView = itemView.findViewById(R.id.avatar)
override fun bind(model: RecipientModel) {
itemView.setOnClickListener { model.onClick(model) }
val onClick = model.onClick
if (onClick != null) {
itemView.setOnClickListener { onClick(model) }
} else {
itemView.setOnClickListener(null)
}
avatar.setRecipient(model.recipient)
if (model.recipient.isSelf) {
@ -90,12 +91,6 @@ object PrivateStoryItem {
}
}
private class NewViewHolder(itemView: View) : MappingViewHolder<NewModel>(itemView) {
override fun bind(model: NewModel) {
itemView.setOnClickListener { model.onClick() }
}
}
private class AddViewerViewHolder(itemView: View) : MappingViewHolder<AddViewerModel>(itemView) {
override fun bind(model: AddViewerModel) {
itemView.setOnClickListener { model.onClick() }

Wyświetl plik

@ -12,14 +12,13 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.WrapperDialogFragment
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
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.DistributionListId
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.stories.settings.story.PrivateStoryItem
import org.thoughtcrime.securesms.util.adapter.mapping.LayoutFactory
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.fragments.findListener
import org.thoughtcrime.securesms.util.navigation.safeNavigate
import org.thoughtcrime.securesms.util.viewholders.RecipientMappingModel
@ -43,7 +42,7 @@ class PrivateStorySettingsFragment : DSLSettingsFragment(
viewModel.refresh()
}
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
adapter.registerFactory(RecipientMappingModel.RecipientIdMappingModel::class.java, LayoutFactory({ RecipientViewHolder(it, RecipientEventListener()) }, R.layout.stories_recipient_item))
PrivateStoryItem.register(adapter)

Wyświetl plik

@ -0,0 +1,11 @@
package org.thoughtcrime.securesms.stories.settings.group
import org.thoughtcrime.securesms.recipients.RecipientId
/**
* Minimum data needed to launch ConversationActivity for a given grou
*/
data class GroupConversationData(
val groupRecipientId: RecipientId,
val groupThreadId: Long
)

Wyświetl plik

@ -0,0 +1,102 @@
package org.thoughtcrime.securesms.stories.settings.group
import android.view.MenuItem
import android.view.ViewGroup
import androidx.appcompat.widget.Toolbar
import androidx.core.content.ContextCompat
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import org.signal.core.util.dp
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.menu.ActionItem
import org.thoughtcrime.securesms.components.menu.SignalContextMenu
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
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.conversation.ConversationIntents
import org.thoughtcrime.securesms.stories.settings.custom.PrivateStoryItem
import org.thoughtcrime.securesms.util.LifecycleDisposable
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
/**
* Displays who can see a group story and gives the user an option to remove it.
*/
class GroupStorySettingsFragment : DSLSettingsFragment(menuId = R.menu.story_group_menu) {
private val lifecycleDisposable = LifecycleDisposable()
private val viewModel: GroupStorySettingsViewModel by viewModels(factoryProducer = {
GroupStorySettingsViewModel.Factory(GroupStorySettingsFragmentArgs.fromBundle(requireArguments()).groupId)
})
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val toolbar: Toolbar = requireView().findViewById(R.id.toolbar)
if (item.itemId == R.id.action_overflow) {
SignalContextMenu.Builder(toolbar, requireView() as ViewGroup)
.preferredHorizontalPosition(SignalContextMenu.HorizontalPosition.END)
.preferredVerticalPosition(SignalContextMenu.VerticalPosition.BELOW)
.offsetX(16.dp)
.offsetY((-4).dp)
.show(
listOf(
ActionItem(
iconRes = R.drawable.ic_open_24_tinted,
title = getString(R.string.StoriesLandingItem__go_to_chat),
action = {
lifecycleDisposable += viewModel.getConversationData().subscribe { data ->
startActivity(ConversationIntents.createBuilder(requireContext(), data.groupRecipientId, data.groupThreadId).build())
}
}
)
)
)
}
return super.onOptionsItemSelected(item)
}
override fun bindAdapter(adapter: MappingAdapter) {
PrivateStoryItem.register(adapter)
lifecycleDisposable.bindTo(viewLifecycleOwner)
viewModel.state.observe(viewLifecycleOwner) { state ->
if (state.removed) {
findNavController().popBackStack()
return@observe
}
setTitle(state.name)
adapter.submitList(getConfiguration(state).toMappingModelList())
}
}
private fun getConfiguration(state: GroupStorySettingsState): DSLConfiguration {
return configure {
sectionHeaderPref(R.string.GroupStorySettingsFragment__who_can_view_this_story)
state.members.forEach {
customPref(PrivateStoryItem.RecipientModel(it))
}
textPref(
title = DSLSettingsText.from(
getString(R.string.GroupStorySettingsFragment__members_of_the_group_s, state.name),
DSLSettingsText.TextAppearanceModifier(R.style.Signal_Text_BodyMedium),
DSLSettingsText.ColorModifier(ContextCompat.getColor(requireContext(), R.color.signal_colorOnSurfaceVariant))
)
)
dividerPref()
clickPref(
title = DSLSettingsText.from(
R.string.GroupStorySettingsFragment__remove_group_story,
DSLSettingsText.ColorModifier(ContextCompat.getColor(requireContext(), R.color.signal_colorError))
),
onClick = {
viewModel.doNotDisplayAsStory()
}
)
}
}
}

Wyświetl plik

@ -0,0 +1,24 @@
package org.thoughtcrime.securesms.stories.settings.group
import io.reactivex.rxjava3.core.Completable
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.schedulers.Schedulers
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.groups.GroupId
class GroupStorySettingsRepository {
fun unmarkAsGroupStory(groupId: GroupId): Completable {
return Completable.fromAction {
SignalDatabase.groups.markDisplayAsStory(groupId, false)
}.subscribeOn(Schedulers.io())
}
fun getConversationData(groupId: GroupId): Single<GroupConversationData> {
return Single.fromCallable {
val recipientId = SignalDatabase.recipients.getByGroupId(groupId).get()
val threadId = SignalDatabase.threads.getThreadIdFor(recipientId) ?: -1L
GroupConversationData(recipientId, threadId)
}.subscribeOn(Schedulers.io())
}
}

Wyświetl plik

@ -0,0 +1,9 @@
package org.thoughtcrime.securesms.stories.settings.group
import org.thoughtcrime.securesms.recipients.Recipient
data class GroupStorySettingsState(
val name: String = "",
val members: List<Recipient> = emptyList(),
val removed: Boolean = false
)

Wyświetl plik

@ -0,0 +1,45 @@
package org.thoughtcrime.securesms.stories.settings.group
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Single
import org.thoughtcrime.securesms.groups.GroupId
import org.thoughtcrime.securesms.groups.LiveGroup
import org.thoughtcrime.securesms.groups.ParcelableGroupId
import org.thoughtcrime.securesms.util.livedata.Store
/**
* This class utilizes LiveData due to pre-existing infrastructure in LiveGroup
*/
class GroupStorySettingsViewModel(private val groupId: GroupId) : ViewModel() {
private val repository = GroupStorySettingsRepository()
private val store = Store(GroupStorySettingsState())
val state: LiveData<GroupStorySettingsState> = store.stateLiveData
init {
val group = LiveGroup(groupId)
store.update(group.fullMembers) { members, state -> state.copy(members = members.map { it.member }) }
store.update(group.title) { title, state -> state.copy(name = title) }
}
fun doNotDisplayAsStory() {
repository.unmarkAsGroupStory(groupId).subscribe {
store.update { it.copy(removed = true) }
}
}
fun getConversationData(): Single<GroupConversationData> {
return repository.getConversationData(groupId).observeOn(AndroidSchedulers.mainThread())
}
class Factory(private val parcelableGroupId: ParcelableGroupId) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return modelClass.cast(GroupStorySettingsViewModel(ParcelableGroupId.get(parcelableGroupId)!!)) as T
}
}
}

Wyświetl plik

@ -10,12 +10,12 @@ import androidx.navigation.fragment.findNavController
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.WrapperDialogFragment
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
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.util.LifecycleDisposable
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.navigation.safeNavigate
class MyStorySettingsFragment : DSLSettingsFragment(
@ -37,7 +37,7 @@ class MyStorySettingsFragment : DSLSettingsFragment(
viewModel.refresh()
}
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
viewModel.state.observe(viewLifecycleOwner) { state ->
adapter.submitList(getConfiguration(state).toMappingModelList())
}

Wyświetl plik

@ -0,0 +1,168 @@
package org.thoughtcrime.securesms.stories.settings.story
import androidx.core.content.ContextCompat
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.ConcatAdapter
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.signal.core.util.dp
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
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.contacts.paged.ContactSearchItems
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
import org.thoughtcrime.securesms.groups.ParcelableGroupId
import org.thoughtcrime.securesms.mediasend.v2.stories.ChooseGroupStoryBottomSheet
import org.thoughtcrime.securesms.mediasend.v2.stories.ChooseStoryTypeBottomSheet
import org.thoughtcrime.securesms.stories.settings.create.CreateStoryFlowDialogFragment
import org.thoughtcrime.securesms.stories.settings.create.CreateStoryWithViewersFragment
import org.thoughtcrime.securesms.util.BottomSheetUtil
import org.thoughtcrime.securesms.util.LifecycleDisposable
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.adapter.mapping.PagingMappingAdapter
import org.thoughtcrime.securesms.util.navigation.safeNavigate
/**
* Allows the user to view their stories they can send to and modify settings.
*/
class StoriesPrivacySettingsFragment :
DSLSettingsFragment(
titleId = R.string.preferences__stories
),
ChooseStoryTypeBottomSheet.Callback {
private val viewModel: StoriesPrivacySettingsViewModel by viewModels()
private val lifecycleDisposable = LifecycleDisposable()
override fun createAdapters(): Array<MappingAdapter> {
return arrayOf(DSLSettingsAdapter(), PagingMappingAdapter<ContactSearchKey>(), DSLSettingsAdapter())
}
override fun bindAdapters(adapter: ConcatAdapter) {
lifecycleDisposable.bindTo(viewLifecycleOwner)
val titleId = StoriesPrivacySettingsFragmentArgs.fromBundle(requireArguments()).titleId
setTitle(titleId)
val (top, middle, bottom) = adapter.adapters
findNavController().addOnDestinationChangedListener { _, destination, _ ->
if (destination.id == R.id.storiesPrivacySettingsFragment) {
viewModel.pagingController.onDataInvalidated()
}
}
@Suppress("UNCHECKED_CAST")
ContactSearchItems.registerStoryItems(
mappingAdapter = middle as PagingMappingAdapter<ContactSearchKey>,
storyListener = { _, story, _ ->
when {
story.recipient.isMyStory -> findNavController().safeNavigate(StoriesPrivacySettingsFragmentDirections.actionStoryPrivacySettingsToMyStorySettings())
story.recipient.isGroup -> findNavController().safeNavigate(StoriesPrivacySettingsFragmentDirections.actionStoryPrivacySettingsToGroupStorySettings(ParcelableGroupId.from(story.recipient.requireGroupId())))
else -> findNavController().safeNavigate(StoriesPrivacySettingsFragmentDirections.actionStoryPrivacySettingsToPrivateStorySettings(story.recipient.requireDistributionListId()))
}
}
)
ContactSearchItems.registerHeaders(middle)
middle.setPagingController(viewModel.pagingController)
parentFragmentManager.setFragmentResultListener(ChooseGroupStoryBottomSheet.GROUP_STORY, viewLifecycleOwner) { _, bundle ->
val results = ChooseGroupStoryBottomSheet.ResultContract.getRecipientIds(bundle)
viewModel.displayGroupsAsStories(results)
}
parentFragmentManager.setFragmentResultListener(CreateStoryWithViewersFragment.REQUEST_KEY, viewLifecycleOwner) { _, _ ->
viewModel.pagingController.onDataInvalidated()
}
lifecycleDisposable += viewModel.headerActionRequests.subscribe {
ChooseStoryTypeBottomSheet().show(childFragmentManager, BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG)
}
lifecycleDisposable += viewModel.state.subscribe { state ->
(top as MappingAdapter).submitList(getTopConfiguration(state).toMappingModelList())
middle.submitList(getMiddleConfiguration(state).toMappingModelList())
(bottom as MappingAdapter).submitList(getBottomConfiguration(state).toMappingModelList())
}
}
private fun getTopConfiguration(state: StoriesPrivacySettingsState): DSLConfiguration {
return configure {
if (state.areStoriesEnabled) {
space(16.dp)
noPadTextPref(
title = DSLSettingsText.from(
R.string.StoriesPrivacySettingsFragment__stories_automatically_disappear,
DSLSettingsText.TextAppearanceModifier(R.style.Signal_Text_BodyMedium),
DSLSettingsText.ColorModifier(ContextCompat.getColor(requireContext(), R.color.signal_colorOnSurfaceVariant))
)
)
space(20.dp)
} else {
clickPref(
title = DSLSettingsText.from(R.string.StoriesPrivacySettingsFragment__turn_on_stories),
summary = DSLSettingsText.from(R.string.StoriesPrivacySettingsFragment__share_and_view),
onClick = {
viewModel.setStoriesEnabled(true)
}
)
}
}
}
private fun getMiddleConfiguration(state: StoriesPrivacySettingsState): DSLConfiguration {
return if (state.areStoriesEnabled) {
configure {
ContactSearchItems.toMappingModelList(
state.storyContactItems,
emptySet()
).forEach {
customPref(it)
}
}
} else {
configure { }
}
}
private fun getBottomConfiguration(state: StoriesPrivacySettingsState): DSLConfiguration {
return if (state.areStoriesEnabled) {
configure {
dividerPref()
clickPref(
title = DSLSettingsText.from(R.string.StoriesPrivacySettingsFragment__turn_off_stories),
summary = DSLSettingsText.from(
R.string.StoriesPrivacySettingsFragment__if_you_opt_out,
DSLSettingsText.TextAppearanceModifier(R.style.Signal_Text_BodyMedium),
DSLSettingsText.ColorModifier(ContextCompat.getColor(requireContext(), R.color.signal_colorOnSurfaceVariant))
),
onClick = {
MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.StoriesPrivacySettingsFragment__turn_off_stories_question)
.setMessage(R.string.StoriesPrivacySettingsFragment__you_will_no_longer_be_able_to)
.setPositiveButton(R.string.StoriesPrivacySettingsFragment__turn_off_stories) { _, _ -> viewModel.setStoriesEnabled(false) }
.setNegativeButton(android.R.string.cancel) { _, _ -> }
.show()
}
)
}
} else {
configure { }
}
}
override fun onGroupStoryClicked() {
ChooseGroupStoryBottomSheet().show(parentFragmentManager, ChooseGroupStoryBottomSheet.GROUP_STORY)
}
override fun onNewStoryClicked() {
CreateStoryFlowDialogFragment().show(parentFragmentManager, CreateStoryWithViewersFragment.REQUEST_KEY)
}
}

Wyświetl plik

@ -0,0 +1,16 @@
package org.thoughtcrime.securesms.stories.settings.story
import io.reactivex.rxjava3.core.Completable
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientId
class StoriesPrivacySettingsRepository {
fun markGroupsAsStories(groups: List<RecipientId>): Completable {
return Completable.fromCallable {
groups
.map { Recipient.resolved(it) }
.forEach { SignalDatabase.groups.markDisplayAsStory(it.requireGroupId()) }
}
}
}

Wyświetl plik

@ -0,0 +1,8 @@
package org.thoughtcrime.securesms.stories.settings.story
import org.thoughtcrime.securesms.contacts.paged.ContactSearchData
data class StoriesPrivacySettingsState(
val areStoriesEnabled: Boolean,
val storyContactItems: List<ContactSearchData> = emptyList()
)

Wyświetl plik

@ -0,0 +1,82 @@
package org.thoughtcrime.securesms.stories.settings.story
import androidx.lifecycle.ViewModel
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.BackpressureStrategy
import io.reactivex.rxjava3.core.Flowable
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import io.reactivex.rxjava3.subjects.PublishSubject
import org.signal.paging.PagedData
import org.signal.paging.PagingConfig
import org.signal.paging.ProxyPagingController
import org.thoughtcrime.securesms.contacts.paged.ContactSearchConfiguration
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
import org.thoughtcrime.securesms.contacts.paged.ContactSearchPagedDataSource
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.stories.Stories
import org.thoughtcrime.securesms.util.rx.RxStore
import java.util.concurrent.TimeUnit
class StoriesPrivacySettingsViewModel : ViewModel() {
private val repository = StoriesPrivacySettingsRepository()
private val store = RxStore(
StoriesPrivacySettingsState(
areStoriesEnabled = Stories.isFeatureEnabled()
)
)
private val pagingConfig = PagingConfig.Builder()
.setBufferPages(1)
.setPageSize(20)
.setStartIndex(0)
.build()
private val disposables = CompositeDisposable()
private val headerActionRequestSubject = PublishSubject.create<Unit>()
val state: Flowable<StoriesPrivacySettingsState> = store.stateFlowable.observeOn(AndroidSchedulers.mainThread())
val pagingController = ProxyPagingController<ContactSearchKey>()
val headerActionRequests: Observable<Unit> = headerActionRequestSubject.debounce(100, TimeUnit.MILLISECONDS)
init {
val configuration = ContactSearchConfiguration.build {
addSection(
ContactSearchConfiguration.Section.Stories(
includeHeader = true,
headerAction = Stories.getHeaderAction {
headerActionRequestSubject.onNext(Unit)
}
)
)
}
val pagedDataSource = ContactSearchPagedDataSource(configuration)
val observablePagedData = PagedData.createForObservable(pagedDataSource, pagingConfig)
pagingController.set(observablePagedData.controller)
store.update(observablePagedData.data.toFlowable(BackpressureStrategy.LATEST)) { data, state ->
state.copy(storyContactItems = data)
}
}
override fun onCleared() {
disposables.clear()
}
fun setStoriesEnabled(isEnabled: Boolean) {
SignalStore.storyValues().isFeatureDisabled = !isEnabled
store.update { it.copy(areStoriesEnabled = Stories.isFeatureEnabled()) }
}
fun displayGroupsAsStories(recipientIds: List<RecipientId>) {
disposables += repository.markGroupsAsStories(recipientIds).subscribe {
pagingController.onDataInvalidated()
}
}
}

Wyświetl plik

@ -1,73 +0,0 @@
package org.thoughtcrime.securesms.stories.settings.story
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
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.recipients.Recipient
import org.thoughtcrime.securesms.util.navigation.safeNavigate
class StorySettingsFragment : DSLSettingsFragment(
titleId = R.string.StorySettingsFragment__story_settings
) {
private val viewModel: StorySettingsViewModel by viewModels(
factoryProducer = {
StorySettingsViewModel.Factory(StorySettingsRepository())
}
)
override fun onResume() {
super.onResume()
viewModel.refresh()
}
override fun bindAdapter(adapter: DSLSettingsAdapter) {
PrivateStoryItem.register(adapter)
viewModel.state.observe(viewLifecycleOwner) { state ->
adapter.submitList(getConfiguration(state).toMappingModelList())
}
}
private fun getConfiguration(state: StorySettingsState): DSLConfiguration {
return configure {
customPref(
PrivateStoryItem.RecipientModel(
recipient = Recipient.self(),
onClick = {
findNavController().safeNavigate(R.id.action_storySettings_to_myStorySettings)
}
)
)
dividerPref()
sectionHeaderPref(R.string.StorySettingsFragment__private_stories)
customPref(
PrivateStoryItem.NewModel(
onClick = {
findNavController().safeNavigate(R.id.action_storySettings_to_newStory)
}
)
)
state.privateStories.forEach { itemData ->
customPref(
PrivateStoryItem.PartialModel(
privateStoryItemData = itemData,
onClick = {
findNavController().safeNavigate(StorySettingsFragmentDirections.actionStorySettingsToPrivateStorySettings(it.privateStoryItemData.id))
}
)
)
}
textPref(summary = DSLSettingsText.from(R.string.StorySettingsFragment__private_stories_can_only_be_viewed))
}
}
}

Wyświetl plik

@ -1,14 +0,0 @@
package org.thoughtcrime.securesms.stories.settings.story
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.schedulers.Schedulers
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.database.model.DistributionListPartialRecord
class StorySettingsRepository {
fun getPrivateStories(): Single<List<DistributionListPartialRecord>> {
return Single.fromCallable {
SignalDatabase.distributionLists.getCustomListsForUi()
}.subscribeOn(Schedulers.io())
}
}

Wyświetl plik

@ -1,7 +0,0 @@
package org.thoughtcrime.securesms.stories.settings.story
import org.thoughtcrime.securesms.database.model.DistributionListPartialRecord
data class StorySettingsState(
val privateStories: List<DistributionListPartialRecord> = emptyList()
)

Wyświetl plik

@ -1,36 +0,0 @@
package org.thoughtcrime.securesms.stories.settings.story
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import org.thoughtcrime.securesms.util.livedata.Store
class StorySettingsViewModel(
private val repository: StorySettingsRepository
) : ViewModel() {
private val store = Store(StorySettingsState())
private val disposables = CompositeDisposable()
val state: LiveData<StorySettingsState> = store.stateLiveData
fun refresh() {
disposables += repository.getPrivateStories().subscribe { privateStories ->
store.update { it.copy(privateStories = privateStories) }
}
}
override fun onCleared() {
disposables.clear()
}
class Factory(
private val repository: StorySettingsRepository
) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return modelClass.cast(StorySettingsViewModel(repository)) as T
}
}
}

Wyświetl plik

@ -7,7 +7,6 @@ import androidx.fragment.app.viewModels
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsAdapter
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity
import org.thoughtcrime.securesms.components.settings.configure
@ -15,6 +14,7 @@ import org.thoughtcrime.securesms.conversation.ConversationIntents
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.stories.viewer.reply.StoryViewsAndRepliesPagerChild
import org.thoughtcrime.securesms.stories.viewer.reply.StoryViewsAndRepliesPagerParent
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.fragments.findListener
import org.thoughtcrime.securesms.util.visible
@ -37,7 +37,7 @@ class StoryViewsFragment :
private val storyId: Long
get() = requireArguments().getLong(ARG_STORY_ID)
override fun bindAdapter(adapter: DSLSettingsAdapter) {
override fun bindAdapter(adapter: MappingAdapter) {
StoryViewItem.register(adapter)
val emptyNotice: View = requireView().findViewById(R.id.empty_notice)

Wyświetl plik

@ -1,36 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:viewBindingIgnore="true"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?selectableItemBackground"
android:minHeight="64dp"
android:orientation="horizontal"
android:paddingHorizontal="@dimen/dsl_settings_gutter">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/icon"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center_vertical"
android:background="@drawable/circle_tintable"
android:importantForAccessibility="no"
android:scaleType="centerInside"
app:backgroundTint="@color/signal_colorSurfaceVariant"
app:srcCompat="@drawable/ic_add_members_20"
app:tint="@color/signal_colorOnSurfaceVariant" />
<TextView
android:id="@+id/label"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="16dp"
android:layout_weight="1"
android:text="@string/StorySettingsFragment__new_private_story"
android:textAppearance="@style/Signal.Text.BodyLarge"
android:textColor="@color/signal_colorOnSurface" />
</LinearLayout>

Wyświetl plik

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_overflow"
android:icon="@drawable/ic_more_vert_24"
android:title="@string/OverflowMenu__overflow_menu"
app:showAsAction="always" />
</menu>

Wyświetl plik

@ -3,6 +3,6 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_settings"
android:title="@string/StorySettingsFragment__story_settings"
android:title="@string/StoriesLandingFragment__story_privacy"
app:showAsAction="never" />
</menu>

Wyświetl plik

@ -322,33 +322,19 @@
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit" />
<action
android:id="@+id/action_privacySettings_to_myStorySettings"
app:destination="@id/my_story_settings"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit" />
<action
android:id="@+id/action_privacySettings_to_newPrivateStory"
app:destination="@id/new_story"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit" />
<action
android:id="@+id/action_privacySettings_to_privateStorySettings"
app:destination="@id/private_story_settings"
android:id="@+id/action_privacySettingsFragment_to_storyPrivacySettings"
app:destination="@+id/story_privacy_settings"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit">
<argument
android:name="private_story"
app:argType="org.thoughtcrime.securesms.database.model.DistributionListId"
android:name="title_id"
app:argType="integer"
app:nullable="false" />
</action>
</fragment>
@ -868,10 +854,6 @@
</fragment>
<include app:graph="@navigation/story_privacy_settings" />
<include app:graph="@navigation/my_story_settings" />
<include app:graph="@navigation/private_story_settings" />
<include app:graph="@navigation/new_story" />
</navigation>

Wyświetl plik

@ -1,22 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/story_settings"
app:startDestination="@id/storySettings">
android:id="@+id/story_privacy_settings"
app:startDestination="@id/storiesPrivacySettingsFragment">
<fragment
android:id="@+id/storySettings"
android:name="org.thoughtcrime.securesms.stories.settings.story.StorySettingsFragment"
android:label="story_settings_fragment">
android:id="@+id/storiesPrivacySettingsFragment"
android:name="org.thoughtcrime.securesms.stories.settings.story.StoriesPrivacySettingsFragment"
android:label="stories_privacy_settings_fragment">
<argument
android:name="title_id"
app:argType="integer"
app:nullable="false" />
<action
android:id="@+id/action_storySettings_to_myStorySettings"
android:id="@+id/action_storyPrivacySettings_to_myStorySettings"
app:destination="@id/my_story_settings"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit" />
<action
android:id="@+id/action_storySettings_to_privateStorySettings"
android:id="@+id/action_storyPrivacySettings_to_privateStorySettings"
app:destination="@id/private_story_settings"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
@ -30,18 +36,33 @@
</action>
<action
android:id="@+id/action_storySettings_to_newStory"
app:destination="@id/new_story"
android:id="@+id/action_storyPrivacySettings_to_groupStorySettings"
app:destination="@id/groupStorySettingsFragment"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit" />
app:popExitAnim="@anim/fragment_close_exit">
<argument
android:name="group_id"
app:argType="org.thoughtcrime.securesms.groups.ParcelableGroupId"
app:nullable="false" />
</action>
</fragment>
<fragment
android:id="@+id/groupStorySettingsFragment"
android:name="org.thoughtcrime.securesms.stories.settings.group.GroupStorySettingsFragment"
android:label="group_story_settings_fragment">
<argument
android:name="group_id"
app:argType="org.thoughtcrime.securesms.groups.ParcelableGroupId"
app:nullable="false" />
</fragment>
<include app:graph="@navigation/my_story_settings" />
<include app:graph="@navigation/private_story_settings" />
<include app:graph="@navigation/new_story" />
</navigation>

Wyświetl plik

@ -2597,6 +2597,8 @@
<!-- Preference label for making one-time donations to Signal -->
<string name="preferences__one_time_donation">One-time Donation</string>
<string name="preferences__privacy">Privacy</string>
<!-- Preference label for stories -->
<string name="preferences__stories">Stories</string>
<string name="preferences__mms_user_agent">MMS User Agent</string>
<string name="preferences__advanced_mms_access_point_names">Manual MMS settings</string>
<string name="preferences__mmsc_url">MMSC URL</string>
@ -3922,6 +3924,8 @@
<string name="PrivacySettingsFragment__signal_message_and_calls">Signal messages and calls, always relay calls, and sealed sender</string>
<string name="PrivacySettingsFragment__default_timer_for_new_changes">Default timer for new chats</string>
<string name="PrivacySettingsFragment__set_a_default_disappearing_message_timer_for_all_new_chats_started_by_you">Set a default disappearing message timer for all new chats started by you.</string>
<!-- Summary for stories preference to launch into story privacy settings -->
<string name="PrivacySettingsFragment__manage_your_stories">Manage your stories and who can view them</string>
<!-- AdvancedPrivacySettingsFragment -->
<string name="AdvancedPrivacySettingsFragment__sealed_sender_link" translatable="false">https://signal.org/blog/sealed-sender</string>
@ -4610,6 +4614,8 @@
<string name="ConversationListTabs__stories">Stories</string>
<!-- String for counts above 99 in conversation list tabs -->
<string name="ConversationListTabs__99p">99+</string>
<!-- Menu item on stories landing page -->
<string name="StoriesLandingFragment__story_privacy">Story privacy</string>
<!-- Title for "My Stories" row item in Stories landing page -->
<string name="StoriesLandingFragment__my_stories">My Stories</string>
<!-- Subtitle for "My Stories" row item when user has not added stories -->
@ -4717,14 +4723,6 @@
<string name="StoryGroupReplyItem__copy">Copy</string>
<!-- Context menu item to delete a story response -->
<string name="StoryGroupReplyItem__delete">Delete</string>
<!-- Story settings page title -->
<string name="StorySettingsFragment__story_settings">Story settings</string>
<!-- Story settings private stories heading -->
<string name="StorySettingsFragment__private_stories">Private stories</string>
<!-- Note at bottom of story settings regarding who can see private stories. -->
<string name="StorySettingsFragment__private_stories_can_only_be_viewed">Private stories can only be viewed by the people you add to them. Only you can see the story name.</string>
<!-- Option label for creating a new private story -->
<string name="StorySettingsFragment__new_private_story">New private story</string>
<!-- Page title for My Story options -->
<string name="MyStorySettingsFragment__my_story">My Story</string>
<!-- Section heading for story visibility -->
@ -4979,6 +4977,11 @@
<item quantity="one">Group Story · %1$d viewer</item>
<item quantity="other">Group Story · %1$d viewers</item>
</plurals>
<!-- Label under name for my story -->
<plurals name="ContactSearchItems__my_story_s_dot_d_viewers">
<item quantity="one">%1$s · %2$d viewer</item>
<item quantity="other">%1$s · %2$d viewers</item>
</plurals>
<!-- Label under name for My Story when first sending to my story -->
<string name="ContactSearchItems__tap_to_choose_your_viewers">Tap to choose your viewers</string>
<!-- Label for context menu item to open story settings -->
@ -5093,6 +5096,35 @@
<!-- Story Info context menu label -->
<string name="StoryInfoBottomSheetDialogFragment__info">Info</string>
<!-- StoriesPrivacySettingsFragment -->
<!-- Explanation about how stories are deleted and managed -->
<string name="StoriesPrivacySettingsFragment__stories_automatically_disappear">Stories automatically disappear after 24 hours. Choose who can view your story or create new stories with specific viewers or groups.</string>
<!-- Preference title to turn off stories -->
<string name="StoriesPrivacySettingsFragment__turn_off_stories">Turn off stories</string>
<!-- Preference summary to turn off stories -->
<string name="StoriesPrivacySettingsFragment__if_you_opt_out">If you opt out of stories you will no longer be able to share or view stories.</string>
<!-- Preference title to turn on stories -->
<string name="StoriesPrivacySettingsFragment__turn_on_stories">Turn on stories</string>
<!-- Preference summary to turn on stories -->
<string name="StoriesPrivacySettingsFragment__share_and_view">Share and view stories from others. Stories automatically disappear after 24 hours.</string>
<!-- Dialog title to turn off stories -->
<string name="StoriesPrivacySettingsFragment__turn_off_stories_question">Turn off stories?</string>
<!-- Dialog message to turn off stories -->
<string name="StoriesPrivacySettingsFragment__you_will_no_longer_be_able_to">You will no longer be able to share or view stories. Any stories you have recently sent will still be visible by others until they expire.</string>
<!-- Page title when launched from stories landing screen -->
<string name="StoriesPrivacySettingsFragment__story_privacy">Story privacy</string>
<!-- GroupStorySettingsFragment -->
<!-- Section header for who can view a group story -->
<string name="GroupStorySettingsFragment__who_can_view_this_story">Who can view this story</string>
<!-- Explanation of who can view a group story -->
<string name="GroupStorySettingsFragment__members_of_the_group_s">Members of the group "%1$s" can view and reply to this story. You can update the membership for this chat in the group.</string>
<!-- Preference label for removing this group story -->
<string name="GroupStorySettingsFragment__remove_group_story">Remove group story</string>
<!-- Generic title for overflow menus -->
<string name="OverflowMenu__overflow_menu">Overflow menu</string>
<!-- EOF -->
</resources>

Wyświetl plik

@ -11,6 +11,7 @@ import org.mockito.kotlin.isNull
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
import org.thoughtcrime.securesms.MockCursor
import org.thoughtcrime.securesms.database.model.DistributionListPrivacyMode
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientId
@ -19,7 +20,7 @@ class ContactSearchPagedDataSourceTest {
private val repository: ContactSearchPagedDataSourceRepository = mock()
private val cursor: MockCursor = mock()
private val groupStoryData = ContactSearchData.Story(Recipient.UNKNOWN, 0)
private val groupStoryData = ContactSearchData.Story(Recipient.UNKNOWN, 0, DistributionListPrivacyMode.ALL)
@Before
fun setUp() {
@ -27,6 +28,7 @@ class ContactSearchPagedDataSourceTest {
whenever(repository.getRecipientFromRecipientCursor(cursor)).thenReturn(Recipient.UNKNOWN)
whenever(repository.getRecipientFromThreadCursor(cursor)).thenReturn(Recipient.UNKNOWN)
whenever(repository.getRecipientFromDistributionListCursor(cursor)).thenReturn(Recipient.UNKNOWN)
whenever(repository.getPrivacyModeFromDistributionListCursor(cursor)).thenReturn(DistributionListPrivacyMode.ALL)
whenever(repository.getGroupStories()).thenReturn(emptySet())
whenever(repository.getLatestStorySends(any())).thenReturn(emptyList())
whenever(cursor.moveToPosition(any())).thenCallRealMethod()

Wyświetl plik

@ -0,0 +1,15 @@
package org.signal.core.util
import androidx.annotation.Px
/**
* Converts the given Float DP value into Pixels.
*/
@get:Px
val Float.dp: Float get() = DimensionUnit.DP.toPixels(this)
/**
* Converts the given Int DP value into Pixels
*/
@get:Px
val Int.dp: Int get() = this.toFloat().dp.toInt()