Timeline refactor (#2175)
* Move Timeline files into their own package * Introduce TimelineViewModel, add coroutines * Simplify StatusViewData * Handle timeilne fetch errors * Rework filters, fix ViewThreadFragment * Fix NotificationsFragment * Simplify Notifications and Thread, handle pin * Redo loading in TimelineViewModel * Improve error handling in TimelineViewModel * Rewrite actions in TimelineViewModel * Apply feedback after timeline factoring review * Handle initial failure in timeline correctly
This commit is contained in:
parent
0a992480c2
commit
44a5b42cac
58 changed files with 3956 additions and 3618 deletions
|
|
@ -40,6 +40,7 @@ import com.keylesspalace.tusky.interfaces.LinkListener;
|
|||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
|
||||
public class LinkHelper {
|
||||
public static String getDomain(String urlString) {
|
||||
|
|
@ -69,7 +70,7 @@ public class LinkHelper {
|
|||
* @param listener to notify about particular spans that are clicked
|
||||
*/
|
||||
public static void setClickableText(TextView view, CharSequence content,
|
||||
@Nullable Status.Mention[] mentions, final LinkListener listener) {
|
||||
@Nullable List<Status.Mention> mentions, final LinkListener listener) {
|
||||
SpannableStringBuilder builder = SpannableStringBuilder.valueOf(content);
|
||||
URLSpan[] urlSpans = builder.getSpans(0, content.length(), URLSpan.class);
|
||||
for (URLSpan span : urlSpans) {
|
||||
|
|
@ -85,7 +86,7 @@ public class LinkHelper {
|
|||
@Override
|
||||
public void onClick(@NonNull View widget) { listener.onViewTag(tag); }
|
||||
};
|
||||
} else if (text.charAt(0) == '@' && mentions != null && mentions.length > 0) {
|
||||
} else if (text.charAt(0) == '@' && mentions != null && mentions.size() > 0) {
|
||||
String accountUsername = text.subSequence(1, text.length()).toString();
|
||||
/* There may be multiple matches for users on different instances with the same
|
||||
* username. If a match has the same domain we know it's for sure the same, but if
|
||||
|
|
@ -141,8 +142,8 @@ public class LinkHelper {
|
|||
* @param listener to notify about particular spans that are clicked
|
||||
*/
|
||||
public static void setClickableMentions(
|
||||
TextView view, @Nullable Status.Mention[] mentions, final LinkListener listener) {
|
||||
if (mentions == null || mentions.length == 0) {
|
||||
TextView view, @Nullable List<Status.Mention> mentions, final LinkListener listener) {
|
||||
if (mentions == null || mentions.size() == 0) {
|
||||
view.setText(null);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,9 +27,9 @@ fun interface StatusProvider {
|
|||
}
|
||||
|
||||
class ListStatusAccessibilityDelegate(
|
||||
private val recyclerView: RecyclerView,
|
||||
private val statusActionListener: StatusActionListener,
|
||||
private val statusProvider: StatusProvider
|
||||
private val recyclerView: RecyclerView,
|
||||
private val statusActionListener: StatusActionListener,
|
||||
private val statusProvider: StatusProvider
|
||||
) : RecyclerViewAccessibilityDelegate(recyclerView) {
|
||||
private val a11yManager = context.getSystemService(Context.ACCESSIBILITY_SERVICE)
|
||||
as AccessibilityManager
|
||||
|
|
@ -39,8 +39,10 @@ class ListStatusAccessibilityDelegate(
|
|||
private val context: Context get() = recyclerView.context
|
||||
|
||||
private val itemDelegate = object : RecyclerViewAccessibilityDelegate.ItemDelegate(this) {
|
||||
override fun onInitializeAccessibilityNodeInfo(host: View,
|
||||
info: AccessibilityNodeInfoCompat) {
|
||||
override fun onInitializeAccessibilityNodeInfo(
|
||||
host: View,
|
||||
info: AccessibilityNodeInfoCompat
|
||||
) {
|
||||
super.onInitializeAccessibilityNodeInfo(host, info)
|
||||
|
||||
val pos = recyclerView.getChildAdapterPosition(host)
|
||||
|
|
@ -52,44 +54,51 @@ class ListStatusAccessibilityDelegate(
|
|||
|
||||
info.addAction(replyAction)
|
||||
|
||||
if (status.rebloggingEnabled) {
|
||||
info.addAction(if (status.isReblogged) unreblogAction else reblogAction)
|
||||
val actionable = status.actionable
|
||||
if (actionable.rebloggingAllowed()) {
|
||||
info.addAction(if (actionable.reblogged) unreblogAction else reblogAction)
|
||||
}
|
||||
info.addAction(if (status.isFavourited) unfavouriteAction else favouriteAction)
|
||||
info.addAction(if (status.isBookmarked) unbookmarkAction else bookmarkAction)
|
||||
info.addAction(if (actionable.favourited) unfavouriteAction else favouriteAction)
|
||||
info.addAction(if (actionable.bookmarked) unbookmarkAction else bookmarkAction)
|
||||
|
||||
val mediaActions = intArrayOf(
|
||||
R.id.action_open_media_1,
|
||||
R.id.action_open_media_2,
|
||||
R.id.action_open_media_3,
|
||||
R.id.action_open_media_4)
|
||||
val attachmentCount = min(status.attachments.size, MAX_MEDIA_ATTACHMENTS)
|
||||
R.id.action_open_media_1,
|
||||
R.id.action_open_media_2,
|
||||
R.id.action_open_media_3,
|
||||
R.id.action_open_media_4
|
||||
)
|
||||
val attachmentCount = min(actionable.attachments.size, MAX_MEDIA_ATTACHMENTS)
|
||||
for (i in 0 until attachmentCount) {
|
||||
info.addAction(AccessibilityActionCompat(
|
||||
info.addAction(
|
||||
AccessibilityActionCompat(
|
||||
mediaActions[i],
|
||||
context.getString(R.string.action_open_media_n, i + 1)))
|
||||
context.getString(R.string.action_open_media_n, i + 1)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
info.addAction(openProfileAction)
|
||||
if (getLinks(status).any()) info.addAction(linksAction)
|
||||
|
||||
val mentions = status.mentions
|
||||
if (mentions != null && mentions.isNotEmpty()) info.addAction(mentionsAction)
|
||||
val mentions = actionable.mentions
|
||||
if (mentions.isNotEmpty()) info.addAction(mentionsAction)
|
||||
|
||||
if (getHashtags(status).any()) info.addAction(hashtagsAction)
|
||||
if (!status.rebloggedByUsername.isNullOrEmpty()) {
|
||||
if (!status.status.reblog?.account?.username.isNullOrEmpty()) {
|
||||
info.addAction(openRebloggerAction)
|
||||
}
|
||||
if (status.reblogsCount > 0) info.addAction(openRebloggedByAction)
|
||||
if (status.favouritesCount > 0) info.addAction(openFavsAction)
|
||||
if (actionable.reblogsCount > 0) info.addAction(openRebloggedByAction)
|
||||
if (actionable.favouritesCount > 0) info.addAction(openFavsAction)
|
||||
|
||||
info.addAction(moreAction)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun performAccessibilityAction(host: View, action: Int,
|
||||
args: Bundle?): Boolean {
|
||||
override fun performAccessibilityAction(
|
||||
host: View, action: Int,
|
||||
args: Bundle?
|
||||
): Boolean {
|
||||
val pos = recyclerView.getChildAdapterPosition(host)
|
||||
when (action) {
|
||||
R.id.action_reply -> {
|
||||
|
|
@ -105,7 +114,8 @@ class ListStatusAccessibilityDelegate(
|
|||
R.id.action_open_profile -> {
|
||||
interrupt()
|
||||
statusActionListener.onViewAccount(
|
||||
(statusProvider.getStatus(pos) as StatusViewData.Concrete).senderId)
|
||||
(statusProvider.getStatus(pos) as StatusViewData.Concrete).actionable.account.id
|
||||
)
|
||||
}
|
||||
R.id.action_open_media_1 -> {
|
||||
interrupt()
|
||||
|
|
@ -166,43 +176,51 @@ class ListStatusAccessibilityDelegate(
|
|||
val links = getLinks(status).toList()
|
||||
val textLinks = links.map { item -> item.link }
|
||||
AlertDialog.Builder(host.context)
|
||||
.setTitle(R.string.title_links_dialog)
|
||||
.setAdapter(ArrayAdapter(
|
||||
host.context,
|
||||
android.R.layout.simple_list_item_1,
|
||||
textLinks)
|
||||
) { _, which -> LinkHelper.openLink(links[which].link, host.context) }
|
||||
.show()
|
||||
.let { forceFocus(it.listView) }
|
||||
.setTitle(R.string.title_links_dialog)
|
||||
.setAdapter(
|
||||
ArrayAdapter(
|
||||
host.context,
|
||||
android.R.layout.simple_list_item_1,
|
||||
textLinks
|
||||
)
|
||||
) { _, which -> LinkHelper.openLink(links[which].link, host.context) }
|
||||
.show()
|
||||
.let { forceFocus(it.listView) }
|
||||
}
|
||||
|
||||
private fun showMentionsDialog(host: View) {
|
||||
val status = getStatus(host) as? StatusViewData.Concrete ?: return
|
||||
val mentions = status.mentions ?: return
|
||||
val mentions = status.actionable.mentions
|
||||
val stringMentions = mentions.map { it.username }
|
||||
AlertDialog.Builder(host.context)
|
||||
.setTitle(R.string.title_mentions_dialog)
|
||||
.setAdapter(ArrayAdapter<CharSequence>(host.context,
|
||||
android.R.layout.simple_list_item_1, stringMentions)
|
||||
) { _, which ->
|
||||
statusActionListener.onViewAccount(mentions[which].id)
|
||||
}
|
||||
.show()
|
||||
.let { forceFocus(it.listView) }
|
||||
.setTitle(R.string.title_mentions_dialog)
|
||||
.setAdapter(
|
||||
ArrayAdapter<CharSequence>(
|
||||
host.context,
|
||||
android.R.layout.simple_list_item_1, stringMentions
|
||||
)
|
||||
) { _, which ->
|
||||
statusActionListener.onViewAccount(mentions[which].id)
|
||||
}
|
||||
.show()
|
||||
.let { forceFocus(it.listView) }
|
||||
}
|
||||
|
||||
private fun showHashtagsDialog(host: View) {
|
||||
val status = getStatus(host) as? StatusViewData.Concrete ?: return
|
||||
val tags = getHashtags(status).map { it.subSequence(1, it.length) }.toList()
|
||||
AlertDialog.Builder(host.context)
|
||||
.setTitle(R.string.title_hashtags_dialog)
|
||||
.setAdapter(ArrayAdapter(host.context,
|
||||
android.R.layout.simple_list_item_1, tags)
|
||||
) { _, which ->
|
||||
statusActionListener.onViewTag(tags[which].toString())
|
||||
}
|
||||
.show()
|
||||
.let { forceFocus(it.listView) }
|
||||
.setTitle(R.string.title_hashtags_dialog)
|
||||
.setAdapter(
|
||||
ArrayAdapter(
|
||||
host.context,
|
||||
android.R.layout.simple_list_item_1, tags
|
||||
)
|
||||
) { _, which ->
|
||||
statusActionListener.onViewTag(tags[which].toString())
|
||||
}
|
||||
.show()
|
||||
.let { forceFocus(it.listView) }
|
||||
}
|
||||
|
||||
private fun getStatus(childView: View): StatusViewData {
|
||||
|
|
@ -215,14 +233,15 @@ class ListStatusAccessibilityDelegate(
|
|||
val content = status.content
|
||||
return if (content is Spannable) {
|
||||
content.getSpans(0, content.length, URLSpan::class.java)
|
||||
.asSequence()
|
||||
.map { span ->
|
||||
val text = content.subSequence(
|
||||
content.getSpanStart(span),
|
||||
content.getSpanEnd(span))
|
||||
if (isHashtag(text)) null else LinkSpanInfo(text.toString(), span.url)
|
||||
}
|
||||
.filterNotNull()
|
||||
.asSequence()
|
||||
.map { span ->
|
||||
val text = content.subSequence(
|
||||
content.getSpanStart(span),
|
||||
content.getSpanEnd(span)
|
||||
)
|
||||
if (isHashtag(text)) null else LinkSpanInfo(text.toString(), span.url)
|
||||
}
|
||||
.filterNotNull()
|
||||
} else {
|
||||
emptySequence()
|
||||
}
|
||||
|
|
@ -231,11 +250,11 @@ class ListStatusAccessibilityDelegate(
|
|||
private fun getHashtags(status: StatusViewData.Concrete): Sequence<CharSequence> {
|
||||
val content = status.content
|
||||
return content.getSpans(0, content.length, Object::class.java)
|
||||
.asSequence()
|
||||
.map { span ->
|
||||
content.subSequence(content.getSpanStart(span), content.getSpanEnd(span))
|
||||
}
|
||||
.filter(this::isHashtag)
|
||||
.asSequence()
|
||||
.map { span ->
|
||||
content.subSequence(content.getSpanStart(span), content.getSpanEnd(span))
|
||||
}
|
||||
.filter(this::isHashtag)
|
||||
}
|
||||
|
||||
private fun forceFocus(host: View) {
|
||||
|
|
@ -253,72 +272,88 @@ class ListStatusAccessibilityDelegate(
|
|||
private fun isHashtag(text: CharSequence) = text.startsWith("#")
|
||||
|
||||
private val collapseCwAction = AccessibilityActionCompat(
|
||||
R.id.action_collapse_cw,
|
||||
context.getString(R.string.status_content_warning_show_less))
|
||||
R.id.action_collapse_cw,
|
||||
context.getString(R.string.status_content_warning_show_less)
|
||||
)
|
||||
|
||||
private val expandCwAction = AccessibilityActionCompat(
|
||||
R.id.action_expand_cw,
|
||||
context.getString(R.string.status_content_warning_show_more))
|
||||
R.id.action_expand_cw,
|
||||
context.getString(R.string.status_content_warning_show_more)
|
||||
)
|
||||
|
||||
private val replyAction = AccessibilityActionCompat(
|
||||
R.id.action_reply,
|
||||
context.getString(R.string.action_reply))
|
||||
R.id.action_reply,
|
||||
context.getString(R.string.action_reply)
|
||||
)
|
||||
|
||||
private val unreblogAction = AccessibilityActionCompat(
|
||||
R.id.action_unreblog,
|
||||
context.getString(R.string.action_unreblog))
|
||||
R.id.action_unreblog,
|
||||
context.getString(R.string.action_unreblog)
|
||||
)
|
||||
|
||||
private val reblogAction = AccessibilityActionCompat(
|
||||
R.id.action_reblog,
|
||||
context.getString(R.string.action_reblog))
|
||||
R.id.action_reblog,
|
||||
context.getString(R.string.action_reblog)
|
||||
)
|
||||
|
||||
private val unfavouriteAction = AccessibilityActionCompat(
|
||||
R.id.action_unfavourite,
|
||||
context.getString(R.string.action_unfavourite))
|
||||
R.id.action_unfavourite,
|
||||
context.getString(R.string.action_unfavourite)
|
||||
)
|
||||
|
||||
private val favouriteAction = AccessibilityActionCompat(
|
||||
R.id.action_favourite,
|
||||
context.getString(R.string.action_favourite))
|
||||
R.id.action_favourite,
|
||||
context.getString(R.string.action_favourite)
|
||||
)
|
||||
|
||||
private val bookmarkAction = AccessibilityActionCompat(
|
||||
R.id.action_bookmark,
|
||||
context.getString(R.string.action_bookmark))
|
||||
R.id.action_bookmark,
|
||||
context.getString(R.string.action_bookmark)
|
||||
)
|
||||
|
||||
private val unbookmarkAction = AccessibilityActionCompat(
|
||||
R.id.action_unbookmark,
|
||||
context.getString(R.string.action_bookmark))
|
||||
R.id.action_unbookmark,
|
||||
context.getString(R.string.action_bookmark)
|
||||
)
|
||||
|
||||
private val openProfileAction = AccessibilityActionCompat(
|
||||
R.id.action_open_profile,
|
||||
context.getString(R.string.action_view_profile))
|
||||
R.id.action_open_profile,
|
||||
context.getString(R.string.action_view_profile)
|
||||
)
|
||||
|
||||
private val linksAction = AccessibilityActionCompat(
|
||||
R.id.action_links,
|
||||
context.getString(R.string.action_links))
|
||||
R.id.action_links,
|
||||
context.getString(R.string.action_links)
|
||||
)
|
||||
|
||||
private val mentionsAction = AccessibilityActionCompat(
|
||||
R.id.action_mentions,
|
||||
context.getString(R.string.action_mentions))
|
||||
R.id.action_mentions,
|
||||
context.getString(R.string.action_mentions)
|
||||
)
|
||||
|
||||
private val hashtagsAction = AccessibilityActionCompat(
|
||||
R.id.action_hashtags,
|
||||
context.getString(R.string.action_hashtags))
|
||||
R.id.action_hashtags,
|
||||
context.getString(R.string.action_hashtags)
|
||||
)
|
||||
|
||||
private val openRebloggerAction = AccessibilityActionCompat(
|
||||
R.id.action_open_reblogger,
|
||||
context.getString(R.string.action_open_reblogger))
|
||||
R.id.action_open_reblogger,
|
||||
context.getString(R.string.action_open_reblogger)
|
||||
)
|
||||
|
||||
private val openRebloggedByAction = AccessibilityActionCompat(
|
||||
R.id.action_open_reblogged_by,
|
||||
context.getString(R.string.action_open_reblogged_by))
|
||||
R.id.action_open_reblogged_by,
|
||||
context.getString(R.string.action_open_reblogged_by)
|
||||
)
|
||||
|
||||
private val openFavsAction = AccessibilityActionCompat(
|
||||
R.id.action_open_faved_by,
|
||||
context.getString(R.string.action_open_faved_by))
|
||||
R.id.action_open_faved_by,
|
||||
context.getString(R.string.action_open_faved_by)
|
||||
)
|
||||
|
||||
private val moreAction = AccessibilityActionCompat(
|
||||
R.id.action_more,
|
||||
context.getString(R.string.action_more)
|
||||
R.id.action_more,
|
||||
context.getString(R.string.action_more)
|
||||
)
|
||||
|
||||
private data class LinkSpanInfo(val text: String, val link: String)
|
||||
|
|
|
|||
|
|
@ -52,4 +52,8 @@ inline fun <T> List<T>.replacedFirstWhich(replacement: T, predicate: (T) -> Bool
|
|||
newList[index] = replacement
|
||||
}
|
||||
return newList
|
||||
}
|
||||
|
||||
inline fun <reified R> Iterable<*>.firstIsInstanceOrNull(): R? {
|
||||
return firstOrNull { it is R }?.let { it as R }
|
||||
}
|
||||
|
|
@ -73,6 +73,15 @@ fun String.isLessThan(other: String): Boolean {
|
|||
}
|
||||
}
|
||||
|
||||
fun String.idCompareTo(other: String): Int {
|
||||
return when {
|
||||
this === other -> 0
|
||||
this.length < other.length -> -1
|
||||
this.length > other.length -> 1
|
||||
else -> this.compareTo(other)
|
||||
}
|
||||
}
|
||||
|
||||
fun Spanned.trimTrailingWhitespace(): Spanned {
|
||||
var i = length
|
||||
do {
|
||||
|
|
|
|||
|
|
@ -1,86 +0,0 @@
|
|||
/* Copyright 2017 Andrew Dawson
|
||||
*
|
||||
* This file is a part of Tusky.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Tusky; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
package com.keylesspalace.tusky.util;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.keylesspalace.tusky.entity.Notification;
|
||||
import com.keylesspalace.tusky.entity.Status;
|
||||
import com.keylesspalace.tusky.viewdata.NotificationViewData;
|
||||
import com.keylesspalace.tusky.viewdata.StatusViewData;
|
||||
|
||||
/**
|
||||
* Created by charlag on 12/07/2017.
|
||||
*/
|
||||
|
||||
public final class ViewDataUtils {
|
||||
@Nullable
|
||||
public static StatusViewData.Concrete statusToViewData(@Nullable Status status,
|
||||
boolean alwaysShowSensitiveMedia,
|
||||
boolean alwaysOpenSpoiler) {
|
||||
if (status == null) return null;
|
||||
Status visibleStatus = status.getReblog() == null ? status : status.getReblog();
|
||||
return new StatusViewData.Builder().setId(status.getId())
|
||||
.setAttachments(visibleStatus.getAttachments())
|
||||
.setAvatar(visibleStatus.getAccount().getAvatar())
|
||||
.setContent(visibleStatus.getContent())
|
||||
.setCreatedAt(visibleStatus.getCreatedAt())
|
||||
.setReblogsCount(visibleStatus.getReblogsCount())
|
||||
.setFavouritesCount(visibleStatus.getFavouritesCount())
|
||||
.setInReplyToId(visibleStatus.getInReplyToId())
|
||||
.setFavourited(visibleStatus.getFavourited())
|
||||
.setBookmarked(visibleStatus.getBookmarked())
|
||||
.setReblogged(visibleStatus.getReblogged())
|
||||
.setIsExpanded(alwaysOpenSpoiler)
|
||||
.setIsShowingSensitiveContent(false)
|
||||
.setMentions(visibleStatus.getMentions())
|
||||
.setNickname(visibleStatus.getAccount().getUsername())
|
||||
.setRebloggedAvatar(status.getReblog() == null ? null : status.getAccount().getAvatar())
|
||||
.setSensitive(visibleStatus.getSensitive())
|
||||
.setIsShowingSensitiveContent(alwaysShowSensitiveMedia || !visibleStatus.getSensitive())
|
||||
.setSpoilerText(visibleStatus.getSpoilerText())
|
||||
.setRebloggedByUsername(status.getReblog() == null ? null : status.getAccount().getName())
|
||||
.setUserFullName(visibleStatus.getAccount().getName())
|
||||
.setVisibility(visibleStatus.getVisibility())
|
||||
.setSenderId(visibleStatus.getAccount().getId())
|
||||
.setRebloggingEnabled(visibleStatus.rebloggingAllowed())
|
||||
.setApplication(visibleStatus.getApplication())
|
||||
.setStatusEmojis(visibleStatus.getEmojis())
|
||||
.setAccountEmojis(visibleStatus.getAccount().getEmojis())
|
||||
.setRebloggedByEmojis(status.getReblog() == null ? null : status.getAccount().getEmojis())
|
||||
.setCollapsible(SmartLengthInputFilterKt.shouldTrimStatus(visibleStatus.getContent()))
|
||||
.setCollapsed(true)
|
||||
.setPoll(visibleStatus.getPoll())
|
||||
.setCard(visibleStatus.getCard())
|
||||
.setIsBot(visibleStatus.getAccount().getBot())
|
||||
.createStatusViewData();
|
||||
}
|
||||
|
||||
public static NotificationViewData.Concrete notificationToViewData(Notification notification,
|
||||
boolean alwaysShowSensitiveData,
|
||||
boolean alwaysOpenSpoiler) {
|
||||
return new NotificationViewData.Concrete(
|
||||
notification.getType(),
|
||||
notification.getId(),
|
||||
notification.getAccount(),
|
||||
statusToViewData(
|
||||
notification.getStatus(),
|
||||
alwaysShowSensitiveData,
|
||||
alwaysOpenSpoiler
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
@file:JvmName("ViewDataUtils")
|
||||
|
||||
/* Copyright 2017 Andrew Dawson
|
||||
*
|
||||
* This file is a part of Tusky.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Tusky; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
package com.keylesspalace.tusky.util
|
||||
|
||||
import com.keylesspalace.tusky.entity.Notification
|
||||
import com.keylesspalace.tusky.entity.Status
|
||||
import com.keylesspalace.tusky.viewdata.NotificationViewData
|
||||
import com.keylesspalace.tusky.viewdata.StatusViewData
|
||||
import com.keylesspalace.tusky.viewdata.toViewData
|
||||
import java.util.*
|
||||
|
||||
@JvmName("statusToViewData")
|
||||
fun Status.toViewData(
|
||||
alwaysShowSensitiveMedia: Boolean,
|
||||
alwaysOpenSpoiler: Boolean
|
||||
): StatusViewData.Concrete {
|
||||
val visibleStatus = this.reblog ?: this
|
||||
|
||||
return StatusViewData.Concrete(
|
||||
status = this,
|
||||
isShowingContent = alwaysShowSensitiveMedia || !visibleStatus.sensitive,
|
||||
isCollapsible = shouldTrimStatus(visibleStatus.content),
|
||||
isCollapsed = false,
|
||||
isExpanded = alwaysOpenSpoiler,
|
||||
)
|
||||
}
|
||||
|
||||
@JvmName("notificationToViewData")
|
||||
fun Notification.toViewData(
|
||||
alwaysShowSensitiveData: Boolean,
|
||||
alwaysOpenSpoiler: Boolean
|
||||
): NotificationViewData.Concrete {
|
||||
return NotificationViewData.Concrete(
|
||||
this.type,
|
||||
this.id,
|
||||
this.account,
|
||||
this.status?.toViewData(alwaysShowSensitiveData, alwaysOpenSpoiler)
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue