mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-20 12:09:45 +01:00
commit
f35c4b486c
@ -17,8 +17,8 @@ android {
|
|||||||
targetSdkVersion 28
|
targetSdkVersion 28
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
||||||
versionCode 90
|
versionCode 91
|
||||||
versionName "6.0.0beta2"
|
versionName "6.0.0beta3"
|
||||||
|
|
||||||
flavorDimensions "default"
|
flavorDimensions "default"
|
||||||
renderscriptTargetApi 19
|
renderscriptTargetApi 19
|
||||||
@ -100,7 +100,6 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
supportLibraryVersion = '28.0.0'
|
|
||||||
workVersion = "1.0.0"
|
workVersion = "1.0.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,17 +114,17 @@ dependencies {
|
|||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
implementation 'androidx.appcompat:appcompat:1.0.2'
|
implementation 'androidx.appcompat:appcompat:1.0.2'
|
||||||
implementation 'com.google.android.material:material:1.0.0'
|
implementation 'com.google.android.material:material:1.0.0'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha3'
|
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha4'
|
||||||
implementation 'com.github.vanniktech:Emoji:746caa4623'
|
implementation 'com.github.vanniktech:Emoji:746caa4623'
|
||||||
implementation 'org.michaelevans.colorart:library:0.0.3'
|
implementation 'org.michaelevans.colorart:library:0.0.3'
|
||||||
implementation "android.arch.work:work-runtime:${workVersion}"
|
implementation "android.arch.work:work-runtime:${workVersion}"
|
||||||
implementation "android.arch.work:work-rxjava2:${workVersion}"
|
implementation "android.arch.work:work-rxjava2:${workVersion}"
|
||||||
androidTestImplementation "android.arch.work:work-testing:${workVersion}"
|
androidTestImplementation "android.arch.work:work-testing:${workVersion}"
|
||||||
|
|
||||||
implementation 'androidx.biometric:biometric:1.0.0-alpha03'
|
implementation 'androidx.biometric:biometric:1.0.0-alpha04'
|
||||||
implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"
|
implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"
|
||||||
|
|
||||||
implementation 'androidx.multidex:multidex:2.0.0'
|
implementation 'androidx.multidex:multidex:2.0.1'
|
||||||
|
|
||||||
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
|
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
|
||||||
implementation "io.reactivex.rxjava2:rxjava:2.2.7"
|
implementation "io.reactivex.rxjava2:rxjava:2.2.7"
|
||||||
|
@ -45,18 +45,28 @@ import java.util.List;
|
|||||||
public class MentionAutocompleteItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder>
|
public class MentionAutocompleteItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder>
|
||||||
implements IFilterable<String> {
|
implements IFilterable<String> {
|
||||||
|
|
||||||
private String userId;
|
private String objectId;
|
||||||
private String displayName;
|
private String displayName;
|
||||||
|
private String source;
|
||||||
private UserEntity currentUser;
|
private UserEntity currentUser;
|
||||||
|
|
||||||
public MentionAutocompleteItem(String userId, String displayName, UserEntity currentUser) {
|
public MentionAutocompleteItem(String objectId, String displayName, String source, UserEntity currentUser) {
|
||||||
this.userId = userId;
|
this.objectId = objectId;
|
||||||
this.displayName = displayName;
|
this.displayName = displayName;
|
||||||
|
this.source = source;
|
||||||
this.currentUser = currentUser;
|
this.currentUser = currentUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUserId() {
|
public String getSource() {
|
||||||
return userId;
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSource(String source) {
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getObjectId() {
|
||||||
|
return objectId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDisplayName() {
|
public String getDisplayName() {
|
||||||
@ -67,7 +77,7 @@ public class MentionAutocompleteItem extends AbstractFlexibleItem<UserItem.UserI
|
|||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (o instanceof MentionAutocompleteItem) {
|
if (o instanceof MentionAutocompleteItem) {
|
||||||
MentionAutocompleteItem inItem = (MentionAutocompleteItem) o;
|
MentionAutocompleteItem inItem = (MentionAutocompleteItem) o;
|
||||||
return (userId.equals(inItem.userId) && displayName.equals(inItem.displayName));
|
return (objectId.equals(inItem.objectId) && displayName.equals(inItem.displayName));
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -93,22 +103,22 @@ public class MentionAutocompleteItem extends AbstractFlexibleItem<UserItem.UserI
|
|||||||
String.valueOf(adapter.getFilter(String.class)), NextcloudTalkApplication.getSharedApplication()
|
String.valueOf(adapter.getFilter(String.class)), NextcloudTalkApplication.getSharedApplication()
|
||||||
.getResources().getColor(R.color.colorPrimary));
|
.getResources().getColor(R.color.colorPrimary));
|
||||||
if (holder.contactMentionId != null) {
|
if (holder.contactMentionId != null) {
|
||||||
FlexibleUtils.highlightText(holder.contactMentionId, "@" + userId,
|
FlexibleUtils.highlightText(holder.contactMentionId, "@" + objectId,
|
||||||
String.valueOf(adapter.getFilter(String.class)), NextcloudTalkApplication.getSharedApplication()
|
String.valueOf(adapter.getFilter(String.class)), NextcloudTalkApplication.getSharedApplication()
|
||||||
.getResources().getColor(R.color.colorPrimary));
|
.getResources().getColor(R.color.colorPrimary));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
holder.contactDisplayName.setText(displayName);
|
holder.contactDisplayName.setText(displayName);
|
||||||
if (holder.contactMentionId != null) {
|
if (holder.contactMentionId != null) {
|
||||||
holder.contactMentionId.setText("@" + userId);
|
holder.contactMentionId.setText("@" + objectId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userId.equals("all")) {
|
if (source.equals("calls")) {
|
||||||
holder.avatarFlipView.setFrontImageBitmap(DisplayUtils.getRoundedBitmapFromVectorDrawableResource(NextcloudTalkApplication.getSharedApplication().getResources(), R.drawable.ic_people_group_white_24px));
|
holder.avatarFlipView.setFrontImageBitmap(DisplayUtils.getRoundedBitmapFromVectorDrawableResource(NextcloudTalkApplication.getSharedApplication().getResources(), R.drawable.ic_people_group_white_24px));
|
||||||
} else {
|
} else {
|
||||||
GlideUrl glideUrl = new GlideUrl(ApiUtils.getUrlForAvatarWithName(currentUser.getBaseUrl(),
|
GlideUrl glideUrl = new GlideUrl(ApiUtils.getUrlForAvatarWithName(currentUser.getBaseUrl(),
|
||||||
userId, R.dimen.avatar_size), new LazyHeaders.Builder()
|
objectId, R.dimen.avatar_size), new LazyHeaders.Builder()
|
||||||
.setHeader("Accept", "image/*")
|
.setHeader("Accept", "image/*")
|
||||||
.setHeader("User-Agent", ApiUtils.getUserAgent())
|
.setHeader("User-Agent", ApiUtils.getUserAgent())
|
||||||
.build());
|
.build());
|
||||||
@ -129,7 +139,7 @@ public class MentionAutocompleteItem extends AbstractFlexibleItem<UserItem.UserI
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean filter(String constraint) {
|
public boolean filter(String constraint) {
|
||||||
return userId != null && StringUtils.containsIgnoreCase(userId, constraint) ||
|
return objectId != null && StringUtils.containsIgnoreCase(objectId, constraint) ||
|
||||||
displayName != null && StringUtils.containsIgnoreCase(displayName, constraint);
|
displayName != null && StringUtils.containsIgnoreCase(displayName, constraint);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -28,14 +28,12 @@ import android.text.Spannable;
|
|||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
import android.text.style.ForegroundColorSpan;
|
import android.text.style.ForegroundColorSpan;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.TextView;
|
|
||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
import com.nextcloud.talk.R;
|
import com.nextcloud.talk.R;
|
||||||
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||||
import com.nextcloud.talk.utils.DisplayUtils;
|
import com.nextcloud.talk.utils.DisplayUtils;
|
||||||
import com.vanniktech.emoji.EmojiTextView;
|
import com.vanniktech.emoji.EmojiTextView;
|
||||||
|
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter;
|
import eu.davidea.flexibleadapter.FlexibleAdapter;
|
||||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
|
||||||
import eu.davidea.viewholders.FlexibleViewHolder;
|
import eu.davidea.viewholders.FlexibleViewHolder;
|
||||||
|
@ -145,18 +145,26 @@ public class MagicIncomingTextMessageViewHolder
|
|||||||
Map<String, String> individualHashMap = message.getMessageParameters().get(key);
|
Map<String, String> individualHashMap = message.getMessageParameters().get(key);
|
||||||
if (individualHashMap != null) {
|
if (individualHashMap != null) {
|
||||||
if (individualHashMap.get("type").equals("user") || individualHashMap.get("type").equals("guest") || individualHashMap.get("type").equals("call")) {
|
if (individualHashMap.get("type").equals("user") || individualHashMap.get("type").equals("guest") || individualHashMap.get("type").equals("call")) {
|
||||||
int color;
|
|
||||||
|
|
||||||
if (individualHashMap.get("id").equals(message.getActiveUserId())) {
|
if (individualHashMap.get("id").equals(message.getActiveUserId())) {
|
||||||
color = NextcloudTalkApplication.getSharedApplication().getResources().getColor(R.color
|
messageString =
|
||||||
.nc_incoming_text_mention_you);
|
DisplayUtils.searchAndReplaceWithMentionSpan(messageText.getContext(),
|
||||||
|
messageString,
|
||||||
|
individualHashMap.get("id"),
|
||||||
|
individualHashMap.get("name"),
|
||||||
|
individualHashMap.get("type"),
|
||||||
|
userUtils.getUserById(message.getActiveUserId()),
|
||||||
|
R.xml.chip_simple_background);
|
||||||
} else {
|
} else {
|
||||||
color = NextcloudTalkApplication.getSharedApplication().getResources().getColor(R.color
|
messageString =
|
||||||
.nc_incoming_text_mention_others);
|
DisplayUtils.searchAndReplaceWithMentionSpan(messageText.getContext(),
|
||||||
|
messageString,
|
||||||
|
individualHashMap.get("id"),
|
||||||
|
individualHashMap.get("name"),
|
||||||
|
individualHashMap.get("type"),
|
||||||
|
userUtils.getUserById(message.getActiveUserId()),
|
||||||
|
R.xml.chip_accent_background);
|
||||||
}
|
}
|
||||||
|
|
||||||
messageString = DisplayUtils.searchAndColor(messageString,
|
|
||||||
"@" + individualHashMap.get("name"), color);
|
|
||||||
} else if (individualHashMap.get("type").equals("file")) {
|
} else if (individualHashMap.get("type").equals("file")) {
|
||||||
itemView.setOnClickListener(v -> {
|
itemView.setOnClickListener(v -> {
|
||||||
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(individualHashMap.get("link")));
|
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(individualHashMap.get("link")));
|
||||||
|
@ -58,6 +58,9 @@ public class MagicOutcomingTextMessageViewHolder extends MessageHolders.Outcomin
|
|||||||
@Inject
|
@Inject
|
||||||
UserUtils userUtils;
|
UserUtils userUtils;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
Context context;
|
||||||
|
|
||||||
private View itemView;
|
private View itemView;
|
||||||
|
|
||||||
public MagicOutcomingTextMessageViewHolder(View itemView) {
|
public MagicOutcomingTextMessageViewHolder(View itemView) {
|
||||||
@ -76,7 +79,6 @@ public class MagicOutcomingTextMessageViewHolder extends MessageHolders.Outcomin
|
|||||||
|
|
||||||
Spannable messageString = new SpannableString(message.getText());
|
Spannable messageString = new SpannableString(message.getText());
|
||||||
|
|
||||||
Context context = NextcloudTalkApplication.getSharedApplication().getApplicationContext();
|
|
||||||
itemView.setSelected(false);
|
itemView.setSelected(false);
|
||||||
messageTimeView.setTextColor(context.getResources().getColor(R.color.white60));
|
messageTimeView.setTextColor(context.getResources().getColor(R.color.white60));
|
||||||
|
|
||||||
@ -92,11 +94,23 @@ public class MagicOutcomingTextMessageViewHolder extends MessageHolders.Outcomin
|
|||||||
if (individualHashMap.get("type").equals("user") || individualHashMap.get("type").equals("guest") || individualHashMap.get("type").equals("call")) {
|
if (individualHashMap.get("type").equals("user") || individualHashMap.get("type").equals("guest") || individualHashMap.get("type").equals("call")) {
|
||||||
if (!individualHashMap.get("id").equals(message.getActiveUserId())) {
|
if (!individualHashMap.get("id").equals(message.getActiveUserId())) {
|
||||||
messageString =
|
messageString =
|
||||||
DisplayUtils.searchAndColor(messageString,
|
DisplayUtils.searchAndReplaceWithMentionSpan(messageText.getContext(),
|
||||||
"@" + individualHashMap.get("name"), NextcloudTalkApplication
|
messageString,
|
||||||
.getSharedApplication().getResources().getColor(R.color.nc_outcoming_text_default));
|
individualHashMap.get("id"),
|
||||||
|
individualHashMap.get("name"),
|
||||||
|
individualHashMap.get("type"),
|
||||||
|
userUtils.getUserById(message.getActiveUserId()),
|
||||||
|
R.xml.chip_simple_background);
|
||||||
|
} else {
|
||||||
|
messageString =
|
||||||
|
DisplayUtils.searchAndReplaceWithMentionSpan(messageText.getContext(),
|
||||||
|
messageString,
|
||||||
|
individualHashMap.get("id"),
|
||||||
|
individualHashMap.get("name"),
|
||||||
|
individualHashMap.get("type"),
|
||||||
|
userUtils.getUserById(message.getActiveUserId()),
|
||||||
|
R.xml.chip_outgoing_own_mention);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (individualHashMap.get("type").equals("file")) {
|
} else if (individualHashMap.get("type").equals("file")) {
|
||||||
itemView.setOnClickListener(v -> {
|
itemView.setOnClickListener(v -> {
|
||||||
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(individualHashMap.get("link")));
|
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(individualHashMap.get("link")));
|
||||||
|
@ -20,15 +20,31 @@
|
|||||||
|
|
||||||
package com.nextcloud.talk.callbacks;
|
package com.nextcloud.talk.callbacks;
|
||||||
|
|
||||||
import android.graphics.Typeface;
|
import android.content.Context;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.Spanned;
|
import android.text.Spanned;
|
||||||
|
import android.text.style.DynamicDrawableSpan;
|
||||||
|
import com.nextcloud.talk.R;
|
||||||
|
import com.nextcloud.talk.models.database.UserEntity;
|
||||||
import com.nextcloud.talk.models.json.mention.Mention;
|
import com.nextcloud.talk.models.json.mention.Mention;
|
||||||
|
import com.nextcloud.talk.utils.DisplayUtils;
|
||||||
import com.nextcloud.talk.utils.MagicCharPolicy;
|
import com.nextcloud.talk.utils.MagicCharPolicy;
|
||||||
import com.nextcloud.talk.utils.text.Spans;
|
import com.nextcloud.talk.utils.text.Spans;
|
||||||
import com.otaliastudios.autocomplete.AutocompleteCallback;
|
import com.otaliastudios.autocomplete.AutocompleteCallback;
|
||||||
|
import com.vanniktech.emoji.EmojiEditText;
|
||||||
|
|
||||||
public class MentionAutocompleteCallback implements AutocompleteCallback<Mention> {
|
public class MentionAutocompleteCallback implements AutocompleteCallback<Mention> {
|
||||||
|
private Context context;
|
||||||
|
private UserEntity conversationUser;
|
||||||
|
private EmojiEditText emojiEditText;
|
||||||
|
|
||||||
|
public MentionAutocompleteCallback(Context context, UserEntity conversationUser,
|
||||||
|
EmojiEditText emojiEditText) {
|
||||||
|
this.context = context;
|
||||||
|
this.conversationUser = conversationUser;
|
||||||
|
this.emojiEditText = emojiEditText;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onPopupItemClicked(Editable editable, Mention item) {
|
public boolean onPopupItemClicked(Editable editable, Mention item) {
|
||||||
int[] range = MagicCharPolicy.getQueryRange(editable);
|
int[] range = MagicCharPolicy.getQueryRange(editable);
|
||||||
@ -37,8 +53,14 @@ public class MentionAutocompleteCallback implements AutocompleteCallback<Mention
|
|||||||
int end = range[1];
|
int end = range[1];
|
||||||
String replacement = item.getLabel();
|
String replacement = item.getLabel();
|
||||||
editable.replace(start, end, replacement + " ");
|
editable.replace(start, end, replacement + " ");
|
||||||
Spans.MentionSpan mentionSpan = new Spans.MentionSpan(Typeface.BOLD, item.getId(), item.getLabel());
|
Spans.MentionChipSpan mentionChipSpan =
|
||||||
editable.setSpan(mentionSpan, start, start + item.getLabel().length() , Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
new Spans.MentionChipSpan(DisplayUtils.getDrawableForMentionChipSpan(context,
|
||||||
|
item.getId(), item.getLabel(), conversationUser, item.getSource(),
|
||||||
|
R.xml.chip_accent_background, emojiEditText),
|
||||||
|
DynamicDrawableSpan.ALIGN_BASELINE,
|
||||||
|
item.getId(), item.getLabel());
|
||||||
|
editable.setSpan(mentionChipSpan, start, start + item.getLabel().length(),
|
||||||
|
Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +95,6 @@ import pub.devrel.easypermissions.AfterPermissionGranted;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@ -118,6 +118,8 @@ public class ChatController extends BaseController implements MessagesListAdapte
|
|||||||
UserUtils userUtils;
|
UserUtils userUtils;
|
||||||
@Inject
|
@Inject
|
||||||
AppPreferences appPreferences;
|
AppPreferences appPreferences;
|
||||||
|
@Inject
|
||||||
|
Context context;
|
||||||
@BindView(R.id.messagesListView)
|
@BindView(R.id.messagesListView)
|
||||||
MessagesList messagesListView;
|
MessagesList messagesListView;
|
||||||
@BindView(R.id.messageInputView)
|
@BindView(R.id.messageInputView)
|
||||||
@ -385,8 +387,9 @@ public class ChatController extends BaseController implements MessagesListAdapte
|
|||||||
}
|
}
|
||||||
|
|
||||||
Editable editable = messageInput.getEditableText();
|
Editable editable = messageInput.getEditableText();
|
||||||
Spans.MentionSpan[] mentionSpans = editable.getSpans(0, messageInput.length(), Spans.MentionSpan.class);
|
Spans.MentionChipSpan[] mentionSpans = editable.getSpans(0, messageInput.length(),
|
||||||
Spans.MentionSpan mentionSpan;
|
Spans.MentionChipSpan.class);
|
||||||
|
Spans.MentionChipSpan mentionSpan;
|
||||||
for (int i = 0; i < mentionSpans.length; i++) {
|
for (int i = 0; i < mentionSpans.length; i++) {
|
||||||
mentionSpan = mentionSpans[i];
|
mentionSpan = mentionSpans[i];
|
||||||
if (start >= editable.getSpanStart(mentionSpan) && start < editable.getSpanEnd(mentionSpan)) {
|
if (start >= editable.getSpanStart(mentionSpan) && start < editable.getSpanEnd(mentionSpan)) {
|
||||||
@ -482,7 +485,8 @@ public class ChatController extends BaseController implements MessagesListAdapte
|
|||||||
float elevation = 6f;
|
float elevation = 6f;
|
||||||
Drawable backgroundDrawable = new ColorDrawable(Color.WHITE);
|
Drawable backgroundDrawable = new ColorDrawable(Color.WHITE);
|
||||||
AutocompletePresenter<Mention> presenter = new MentionAutocompletePresenter(getApplicationContext(), roomToken);
|
AutocompletePresenter<Mention> presenter = new MentionAutocompletePresenter(getApplicationContext(), roomToken);
|
||||||
AutocompleteCallback<Mention> callback = new MentionAutocompleteCallback();
|
AutocompleteCallback<Mention> callback = new MentionAutocompleteCallback(getActivity(),
|
||||||
|
conversationUser, messageInput);
|
||||||
|
|
||||||
if (mentionAutocomplete == null && messageInput != null) {
|
if (mentionAutocomplete == null && messageInput != null) {
|
||||||
mentionAutocomplete = Autocomplete.<Mention>on(messageInput)
|
mentionAutocomplete = Autocomplete.<Mention>on(messageInput)
|
||||||
@ -728,8 +732,9 @@ public class ChatController extends BaseController implements MessagesListAdapte
|
|||||||
|
|
||||||
private void submitMessage() {
|
private void submitMessage() {
|
||||||
final Editable editable = messageInput.getEditableText();
|
final Editable editable = messageInput.getEditableText();
|
||||||
Spans.MentionSpan mentionSpans[] = editable.getSpans(0, editable.length(), Spans.MentionSpan.class);
|
Spans.MentionChipSpan mentionSpans[] = editable.getSpans(0, editable.length(),
|
||||||
Spans.MentionSpan mentionSpan;
|
Spans.MentionChipSpan.class);
|
||||||
|
Spans.MentionChipSpan mentionSpan;
|
||||||
for (int i = 0; i < mentionSpans.length; i++) {
|
for (int i = 0; i < mentionSpans.length; i++) {
|
||||||
mentionSpan = mentionSpans[i];
|
mentionSpan = mentionSpans[i];
|
||||||
editable.replace(editable.getSpanStart(mentionSpan), editable.getSpanEnd(mentionSpan), "@" + mentionSpan.getId());
|
editable.replace(editable.getSpanStart(mentionSpan), editable.getSpanEnd(mentionSpan), "@" + mentionSpan.getId());
|
||||||
|
@ -32,10 +32,10 @@ import android.view.ViewGroup;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.RequiresApi;
|
import androidx.annotation.RequiresApi;
|
||||||
import androidx.biometric.BiometricPrompt;
|
import androidx.biometric.BiometricPrompt;
|
||||||
|
import androidx.fragment.app.FragmentActivity;
|
||||||
import autodagger.AutoInjector;
|
import autodagger.AutoInjector;
|
||||||
import butterknife.OnClick;
|
import butterknife.OnClick;
|
||||||
import com.nextcloud.talk.R;
|
import com.nextcloud.talk.R;
|
||||||
import com.nextcloud.talk.activities.MainActivity;
|
|
||||||
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||||
import com.nextcloud.talk.controllers.base.BaseController;
|
import com.nextcloud.talk.controllers.base.BaseController;
|
||||||
import com.nextcloud.talk.utils.SecurityUtils;
|
import com.nextcloud.talk.utils.SecurityUtils;
|
||||||
@ -88,7 +88,7 @@ public class LockedController extends BaseController {
|
|||||||
|
|
||||||
Executor executor = Executors.newSingleThreadExecutor();
|
Executor executor = Executors.newSingleThreadExecutor();
|
||||||
|
|
||||||
final BiometricPrompt biometricPrompt = new BiometricPrompt((MainActivity) context, executor,
|
final BiometricPrompt biometricPrompt = new BiometricPrompt((FragmentActivity) context, executor,
|
||||||
new BiometricPrompt.AuthenticationCallback() {
|
new BiometricPrompt.AuthenticationCallback() {
|
||||||
@Override
|
@Override
|
||||||
public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
|
public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
|
||||||
|
@ -192,8 +192,10 @@ public class CallMenuController extends BaseController implements FlexibleAdapte
|
|||||||
|
|
||||||
|
|
||||||
if (conversation.canLeave(currentUser)) {
|
if (conversation.canLeave(currentUser)) {
|
||||||
menuItems.add(new MenuItem(getResources().getString(R.string.nc_leave), 1, getResources().getDrawable(R.drawable
|
menuItems.add(new MenuItem(getResources().getString(R.string.nc_leave), 1,
|
||||||
.ic_close_grey600_24dp)));
|
DisplayUtils.getTintedDrawable(getResources(),
|
||||||
|
R.drawable.ic_exit_to_app_black_24dp, R.color.grey_600)
|
||||||
|
));
|
||||||
}
|
}
|
||||||
} else if (menuType.equals(MenuType.SHARE)) {
|
} else if (menuType.equals(MenuType.SHARE)) {
|
||||||
prepareIntent();
|
prepareIntent();
|
||||||
|
@ -22,7 +22,6 @@ package com.nextcloud.talk.controllers.bottomsheet;
|
|||||||
|
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.res.ColorStateList;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
@ -33,7 +32,10 @@ import android.view.View;
|
|||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.inputmethod.EditorInfo;
|
import android.view.inputmethod.EditorInfo;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import autodagger.AutoInjector;
|
||||||
|
import butterknife.BindView;
|
||||||
|
import butterknife.OnClick;
|
||||||
import com.bluelinelabs.conductor.RouterTransaction;
|
import com.bluelinelabs.conductor.RouterTransaction;
|
||||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
|
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
|
||||||
import com.google.android.material.textfield.TextInputEditText;
|
import com.google.android.material.textfield.TextInputEditText;
|
||||||
@ -47,17 +49,11 @@ import com.nextcloud.talk.utils.ShareUtils;
|
|||||||
import com.nextcloud.talk.utils.bundle.BundleKeys;
|
import com.nextcloud.talk.utils.bundle.BundleKeys;
|
||||||
import com.nextcloud.talk.utils.database.user.UserUtils;
|
import com.nextcloud.talk.utils.database.user.UserUtils;
|
||||||
import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder;
|
import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder;
|
||||||
|
|
||||||
import org.greenrobot.eventbus.EventBus;
|
import org.greenrobot.eventbus.EventBus;
|
||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import autodagger.AutoInjector;
|
|
||||||
import butterknife.BindView;
|
|
||||||
import butterknife.OnClick;
|
|
||||||
|
|
||||||
@AutoInjector(NextcloudTalkApplication.class)
|
@AutoInjector(NextcloudTalkApplication.class)
|
||||||
public class EntryMenuController extends BaseController {
|
public class EntryMenuController extends BaseController {
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
package com.nextcloud.talk.models.json.mention;
|
package com.nextcloud.talk.models.json.mention;
|
||||||
|
|
||||||
import com.bluelinelabs.logansquare.annotation.JsonField;
|
import com.bluelinelabs.logansquare.annotation.JsonField;
|
||||||
|
import com.bluelinelabs.logansquare.annotation.JsonIgnore;
|
||||||
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.parceler.Parcel;
|
import org.parceler.Parcel;
|
||||||
@ -34,7 +35,7 @@ public class Mention {
|
|||||||
@JsonField(name = "label")
|
@JsonField(name = "label")
|
||||||
String label;
|
String label;
|
||||||
|
|
||||||
// type of user (guests or users)
|
// type of user (guests or users or calls)
|
||||||
@JsonField(name = "source")
|
@JsonField(name = "source")
|
||||||
String source;
|
String source;
|
||||||
}
|
}
|
||||||
|
@ -113,7 +113,8 @@ public class MentionAutocompletePresenter extends RecyclerViewPresenter<Mention>
|
|||||||
List<AbstractFlexibleItem> internalAbstractFlexibleItemList = new ArrayList<>();
|
List<AbstractFlexibleItem> internalAbstractFlexibleItemList = new ArrayList<>();
|
||||||
for (Mention mention : mentionsList) {
|
for (Mention mention : mentionsList) {
|
||||||
internalAbstractFlexibleItemList.add(
|
internalAbstractFlexibleItemList.add(
|
||||||
new MentionAutocompleteItem(mention.getId(), mention.getLabel(),
|
new MentionAutocompleteItem(mention.getId(),
|
||||||
|
mention.getLabel(), mention.getSource(),
|
||||||
currentUser));
|
currentUser));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,9 +144,9 @@ public class MentionAutocompletePresenter extends RecyclerViewPresenter<Mention>
|
|||||||
Mention mention = new Mention();
|
Mention mention = new Mention();
|
||||||
MentionAutocompleteItem mentionAutocompleteItem = (MentionAutocompleteItem) adapter.getItem(position);
|
MentionAutocompleteItem mentionAutocompleteItem = (MentionAutocompleteItem) adapter.getItem(position);
|
||||||
if (mentionAutocompleteItem != null) {
|
if (mentionAutocompleteItem != null) {
|
||||||
mention.setId(mentionAutocompleteItem.getUserId());
|
mention.setId(mentionAutocompleteItem.getObjectId());
|
||||||
mention.setLabel(mentionAutocompleteItem.getDisplayName());
|
mention.setLabel(mentionAutocompleteItem.getDisplayName());
|
||||||
mention.setSource("users");
|
mention.setSource(mentionAutocompleteItem.getSource());
|
||||||
dispatchClick(mention);
|
dispatchClick(mention);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -24,6 +24,7 @@ import android.annotation.SuppressLint;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.res.ColorStateList;
|
import android.content.res.ColorStateList;
|
||||||
|
import android.content.res.Configuration;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
@ -37,10 +38,7 @@ import android.net.Uri;
|
|||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.text.*;
|
import android.text.*;
|
||||||
import android.text.method.LinkMovementMethod;
|
import android.text.method.LinkMovementMethod;
|
||||||
import android.text.style.AbsoluteSizeSpan;
|
import android.text.style.*;
|
||||||
import android.text.style.ClickableSpan;
|
|
||||||
import android.text.style.ForegroundColorSpan;
|
|
||||||
import android.text.style.StyleSpan;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@ -50,15 +48,26 @@ import androidx.annotation.*;
|
|||||||
import androidx.appcompat.widget.AppCompatDrawableManager;
|
import androidx.appcompat.widget.AppCompatDrawableManager;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
import androidx.core.graphics.drawable.DrawableCompat;
|
import androidx.core.graphics.drawable.DrawableCompat;
|
||||||
|
import com.facebook.common.executors.UiThreadImmediateExecutorService;
|
||||||
|
import com.facebook.common.references.CloseableReference;
|
||||||
|
import com.facebook.datasource.DataSource;
|
||||||
|
import com.facebook.drawee.backends.pipeline.Fresco;
|
||||||
import com.facebook.drawee.controller.ControllerListener;
|
import com.facebook.drawee.controller.ControllerListener;
|
||||||
import com.facebook.drawee.view.SimpleDraweeView;
|
import com.facebook.drawee.view.SimpleDraweeView;
|
||||||
import com.facebook.imagepipeline.common.RotationOptions;
|
import com.facebook.imagepipeline.common.RotationOptions;
|
||||||
|
import com.facebook.imagepipeline.core.ImagePipeline;
|
||||||
|
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber;
|
||||||
|
import com.facebook.imagepipeline.image.CloseableImage;
|
||||||
import com.facebook.imagepipeline.image.ImageInfo;
|
import com.facebook.imagepipeline.image.ImageInfo;
|
||||||
import com.facebook.imagepipeline.postprocessors.RoundAsCirclePostprocessor;
|
import com.facebook.imagepipeline.postprocessors.RoundAsCirclePostprocessor;
|
||||||
import com.facebook.imagepipeline.request.ImageRequest;
|
import com.facebook.imagepipeline.request.ImageRequest;
|
||||||
import com.facebook.imagepipeline.request.ImageRequestBuilder;
|
import com.facebook.imagepipeline.request.ImageRequestBuilder;
|
||||||
|
import com.google.android.material.chip.ChipDrawable;
|
||||||
import com.nextcloud.talk.R;
|
import com.nextcloud.talk.R;
|
||||||
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||||
|
import com.nextcloud.talk.models.database.UserEntity;
|
||||||
|
import com.nextcloud.talk.utils.text.Spans;
|
||||||
|
import com.vanniktech.emoji.EmojiEditText;
|
||||||
import com.vanniktech.emoji.EmojiTextView;
|
import com.vanniktech.emoji.EmojiTextView;
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
@ -209,6 +218,96 @@ public class DisplayUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static Drawable getDrawableForMentionChipSpan(Context context, String id, String label,
|
||||||
|
UserEntity conversationUser, String type,
|
||||||
|
@XmlRes int chipResource,
|
||||||
|
@Nullable EmojiEditText emojiEditText) {
|
||||||
|
ChipDrawable chip = ChipDrawable.createFromResource(context, chipResource);
|
||||||
|
chip.setText(label);
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
Configuration config = context.getResources().getConfiguration();
|
||||||
|
chip.setLayoutDirection(config.getLayoutDirection());
|
||||||
|
}
|
||||||
|
|
||||||
|
int drawable;
|
||||||
|
|
||||||
|
boolean isCall = "call".equals(type) || "calls".equals(type);
|
||||||
|
|
||||||
|
if (!isCall) {
|
||||||
|
if (chipResource == R.xml.chip_accent_background) {
|
||||||
|
drawable = R.drawable.white_circle;
|
||||||
|
} else {
|
||||||
|
drawable = R.drawable.accent_circle;
|
||||||
|
}
|
||||||
|
|
||||||
|
chip.setChipIcon(context.getDrawable(drawable));
|
||||||
|
} else {
|
||||||
|
chip.setChipIcon(getRoundedDrawable(context.getDrawable(R.drawable.ic_people_group_white_24px)));
|
||||||
|
}
|
||||||
|
|
||||||
|
chip.setBounds(0, 0, chip.getIntrinsicWidth(), chip.getIntrinsicHeight());
|
||||||
|
|
||||||
|
if (!isCall) {
|
||||||
|
ImageRequest imageRequest =
|
||||||
|
getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(conversationUser.getBaseUrl(), id, R.dimen.avatar_size_big));
|
||||||
|
ImagePipeline imagePipeline = Fresco.getImagePipeline();
|
||||||
|
DataSource<CloseableReference<CloseableImage>> dataSource = imagePipeline.fetchDecodedImage(imageRequest, context);
|
||||||
|
|
||||||
|
dataSource.subscribe(
|
||||||
|
new BaseBitmapDataSubscriber() {
|
||||||
|
@Override
|
||||||
|
protected void onNewResultImpl(Bitmap bitmap) {
|
||||||
|
if (bitmap != null) {
|
||||||
|
chip.setChipIcon(getRoundedDrawable(new BitmapDrawable(bitmap)));
|
||||||
|
|
||||||
|
// A hack to refresh the chip icon
|
||||||
|
if (emojiEditText != null) {
|
||||||
|
emojiEditText.post(() -> emojiEditText.setTextKeepState(emojiEditText.getText(), TextView.BufferType.SPANNABLE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onFailureImpl(DataSource<CloseableReference<CloseableImage>> dataSource) {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
UiThreadImmediateExecutorService.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
return chip;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static Spannable searchAndReplaceWithMentionSpan(Context context, Spannable text,
|
||||||
|
String id, String label, String type,
|
||||||
|
UserEntity conversationUser,
|
||||||
|
@XmlRes int chipXmlRes) {
|
||||||
|
|
||||||
|
Spannable spannableString = new SpannableString(text);
|
||||||
|
String stringText = text.toString();
|
||||||
|
|
||||||
|
Matcher m = Pattern.compile("@" + label,
|
||||||
|
Pattern.CASE_INSENSITIVE | Pattern.LITERAL | Pattern.MULTILINE)
|
||||||
|
.matcher(spannableString);
|
||||||
|
|
||||||
|
int lastStartIndex = -1;
|
||||||
|
Spans.MentionChipSpan mentionChipSpan;
|
||||||
|
while (m.find()) {
|
||||||
|
int start = stringText.indexOf(m.group(), lastStartIndex);
|
||||||
|
int end = start + m.group().length();
|
||||||
|
lastStartIndex = end;
|
||||||
|
mentionChipSpan = new Spans.MentionChipSpan(DisplayUtils.getDrawableForMentionChipSpan(context,
|
||||||
|
id, label, conversationUser, type, chipXmlRes, null),
|
||||||
|
DynamicDrawableSpan.ALIGN_BASELINE, id,
|
||||||
|
label);
|
||||||
|
spannableString.setSpan(mentionChipSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return spannableString;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public static Spannable searchAndColor(Spannable text, String searchText, @ColorInt int color) {
|
public static Spannable searchAndColor(Spannable text, String searchText, @ColorInt int color) {
|
||||||
|
|
||||||
Spannable spannableString = new SpannableString(text);
|
Spannable spannableString = new SpannableString(text);
|
||||||
|
@ -105,6 +105,13 @@ public class UserUtils {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public UserEntity getUserById(String id) {
|
||||||
|
Result findUserQueryResult = dataStore.select(User.class).where(UserEntity.USER_ID.eq(id))
|
||||||
|
.limit(1).get();
|
||||||
|
|
||||||
|
return (UserEntity) findUserQueryResult.firstOrNull();
|
||||||
|
}
|
||||||
|
|
||||||
public UserEntity getUserWithId(long id) {
|
public UserEntity getUserWithId(long id) {
|
||||||
Result findUserQueryResult = dataStore.select(User.class).where(UserEntity.ID.eq(id))
|
Result findUserQueryResult = dataStore.select(User.class).where(UserEntity.ID.eq(id))
|
||||||
.limit(1).get();
|
.limit(1).get();
|
||||||
|
@ -20,20 +20,22 @@
|
|||||||
|
|
||||||
package com.nextcloud.talk.utils.text;
|
package com.nextcloud.talk.utils.text;
|
||||||
|
|
||||||
import android.text.style.StyleSpan;
|
import android.graphics.drawable.Drawable;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
public class Spans {
|
public class Spans {
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public static class MentionSpan extends StyleSpan {
|
public static class MentionChipSpan extends TextAlignedImageSpan {
|
||||||
String id;
|
String id;
|
||||||
String label;
|
String label;
|
||||||
|
|
||||||
public MentionSpan(int style, String id, String label) {
|
public MentionChipSpan(@NonNull Drawable drawable, int verticalAlignment, String id, String label) {
|
||||||
super(style);
|
super(drawable, verticalAlignment);
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.label = label;
|
this.label = label;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Nextcloud Talk application
|
||||||
|
*
|
||||||
|
* @author Mario Danic
|
||||||
|
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Taken and adapter from
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.nextcloud.talk.utils.text;
|
||||||
|
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.text.style.ImageSpan;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
public class TextAlignedImageSpan extends ImageSpan {
|
||||||
|
public TextAlignedImageSpan(@NonNull Drawable drawable, int verticalAlignment) {
|
||||||
|
super(drawable, verticalAlignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSize(@NonNull Paint paint, CharSequence text, int start, int end,
|
||||||
|
Paint.FontMetricsInt fontMetricsInt) {
|
||||||
|
Drawable drawable = getDrawable();
|
||||||
|
Rect drawableBounds = drawable.getBounds();
|
||||||
|
|
||||||
|
if (fontMetricsInt != null) {
|
||||||
|
Paint.FontMetricsInt fmPaint = paint.getFontMetricsInt();
|
||||||
|
int fontHeight = fmPaint.bottom - fmPaint.top;
|
||||||
|
int drHeight = drawableBounds.bottom - drawableBounds.top;
|
||||||
|
|
||||||
|
int top = drHeight / 2 - fontHeight / 4;
|
||||||
|
int bottom = drHeight / 2 + fontHeight / 4;
|
||||||
|
|
||||||
|
fontMetricsInt.ascent = -bottom;
|
||||||
|
fontMetricsInt.top = -bottom;
|
||||||
|
fontMetricsInt.bottom = top;
|
||||||
|
fontMetricsInt.descent = top;
|
||||||
|
}
|
||||||
|
|
||||||
|
return drawableBounds.right;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end,
|
||||||
|
float x, int top, int y, int bottom, @NonNull Paint paint) {
|
||||||
|
Drawable drawable = getDrawable();
|
||||||
|
canvas.save();
|
||||||
|
int transY;
|
||||||
|
transY = ((bottom - top) - drawable.getBounds().bottom) / 2 + top;
|
||||||
|
canvas.translate(x, transY);
|
||||||
|
drawable.draw(canvas);
|
||||||
|
canvas.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
26
app/src/main/res/drawable/accent_circle.xml
Normal file
26
app/src/main/res/drawable/accent_circle.xml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Nextcloud Talk application
|
||||||
|
~
|
||||||
|
~ @author Mario Danic
|
||||||
|
~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
~ at your option) any later version.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="oval">
|
||||||
|
<solid
|
||||||
|
android:color="@color/colorAccent"/>
|
||||||
|
</shape>
|
26
app/src/main/res/drawable/white_circle.xml
Normal file
26
app/src/main/res/drawable/white_circle.xml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Nextcloud Talk application
|
||||||
|
~
|
||||||
|
~ @author Mario Danic
|
||||||
|
~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
~ at your option) any later version.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="oval">
|
||||||
|
<solid
|
||||||
|
android:color="@color/white"/>
|
||||||
|
</shape>
|
@ -52,6 +52,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textColor="@color/colorPrimary"
|
android:textColor="@color/colorPrimary"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
android:textSize="12sp" />
|
android:textSize="12sp" />
|
||||||
|
|
||||||
<com.vanniktech.emoji.EmojiTextView
|
<com.vanniktech.emoji.EmojiTextView
|
||||||
@ -59,11 +60,11 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textIsSelectable="true"
|
android:textIsSelectable="true"
|
||||||
|
android:lineSpacingMultiplier="1.2"
|
||||||
app:layout_alignSelf="flex_start"
|
app:layout_alignSelf="flex_start"
|
||||||
app:layout_flexGrow="1"
|
app:layout_flexGrow="1"
|
||||||
app:layout_wrapBefore="true" />
|
app:layout_wrapBefore="true" />
|
||||||
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@id/messageTime"
|
android:id="@id/messageTime"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignWithParentIfMissing="true"
|
android:layout_alignWithParentIfMissing="true"
|
||||||
android:textColorHighlight="@color/nc_grey"
|
android:textColorHighlight="@color/nc_grey"
|
||||||
|
android:lineSpacingMultiplier="1.2"
|
||||||
android:textIsSelectable="true" />
|
android:textIsSelectable="true" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
|
android:lineSpacingMultiplier="1.2"
|
||||||
android:imeOptions="actionDone"
|
android:imeOptions="actionDone"
|
||||||
android:layout_toStartOf="@id/sendButtonSpace"
|
android:layout_toStartOf="@id/sendButtonSpace"
|
||||||
android:inputType="textAutoCorrect|textMultiLine|textCapSentences"/>
|
android:inputType="textAutoCorrect|textMultiLine|textCapSentences"/>
|
||||||
|
@ -16,4 +16,12 @@
|
|||||||
<item name="android:textSize">12sp</item>
|
<item name="android:textSize">12sp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="ChipTextAppearance" parent="TextAppearance.MaterialComponents.Chip">
|
||||||
|
<item name="android:textColor">@android:color/white</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="ChipAccentTextAppearance" parent="TextAppearance.MaterialComponents.Chip">
|
||||||
|
<item name="android:textColor">@color/colorAccent</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
26
app/src/main/res/xml/chip_accent_background.xml
Normal file
26
app/src/main/res/xml/chip_accent_background.xml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Nextcloud Talk application
|
||||||
|
~
|
||||||
|
~ @author Mario Danic
|
||||||
|
~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
~ at your option) any later version.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<chip xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:textAppearance="@style/ChipTextAppearance"
|
||||||
|
app:chipBackgroundColor="@color/colorAccent"
|
||||||
|
app:closeIconEnabled="false"/>
|
26
app/src/main/res/xml/chip_outgoing_own_mention.xml
Normal file
26
app/src/main/res/xml/chip_outgoing_own_mention.xml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Nextcloud Talk application
|
||||||
|
~
|
||||||
|
~ @author Mario Danic
|
||||||
|
~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
~ at your option) any later version.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<chip xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:textAppearance="@style/ChipAccentTextAppearance"
|
||||||
|
app:chipBackgroundColor="@color/white_four"
|
||||||
|
app:closeIconEnabled="false" />
|
26
app/src/main/res/xml/chip_simple_background.xml
Normal file
26
app/src/main/res/xml/chip_simple_background.xml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Nextcloud Talk application
|
||||||
|
~
|
||||||
|
~ @author Mario Danic
|
||||||
|
~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||||
|
~
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
~ at your option) any later version.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<chip xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:textAppearance="@style/ChipAccentTextAppearance"
|
||||||
|
app:chipBackgroundColor="@color/white"
|
||||||
|
app:closeIconEnabled="false" />
|
Loading…
Reference in New Issue
Block a user