Add PNP Listing Wiring.

fork-5.53.8
Alex Hart 2022-09-08 17:25:01 -03:00 zatwierdzone przez Greyson Parrelli
rodzic 8e9f311fca
commit 176a705079
6 zmienionych plików z 153 dodań i 8 usunięć

Wyświetl plik

@ -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<T : ViewBinding>(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
}
}

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/dsl_settings_toolbar" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/toolbar" />
<com.google.android.material.button.MaterialButton
android:id="@+id/save"
style="@style/Signal.Widget.Button.Large.Tonal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/dsl_settings_gutter"
android:layout_marginBottom="16dp"
android:text="@string/save"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>