Add 'reply to' indicators in posts

main
Karol Kosek 4 years ago
parent 828198dab7
commit 34fa8b9664
  1. 1
      app/src/husky/res/values/strings.xml
  2. 14
      app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java
  3. 7
      app/src/main/java/com/keylesspalace/tusky/entity/Status.kt
  4. 1
      app/src/main/java/com/keylesspalace/tusky/util/ViewDataUtils.java
  5. 20
      app/src/main/java/com/keylesspalace/tusky/viewdata/StatusViewData.java
  6. 10
      app/src/main/res/drawable/ic_reply_18dp.xml
  7. 20
      app/src/main/res/layout/item_status.xml
  8. 18
      app/src/main/res/layout/item_status_detailed.xml

@ -95,6 +95,7 @@
<string name="status_share_content">Share content of post</string> <string name="status_share_content">Share content of post</string>
<string name="status_share_link">Share link to post</string> <string name="status_share_link">Share link to post</string>
<string name="status_boosted_format">%s repeated</string> <string name="status_boosted_format">%s repeated</string>
<string name="status_replied_to_format">Reply to %s</string>
<string name="title_scheduled_toot">Scheduled posts</string> <string name="title_scheduled_toot">Scheduled posts</string>
<string name="title_reblogged_by">Repeated by</string> <string name="title_reblogged_by">Repeated by</string>

@ -69,6 +69,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
private TextView displayName; private TextView displayName;
private TextView username; private TextView username;
private TextView replyInfo;
private ImageButton replyButton; private ImageButton replyButton;
private SparkButton reblogButton; private SparkButton reblogButton;
private SparkButton favouriteButton; private SparkButton favouriteButton;
@ -121,6 +122,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
timestampInfo = itemView.findViewById(R.id.status_timestamp_info); timestampInfo = itemView.findViewById(R.id.status_timestamp_info);
content = itemView.findViewById(R.id.status_content); content = itemView.findViewById(R.id.status_content);
avatar = itemView.findViewById(R.id.status_avatar); avatar = itemView.findViewById(R.id.status_avatar);
replyInfo = itemView.findViewById(R.id.reply_info);
replyButton = itemView.findViewById(R.id.status_reply); replyButton = itemView.findViewById(R.id.status_reply);
reblogButton = itemView.findViewById(R.id.status_inset); reblogButton = itemView.findViewById(R.id.status_inset);
favouriteButton = itemView.findViewById(R.id.status_favourite); favouriteButton = itemView.findViewById(R.id.status_favourite);
@ -379,6 +381,17 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
} }
protected void setReplyInfo(StatusViewData.Concrete status) {
if (status.getInReplyToId() != null) {
Context context = replyInfo.getContext();
String replyToAccount = status.getInReplyToAccountAcct();
replyInfo.setText(context.getString(R.string.status_replied_to_format, replyToAccount));
replyInfo.setVisibility(View.VISIBLE);
} else {
replyInfo.setVisibility(View.GONE);
}
}
private void setReblogged(boolean reblogged) { private void setReblogged(boolean reblogged) {
reblogButton.setChecked(reblogged); reblogButton.setChecked(reblogged);
} }
@ -757,6 +770,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
setUsername(status.getNickname()); setUsername(status.getNickname());
setCreatedAt(status.getCreatedAt(), statusDisplayOptions); setCreatedAt(status.getCreatedAt(), statusDisplayOptions);
setIsReply(status.getInReplyToId() != null); setIsReply(status.getInReplyToId() != null);
setReplyInfo(status);
setAvatar(status.getAvatar(), status.getRebloggedAvatar(), status.isBot(), statusDisplayOptions); setAvatar(status.getAvatar(), status.getRebloggedAvatar(), status.isBot(), statusDisplayOptions);
setReblogged(status.isReblogged()); setReblogged(status.isReblogged());
setFavourited(status.isFavourited()); setFavourited(status.isFavourited());

