From ed60cc3a78eac55a3bf47842e9be58c4401cfdee Mon Sep 17 00:00:00 2001 From: Conny Duck Date: Thu, 1 Mar 2018 21:10:10 +0100 Subject: [PATCH] gracefully handle null statuses in notifications --- .../tusky/adapter/NotificationsAdapter.java | 39 +++++++++++++++---- .../tusky/adapter/StatusBaseViewHolder.java | 11 ++++++ .../tusky/adapter/StatusViewHolder.java | 27 +++++++------ .../res/layout/item_status_notification.xml | 4 +- 4 files changed, 60 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/NotificationsAdapter.java b/app/src/main/java/com/keylesspalace/tusky/adapter/NotificationsAdapter.java index 947b7cc82..42c9e1859 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/NotificationsAdapter.java +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/NotificationsAdapter.java @@ -132,16 +132,25 @@ public class NotificationsAdapter extends RecyclerView.Adapter { case REBLOG: { StatusNotificationViewHolder holder = (StatusNotificationViewHolder) viewHolder; StatusViewData.Concrete statusViewData = concreteNotificaton.getStatusViewData(); - holder.setDisplayName(statusViewData.getUserFullName()); - holder.setUsername(statusViewData.getNickname()); - holder.setCreatedAt(statusViewData.getCreatedAt()); + + if(statusViewData == null) { + holder.showNotificationContent(false); + } else { + holder.showNotificationContent(true); + + holder.setDisplayName(statusViewData.getUserFullName()); + holder.setUsername(statusViewData.getNickname()); + holder.setCreatedAt(statusViewData.getCreatedAt()); + + holder.setAvatars(concreteNotificaton.getStatusViewData().getAvatar(), + concreteNotificaton.getAccount().avatar); + } holder.setMessage(concreteNotificaton, statusListener); holder.setupButtons(notificationActionListener, concreteNotificaton.getAccount().id, concreteNotificaton.getId()); - holder.setAvatars(concreteNotificaton.getStatusViewData().getAvatar(), - concreteNotificaton.getAccount().avatar); + break; } case FOLLOW: { @@ -284,6 +293,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter { private static class StatusNotificationViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, ToggleButton.OnCheckedChangeListener { private final TextView message; + private final View statusNameBar; private final TextView displayName; private final TextView username; private final TextView timestampInfo; @@ -303,6 +313,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter { StatusNotificationViewHolder(View itemView) { super(itemView); message = itemView.findViewById(R.id.notification_top_text); + statusNameBar = itemView.findViewById(R.id.status_name_bar); displayName = itemView.findViewById(R.id.status_display_name); username = itemView.findViewById(R.id.status_username); timestampInfo = itemView.findViewById(R.id.status_timestamp_info); @@ -324,6 +335,15 @@ public class NotificationsAdapter extends RecyclerView.Adapter { contentWarningButton.setOnCheckedChangeListener(this); } + private void showNotificationContent(boolean show) { + statusNameBar.setVisibility(show ? View.VISIBLE : View.GONE); + contentWarningBar.setVisibility(show ? View.VISIBLE : View.GONE); + statusContent.setVisibility(show ? View.VISIBLE : View.GONE); + statusAvatar.setVisibility(show ? View.VISIBLE : View.GONE); + notificationAvatar.setVisibility(show ? View.VISIBLE : View.GONE); + + } + private void setDisplayName(String name) { displayName.setText(name); } @@ -396,9 +416,12 @@ public class NotificationsAdapter extends RecyclerView.Adapter { Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); message.setText(str); - boolean hasSpoiler = !TextUtils.isEmpty(statusViewData.getSpoilerText()); - contentWarningBar.setVisibility(hasSpoiler ? View.VISIBLE : View.GONE); - setupContentAndSpoiler(notificationViewData, listener); + if (statusViewData != null) { + boolean hasSpoiler = !TextUtils.isEmpty(statusViewData.getSpoilerText()); + contentWarningBar.setVisibility(hasSpoiler ? View.VISIBLE : View.GONE); + setupContentAndSpoiler(notificationViewData, listener); + } + } void setupButtons(final NotificationActionListener listener, final String accountId, 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 e45f5cbd9..2c2ccc76d 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java @@ -10,6 +10,7 @@ import android.support.v7.widget.RecyclerView; import android.text.Spanned; import android.text.TextUtils; import android.view.View; +import android.view.ViewGroup; import android.widget.CompoundButton; import android.widget.ImageButton; import android.widget.ImageView; @@ -27,6 +28,7 @@ import com.keylesspalace.tusky.util.LinkHelper; import com.keylesspalace.tusky.util.ThemeUtils; import com.keylesspalace.tusky.view.RoundedTransformation; import com.keylesspalace.tusky.viewdata.StatusViewData; +import com.mikepenz.iconics.utils.Utils; import com.squareup.picasso.Picasso; import com.varunest.sparkbutton.SparkButton; import com.varunest.sparkbutton.SparkEventListener; @@ -147,6 +149,15 @@ abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { timestampInfo.setContentDescription(readoutAloud); } + protected void showContent(boolean show) { + if(show) { + container.setVisibility(View.VISIBLE); + container.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT; + } else { + container.setVisibility(View.INVISIBLE); + container.getLayoutParams().height = Utils.convertDpToPx(container.getContext(), 24); + } + } private void setIsReply(boolean isReply) { if(isReply) { 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 4696e3abe..a0263984e 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusViewHolder.java +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusViewHolder.java @@ -78,19 +78,24 @@ public class StatusViewHolder extends StatusBaseViewHolder { @Override void setupWithStatus(StatusViewData.Concrete status, final StatusActionListener listener, boolean mediaPreviewEnabled) { - super.setupWithStatus(status, listener, mediaPreviewEnabled); - - String rebloggedByDisplayName = status.getRebloggedByUsername(); - if (rebloggedByDisplayName == null) { - hideRebloggedByDisplayName(); + if(status == null) { + showContent(false); } else { - setRebloggedByDisplayName(rebloggedByDisplayName); - } + showContent(true); + super.setupWithStatus(status, listener, mediaPreviewEnabled); - // I think it's not efficient to create new object every time we bind a holder. - // More efficient approach would be creating View.OnClickListener during holder creation - // and storing StatusActionListener in a variable after binding. - rebloggedBar.setOnClickListener(v -> listener.onOpenReblog(getAdapterPosition())); + String rebloggedByDisplayName = status.getRebloggedByUsername(); + if (rebloggedByDisplayName == null) { + hideRebloggedByDisplayName(); + } else { + setRebloggedByDisplayName(rebloggedByDisplayName); + } + + // I think it's not efficient to create new object every time we bind a holder. + // More efficient approach would be creating View.OnClickListener during holder creation + // and storing StatusActionListener in a variable after binding. + rebloggedBar.setOnClickListener(v -> listener.onOpenReblog(getAdapterPosition())); + } } private void setRebloggedByDisplayName(String name) { diff --git a/app/src/main/res/layout/item_status_notification.xml b/app/src/main/res/layout/item_status_notification.xml index 96d9c30d8..4dfad6490 100644 --- a/app/src/main/res/layout/item_status_notification.xml +++ b/app/src/main/res/layout/item_status_notification.xml @@ -14,6 +14,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" + android:layout_marginBottom="6dp" android:layout_marginTop="8dp" android:drawablePadding="10dp" android:ellipsize="end" @@ -30,8 +31,7 @@ android:layout_height="wrap_content" android:layout_below="@+id/notification_top_text" android:layout_toEndOf="@+id/notification_status_avatar" - android:paddingBottom="4dp" - android:paddingTop="6dp"> + android:paddingBottom="4dp">