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 619e6bd1..4a7dce80 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/NotificationsAdapter.java +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/NotificationsAdapter.java @@ -24,15 +24,20 @@ import android.support.v4.content.ContextCompat; import android.support.v7.widget.RecyclerView; import android.text.SpannableStringBuilder; import android.text.Spanned; +import android.text.TextUtils; import android.text.style.StyleSpan; +import android.text.style.URLSpan; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.CompoundButton; import android.widget.ImageView; import android.widget.TextView; +import android.widget.ToggleButton; import com.keylesspalace.tusky.R; import com.keylesspalace.tusky.entity.Notification; +import com.keylesspalace.tusky.entity.Status; import com.keylesspalace.tusky.interfaces.StatusActionListener; import com.keylesspalace.tusky.view.RoundedTransformation; import com.keylesspalace.tusky.viewdata.NotificationViewData; @@ -123,9 +128,11 @@ public class NotificationsAdapter extends RecyclerView.Adapter { StatusNotificationViewHolder holder = (StatusNotificationViewHolder) viewHolder; holder.setMessage(type, concreteNotificaton.getAccount().getDisplayName(), concreteNotificaton.getStatusViewData()); - holder.setupButtons(notificationActionListener, concreteNotificaton.getAccount().id); + holder.setupButtons(notificationActionListener, + concreteNotificaton.getAccount().id, + concreteNotificaton.getId()); holder.setAvatars(concreteNotificaton.getStatusViewData().getAvatar(), - concreteNotificaton.getAccount().avatar); + concreteNotificaton.getId()); break; } case FOLLOW: { @@ -211,6 +218,8 @@ public class NotificationsAdapter extends RecyclerView.Adapter { public interface NotificationActionListener { void onViewAccount(String id); + + void onViewStatusForNotificationId(String notificationId); } private static class FollowViewHolder extends RecyclerView.ViewHolder { @@ -258,13 +267,23 @@ public class NotificationsAdapter extends RecyclerView.Adapter { } } - private static class StatusNotificationViewHolder extends RecyclerView.ViewHolder { - private TextView message; - private ImageView icon; - private TextView statusContent; - private ViewGroup container; - private ImageView statusAvatar; - private ImageView notificationAvatar; + private static class StatusNotificationViewHolder extends RecyclerView.ViewHolder + implements View.OnClickListener, ToggleButton.OnCheckedChangeListener { + private final TextView message; + private final ImageView icon; + private final TextView statusContent; + private final ViewGroup container; + private final ImageView statusAvatar; + private final ImageView notificationAvatar; + private final ViewGroup topBar; + private final View contentWarningBar; + private final TextView contentWarningDescriptionTextView; + private final ToggleButton contentWarningButton; + + private String accountId; + private String notificationId; + private NotificationActionListener listener; + private StatusViewData.Concrete statusViewData; StatusNotificationViewHolder(View itemView) { super(itemView); @@ -274,13 +293,24 @@ public class NotificationsAdapter extends RecyclerView.Adapter { container = itemView.findViewById(R.id.notification_container); statusAvatar = itemView.findViewById(R.id.notification_status_avatar); notificationAvatar = itemView.findViewById(R.id.notification_notification_avatar); + topBar = itemView.findViewById(R.id.notification_top_bar); + contentWarningBar = itemView.findViewById(R.id.notification_content_warning_bar); + contentWarningDescriptionTextView = itemView.findViewById(R.id.notification_content_warning_description); + contentWarningButton = itemView.findViewById(R.id.notification_content_warning_button); + int darkerFilter = Color.rgb(123, 123, 123); statusAvatar.setColorFilter(darkerFilter, PorterDuff.Mode.MULTIPLY); notificationAvatar.setColorFilter(darkerFilter, PorterDuff.Mode.MULTIPLY); + + container.setOnClickListener(this); + topBar.setOnClickListener(this); + contentWarningButton.setOnCheckedChangeListener(this); } void setMessage(Notification.Type type, String displayName, StatusViewData.Concrete status) { + this.statusViewData = status; + Context context = message.getContext(); String format; switch (type) { @@ -305,16 +335,17 @@ public class NotificationsAdapter extends RecyclerView.Adapter { str.setSpan(new StyleSpan(Typeface.BOLD), 0, displayName.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); message.setText(str); - statusContent.setText(status.getContent()); + + boolean hasSpoiler = !TextUtils.isEmpty(statusViewData.getSpoilerText()); + contentWarningBar.setVisibility(hasSpoiler ? View.VISIBLE : View.GONE); + setupContentAndSpoiler(false); } - void setupButtons(final NotificationActionListener listener, final String accountId) { - container.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - listener.onViewAccount(accountId); - } - }); + void setupButtons(final NotificationActionListener listener, final String accountId, + final String notificationId) { + this.listener = listener; + this.accountId = accountId; + this.notificationId = notificationId; } void setAvatars(@Nullable String statusAvatarUrl, @Nullable String notificationAvatarUrl) { @@ -341,5 +372,51 @@ public class NotificationsAdapter extends RecyclerView.Adapter { .into(notificationAvatar); } } + + @Override + public void onClick(View v) { + switch (v.getId()) { + case R.id.notification_container: + if (listener != null) listener.onViewStatusForNotificationId(notificationId); + break; + case R.id.notification_top_bar: + if (listener != null) listener.onViewAccount(accountId); + break; + } + } + + private void setupContentAndSpoiler(boolean shouldShowContentIfSpoiler) { + boolean hasSpoiler = !TextUtils.isEmpty(statusViewData.getSpoilerText()); + CharSequence content; + if (!shouldShowContentIfSpoiler && hasSpoiler) { + if (statusViewData.getMentions() != null && + statusViewData.getMentions().length > 0) { + // If there is a content warning and mentions we're alternating between + // showing mentions and showing full content. As mentions are plain text we + // have to construct URLSpans ourselves. + SpannableStringBuilder contentBuilder = new SpannableStringBuilder(); + for (Status.Mention mention : statusViewData.getMentions()) { + int start = contentBuilder.length() > 0 ? contentBuilder.length() - 1 : 0; + contentBuilder.append('@'); + contentBuilder.append(mention.username); + contentBuilder.append(' '); + contentBuilder.setSpan(new URLSpan(mention.url), start, + mention.username.length() + 1, 0); + } + content = contentBuilder; + } else { + content = null; + } + } else { + content = statusViewData.getContent(); + } + statusContent.setText(content); + contentWarningDescriptionTextView.setText(statusViewData.getSpoilerText()); + } + + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + setupContentAndSpoiler(isChecked); + } } } diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java index 583ee0ac..fe535fbe 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java @@ -394,6 +394,18 @@ public class NotificationsFragment extends SFragment implements super.viewAccount(id); } + @Override + public void onViewStatusForNotificationId(String notificationId) { + for (Either either : notifications) { + Notification notification = either.getAsRightOrNull(); + if (notification != null && notification.id.equals(notificationId)) { + super.viewThread(notification.status); + return; + } + } + Log.w(TAG, "Didn't find a notification for ID: " + notificationId); + } + @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { switch (key) { diff --git a/app/src/main/res/layout/item_status_notification.xml b/app/src/main/res/layout/item_status_notification.xml index dd7dd707..f8e12c02 100644 --- a/app/src/main/res/layout/item_status_notification.xml +++ b/app/src/main/res/layout/item_status_notification.xml @@ -40,11 +40,50 @@ + + + + + + + +