@ -151,6 +151,10 @@ data class Status(
return pleroma?.emojiReactions; return pleroma?.emojiReactions;
} }
fun getInReplyToAccountAcct(): String? {
return pleroma?.inReplyToAccountAcct;
}
private fun getEditableText(): String { private fun getEditableText(): String {
val builder = SpannableStringBuilder(content) 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)) {
@ -182,7 +186,8 @@ data class Status(
data class PleromaStatus( data class PleromaStatus(
@SerializedName("thread_muted") var threadMuted: Boolean?, @SerializedName("thread_muted") var threadMuted: Boolean?,
@SerializedName("conversation_id") val conversationId: Int?, @SerializedName("conversation_id") val conversationId: Int?,
@SerializedName("emoji_reactions") val emojiReactions: List<EmojiReaction>? @SerializedName("emoji_reactions") val emojiReactions: List<EmojiReaction>?,
@SerializedName("in_reply_to_account_acct") val inReplyToAccountAcct: String?
) )
data class Mention ( data class Mention (

@ -46,6 +46,7 @@ public final class ViewDataUtils {
.setReblogsCount(visibleStatus.getReblogsCount()) .setReblogsCount(visibleStatus.getReblogsCount())
.setFavouritesCount(visibleStatus.getFavouritesCount()) .setFavouritesCount(visibleStatus.getFavouritesCount())
.setInReplyToId(visibleStatus.getInReplyToId()) .setInReplyToId(visibleStatus.getInReplyToId())
.setInReplyToAccountAcct(visibleStatus.getInReplyToAccountAcct())
.setFavourited(visibleStatus.getFavourited()) .setFavourited(visibleStatus.getFavourited())
.setBookmarked(visibleStatus.getBookmarked()) .setBookmarked(visibleStatus.getBookmarked())
.setReblogged(visibleStatus.getReblogged()) .setReblogged(visibleStatus.getReblogged())

@ -77,6 +77,8 @@ public abstract class StatusViewData {
private final int favouritesCount; private final int favouritesCount;
@Nullable @Nullable
private final String inReplyToId; private final String inReplyToId;
@Nullable
private final String inReplyToAccountAcct;
// I would rather have something else but it would be too much of a rewrite // I would rather have something else but it would be too much of a rewrite
@Nullable @Nullable
private final Status.Mention[] mentions; private final Status.Mention[] mentions;
@ -104,7 +106,7 @@ public abstract class StatusViewData {
@Nullable String rebloggedByUsername, @Nullable String rebloggedAvatar, boolean sensitive, boolean isExpanded, @Nullable String rebloggedByUsername, @Nullable String rebloggedAvatar, boolean sensitive, boolean isExpanded,
boolean isShowingContent, String userFullName, String nickname, String avatar, boolean isShowingContent, String userFullName, String nickname, String avatar,
Date createdAt, int reblogsCount, int favouritesCount, @Nullable String inReplyToId, Date createdAt, int reblogsCount, int favouritesCount, @Nullable String inReplyToId,
@Nullable Status.Mention[] mentions, String senderId, boolean rebloggingEnabled, @Nullable String inReplyToAccountAcct, @Nullable Status.Mention[] mentions, String senderId, boolean rebloggingEnabled,
Status.Application application, List<Emoji> statusEmojis, List<Emoji> accountEmojis, @Nullable Card card, Status.Application application, List<Emoji> statusEmojis, List<Emoji> accountEmojis, @Nullable Card card,
boolean isCollapsible, boolean isCollapsed, @Nullable PollViewData poll, boolean isBot, boolean isMuted, boolean isThreadMuted, boolean isCollapsible, boolean isCollapsed, @Nullable PollViewData poll, boolean isBot, boolean isMuted, boolean isThreadMuted,
boolean isUserMuted, int conversationId, @Nullable List<EmojiReaction> emojiReactions) { boolean isUserMuted, int conversationId, @Nullable List<EmojiReaction> emojiReactions) {
@ -136,6 +138,7 @@ public abstract class StatusViewData {
this.reblogsCount = reblogsCount; this.reblogsCount = reblogsCount;
this.favouritesCount = favouritesCount; this.favouritesCount = favouritesCount;
this.inReplyToId = inReplyToId; this.inReplyToId = inReplyToId;
this.inReplyToAccountAcct = inReplyToAccountAcct;
this.mentions = mentions; this.mentions = mentions;
this.senderId = senderId; this.senderId = senderId;
this.rebloggingEnabled = rebloggingEnabled; this.rebloggingEnabled = rebloggingEnabled;
@ -240,6 +243,11 @@ public abstract class StatusViewData {
return inReplyToId; return inReplyToId;
} }
@Nullable
public String getInReplyToAccountAcct() {
return inReplyToAccountAcct;
}
public String getSenderId() { public String getSenderId() {
return senderId; return senderId;
} }
@ -343,6 +351,7 @@ public abstract class StatusViewData {
Objects.equals(avatar, concrete.avatar) && Objects.equals(avatar, concrete.avatar) &&
Objects.equals(createdAt, concrete.createdAt) && Objects.equals(createdAt, concrete.createdAt) &&
Objects.equals(inReplyToId, concrete.inReplyToId) && Objects.equals(inReplyToId, concrete.inReplyToId) &&
Objects.equals(inReplyToAccountAcct, concrete.inReplyToAccountAcct) &&
Arrays.equals(mentions, concrete.mentions) && Arrays.equals(mentions, concrete.mentions) &&
Objects.equals(senderId, concrete.senderId) && Objects.equals(senderId, concrete.senderId) &&
Objects.equals(application, concrete.application) && Objects.equals(application, concrete.application) &&
@ -451,6 +460,7 @@ public abstract class StatusViewData {
private int reblogsCount; private int reblogsCount;
private int favouritesCount; private int favouritesCount;
private String inReplyToId; private String inReplyToId;
private String inReplyToAccountAcct;
private Status.Mention[] mentions; private Status.Mention[] mentions;
private String senderId; private String senderId;
private boolean rebloggingEnabled; private boolean rebloggingEnabled;
@ -492,6 +502,7 @@ public abstract class StatusViewData {
reblogsCount = viewData.reblogsCount; reblogsCount = viewData.reblogsCount;
favouritesCount = viewData.favouritesCount; favouritesCount = viewData.favouritesCount;
inReplyToId = viewData.inReplyToId; inReplyToId = viewData.inReplyToId;
inReplyToAccountAcct = viewData.inReplyToAccountAcct;
mentions = viewData.mentions == null ? null : viewData.mentions.clone(); mentions = viewData.mentions == null ? null : viewData.mentions.clone();
senderId = viewData.senderId; senderId = viewData.senderId;
rebloggingEnabled = viewData.rebloggingEnabled; rebloggingEnabled = viewData.rebloggingEnabled;
@ -614,6 +625,11 @@ public abstract class StatusViewData {
return this; return this;
} }
public Builder setInReplyToAccountAcct(String inReplyToAccountAcct) {
this.inReplyToAccountAcct = inReplyToAccountAcct;
return this;
}
public Builder setMentions(Status.Mention[] mentions) { public Builder setMentions(Status.Mention[] mentions) {
this.mentions = mentions; this.mentions = mentions;
return this; return this;
@ -711,7 +727,7 @@ public abstract class StatusViewData {
return new StatusViewData.Concrete(id, content, reblogged, favourited, bookmarked, spoilerText, return new StatusViewData.Concrete(id, content, reblogged, favourited, bookmarked, spoilerText,
visibility, attachments, rebloggedByUsername, rebloggedAvatar, isSensitive, isExpanded, visibility, attachments, rebloggedByUsername, rebloggedAvatar, isSensitive, isExpanded,
isShowingContent, userFullName, nickname, avatar, createdAt, reblogsCount, isShowingContent, userFullName, nickname, avatar, createdAt, reblogsCount,
favouritesCount, inReplyToId, mentions, senderId, rebloggingEnabled, application, favouritesCount, inReplyToId, inReplyToAccountAcct, mentions, senderId, rebloggingEnabled, application,
statusEmojis, accountEmojis, card, isCollapsible, isCollapsed, poll, isBot, isMuted, isThreadMuted, statusEmojis, accountEmojis, card, isCollapsible, isCollapsed, poll, isBot, isMuted, isThreadMuted,
isUserMuted, conversationId, emojiReactions); isUserMuted, conversationId, emojiReactions);
} }

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="18dp"
android:height="18dp"
android:autoMirrored="true"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="?android:attr/textColorTertiary"
android:pathData="M10,9V5l-7,7 7,7v-4.1c5,0 8.5,1.6 11,5.1 -1,-5 -4,-10 -11,-11z" />
</vector>

@ -115,6 +115,22 @@
app:layout_constraintBaseline_toBaselineOf="@id/status_display_name" app:layout_constraintBaseline_toBaselineOf="@id/status_display_name"
tools:text="13:37" /> tools:text="13:37" />
<TextView
android:id="@+id/reply_info"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:drawablePadding="6dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:textColorTertiary"
android:textSize="?attr/status_text_medium"
app:drawableStartCompat="@drawable/ic_reply_18dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/status_display_name"
app:layout_constraintTop_toBottomOf="@+id/status_display_name"
tools:text="Reply to a1batross" />
<androidx.emoji.widget.EmojiTextView <androidx.emoji.widget.EmojiTextView
android:id="@+id/status_content_warning_description" android:id="@+id/status_content_warning_description"
android:layout_width="0dp" android:layout_width="0dp"
@ -126,8 +142,8 @@
android:textSize="?attr/status_text_medium" android:textSize="?attr/status_text_medium"
android:visibility="gone" android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@id/status_display_name" app:layout_constraintStart_toStartOf="@+id/status_display_name"
app:layout_constraintTop_toBottomOf="@id/status_display_name" app:layout_constraintTop_toBottomOf="@+id/reply_info"
tools:text="content warning which is very long and it doesn't fit" tools:text="content warning which is very long and it doesn't fit"
tools:visibility="visible" /> tools:visibility="visible" />

@ -79,6 +79,22 @@
app:layout_constraintTop_toBottomOf="@id/status_display_name" app:layout_constraintTop_toBottomOf="@id/status_display_name"
tools:text="\@ConnyDuck\@mastodon.social" /> tools:text="\@ConnyDuck\@mastodon.social" />
<TextView
android:id="@+id/reply_info"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:drawablePadding="6dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:textColorTertiary"
android:textSize="?attr/status_text_medium"
app:drawableStartCompat="@drawable/ic_reply_18dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@id/status_avatar"
app:layout_constraintTop_toBottomOf="@+id/status_avatar"
tools:text="Reply to a1batross" />
<androidx.emoji.widget.EmojiTextView <androidx.emoji.widget.EmojiTextView
android:id="@+id/status_content_warning_description" android:id="@+id/status_content_warning_description"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -90,7 +106,7 @@
android:textColor="?android:textColorPrimary" android:textColor="?android:textColorPrimary"
android:textSize="?attr/status_text_large" android:textSize="?attr/status_text_large"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/status_avatar" app:layout_constraintTop_toBottomOf="@id/reply_info"
tools:text="CW this is a long long long long long long long long content warning" /> tools:text="CW this is a long long long long long long long long content warning" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton

Loading…
Cancel
Save