From 176a70507963e9c3be2ae424fbefb38e84e5fc1f Mon Sep 17 00:00:00 2001 From: Alex Hart Date: Thu, 8 Sep 2022 17:25:01 -0300 Subject: [PATCH] Add PNP Listing Wiring. --- .../components/ViewBinderDelegate.kt | 34 +++++++++++++++++++ .../profiles/edit/EditProfileFragment.java | 30 ++++++++++++---- .../pnp/WhoCanSeeMyPhoneNumberFragment.kt | 28 ++++++++++++++- .../pnp/WhoCanSeeMyPhoneNumberRepository.kt | 31 +++++++++++++++++ .../pnp/WhoCanSeeMyPhoneNumberViewModel.kt | 8 ++++- .../who_can_see_my_phone_number_fragment.xml | 30 ++++++++++++++++ 6 files changed, 153 insertions(+), 8 deletions(-) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/components/ViewBinderDelegate.kt create mode 100644 app/src/main/java/org/thoughtcrime/securesms/profiles/edit/pnp/WhoCanSeeMyPhoneNumberRepository.kt create mode 100644 app/src/main/res/layout/who_can_see_my_phone_number_fragment.xml diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/ViewBinderDelegate.kt b/app/src/main/java/org/thoughtcrime/securesms/components/ViewBinderDelegate.kt new file mode 100644 index 0000000000..bbe273bff2 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/components/ViewBinderDelegate.kt @@ -0,0 +1,34 @@ +package org.thoughtcrime.securesms.components + +import android.view.View +import androidx.fragment.app.Fragment +import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.viewbinding.ViewBinding +import org.whispersystems.signalservice.api.util.Preconditions +import kotlin.reflect.KProperty + +/** + * ViewBinderDelegate which enforces the "best practices" for maintaining a reference to a view binding given by + * Android official documentation. + */ +class ViewBinderDelegate(private val bindingFactory: (View) -> T) : DefaultLifecycleObserver { + + private var binding: T? = null + + operator fun getValue(thisRef: Fragment, property: KProperty<*>): T { + Preconditions.checkState(thisRef.viewLifecycleOwner.lifecycle.currentState.isAtLeast(Lifecycle.State.CREATED)) + + if (binding == null) { + thisRef.viewLifecycleOwner.lifecycle.addObserver(this@ViewBinderDelegate) + binding = bindingFactory(thisRef.requireView()) + } + + return binding!! + } + + override fun onDestroy(owner: LifecycleOwner) { + binding = null + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/profiles/edit/EditProfileFragment.java b/app/src/main/java/org/thoughtcrime/securesms/profiles/edit/EditProfileFragment.java index 9456fcc72f..02b313a164 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/profiles/edit/EditProfileFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/profiles/edit/EditProfileFragment.java @@ -19,7 +19,6 @@ import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import androidx.core.content.ContextCompat; import androidx.lifecycle.ViewModelProvider; -import androidx.lifecycle.ViewModelProviders; import androidx.navigation.Navigation; import com.airbnb.lottie.SimpleColorFilter; @@ -36,8 +35,11 @@ import org.thoughtcrime.securesms.avatar.picker.AvatarPickerFragment; import org.thoughtcrime.securesms.databinding.ProfileCreateFragmentBinding; import org.thoughtcrime.securesms.groups.GroupId; import org.thoughtcrime.securesms.groups.ParcelableGroupId; +import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues; +import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.mediasend.Media; import org.thoughtcrime.securesms.mms.GlideApp; +import org.thoughtcrime.securesms.profiles.edit.pnp.WhoCanSeeMyPhoneNumberFragment; import org.thoughtcrime.securesms.profiles.manage.EditProfileNameFragment; import org.thoughtcrime.securesms.providers.BlobProvider; import org.thoughtcrime.securesms.util.CommunicationActions; @@ -59,9 +61,9 @@ import static org.thoughtcrime.securesms.profiles.edit.EditProfileActivity.SHOW_ */ public class EditProfileFragment extends LoggingFragment { - private static final String TAG = Log.tag(EditProfileFragment.class); - private static final int MAX_DESCRIPTION_GLYPHS = 480; - private static final int MAX_DESCRIPTION_BYTES = 8192; + private static final String TAG = Log.tag(EditProfileFragment.class); + private static final int MAX_DESCRIPTION_GLYPHS = 480; + private static final int MAX_DESCRIPTION_BYTES = 8192; private Intent nextIntent; @@ -209,10 +211,15 @@ public class EditProfileFragment extends LoggingFragment { binding.profileDescriptionText.setOnLinkClickListener(v -> CommunicationActions.openBrowserLink(requireContext(), getString(R.string.EditProfileFragment__support_link))); if (FeatureFlags.phoneNumberPrivacy()) { + getParentFragmentManager().setFragmentResultListener(WhoCanSeeMyPhoneNumberFragment.REQUEST_KEY, getViewLifecycleOwner(), (requestKey, result) -> { + if (WhoCanSeeMyPhoneNumberFragment.REQUEST_KEY.equals(requestKey)) { + presentWhoCanFindMeDescription(SignalStore.phoneNumberPrivacy().getPhoneNumberListingMode()); + } + }); + binding.whoCanFindMeContainer.setVisibility(View.VISIBLE); binding.whoCanFindMeContainer.setOnClickListener(v -> SafeNavigation.safeNavigate(Navigation.findNavController(v), EditProfileFragmentDirections.actionCreateProfileFragmentToPhoneNumberPrivacy())); - // TODO [alex] -- Where does this value come from? - binding.whoCanFindMeDescription.setText(R.string.PhoneNumberPrivacy_everyone); + presentWhoCanFindMeDescription(SignalStore.phoneNumberPrivacy().getPhoneNumberListingMode()); } } @@ -279,6 +286,17 @@ public class EditProfileFragment extends LoggingFragment { } } + private void presentWhoCanFindMeDescription(PhoneNumberPrivacyValues.PhoneNumberListingMode phoneNumberListingMode) { + switch (phoneNumberListingMode) { + case LISTED: + binding.whoCanFindMeDescription.setText(R.string.PhoneNumberPrivacy_everyone); + break; + case UNLISTED: + binding.whoCanFindMeDescription.setText(R.string.PhoneNumberPrivacy_nobody); + break; + } + } + private void startAvatarSelection() { if (viewModel.isGroup()) { Parcelable groupId = ParcelableGroupId.from(viewModel.getGroupId()); 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 0eac2de578..68661bcbe2 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 @@ -1,11 +1,17 @@ package org.thoughtcrime.securesms.profiles.edit.pnp +import android.os.Bundle +import androidx.fragment.app.setFragmentResult import androidx.fragment.app.viewModels +import androidx.navigation.fragment.findNavController +import io.reactivex.rxjava3.kotlin.subscribeBy import org.thoughtcrime.securesms.R +import org.thoughtcrime.securesms.components.ViewBinderDelegate 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.databinding.WhoCanSeeMyPhoneNumberFragmentBinding import org.thoughtcrime.securesms.util.FeatureFlags import org.thoughtcrime.securesms.util.LifecycleDisposable import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter @@ -13,17 +19,37 @@ import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter /** * Allows the user to select who can see their phone number during registration. */ -class WhoCanSeeMyPhoneNumberFragment : DSLSettingsFragment(titleId = R.string.WhoCanSeeMyPhoneNumberFragment__who_can_find_me_by_number) { +class WhoCanSeeMyPhoneNumberFragment : DSLSettingsFragment( + titleId = R.string.WhoCanSeeMyPhoneNumberFragment__who_can_find_me_by_number, + layoutId = R.layout.who_can_see_my_phone_number_fragment +) { + + companion object { + /** + * Components can listen to this result to know when the user hit the submit button. + */ + const val REQUEST_KEY = "who_can_see_my_phone_number_key" + } private val viewModel: WhoCanSeeMyPhoneNumberViewModel by viewModels() private val lifecycleDisposable = LifecycleDisposable() + private val binding by ViewBinderDelegate(WhoCanSeeMyPhoneNumberFragmentBinding::bind) + override fun bindAdapter(adapter: MappingAdapter) { require(FeatureFlags.phoneNumberPrivacy()) lifecycleDisposable += viewModel.state.subscribe { adapter.submitList(getConfiguration(it).toMappingModelList()) } + + binding.save.setOnClickListener { + binding.save.isEnabled = false + viewModel.onSave().subscribeBy(onComplete = { + setFragmentResult(REQUEST_KEY, Bundle()) + findNavController().popBackStack() + }) + } } private fun getConfiguration(state: WhoCanSeeMyPhoneNumberState): DSLConfiguration { diff --git a/app/src/main/java/org/thoughtcrime/securesms/profiles/edit/pnp/WhoCanSeeMyPhoneNumberRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/profiles/edit/pnp/WhoCanSeeMyPhoneNumberRepository.kt new file mode 100644 index 0000000000..df76378886 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/profiles/edit/pnp/WhoCanSeeMyPhoneNumberRepository.kt @@ -0,0 +1,31 @@ +package org.thoughtcrime.securesms.profiles.edit.pnp + +import io.reactivex.rxjava3.core.Completable +import org.thoughtcrime.securesms.dependencies.ApplicationDependencies +import org.thoughtcrime.securesms.jobs.RefreshAttributesJob +import org.thoughtcrime.securesms.keyvalue.PhoneNumberPrivacyValues +import org.thoughtcrime.securesms.keyvalue.SignalStore + +/** + * Manages the current phone-number listing state. + */ +class WhoCanSeeMyPhoneNumberRepository { + + fun getCurrentState(): WhoCanSeeMyPhoneNumberState { + return when (SignalStore.phoneNumberPrivacy().phoneNumberListingMode) { + PhoneNumberPrivacyValues.PhoneNumberListingMode.LISTED -> WhoCanSeeMyPhoneNumberState.EVERYONE + PhoneNumberPrivacyValues.PhoneNumberListingMode.UNLISTED -> WhoCanSeeMyPhoneNumberState.NOBODY + } + } + + fun onSave(whoCanSeeMyPhoneNumberState: WhoCanSeeMyPhoneNumberState): Completable { + return Completable.fromAction { + SignalStore.phoneNumberPrivacy().phoneNumberListingMode = when (whoCanSeeMyPhoneNumberState) { + WhoCanSeeMyPhoneNumberState.EVERYONE -> PhoneNumberPrivacyValues.PhoneNumberListingMode.LISTED + WhoCanSeeMyPhoneNumberState.NOBODY -> PhoneNumberPrivacyValues.PhoneNumberListingMode.UNLISTED + } + + ApplicationDependencies.getJobManager().add(RefreshAttributesJob()) + } + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/profiles/edit/pnp/WhoCanSeeMyPhoneNumberViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/profiles/edit/pnp/WhoCanSeeMyPhoneNumberViewModel.kt index a518d4e615..a38c53ba02 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/profiles/edit/pnp/WhoCanSeeMyPhoneNumberViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/profiles/edit/pnp/WhoCanSeeMyPhoneNumberViewModel.kt @@ -2,13 +2,15 @@ package org.thoughtcrime.securesms.profiles.edit.pnp import androidx.lifecycle.ViewModel import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers +import io.reactivex.rxjava3.core.Completable import io.reactivex.rxjava3.core.Flowable import io.reactivex.rxjava3.disposables.CompositeDisposable import org.thoughtcrime.securesms.util.rx.RxStore class WhoCanSeeMyPhoneNumberViewModel : ViewModel() { - private val store = RxStore(WhoCanSeeMyPhoneNumberState.EVERYONE) + private val repository = WhoCanSeeMyPhoneNumberRepository() + private val store = RxStore(repository.getCurrentState()) private val disposables = CompositeDisposable() val state: Flowable = store.stateFlowable.subscribeOn(AndroidSchedulers.mainThread()) @@ -21,6 +23,10 @@ class WhoCanSeeMyPhoneNumberViewModel : ViewModel() { store.update { WhoCanSeeMyPhoneNumberState.NOBODY } } + fun onSave(): Completable { + return repository.onSave(store.state).observeOn(AndroidSchedulers.mainThread()) + } + override fun onCleared() { disposables.clear() } diff --git a/app/src/main/res/layout/who_can_see_my_phone_number_fragment.xml b/app/src/main/res/layout/who_can_see_my_phone_number_fragment.xml new file mode 100644 index 0000000000..2c2301f2b3 --- /dev/null +++ b/app/src/main/res/layout/who_can_see_my_phone_number_fragment.xml @@ -0,0 +1,30 @@ + + + + + + + + + \ No newline at end of file