Add internal setting to see recipient details.

master
Greyson Parrelli 2020-07-31 14:10:20 -04:00
parent 9b61e1c85c
commit 33cc8363f9
7 changed files with 92 additions and 13 deletions

View File

@ -8,6 +8,7 @@ public final class InternalValues extends SignalStoreValues {
public static final String GV2_FORCE_INVITES = "internal.gv2.force_invites";
public static final String GV2_IGNORE_SERVER_CHANGES = "internal.gv2.ignore_server_changes";
public static final String GV2_IGNORE_P2P_CHANGES = "internal.gv2.ignore_p2p_changes";
public static final String RECIPIENT_DETAILS = "internal.recipient_details";
InternalValues(KeyValueStore store) {
super(store);
@ -51,4 +52,11 @@ public final class InternalValues extends SignalStoreValues {
public synchronized boolean gv2IgnoreP2PChanges() {
return FeatureFlags.internalUser() && getBoolean(GV2_IGNORE_P2P_CHANGES, false);
}
/**
* Show detailed recipient info in the {@link org.thoughtcrime.securesms.recipients.ui.managerecipient.ManageRecipientFragment}.
*/
public synchronized boolean recipientDetails() {
return FeatureFlags.internalUser() && getBoolean(RECIPIENT_DETAILS, false);
}
}

View File

@ -34,6 +34,7 @@ public class InternalOptionsPreferenceFragment extends CorrectedPreferenceFragme
PreferenceDataStore preferenceDataStore = SignalStore.getPreferenceDataStore();
initializeSwitchPreference(preferenceDataStore, InternalValues.RECIPIENT_DETAILS, SignalStore.internalValues().recipientDetails());
initializeSwitchPreference(preferenceDataStore, InternalValues.GV2_DO_NOT_CREATE_GV2, SignalStore.internalValues().gv2DoNotCreateGv2Groups());
initializeSwitchPreference(preferenceDataStore, InternalValues.GV2_FORCE_INVITES, SignalStore.internalValues().gv2ForceInvites());
initializeSwitchPreference(preferenceDataStore, InternalValues.GV2_IGNORE_SERVER_CHANGES, SignalStore.internalValues().gv2IgnoreServerChanges());

View File

@ -39,6 +39,7 @@ import org.thoughtcrime.securesms.components.ThreadPhotoRailView;
import org.thoughtcrime.securesms.contacts.avatars.FallbackContactPhoto;
import org.thoughtcrime.securesms.contacts.avatars.FallbackPhoto80dp;
import org.thoughtcrime.securesms.groups.ui.GroupMemberListView;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.mediaoverview.MediaOverviewActivity;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
@ -68,6 +69,7 @@ public class ManageRecipientFragment extends LoggingFragment {
private Toolbar toolbar;
private TextView title;
private TextView subtitle;
private TextView internalDetails;
private View contactRow;
private TextView contactText;
private ImageView contactIcon;
@ -125,6 +127,7 @@ public class ManageRecipientFragment extends LoggingFragment {
contactIcon = view.findViewById(R.id.recipient_contact_icon);
title = view.findViewById(R.id.name);
subtitle = view.findViewById(R.id.username_number);
internalDetails = view.findViewById(R.id.recipient_internal_details);
sharedGroupList = view.findViewById(R.id.shared_group_list);
groupsInCommonCount = view.findViewById(R.id.groups_in_common_count);
threadPhotoRailView = view.findViewById(R.id.recent_photos);
@ -214,6 +217,13 @@ public class ManageRecipientFragment extends LoggingFragment {
viewModel.getMuteState().observe(getViewLifecycleOwner(), this::presentMuteState);
viewModel.getCanAddToAGroup().observe(getViewLifecycleOwner(), canAdd -> addToAGroup.setVisibility(canAdd ? View.VISIBLE : View.GONE));
if (SignalStore.internalValues().recipientDetails()) {
viewModel.getInternalDetails().observe(getViewLifecycleOwner(), internalDetails::setText);
internalDetails.setVisibility(View.VISIBLE);
} else {
internalDetails.setVisibility(View.GONE);
}
disappearingMessagesRow.setOnClickListener(v -> viewModel.handleExpirationSelection(requireContext()));
block.setOnClickListener(v -> viewModel.onBlockClicked(requireActivity()));
unblock.setOnClickListener(v -> viewModel.onUnblockClicked(requireActivity()));

View File

@ -27,17 +27,21 @@ import org.thoughtcrime.securesms.database.loaders.ThreadMediaLoader;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.groups.ui.GroupMemberEntry;
import org.thoughtcrime.securesms.groups.ui.addtogroup.AddToGroupsActivity;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.thoughtcrime.securesms.util.Base64;
import org.thoughtcrime.securesms.util.CommunicationActions;
import org.thoughtcrime.securesms.util.DefaultValueLiveData;
import org.thoughtcrime.securesms.util.ExpirationUtil;
import org.thoughtcrime.securesms.util.Hex;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
import java.util.List;
import java.util.UUID;
public final class ManageRecipientViewModel extends ViewModel {
@ -47,14 +51,15 @@ public final class ManageRecipientViewModel extends ViewModel {
private final ManageRecipientRepository manageRecipientRepository;
private final LiveData<String> title;
private final LiveData<String> subtitle;
private final LiveData<String> internalDetails;
private final LiveData<String> disappearingMessageTimer;
private final MutableLiveData<IdentityDatabase.IdentityRecord> identity;
private final LiveData<Recipient> recipient;
private final MutableLiveData<MediaCursor> mediaCursor = new MutableLiveData<>(null);
private final MutableLiveData<MediaCursor> mediaCursor;
private final LiveData<MuteState> muteState;
private final LiveData<Boolean> hasCustomNotifications;
private final LiveData<Boolean> canCollapseMemberList;
private final DefaultValueLiveData<CollapseState> groupListCollapseState = new DefaultValueLiveData<>(CollapseState.COLLAPSED);
private final DefaultValueLiveData<CollapseState> groupListCollapseState;
private final LiveData<Boolean> canBlock;
private final LiveData<List<GroupMemberEntry.FullMember>> visibleSharedGroups;
private final LiveData<String> sharedGroupsCountSummary;
@ -63,14 +68,20 @@ public final class ManageRecipientViewModel extends ViewModel {
private ManageRecipientViewModel(@NonNull Context context, @NonNull ManageRecipientRepository manageRecipientRepository) {
this.context = context;
this.manageRecipientRepository = manageRecipientRepository;
this.recipient = Recipient.live(manageRecipientRepository.getRecipientId()).getLiveData();
this.title = Transformations.map(recipient, r -> getDisplayTitle(r, context) );
this.subtitle = Transformations.map(recipient, r -> getDisplaySubtitle(r, context));
this.identity = new MutableLiveData<>();
this.mediaCursor = new MutableLiveData<>(null);
this.groupListCollapseState = new DefaultValueLiveData<>(CollapseState.COLLAPSED);
this.disappearingMessageTimer = Transformations.map(this.recipient, r -> ExpirationUtil.getExpirationDisplayValue(context, r.getExpireMessages()));
this.muteState = Transformations.map(this.recipient, r -> new MuteState(r.getMuteUntil(), r.isMuted()));
this.hasCustomNotifications = Transformations.map(this.recipient, r -> r.getNotificationChannel() != null || !NotificationChannels.supported());
this.canBlock = Transformations.map(this.recipient, r -> !r.isBlocked());
this.internalDetails = Transformations.map(this.recipient, this::populateInternalDetails);
manageRecipientRepository.getThreadId(this::onThreadIdLoaded);
this.recipient = Recipient.live(manageRecipientRepository.getRecipientId()).getLiveData();
this.title = Transformations.map(recipient, r -> getDisplayTitle(r, context));
this.subtitle = Transformations.map(recipient, r -> getDisplaySubtitle(r, context));
this.identity = new MutableLiveData<>();
LiveData<List<Recipient>> allSharedGroups = LiveDataUtil.mapAsync(this.recipient, r -> manageRecipientRepository.getSharedGroups(r.getId()));
this.sharedGroupsCountSummary = Transformations.map(allSharedGroups, list -> {
@ -87,10 +98,6 @@ public final class ManageRecipientViewModel extends ViewModel {
ManageRecipientViewModel::filterSharedGroupList),
recipients -> Stream.of(recipients).map(r -> new GroupMemberEntry.FullMember(r, false)).toList());
this.disappearingMessageTimer = Transformations.map(this.recipient, r -> ExpirationUtil.getExpirationDisplayValue(context, r.getExpireMessages()));
this.muteState = Transformations.map(this.recipient, r -> new MuteState(r.getMuteUntil(), r.isMuted()));
this.hasCustomNotifications = Transformations.map(this.recipient, r -> r.getNotificationChannel() != null || !NotificationChannels.supported());
this.canBlock = Transformations.map(this.recipient, r -> !r.isBlocked());
boolean isSelf = manageRecipientRepository.getRecipientId().equals(Recipient.self().getId());
if (!isSelf) {
@ -99,8 +106,9 @@ public final class ManageRecipientViewModel extends ViewModel {
MutableLiveData<Integer> localGroupCount = new MutableLiveData<>(0);
canAddToAGroup = LiveDataUtil.combineLatest(recipient, localGroupCount,
(r, count) -> count > 0 && r.isRegistered() && !r.isGroup() && !r.isLocalNumber());
this.canAddToAGroup = LiveDataUtil.combineLatest(recipient,
localGroupCount,
(r, count) -> count > 0 && r.isRegistered() && !r.isGroup() && !r.isLocalNumber());
manageRecipientRepository.getActiveGroupCount(localGroupCount::postValue);
}
@ -136,6 +144,10 @@ public final class ManageRecipientViewModel extends ViewModel {
return subtitle;
}
LiveData<String> getInternalDetails() {
return internalDetails;
}
LiveData<Recipient> getRecipient() {
return recipient;
}
@ -265,6 +277,27 @@ public final class ManageRecipientViewModel extends ViewModel {
manageRecipientRepository.refreshRecipient();
}
private @NonNull String populateInternalDetails(@NonNull Recipient recipient) {
if (!SignalStore.internalValues().recipientDetails()) {
return "";
}
String profileKeyBase64 = recipient.getProfileKey() != null ? Base64.encodeBytes(recipient.getProfileKey()) : "None";
String profileKeyHex = recipient.getProfileKey() != null ? Hex.toStringCondensed(recipient.getProfileKey()) : "None";
return String.format("-- Profile Name --\n%s\n\n" +
"-- Profile Sharing --\n%s\n\n" +
"-- Profile Key (Base64) --\n%s\n\n" +
"-- Profile Key (Hex) --\n%s\n\n" +
"-- UUID --\n%s\n\n" +
"-- RecipientId --\n%s",
recipient.getProfileName().toString(),
recipient.isProfileSharing(),
profileKeyBase64,
profileKeyHex,
recipient.getUuid().transform(UUID::toString).or("None"),
recipient.getId().serialize());
}
static final class MediaCursor {
private final long threadId;
@NonNull private final CursorFactory mediaCursorFactory;

View File

@ -55,6 +55,18 @@
android:textColor="?title_text_color_secondary"
tools:text="\@spidergwen +1 555-654-6657" />
<TextView
android:id="@+id/recipient_internal_details"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="14dp"
android:textAppearance="@style/Signal.Text.Caption"
android:textColor="?title_text_color_secondary"
android:gravity="center"
android:textIsSelectable="true"
android:visibility="gone" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"

View File

@ -2004,6 +2004,9 @@
<string name="preferences__internal_rotate_profile_key_description" translatable="false">Creates a new versioned profile, and triggers an update of any GV2 group you belong to.</string>
<string name="preferences__internal_refresh_remote_values" translatable="false">Refresh remote values</string>
<string name="preferences__internal_refresh_remote_values_description" translatable="false">Forces a refresh of remote values locally instead of waiting for the elapsed time</string>
<string name="preferences__internal_display" translatable="false">Display</string>
<string name="preferences__internal_user_details" translatable="false">User Details</string>
<string name="preferences__internal_user_details_description" translatable="false">See more information about a user when viewing conversation settings.</string>
<string name="preferences__internal_storage_service" translatable="false">Storage service</string>
<string name="preferences__internal_force_storage_service_sync" translatable="false">Overwrite remote data</string>
<string name="preferences__internal_force_storage_service_sync_description" translatable="false">Forces remote storage to match the local device state.</string>

View File

@ -22,6 +22,18 @@
</PreferenceCategory>
<PreferenceCategory
android:key="internal_display"
android:title="@string/preferences__internal_display">
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
android:key="internal.recipient_details"
android:defaultValue="false"
android:summary="@string/preferences__internal_user_details_description"
android:title="@string/preferences__internal_user_details" />
</PreferenceCategory>
<PreferenceCategory
android:key="internal_storage"
android:title="@string/preferences__internal_storage_service">