Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions app/src/main/java/com/nextcloud/utils/text/Spans.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2021 Andy Scherzinger <info@andy-scherzinger.de>
* SPDX-FileCopyrightText: 2017-2018 Mario Danic <mario@lovelyhq.com>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package com.nextcloud.utils.text;

import android.graphics.drawable.Drawable;

import androidx.annotation.NonNull;
import thirdparties.fresco.BetterImageSpan;

public class Spans {

public static class MentionChipSpan extends BetterImageSpan {
public String id;
public CharSequence label;

public MentionChipSpan(@NonNull Drawable drawable, int verticalAlignment, String id, CharSequence label) {
super(drawable, verticalAlignment);
this.id = id;
this.label = label;
}

public String getId() {
return this.id;
}

public CharSequence getLabel() {
return this.label;
}

public void setId(String id) {
this.id = id;
}

public void setLabel(CharSequence label) {
this.label = label;
}

public boolean equals(final Object o) {
if (o == this) {
return true;
}
if (!(o instanceof MentionChipSpan)) {
return false;
}
final MentionChipSpan other = (MentionChipSpan) o;
if (!other.canEqual((Object) this)) {
return false;
}
final Object this$id = this.getId();
final Object other$id = other.getId();
if (this$id == null ? other$id != null : !this$id.equals(other$id)) {
return false;
}
final Object this$label = this.getLabel();
final Object other$label = other.getLabel();

return this$label == null ? other$label == null : this$label.equals(other$label);
}

protected boolean canEqual(final Object other) {
return other instanceof MentionChipSpan;
}

public int hashCode() {
final int PRIME = 59;
int result = 1;
final Object $id = this.getId();
result = result * PRIME + ($id == null ? 43 : $id.hashCode());
final Object $label = this.getLabel();
return result * PRIME + ($label == null ? 43 : $label.hashCode());
}

public String toString() {
return "Spans.MentionChipSpan(id=" + this.getId() + ", label=" + this.getLabel() + ")";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ class NotificationsActivity :
private fun initializeAdapter() {
initializeClient()
if (adapter == null) {
adapter = NotificationListAdapter(client, this, viewThemeUtils)
adapter = NotificationListAdapter(client, this, viewThemeUtils, accountManager)
binding.list.adapter = adapter
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.text.Spannable;
Expand All @@ -24,7 +25,6 @@
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.text.format.DateUtils;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.text.style.ForegroundColorSpan;
import android.text.style.StyleSpan;
Expand All @@ -35,10 +35,12 @@
import android.widget.LinearLayout;
import android.widget.TextView;

import com.google.android.material.chip.ChipDrawable;
import com.nextcloud.client.account.CurrentAccountProvider;
import com.nextcloud.client.network.ClientFactory;
import com.nextcloud.common.NextcloudClient;
import com.nextcloud.utils.GlideHelper;
import com.nextcloud.utils.text.Spans;
import com.owncloud.android.MainApp;
import com.owncloud.android.R;
import com.owncloud.android.databinding.ActivityListItemBinding;
Expand All @@ -61,11 +63,13 @@

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import thirdparties.fresco.BetterImageSpan;

/**
* Adapter for the activity view.
*/
public class ActivityListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements StickyHeaderAdapter {
public class ActivityListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements StickyHeaderAdapter,
DisplayUtils.AvatarGenerationListener {

static final int HEADER_TYPE = 100;
static final int ACTIVITY_TYPE = 101;
Expand Down Expand Up @@ -147,9 +151,8 @@ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int positi

if (!TextUtils.isEmpty(activity.getRichSubjectElement().getRichSubject())) {
activityViewHolder.binding.subject.setVisibility(View.VISIBLE);
activityViewHolder.binding.subject.setMovementMethod(LinkMovementMethod.getInstance());
activityViewHolder.binding.subject.setText(addClickablePart(activity.getRichSubjectElement()),
TextView.BufferType.SPANNABLE);
activityViewHolder.binding.subject.setText(addClickablePart(activity.getRichSubjectElement()));

activityViewHolder.binding.subject.setVisibility(View.VISIBLE);
} else if (!TextUtils.isEmpty(activity.getSubject())) {
activityViewHolder.binding.subject.setVisibility(View.VISIBLE);
Expand Down Expand Up @@ -275,6 +278,17 @@ private ImageView createThumbnailNew(PreviewObject previewObject, List<RichObjec
return imageView;
}

private ChipDrawable getDrawableForMentionChipSpan(int chipResource, String text) {
ChipDrawable chip = ChipDrawable.createFromResource(context, chipResource);
chip.setEllipsize(TextUtils.TruncateAt.MIDDLE);
chip.setLayoutDirection(context.getResources().getConfiguration().getLayoutDirection());
chip.setText(text);
chip.setChipIconResource(R.drawable.accent_circle);
chip.setBounds(0, 0, chip.getIntrinsicWidth(), chip.getIntrinsicHeight());

return chip;
}

private SpannableStringBuilder addClickablePart(RichElement richElement) {
String text = richElement.getRichSubject();
SpannableStringBuilder ssb = new SpannableStringBuilder(text);
Expand All @@ -286,28 +300,53 @@ private SpannableStringBuilder addClickablePart(RichElement richElement) {
final String clickString = text.substring(idx1 + 1, idx2 - 1);
final RichObject richObject = searchObjectByName(richElement.getRichObjectList(), clickString);
if (richObject != null) {
String name = richObject.getName();
ssb.replace(idx1, idx2, name);
text = ssb.toString();
idx2 = idx1 + name.length();
ssb.setSpan(new ClickableSpan() {
@Override
public void onClick(@NonNull View widget) {
activityListInterface.onActivityClicked(richObject);
}

@Override
public void updateDrawState(@NonNull TextPaint ds) {
ds.setUnderlineText(false);
}
}, idx1, idx2, 0);
ssb.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), idx1, idx2, 0);
ssb.setSpan(
new ForegroundColorSpan(context.getResources().getColor(R.color.text_color)),
idx1,
idx2,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
);
if ("user".equals(richObject.getType())) {
String name = richObject.getName();

ChipDrawable drawableForChip = getDrawableForMentionChipSpan(R.xml.chip_others, name);

Spans.MentionChipSpan mentionChipSpan = new Spans.MentionChipSpan(drawableForChip,
BetterImageSpan.ALIGN_CENTER,
richObject.getId(),
name
);

DisplayUtils.setAvatar(
currentAccountProvider.getUser(),
richObject.getId(),
name,
this,
context.getResources().getDimension(R.dimen.standard_padding),
context.getResources(),
drawableForChip,
context
);

ssb.setSpan(mentionChipSpan, idx1, idx2, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
} else {
String name = richObject.getName();
ssb.replace(idx1, idx2, name);
text = ssb.toString();
idx2 = idx1 + name.length();
ssb.setSpan(new ClickableSpan() {
@Override
public void onClick(@NonNull View widget) {
activityListInterface.onActivityClicked(richObject);
}

@Override
public void updateDrawState(@NonNull TextPaint ds) {
ds.setUnderlineText(false);
}
}, idx1, idx2, 0);
ssb.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), idx1, idx2, 0);
ssb.setSpan(
new ForegroundColorSpan(context.getResources().getColor(R.color.log_level_error)),
idx1,
idx2,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
);
}
}
idx1 = text.indexOf('{', idx2);
}
Expand Down Expand Up @@ -396,6 +435,16 @@ public boolean isHeader(int itemPosition) {
return this.getItemViewType(itemPosition) == HEADER_TYPE;
}

@Override
public void avatarGenerated(Drawable avatarDrawable, Object callContext) {
((ChipDrawable) callContext).setChipIcon(avatarDrawable);
}

@Override
public boolean shouldCallGeneratedCallback(String tag, Object callContext) {
return true;
}

protected class ActivityViewHolder extends RecyclerView.ViewHolder {

ActivityListItemBinding binding;
Expand Down
Loading