Fix loading toots with conversation_id as String
It happens at Gleasonator but it could happen to other instances. The ones which returns this value as an Integer should work perfectly. Fixes: https://todo.sr.ht/~captainepoch/husky/48
This commit is contained in:
parent
06b01e5a37
commit
0bd5182b9e
6 changed files with 203 additions and 150 deletions
|
@ -1,17 +1,22 @@
|
|||
/* Copyright 2017 Andrew Dawson
|
||||
/*
|
||||
* Husky -- A Pleroma client for Android
|
||||
*
|
||||
* This file is a part of Tusky.
|
||||
* Copyright (C) 2022 The Husky Developers
|
||||
* Copyright (C) 2017 Andrew Dawson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Tusky; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.keylesspalace.tusky.entity
|
||||
|
||||
|
@ -19,7 +24,7 @@ import android.text.SpannableStringBuilder
|
|||
import android.text.Spanned
|
||||
import android.text.style.URLSpan
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import java.util.*
|
||||
import java.util.Date
|
||||
|
||||
data class Status(
|
||||
var id: String,
|
||||
|
@ -58,17 +63,21 @@ data class Status(
|
|||
|
||||
enum class Visibility(val num: Int) {
|
||||
UNKNOWN(0),
|
||||
|
||||
@SerializedName("public")
|
||||
PUBLIC(1),
|
||||
|
||||
@SerializedName("unlisted")
|
||||
UNLISTED(2),
|
||||
|
||||
@SerializedName("private")
|
||||
PRIVATE(3),
|
||||
|
||||
@SerializedName("direct")
|
||||
DIRECT(4);
|
||||
|
||||
fun serverString(): String {
|
||||
return when (this) {
|
||||
return when(this) {
|
||||
PUBLIC -> "public"
|
||||
UNLISTED -> "unlisted"
|
||||
PRIVATE -> "private"
|
||||
|
@ -81,7 +90,7 @@ data class Status(
|
|||
|
||||
@JvmStatic
|
||||
fun byNum(num: Int): Visibility {
|
||||
return when (num) {
|
||||
return when(num) {
|
||||
4 -> DIRECT
|
||||
3 -> PRIVATE
|
||||
2 -> UNLISTED
|
||||
|
@ -93,7 +102,7 @@ data class Status(
|
|||
|
||||
@JvmStatic
|
||||
fun byString(s: String): Visibility {
|
||||
return when (s) {
|
||||
return when(s) {
|
||||
"public" -> PUBLIC
|
||||
"unlisted" -> UNLISTED
|
||||
"private" -> PRIVATE
|
||||
|
@ -143,8 +152,8 @@ data class Status(
|
|||
pleroma.threadMuted = mute
|
||||
}
|
||||
|
||||
fun getConversationId(): Int {
|
||||
return pleroma?.conversationId ?: -1
|
||||
fun getConversationId(): String {
|
||||
return pleroma?.conversationId ?: ""
|
||||
}
|
||||
|
||||
fun getEmojiReactions(): List<EmojiReaction>? {
|
||||
|
@ -161,10 +170,10 @@ data class Status(
|
|||
|
||||
private fun getEditableText(): String {
|
||||
val builder = SpannableStringBuilder(content)
|
||||
for (span in content.getSpans(0, content.length, URLSpan::class.java)) {
|
||||
for(span in content.getSpans(0, content.length, URLSpan::class.java)) {
|
||||
val url = span.url
|
||||
for ((_, url1, username) in mentions) {
|
||||
if (url == url1) {
|
||||
for((_, url1, username) in mentions) {
|
||||
if(url == url1) {
|
||||
val start = builder.getSpanStart(span)
|
||||
val end = builder.getSpanEnd(span)
|
||||
builder.replace(start, end, "@$username")
|
||||
|
@ -176,8 +185,8 @@ data class Status(
|
|||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other == null || javaClass != other.javaClass) return false
|
||||
if(this === other) return true
|
||||
if(other == null || javaClass != other.javaClass) return false
|
||||
|
||||
val status = other as Status?
|
||||
return id == status?.id
|
||||
|
@ -189,20 +198,20 @@ data class Status(
|
|||
|
||||
data class PleromaStatus(
|
||||
@SerializedName("thread_muted") var threadMuted: Boolean?,
|
||||
@SerializedName("conversation_id") val conversationId: Int?,
|
||||
@SerializedName("conversation_id") val conversationId: String?,
|
||||
@SerializedName("emoji_reactions") val emojiReactions: List<EmojiReaction>?,
|
||||
@SerializedName("in_reply_to_account_acct") val inReplyToAccountAcct: String?,
|
||||
@SerializedName("parent_visible") val parentVisible: Boolean?
|
||||
)
|
||||
|
||||
data class Mention (
|
||||
data class Mention(
|
||||
val id: String,
|
||||
val url: String?, // can be null due to bug in some Pleroma versions
|
||||
@SerializedName("acct") val username: String,
|
||||
@SerializedName("username") val localUsername: String
|
||||
)
|
||||
|
||||
data class Application (
|
||||
data class Application(
|
||||
val name: String,
|
||||
val website: String?
|
||||
)
|
||||
|
|
|
@ -350,9 +350,9 @@ public class NotificationsFragment extends SFragment implements
|
|||
if (posAndNotification == null)
|
||||
return;
|
||||
|
||||
int conversationId = posAndNotification.second.getStatus().getConversationId();
|
||||
String conversationId = posAndNotification.second.getStatus().getConversationId();
|
||||
|
||||
if(conversationId == -1) { // invalid conversation ID
|
||||
if(conversationId.isEmpty()) { // invalid conversation ID
|
||||
if(withMuted) {
|
||||
setMutedStatusForStatus(posAndNotification.first, posAndNotification.second.getStatus(), event.getMute(), event.getMute());
|
||||
} else {
|
||||
|
@ -1016,7 +1016,7 @@ public class NotificationsFragment extends SFragment implements
|
|||
updateAdapter();
|
||||
}
|
||||
|
||||
private void removeAllByConversationId(int conversationId) {
|
||||
private void removeAllByConversationId(String conversationId) {
|
||||
// using iterator to safely remove items while iterating
|
||||
Iterator<Either<Placeholder, Notification>> iterator = notifications.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
|
@ -1024,7 +1024,7 @@ public class NotificationsFragment extends SFragment implements
|
|||
Notification notification = placeholderOrNotification.asRightOrNull();
|
||||
if (notification != null && notification.getStatus() != null
|
||||
&& notification.getType() == Notification.Type.MENTION &&
|
||||
notification.getStatus().getConversationId() == conversationId) {
|
||||
notification.getStatus().getConversationId().equalsIgnoreCase(conversationId)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,23 @@
|
|||
/* Copyright 2017 Andrew Dawson
|
||||
/*
|
||||
* Husky -- A Pleroma client for Android
|
||||
*
|
||||
* This file is a part of Tusky.
|
||||
* Copyright (C) 2022 The Husky Developers
|
||||
* Copyright (C) 2017 Andrew Dawson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Tusky; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
package com.keylesspalace.tusky.fragment;
|
||||
|
||||
|
@ -22,7 +28,6 @@ import android.content.Intent;
|
|||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
@ -108,13 +113,13 @@ import kotlin.jvm.functions.Function1;
|
|||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
import timber.log.Timber;
|
||||
|
||||
public class TimelineFragment extends SFragment implements
|
||||
SwipeRefreshLayout.OnRefreshListener,
|
||||
StatusActionListener,
|
||||
Injectable, ReselectableFragment, RefreshableFragment {
|
||||
|
||||
private static final String TAG = "TimelineF"; // logging tag
|
||||
private static final String KIND_ARG = "kind";
|
||||
private static final String ID_ARG = "id";
|
||||
private static final String HASHTAGS_ARG = "hastags";
|
||||
|
@ -475,7 +480,7 @@ public class TimelineFragment extends SFragment implements
|
|||
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
|
||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(requireContext());
|
||||
|
||||
/* This is delayed until onActivityCreated solely because MainActivity.composeButton isn't
|
||||
* guaranteed to be set until then. */
|
||||
|
@ -623,7 +628,7 @@ public class TimelineFragment extends SFragment implements
|
|||
.as(autoDisposable(from(this, Lifecycle.Event.ON_DESTROY)))
|
||||
.subscribe(
|
||||
(newStatus) -> setRebloggedForStatus(position, status, reblog),
|
||||
(err) -> Log.d(TAG, "Failed to reblog status " + status.getId(), err)
|
||||
(err) -> Timber.e("Failed to reblog status " + status.getId() + ", Error[" + err + "]")
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -655,7 +660,7 @@ public class TimelineFragment extends SFragment implements
|
|||
.as(autoDisposable(from(this, Lifecycle.Event.ON_DESTROY)))
|
||||
.subscribe(
|
||||
(newStatus) -> setFavouriteForStatus(position, newStatus, favourite),
|
||||
(err) -> Log.d(TAG, "Failed to favourite status " + status.getId(), err)
|
||||
(err) -> Timber.e("Failed to favourite status " + status.getId() + ", Error [" + err + "]")
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -687,7 +692,7 @@ public class TimelineFragment extends SFragment implements
|
|||
.as(autoDisposable(from(this, Lifecycle.Event.ON_DESTROY)))
|
||||
.subscribe(
|
||||
(newStatus) -> setBookmarkForStatus(position, newStatus, bookmark),
|
||||
(err) -> Log.d(TAG, "Failed to favourite status " + status.getId(), err)
|
||||
(err) -> Timber.e(err, "Failed to favourite status " + status.getId())
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -743,8 +748,8 @@ public class TimelineFragment extends SFragment implements
|
|||
.as(autoDisposable(from(this)))
|
||||
.subscribe(
|
||||
(newPoll) -> setVoteForPoll(position, status, newPoll),
|
||||
(t) -> Log.d(TAG,
|
||||
"Failed to vote in poll: " + status.getId(), t)
|
||||
(t) -> Timber.e(t,
|
||||
"Failed to vote in poll: " + status.getId())
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -815,7 +820,7 @@ public class TimelineFragment extends SFragment implements
|
|||
? statuses.get(position + 1).asRight().getId()
|
||||
: null;
|
||||
if(fromStatus == null || toStatus == null) {
|
||||
Log.e(TAG, "Failed to load more at " + position + ", wrong placeholder position");
|
||||
Timber.e("Failed to load more at " + position + ", wrong placeholder position");
|
||||
return;
|
||||
}
|
||||
sendFetchTimelineRequest(fromStatus.getId(), toStatus.getId(), maxMinusOne,
|
||||
|
@ -826,14 +831,14 @@ public class TimelineFragment extends SFragment implements
|
|||
statuses.setPairedItem(position, newViewData);
|
||||
updateAdapter();
|
||||
} else {
|
||||
Log.e(TAG, "error loading more");
|
||||
Timber.e("error loading more");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onContentCollapsedChange(boolean isCollapsed, int position) {
|
||||
if(position < 0 || position >= statuses.size()) {
|
||||
Log.e(TAG, String.format("Tried to access out of bounds status position: %d of %d", position, statuses.size() - 1));
|
||||
Timber.e(String.format("Tried to access out of bounds status position: %d of %d", position, statuses.size() - 1));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -841,7 +846,7 @@ public class TimelineFragment extends SFragment implements
|
|||
if(!(status instanceof StatusViewData.Concrete)) {
|
||||
// Statuses PairedList contains a base type of StatusViewData.Concrete and also doesn't
|
||||
// check for null values when adding values to it although this doesn't seem to be an issue.
|
||||
Log.e(TAG, String.format(
|
||||
Timber.e(String.format(
|
||||
"Expected StatusViewData.Concrete, got %s instead at position: %d of %d",
|
||||
status == null ? "<null>" : status.getClass().getSimpleName(),
|
||||
position,
|
||||
|
@ -960,13 +965,13 @@ public class TimelineFragment extends SFragment implements
|
|||
updateAdapter();
|
||||
}
|
||||
|
||||
private void removeAllByConversationId(int conversationId) {
|
||||
private void removeAllByConversationId(String conversationId) {
|
||||
// using iterator to safely remove items while iterating
|
||||
Iterator<Either<Placeholder, Status>> iterator = statuses.iterator();
|
||||
while(iterator.hasNext()) {
|
||||
Status status = iterator.next().asRightOrNull();
|
||||
if(status != null &&
|
||||
(status.getConversationId() == conversationId) || status.getActionableStatus().getConversationId() == conversationId) {
|
||||
(status.getConversationId().equalsIgnoreCase(conversationId)) || status.getActionableStatus().getConversationId().equalsIgnoreCase(conversationId)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
@ -1249,7 +1254,7 @@ public class TimelineFragment extends SFragment implements
|
|||
}
|
||||
}
|
||||
|
||||
Log.e(TAG, "Fetch Failure: " + exception.getMessage());
|
||||
Timber.e("Fetch Failure: %s", exception.getMessage());
|
||||
updateBottomLoadingState(fetchEnd);
|
||||
progressBar.setVisibility(View.GONE);
|
||||
}
|
||||
|
@ -1453,9 +1458,9 @@ public class TimelineFragment extends SFragment implements
|
|||
return;
|
||||
|
||||
Status eventStatus = statuses.get(pos).asRight();
|
||||
int conversationId = eventStatus.getConversationId();
|
||||
String conversationId = eventStatus.getConversationId();
|
||||
|
||||
if(conversationId == -1) { // invalid conversation ID
|
||||
if(conversationId.isEmpty()) { // invalid conversation ID
|
||||
if(isFilteringMuted()) {
|
||||
statuses.remove(pos);
|
||||
} else {
|
||||
|
@ -1650,13 +1655,12 @@ public class TimelineFragment extends SFragment implements
|
|||
.as(autoDisposable(from(this)))
|
||||
.subscribe(
|
||||
(newStatus) -> setEmojiReactionForStatus(position, newStatus),
|
||||
(t) -> Log.d(TAG,
|
||||
"Failed to react with " + emoji + " on status: " + statusId, t)
|
||||
(t) -> Timber.e(t,
|
||||
"Failed to react with " + emoji + " on status: " + statusId)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onEmojiReactMenu(@NonNull View view, final EmojiReaction emoji, final String statusId) {
|
||||
super.emojiReactMenu(statusId, emoji, view, this);
|
||||
|
|
|
@ -1,3 +1,23 @@
|
|||
/*
|
||||
* Husky -- A Pleroma client for Android
|
||||
*
|
||||
* Copyright (C) 2022 The Husky Developers
|
||||
* Copyright (C) 2018 Tusky Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.keylesspalace.tusky.repository
|
||||
|
||||
import android.text.SpannedString
|
||||
|
|
|
@ -53,6 +53,7 @@ object OkHttpUtils {
|
|||
|
||||
val builder = OkHttpClient.Builder()
|
||||
.addInterceptor(getUserAgentInterceptor())
|
||||
//.addInterceptor(getDebugInformation())
|
||||
.addInterceptor(BrotliInterceptor)
|
||||
.readTimeout(60, SECONDS)
|
||||
.writeTimeout(60, SECONDS)
|
||||
|
|
|
@ -1,33 +1,35 @@
|
|||
/* Copyright 2017 Andrew Dawson
|
||||
/*
|
||||
* Husky -- A Pleroma client for Android
|
||||
*
|
||||
* This file is a part of Tusky.
|
||||
* Copyright (C) 2022 The Husky Developers
|
||||
* Copyright (C) 2017 Andrew Dawson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Tusky; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.keylesspalace.tusky.viewdata;
|
||||
|
||||
import android.os.Build;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.Spanned;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.keylesspalace.tusky.entity.Attachment;
|
||||
import com.keylesspalace.tusky.entity.Card;
|
||||
import com.keylesspalace.tusky.entity.Emoji;
|
||||
import com.keylesspalace.tusky.entity.EmojiReaction;
|
||||
import com.keylesspalace.tusky.entity.Poll;
|
||||
import com.keylesspalace.tusky.entity.Status;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
@ -36,15 +38,14 @@ import java.util.List;
|
|||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Created by charlag on 11/07/2017.
|
||||
* <p>
|
||||
* Class to represent data required to display either a notification or a placeholder.
|
||||
* It is either a {@link StatusViewData.Concrete} or a {@link StatusViewData.Placeholder}.
|
||||
*/
|
||||
|
||||
public abstract class StatusViewData {
|
||||
|
||||
private StatusViewData() { }
|
||||
private StatusViewData() {
|
||||
}
|
||||
|
||||
public abstract long getViewDataId();
|
||||
|
||||
|
@ -91,15 +92,21 @@ public abstract class StatusViewData {
|
|||
private final List<Emoji> rebloggedByAccountEmojis;
|
||||
@Nullable
|
||||
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 isCollapsible;
|
||||
/**
|
||||
* Whether the status meets the requirement to be collapse
|
||||
*/
|
||||
final boolean isCollapsed;
|
||||
/**
|
||||
* Whether the status is shown partially or fully
|
||||
*/
|
||||
@Nullable
|
||||
private final PollViewData poll;
|
||||
private final boolean isBot;
|
||||
private final boolean isMuted; /* user toggle */
|
||||
private final boolean isThreadMuted; /* thread_muted state got from backend */
|
||||
private final boolean isUserMuted; /* muted state got from backend */
|
||||
private final int conversationId;
|
||||
private final String conversationId;
|
||||
@Nullable
|
||||
private final List<EmojiReaction> emojiReactions;
|
||||
private final boolean parentVisible;
|
||||
|
@ -112,10 +119,10 @@ public abstract class StatusViewData {
|
|||
@Nullable String inReplyToAccountAcct, @Nullable Status.Mention[] mentions, String senderId, boolean rebloggingEnabled,
|
||||
Status.Application application, List<Emoji> statusEmojis, List<Emoji> accountEmojis, List<Emoji> rebloggedByAccountEmojis, @Nullable Card card,
|
||||
boolean isCollapsible, boolean isCollapsed, @Nullable PollViewData poll, boolean isBot, boolean isMuted, boolean isThreadMuted,
|
||||
boolean isUserMuted, int conversationId, @Nullable List<EmojiReaction> emojiReactions, boolean parentVisible) {
|
||||
boolean isUserMuted, String conversationId, @Nullable List<EmojiReaction> emojiReactions, boolean parentVisible) {
|
||||
|
||||
this.id = id;
|
||||
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.M) {
|
||||
if(Build.VERSION.SDK_INT == Build.VERSION_CODES.M) {
|
||||
// https://github.com/tuskyapp/Tusky/issues/563
|
||||
this.content = replaceCrashingCharacters(content);
|
||||
this.spoilerText = spoilerText == null ? null : replaceCrashingCharacters(spoilerText).toString();
|
||||
|
@ -212,7 +219,9 @@ public abstract class StatusViewData {
|
|||
return isShowingContent;
|
||||
}
|
||||
|
||||
public boolean isBot(){ return isBot; }
|
||||
public boolean isBot() {
|
||||
return isBot;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getRebloggedAvatar() {
|
||||
|
@ -318,7 +327,8 @@ public abstract class StatusViewData {
|
|||
return poll;
|
||||
}
|
||||
|
||||
@Override public long getViewDataId() {
|
||||
@Override
|
||||
public long getViewDataId() {
|
||||
// Chance of collision is super low and impact of mistake is low as well
|
||||
return id.hashCode();
|
||||
}
|
||||
|
@ -341,8 +351,8 @@ public abstract class StatusViewData {
|
|||
}
|
||||
|
||||
public boolean deepEquals(StatusViewData o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if(this == o) return true;
|
||||
if(o == null || getClass() != o.getClass()) return false;
|
||||
Concrete concrete = (Concrete) o;
|
||||
return reblogged == concrete.reblogged &&
|
||||
favourited == concrete.favourited &&
|
||||
|
@ -393,17 +403,17 @@ public abstract class StatusViewData {
|
|||
SpannableStringBuilder builder = null;
|
||||
int length = content.length();
|
||||
|
||||
for (int index = 0; index < length; ++index) {
|
||||
for(int index = 0; index < length; ++index) {
|
||||
char character = content.charAt(index);
|
||||
|
||||
// If there are more than one or two, switch to a map
|
||||
if (character == SOFT_HYPHEN) {
|
||||
if (!replacing) {
|
||||
if(character == SOFT_HYPHEN) {
|
||||
if(!replacing) {
|
||||
replacing = true;
|
||||
builder = new SpannableStringBuilder(content, 0, index);
|
||||
}
|
||||
builder.append(ASCII_HYPHEN);
|
||||
} else if (replacing) {
|
||||
} else if(replacing) {
|
||||
builder.append(character);
|
||||
}
|
||||
}
|
||||
|
@ -429,19 +439,22 @@ public abstract class StatusViewData {
|
|||
return id;
|
||||
}
|
||||
|
||||
@Override public long getViewDataId() {
|
||||
@Override
|
||||
public long getViewDataId() {
|
||||
return id.hashCode();
|
||||
}
|
||||
|
||||
@Override public boolean deepEquals(StatusViewData other) {
|
||||
if (!(other instanceof Placeholder)) return false;
|
||||
@Override
|
||||
public boolean deepEquals(StatusViewData other) {
|
||||
if(!(other instanceof Placeholder)) return false;
|
||||
Placeholder that = (Placeholder) other;
|
||||
return isLoading == that.isLoading && id.equals(that.id);
|
||||
}
|
||||
|
||||
@Override public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if(this == o) return true;
|
||||
if(o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Placeholder that = (Placeholder) o;
|
||||
|
||||
|
@ -486,14 +499,20 @@ public abstract class StatusViewData {
|
|||
private List<Emoji> accountEmojis;
|
||||
private List<Emoji> rebloggedByAccountEmojis;
|
||||
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 isCollapsible;
|
||||
/**
|
||||
* Whether the status meets the requirement to be collapsed
|
||||
*/
|
||||
private boolean isCollapsed;
|
||||
/**
|
||||
* Whether the status is shown partially or fully
|
||||
*/
|
||||
private PollViewData poll;
|
||||
private boolean isBot;
|
||||
private boolean isMuted;
|
||||
private boolean isThreadMuted;
|
||||
private boolean isUserMuted;
|
||||
private int conversationId;
|
||||
private String conversationId;
|
||||
private List<EmojiReaction> emojiReactions;
|
||||
private boolean parentVisible;
|
||||
|
||||
|
@ -739,7 +758,7 @@ public abstract class StatusViewData {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder setConversationId(int conversationId) {
|
||||
public Builder setConversationId(String conversationId) {
|
||||
this.conversationId = conversationId;
|
||||
return this;
|
||||
}
|
||||
|
@ -750,9 +769,9 @@ public abstract class StatusViewData {
|
|||
}
|
||||
|
||||
public StatusViewData.Concrete createStatusViewData() {
|
||||
if (this.statusEmojis == null) statusEmojis = Collections.emptyList();
|
||||
if (this.accountEmojis == null) accountEmojis = Collections.emptyList();
|
||||
if (this.createdAt == null) createdAt = new Date();
|
||||
if(this.statusEmojis == null) statusEmojis = Collections.emptyList();
|
||||
if(this.accountEmojis == null) accountEmojis = Collections.emptyList();
|
||||
if(this.createdAt == null) createdAt = new Date();
|
||||
|
||||
return new StatusViewData.Concrete(id, content, reblogged, favourited, bookmarked, spoilerText,
|
||||
visibility, attachments, rebloggedByUsername, rebloggedAvatar, isSensitive, isExpanded,
|
||||
|
|
Loading…
Reference in a new issue