mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-25 01:07:47 +00:00
Merge branch 'dev' into custom-server
# Conflicts: # src/org/thoughtcrime/securesms/loki/DisplayNameActivity.kt
This commit is contained in:
commit
2f18c5bad2
@ -2,10 +2,8 @@
|
||||
<ScrollView
|
||||
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="match_parent"
|
||||
tools:context=".loki.AccountDetailsActivity">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
51
res/layout/cell_user_selection_view.xml
Normal file
51
res/layout/cell_user_selection_view.xml
Normal file
@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<org.thoughtcrime.securesms.loki.UserSelectionViewCell
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="52dp"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:gravity="center_vertical"
|
||||
android:background="?attr/conversation_list_item_background">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="38dp"
|
||||
android:layout_marginTop="1dp">
|
||||
|
||||
<!-- The frame layout below is a workaround for an avatar image view bug -->
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/profilePictureImageViewContainer"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" >
|
||||
|
||||
<org.thoughtcrime.securesms.components.AvatarImageView
|
||||
android:id="@+id/profilePictureImageView"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_marginBottom="2dp" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/moderatorIconImageView"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginEnd="1.5dp"
|
||||
android:src="@drawable/icon_crown"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentBottom="true" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/displayNameTextView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
style="@style/Signal.Text.Body"
|
||||
android:ellipsize="end" />
|
||||
|
||||
</org.thoughtcrime.securesms.loki.UserSelectionViewCell>
|
@ -71,17 +71,26 @@
|
||||
android:inflatedId="@+id/attachment_editor"
|
||||
android:layout="@layout/conversation_activity_attachment_editor_stub" />
|
||||
|
||||
<FrameLayout
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false">
|
||||
android:orientation="vertical">
|
||||
|
||||
<include layout="@layout/conversation_input_panel" />
|
||||
<include layout="@layout/view_user_selection" />
|
||||
|
||||
<include layout="@layout/conversation_search_nav" />
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false">
|
||||
|
||||
</FrameLayout>
|
||||
<include layout="@layout/conversation_input_panel" />
|
||||
|
||||
<include layout="@layout/conversation_search_nav" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/register_button"
|
||||
|
@ -101,6 +101,7 @@
|
||||
tools:visibility="invisible"
|
||||
tools:hint="Send TextSecure message" >
|
||||
<requestFocus />
|
||||
|
||||
</org.thoughtcrime.securesms.components.ComposeText>
|
||||
|
||||
<FrameLayout
|
||||
|
8
res/layout/view_user_selection.xml
Normal file
8
res/layout/view_user_selection.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<org.thoughtcrime.securesms.loki.UserSelectionView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/userSelectionView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:paddingTop="6dp"
|
||||
android:listSelector="@color/transparent" />
|
@ -2,6 +2,7 @@
|
||||
<resources>
|
||||
<!-- Loki -->
|
||||
<color name="loki_green">#78be20</color>
|
||||
<color name="loki_dark_green">#419B41</color>
|
||||
<color name="loki_darkest_gray">#0a0a0a</color>
|
||||
<!-- Loki -->
|
||||
|
||||
|
@ -1552,7 +1552,7 @@
|
||||
<!-- Display name activity -->
|
||||
<string name="activity_display_name_title">Create Your Loki Messenger Account</string>
|
||||
<string name="activity_display_name_subtitle">Enter a name to be shown to your contacts</string>
|
||||
<string name="activity_display_name_name_edit_text_label">Display Name (Optional)</string>
|
||||
<string name="activity_display_name_name_edit_text_label">Display Name</string>
|
||||
<string name="activity_display_name_button_title">Next</string>
|
||||
<!-- Key pair activity -->
|
||||
<string name="activity_key_pair_title">Create Your Loki Messenger Account</string>
|
||||
|
@ -160,7 +160,7 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActionBarA
|
||||
super.onCreate(icicle);
|
||||
|
||||
String masterHexEncodedPublicKey = TextSecurePreferences.getMasterHexEncodedPublicKey(getContext());
|
||||
boolean isMasterDevice = (masterHexEncodedPublicKey != null);
|
||||
boolean isMasterDevice = (masterHexEncodedPublicKey == null);
|
||||
|
||||
Preference profilePreference = this.findPreference(PREFERENCE_CATEGORY_PROFILE);
|
||||
// Hide if this is a slave device
|
||||
|
@ -203,7 +203,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit
|
||||
int height = profilePictureImageView.getHeight();
|
||||
if (width == 0 || height == 0) return true;
|
||||
profilePictureImageView.getViewTreeObserver().removeOnPreDrawListener(this);
|
||||
JazzIdenticonDrawable identicon = new JazzIdenticonDrawable(width, height, recipient.getAddress().serialize());
|
||||
JazzIdenticonDrawable identicon = new JazzIdenticonDrawable(width, height, recipient.getAddress().serialize().toLowerCase());
|
||||
profilePictureImageView.setImageDrawable(identicon);
|
||||
return true;
|
||||
}
|
||||
|
@ -37,6 +37,8 @@ import org.thoughtcrime.securesms.components.FromTextView;
|
||||
import org.thoughtcrime.securesms.components.ThumbnailView;
|
||||
import org.thoughtcrime.securesms.components.TypingIndicatorView;
|
||||
import org.thoughtcrime.securesms.database.model.ThreadRecord;
|
||||
import org.thoughtcrime.securesms.loki.LokiAPIUtilities;
|
||||
import org.thoughtcrime.securesms.loki.MentionUtilities;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
||||
@ -270,8 +272,9 @@ public class ConversationListItem extends RelativeLayout
|
||||
}
|
||||
|
||||
private @NonNull CharSequence getTrimmedSnippet(@NonNull CharSequence snippet) {
|
||||
return snippet.length() <= MAX_SNIPPET_LENGTH ? snippet
|
||||
: snippet.subSequence(0, MAX_SNIPPET_LENGTH);
|
||||
LokiAPIUtilities.INSTANCE.populateUserIDCacheIfNeeded(threadId, getContext()); // TODO: Terrible place to do this, but okay for now
|
||||
snippet = MentionUtilities.highlightMentions(snippet, this.recipient.isGroupRecipient(), getContext());
|
||||
return snippet.length() <= MAX_SNIPPET_LENGTH ? snippet : snippet.subSequence(0, MAX_SNIPPET_LENGTH);
|
||||
}
|
||||
|
||||
private void setThumbnailSnippet(ThreadRecord thread) {
|
||||
|
@ -232,7 +232,10 @@ public class CreateProfileActivity extends BaseActionBarActivity implements Inje
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {}
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
if (s.toString().getBytes().length > ProfileCipher.NAME_PADDED_LENGTH) {
|
||||
if (s.toString().isEmpty()) {
|
||||
name.getInput().setError("Invalid");
|
||||
finishButton.setEnabled(false);
|
||||
} else if (s.toString().getBytes().length > ProfileCipher.NAME_PADDED_LENGTH) {
|
||||
name.getInput().setError(getString(R.string.CreateProfileActivity_too_long));
|
||||
finishButton.setEnabled(false);
|
||||
} else if (name.getInput().getError() != null || !finishButton.isEnabled()) {
|
||||
|
@ -19,6 +19,7 @@ import android.view.ViewOutlineProvider;
|
||||
import org.thoughtcrime.securesms.color.MaterialColor;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.GeneratedContactPhoto;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.loki.JazzIdenticonDrawable;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
@ -118,11 +119,15 @@ public class AvatarImageView extends AppCompatImageView {
|
||||
|
||||
image = new GeneratedContactPhoto(name, R.drawable.ic_profile_default).asDrawable(context, fallbackColor.toAvatarColor(context));
|
||||
} else {
|
||||
image = new JazzIdenticonDrawable(w, h, recipient.getAddress().serialize());
|
||||
image = new JazzIdenticonDrawable(w, h, recipient.getAddress().serialize().toLowerCase());
|
||||
}
|
||||
setImageDrawable(image);
|
||||
}
|
||||
|
||||
public void update(String hexEncodedPublicKey) {
|
||||
this.recipient = Recipient.from(getContext(), Address.fromSerialized(hexEncodedPublicKey), false);
|
||||
}
|
||||
|
||||
public void setAvatar(@NonNull GlideRequests requestManager, @Nullable Recipient recipient, boolean quickContactEnabled) {
|
||||
this.recipient = recipient;
|
||||
/*
|
||||
|
@ -156,7 +156,11 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil;
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.loki.FriendRequestViewDelegate;
|
||||
import org.thoughtcrime.securesms.loki.LokiAPIUtilities;
|
||||
import org.thoughtcrime.securesms.loki.LokiThreadDatabaseDelegate;
|
||||
import org.thoughtcrime.securesms.loki.LokiUserDatabase;
|
||||
import org.thoughtcrime.securesms.loki.Mention;
|
||||
import org.thoughtcrime.securesms.loki.UserSelectionView;
|
||||
import org.thoughtcrime.securesms.mediasend.Media;
|
||||
import org.thoughtcrime.securesms.mediasend.MediaSendActivity;
|
||||
import org.thoughtcrime.securesms.mms.AttachmentManager;
|
||||
@ -224,12 +228,14 @@ import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.loki.api.LokiAPI;
|
||||
import org.whispersystems.signalservice.loki.messaging.LokiMessageFriendRequestStatus;
|
||||
import org.whispersystems.signalservice.loki.messaging.LokiThreadFriendRequestStatus;
|
||||
import org.whispersystems.signalservice.loki.utilities.Analytics;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedList;
|
||||
@ -239,7 +245,9 @@ import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import kotlin.Unit;
|
||||
import network.loki.messenger.R;
|
||||
import nl.komponents.kovenant.combine.Tuple2;
|
||||
|
||||
import static org.thoughtcrime.securesms.TransportOption.Type;
|
||||
import static org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord;
|
||||
@ -292,23 +300,24 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
private static final int SMS_DEFAULT = 11;
|
||||
private static final int MEDIA_SENDER = 12;
|
||||
|
||||
private GlideRequests glideRequests;
|
||||
protected ComposeText composeText;
|
||||
private AnimatingToggle buttonToggle;
|
||||
private SendButton sendButton;
|
||||
private ImageButton attachButton;
|
||||
protected ConversationTitleView titleView;
|
||||
private TextView charactersLeft;
|
||||
private ConversationFragment fragment;
|
||||
private Button unblockButton;
|
||||
private Button makeDefaultSmsButton;
|
||||
private Button registerButton;
|
||||
private InputAwareLayout container;
|
||||
private View composePanel;
|
||||
protected Stub<ReminderView> reminderView;
|
||||
private Stub<UnverifiedBannerView> unverifiedBannerView;
|
||||
private GlideRequests glideRequests;
|
||||
protected ComposeText composeText;
|
||||
private AnimatingToggle buttonToggle;
|
||||
private SendButton sendButton;
|
||||
private ImageButton attachButton;
|
||||
protected ConversationTitleView titleView;
|
||||
private TextView charactersLeft;
|
||||
private ConversationFragment fragment;
|
||||
private Button unblockButton;
|
||||
private Button makeDefaultSmsButton;
|
||||
private Button registerButton;
|
||||
private InputAwareLayout container;
|
||||
private View composePanel;
|
||||
protected Stub<ReminderView> reminderView;
|
||||
private Stub<UnverifiedBannerView> unverifiedBannerView;
|
||||
private Stub<GroupShareProfileView> groupShareProfileView;
|
||||
private TypingStatusTextWatcher typingTextWatcher;
|
||||
private MentionTextWatcher mentionTextWatcher;
|
||||
private ConversationSearchBottomBar searchNav;
|
||||
private MenuItem searchViewItem;
|
||||
|
||||
@ -338,6 +347,12 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
private final DynamicNoActionBarTheme dynamicTheme = new DynamicNoActionBarTheme();
|
||||
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
|
||||
|
||||
// Mentions
|
||||
private UserSelectionView userSelectionView;
|
||||
private int currentMentionStartIndex = -1;
|
||||
private ArrayList<Mention> mentions = new ArrayList<>();
|
||||
private String oldText = "";
|
||||
|
||||
|
||||
@Override
|
||||
protected void onPreCreate() {
|
||||
@ -389,11 +404,25 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
composeText.addTextChangedListener(typingTextWatcher);
|
||||
}
|
||||
composeText.setSelection(composeText.length(), composeText.length());
|
||||
composeText.addTextChangedListener(mentionTextWatcher);
|
||||
userSelectionView.setOnUserSelected(tuple -> {
|
||||
Mention mention = new Mention(currentMentionStartIndex, tuple.getFirst(), tuple.getSecond());
|
||||
mentions.add(mention);
|
||||
String oldText = composeText.getText().toString();
|
||||
String newText = oldText.substring(0, currentMentionStartIndex) + "@" + tuple.getSecond();
|
||||
composeText.setText(newText);
|
||||
composeText.setSelection(newText.length());
|
||||
userSelectionView.hide();
|
||||
currentMentionStartIndex = -1;
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
LokiAPIUtilities.INSTANCE.populateUserIDCacheIfNeeded(threadId, this);
|
||||
|
||||
if (this.recipient.isGroupRecipient()) {
|
||||
if (this.recipient.getName().equals("Loki Public Chat")) {
|
||||
Analytics.Companion.getShared().track("Loki Public Chat Opened");
|
||||
@ -1552,6 +1581,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
inlineAttachmentToggle = ViewUtil.findById(this, R.id.inline_attachment_container);
|
||||
inputPanel = ViewUtil.findById(this, R.id.bottom_panel);
|
||||
searchNav = ViewUtil.findById(this, R.id.conversation_search_nav);
|
||||
userSelectionView = ViewUtil.findById(this, R.id.userSelectionView);
|
||||
|
||||
ImageButton quickCameraToggle = ViewUtil.findById(this, R.id.quick_camera_toggle);
|
||||
ImageButton inlineAttachmentButton = ViewUtil.findById(this, R.id.inline_attachment_button);
|
||||
@ -1564,6 +1594,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
attachmentManager = new AttachmentManager(this, this);
|
||||
audioRecorder = new AudioRecorder(this);
|
||||
typingTextWatcher = new TypingStatusTextWatcher();
|
||||
mentionTextWatcher = new MentionTextWatcher();
|
||||
|
||||
SendButtonListener sendButtonListener = new SendButtonListener();
|
||||
ComposeKeyPressedListener composeKeyPressedListener = new ComposeKeyPressedListener();
|
||||
@ -2060,12 +2091,20 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
|
||||
private String getMessage() throws InvalidMessageException {
|
||||
String rawText = composeText.getTextTrimmed();
|
||||
|
||||
if (rawText.length() < 1 && !attachmentManager.isAttachmentPresent())
|
||||
throw new InvalidMessageException(getString(R.string.ConversationActivity_message_is_empty_exclamation));
|
||||
|
||||
return rawText;
|
||||
String result = composeText.getTextTrimmed();
|
||||
if (result.length() < 1 && !attachmentManager.isAttachmentPresent()) throw new InvalidMessageException();
|
||||
int shift = 0;
|
||||
for (Mention mention : mentions) {
|
||||
try {
|
||||
int startIndex = mention.getLocationInString() + shift;
|
||||
int endIndex = startIndex + mention.getDisplayName().length() + 1; // + 1 to include the @
|
||||
shift = shift + mention.getHexEncodedPublicKey().length() - mention.getDisplayName().length();
|
||||
result = result.substring(0, startIndex) + "@" + mention.getHexEncodedPublicKey() + result.substring(endIndex);
|
||||
} catch (Exception exception) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Pair<String, Optional<Slide>> getSplitMessage(String rawText, int maxPrimaryMessageSize) {
|
||||
@ -2592,6 +2631,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
private void silentlySetComposeText(String text) {
|
||||
typingTextWatcher.setEnabled(false);
|
||||
composeText.setText(text);
|
||||
if (text.isEmpty()) clearMentions();
|
||||
typingTextWatcher.setEnabled(true);
|
||||
}
|
||||
|
||||
@ -2706,7 +2746,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
|
||||
private class TypingStatusTextWatcher extends SimpleTextWatcher {
|
||||
|
||||
private boolean enabled = true;
|
||||
|
||||
@Override
|
||||
@ -2721,6 +2760,55 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
}
|
||||
|
||||
private class MentionTextWatcher extends SimpleTextWatcher {
|
||||
|
||||
@Override
|
||||
public void onTextChanged(String text) {
|
||||
boolean isBackspace = text.length() < oldText.length();
|
||||
if (isBackspace) {
|
||||
currentMentionStartIndex = -1;
|
||||
for (Mention mention : mentions) {
|
||||
boolean isValid;
|
||||
if (mention.getLocationInString() > (text.length() - 1)) {
|
||||
isValid = false;
|
||||
} else {
|
||||
isValid = text.substring(mention.getLocationInString()).startsWith("@" + mention.getDisplayName());
|
||||
}
|
||||
if (!isValid) {
|
||||
mentions.remove(mention);
|
||||
}
|
||||
}
|
||||
} else if (text.length() > 0) {
|
||||
if (currentMentionStartIndex > text.length()) {
|
||||
clearMentions(); // Should never occur
|
||||
}
|
||||
int currentEndIndex = text.length() - 1;
|
||||
char lastCharacter = text.charAt(currentEndIndex);
|
||||
LokiUserDatabase userDatabase = DatabaseFactory.getLokiUserDatabase(ConversationActivity.this);
|
||||
if (lastCharacter == '@') {
|
||||
List<Tuple2<String, String>> users = LokiAPI.Companion.getUsers("", threadId, userDatabase);
|
||||
currentMentionStartIndex = currentEndIndex;
|
||||
userSelectionView.show(users, threadId);
|
||||
} else if (Character.isWhitespace(lastCharacter)) {
|
||||
currentMentionStartIndex = -1;
|
||||
userSelectionView.hide();
|
||||
} else {
|
||||
if (currentMentionStartIndex != -1) {
|
||||
String query = text.substring(currentMentionStartIndex + 1); // + 1 to get rid of the @
|
||||
List<Tuple2<String, String>> users = LokiAPI.Companion.getUsers(query, threadId, userDatabase);
|
||||
userSelectionView.show(users, threadId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void clearMentions() {
|
||||
oldText = "";
|
||||
currentMentionStartIndex = -1;
|
||||
mentions.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setThreadId(long threadId) {
|
||||
this.threadId = threadId;
|
||||
@ -2747,11 +2835,11 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
|
||||
inputPanel.setQuote(GlideApp.with(this),
|
||||
messageRecord.getDateSent(),
|
||||
author,
|
||||
body,
|
||||
slideDeck,
|
||||
recipient);
|
||||
messageRecord.getDateSent(),
|
||||
author,
|
||||
body,
|
||||
slideDeck,
|
||||
recipient);
|
||||
|
||||
} else if (messageRecord.isMms() && !((MmsMessageRecord) messageRecord).getLinkPreviews().isEmpty()) {
|
||||
LinkPreview linkPreview = ((MmsMessageRecord) messageRecord).getLinkPreviews().get(0);
|
||||
@ -2762,18 +2850,18 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
}
|
||||
|
||||
inputPanel.setQuote(GlideApp.with(this),
|
||||
messageRecord.getDateSent(),
|
||||
author,
|
||||
messageRecord.getBody(),
|
||||
slideDeck,
|
||||
recipient);
|
||||
messageRecord.getDateSent(),
|
||||
author,
|
||||
messageRecord.getBody(),
|
||||
slideDeck,
|
||||
recipient);
|
||||
} else {
|
||||
inputPanel.setQuote(GlideApp.with(this),
|
||||
messageRecord.getDateSent(),
|
||||
author,
|
||||
messageRecord.getBody(),
|
||||
messageRecord.isMms() ? ((MmsMessageRecord) messageRecord).getSlideDeck() : new SlideDeck(),
|
||||
recipient);
|
||||
messageRecord.getDateSent(),
|
||||
author,
|
||||
messageRecord.getBody(),
|
||||
messageRecord.isMms() ? ((MmsMessageRecord) messageRecord).getSlideDeck() : new SlideDeck(),
|
||||
recipient);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,6 +91,7 @@ import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.loki.FriendRequestView;
|
||||
import org.thoughtcrime.securesms.loki.FriendRequestViewDelegate;
|
||||
import org.thoughtcrime.securesms.loki.LokiMessageDatabase;
|
||||
import org.thoughtcrime.securesms.loki.MentionUtilities;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.mms.ImageSlide;
|
||||
import org.thoughtcrime.securesms.mms.PartAuthority;
|
||||
@ -212,7 +213,7 @@ public class ConversationItem extends LinearLayout
|
||||
this.groupSenderProfileName = findViewById(R.id.group_message_sender_profile);
|
||||
this.alertView = findViewById(R.id.indicators_parent);
|
||||
this.contactPhoto = findViewById(R.id.contact_photo);
|
||||
this.moderatorIconImageView = findViewById(R.id.moderator_icon_image_view);
|
||||
this.moderatorIconImageView = findViewById(R.id.moderator_icon_image_view);
|
||||
this.contactPhotoHolder = findViewById(R.id.contact_photo_container);
|
||||
this.bodyBubble = findViewById(R.id.body_bubble);
|
||||
this.mediaThumbnailStub = new Stub<>(findViewById(R.id.image_view_stub));
|
||||
@ -260,7 +261,7 @@ public class ConversationItem extends LinearLayout
|
||||
setMessageShape(messageRecord, previousMessageRecord, nextMessageRecord, groupThread);
|
||||
setMediaAttributes(messageRecord, previousMessageRecord, nextMessageRecord, conversationRecipient, groupThread);
|
||||
setInteractionState(messageRecord, pulseHighlight);
|
||||
setBodyText(messageRecord, searchQuery);
|
||||
setBodyText(messageRecord, searchQuery, groupThread);
|
||||
setBubbleState(messageRecord);
|
||||
setStatusIcons(messageRecord);
|
||||
setContactPhoto(recipient);
|
||||
@ -466,17 +467,17 @@ public class ConversationItem extends LinearLayout
|
||||
!StickerUrl.isValidShareLink(linkPreview.getUrl());
|
||||
}
|
||||
|
||||
private void setBodyText(MessageRecord messageRecord, @Nullable String searchQuery) {
|
||||
private void setBodyText(MessageRecord messageRecord, @Nullable String searchQuery, boolean isGroupThread) {
|
||||
bodyText.setClickable(false);
|
||||
bodyText.setFocusable(false);
|
||||
bodyText.setTextSize(TypedValue.COMPLEX_UNIT_SP, TextSecurePreferences.getMessageBodyTextSize(context));
|
||||
|
||||
if (isCaptionlessMms(messageRecord)) {
|
||||
bodyText.setVisibility(View.GONE);
|
||||
} else {
|
||||
Spannable styledText = linkifyMessageBody(messageRecord.getDisplayBody(getContext()), batchSelected.isEmpty());
|
||||
styledText = SearchUtil.getHighlightedSpan(locale, () -> new BackgroundColorSpan(Color.YELLOW), styledText, searchQuery);
|
||||
styledText = SearchUtil.getHighlightedSpan(locale, () -> new ForegroundColorSpan(Color.BLACK), styledText, searchQuery);
|
||||
} else { ;
|
||||
Spannable text = MentionUtilities.highlightMentions(linkifyMessageBody(messageRecord.getDisplayBody(context), batchSelected.isEmpty()), messageRecord.isOutgoing(), isGroupThread, context);
|
||||
text = SearchUtil.getHighlightedSpan(locale, () -> new BackgroundColorSpan(Color.YELLOW), text, searchQuery);
|
||||
text = SearchUtil.getHighlightedSpan(locale, () -> new ForegroundColorSpan(Color.BLACK), text, searchQuery);
|
||||
|
||||
if (hasExtraText(messageRecord)) {
|
||||
bodyText.setOverflowText(getLongMessageSpan(messageRecord));
|
||||
@ -484,7 +485,7 @@ public class ConversationItem extends LinearLayout
|
||||
bodyText.setOverflowText(null);
|
||||
}
|
||||
|
||||
bodyText.setText(styledText);
|
||||
bodyText.setText(text);
|
||||
bodyText.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
@ -790,7 +791,8 @@ public class ConversationItem extends LinearLayout
|
||||
if (current.isMms() && !current.isMmsNotification() && ((MediaMmsMessageRecord)current).getQuote() != null) {
|
||||
Quote quote = ((MediaMmsMessageRecord)current).getQuote();
|
||||
//noinspection ConstantConditions
|
||||
quoteView.setQuote(glideRequests, quote.getId(), Recipient.from(context, quote.getAuthor(), true), quote.getText(), quote.isOriginalMissing(), quote.getAttachment(), conversationRecipient);
|
||||
String quoteBody = MentionUtilities.highlightMentions(quote.getText(), isGroupThread, context);
|
||||
quoteView.setQuote(glideRequests, quote.getId(), Recipient.from(context, quote.getAuthor(), true), quoteBody, quote.isOriginalMissing(), quote.getAttachment(), conversationRecipient);
|
||||
quoteView.setVisibility(View.VISIBLE);
|
||||
quoteView.getLayoutParams().width = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
|
||||
|
@ -67,6 +67,7 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository;
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.loki.LokiAPIUtilities;
|
||||
import org.thoughtcrime.securesms.loki.LokiMessageDatabase;
|
||||
import org.thoughtcrime.securesms.loki.LokiPreKeyBundleDatabase;
|
||||
import org.thoughtcrime.securesms.loki.LokiPreKeyRecordDatabase;
|
||||
@ -123,6 +124,7 @@ import org.whispersystems.signalservice.api.messages.multidevice.VerifiedMessage
|
||||
import org.whispersystems.signalservice.api.messages.shared.SharedContact;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.loki.api.DeviceLinkingSession;
|
||||
import org.whispersystems.signalservice.loki.api.LokiAPI;
|
||||
import org.whispersystems.signalservice.loki.api.LokiStorageAPI;
|
||||
import org.whispersystems.signalservice.loki.api.PairingAuthorisation;
|
||||
import org.whispersystems.signalservice.loki.crypto.LokiServiceCipher;
|
||||
@ -1021,6 +1023,12 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
|
||||
if (smsMessageId.isPresent()) database.deleteMessage(smsMessageId.get());
|
||||
|
||||
// Loki - Cache the user hex encoded public key (for mentions)
|
||||
if (threadId != null) {
|
||||
LokiAPIUtilities.INSTANCE.populateUserIDCacheIfNeeded(threadId, context);
|
||||
LokiAPI.Companion.cache(textMessage.getSender().serialize(), threadId);
|
||||
}
|
||||
|
||||
// Loki - Store message server ID
|
||||
updateGroupChatMessageServerID(messageServerIDOrNull, insertResult);
|
||||
|
||||
|
@ -3,7 +3,7 @@ package org.thoughtcrime.securesms.loki
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import kotlinx.android.synthetic.main.activity_account_details.*
|
||||
import kotlinx.android.synthetic.main.activity_display_name.*
|
||||
import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.ApplicationContext
|
||||
import org.thoughtcrime.securesms.BaseActionBarActivity
|
||||
@ -19,21 +19,21 @@ class DisplayNameActivity : BaseActionBarActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_account_details)
|
||||
setContentView(R.layout.activity_display_name)
|
||||
nextButton.setOnClickListener { continueIfPossible() }
|
||||
Analytics.shared.track("Display Name Screen Viewed")
|
||||
}
|
||||
|
||||
private fun continueIfPossible() {
|
||||
val uncheckedName = nameEditText.text.toString()
|
||||
val name = if (uncheckedName.isNotEmpty()) { uncheckedName.trim() } else { null }
|
||||
if (name != null) {
|
||||
if (name.toByteArray().size > ProfileCipher.NAME_PADDED_LENGTH) {
|
||||
return nameEditText.input.setError("Too Long")
|
||||
} else {
|
||||
Analytics.shared.track("Display Name Updated")
|
||||
TextSecurePreferences.setProfileName(this, name)
|
||||
}
|
||||
val name = nameEditText.text.toString()
|
||||
if (name.isEmpty()) {
|
||||
return nameEditText.input.setError("Invalid")
|
||||
}
|
||||
if (name.toByteArray().size > ProfileCipher.NAME_PADDED_LENGTH) {
|
||||
return nameEditText.input.setError("Too Long")
|
||||
} else {
|
||||
Analytics.shared.track("Display Name Updated")
|
||||
TextSecurePreferences.setProfileName(this, name)
|
||||
}
|
||||
val inputMethodManager = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
inputMethodManager.hideSoftInputFromWindow(nameEditText.windowToken, 0)
|
||||
|
29
src/org/thoughtcrime/securesms/loki/LokiAPIUtilities.kt
Normal file
29
src/org/thoughtcrime/securesms/loki/LokiAPIUtilities.kt
Normal file
@ -0,0 +1,29 @@
|
||||
package org.thoughtcrime.securesms.loki
|
||||
|
||||
import android.content.Context
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.whispersystems.signalservice.loki.api.LokiAPI
|
||||
|
||||
object LokiAPIUtilities {
|
||||
|
||||
fun populateUserIDCacheIfNeeded(threadID: Long, context: Context) {
|
||||
if (LokiAPI.userIDCache[threadID] != null) { return }
|
||||
val result = mutableSetOf<String>()
|
||||
val messageDatabase = DatabaseFactory.getMmsSmsDatabase(context)
|
||||
val reader = messageDatabase.readerFor(messageDatabase.getConversation(threadID))
|
||||
var record: MessageRecord? = reader.next
|
||||
while (record != null) {
|
||||
result.add(record.individualRecipient.address.serialize())
|
||||
try {
|
||||
record = reader.next
|
||||
} catch (exception: Exception) {
|
||||
record = null
|
||||
}
|
||||
}
|
||||
reader.close()
|
||||
result.add(TextSecurePreferences.getLocalNumber(context))
|
||||
LokiAPI.userIDCache[threadID] = result
|
||||
}
|
||||
}
|
@ -46,7 +46,7 @@ class LokiUserDatabase(context: Context, helper: SQLCipherOpenHelper) : Database
|
||||
Recipient.from(context, Address.fromSerialized(hexEncodedPublicKey), false).notifyListeners()
|
||||
}
|
||||
|
||||
fun getServerDisplayName(serverID: String, hexEncodedPublicKey: String): String? {
|
||||
override fun getServerDisplayName(serverID: String, hexEncodedPublicKey: String): String? {
|
||||
val database = databaseHelper.readableDatabase
|
||||
return database.get(serverDisplayNameTable, "${Companion.hexEncodedPublicKey} = ? AND ${Companion.serverID} = ?", arrayOf( hexEncodedPublicKey, serverID )) { cursor ->
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(displayName))
|
||||
|
3
src/org/thoughtcrime/securesms/loki/Mention.kt
Normal file
3
src/org/thoughtcrime/securesms/loki/Mention.kt
Normal file
@ -0,0 +1,3 @@
|
||||
package org.thoughtcrime.securesms.loki
|
||||
|
||||
data class Mention(val locationInString: Int, val hexEncodedPublicKey: String, val displayName: String)
|
56
src/org/thoughtcrime/securesms/loki/MentionUtilities.kt
Normal file
56
src/org/thoughtcrime/securesms/loki/MentionUtilities.kt
Normal file
@ -0,0 +1,56 @@
|
||||
package org.thoughtcrime.securesms.loki
|
||||
|
||||
import android.content.Context
|
||||
import android.text.Spannable
|
||||
import android.text.SpannableString
|
||||
import android.text.style.BackgroundColorSpan
|
||||
import android.util.Range
|
||||
import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.whispersystems.signalservice.loki.api.LokiGroupChatAPI
|
||||
import java.util.regex.Pattern
|
||||
|
||||
object MentionUtilities {
|
||||
|
||||
@JvmStatic
|
||||
fun highlightMentions(text: CharSequence, isGroupThread: Boolean, context: Context): String {
|
||||
return MentionUtilities.highlightMentions(text, false, isGroupThread, context).toString() // isOutgoingMessage is irrelevant
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun highlightMentions(text: CharSequence, isOutgoingMessage: Boolean, isGroupThread: Boolean, context: Context): SpannableString {
|
||||
var text = text
|
||||
val pattern = Pattern.compile("@[0-9a-fA-F]*")
|
||||
var matcher = pattern.matcher(text)
|
||||
val mentions = mutableListOf<Range<Int>>()
|
||||
var startIndex = 0
|
||||
if (matcher.find(startIndex) && isGroupThread) {
|
||||
while (true) {
|
||||
val userID = text.subSequence(matcher.start() + 1, matcher.end()).toString() // +1 to get rid of the @
|
||||
val userDisplayName: String? = if (userID.toLowerCase() == TextSecurePreferences.getLocalNumber(context).toLowerCase()) {
|
||||
TextSecurePreferences.getProfileName(context)
|
||||
} else {
|
||||
val publicChatID = LokiGroupChatAPI.publicChatServer + "." + LokiGroupChatAPI.publicChatServerID
|
||||
DatabaseFactory.getLokiUserDatabase(context).getServerDisplayName(publicChatID, userID)
|
||||
}
|
||||
if (userDisplayName != null) {
|
||||
text = text.subSequence(0, matcher.start()).toString() + "@" + userDisplayName + text.subSequence(matcher.end(), text.length)
|
||||
val endIndex = matcher.start() + 1 + userDisplayName.length
|
||||
startIndex = endIndex
|
||||
mentions.add(Range.create(matcher.start(), endIndex))
|
||||
} else {
|
||||
startIndex = matcher.end()
|
||||
}
|
||||
matcher = pattern.matcher(text)
|
||||
if (!matcher.find(startIndex)) { break }
|
||||
}
|
||||
}
|
||||
val result = SpannableString(text)
|
||||
for (range in mentions) {
|
||||
val highlightColor = if (isOutgoingMessage) context.resources.getColor(R.color.loki_dark_green) else context.resources.getColor(R.color.loki_green)
|
||||
result.setSpan(BackgroundColorSpan(highlightColor), range.lower, range.upper, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@ import android.view.ViewGroup
|
||||
import kotlinx.android.synthetic.main.fragment_new_conversation.*
|
||||
import network.loki.messenger.R
|
||||
|
||||
class NewConversationFragment() : Fragment() {
|
||||
class NewConversationFragment : Fragment() {
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_new_conversation, container, false)
|
||||
|
@ -9,9 +9,6 @@ import android.view.View
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.Toast
|
||||
import kotlinx.android.synthetic.main.activity_seed.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.ApplicationContext
|
||||
import org.thoughtcrime.securesms.BaseActionBarActivity
|
||||
@ -180,13 +177,12 @@ class SeedActivity : BaseActionBarActivity(), DeviceLinkingDialogDelegate {
|
||||
IdentityKeyUtil.generateIdentityKeyPair(this, seed)
|
||||
}
|
||||
val keyPair = IdentityKeyUtil.getIdentityKeyPair(this)
|
||||
val publicKey = keyPair.publicKey
|
||||
val hexEncodedPublicKey = keyPair.hexEncodedPublicKey
|
||||
val userHexEncodedPublicKey = keyPair.hexEncodedPublicKey
|
||||
val registrationID = KeyHelper.generateRegistrationId(false)
|
||||
TextSecurePreferences.setLocalRegistrationId(this, registrationID)
|
||||
DatabaseFactory.getIdentityDatabase(this).saveIdentity(Address.fromSerialized(hexEncodedPublicKey), publicKey,
|
||||
DatabaseFactory.getIdentityDatabase(this).saveIdentity(Address.fromSerialized(userHexEncodedPublicKey), keyPair.publicKey,
|
||||
IdentityDatabase.VerifiedStatus.VERIFIED, true, System.currentTimeMillis(), true)
|
||||
TextSecurePreferences.setLocalNumber(this, hexEncodedPublicKey)
|
||||
TextSecurePreferences.setLocalNumber(this, userHexEncodedPublicKey)
|
||||
when (mode) {
|
||||
Mode.Register -> Analytics.shared.track("Seed Created")
|
||||
Mode.Restore -> Analytics.shared.track("Seed Restored")
|
||||
@ -195,22 +191,20 @@ class SeedActivity : BaseActionBarActivity(), DeviceLinkingDialogDelegate {
|
||||
if (mode == Mode.Link) {
|
||||
TextSecurePreferences.setHasSeenWelcomeScreen(this, true)
|
||||
TextSecurePreferences.setPromptedPushRegistration(this, true)
|
||||
val primaryDevicePublicKey = publicKeyEditText.text.trim().toString()
|
||||
val authorisation = PairingAuthorisation(primaryDevicePublicKey, hexEncodedPublicKey).sign(PairingAuthorisation.Type.REQUEST, keyPair.privateKey.serialize())
|
||||
val masterHexEncodedPublicKey = publicKeyEditText.text.trim().toString()
|
||||
val authorisation = PairingAuthorisation(masterHexEncodedPublicKey, userHexEncodedPublicKey).sign(PairingAuthorisation.Type.REQUEST, keyPair.privateKey.serialize())
|
||||
if (authorisation == null) {
|
||||
Log.d("Loki", "Failed to sign outgoing pairing request.")
|
||||
Log.d("Loki", "Failed to sign pairing request.")
|
||||
resetForRegistration()
|
||||
return Toast.makeText(application, "Failed to link device.", Toast.LENGTH_SHORT).show()
|
||||
return Toast.makeText(application, "Couldn't start device linking process.", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
val application = ApplicationContext.getInstance(this)
|
||||
application.startLongPollingIfNeeded()
|
||||
application.setUpP2PAPI()
|
||||
application.setUpStorageAPIIfNeeded()
|
||||
DeviceLinkingDialog.show(this, DeviceLinkingView.Mode.Slave, this)
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
retryIfNeeded(8) {
|
||||
sendPairingAuthorisationMessage(this@SeedActivity, authorisation.primaryDevicePublicKey, authorisation).get()
|
||||
}
|
||||
retryIfNeeded(8) {
|
||||
sendPairingAuthorisationMessage(this@SeedActivity, authorisation.primaryDevicePublicKey, authorisation).get()
|
||||
}
|
||||
} else {
|
||||
startActivity(Intent(this, DisplayNameActivity::class.java))
|
||||
|
71
src/org/thoughtcrime/securesms/loki/UserSelectionView.kt
Normal file
71
src/org/thoughtcrime/securesms/loki/UserSelectionView.kt
Normal file
@ -0,0 +1,71 @@
|
||||
package org.thoughtcrime.securesms.loki
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.BaseAdapter
|
||||
import android.widget.ListView
|
||||
import nl.komponents.kovenant.combine.Tuple2
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory
|
||||
|
||||
class UserSelectionView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : ListView(context, attrs, defStyleAttr) {
|
||||
private var users = listOf<Tuple2<String, String>>()
|
||||
set(newValue) { field = newValue; userSelectionViewAdapter.users = newValue }
|
||||
private var hasGroupContext = false
|
||||
var onUserSelected: ((Tuple2<String, String>) -> Unit)? = null
|
||||
|
||||
private val userSelectionViewAdapter by lazy { Adapter(context) }
|
||||
|
||||
private class Adapter(private val context: Context) : BaseAdapter() {
|
||||
var users = listOf<Tuple2<String, String>>()
|
||||
set(newValue) { field = newValue; notifyDataSetChanged() }
|
||||
var hasGroupContext = false
|
||||
|
||||
override fun getCount(): Int {
|
||||
return users.count()
|
||||
}
|
||||
|
||||
override fun getItemId(position: Int): Long {
|
||||
return position.toLong()
|
||||
}
|
||||
|
||||
override fun getItem(position: Int): Tuple2<String, String> {
|
||||
return users[position]
|
||||
}
|
||||
|
||||
override fun getView(position: Int, cellToBeReused: View?, parent: ViewGroup): View {
|
||||
val cell = cellToBeReused as UserSelectionViewCell? ?: UserSelectionViewCell.inflate(LayoutInflater.from(context), parent)
|
||||
val user = getItem(position)
|
||||
cell.user = user
|
||||
cell.hasGroupContext = hasGroupContext
|
||||
return cell
|
||||
}
|
||||
}
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
|
||||
constructor(context: Context) : this(context, null)
|
||||
|
||||
init {
|
||||
adapter = userSelectionViewAdapter
|
||||
userSelectionViewAdapter.users = users
|
||||
setOnItemClickListener { _, _, position, _ ->
|
||||
onUserSelected?.invoke(users[position])
|
||||
}
|
||||
}
|
||||
|
||||
fun show(users: List<Tuple2<String, String>>, threadID: Long) {
|
||||
hasGroupContext = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadID)!!.isGroupRecipient
|
||||
this.users = users
|
||||
val layoutParams = this.layoutParams as ViewGroup.LayoutParams
|
||||
layoutParams.height = toPx(6 + Math.min(users.count(), 4) * 52, resources)
|
||||
this.layoutParams = layoutParams
|
||||
}
|
||||
|
||||
fun hide() {
|
||||
val layoutParams = this.layoutParams as ViewGroup.LayoutParams
|
||||
layoutParams.height = 0
|
||||
this.layoutParams = layoutParams
|
||||
}
|
||||
}
|
48
src/org/thoughtcrime/securesms/loki/UserSelectionViewCell.kt
Normal file
48
src/org/thoughtcrime/securesms/loki/UserSelectionViewCell.kt
Normal file
@ -0,0 +1,48 @@
|
||||
package org.thoughtcrime.securesms.loki
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Outline
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewOutlineProvider
|
||||
import android.widget.LinearLayout
|
||||
import kotlinx.android.synthetic.main.cell_user_selection_view.view.*
|
||||
import network.loki.messenger.R
|
||||
import nl.komponents.kovenant.combine.Tuple2
|
||||
import org.whispersystems.signalservice.loki.api.LokiGroupChatAPI
|
||||
|
||||
class UserSelectionViewCell(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : LinearLayout(context, attrs, defStyleAttr) {
|
||||
var user = Tuple2("", "")
|
||||
set(newValue) { field = newValue; update() }
|
||||
var hasGroupContext = false
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
|
||||
constructor(context: Context) : this(context, null)
|
||||
|
||||
companion object {
|
||||
|
||||
fun inflate(layoutInflater: LayoutInflater, parent: ViewGroup): UserSelectionViewCell {
|
||||
return layoutInflater.inflate(R.layout.cell_user_selection_view, parent, false) as UserSelectionViewCell
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFinishInflate() {
|
||||
super.onFinishInflate()
|
||||
profilePictureImageViewContainer.outlineProvider = object : ViewOutlineProvider() {
|
||||
|
||||
override fun getOutline(view: View, outline: Outline) {
|
||||
outline.setOval(0, 0, view.width, view.height)
|
||||
}
|
||||
}
|
||||
profilePictureImageViewContainer.clipToOutline = true
|
||||
}
|
||||
|
||||
private fun update() {
|
||||
displayNameTextView.text = user.second
|
||||
profilePictureImageView.update(user.first)
|
||||
val isUserModerator = LokiGroupChatAPI.isUserModerator(user.first, LokiGroupChatAPI.publicChatServerID, LokiGroupChatAPI.publicChatServer)
|
||||
moderatorIconImageView.visibility = if (isUserModerator && hasGroupContext) View.VISIBLE else View.GONE
|
||||
}
|
||||
}
|
@ -100,7 +100,7 @@ public class ProfilePreference extends Preference {
|
||||
int height = avatarView.getHeight();
|
||||
if (width == 0 || height == 0) return true;
|
||||
avatarView.getViewTreeObserver().removeOnPreDrawListener(this);
|
||||
JazzIdenticonDrawable identicon = new JazzIdenticonDrawable(width, height, userHexEncodedPublicKey);
|
||||
JazzIdenticonDrawable identicon = new JazzIdenticonDrawable(width, height, userHexEncodedPublicKey.toLowerCase());
|
||||
avatarView.setImageDrawable(identicon);
|
||||
return true;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user