From 391cd12974bd4ef1a245a9a8ce0ba47ec0c11292 Mon Sep 17 00:00:00 2001 From: Levi Bard Date: Tue, 9 Apr 2019 20:13:25 +0200 Subject: [PATCH] Add bot indicator overlay to avatars (#1173) * Add bot indicator overlay to avatars * Add bot overlay to account list in search view * Add preference for bot avatar overlay --- .../tusky/PreferencesActivity.kt | 3 ++ .../tusky/adapter/AccountViewHolder.java | 13 +++++++++ .../tusky/adapter/StatusBaseViewHolder.java | 19 +++++++++++-- .../tusky/adapter/StatusViewHolder.java | 22 ++++++--------- .../tusky/util/ViewDataUtils.java | 2 ++ .../tusky/viewdata/StatusViewData.java | 16 +++++++++-- app/src/main/res/drawable/ic_bot_24dp.xml | 8 ++++++ app/src/main/res/layout/item_account.xml | 28 +++++++++++++++---- app/src/main/res/layout/item_conversation.xml | 2 +- app/src/main/res/layout/item_status.xml | 10 +++---- .../main/res/layout/item_status_detailed.xml | 20 ++++++++++--- app/src/main/res/values/strings.xml | 1 + app/src/main/res/xml/preferences.xml | 5 ++++ 13 files changed, 115 insertions(+), 34 deletions(-) create mode 100644 app/src/main/res/drawable/ic_bot_24dp.xml diff --git a/app/src/main/java/com/keylesspalace/tusky/PreferencesActivity.kt b/app/src/main/java/com/keylesspalace/tusky/PreferencesActivity.kt index 96d7c7587..9d6e2ec06 100644 --- a/app/src/main/java/com/keylesspalace/tusky/PreferencesActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/PreferencesActivity.kt @@ -143,6 +143,9 @@ class PreferencesActivity : BaseActivity(), SharedPreferences.OnSharedPreference "absoluteTimeView" -> { restartActivitiesOnExit = true } + "showBotOverlay" -> { + restartActivitiesOnExit = true + } "language" -> { restartActivitiesOnExit = true this.restartCurrentActivity() diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/AccountViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/adapter/AccountViewHolder.java index 996100668..0753466a8 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/AccountViewHolder.java +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/AccountViewHolder.java @@ -2,6 +2,8 @@ package com.keylesspalace.tusky.adapter; import android.content.Context; import androidx.recyclerview.widget.RecyclerView; + +import android.preference.PreferenceManager; import android.view.View; import android.widget.ImageView; import android.widget.TextView; @@ -17,13 +19,17 @@ class AccountViewHolder extends RecyclerView.ViewHolder { private TextView username; private TextView displayName; private ImageView avatar; + private ImageView avatarInset; private String accountId; + private boolean showBotOverlay; AccountViewHolder(View itemView) { super(itemView); username = itemView.findViewById(R.id.account_username); displayName = itemView.findViewById(R.id.account_display_name); avatar = itemView.findViewById(R.id.account_avatar); + avatarInset = itemView.findViewById(R.id.account_avatar_inset); + showBotOverlay = PreferenceManager.getDefaultSharedPreferences(itemView.getContext()).getBoolean("showBotOverlay", true); } void setupWithAccount(Account account) { @@ -38,6 +44,13 @@ class AccountViewHolder extends RecyclerView.ViewHolder { .load(account.getAvatar()) .placeholder(R.drawable.avatar_default) .into(avatar); + if (showBotOverlay && account.getBot()) { + avatarInset.setVisibility(View.VISIBLE); + avatarInset.setImageResource(R.drawable.ic_bot_24dp); + avatarInset.setBackgroundColor(0x50ffffff); + } else { + avatarInset.setVisibility(View.GONE); + } } void setupActionListener(final AccountActionListener listener) { diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java index ef763920a..627ab76b0 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java @@ -2,6 +2,7 @@ package com.keylesspalace.tusky.adapter; import android.content.Context; import android.graphics.drawable.Drawable; +import android.preference.PreferenceManager; import android.text.Spanned; import android.text.TextUtils; import android.view.View; @@ -62,6 +63,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { private View sensitiveMediaShow; protected TextView mediaLabel; private ToggleButton contentWarningButton; + protected ImageView avatarInset; public ImageView avatar; public TextView timestampInfo; @@ -71,6 +73,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { private boolean useAbsoluteTime; private SimpleDateFormat shortSdf; private SimpleDateFormat longSdf; + private boolean showBotOverlay; private final NumberFormat numberFormat = NumberFormat.getNumberInstance(); @@ -82,7 +85,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { content = itemView.findViewById(R.id.status_content); avatar = itemView.findViewById(R.id.status_avatar); replyButton = itemView.findViewById(R.id.status_reply); - reblogButton = itemView.findViewById(R.id.status_reblog); + reblogButton = itemView.findViewById(R.id.status_inset); favouriteButton = itemView.findViewById(R.id.status_favourite); moreButton = itemView.findViewById(R.id.status_more); reblogged = false; @@ -104,10 +107,12 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { mediaLabel = itemView.findViewById(R.id.status_media_label); contentWarningDescription = itemView.findViewById(R.id.status_content_warning_description); contentWarningButton = itemView.findViewById(R.id.status_content_warning_button); + avatarInset = itemView.findViewById(R.id.status_avatar_inset); this.useAbsoluteTime = useAbsoluteTime; shortSdf = new SimpleDateFormat("HH:mm:ss", Locale.getDefault()); longSdf = new SimpleDateFormat("MM/dd HH:mm:ss", Locale.getDefault()); + showBotOverlay = PreferenceManager.getDefaultSharedPreferences(itemView.getContext()).getBoolean("showBotOverlay", true); } protected abstract int getMediaPreviewHeight(Context context); @@ -173,7 +178,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { } } - protected void setAvatar(String url, @Nullable String rebloggedUrl) { + protected void setAvatar(String url, @Nullable String rebloggedUrl, boolean isBot) { if (TextUtils.isEmpty(url)) { avatar.setImageResource(R.drawable.avatar_default); } else { @@ -182,6 +187,14 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { .placeholder(R.drawable.avatar_default) .into(avatar); } + + if (showBotOverlay && isBot && TextUtils.isEmpty(rebloggedUrl)) { + avatarInset.setVisibility(View.VISIBLE); + avatarInset.setImageResource(R.drawable.ic_bot_24dp); + avatarInset.setBackgroundColor(0x50ffffff); + } else { + avatarInset.setVisibility(View.GONE); + } } protected void setCreatedAt(@Nullable Date createdAt) { @@ -555,7 +568,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { setUsername(status.getNickname()); setCreatedAt(status.getCreatedAt()); setIsReply(status.getInReplyToId() != null); - setAvatar(status.getAvatar(), status.getRebloggedAvatar()); + setAvatar(status.getAvatar(), status.getRebloggedAvatar(), status.isBot()); setReblogged(status.isReblogged()); setFavourited(status.isFavourited()); List attachments = status.getAttachments(); diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusViewHolder.java index f13a359fe..72742057f 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusViewHolder.java +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusViewHolder.java @@ -17,6 +17,7 @@ package com.keylesspalace.tusky.adapter; import android.content.Context; import android.text.InputFilter; +import android.text.TextUtils; import android.view.View; import android.widget.ImageView; import android.widget.TextView; @@ -36,35 +37,28 @@ public class StatusViewHolder extends StatusBaseViewHolder { private static final InputFilter[] COLLAPSE_INPUT_FILTER = new InputFilter[]{SmartLengthInputFilter.INSTANCE}; private static final InputFilter[] NO_INPUT_FILTER = new InputFilter[0]; - private ImageView avatarReblog; private TextView rebloggedBar; private ToggleButton contentCollapseButton; StatusViewHolder(View itemView, boolean useAbsoluteTime) { super(itemView, useAbsoluteTime); - avatarReblog = itemView.findViewById(R.id.status_avatar_reblog); rebloggedBar = itemView.findViewById(R.id.status_reblogged); contentCollapseButton = itemView.findViewById(R.id.button_toggle_content); } @Override - protected void setAvatar(String url, @Nullable String rebloggedUrl) { - super.setAvatar(url, rebloggedUrl); - + protected void setAvatar(String url, @Nullable String rebloggedUrl, boolean isBot) { + super.setAvatar(url, rebloggedUrl, isBot); Context context = avatar.getContext(); - boolean hasReblog = rebloggedUrl != null && !rebloggedUrl.isEmpty(); - int padding = hasReblog ? Utils.dpToPx(context, 12) : 0; - avatar.setPaddingRelative(0, 0, padding, padding); - - if (hasReblog) { - avatarReblog.setVisibility(View.VISIBLE); + if (!TextUtils.isEmpty(rebloggedUrl)) { + int padding = Utils.dpToPx(context, 12); + avatar.setPaddingRelative(0, 0, padding, padding); + avatarInset.setVisibility(View.VISIBLE); Picasso.with(context) .load(rebloggedUrl) .placeholder(R.drawable.avatar_default) - .into(avatarReblog); - } else { - avatarReblog.setVisibility(View.GONE); + .into(avatarInset); } } diff --git a/app/src/main/java/com/keylesspalace/tusky/util/ViewDataUtils.java b/app/src/main/java/com/keylesspalace/tusky/util/ViewDataUtils.java index 36ee6344c..6c616885b 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/ViewDataUtils.java +++ b/app/src/main/java/com/keylesspalace/tusky/util/ViewDataUtils.java @@ -63,6 +63,8 @@ public final class ViewDataUtils { SmartLengthInputFilter.LENGTH_DEFAULT )) .setCollapsed(true) + .setIsBot(visibleStatus.getAccount().getBot()) + .createStatusViewData(); } diff --git a/app/src/main/java/com/keylesspalace/tusky/viewdata/StatusViewData.java b/app/src/main/java/com/keylesspalace/tusky/viewdata/StatusViewData.java index abe994953..904eacb93 100644 --- a/app/src/main/java/com/keylesspalace/tusky/viewdata/StatusViewData.java +++ b/app/src/main/java/com/keylesspalace/tusky/viewdata/StatusViewData.java @@ -87,6 +87,7 @@ public abstract class StatusViewData { private final Card card; private final boolean isCollapsible; /** Whether the status meets the requirement to be collapse */ final boolean isCollapsed; /** Whether the status is shown partially or fully */ + private final boolean isBot; public Concrete(String id, Spanned content, boolean reblogged, boolean favourited, @Nullable String spoilerText, Status.Visibility visibility, List attachments, @@ -95,7 +96,7 @@ public abstract class StatusViewData { Date createdAt, int reblogsCount, int favouritesCount, @Nullable String inReplyToId, @Nullable Status.Mention[] mentions, String senderId, boolean rebloggingEnabled, Status.Application application, List statusEmojis, List accountEmojis, @Nullable Card card, - boolean isCollapsible, boolean isCollapsed) { + boolean isCollapsible, boolean isCollapsed, boolean isBot) { this.id = id; if (Build.VERSION.SDK_INT == 23) { // https://github.com/tuskyapp/Tusky/issues/563 @@ -131,6 +132,7 @@ public abstract class StatusViewData { this.card = card; this.isCollapsible = isCollapsible; this.isCollapsed = isCollapsed; + this.isBot = isBot; } public String getId() { @@ -179,6 +181,8 @@ public abstract class StatusViewData { return isShowingContent; } + public boolean isBot(){ return isBot; } + @Nullable public String getRebloggedAvatar() { return rebloggedAvatar; @@ -277,6 +281,7 @@ public abstract class StatusViewData { isSensitive == concrete.isSensitive && isExpanded == concrete.isExpanded && isShowingContent == concrete.isShowingContent && + isBot == concrete.isBot && reblogsCount == concrete.reblogsCount && favouritesCount == concrete.favouritesCount && rebloggingEnabled == concrete.rebloggingEnabled && @@ -402,6 +407,7 @@ public abstract class StatusViewData { private Card card; private boolean isCollapsible; /** Whether the status meets the requirement to be collapsed */ private boolean isCollapsed; /** Whether the status is shown partially or fully */ + private boolean isBot; public Builder() { } @@ -435,6 +441,7 @@ public abstract class StatusViewData { card = viewData.getCard(); isCollapsible = viewData.isCollapsible(); isCollapsed = viewData.isCollapsed(); + isBot = viewData.isBot(); } public Builder setId(String id) { @@ -497,6 +504,11 @@ public abstract class StatusViewData { return this; } + public Builder setIsBot(boolean isBot) { + this.isBot = isBot; + return this; + } + public Builder setUserFullName(String userFullName) { this.userFullName = userFullName; return this; @@ -600,7 +612,7 @@ public abstract class StatusViewData { attachments, rebloggedByUsername, rebloggedAvatar, isSensitive, isExpanded, isShowingContent, userFullName, nickname, avatar, createdAt, reblogsCount, favouritesCount, inReplyToId, mentions, senderId, rebloggingEnabled, application, - statusEmojis, accountEmojis, card, isCollapsible, isCollapsed); + statusEmojis, accountEmojis, card, isCollapsible, isCollapsed, isBot); } } } diff --git a/app/src/main/res/drawable/ic_bot_24dp.xml b/app/src/main/res/drawable/ic_bot_24dp.xml new file mode 100644 index 000000000..abb3efb44 --- /dev/null +++ b/app/src/main/res/drawable/ic_bot_24dp.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_account.xml b/app/src/main/res/layout/item_account.xml index 489328a0d..e19ebab31 100644 --- a/app/src/main/res/layout/item_account.xml +++ b/app/src/main/res/layout/item_account.xml @@ -1,6 +1,7 @@ - + android:foregroundGravity="center_vertical" + android:layout_marginEnd="24dp" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toTopOf="parent"/> + + + - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/item_conversation.xml b/app/src/main/res/layout/item_conversation.xml index f009e0acd..3e81f53c3 100644 --- a/app/src/main/res/layout/item_conversation.xml +++ b/app/src/main/res/layout/item_conversation.xml @@ -69,7 +69,7 @@ tools:src="@drawable/avatar_default" /> + + Compose Toot Compose + Show indicator for bots diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index a055b25d5..265725a75 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -46,6 +46,11 @@ android:key="absoluteTimeView" android:title="@string/pref_title_absolute_time" /> + +