diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/MutedStatusViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/adapter/MutedStatusViewHolder.java index 94e3efd0..ea42f73d 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/MutedStatusViewHolder.java +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/MutedStatusViewHolder.java @@ -74,7 +74,7 @@ public class MutedStatusViewHolder extends RecyclerView.ViewHolder { displayName = itemView.findViewById(R.id.status_display_name); username = itemView.findViewById(R.id.status_username); timestampInfo = itemView.findViewById(R.id.status_timestamp_info); - unmuteButton = itemView.findViewById(R.id.status_unmute); + unmuteButton = itemView.findViewById(R.id.status_toggle_mute); this.shortSdf = new SimpleDateFormat("HH:mm:ss", Locale.getDefault()); this.longSdf = new SimpleDateFormat("MM/dd HH:mm:ss", Locale.getDefault()); 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 56cef6ee..96bb7302 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusViewHolder.java +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusViewHolder.java @@ -21,6 +21,7 @@ import android.text.TextUtils; import android.view.View; import android.widget.Button; import android.widget.TextView; +import android.widget.ImageButton; import androidx.annotation.Nullable; import androidx.recyclerview.widget.RecyclerView; @@ -39,11 +40,13 @@ public class StatusViewHolder extends StatusBaseViewHolder { private TextView statusInfo; private Button contentCollapseButton; + private ImageButton toggleVisibility; public StatusViewHolder(View itemView) { super(itemView); statusInfo = itemView.findViewById(R.id.status_info); contentCollapseButton = itemView.findViewById(R.id.button_toggle_content); + toggleVisibility = itemView.findViewById(R.id.status_toggle_mute); } @Override @@ -67,6 +70,13 @@ public class StatusViewHolder extends StatusBaseViewHolder { setRebloggedByDisplayName(rebloggedByDisplayName); statusInfo.setOnClickListener(v -> listener.onOpenReblog(getAdapterPosition())); } + + if(status.isThreadMutedOnBackend()) { + toggleVisibility.setVisibility(View.VISIBLE); + toggleVisibility.setOnClickListener(v -> listener.onMute(getAdapterPosition(), true)); + } else { + toggleVisibility.setVisibility(View.GONE); + } } super.setupWithStatus(status, listener, statusDisplayOptions, payloads); diff --git a/app/src/main/java/com/keylesspalace/tusky/entity/Status.kt b/app/src/main/java/com/keylesspalace/tusky/entity/Status.kt index b165bc8c..4f6f22c8 100644 --- a/app/src/main/java/com/keylesspalace/tusky/entity/Status.kt +++ b/app/src/main/java/com/keylesspalace/tusky/entity/Status.kt @@ -138,6 +138,10 @@ data class Status( if(pleroma?.threadMuted != null) pleroma.threadMuted = mute } + + fun getConversationId(): Int { + return pleroma?.conversationId ?: -1 + } private fun getEditableText(): String { val builder = SpannableStringBuilder(content) @@ -168,7 +172,8 @@ data class Status( } data class PleromaStatus( - @SerializedName("thread_muted") var threadMuted: Boolean? + @SerializedName("thread_muted") var threadMuted: Boolean?, + @SerializedName("conversation_id") val conversationId: Int? ) data class Mention ( 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 482bd698..fc6645c1 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/NotificationsFragment.java @@ -329,9 +329,15 @@ public class NotificationsFragment extends SFragment implements Pair posAndNotification = findReplyPosition(event.getStatusId()); if (posAndNotification == null) return; //noinspection ConstantConditions - setMutedStatusForStatus(posAndNotification.first, - posAndNotification.second.getStatus(), - event.getMute()); + // using iterator to safely remove items while iterating + for (int i = 0; i < notifications.size(); i++) { + Notification notification = notifications.get(i).asRightOrNull(); + if (notification != null && notification.getStatus() != null + && notification.getType() == Notification.Type.MENTION) { + setMutedStatusForStatus(i, notification.getStatus(), event.getMute()); + } + } + updateAdapter(); } @Override @@ -621,13 +627,13 @@ public class NotificationsFragment extends SFragment implements StatusViewData.Builder viewDataBuilder = new StatusViewData.Builder(viewdata.getStatusViewData()); viewDataBuilder.setThreadMuted(muted); + viewDataBuilder.setThreadMutedOnBackend(muted); NotificationViewData.Concrete newViewData = new NotificationViewData.Concrete( viewdata.getType(), viewdata.getId(), viewdata.getAccount(), viewDataBuilder.createStatusViewData(), viewdata.isExpanded()); notifications.setPairedItem(position, newViewData); - updateAdapter(); } 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 28e553a0..9ace77f9 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/ViewDataUtils.java +++ b/app/src/main/java/com/keylesspalace/tusky/util/ViewDataUtils.java @@ -67,6 +67,8 @@ public final class ViewDataUtils { .setIsBot(visibleStatus.getAccount().getBot()) .setUserMuted(visibleStatus.isUserMuted()) .setThreadMuted(visibleStatus.isThreadMuted()) + .setThreadMutedOnBackend(visibleStatus.isThreadMuted()) + .setConversationId(visibleStatus.getConversationId()) .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 014c5d8d..c27305d0 100644 --- a/app/src/main/java/com/keylesspalace/tusky/viewdata/StatusViewData.java +++ b/app/src/main/java/com/keylesspalace/tusky/viewdata/StatusViewData.java @@ -91,8 +91,10 @@ public abstract class StatusViewData { @Nullable private final PollViewData poll; private final boolean isBot; - private final boolean isThreadMuted; + private final boolean isThreadMuted; /* toggle for showing thread */ private final boolean isUserMuted; + private final boolean isThreadMutedOnBackend; /* thread_muted state got from backend */ + private final int conversationId; public Concrete(String id, Spanned content, boolean reblogged, boolean favourited, boolean bookmarked, @Nullable String spoilerText, Status.Visibility visibility, List attachments, @@ -102,7 +104,7 @@ public abstract class StatusViewData { @Nullable Status.Mention[] mentions, String senderId, boolean rebloggingEnabled, Status.Application application, List statusEmojis, List accountEmojis, @Nullable Card card, boolean isCollapsible, boolean isCollapsed, @Nullable PollViewData poll, boolean isBot, boolean isThreadMuted, - boolean isUserMuted) { + boolean isUserMuted, boolean isThreadMutedOnBackend, int conversationId) { this.id = id; if (Build.VERSION.SDK_INT == 23) { @@ -143,7 +145,9 @@ public abstract class StatusViewData { this.poll = poll; this.isBot = isBot; this.isThreadMuted = isThreadMuted; + this.isThreadMutedOnBackend = isThreadMutedOnBackend; this.isUserMuted = isUserMuted; + this.conversationId = conversationId; } public String getId() { @@ -296,6 +300,10 @@ public abstract class StatusViewData { return isThreadMuted; } + public boolean isThreadMutedOnBackend() { + return isThreadMutedOnBackend; + } + public boolean isUserMuted() { return isUserMuted; } @@ -335,7 +343,9 @@ public abstract class StatusViewData { Objects.equals(poll, concrete.poll) && isCollapsed == concrete.isCollapsed && isThreadMuted == concrete.isThreadMuted && - isUserMuted == concrete.isUserMuted; + isUserMuted == concrete.isUserMuted && + isThreadMutedOnBackend == concrete.isThreadMutedOnBackend && + conversationId == concrete.conversationId; } static Spanned replaceCrashingCharacters(Spanned content) { @@ -443,7 +453,9 @@ public abstract class StatusViewData { private PollViewData poll; private boolean isBot; private boolean isThreadMuted; + private boolean isThreadMutedOnBackend; private boolean isUserMuted; + private int conversationId; public Builder() { } @@ -482,6 +494,7 @@ public abstract class StatusViewData { isBot = viewData.isBot(); isThreadMuted = viewData.isThreadMuted; isUserMuted = viewData.isUserMuted; + isThreadMutedOnBackend = viewData.isThreadMutedOnBackend; } public Builder setId(String id) { @@ -662,6 +675,16 @@ public abstract class StatusViewData { this.isThreadMuted = isThreadMuted; return this; } + + public Builder setThreadMutedOnBackend(Boolean isThreadMutedOnBackend) { + this.isThreadMutedOnBackend = isThreadMutedOnBackend; + return this; + } + + public Builder setConversationId(int conversationId) { + this.conversationId = conversationId; + return this; + } public StatusViewData.Concrete createStatusViewData() { if (this.statusEmojis == null) statusEmojis = Collections.emptyList(); @@ -672,7 +695,8 @@ public abstract class StatusViewData { visibility, attachments, rebloggedByUsername, rebloggedAvatar, isSensitive, isExpanded, isShowingContent, userFullName, nickname, avatar, createdAt, reblogsCount, favouritesCount, inReplyToId, mentions, senderId, rebloggingEnabled, application, - statusEmojis, accountEmojis, card, isCollapsible, isCollapsed, poll, isBot, isThreadMuted, isUserMuted); + statusEmojis, accountEmojis, card, isCollapsible, isCollapsed, poll, isBot, isThreadMuted, + isUserMuted, isThreadMutedOnBackend, conversationId); } } } diff --git a/app/src/main/res/layout/item_status.xml b/app/src/main/res/layout/item_status.xml index d2505666..1c0da303 100644 --- a/app/src/main/res/layout/item_status.xml +++ b/app/src/main/res/layout/item_status.xml @@ -69,7 +69,7 @@ android:textSize="?attr/status_text_medium" android:textStyle="normal|bold" app:layout_constrainedWidth="true" - app:layout_constraintEnd_toStartOf="@id/status_timestamp_info" + app:layout_constraintEnd_toStartOf="@id/status_toggle_mute" app:layout_constraintHorizontal_bias="0" app:layout_constraintStart_toEndOf="@id/status_avatar" app:layout_constraintTop_toBottomOf="@id/status_info" @@ -84,11 +84,25 @@ android:maxLines="1" android:textColor="?android:textColorSecondary" android:textSize="?attr/status_text_medium" - app:layout_constraintEnd_toStartOf="@id/status_timestamp_info" + app:layout_constraintEnd_toStartOf="@id/status_toggle_mute" app:layout_constraintStart_toEndOf="@id/status_display_name" - app:layout_constraintBaseline_toBaselineOf="@id/status_display_name" + app:layout_constraintBaseline_toBaselineOf="@id/status_display_name" tools:text="\@Entenhausen@birbsarecooooooooooool.site" /> + + + app:srcCompat="@drawable/ic_eye_24dp" />