From f341e02fb7c5a53cd256c0c41d68ce15f65bb597 Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Thu, 18 Aug 2022 10:11:42 -0300 Subject: [PATCH] Story privacy screen updates. --- .../flow/GiftFlowConfirmationFragment.kt | 4 +- .../gifts/flow/GiftFlowStartFragment.kt | 4 +- .../featured/SelectFeaturedBadgeFragment.kt | 4 +- .../self/overview/BadgesOverviewFragment.kt | 4 +- .../settings/DSLSettingsFragment.kt | 41 ++++- .../settings/app/AppSettingsFragment.kt | 4 +- .../app/account/AccountSettingsFragment.kt | 4 +- .../appearance/AppearanceSettingsFragment.kt | 4 +- .../app/chats/ChatsSettingsFragment.kt | 4 +- .../app/chats/sms/SmsSettingsFragment.kt | 4 +- .../data/DataAndStorageSettingsFragment.kt | 4 +- .../settings/app/help/HelpSettingsFragment.kt | 4 +- .../app/internal/InternalSettingsFragment.kt | 4 +- .../donor/DonorErrorConfigurationFragment.kt | 4 +- .../NotificationsSettingsFragment.kt | 4 +- .../profiles/AddAllowedMembersFragment.kt | 4 +- .../EditNotificationProfileFragment.kt | 4 +- .../NotificationProfileDetailsFragment.kt | 4 +- .../profiles/NotificationProfilesFragment.kt | 4 +- .../app/privacy/PrivacySettingsFragment.kt | 55 +----- .../app/privacy/PrivacySettingsRepository.kt | 7 - .../app/privacy/PrivacySettingsState.kt | 5 +- .../app/privacy/PrivacySettingsViewModel.kt | 16 +- .../AdvancedPrivacySettingsFragment.kt | 4 +- .../expire/ExpireTimerSettingsFragment.kt | 4 +- .../manage/ManageDonationsFragment.kt | 4 +- .../detail/DonationReceiptDetailFragment.kt | 4 +- .../subscribe/SubscribeFragment.kt | 4 +- .../ConversationSettingsFragment.kt | 4 +- .../InternalConversationSettingsFragment.kt | 4 +- .../PermissionsSettingsFragment.kt | 4 +- .../SoundsAndNotificationsSettingsFragment.kt | 4 +- .../CustomNotificationsSettingsFragment.kt | 4 +- .../contacts/paged/ContactSearchData.kt | 3 +- .../contacts/paged/ContactSearchItems.kt | 80 ++++++--- .../paged/ContactSearchPagedDataSource.kt | 7 +- .../ContactSearchPagedDataSourceRepository.kt | 7 +- .../contacts/paged/ContactSearchViewModel.kt | 3 +- .../database/DistributionListDatabase.kt | 1 + .../securesms/groups/ParcelableGroupId.java | 2 +- .../v2/stories/ChooseGroupStoryBottomSheet.kt | 7 + .../pnp/WhoCanSeeMyPhoneNumberFragment.kt | 4 +- .../ShareableGroupLinkFragment.kt | 4 +- .../SafetyNumberReviewConnectionsFragment.kt | 4 +- .../thoughtcrime/securesms/stories/Stories.kt | 11 +- .../stories/landing/StoriesLandingFragment.kt | 6 +- .../securesms/stories/my/MyStoriesFragment.kt | 4 +- .../stories/settings/StorySettingsActivity.kt | 4 +- .../create/CreateStoryWithViewersFragment.kt | 4 +- .../{story => custom}/PrivateStoryItem.kt | 37 ++-- .../custom/PrivateStorySettingsFragment.kt | 5 +- .../settings/group/GroupConversationData.kt | 11 ++ .../group/GroupStorySettingsFragment.kt | 102 +++++++++++ .../group/GroupStorySettingsRepository.kt | 24 +++ .../settings/group/GroupStorySettingsState.kt | 9 + .../group/GroupStorySettingsViewModel.kt | 45 +++++ .../settings/my/MyStorySettingsFragment.kt | 4 +- .../story/StoriesPrivacySettingsFragment.kt | 168 ++++++++++++++++++ .../story/StoriesPrivacySettingsRepository.kt | 16 ++ .../story/StoriesPrivacySettingsState.kt | 8 + .../story/StoriesPrivacySettingsViewModel.kt | 82 +++++++++ .../settings/story/StorySettingsFragment.kt | 73 -------- .../settings/story/StorySettingsRepository.kt | 14 -- .../settings/story/StorySettingsState.kt | 7 - .../settings/story/StorySettingsViewModel.kt | 36 ---- .../viewer/views/StoryViewsFragment.kt | 4 +- .../layout/stories_private_story_new_item.xml | 36 ---- app/src/main/res/menu/story_group_menu.xml | 9 + app/src/main/res/menu/story_landing_menu.xml | 2 +- app/src/main/res/navigation/app_settings.xml | 30 +--- ...ettings.xml => story_privacy_settings.xml} | 47 +++-- app/src/main/res/values/strings.xml | 48 ++++- .../paged/ContactSearchPagedDataSourceTest.kt | 4 +- .../core/util/DimensionUnitExtensions.kt | 15 ++ 74 files changed, 800 insertions(+), 423 deletions(-) rename app/src/main/java/org/thoughtcrime/securesms/stories/settings/{story => custom}/PrivateStoryItem.kt (79%) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/stories/settings/group/GroupConversationData.kt create mode 100644 app/src/main/java/org/thoughtcrime/securesms/stories/settings/group/GroupStorySettingsFragment.kt create mode 100644 app/src/main/java/org/thoughtcrime/securesms/stories/settings/group/GroupStorySettingsRepository.kt create mode 100644 app/src/main/java/org/thoughtcrime/securesms/stories/settings/group/GroupStorySettingsState.kt create mode 100644 app/src/main/java/org/thoughtcrime/securesms/stories/settings/group/GroupStorySettingsViewModel.kt create mode 100644 app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StoriesPrivacySettingsFragment.kt create mode 100644 app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StoriesPrivacySettingsRepository.kt create mode 100644 app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StoriesPrivacySettingsState.kt create mode 100644 app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StoriesPrivacySettingsViewModel.kt delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StorySettingsFragment.kt delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StorySettingsRepository.kt delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StorySettingsState.kt delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StorySettingsViewModel.kt delete mode 100644 app/src/main/res/layout/stories_private_story_new_item.xml create mode 100644 app/src/main/res/menu/story_group_menu.xml rename app/src/main/res/navigation/{story_settings.xml => story_privacy_settings.xml} (50%) create mode 100644 core-util/src/main/java/org/signal/core/util/DimensionUnitExtensions.kt diff --git a/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/flow/GiftFlowConfirmationFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/flow/GiftFlowConfirmationFragment.kt index a4461e6f2..2b1410bb0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/flow/GiftFlowConfirmationFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/flow/GiftFlowConfirmationFragment.kt @@ -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() private val debouncer = Debouncer(100L) - override fun bindAdapter(adapter: DSLSettingsAdapter) { + override fun bindAdapter(adapter: MappingAdapter) { RecipientPreference.register(adapter) GiftRowItem.register(adapter) diff --git a/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/flow/GiftFlowStartFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/flow/GiftFlowStartFragment.kt index 85a8a3119..5c029c8c4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/flow/GiftFlowStartFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/badges/gifts/flow/GiftFlowStartFragment.kt @@ -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) diff --git a/app/src/main/java/org/thoughtcrime/securesms/badges/self/featured/SelectFeaturedBadgeFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/badges/self/featured/SelectFeaturedBadgeFragment.kt index 1e2e9bc33..35cb0eb38 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/badges/self/featured/SelectFeaturedBadgeFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/badges/self/featured/SelectFeaturedBadgeFragment.kt @@ -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) diff --git a/app/src/main/java/org/thoughtcrime/securesms/badges/self/overview/BadgesOverviewFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/badges/self/overview/BadgesOverviewFragment.kt index 81592a672..fb2f0dd8f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/badges/self/overview/BadgesOverviewFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/badges/self/overview/BadgesOverviewFragment.kt @@ -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)) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/DSLSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/DSLSettingsFragment.kt index 8a3b3f0aa..1cacaf9cf 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/DSLSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/DSLSettingsFragment.kt @@ -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 = when { + settingsAdapters.size > 1 -> ConcatAdapter(config, *settingsAdapters) + settingsAdapters.size == 1 -> settingsAdapters.first() + else -> error("Require one or more settings adapters.") + } recyclerView = view.findViewById(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 { + 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 { diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsFragment.kt index 9565989ce..85e918d98 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/AppSettingsFragment.kt @@ -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)) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsFragment.kt index 28dae4a9d..7a9f47e7e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/account/AccountSettingsFragment.kt @@ -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 -> diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/appearance/AppearanceSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/appearance/AppearanceSettingsFragment.kt index 72b71a530..1b6d3ac00 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/appearance/AppearanceSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/appearance/AppearanceSettingsFragment.kt @@ -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 -> diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/ChatsSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/ChatsSettingsFragment.kt index 1481c300e..baf9d51ea 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/ChatsSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/ChatsSettingsFragment.kt @@ -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] diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/sms/SmsSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/sms/SmsSettingsFragment.kt index c4a342756..d08fb9244 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/sms/SmsSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/chats/sms/SmsSettingsFragment.kt @@ -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) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/data/DataAndStorageSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/data/DataAndStorageSettingsFragment.kt index 961c7e121..8411ece67 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/data/DataAndStorageSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/data/DataAndStorageSettingsFragment.kt @@ -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) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/help/HelpSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/help/HelpSettingsFragment.kt index 54f0b4837..dbf4e296b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/help/HelpSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/help/HelpSettingsFragment.kt @@ -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()) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/InternalSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/InternalSettingsFragment.kt index e8ea176d8..8efc61224 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/InternalSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/InternalSettingsFragment.kt @@ -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] diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/donor/DonorErrorConfigurationFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/donor/DonorErrorConfigurationFragment.kt index 905cecc3f..0f25c63e2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/donor/DonorErrorConfigurationFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/internal/donor/DonorErrorConfigurationFragment.kt @@ -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()) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/NotificationsSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/NotificationsSettingsFragment.kt index a6fbcd004..8d8b69d5e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/NotificationsSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/NotificationsSettingsFragment.kt @@ -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) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/AddAllowedMembersFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/AddAllowedMembersFragment.kt index 8512b2f41..5069a56ae 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/AddAllowedMembersFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/AddAllowedMembersFragment.kt @@ -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) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/EditNotificationProfileFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/EditNotificationProfileFragment.kt index bc33d7f8c..a1551e616 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/EditNotificationProfileFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/EditNotificationProfileFragment.kt @@ -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 -> diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/NotificationProfileDetailsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/NotificationProfileDetailsFragment.kt index da22fa95c..ad4819658 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/NotificationProfileDetailsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/NotificationProfileDetailsFragment.kt @@ -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) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/NotificationProfilesFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/NotificationProfilesFragment.kt index 8860dea67..1f0dc884f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/NotificationProfilesFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/NotificationProfilesFragment.kt @@ -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) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/PrivacySettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/PrivacySettingsFragment.kt index d38a4ebb5..206975a63 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/PrivacySettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/PrivacySettingsFragment.kt @@ -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)) } ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/PrivacySettingsRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/PrivacySettingsRepository.kt index 3c2986eab..a955ca8e9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/PrivacySettingsRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/PrivacySettingsRepository.kt @@ -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) -> Unit) { - SignalExecutors.BOUNDED.execute { - consumer(SignalDatabase.distributionLists.getCustomListsForUi()) - } - } - fun syncReadReceiptState() { SignalExecutors.BOUNDED.execute { SignalDatabase.recipients.markNeedsSync(Recipient.self().id) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/PrivacySettingsState.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/PrivacySettingsState.kt index 0ecd65500..14f6e5591 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/PrivacySettingsState.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/PrivacySettingsState.kt @@ -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, - val isStoriesEnabled: Boolean + val universalExpireTimer: Int ) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/PrivacySettingsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/PrivacySettingsViewModel.kt index d9dafbcc4..a9e055c75 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/PrivacySettingsViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/PrivacySettingsViewModel.kt @@ -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( diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/advanced/AdvancedPrivacySettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/advanced/AdvancedPrivacySettingsFragment.kt index 37957b1e0..68d2e0739 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/advanced/AdvancedPrivacySettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/advanced/AdvancedPrivacySettingsFragment.kt @@ -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) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/expire/ExpireTimerSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/expire/ExpireTimerSettingsFragment.kt index 960eb3f0a..7b2eb154a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/expire/ExpireTimerSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/privacy/expire/ExpireTimerSettingsFragment.kt @@ -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()) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/manage/ManageDonationsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/manage/ManageDonationsFragment.kt index c92a94302..ac56d3497 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/manage/ManageDonationsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/manage/ManageDonationsFragment.kt @@ -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) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/receipts/detail/DonationReceiptDetailFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/receipts/detail/DonationReceiptDetailFragment.kt index d7c654c0c..9cc0ec5c9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/receipts/detail/DonationReceiptDetailFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/receipts/detail/DonationReceiptDetailFragment.kt @@ -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) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/subscribe/SubscribeFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/subscribe/SubscribeFragment.kt index 361b0fe7f..df862602e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/subscribe/SubscribeFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/subscription/subscribe/SubscribeFragment.kt @@ -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() diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsFragment.kt index a89b1505f..04b436d37 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsFragment.kt @@ -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) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/InternalConversationSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/InternalConversationSettingsFragment.kt index 1fdbbdce7..f8226e098 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/InternalConversationSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/InternalConversationSettingsFragment.kt @@ -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()) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/permissions/PermissionsSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/permissions/PermissionsSettingsFragment.kt index 673cc2415..7ba7361e0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/permissions/PermissionsSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/permissions/PermissionsSettingsFragment.kt @@ -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()) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/sounds/SoundsAndNotificationsSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/sounds/SoundsAndNotificationsSettingsFragment.kt index 5ad9e9ea4..35c6c5c58 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/sounds/SoundsAndNotificationsSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/sounds/SoundsAndNotificationsSettingsFragment.kt @@ -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()) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/sounds/custom/CustomNotificationsSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/sounds/custom/CustomNotificationsSettingsFragment.kt index 4c6f95991..914f7d178 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/sounds/custom/CustomNotificationsSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/sounds/custom/CustomNotificationsSettingsFragment.kt @@ -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) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchData.kt b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchData.kt index 0e990db93..c7651fcc3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchData.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchData.kt @@ -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. diff --git a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchItems.kt b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchItems.kt index 5fa253740..5732bf1df 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchItems.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchItems.kt @@ -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(itemView, displayCheckBox, onClick) { + private class StoryViewHolder( + itemView: View, + displayCheckBox: Boolean, + onClick: StoryClickListener, + private val storyContextMenuCallbacks: StoryContextMenuCallbacks? + ) : BaseRecipientViewHolder(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 = 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 { + private fun getMyStoryContextMenuActions(model: StoryModel, callbacks: StoryContextMenuCallbacks): List { 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 { + private fun getGroupStoryContextMenuActions(model: StoryModel, callbacks: StoryContextMenuCallbacks): List { 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 { + private fun getPrivateStoryContextMenuActions(model: StoryModel, callbacks: StoryContextMenuCallbacks): List { 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) + } + } } /** diff --git a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSource.kt b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSource.kt index 683c98150..a3c9f9d2e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSource.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSource.kt @@ -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)) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSourceRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSourceRepository.kt index 938377a03..cc212fb7d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSourceRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSourceRepository.kt @@ -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 { 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() } diff --git a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchViewModel.kt index feb2e0c84..ac79eb476 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchViewModel.kt @@ -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) } ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/DistributionListDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/database/DistributionListDatabase.kt index daf547d10..86d021b70 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/DistributionListDatabase.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/DistributionListDatabase.kt @@ -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( diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/ParcelableGroupId.java b/app/src/main/java/org/thoughtcrime/securesms/groups/ParcelableGroupId.java index 9ff5fcb88..9fdb13267 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/ParcelableGroupId.java +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/ParcelableGroupId.java @@ -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); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/stories/ChooseGroupStoryBottomSheet.kt b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/stories/ChooseGroupStoryBottomSheet.kt index 2f31baa92..e91ebd963 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/stories/ChooseGroupStoryBottomSheet.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/stories/ChooseGroupStoryBottomSheet.kt @@ -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 { + return bundle.getParcelableArrayList(RESULT_SET)!! + } + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/profiles/edit/pnp/WhoCanSeeMyPhoneNumberFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/profiles/edit/pnp/WhoCanSeeMyPhoneNumberFragment.kt index 5c1425636..0eac2de57 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/profiles/edit/pnp/WhoCanSeeMyPhoneNumberFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/profiles/edit/pnp/WhoCanSeeMyPhoneNumberFragment.kt @@ -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 { diff --git a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/sharablegrouplink/ShareableGroupLinkFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/sharablegrouplink/ShareableGroupLinkFragment.kt index 695c5f15e..204048765 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/sharablegrouplink/ShareableGroupLinkFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/sharablegrouplink/ShareableGroupLinkFragment.kt @@ -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) -> diff --git a/app/src/main/java/org/thoughtcrime/securesms/safety/review/SafetyNumberReviewConnectionsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/safety/review/SafetyNumberReviewConnectionsFragment.kt index fd48736a2..82c68e86d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/safety/review/SafetyNumberReviewConnectionsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/safety/review/SafetyNumberReviewConnectionsFragment.kt @@ -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) diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/Stories.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/Stories.kt index 1a027747c..6296b616a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/Stories.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/Stories.kt @@ -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) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/landing/StoriesLandingFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/landing/StoriesLandingFragment.kt index f69952dd4..7efdd1199 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/landing/StoriesLandingFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/landing/StoriesLandingFragment.kt @@ -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) diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/my/MyStoriesFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/my/MyStoriesFragment.kt index afa05fd94..b5c0a4342 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/my/MyStoriesFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/my/MyStoriesFragment.kt @@ -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( diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/settings/StorySettingsActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/StorySettingsActivity.kt index cf78095bc..b0936a088 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/settings/StorySettingsActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/StorySettingsActivity.kt @@ -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)) } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/settings/create/CreateStoryWithViewersFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/create/CreateStoryWithViewersFragment.kt index ebf6d41f1..4f455b98e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/settings/create/CreateStoryWithViewersFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/create/CreateStoryWithViewersFragment.kt @@ -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 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) diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/PrivateStoryItem.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/custom/PrivateStoryItem.kt similarity index 79% rename from app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/PrivateStoryItem.kt rename to app/src/main/java/org/thoughtcrime/securesms/stories/settings/custom/PrivateStoryItem.kt index 83902ef93..936c70c2f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/PrivateStoryItem.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/custom/PrivateStoryItem.kt @@ -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() { - 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() { 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(itemView) { - override fun bind(model: NewModel) { - itemView.setOnClickListener { model.onClick() } - } - } - private class AddViewerViewHolder(itemView: View) : MappingViewHolder(itemView) { override fun bind(model: AddViewerModel) { itemView.setOnClickListener { model.onClick() } diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/settings/custom/PrivateStorySettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/custom/PrivateStorySettingsFragment.kt index bc2668eaa..c45fc0ebd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/settings/custom/PrivateStorySettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/custom/PrivateStorySettingsFragment.kt @@ -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) diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/settings/group/GroupConversationData.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/group/GroupConversationData.kt new file mode 100644 index 000000000..b812833f2 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/group/GroupConversationData.kt @@ -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 +) diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/settings/group/GroupStorySettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/group/GroupStorySettingsFragment.kt new file mode 100644 index 000000000..f480d213a --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/group/GroupStorySettingsFragment.kt @@ -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() + } + ) + } + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/settings/group/GroupStorySettingsRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/group/GroupStorySettingsRepository.kt new file mode 100644 index 000000000..2507b64a7 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/group/GroupStorySettingsRepository.kt @@ -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 { + return Single.fromCallable { + val recipientId = SignalDatabase.recipients.getByGroupId(groupId).get() + val threadId = SignalDatabase.threads.getThreadIdFor(recipientId) ?: -1L + + GroupConversationData(recipientId, threadId) + }.subscribeOn(Schedulers.io()) + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/settings/group/GroupStorySettingsState.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/group/GroupStorySettingsState.kt new file mode 100644 index 000000000..016cf3b42 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/group/GroupStorySettingsState.kt @@ -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 = emptyList(), + val removed: Boolean = false +) diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/settings/group/GroupStorySettingsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/group/GroupStorySettingsViewModel.kt new file mode 100644 index 000000000..2fc8f5603 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/group/GroupStorySettingsViewModel.kt @@ -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 = 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 { + return repository.getConversationData(groupId).observeOn(AndroidSchedulers.mainThread()) + } + + class Factory(private val parcelableGroupId: ParcelableGroupId) : ViewModelProvider.Factory { + override fun create(modelClass: Class): T { + return modelClass.cast(GroupStorySettingsViewModel(ParcelableGroupId.get(parcelableGroupId)!!)) as T + } + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/settings/my/MyStorySettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/my/MyStorySettingsFragment.kt index 6a3467a89..86aa96127 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/settings/my/MyStorySettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/my/MyStorySettingsFragment.kt @@ -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()) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StoriesPrivacySettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StoriesPrivacySettingsFragment.kt new file mode 100644 index 000000000..3070657d0 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StoriesPrivacySettingsFragment.kt @@ -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 { + return arrayOf(DSLSettingsAdapter(), PagingMappingAdapter(), 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, + 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) + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StoriesPrivacySettingsRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StoriesPrivacySettingsRepository.kt new file mode 100644 index 000000000..05111acb5 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StoriesPrivacySettingsRepository.kt @@ -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): Completable { + return Completable.fromCallable { + groups + .map { Recipient.resolved(it) } + .forEach { SignalDatabase.groups.markDisplayAsStory(it.requireGroupId()) } + } + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StoriesPrivacySettingsState.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StoriesPrivacySettingsState.kt new file mode 100644 index 000000000..35ace1d3d --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StoriesPrivacySettingsState.kt @@ -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 = emptyList() +) diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StoriesPrivacySettingsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StoriesPrivacySettingsViewModel.kt new file mode 100644 index 000000000..bdb077e10 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StoriesPrivacySettingsViewModel.kt @@ -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() + + val state: Flowable = store.stateFlowable.observeOn(AndroidSchedulers.mainThread()) + val pagingController = ProxyPagingController() + val headerActionRequests: Observable = 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) { + disposables += repository.markGroupsAsStories(recipientIds).subscribe { + pagingController.onDataInvalidated() + } + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StorySettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StorySettingsFragment.kt deleted file mode 100644 index fb577601e..000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StorySettingsFragment.kt +++ /dev/null @@ -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)) - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StorySettingsRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StorySettingsRepository.kt deleted file mode 100644 index b75cd3276..000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StorySettingsRepository.kt +++ /dev/null @@ -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> { - return Single.fromCallable { - SignalDatabase.distributionLists.getCustomListsForUi() - }.subscribeOn(Schedulers.io()) - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StorySettingsState.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StorySettingsState.kt deleted file mode 100644 index c600bf1df..000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StorySettingsState.kt +++ /dev/null @@ -1,7 +0,0 @@ -package org.thoughtcrime.securesms.stories.settings.story - -import org.thoughtcrime.securesms.database.model.DistributionListPartialRecord - -data class StorySettingsState( - val privateStories: List = emptyList() -) diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StorySettingsViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StorySettingsViewModel.kt deleted file mode 100644 index cbf2eb6d3..000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/settings/story/StorySettingsViewModel.kt +++ /dev/null @@ -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 = 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 create(modelClass: Class): T { - return modelClass.cast(StorySettingsViewModel(repository)) as T - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/views/StoryViewsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/views/StoryViewsFragment.kt index e27580fe1..0c26c6a30 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/views/StoryViewsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/views/StoryViewsFragment.kt @@ -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) diff --git a/app/src/main/res/layout/stories_private_story_new_item.xml b/app/src/main/res/layout/stories_private_story_new_item.xml deleted file mode 100644 index 3a2195114..000000000 --- a/app/src/main/res/layout/stories_private_story_new_item.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/menu/story_group_menu.xml b/app/src/main/res/menu/story_group_menu.xml new file mode 100644 index 000000000..8fc8276ca --- /dev/null +++ b/app/src/main/res/menu/story_group_menu.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/story_landing_menu.xml b/app/src/main/res/menu/story_landing_menu.xml index 11555c7b8..c376b1964 100644 --- a/app/src/main/res/menu/story_landing_menu.xml +++ b/app/src/main/res/menu/story_landing_menu.xml @@ -3,6 +3,6 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> \ No newline at end of file diff --git a/app/src/main/res/navigation/app_settings.xml b/app/src/main/res/navigation/app_settings.xml index 51d1b5417..bf436498f 100644 --- a/app/src/main/res/navigation/app_settings.xml +++ b/app/src/main/res/navigation/app_settings.xml @@ -322,33 +322,19 @@ app:exitAnim="@anim/fragment_open_exit" app:popEnterAnim="@anim/fragment_close_enter" app:popExitAnim="@anim/fragment_close_exit" /> + - - - @@ -868,10 +854,6 @@ + - - - - - \ No newline at end of file diff --git a/app/src/main/res/navigation/story_settings.xml b/app/src/main/res/navigation/story_privacy_settings.xml similarity index 50% rename from app/src/main/res/navigation/story_settings.xml rename to app/src/main/res/navigation/story_privacy_settings.xml index c30811989..b74eafe36 100644 --- a/app/src/main/res/navigation/story_settings.xml +++ b/app/src/main/res/navigation/story_privacy_settings.xml @@ -1,22 +1,28 @@ + android:id="@+id/story_privacy_settings" + app:startDestination="@id/storiesPrivacySettingsFragment"> + android:id="@+id/storiesPrivacySettingsFragment" + android:name="org.thoughtcrime.securesms.stories.settings.story.StoriesPrivacySettingsFragment" + android:label="stories_privacy_settings_fragment"> + + + + app:popExitAnim="@anim/fragment_close_exit"> + + + + + + + + + - - - \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8a93cc060..8e6e230a0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2597,6 +2597,8 @@ One-time Donation Privacy + + Stories MMS User Agent Manual MMS settings MMSC URL @@ -3922,6 +3924,8 @@ Signal messages and calls, always relay calls, and sealed sender Default timer for new chats Set a default disappearing message timer for all new chats started by you. + + Manage your stories and who can view them https://signal.org/blog/sealed-sender @@ -4610,6 +4614,8 @@ Stories 99+ + + Story privacy My Stories @@ -4717,14 +4723,6 @@ Copy Delete - - Story settings - - Private stories - - Private stories can only be viewed by the people you add to them. Only you can see the story name. - - New private story My Story @@ -4979,6 +4977,11 @@ Group Story · %1$d viewer Group Story · %1$d viewers + + + %1$s · %2$d viewer + %1$s · %2$d viewers + Tap to choose your viewers @@ -5093,6 +5096,35 @@ Info + + + Stories automatically disappear after 24 hours. Choose who can view your story or create new stories with specific viewers or groups. + + Turn off stories + + If you opt out of stories you will no longer be able to share or view stories. + + Turn on stories + + Share and view stories from others. Stories automatically disappear after 24 hours. + + Turn off stories? + + 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. + + Story privacy + + + + Who can view this story + + Members of the group "%1$s" can view and reply to this story. You can update the membership for this chat in the group. + + Remove group story + + + Overflow menu + diff --git a/app/src/test/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSourceTest.kt b/app/src/test/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSourceTest.kt index bb4073886..a384d72fa 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSourceTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchPagedDataSourceTest.kt @@ -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() diff --git a/core-util/src/main/java/org/signal/core/util/DimensionUnitExtensions.kt b/core-util/src/main/java/org/signal/core/util/DimensionUnitExtensions.kt new file mode 100644 index 000000000..b403bcb25 --- /dev/null +++ b/core-util/src/main/java/org/signal/core/util/DimensionUnitExtensions.kt @@ -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() \ No newline at end of file