WIP: enable contact with UI

This commit is contained in:
Ryan ZHAO 2021-05-11 17:05:04 +10:00
parent 2cac49b965
commit b43000bdd0
8 changed files with 316 additions and 272 deletions

View file

@ -17,8 +17,6 @@
package org.thoughtcrime.securesms.conversation; package org.thoughtcrime.securesms.conversation;
import android.Manifest; import android.Manifest;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.content.ActivityNotFoundException; import android.content.ActivityNotFoundException;
@ -58,9 +56,7 @@ import android.view.View.OnFocusChangeListener;
import android.view.View.OnKeyListener; import android.view.View.OnKeyListener;
import android.view.WindowManager; import android.view.WindowManager;
import android.view.inputmethod.EditorInfo; import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.ProgressBar; import android.widget.ProgressBar;
@ -220,14 +216,14 @@ import network.loki.messenger.R;
*/ */
@SuppressLint("StaticFieldLeak") @SuppressLint("StaticFieldLeak")
public class ConversationActivity extends PassphraseRequiredActionBarActivity public class ConversationActivity extends PassphraseRequiredActionBarActivity
implements ConversationFragment.ConversationFragmentListener, implements ConversationFragment.ConversationFragmentListener,
AttachmentManager.AttachmentListener, AttachmentManager.AttachmentListener,
RecipientModifiedListener, RecipientModifiedListener,
OnKeyboardShownListener, OnKeyboardShownListener,
InputPanel.Listener, InputPanel.Listener,
InputPanel.MediaListener, InputPanel.MediaListener,
ComposeText.CursorPositionChangedListener, ComposeText.CursorPositionChangedListener,
ConversationSearchBottomBar.EventListener ConversationSearchBottomBar.EventListener
{ {
private static final String TAG = ConversationActivity.class.getSimpleName(); private static final String TAG = ConversationActivity.class.getSimpleName();
@ -242,11 +238,11 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
public static final String LAST_SEEN_EXTRA = "last_seen"; public static final String LAST_SEEN_EXTRA = "last_seen";
public static final String STARTING_POSITION_EXTRA = "starting_position"; public static final String STARTING_POSITION_EXTRA = "starting_position";
// private static final int PICK_GALLERY = 1; // private static final int PICK_GALLERY = 1;
private static final int PICK_DOCUMENT = 2; private static final int PICK_DOCUMENT = 2;
private static final int PICK_AUDIO = 3; private static final int PICK_AUDIO = 3;
private static final int PICK_CONTACT = 4; private static final int PICK_CONTACT = 4;
// private static final int GET_CONTACT_DETAILS = 5; // private static final int GET_CONTACT_DETAILS = 5;
// private static final int GROUP_EDIT = 6; // private static final int GROUP_EDIT = 6;
private static final int TAKE_PHOTO = 7; private static final int TAKE_PHOTO = 7;
private static final int ADD_CONTACT = 8; private static final int ADD_CONTACT = 8;
@ -261,7 +257,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
private ImageButton sendButton; private ImageButton sendButton;
private ImageButton attachButton; private ImageButton attachButton;
private ProfilePictureView profilePictureView; private ProfilePictureView profilePictureView;
private EditText titleTextView; private TextView titleTextView;
private ConversationFragment fragment; private ConversationFragment fragment;
private Button unblockButton; private Button unblockButton;
private Button makeDefaultSmsButton; private Button makeDefaultSmsButton;
@ -274,7 +270,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
private ImageView muteIndicatorImageView; private ImageView muteIndicatorImageView;
private TextView subtitleTextView; private TextView subtitleTextView;
private View homeButtonContainer; private View homeButtonContainer;
private View cancelButtonContainer;
private AttachmentTypeSelector attachmentTypeSelector; private AttachmentTypeSelector attachmentTypeSelector;
private AttachmentManager attachmentManager; private AttachmentManager attachmentManager;
@ -378,52 +373,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
} }
}); });
if (isGroupConversation()) {
titleTextView.setEnabled(false);
} else {
titleTextView.setImeOptions(EditorInfo.IME_ACTION_DONE);
titleTextView.setOnEditorActionListener((v, actionId, event) -> {
if (actionId == EditorInfo.IME_ACTION_DONE) {
String nickname = v.getText().toString().trim();
SSKEnvironment.shared.getProfileManager().setDisplayName(this, getRecipient(), nickname);
v.clearFocus();
return true;
}
return false;
});
titleTextView.setOnFocusChangeListener((v, hasFocus) -> {
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
if (!hasFocus) {
EditText textView = (EditText) v;
if (textView.getText().toString().isEmpty()) {
textView.setText(getRecipient().getName());
}
imm.hideSoftInputFromWindow(v.getWindowToken(),0);
inputPanel.animate().alpha(1f).setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
inputPanel.setVisibility(View.VISIBLE);
}
});
cancelButtonContainer.setVisibility(View.GONE);
} else {
inputPanel.animate().alpha(0f).setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
inputPanel.setVisibility(View.INVISIBLE);
}
});
String nickname = DatabaseFactory.getStorage(this).getDisplayName(getRecipient().getAddress().serialize());
titleTextView.setText(nickname);
if (nickname != null) {
titleTextView.setSelection(nickname.length());
}
imm.showSoftInput(v, 0);
cancelButtonContainer.setVisibility(View.VISIBLE);
}
});
}
MentionManagerUtilities.INSTANCE.populateUserPublicKeyCacheIfNeeded(threadId, this); MentionManagerUtilities.INSTANCE.populateUserPublicKeyCacheIfNeeded(threadId, this);
OpenGroup publicChat = DatabaseFactory.getLokiThreadDatabase(this).getPublicChat(threadId); OpenGroup publicChat = DatabaseFactory.getLokiThreadDatabase(this).getPublicChat(threadId);
@ -471,7 +420,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
protected void onNewIntent(Intent intent) { protected void onNewIntent(Intent intent) {
super.onNewIntent(intent); super.onNewIntent(intent);
Log.i(TAG, "onNewIntent()"); Log.i(TAG, "onNewIntent()");
if (isFinishing()) { if (isFinishing()) {
Log.w(TAG, "Activity is finishing..."); Log.w(TAG, "Activity is finishing...");
return; return;
@ -566,85 +515,85 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
super.onActivityResult(reqCode, resultCode, data); super.onActivityResult(reqCode, resultCode, data);
if ((data == null && reqCode != TAKE_PHOTO && reqCode != SMS_DEFAULT) || if ((data == null && reqCode != TAKE_PHOTO && reqCode != SMS_DEFAULT) ||
(resultCode != RESULT_OK && reqCode != SMS_DEFAULT)) (resultCode != RESULT_OK && reqCode != SMS_DEFAULT))
{ {
updateLinkPreviewState(); updateLinkPreviewState();
return; return;
} }
switch (reqCode) { switch (reqCode) {
case PICK_DOCUMENT: case PICK_DOCUMENT:
setMedia(data.getData(), MediaType.DOCUMENT); setMedia(data.getData(), MediaType.DOCUMENT);
break; break;
case PICK_AUDIO: case PICK_AUDIO:
setMedia(data.getData(), MediaType.AUDIO); setMedia(data.getData(), MediaType.AUDIO);
break; break;
case TAKE_PHOTO: case TAKE_PHOTO:
if (attachmentManager.getCaptureUri() != null) { if (attachmentManager.getCaptureUri() != null) {
setMedia(attachmentManager.getCaptureUri(), MediaType.IMAGE); setMedia(attachmentManager.getCaptureUri(), MediaType.IMAGE);
} }
break; break;
case ADD_CONTACT: case ADD_CONTACT:
recipient = Recipient.from(this, recipient.getAddress(), true); recipient = Recipient.from(this, recipient.getAddress(), true);
recipient.addListener(this); recipient.addListener(this);
fragment.reloadList(); fragment.reloadList();
break; break;
/* /*
case PICK_LOCATION: case PICK_LOCATION:
SignalPlace place = new SignalPlace(PlacePicker.getPlace(data, this)); SignalPlace place = new SignalPlace(PlacePicker.getPlace(data, this));
attachmentManager.setLocation(place, getCurrentMediaConstraints()); attachmentManager.setLocation(place, getCurrentMediaConstraints());
break; break;
*/ */
case PICK_GIF: case PICK_GIF:
setMedia(data.getData(), setMedia(data.getData(),
MediaType.GIF, MediaType.GIF,
data.getIntExtra(GiphyActivity.EXTRA_WIDTH, 0), data.getIntExtra(GiphyActivity.EXTRA_WIDTH, 0),
data.getIntExtra(GiphyActivity.EXTRA_HEIGHT, 0)); data.getIntExtra(GiphyActivity.EXTRA_HEIGHT, 0));
break; break;
case SMS_DEFAULT: case SMS_DEFAULT:
initializeSecurity(true, isDefaultSms); initializeSecurity(true, isDefaultSms);
break; break;
case MEDIA_SENDER: case MEDIA_SENDER:
long expiresIn = recipient.getExpireMessages() * 1000L; long expiresIn = recipient.getExpireMessages() * 1000L;
int subscriptionId = -1; int subscriptionId = -1;
boolean initiating = threadId == -1; boolean initiating = threadId == -1;
String message = data.getStringExtra(MediaSendActivity.EXTRA_MESSAGE); String message = data.getStringExtra(MediaSendActivity.EXTRA_MESSAGE);
SlideDeck slideDeck = new SlideDeck(); SlideDeck slideDeck = new SlideDeck();
List<Media> mediaList = data.getParcelableArrayListExtra(MediaSendActivity.EXTRA_MEDIA); List<Media> mediaList = data.getParcelableArrayListExtra(MediaSendActivity.EXTRA_MEDIA);
for (Media mediaItem : mediaList) { for (Media mediaItem : mediaList) {
if (MediaUtil.isVideoType(mediaItem.getMimeType())) { if (MediaUtil.isVideoType(mediaItem.getMimeType())) {
slideDeck.addSlide(new VideoSlide(this, mediaItem.getUri(), 0, mediaItem.getCaption().orNull())); slideDeck.addSlide(new VideoSlide(this, mediaItem.getUri(), 0, mediaItem.getCaption().orNull()));
} else if (MediaUtil.isGif(mediaItem.getMimeType())) { } else if (MediaUtil.isGif(mediaItem.getMimeType())) {
slideDeck.addSlide(new GifSlide(this, mediaItem.getUri(), 0, mediaItem.getWidth(), mediaItem.getHeight(), mediaItem.getCaption().orNull())); slideDeck.addSlide(new GifSlide(this, mediaItem.getUri(), 0, mediaItem.getWidth(), mediaItem.getHeight(), mediaItem.getCaption().orNull()));
} else if (MediaUtil.isImageType(mediaItem.getMimeType())) { } else if (MediaUtil.isImageType(mediaItem.getMimeType())) {
slideDeck.addSlide(new ImageSlide(this, mediaItem.getUri(), 0, mediaItem.getWidth(), mediaItem.getHeight(), mediaItem.getCaption().orNull())); slideDeck.addSlide(new ImageSlide(this, mediaItem.getUri(), 0, mediaItem.getWidth(), mediaItem.getHeight(), mediaItem.getCaption().orNull()));
} else { } else {
Log.w(TAG, "Asked to send an unexpected mimeType: '" + mediaItem.getMimeType() + "'. Skipping."); Log.w(TAG, "Asked to send an unexpected mimeType: '" + mediaItem.getMimeType() + "'. Skipping.");
}
} }
}
final Context context = ConversationActivity.this.getApplicationContext(); final Context context = ConversationActivity.this.getApplicationContext();
sendMediaMessage(message, sendMediaMessage(message,
slideDeck, slideDeck,
inputPanel.getQuote().orNull(), inputPanel.getQuote().orNull(),
Optional.absent(), Optional.absent(),
initiating).addListener(new AssertedSuccessListener<Void>() { initiating).addListener(new AssertedSuccessListener<Void>() {
@Override @Override
public void onSuccess(Void result) { public void onSuccess(Void result) {
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> { AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
Stream.of(slideDeck.getSlides()) Stream.of(slideDeck.getSlides())
.map(Slide::getUri) .map(Slide::getUri)
.withoutNulls() .withoutNulls()
.filter(BlobProvider::isAuthority) .filter(BlobProvider::isAuthority)
.forEach(uri -> BlobProvider.getInstance().delete(context, uri)); .forEach(uri -> BlobProvider.getInstance().delete(context, uri));
}); });
} }
}); });
break; break;
} }
} }
@ -722,14 +671,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
if (isSingleConversation() && getRecipient().getContactUri() == null) { if (isSingleConversation() && getRecipient().getContactUri() == null) {
inflater.inflate(R.menu.conversation_add_to_contacts, menu); inflater.inflate(R.menu.conversation_add_to_contacts, menu);
} }
if (recipient != null && recipient.isLocalNumber()) { if (recipient != null && recipient.isLocalNumber()) {
if (isSecureText) menu.findItem(R.id.menu_call_secure).setVisible(false); if (isSecureText) menu.findItem(R.id.menu_call_secure).setVisible(false);
else menu.findItem(R.id.menu_call_insecure).setVisible(false); else menu.findItem(R.id.menu_call_insecure).setVisible(false);
MenuItem muteItem = menu.findItem(R.id.menu_mute_notifications); MenuItem muteItem = menu.findItem(R.id.menu_mute_notifications);
if (muteItem != null) { if (muteItem != null) {
muteItem.setVisible(false); muteItem.setVisible(false);
} }
@ -797,25 +742,25 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
switch (item.getItemId()) { switch (item.getItemId()) {
// case R.id.menu_call_secure: handleDial(getRecipient(), true); return true; // case R.id.menu_call_secure: handleDial(getRecipient(), true); return true;
// case R.id.menu_call_insecure: handleDial(getRecipient(), false); return true; // case R.id.menu_call_insecure: handleDial(getRecipient(), false); return true;
case R.id.menu_unblock: handleUnblock(); return true; case R.id.menu_unblock: handleUnblock(); return true;
case R.id.menu_block: handleBlock(); return true; case R.id.menu_block: handleBlock(); return true;
case R.id.menu_copy_session_id: handleCopySessionID(); return true; case R.id.menu_copy_session_id: handleCopySessionID(); return true;
case R.id.menu_view_media: handleViewMedia(); return true; case R.id.menu_view_media: handleViewMedia(); return true;
case R.id.menu_add_shortcut: handleAddShortcut(); return true; case R.id.menu_add_shortcut: handleAddShortcut(); return true;
case R.id.menu_search: handleSearch(); return true; case R.id.menu_search: handleSearch(); return true;
// case R.id.menu_add_to_contacts: handleAddToContacts(); return true; // case R.id.menu_add_to_contacts: handleAddToContacts(); return true;
// case R.id.menu_reset_secure_session: handleResetSecureSession(); return true; // case R.id.menu_reset_secure_session: handleResetSecureSession(); return true;
// case R.id.menu_group_recipients: handleDisplayGroupRecipients(); return true; // case R.id.menu_group_recipients: handleDisplayGroupRecipients(); return true;
case R.id.menu_distribution_broadcast: handleDistributionBroadcastEnabled(item); return true; case R.id.menu_distribution_broadcast: handleDistributionBroadcastEnabled(item); return true;
case R.id.menu_distribution_conversation: handleDistributionConversationEnabled(item); return true; case R.id.menu_distribution_conversation: handleDistributionConversationEnabled(item); return true;
case R.id.menu_edit_group: handleEditPushGroup(); return true; case R.id.menu_edit_group: handleEditPushGroup(); return true;
case R.id.menu_leave: handleLeavePushGroup(); return true; case R.id.menu_leave: handleLeavePushGroup(); return true;
case R.id.menu_mute_notifications: handleMuteNotifications(); return true; case R.id.menu_mute_notifications: handleMuteNotifications(); return true;
case R.id.menu_unmute_notifications: handleUnmuteNotifications(); return true; case R.id.menu_unmute_notifications: handleUnmuteNotifications(); return true;
// case R.id.menu_conversation_settings: handleConversationSettings(); return true; // case R.id.menu_conversation_settings: handleConversationSettings(); return true;
case R.id.menu_expiring_messages_off: case R.id.menu_expiring_messages_off:
case R.id.menu_expiring_messages: handleSelectMessageExpiration(); return true; case R.id.menu_expiring_messages: handleSelectMessageExpiration(); return true;
case android.R.id.home: handleReturnToConversationList(); return true; case android.R.id.home: handleReturnToConversationList(); return true;
} }
return false; return false;
@ -886,7 +831,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
@Override @Override
protected Void doInBackground(Void... params) { protected Void doInBackground(Void... params) {
DatabaseFactory.getRecipientDatabase(ConversationActivity.this) DatabaseFactory.getRecipientDatabase(ConversationActivity.this)
.setMuted(recipient, until); .setMuted(recipient, until);
return null; return null;
} }
@ -901,7 +846,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
@Override @Override
protected Void doInBackground(Void... params) { protected Void doInBackground(Void... params) {
DatabaseFactory.getRecipientDatabase(ConversationActivity.this) DatabaseFactory.getRecipientDatabase(ConversationActivity.this)
.setMuted(recipient, 0); .setMuted(recipient, 0);
return null; return null;
} }
@ -913,20 +858,20 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
int bodyRes = R.string.ConversationActivity_you_will_once_again_be_able_to_receive_messages_and_calls_from_this_contact; int bodyRes = R.string.ConversationActivity_you_will_once_again_be_able_to_receive_messages_and_calls_from_this_contact;
new AlertDialog.Builder(this) new AlertDialog.Builder(this)
.setTitle(titleRes) .setTitle(titleRes)
.setMessage(bodyRes) .setMessage(bodyRes)
.setNegativeButton(android.R.string.cancel, null) .setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(R.string.ConversationActivity_unblock, (dialog, which) -> { .setPositiveButton(R.string.ConversationActivity_unblock, (dialog, which) -> {
new AsyncTask<Void, Void, Void>() { new AsyncTask<Void, Void, Void>() {
@Override @Override
protected Void doInBackground(Void... params) { protected Void doInBackground(Void... params) {
DatabaseFactory.getRecipientDatabase(ConversationActivity.this) DatabaseFactory.getRecipientDatabase(ConversationActivity.this)
.setBlocked(recipient, false); .setBlocked(recipient, false);
return null; return null;
} }
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}).show(); }).show();
} }
@TargetApi(Build.VERSION_CODES.KITKAT) @TargetApi(Build.VERSION_CODES.KITKAT)
@ -996,7 +941,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
if (icon == null) { if (icon == null) {
icon = IconCompat.createWithResource(context, recipient.isGroupRecipient() ? R.mipmap.ic_group_shortcut icon = IconCompat.createWithResource(context, recipient.isGroupRecipient() ? R.mipmap.ic_group_shortcut
: R.mipmap.ic_person_shortcut); : R.mipmap.ic_person_shortcut);
} }
return icon; return icon;
@ -1006,14 +951,14 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
protected void onPostExecute(IconCompat icon) { protected void onPostExecute(IconCompat icon) {
Context context = getApplicationContext(); Context context = getApplicationContext();
String name = Optional.fromNullable(recipient.getName()) String name = Optional.fromNullable(recipient.getName())
.or(Optional.fromNullable(recipient.getProfileName())) .or(Optional.fromNullable(recipient.getProfileName()))
.or(recipient.toShortString()); .or(recipient.toShortString());
ShortcutInfoCompat shortcutInfo = new ShortcutInfoCompat.Builder(context, recipient.getAddress().serialize() + '-' + System.currentTimeMillis()) ShortcutInfoCompat shortcutInfo = new ShortcutInfoCompat.Builder(context, recipient.getAddress().serialize() + '-' + System.currentTimeMillis())
.setShortLabel(name) .setShortLabel(name)
.setIcon(icon) .setIcon(icon)
.setIntent(ShortcutLauncherActivity.createIntent(context, recipient.getAddress())) .setIntent(ShortcutLauncherActivity.createIntent(context, recipient.getAddress()))
.build(); .build();
if (ShortcutManagerCompat.requestPinShortcut(context, shortcutInfo, null)) { if (ShortcutManagerCompat.requestPinShortcut(context, shortcutInfo, null)) {
Toast.makeText(context, getString(R.string.ConversationActivity_added_to_home_screen), Toast.LENGTH_LONG).show(); Toast.makeText(context, getString(R.string.ConversationActivity_added_to_home_screen), Toast.LENGTH_LONG).show();
@ -1029,7 +974,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
private void handleLeavePushGroup() { private void handleLeavePushGroup() {
if (getRecipient() == null) { if (getRecipient() == null) {
Toast.makeText(this, getString(R.string.ConversationActivity_invalid_recipient), Toast.makeText(this, getString(R.string.ConversationActivity_invalid_recipient),
Toast.LENGTH_LONG).show(); Toast.LENGTH_LONG).show();
return; return;
} }
@ -1092,7 +1037,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
@Override @Override
protected Void doInBackground(Void... params) { protected Void doInBackground(Void... params) {
DatabaseFactory.getThreadDatabase(ConversationActivity.this) DatabaseFactory.getThreadDatabase(ConversationActivity.this)
.setDistributionType(threadId, DistributionTypes.BROADCAST); .setDistributionType(threadId, DistributionTypes.BROADCAST);
return null; return null;
} }
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
@ -1108,7 +1053,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
@Override @Override
protected Void doInBackground(Void... params) { protected Void doInBackground(Void... params) {
DatabaseFactory.getThreadDatabase(ConversationActivity.this) DatabaseFactory.getThreadDatabase(ConversationActivity.this)
.setDistributionType(threadId, DistributionTypes.CONVERSATION); .setDistributionType(threadId, DistributionTypes.CONVERSATION);
return null; return null;
} }
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
@ -1142,7 +1087,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
/* Loki - We don't support SMS /* Loki - We don't support SMS
if (!isSecureText && !isPushGroupConversation()) sendButton.disableTransport(Type.TEXTSECURE); if (!isSecureText && !isPushGroupConversation()) sendButton.disableTransport(Type.TEXTSECURE);
if (recipient.isPushGroupRecipient()) sendButton.disableTransport(Type.SMS); if (recipient.isPushGroupRecipient()) sendButton.disableTransport(Type.SMS);
if (!recipient.isPushGroupRecipient() && recipient.isForceSmsSelection()) { if (!recipient.isPushGroupRecipient() && recipient.isForceSmsSelection()) {
sendButton.setDefaultTransport(Type.SMS); sendButton.setDefaultTransport(Type.SMS);
} else { } else {
@ -1314,7 +1258,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
muteIndicatorImageView = ViewUtil.findById(this, R.id.muteIndicatorImageView); muteIndicatorImageView = ViewUtil.findById(this, R.id.muteIndicatorImageView);
subtitleTextView = ViewUtil.findById(this, R.id.subtitleTextView); subtitleTextView = ViewUtil.findById(this, R.id.subtitleTextView);
homeButtonContainer = ViewUtil.findById(this, R.id.homeButtonContainer); homeButtonContainer = ViewUtil.findById(this, R.id.homeButtonContainer);
cancelButtonContainer = ViewUtil.findById(this, R.id.cancelButtonContainer);
ImageButton quickCameraToggle = ViewUtil.findById(this, R.id.quick_camera_toggle); ImageButton quickCameraToggle = ViewUtil.findById(this, R.id.quick_camera_toggle);
ImageButton inlineAttachmentButton = ViewUtil.findById(this, R.id.inline_attachment_button); ImageButton inlineAttachmentButton = ViewUtil.findById(this, R.id.inline_attachment_button);
@ -1360,12 +1303,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
inlineAttachmentButton.setOnClickListener(v -> handleAddAttachment()); inlineAttachmentButton.setOnClickListener(v -> handleAddAttachment());
homeButtonContainer.setOnClickListener(v -> onSupportNavigateUp()); homeButtonContainer.setOnClickListener(v -> onSupportNavigateUp());
cancelButtonContainer.setOnClickListener(v -> {
titleTextView.setText("");
SSKEnvironment.shared.getProfileManager().setDisplayName(this, getRecipient(), "");
titleTextView.clearFocus();
});
} }
protected void initializeActionBar() { protected void initializeActionBar() {
@ -1480,35 +1417,35 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
Log.i(TAG, "Selected: " + type); Log.i(TAG, "Selected: " + type);
switch (type) { switch (type) {
case AttachmentTypeSelector.ADD_GALLERY: case AttachmentTypeSelector.ADD_GALLERY:
AttachmentManager.selectGallery(this, MEDIA_SENDER, recipient, composeText.getTextTrimmed()); break; AttachmentManager.selectGallery(this, MEDIA_SENDER, recipient, composeText.getTextTrimmed()); break;
case AttachmentTypeSelector.ADD_DOCUMENT: case AttachmentTypeSelector.ADD_DOCUMENT:
AttachmentManager.selectDocument(this, PICK_DOCUMENT); break; AttachmentManager.selectDocument(this, PICK_DOCUMENT); break;
case AttachmentTypeSelector.ADD_SOUND: case AttachmentTypeSelector.ADD_SOUND:
AttachmentManager.selectAudio(this, PICK_AUDIO); break; AttachmentManager.selectAudio(this, PICK_AUDIO); break;
case AttachmentTypeSelector.ADD_CONTACT_INFO: case AttachmentTypeSelector.ADD_CONTACT_INFO:
AttachmentManager.selectContactInfo(this, PICK_CONTACT); break; AttachmentManager.selectContactInfo(this, PICK_CONTACT); break;
case AttachmentTypeSelector.ADD_LOCATION: case AttachmentTypeSelector.ADD_LOCATION:
AttachmentManager.selectLocation(this, PICK_LOCATION); break; AttachmentManager.selectLocation(this, PICK_LOCATION); break;
case AttachmentTypeSelector.TAKE_PHOTO: case AttachmentTypeSelector.TAKE_PHOTO:
attachmentManager.capturePhoto(this, TAKE_PHOTO); break; attachmentManager.capturePhoto(this, TAKE_PHOTO); break;
case AttachmentTypeSelector.ADD_GIF: case AttachmentTypeSelector.ADD_GIF:
boolean hasSeenGIFMetaDataWarning = TextSecurePreferences.hasSeenGIFMetaDataWarning(this); boolean hasSeenGIFMetaDataWarning = TextSecurePreferences.hasSeenGIFMetaDataWarning(this);
if (!hasSeenGIFMetaDataWarning) { if (!hasSeenGIFMetaDataWarning) {
AlertDialog.Builder builder = new AlertDialog.Builder(this); AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Search GIFs?"); builder.setTitle("Search GIFs?");
builder.setMessage("You will not have full metadata protection when sending GIFs."); builder.setMessage("You will not have full metadata protection when sending GIFs.");
builder.setPositiveButton("OK", (dialog, which) -> { builder.setPositiveButton("OK", (dialog, which) -> {
AttachmentManager.selectGif(this, PICK_GIF);
dialog.dismiss();
});
builder.setNegativeButton("Cancel", (dialog, which) -> dialog.dismiss());
builder.create().show();
TextSecurePreferences.setHasSeenGIFMetaDataWarning(this);
} else {
AttachmentManager.selectGif(this, PICK_GIF); AttachmentManager.selectGif(this, PICK_GIF);
dialog.dismiss(); }
}); break;
builder.setNegativeButton("Cancel", (dialog, which) -> dialog.dismiss());
builder.create().show();
TextSecurePreferences.setHasSeenGIFMetaDataWarning(this);
} else {
AttachmentManager.selectGif(this, PICK_GIF);
}
break;
} }
} }
@ -1603,8 +1540,8 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
draftDatabase.insertDrafts(threadId, drafts); draftDatabase.insertDrafts(threadId, drafts);
threadDatabase.updateSnippet(threadId, drafts.getSnippet(ConversationActivity.this), threadDatabase.updateSnippet(threadId, drafts.getSnippet(ConversationActivity.this),
drafts.getUriSnippet(), drafts.getUriSnippet(),
System.currentTimeMillis(), Types.BASE_DRAFT_TYPE, true); System.currentTimeMillis(), Types.BASE_DRAFT_TYPE, true);
} else if (threadId > 0) { } else if (threadId > 0) {
threadDatabase.update(threadId, false); threadDatabase.update(threadId, false);
} }
@ -1707,10 +1644,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
String timestamp = new SimpleDateFormat("yyyy-MM-dd-HHmmss", Locale.US).format(new Date()); String timestamp = new SimpleDateFormat("yyyy-MM-dd-HHmmss", Locale.US).format(new Date());
String filename = String.format("signal-%s.txt", timestamp); String filename = String.format("signal-%s.txt", timestamp);
Uri textUri = BlobProvider.getInstance() Uri textUri = BlobProvider.getInstance()
.forData(textData) .forData(textData)
.withMimeType(MediaTypes.LONG_TEXT) .withMimeType(MediaTypes.LONG_TEXT)
.withFileName(filename) .withFileName(filename)
.createForSingleSessionInMemory(); .createForSingleSessionInMemory();
textSlide = Optional.of(new TextSlide(this, textUri, filename, textData.length)); textSlide = Optional.of(new TextSlide(this, textUri, filename, textData.length));
} }
@ -1788,10 +1725,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
boolean needsSplit = message.length() > characterCalculator.calculateCharacters(message).maxPrimaryMessageSize; boolean needsSplit = message.length() > characterCalculator.calculateCharacters(message).maxPrimaryMessageSize;
boolean isMediaMessage = attachmentManager.isAttachmentPresent() || boolean isMediaMessage = attachmentManager.isAttachmentPresent() ||
// recipient.isGroupRecipient() || // recipient.isGroupRecipient() ||
inputPanel.getQuote().isPresent() || inputPanel.getQuote().isPresent() ||
linkPreviewViewModel.hasLinkPreview() || linkPreviewViewModel.hasLinkPreview() ||
LinkPreviewUtil.isValidMediaUrl(message) || // Loki - Send GIFs as media messages LinkPreviewUtil.isValidMediaUrl(message) || // Loki - Send GIFs as media messages
needsSplit; needsSplit;
if (isMediaMessage) { if (isMediaMessage) {
sendMediaMessage(initiating); sendMediaMessage(initiating);
@ -1812,7 +1749,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
} }
private void sendMediaMessage(boolean initiating) private void sendMediaMessage(boolean initiating)
throws InvalidMessageException throws InvalidMessageException
{ {
Log.i(TAG, "Sending media message..."); Log.i(TAG, "Sending media message...");
sendMediaMessage(getMessage(), attachmentManager.buildSlideDeck(), inputPanel.getQuote().orNull(), linkPreviewViewModel.getActiveLinkPreview(), initiating); sendMediaMessage(getMessage(), attachmentManager.buildSlideDeck(), inputPanel.getQuote().orNull(), linkPreviewViewModel.getActiveLinkPreview(), initiating);
@ -1872,7 +1809,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
} }
private void sendTextMessage(final boolean initiating) private void sendTextMessage(final boolean initiating)
throws InvalidMessageException throws InvalidMessageException
{ {
final Context context = getApplicationContext(); final Context context = getApplicationContext();
final String messageBody = getMessage(); final String messageBody = getMessage();
@ -1933,10 +1870,10 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
@Override @Override
public void onRecorderPermissionRequired() { public void onRecorderPermissionRequired() {
Permissions.with(this) Permissions.with(this)
.request(Manifest.permission.RECORD_AUDIO) .request(Manifest.permission.RECORD_AUDIO)
.withRationaleDialog(getString(R.string.ConversationActivity_to_send_audio_messages_allow_signal_access_to_your_microphone), R.drawable.ic_baseline_mic_48) .withRationaleDialog(getString(R.string.ConversationActivity_to_send_audio_messages_allow_signal_access_to_your_microphone), R.drawable.ic_baseline_mic_48)
.withPermanentDenialDialog(getString(R.string.ConversationActivity_signal_requires_the_microphone_permission_in_order_to_send_audio_messages)) .withPermanentDenialDialog(getString(R.string.ConversationActivity_signal_requires_the_microphone_permission_in_order_to_send_audio_messages))
.execute(); .execute();
} }
@Override @Override
@ -2095,16 +2032,16 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
@Override @Override
public void onClick(View v) { public void onClick(View v) {
Permissions.with(ConversationActivity.this) Permissions.with(ConversationActivity.this)
.request(Manifest.permission.CAMERA) .request(Manifest.permission.CAMERA)
.withRationaleDialog(getString(R.string.ConversationActivity_to_capture_photos_and_video_allow_signal_access_to_the_camera), R.drawable.ic_baseline_photo_camera_48) .withRationaleDialog(getString(R.string.ConversationActivity_to_capture_photos_and_video_allow_signal_access_to_the_camera), R.drawable.ic_baseline_photo_camera_48)
.withPermanentDenialDialog(getString(R.string.ConversationActivity_signal_needs_the_camera_permission_to_take_photos_or_video)) .withPermanentDenialDialog(getString(R.string.ConversationActivity_signal_needs_the_camera_permission_to_take_photos_or_video))
.onAllGranted(() -> { .onAllGranted(() -> {
composeText.clearFocus(); composeText.clearFocus();
startActivityForResult(MediaSendActivity.buildCameraIntent(ConversationActivity.this, recipient), MEDIA_SENDER); startActivityForResult(MediaSendActivity.buildCameraIntent(ConversationActivity.this, recipient), MEDIA_SENDER);
overridePendingTransition(R.anim.camera_slide_from_bottom, R.anim.stationary); overridePendingTransition(R.anim.camera_slide_from_bottom, R.anim.stationary);
}) })
.onAnyDenied(() -> Toast.makeText(ConversationActivity.this, R.string.ConversationActivity_signal_needs_camera_permissions_to_take_photos_or_video, Toast.LENGTH_LONG).show()) .onAnyDenied(() -> Toast.makeText(ConversationActivity.this, R.string.ConversationActivity_signal_needs_camera_permissions_to_take_photos_or_video, Toast.LENGTH_LONG).show())
.execute(); .execute();
} }
} }
@ -2214,7 +2151,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
} }
if (text.length() > 0) { if (text.length() > 0) {
if (currentMentionStartIndex > text.length()) { if (currentMentionStartIndex > text.length()) {
resetMentions(); // Should never occur resetMentions(); // Should never occur
} }
int lastCharacterIndex = text.length() - 1; int lastCharacterIndex = text.length() - 1;
char lastCharacter = text.charAt(lastCharacterIndex); char lastCharacter = text.charAt(lastCharacterIndex);
@ -2281,12 +2218,12 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
} }
inputPanel.setQuote(GlideApp.with(this), inputPanel.setQuote(GlideApp.with(this),
messageRecord.getDateSent(), messageRecord.getDateSent(),
author, author,
body, body,
slideDeck, slideDeck,
recipient, recipient,
threadId); threadId);
} else if (messageRecord.isMms() && !((MmsMessageRecord) messageRecord).getLinkPreviews().isEmpty()) { } else if (messageRecord.isMms() && !((MmsMessageRecord) messageRecord).getLinkPreviews().isEmpty()) {
LinkPreview linkPreview = ((MmsMessageRecord) messageRecord).getLinkPreviews().get(0); LinkPreview linkPreview = ((MmsMessageRecord) messageRecord).getLinkPreviews().get(0);
@ -2297,26 +2234,26 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
} }
inputPanel.setQuote(GlideApp.with(this), inputPanel.setQuote(GlideApp.with(this),
messageRecord.getDateSent(), messageRecord.getDateSent(),
author, author,
messageRecord.getBody(), messageRecord.getBody(),
slideDeck, slideDeck,
recipient, recipient,
threadId); threadId);
} else { } else {
inputPanel.setQuote(GlideApp.with(this), inputPanel.setQuote(GlideApp.with(this),
messageRecord.getDateSent(), messageRecord.getDateSent(),
author, author,
messageRecord.getBody(), messageRecord.getBody(),
messageRecord.isMms() ? ((MmsMessageRecord) messageRecord).getSlideDeck() : new SlideDeck(), messageRecord.isMms() ? ((MmsMessageRecord) messageRecord).getSlideDeck() : new SlideDeck(),
recipient, recipient,
threadId); threadId);
} }
} }
@Override @Override
public void onMessageActionToolbarOpened() { public void onMessageActionToolbarOpened() {
searchViewItem.collapseActionView(); searchViewItem.collapseActionView();
} }
@Override @Override
@ -2382,8 +2319,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
} else if (recipient.getAddress().toString().toLowerCase().equals(userPublicKey)) { } else if (recipient.getAddress().toString().toLowerCase().equals(userPublicKey)) {
titleTextView.setText(getResources().getString(R.string.note_to_self)); titleTextView.setText(getResources().getString(R.string.note_to_self));
} else { } else {
boolean hasName = (recipient.getName() != null && !recipient.getName().isEmpty()); String displayName = SSKEnvironment.shared.getProfileManager().getDisplayName(getApplicationContext(), recipient);
titleTextView.setText(hasName ? recipient.getName() : recipient.getAddress().toString()); boolean hasName = displayName != null;
titleTextView.setText(hasName ? displayName : recipient.getAddress().toString());
} }
} }
@ -2434,7 +2372,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
private void updateMessageStatusProgressBar() { private void updateMessageStatusProgressBar() {
if (messageStatus != null) { if (messageStatus != null) {
messageStatusProgressBar.setAlpha(1.0f); messageStatusProgressBar.setAlpha(1.0f);
switch (messageStatus) { switch (messageStatus) {
case "calculatingPoW": setMessageStatusProgressAnimatedIfPossible(25); break; case "calculatingPoW": setMessageStatusProgressAnimatedIfPossible(25); break;
case "contactingNetwork": setMessageStatusProgressAnimatedIfPossible(50); break; case "contactingNetwork": setMessageStatusProgressAnimatedIfPossible(50); break;
@ -2471,7 +2409,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
default: return -1; default: return -1;
} }
} else { } else {
return -1; return -1;
} }
} }

View file

@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.loki.database
import android.content.ContentValues import android.content.ContentValues
import android.content.Context import android.content.Context
import androidx.core.database.getStringOrNull
import net.sqlcipher.Cursor import net.sqlcipher.Cursor
import org.session.libsession.messaging.contacts.Contact import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.messaging.jobs.Job import org.session.libsession.messaging.jobs.Job
@ -35,7 +36,7 @@ class SessionContactDatabase(context: Context, helper: SQLCipherOpenHelper) : Da
fun getContactWithSessionID(sessionID: String): Contact? { fun getContactWithSessionID(sessionID: String): Contact? {
val database = databaseHelper.readableDatabase val database = databaseHelper.readableDatabase
return database.get(sessionContactTable, "$sessionID = ?", arrayOf(sessionID)) { cursor -> return database.get(sessionContactTable, "${SessionContactDatabase.sessionID} = ?", arrayOf(sessionID)) { cursor ->
contactFromCursor(cursor) contactFromCursor(cursor)
} }
} }
@ -55,7 +56,9 @@ class SessionContactDatabase(context: Context, helper: SQLCipherOpenHelper) : Da
contentValues.put(nickname, contact.nickname) contentValues.put(nickname, contact.nickname)
contentValues.put(profilePictureURL, contact.profilePictureURL) contentValues.put(profilePictureURL, contact.profilePictureURL)
contentValues.put(profilePictureFileName, contact.profilePictureFileName) contentValues.put(profilePictureFileName, contact.profilePictureFileName)
contentValues.put(profilePictureEncryptionKey, Base64.encodeBytes(contact.profilePictureEncryptionKey)) contact.profilePictureEncryptionKey?.let {
contentValues.put(profilePictureEncryptionKey, Base64.encodeBytes(it))
}
contentValues.put(threadID, threadID) contentValues.put(threadID, threadID)
contentValues.put(isTrusted, if (contact.isTrusted) 1 else 0) contentValues.put(isTrusted, if (contact.isTrusted) 1 else 0)
database.insertOrUpdate(sessionContactTable, contentValues, "$sessionID = ?", arrayOf(contact.sessionID)) database.insertOrUpdate(sessionContactTable, contentValues, "$sessionID = ?", arrayOf(contact.sessionID))
@ -64,11 +67,13 @@ class SessionContactDatabase(context: Context, helper: SQLCipherOpenHelper) : Da
private fun contactFromCursor(cursor: Cursor): Contact { private fun contactFromCursor(cursor: Cursor): Contact {
val sessionID = cursor.getString(sessionID) val sessionID = cursor.getString(sessionID)
val contact = Contact(sessionID) val contact = Contact(sessionID)
contact.name = cursor.getString(name) contact.name = cursor.getStringOrNull(name)
contact.nickname = cursor.getString(nickname) contact.nickname = cursor.getStringOrNull(nickname)
contact.profilePictureURL = cursor.getString(profilePictureURL) contact.profilePictureURL = cursor.getStringOrNull(profilePictureURL)
contact.profilePictureFileName = cursor.getString(profilePictureFileName) contact.profilePictureFileName = cursor.getStringOrNull(profilePictureFileName)
contact.profilePictureEncryptionKey = Base64.decode(cursor.getString(profilePictureEncryptionKey)) cursor.getStringOrNull(profilePictureEncryptionKey)?.let {
contact.profilePictureEncryptionKey = Base64.decode(it)
}
contact.threadID = cursor.getInt(threadID) contact.threadID = cursor.getInt(threadID)
contact.isTrusted = cursor.getInt(isTrusted) != 0 contact.isTrusted = cursor.getInt(isTrusted) != 0
return contact return contact

View file

@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.loki.dialogs
import android.content.ClipData import android.content.ClipData
import android.content.ClipboardManager import android.content.ClipboardManager
import android.content.Context import android.content.Context
import android.opengl.Visibility
import android.os.Bundle import android.os.Bundle
import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import android.view.LayoutInflater import android.view.LayoutInflater
@ -12,6 +13,9 @@ import android.widget.Toast
import kotlinx.android.synthetic.main.fragment_user_details_bottom_sheet.* import kotlinx.android.synthetic.main.fragment_user_details_bottom_sheet.*
import kotlinx.android.synthetic.main.view_conversation.view.* import kotlinx.android.synthetic.main.view_conversation.view.*
import network.loki.messenger.R import network.loki.messenger.R
import org.session.libsession.messaging.threads.Address
import org.session.libsession.messaging.threads.recipients.Recipient
import org.session.libsession.utilities.SSKEnvironment
import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.mms.GlideApp import org.thoughtcrime.securesms.mms.GlideApp
@ -24,11 +28,32 @@ public class UserDetailsBottomSheet : BottomSheetDialogFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
val publicKey = arguments?.getString("publicKey") ?: return dismiss() val publicKey = arguments?.getString("publicKey") ?: return dismiss()
val recipient = Recipient.from(requireContext(), Address.fromSerialized(publicKey), false)
profilePictureView.publicKey = publicKey profilePictureView.publicKey = publicKey
profilePictureView.glide = GlideApp.with(this) profilePictureView.glide = GlideApp.with(this)
profilePictureView.isLarge = true profilePictureView.isLarge = true
profilePictureView.update() profilePictureView.update()
nameTextView.text = DatabaseFactory.getLokiUserDatabase(requireContext()).getDisplayName(publicKey) ?: "Anonymous" nameTextViewContainer.visibility = View.VISIBLE
nameTextViewContainer.setOnClickListener {
nameTextViewContainer.visibility = View.INVISIBLE
nameEditContainer.visibility = View.VISIBLE
nameEditText.requestFocus()
}
btnCancelNickNameEdit.setOnClickListener {
nameEditText.clearFocus()
nameTextViewContainer.visibility = View.VISIBLE
nameEditContainer.visibility = View.INVISIBLE
nameEditText.text = null
}
btnSaveNickNameEdit.setOnClickListener {
nameEditText.clearFocus()
nameTextViewContainer.visibility = View.VISIBLE
nameEditContainer.visibility = View.INVISIBLE
var newNickName = null
SSKEnvironment.shared.profileManager.setDisplayName(requireContext(), recipient, newNickName)
nameTextView.text = SSKEnvironment.shared.profileManager.getDisplayName(requireContext(), recipient) ?: "Anonymous"
}
nameTextView.text = SSKEnvironment.shared.profileManager.getDisplayName(requireContext(), recipient) ?: "Anonymous"
publicKeyTextView.text = publicKey publicKeyTextView.text = publicKey
copyButton.setOnClickListener { copyButton.setOnClickListener {
val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager

View file

@ -1,6 +1,7 @@
package org.thoughtcrime.securesms.loki.utilities package org.thoughtcrime.securesms.loki.utilities
import android.content.ContentValues import android.content.ContentValues
import androidx.core.database.getStringOrNull
import net.sqlcipher.Cursor import net.sqlcipher.Cursor
import net.sqlcipher.database.SQLiteDatabase import net.sqlcipher.database.SQLiteDatabase
import org.session.libsignal.utilities.Base64 import org.session.libsignal.utilities.Base64
@ -56,4 +57,8 @@ fun Cursor.getLong(columnName: String): Long {
fun Cursor.getBase64EncodedData(columnName: String): ByteArray { fun Cursor.getBase64EncodedData(columnName: String): ByteArray {
return Base64.decode(getString(columnName)) return Base64.decode(getString(columnName))
}
fun Cursor.getStringOrNull(columnName: String): String? {
return getStringOrNull(getColumnIndexOrThrow(columnName))
} }

View file

@ -73,4 +73,16 @@ class ProfileManager: SSKEnvironment.ProfileManagerProtocol {
override fun updateOpenGroupProfilePicturesIfNeeded(context: Context) { override fun updateOpenGroupProfilePicturesIfNeeded(context: Context) {
ApplicationContext.getInstance(context).updateOpenGroupProfilePicturesIfNeeded() ApplicationContext.getInstance(context).updateOpenGroupProfilePicturesIfNeeded()
} }
override fun getDisplayName(context: Context, recipient: Recipient): String? {
val sessionID = recipient.address.serialize()
val contactDatabase = DatabaseFactory.getSessionContactDatabase(context)
var contact = contactDatabase.getContactWithSessionID(sessionID)
if (contact == null) {
contact = Contact(sessionID)
contact.name = DatabaseFactory.getLokiUserDatabase(context).getDisplayName(sessionID) ?: recipient.profileName ?: recipient.name
contactDatabase.setContact(contact)
}
return contact.displayName(Contact.contextForRecipient(recipient))
}
} }

View file

@ -51,7 +51,7 @@
android:layout_marginStart="@dimen/medium_spacing" android:layout_marginStart="@dimen/medium_spacing"
android:orientation="vertical"> android:orientation="vertical">
<EditText <TextView
android:id="@+id/titleTextView" android:id="@+id/titleTextView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -59,10 +59,8 @@
android:maxLines="1" android:maxLines="1"
android:ellipsize="end" android:ellipsize="end"
android:text="Conversation" android:text="Conversation"
android:hint="Enter a name"
android:textColor="@color/text" android:textColor="@color/text"
android:textSize="@dimen/large_font_size" android:textSize="@dimen/large_font_size"
android:inputType="text"
android:fontFamily="sans-serif-medium" /> android:fontFamily="sans-serif-medium" />
<LinearLayout <LinearLayout

View file

@ -16,17 +16,77 @@
android:id="@+id/profilePictureView" android:id="@+id/profilePictureView"
android:layout_width="@dimen/large_profile_picture_size" android:layout_width="@dimen/large_profile_picture_size"
android:layout_height="@dimen/large_profile_picture_size" android:layout_height="@dimen/large_profile_picture_size"
android:layout_marginTop="@dimen/large_spacing" /> android:layout_marginTop="@dimen/large_spacing"/>
<TextView <RelativeLayout
android:id="@+id/nameTextView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="@dimen/medium_spacing" android:layout_marginTop="@dimen/medium_spacing"
android:textSize="@dimen/massive_font_size" android:gravity="center">
android:textStyle="bold"
android:textColor="@color/text" <LinearLayout
android:text="Spiderman" /> android:id="@+id/nameTextViewContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:visibility="invisible">
<TextView
android:id="@+id/nameTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="@dimen/massive_font_size"
android:textStyle="bold"
android:textColor="@color/text"
android:text="Spiderman"
android:paddingStart="24dp"
android:paddingEnd="0dp"
android:drawablePadding="@dimen/small_spacing"
app:drawableEndCompat="@drawable/ic_baseline_edit_24" />
</LinearLayout>
<LinearLayout
android:id="@+id/nameEditContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
android:visibility="invisible">
<ImageView
android:id="@+id/btnCancelNickNameEdit"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/ic_baseline_clear_24"/>
<EditText
android:id="@+id/nameEditText"
style="@style/SessionEditText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="@dimen/small_spacing"
android:layout_marginEnd="@dimen/small_spacing"
android:textAlignment="center"
android:textSize="@dimen/very_large_font_size"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:inputType="text"
android:singleLine="true"
android:imeOptions="actionDone"
android:hint="Enter a name"/>
<ImageView
android:id="@+id/btnSaveNickNameEdit"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center"
android:src="@drawable/ic_baseline_done_24"/>
</LinearLayout>
</RelativeLayout>
<TextView <TextView
style="@style/SessionIDTextView" style="@style/SessionIDTextView"

View file

@ -36,6 +36,7 @@ class SSKEnvironment(
fun setProfileKey(context: Context, recipient: Recipient, profileKey: ByteArray) fun setProfileKey(context: Context, recipient: Recipient, profileKey: ByteArray)
fun setUnidentifiedAccessMode(context: Context, recipient: Recipient, unidentifiedAccessMode: Recipient.UnidentifiedAccessMode) fun setUnidentifiedAccessMode(context: Context, recipient: Recipient, unidentifiedAccessMode: Recipient.UnidentifiedAccessMode)
fun updateOpenGroupProfilePicturesIfNeeded(context: Context) fun updateOpenGroupProfilePicturesIfNeeded(context: Context)
fun getDisplayName(context: Context, recipient: Recipient): String?
} }
interface MessageExpirationManagerProtocol { interface MessageExpirationManagerProtocol {