mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-23 04:28:35 +00:00
Update contacts permission UI.
This commit is contained in:
committed by
Nicholas Tinsley
parent
13bd4a9c74
commit
0465fdea62
@@ -3,6 +3,7 @@ package org.thoughtcrime.securesms
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import org.thoughtcrime.securesms.contacts.paged.ContactSearchAdapter
|
||||
import org.thoughtcrime.securesms.contacts.paged.ContactSearchConfiguration
|
||||
import org.thoughtcrime.securesms.contacts.paged.ContactSearchData
|
||||
@@ -24,6 +25,8 @@ class ContactSelectionListAdapter(
|
||||
init {
|
||||
registerFactory(NewGroupModel::class.java, LayoutFactory({ NewGroupViewHolder(it, onClickCallbacks::onNewGroupClicked) }, R.layout.contact_selection_new_group_item))
|
||||
registerFactory(InviteToSignalModel::class.java, LayoutFactory({ InviteToSignalViewHolder(it, onClickCallbacks::onInviteToSignalClicked) }, R.layout.contact_selection_invite_action_item))
|
||||
registerFactory(FindContactsModel::class.java, LayoutFactory({ FindContactsViewHolder(it, onClickCallbacks::onFindContactsClicked) }, R.layout.contact_selection_find_contacts_item))
|
||||
registerFactory(FindContactsBannerModel::class.java, LayoutFactory({ FindContactsBannerViewHolder(it, onClickCallbacks::onDismissFindContactsBannerClicked, onClickCallbacks::onFindContactsClicked) }, R.layout.contact_selection_find_contacts_banner_item))
|
||||
registerFactory(RefreshContactsModel::class.java, LayoutFactory({ RefreshContactsViewHolder(it, onClickCallbacks::onRefreshContactsClicked) }, R.layout.contact_selection_refresh_action_item))
|
||||
registerFactory(MoreHeaderModel::class.java, LayoutFactory({ MoreHeaderViewHolder(it) }, R.layout.contact_search_section_header))
|
||||
registerFactory(EmptyModel::class.java, LayoutFactory({ EmptyViewHolder(it) }, R.layout.contact_selection_empty_state))
|
||||
@@ -46,6 +49,16 @@ class ContactSelectionListAdapter(
|
||||
override fun areContentsTheSame(newItem: RefreshContactsModel): Boolean = true
|
||||
}
|
||||
|
||||
class FindContactsModel : MappingModel<FindContactsModel> {
|
||||
override fun areItemsTheSame(newItem: FindContactsModel): Boolean = true
|
||||
override fun areContentsTheSame(newItem: FindContactsModel): Boolean = true
|
||||
}
|
||||
|
||||
class FindContactsBannerModel : MappingModel<FindContactsBannerModel> {
|
||||
override fun areItemsTheSame(newItem: FindContactsBannerModel): Boolean = true
|
||||
override fun areContentsTheSame(newItem: FindContactsBannerModel): Boolean = true
|
||||
}
|
||||
|
||||
class FindByUsernameModel : MappingModel<FindByUsernameModel> {
|
||||
override fun areItemsTheSame(newItem: FindByUsernameModel): Boolean = true
|
||||
override fun areContentsTheSame(newItem: FindByUsernameModel): Boolean = true
|
||||
@@ -86,6 +99,23 @@ class ContactSelectionListAdapter(
|
||||
override fun bind(model: RefreshContactsModel) = Unit
|
||||
}
|
||||
|
||||
private class FindContactsViewHolder(itemView: View, onClickListener: () -> Unit) : MappingViewHolder<FindContactsModel>(itemView) {
|
||||
init {
|
||||
itemView.setOnClickListener { onClickListener() }
|
||||
}
|
||||
|
||||
override fun bind(model: FindContactsModel) = Unit
|
||||
}
|
||||
|
||||
private class FindContactsBannerViewHolder(itemView: View, onDismissListener: () -> Unit, onClickListener: () -> Unit) : MappingViewHolder<FindContactsBannerModel>(itemView) {
|
||||
init {
|
||||
itemView.findViewById<MaterialButton>(R.id.no_thanks_button).setOnClickListener { onDismissListener() }
|
||||
itemView.findViewById<MaterialButton>(R.id.allow_contacts_button).setOnClickListener { onClickListener() }
|
||||
}
|
||||
|
||||
override fun bind(model: FindContactsBannerModel) = Unit
|
||||
}
|
||||
|
||||
private class MoreHeaderViewHolder(itemView: View) : MappingViewHolder<MoreHeaderModel>(itemView) {
|
||||
|
||||
private val headerTextView: TextView = itemView.findViewById(R.id.section_header)
|
||||
@@ -129,6 +159,8 @@ class ContactSelectionListAdapter(
|
||||
INVITE_TO_SIGNAL("invite-to-signal"),
|
||||
MORE_HEADING("more-heading"),
|
||||
REFRESH_CONTACTS("refresh-contacts"),
|
||||
FIND_CONTACTS("find-contacts"),
|
||||
FIND_CONTACTS_BANNER("find-contacts-banner"),
|
||||
FIND_BY_USERNAME("find-by-username"),
|
||||
FIND_BY_PHONE_NUMBER("find-by-phone-number");
|
||||
|
||||
@@ -152,6 +184,8 @@ class ContactSelectionListAdapter(
|
||||
ArbitraryRow.INVITE_TO_SIGNAL -> InviteToSignalModel()
|
||||
ArbitraryRow.MORE_HEADING -> MoreHeaderModel()
|
||||
ArbitraryRow.REFRESH_CONTACTS -> RefreshContactsModel()
|
||||
ArbitraryRow.FIND_CONTACTS -> FindContactsModel()
|
||||
ArbitraryRow.FIND_CONTACTS_BANNER -> FindContactsBannerModel()
|
||||
ArbitraryRow.FIND_BY_PHONE_NUMBER -> FindByPhoneNumberModel()
|
||||
ArbitraryRow.FIND_BY_USERNAME -> FindByUsernameModel()
|
||||
}
|
||||
@@ -162,6 +196,8 @@ class ContactSelectionListAdapter(
|
||||
fun onNewGroupClicked()
|
||||
fun onInviteToSignalClicked()
|
||||
fun onRefreshContactsClicked()
|
||||
fun onFindContactsClicked()
|
||||
fun onDismissFindContactsBannerClicked()
|
||||
fun onFindByPhoneNumberClicked()
|
||||
fun onFindByUsernameClicked()
|
||||
}
|
||||
|
||||
@@ -70,13 +70,13 @@ import org.thoughtcrime.securesms.contacts.paged.ContactSearchState;
|
||||
import org.thoughtcrime.securesms.contacts.sync.ContactDiscovery;
|
||||
import org.thoughtcrime.securesms.groups.SelectionLimits;
|
||||
import org.thoughtcrime.securesms.groups.ui.GroupLimitDialog;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.profiles.manage.UsernameRepository;
|
||||
import org.thoughtcrime.securesms.profiles.manage.UsernameRepository.UsernameAciFetchResult;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.CommunicationActions;
|
||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.UsernameUtil;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
@@ -125,10 +125,6 @@ public final class ContactSelectionListFragment extends LoggingFragment {
|
||||
private TextView emptyText;
|
||||
private OnContactSelectedListener onContactSelectedListener;
|
||||
private SwipeRefreshLayout swipeRefresh;
|
||||
private View showContactsLayout;
|
||||
private Button showContactsButton;
|
||||
private TextView showContactsDescription;
|
||||
private ProgressWheel showContactsProgress;
|
||||
private String cursorFilter;
|
||||
private RecyclerView recyclerView;
|
||||
private RecyclerViewFastScroller fastScroller;
|
||||
@@ -223,26 +219,12 @@ public final class ContactSelectionListFragment extends LoggingFragment {
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
|
||||
Permissions.with(this)
|
||||
.request(Manifest.permission.WRITE_CONTACTS, Manifest.permission.READ_CONTACTS)
|
||||
.ifNecessary()
|
||||
.onAllGranted(() -> {
|
||||
if (!TextSecurePreferences.hasSuccessfullyRetrievedDirectory(getActivity())) {
|
||||
if (hasContactsPermissions(requireContext()) && !TextSecurePreferences.hasSuccessfullyRetrievedDirectory(getActivity())) {
|
||||
handleContactPermissionGranted();
|
||||
} else {
|
||||
contactSearchMediator.refresh();
|
||||
}
|
||||
})
|
||||
.onAnyDenied(() -> {
|
||||
requireActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
|
||||
|
||||
if (safeArguments().getBoolean(RECENTS, requireActivity().getIntent().getBooleanExtra(RECENTS, false))) {
|
||||
contactSearchMediator.refresh();
|
||||
} else {
|
||||
initializeNoContactsPermission();
|
||||
}
|
||||
})
|
||||
.execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -253,10 +235,6 @@ public final class ContactSelectionListFragment extends LoggingFragment {
|
||||
recyclerView = view.findViewById(R.id.recycler_view);
|
||||
swipeRefresh = view.findViewById(R.id.swipe_refresh);
|
||||
fastScroller = view.findViewById(R.id.fast_scroller);
|
||||
showContactsLayout = view.findViewById(R.id.show_contacts_container);
|
||||
showContactsButton = view.findViewById(R.id.show_contacts_button);
|
||||
showContactsDescription = view.findViewById(R.id.show_contacts_description);
|
||||
showContactsProgress = view.findViewById(R.id.progress);
|
||||
chipRecycler = view.findViewById(R.id.chipRecycler);
|
||||
constraintLayout = view.findViewById(R.id.container);
|
||||
headerActionView = view.findViewById(R.id.header_action);
|
||||
@@ -269,6 +247,11 @@ public final class ContactSelectionListFragment extends LoggingFragment {
|
||||
public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationFinished(@NonNull RecyclerView.ViewHolder viewHolder) {
|
||||
recyclerView.setAlpha(1f);
|
||||
}
|
||||
});
|
||||
|
||||
contactChipViewModel = new ViewModelProvider(this).get(ContactChipViewModel.class);
|
||||
@@ -372,6 +355,19 @@ public final class ContactSelectionListFragment extends LoggingFragment {
|
||||
fixedContacts,
|
||||
displayOptions,
|
||||
new ContactSelectionListAdapter.OnContactSelectionClick() {
|
||||
@Override
|
||||
public void onDismissFindContactsBannerClicked() {
|
||||
SignalStore.uiHints().markDismissedContactsPermissionBanner();
|
||||
if (onRefreshListener != null) {
|
||||
onRefreshListener.onRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFindContactsClicked() {
|
||||
requestContactPermissions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRefreshContactsClicked() {
|
||||
if (onRefreshListener != null) {
|
||||
@@ -498,6 +494,27 @@ public final class ContactSelectionListFragment extends LoggingFragment {
|
||||
return isMulti;
|
||||
}
|
||||
|
||||
private void requestContactPermissions() {
|
||||
Permissions.with(this)
|
||||
.request(Manifest.permission.WRITE_CONTACTS, Manifest.permission.READ_CONTACTS)
|
||||
.ifNecessary()
|
||||
.onAllGranted(() -> {
|
||||
recyclerView.setAlpha(0.5f);
|
||||
if (!TextSecurePreferences.hasSuccessfullyRetrievedDirectory(getActivity())) {
|
||||
handleContactPermissionGranted();
|
||||
} else {
|
||||
contactSearchMediator.refresh();
|
||||
if (onRefreshListener != null) {
|
||||
swipeRefresh.setRefreshing(true);
|
||||
onRefreshListener.onRefresh();
|
||||
}
|
||||
}
|
||||
})
|
||||
.onAnyDenied(() -> contactSearchMediator.refresh())
|
||||
.withPermanentDenialDialog(getString(R.string.ContactSelectionListFragment_signal_requires_the_contacts_permission_in_order_to_display_your_contacts), null, R.string.ContactSelectionListFragment_allow_access_contacts, R.string.ContactSelectionListFragment_to_find_people, getParentFragmentManager())
|
||||
.execute();
|
||||
}
|
||||
|
||||
private void initializeCursor() {
|
||||
recyclerView.addItemDecoration(new LetterHeaderDecoration(requireContext(), this::hideLetterHeaders));
|
||||
recyclerView.setAdapter(contactSearchMediator.getAdapter());
|
||||
@@ -521,28 +538,6 @@ public final class ContactSelectionListFragment extends LoggingFragment {
|
||||
return hasQueryFilter() || shouldDisplayRecents();
|
||||
}
|
||||
|
||||
private void initializeNoContactsPermission() {
|
||||
swipeRefresh.setVisibility(View.GONE);
|
||||
|
||||
showContactsLayout.setVisibility(View.VISIBLE);
|
||||
showContactsProgress.setVisibility(View.INVISIBLE);
|
||||
showContactsDescription.setText(R.string.contact_selection_list_fragment__signal_needs_access_to_your_contacts_in_order_to_display_them);
|
||||
showContactsButton.setVisibility(View.VISIBLE);
|
||||
|
||||
showContactsButton.setOnClickListener(v -> {
|
||||
Permissions.with(this)
|
||||
.request(Manifest.permission.WRITE_CONTACTS, Manifest.permission.READ_CONTACTS)
|
||||
.ifNecessary()
|
||||
.withPermanentDenialDialog(getString(R.string.ContactSelectionListFragment_signal_requires_the_contacts_permission_in_order_to_display_your_contacts))
|
||||
.onSomeGranted(permissions -> {
|
||||
if (permissions.contains(Manifest.permission.WRITE_CONTACTS)) {
|
||||
handleContactPermissionGranted();
|
||||
}
|
||||
})
|
||||
.execute();
|
||||
});
|
||||
}
|
||||
|
||||
public void setQueryFilter(String filter) {
|
||||
if (Objects.equals(filter, this.cursorFilter)) {
|
||||
return;
|
||||
@@ -583,7 +578,6 @@ public final class ContactSelectionListFragment extends LoggingFragment {
|
||||
}
|
||||
|
||||
swipeRefresh.setVisibility(View.VISIBLE);
|
||||
showContactsLayout.setVisibility(View.GONE);
|
||||
|
||||
emptyText.setText(R.string.contact_selection_group_activity__no_contacts);
|
||||
boolean useFastScroller = count > 20;
|
||||
@@ -614,12 +608,10 @@ public final class ContactSelectionListFragment extends LoggingFragment {
|
||||
new AsyncTask<Void, Void, Boolean>() {
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
swipeRefresh.setVisibility(View.GONE);
|
||||
showContactsLayout.setVisibility(View.VISIBLE);
|
||||
showContactsButton.setVisibility(View.INVISIBLE);
|
||||
showContactsDescription.setText(R.string.ConversationListFragment_loading);
|
||||
showContactsProgress.setVisibility(View.VISIBLE);
|
||||
showContactsProgress.spin();
|
||||
if (onRefreshListener != null) {
|
||||
setRefreshing(true);
|
||||
onRefreshListener.onRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -636,14 +628,11 @@ public final class ContactSelectionListFragment extends LoggingFragment {
|
||||
@Override
|
||||
protected void onPostExecute(Boolean result) {
|
||||
if (result) {
|
||||
showContactsLayout.setVisibility(View.GONE);
|
||||
swipeRefresh.setVisibility(View.VISIBLE);
|
||||
reset();
|
||||
} else {
|
||||
Context context = getContext();
|
||||
if (context != null) {
|
||||
Toast.makeText(getContext(), R.string.ContactSelectionListFragment_error_retrieving_contacts_check_your_network_connection, Toast.LENGTH_LONG).show();
|
||||
initializeNoContactsPermission();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -890,6 +879,13 @@ public final class ContactSelectionListFragment extends LoggingFragment {
|
||||
return ContactSearchConfiguration.build(builder -> {
|
||||
builder.setQuery(contactSearchState.getQuery());
|
||||
|
||||
if (newConversationCallback != null &&
|
||||
!hasContactsPermissions(requireContext()) &&
|
||||
!SignalStore.uiHints().getDismissedContactsPermissionBanner() &&
|
||||
!hasQuery) {
|
||||
builder.arbitrary(ContactSelectionListAdapter.ArbitraryRepository.ArbitraryRow.FIND_CONTACTS_BANNER.getCode());
|
||||
}
|
||||
|
||||
if (newConversationCallback != null && !hasQuery) {
|
||||
builder.arbitrary(ContactSelectionListAdapter.ArbitraryRepository.ArbitraryRow.NEW_GROUP.getCode());
|
||||
}
|
||||
@@ -946,7 +942,7 @@ public final class ContactSelectionListFragment extends LoggingFragment {
|
||||
builder.username(newRowMode);
|
||||
}
|
||||
|
||||
if ((newCallCallback != null || newConversationCallback != null) && !hasQuery) {
|
||||
if ((newCallCallback != null || newConversationCallback != null)) {
|
||||
addMoreSection(builder);
|
||||
builder.withEmptyState(emptyBuilder -> {
|
||||
emptyBuilder.addSection(ContactSearchConfiguration.Section.Empty.INSTANCE);
|
||||
@@ -959,9 +955,17 @@ public final class ContactSelectionListFragment extends LoggingFragment {
|
||||
});
|
||||
}
|
||||
|
||||
private boolean hasContactsPermissions(@NonNull Context context) {
|
||||
return Permissions.hasAll(context, Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS);
|
||||
}
|
||||
|
||||
private void addMoreSection(@NonNull ContactSearchConfiguration.Builder builder) {
|
||||
builder.arbitrary(ContactSelectionListAdapter.ArbitraryRepository.ArbitraryRow.MORE_HEADING.getCode());
|
||||
if (hasContactsPermissions(requireContext())) {
|
||||
builder.arbitrary(ContactSelectionListAdapter.ArbitraryRepository.ArbitraryRow.REFRESH_CONTACTS.getCode());
|
||||
} else if (SignalStore.uiHints().getDismissedContactsPermissionBanner()) {
|
||||
builder.arbitrary(ContactSelectionListAdapter.ArbitraryRepository.ArbitraryRow.FIND_CONTACTS.getCode());
|
||||
}
|
||||
builder.arbitrary(ContactSelectionListAdapter.ArbitraryRepository.ArbitraryRow.INVITE_TO_SIGNAL.getCode());
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ public class UiHints extends SignalStoreValues {
|
||||
private static final String LAST_CRASH_PROMPT = "uihints.last_crash_prompt";
|
||||
private static final String HAS_COMPLETED_USERNAME_ONBOARDING = "uihints.has_completed_username_onboarding";
|
||||
private static final String HAS_SEEN_DOUBLE_TAP_EDIT_EDUCATION_SHEET = "uihints.has_seen_double_tap_edit_education_sheet";
|
||||
private static final String DISMISSED_CONTACTS_PERMISSION_BANNER = "uihints.dismissed_contacts_permission_banner";
|
||||
|
||||
UiHints(@NonNull KeyValueStore store) {
|
||||
super(store);
|
||||
@@ -167,4 +168,12 @@ public class UiHints extends SignalStoreValues {
|
||||
public boolean getHasSeenDoubleTapEditEducationSheet() {
|
||||
return getBoolean(HAS_SEEN_DOUBLE_TAP_EDIT_EDUCATION_SHEET, false);
|
||||
}
|
||||
|
||||
public void markDismissedContactsPermissionBanner() {
|
||||
putBoolean(DISMISSED_CONTACTS_PERMISSION_BANNER, true);
|
||||
}
|
||||
|
||||
public boolean getDismissedContactsPermissionBanner() {
|
||||
return getBoolean(DISMISSED_CONTACTS_PERMISSION_BANNER, false);
|
||||
}
|
||||
}
|
||||
|
||||
31
app/src/main/res/drawable/permissions_contact_book.xml
Normal file
31
app/src/main/res/drawable/permissions_contact_book.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="72dp"
|
||||
android:height="72dp"
|
||||
android:viewportWidth="72"
|
||||
android:viewportHeight="72">
|
||||
<path
|
||||
android:pathData="M12,12C12,8.686 14.686,6 18,6V54.75H12V12Z"
|
||||
android:fillColor="#A0AFCF"/>
|
||||
<path
|
||||
android:pathData="M18,6H60V54H18V6Z"
|
||||
android:fillColor="#C3CFE9"/>
|
||||
<path
|
||||
android:pathData="M18,54H60V63C60,64.657 58.657,66 57,66H18C14.686,66 12,63.314 12,60C12,56.686 14.686,54 18,54Z"
|
||||
android:fillColor="#F5F8FF"/>
|
||||
<path
|
||||
android:pathData="M18,4.5C13.858,4.5 10.5,7.858 10.5,12V60C10.5,64.142 13.858,67.5 18,67.5H57C59.485,67.5 61.5,65.485 61.5,63V9C61.5,6.515 59.485,4.5 57,4.5H18ZM58.5,9C58.5,8.172 57.828,7.5 57,7.5H18C15.515,7.5 13.5,9.515 13.5,12V54C14.753,53.058 16.312,52.5 18,52.5H57C57.828,52.5 58.5,51.828 58.5,51V9ZM58.5,55.244C58.031,55.41 57.526,55.5 57,55.5H18C15.515,55.5 13.5,57.515 13.5,60C13.5,62.485 15.515,64.5 18,64.5H57C57.828,64.5 58.5,63.828 58.5,63V55.244Z"
|
||||
android:fillColor="#6C7B9D"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M39.219,23.935C39.219,21.45 40.873,19.375 43.125,19.375C45.377,19.375 47.031,21.45 47.031,23.935C47.031,25.189 46.622,26.373 45.939,27.254C45.257,28.136 44.268,28.75 43.125,28.75C41.982,28.75 40.993,28.136 40.311,27.254C39.628,26.373 39.219,25.189 39.219,23.935Z"
|
||||
android:fillColor="#4C5876"/>
|
||||
<path
|
||||
android:pathData="M33.125,38.438C33.125,35.928 34.198,33.766 35.879,32.183C34.689,31.587 33.319,31.25 31.875,31.25C27.469,31.25 23.75,34.392 23.75,38.438C23.75,38.98 24.198,39.375 24.696,39.375H33.176C33.142,39.068 33.125,38.756 33.125,38.438Z"
|
||||
android:fillColor="#4C5876"/>
|
||||
<path
|
||||
android:pathData="M31.875,19.375C29.623,19.375 27.969,21.45 27.969,23.935C27.969,25.189 28.378,26.373 29.061,27.254C29.743,28.136 30.732,28.75 31.875,28.75C33.018,28.75 34.007,28.136 34.689,27.254C35.372,26.373 35.781,25.189 35.781,23.935C35.781,21.45 34.127,19.375 31.875,19.375Z"
|
||||
android:fillColor="#4C5876"/>
|
||||
<path
|
||||
android:pathData="M35,38.438C35,34.392 38.719,31.25 43.125,31.25C47.531,31.25 51.25,34.392 51.25,38.438C51.25,38.98 50.802,39.375 50.304,39.375H35.946C35.448,39.375 35,38.98 35,38.438Z"
|
||||
android:fillColor="#4C5876"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
android:background="@drawable/rounded_outline"
|
||||
android:padding="15dp"
|
||||
tools:viewBindingIgnore="true">
|
||||
|
||||
<com.google.android.material.imageview.ShapeableImageView
|
||||
android:id="@+id/image"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:scaleType="centerInside"
|
||||
android:importantForAccessibility="no"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:srcCompat="@drawable/permissions_contact_book" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:layout_marginTop="20dp"
|
||||
android:text="@string/contact_selection_activity__find_people_you_know"
|
||||
android:textAppearance="@style/Signal.Text.BodyLarge"
|
||||
app:layout_constraintTop_toBottomOf="@id/image"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/description"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/ContactSelectionListFragment__allow_access_to_your_contacts_encrypted"
|
||||
android:textAppearance="@style/Signal.Text.BodyMedium"
|
||||
android:textColor="@color/signal_colorOnSurfaceVariant"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/title" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/no_thanks_button"
|
||||
style="@style/Signal.Widget.Button.Medium.Tonal"
|
||||
android:layout_width="140dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="10dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/description"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/allow_contacts_button"
|
||||
android:text="@string/RatingManager_no_thanks" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/allow_contacts_button"
|
||||
style="@style/Signal.Widget.Button.Medium.Tonal"
|
||||
android:layout_width="140dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="10dp"
|
||||
app:layout_constraintStart_toEndOf="@id/no_thanks_button"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/description"
|
||||
android:text="@string/ContactSelectionListFragment__allow_access" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/rounded_inset_ripple_background"
|
||||
android:minHeight="@dimen/contact_selection_item_height"
|
||||
android:paddingStart="@dimen/dsl_settings_gutter"
|
||||
android:paddingEnd="@dimen/dsl_settings_gutter"
|
||||
tools:viewBindingIgnore="true">
|
||||
|
||||
<com.google.android.material.imageview.ShapeableImageView
|
||||
android:id="@+id/image"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:background="@color/signal_colorSurfaceVariant"
|
||||
android:importantForAccessibility="no"
|
||||
android:scaleType="centerInside"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Signal.Circle"
|
||||
app:srcCompat="@drawable/symbol_person_circle_24"
|
||||
app:tint="@color/signal_colorOnSurface" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:ellipsize="marquee"
|
||||
android:labelFor="@id/action_icon"
|
||||
android:singleLine="true"
|
||||
android:text="@string/contact_selection_activity__find_people_you_know"
|
||||
android:textAppearance="@style/Signal.Text.BodyLarge"
|
||||
app:layout_constraintBottom_toTopOf="@id/description"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/image"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/description"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:ellipsize="marquee"
|
||||
android:labelFor="@id/action_icon"
|
||||
android:maxLines="2"
|
||||
android:text="@string/contact_selection_activity__allow_access_to_contacts"
|
||||
android:textAppearance="@style/Signal.Text.BodyMedium"
|
||||
android:textColor="@color/signal_colorOnSurfaceVariant"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/image"
|
||||
app:layout_constraintTop_toBottomOf="@id/title" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -48,71 +48,6 @@
|
||||
app:layout_constraintTop_toBottomOf="@+id/chipRecycler"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/show_contacts_container"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/chipRecycler"
|
||||
tools:visibility="visible">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/show_contacts_button"
|
||||
style="@style/Signal.Widget.Button.Large.Primary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="20dp"
|
||||
android:background="@color/core_ultramarine"
|
||||
android:padding="10dp"
|
||||
android:text="@string/contact_selection_list_fragment__show_contacts"
|
||||
android:textColor="@color/white" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.pnikosis.materialishprogress.ProgressWheel
|
||||
android:id="@+id/progress"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="invisible"
|
||||
app:matProg_barColor="@color/core_ultramarine_dark"
|
||||
app:matProg_barWidth="6dp"
|
||||
app:matProg_circleRadius="145dp"
|
||||
app:matProg_progressIndeterminate="true"
|
||||
app:matProg_rimColor="@color/core_ultramarine"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:importantForAccessibility="no"
|
||||
android:src="@drawable/no_contacts" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/show_contacts_description"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="50dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginEnd="50dp"
|
||||
android:gravity="center"
|
||||
android:lineSpacingMultiplier="1.3"
|
||||
android:text="@string/contact_selection_list_fragment__signal_needs_access_to_your_contacts_in_order_to_display_them"
|
||||
android:textSize="15sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/header_action"
|
||||
style="@style/Widget.Signal.Button.Small"
|
||||
|
||||
@@ -2714,6 +2714,10 @@
|
||||
<string name="contact_selection_activity__refresh_contacts">Refresh contacts</string>
|
||||
<!-- Row item description for refreshing contacts -->
|
||||
<string name="contact_selection_activity__missing_someone">Missing someone? Try refreshing</string>
|
||||
<!-- Row item title for finding people on Signal via your contacts -->
|
||||
<string name="contact_selection_activity__find_people_you_know">Find people you know on Signal</string>
|
||||
<!-- Row item description asking users for access to their contacts to find people they know -->
|
||||
<string name="contact_selection_activity__allow_access_to_contacts">Allow access to your contacts</string>
|
||||
<!-- Row header title for more section -->
|
||||
<string name="contact_selection_activity__more">More</string>
|
||||
|
||||
@@ -2747,6 +2751,14 @@
|
||||
<string name="ContactSelectionListFragment__find_by_phone_number">Find by phone number</string>
|
||||
<!-- Text on row item to find user by username -->
|
||||
<string name="ContactSelectionListFragment__find_by_username">Find by username</string>
|
||||
<!-- Dialog title asking users for contact permission -->
|
||||
<string name="ContactSelectionListFragment_allow_access_contacts">Allow access to contacts</string>
|
||||
<!-- Dialog description that will explain the steps needed to give contact permissions -->
|
||||
<string name="ContactSelectionListFragment_to_find_people">To find people you know on Signal:</string>
|
||||
<!-- Text on button prompting users to give Signal contact permissions -->
|
||||
<string name="ContactSelectionListFragment__allow_access">Allow access</string>
|
||||
<!-- Text asking for user's contact permission -->
|
||||
<string name="ContactSelectionListFragment__allow_access_to_your_contacts_encrypted">Allow access to your contacts. Your contacts are encrypted and not visible to the Signal service.</string>
|
||||
|
||||
<!-- contact_selection_list_fragment -->
|
||||
<string name="contact_selection_list_fragment__signal_needs_access_to_your_contacts_in_order_to_display_them">Signal needs access to your contacts in order to display them.</string>
|
||||
|
||||
Reference in New Issue
Block a user