diff --git a/app/build.gradle b/app/build.gradle index 22335289a..26c2b442e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -17,8 +17,8 @@ android { targetSdkVersion 28 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - versionCode 90 - versionName "6.0.0beta2" + versionCode 91 + versionName "6.0.0beta3" flavorDimensions "default" renderscriptTargetApi 19 @@ -100,7 +100,6 @@ android { } ext { - supportLibraryVersion = '28.0.0' workVersion = "1.0.0" } @@ -115,17 +114,17 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'androidx.appcompat:appcompat:1.0.2' 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 'org.michaelevans.colorart:library:0.0.3' implementation "android.arch.work:work-runtime:${workVersion}" implementation "android.arch.work:work-rxjava2:${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.multidex:multidex:2.0.0' + implementation 'androidx.multidex:multidex:2.0.1' implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' implementation "io.reactivex.rxjava2:rxjava:2.2.7" diff --git a/app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.java b/app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.java index 4bb634b54..97f997f48 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.java @@ -45,18 +45,28 @@ import java.util.List; public class MentionAutocompleteItem extends AbstractFlexibleItem implements IFilterable { - private String userId; + private String objectId; private String displayName; + private String source; private UserEntity currentUser; - public MentionAutocompleteItem(String userId, String displayName, UserEntity currentUser) { - this.userId = userId; + public MentionAutocompleteItem(String objectId, String displayName, String source, UserEntity currentUser) { + this.objectId = objectId; this.displayName = displayName; + this.source = source; this.currentUser = currentUser; } - public String getUserId() { - return userId; + public String getSource() { + return source; + } + + public void setSource(String source) { + this.source = source; + } + + public String getObjectId() { + return objectId; } public String getDisplayName() { @@ -67,7 +77,7 @@ public class MentionAutocompleteItem extends AbstractFlexibleItem individualHashMap = message.getMessageParameters().get(key); if (individualHashMap != null) { 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())) { - color = NextcloudTalkApplication.getSharedApplication().getResources().getColor(R.color - .nc_incoming_text_mention_you); + messageString = + DisplayUtils.searchAndReplaceWithMentionSpan(messageText.getContext(), + messageString, + individualHashMap.get("id"), + individualHashMap.get("name"), + individualHashMap.get("type"), + userUtils.getUserById(message.getActiveUserId()), + R.xml.chip_simple_background); } else { - color = NextcloudTalkApplication.getSharedApplication().getResources().getColor(R.color - .nc_incoming_text_mention_others); + messageString = + 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")) { itemView.setOnClickListener(v -> { Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(individualHashMap.get("link"))); diff --git a/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicOutcomingTextMessageViewHolder.java b/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicOutcomingTextMessageViewHolder.java index 26633d1fd..b71f0dbc2 100644 --- a/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicOutcomingTextMessageViewHolder.java +++ b/app/src/main/java/com/nextcloud/talk/adapters/messages/MagicOutcomingTextMessageViewHolder.java @@ -58,6 +58,9 @@ public class MagicOutcomingTextMessageViewHolder extends MessageHolders.Outcomin @Inject UserUtils userUtils; + @Inject + Context context; + private View itemView; public MagicOutcomingTextMessageViewHolder(View itemView) { @@ -76,7 +79,6 @@ public class MagicOutcomingTextMessageViewHolder extends MessageHolders.Outcomin Spannable messageString = new SpannableString(message.getText()); - Context context = NextcloudTalkApplication.getSharedApplication().getApplicationContext(); itemView.setSelected(false); 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("id").equals(message.getActiveUserId())) { messageString = - DisplayUtils.searchAndColor(messageString, - "@" + individualHashMap.get("name"), NextcloudTalkApplication - .getSharedApplication().getResources().getColor(R.color.nc_outcoming_text_default)); + DisplayUtils.searchAndReplaceWithMentionSpan(messageText.getContext(), + messageString, + 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")) { itemView.setOnClickListener(v -> { Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(individualHashMap.get("link"))); diff --git a/app/src/main/java/com/nextcloud/talk/callbacks/MentionAutocompleteCallback.java b/app/src/main/java/com/nextcloud/talk/callbacks/MentionAutocompleteCallback.java index 9785db472..926813d77 100644 --- a/app/src/main/java/com/nextcloud/talk/callbacks/MentionAutocompleteCallback.java +++ b/app/src/main/java/com/nextcloud/talk/callbacks/MentionAutocompleteCallback.java @@ -20,15 +20,31 @@ package com.nextcloud.talk.callbacks; -import android.graphics.Typeface; +import android.content.Context; import android.text.Editable; 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.utils.DisplayUtils; import com.nextcloud.talk.utils.MagicCharPolicy; import com.nextcloud.talk.utils.text.Spans; import com.otaliastudios.autocomplete.AutocompleteCallback; +import com.vanniktech.emoji.EmojiEditText; public class MentionAutocompleteCallback implements AutocompleteCallback { + 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 public boolean onPopupItemClicked(Editable editable, Mention item) { int[] range = MagicCharPolicy.getQueryRange(editable); @@ -37,8 +53,14 @@ public class MentionAutocompleteCallback implements AutocompleteCallback= editable.getSpanStart(mentionSpan) && start < editable.getSpanEnd(mentionSpan)) { @@ -482,7 +485,8 @@ public class ChatController extends BaseController implements MessagesListAdapte float elevation = 6f; Drawable backgroundDrawable = new ColorDrawable(Color.WHITE); AutocompletePresenter presenter = new MentionAutocompletePresenter(getApplicationContext(), roomToken); - AutocompleteCallback callback = new MentionAutocompleteCallback(); + AutocompleteCallback callback = new MentionAutocompleteCallback(getActivity(), + conversationUser, messageInput); if (mentionAutocomplete == null && messageInput != null) { mentionAutocomplete = Autocomplete.on(messageInput) @@ -728,8 +732,9 @@ public class ChatController extends BaseController implements MessagesListAdapte private void submitMessage() { final Editable editable = messageInput.getEditableText(); - Spans.MentionSpan mentionSpans[] = editable.getSpans(0, editable.length(), Spans.MentionSpan.class); - Spans.MentionSpan mentionSpan; + Spans.MentionChipSpan mentionSpans[] = editable.getSpans(0, editable.length(), + Spans.MentionChipSpan.class); + Spans.MentionChipSpan mentionSpan; for (int i = 0; i < mentionSpans.length; i++) { mentionSpan = mentionSpans[i]; editable.replace(editable.getSpanStart(mentionSpan), editable.getSpanEnd(mentionSpan), "@" + mentionSpan.getId()); diff --git a/app/src/main/java/com/nextcloud/talk/controllers/LockedController.java b/app/src/main/java/com/nextcloud/talk/controllers/LockedController.java index 903fb3810..82743b8bf 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/LockedController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/LockedController.java @@ -32,10 +32,10 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; import androidx.biometric.BiometricPrompt; +import androidx.fragment.app.FragmentActivity; import autodagger.AutoInjector; import butterknife.OnClick; import com.nextcloud.talk.R; -import com.nextcloud.talk.activities.MainActivity; import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.controllers.base.BaseController; import com.nextcloud.talk.utils.SecurityUtils; @@ -88,7 +88,7 @@ public class LockedController extends BaseController { Executor executor = Executors.newSingleThreadExecutor(); - final BiometricPrompt biometricPrompt = new BiometricPrompt((MainActivity) context, executor, + final BiometricPrompt biometricPrompt = new BiometricPrompt((FragmentActivity) context, executor, new BiometricPrompt.AuthenticationCallback() { @Override public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) { diff --git a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/CallMenuController.java b/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/CallMenuController.java index ffbdc55f0..95205bcb4 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/CallMenuController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/CallMenuController.java @@ -192,8 +192,10 @@ public class CallMenuController extends BaseController implements FlexibleAdapte if (conversation.canLeave(currentUser)) { - menuItems.add(new MenuItem(getResources().getString(R.string.nc_leave), 1, getResources().getDrawable(R.drawable - .ic_close_grey600_24dp))); + menuItems.add(new MenuItem(getResources().getString(R.string.nc_leave), 1, + DisplayUtils.getTintedDrawable(getResources(), + R.drawable.ic_exit_to_app_black_24dp, R.color.grey_600) + )); } } else if (menuType.equals(MenuType.SHARE)) { prepareIntent(); diff --git a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/EntryMenuController.java b/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/EntryMenuController.java index 9f30efb71..89db5b5a2 100644 --- a/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/EntryMenuController.java +++ b/app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/EntryMenuController.java @@ -22,7 +22,6 @@ package com.nextcloud.talk.controllers.bottomsheet; import android.content.ComponentName; import android.content.Intent; -import android.content.res.ColorStateList; import android.os.Bundle; import android.text.Editable; import android.text.InputType; @@ -33,7 +32,10 @@ import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; 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.changehandler.HorizontalChangeHandler; 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.database.user.UserUtils; import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder; - import org.greenrobot.eventbus.EventBus; import org.parceler.Parcels; import javax.inject.Inject; -import androidx.annotation.NonNull; -import autodagger.AutoInjector; -import butterknife.BindView; -import butterknife.OnClick; - @AutoInjector(NextcloudTalkApplication.class) public class EntryMenuController extends BaseController { diff --git a/app/src/main/java/com/nextcloud/talk/models/json/mention/Mention.java b/app/src/main/java/com/nextcloud/talk/models/json/mention/Mention.java index 4d02460ea..f6f32dd98 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/mention/Mention.java +++ b/app/src/main/java/com/nextcloud/talk/models/json/mention/Mention.java @@ -20,6 +20,7 @@ package com.nextcloud.talk.models.json.mention; import com.bluelinelabs.logansquare.annotation.JsonField; +import com.bluelinelabs.logansquare.annotation.JsonIgnore; import com.bluelinelabs.logansquare.annotation.JsonObject; import lombok.Data; import org.parceler.Parcel; @@ -34,7 +35,7 @@ public class Mention { @JsonField(name = "label") String label; - // type of user (guests or users) + // type of user (guests or users or calls) @JsonField(name = "source") String source; } diff --git a/app/src/main/java/com/nextcloud/talk/presenters/MentionAutocompletePresenter.java b/app/src/main/java/com/nextcloud/talk/presenters/MentionAutocompletePresenter.java index 7d1d2204a..2f7445d15 100644 --- a/app/src/main/java/com/nextcloud/talk/presenters/MentionAutocompletePresenter.java +++ b/app/src/main/java/com/nextcloud/talk/presenters/MentionAutocompletePresenter.java @@ -113,7 +113,8 @@ public class MentionAutocompletePresenter extends RecyclerViewPresenter List internalAbstractFlexibleItemList = new ArrayList<>(); for (Mention mention : mentionsList) { internalAbstractFlexibleItemList.add( - new MentionAutocompleteItem(mention.getId(), mention.getLabel(), + new MentionAutocompleteItem(mention.getId(), + mention.getLabel(), mention.getSource(), currentUser)); } @@ -143,9 +144,9 @@ public class MentionAutocompletePresenter extends RecyclerViewPresenter Mention mention = new Mention(); MentionAutocompleteItem mentionAutocompleteItem = (MentionAutocompleteItem) adapter.getItem(position); if (mentionAutocompleteItem != null) { - mention.setId(mentionAutocompleteItem.getUserId()); + mention.setId(mentionAutocompleteItem.getObjectId()); mention.setLabel(mentionAutocompleteItem.getDisplayName()); - mention.setSource("users"); + mention.setSource(mentionAutocompleteItem.getSource()); dispatchClick(mention); } return true; diff --git a/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java b/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java index ffbe23455..326b59b26 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java +++ b/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java @@ -24,6 +24,7 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.content.res.ColorStateList; +import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; @@ -37,10 +38,7 @@ import android.net.Uri; import android.os.Build; import android.text.*; import android.text.method.LinkMovementMethod; -import android.text.style.AbsoluteSizeSpan; -import android.text.style.ClickableSpan; -import android.text.style.ForegroundColorSpan; -import android.text.style.StyleSpan; +import android.text.style.*; import android.util.Log; import android.util.TypedValue; import android.view.View; @@ -50,15 +48,26 @@ import androidx.annotation.*; import androidx.appcompat.widget.AppCompatDrawableManager; import androidx.core.content.ContextCompat; 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.view.SimpleDraweeView; 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.postprocessors.RoundAsCirclePostprocessor; import com.facebook.imagepipeline.request.ImageRequest; import com.facebook.imagepipeline.request.ImageRequestBuilder; +import com.google.android.material.chip.ChipDrawable; import com.nextcloud.talk.R; 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 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> 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> 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) { Spannable spannableString = new SpannableString(text); diff --git a/app/src/main/java/com/nextcloud/talk/utils/database/user/UserUtils.java b/app/src/main/java/com/nextcloud/talk/utils/database/user/UserUtils.java index 531351e17..9e08993be 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/database/user/UserUtils.java +++ b/app/src/main/java/com/nextcloud/talk/utils/database/user/UserUtils.java @@ -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) { Result findUserQueryResult = dataStore.select(User.class).where(UserEntity.ID.eq(id)) .limit(1).get(); diff --git a/app/src/main/java/com/nextcloud/talk/utils/text/Spans.java b/app/src/main/java/com/nextcloud/talk/utils/text/Spans.java index 1bcd93e54..6a82730fa 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/text/Spans.java +++ b/app/src/main/java/com/nextcloud/talk/utils/text/Spans.java @@ -20,20 +20,22 @@ package com.nextcloud.talk.utils.text; -import android.text.style.StyleSpan; +import android.graphics.drawable.Drawable; +import androidx.annotation.NonNull; import lombok.Data; public class Spans { + @Data - public static class MentionSpan extends StyleSpan { + public static class MentionChipSpan extends TextAlignedImageSpan { String id; String label; - public MentionSpan(int style, String id, String label) { - super(style); + public MentionChipSpan(@NonNull Drawable drawable, int verticalAlignment, String id, String label) { + super(drawable, verticalAlignment); this.id = id; this.label = label; } - } + } diff --git a/app/src/main/java/com/nextcloud/talk/utils/text/TextAlignedImageSpan.java b/app/src/main/java/com/nextcloud/talk/utils/text/TextAlignedImageSpan.java new file mode 100644 index 000000000..e3d0de015 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/utils/text/TextAlignedImageSpan.java @@ -0,0 +1,71 @@ +/* + * Nextcloud Talk application + * + * @author Mario Danic + * Copyright (C) 2017-2018 Mario Danic + * + * 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 . + * + * 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(); + } + +} diff --git a/app/src/main/res/drawable/accent_circle.xml b/app/src/main/res/drawable/accent_circle.xml new file mode 100644 index 000000000..1a0e70aca --- /dev/null +++ b/app/src/main/res/drawable/accent_circle.xml @@ -0,0 +1,26 @@ + + + + + + diff --git a/app/src/main/res/drawable/white_circle.xml b/app/src/main/res/drawable/white_circle.xml new file mode 100644 index 000000000..836510890 --- /dev/null +++ b/app/src/main/res/drawable/white_circle.xml @@ -0,0 +1,26 @@ + + + + + + diff --git a/app/src/main/res/layout/item_custom_incoming_text_message.xml b/app/src/main/res/layout/item_custom_incoming_text_message.xml index ee19fc9ad..131bb9478 100644 --- a/app/src/main/res/layout/item_custom_incoming_text_message.xml +++ b/app/src/main/res/layout/item_custom_incoming_text_message.xml @@ -52,6 +52,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:textColor="@color/colorPrimary" + android:layout_marginBottom="4dp" android:textSize="12sp" /> - diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index c77a38260..883b1bb6d 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -16,4 +16,12 @@ 12sp + + + + diff --git a/app/src/main/res/xml/chip_accent_background.xml b/app/src/main/res/xml/chip_accent_background.xml new file mode 100644 index 000000000..448cdf679 --- /dev/null +++ b/app/src/main/res/xml/chip_accent_background.xml @@ -0,0 +1,26 @@ + + + + diff --git a/app/src/main/res/xml/chip_outgoing_own_mention.xml b/app/src/main/res/xml/chip_outgoing_own_mention.xml new file mode 100644 index 000000000..432b1dea6 --- /dev/null +++ b/app/src/main/res/xml/chip_outgoing_own_mention.xml @@ -0,0 +1,26 @@ + + + + diff --git a/app/src/main/res/xml/chip_simple_background.xml b/app/src/main/res/xml/chip_simple_background.xml new file mode 100644 index 000000000..1813cd05a --- /dev/null +++ b/app/src/main/res/xml/chip_simple_background.xml @@ -0,0 +1,26 @@ + + + +