parent
f40ac42c08
commit
4098cd3a2c
@ -0,0 +1,203 @@ |
||||
package com.keylesspalace.tusky.adapter; |
||||
|
||||
import android.content.Context; |
||||
import android.graphics.drawable.BitmapDrawable; |
||||
import android.graphics.drawable.ColorDrawable; |
||||
import android.graphics.drawable.Drawable; |
||||
import android.text.Spanned; |
||||
import android.text.TextUtils; |
||||
import android.text.format.DateUtils; |
||||
import android.view.View; |
||||
import android.widget.Button; |
||||
import android.widget.ImageButton; |
||||
import android.widget.ImageView; |
||||
import android.widget.TextView; |
||||
import android.widget.Toast; |
||||
|
||||
import androidx.annotation.DrawableRes; |
||||
import androidx.annotation.NonNull; |
||||
import androidx.annotation.Nullable; |
||||
import androidx.recyclerview.widget.DefaultItemAnimator; |
||||
import androidx.recyclerview.widget.LinearLayoutManager; |
||||
import androidx.recyclerview.widget.RecyclerView; |
||||
|
||||
import com.bumptech.glide.Glide; |
||||
import com.google.android.material.button.MaterialButton; |
||||
import com.keylesspalace.tusky.R; |
||||
import com.keylesspalace.tusky.entity.Attachment; |
||||
import com.keylesspalace.tusky.entity.Attachment.Focus; |
||||
import com.keylesspalace.tusky.entity.Attachment.MetaData; |
||||
import com.keylesspalace.tusky.entity.Emoji; |
||||
import com.keylesspalace.tusky.entity.Status; |
||||
import com.keylesspalace.tusky.interfaces.StatusActionListener; |
||||
import com.keylesspalace.tusky.util.CustomEmojiHelper; |
||||
import com.keylesspalace.tusky.util.HtmlUtils; |
||||
import com.keylesspalace.tusky.util.ImageLoadingHelper; |
||||
import com.keylesspalace.tusky.util.LinkHelper; |
||||
import com.keylesspalace.tusky.util.StatusDisplayOptions; |
||||
import com.keylesspalace.tusky.util.ThemeUtils; |
||||
import com.keylesspalace.tusky.util.TimestampUtils; |
||||
import com.keylesspalace.tusky.view.MediaPreviewImageView; |
||||
import com.keylesspalace.tusky.viewdata.PollOptionViewData; |
||||
import com.keylesspalace.tusky.viewdata.PollViewData; |
||||
import com.keylesspalace.tusky.viewdata.PollViewDataKt; |
||||
import com.keylesspalace.tusky.viewdata.StatusViewData; |
||||
import com.mikepenz.iconics.utils.Utils; |
||||
|
||||
import java.text.SimpleDateFormat; |
||||
import java.util.Date; |
||||
import java.util.List; |
||||
import java.util.Locale; |
||||
import java.util.Objects; |
||||
|
||||
import at.connyduck.sparkbutton.SparkButton; |
||||
import kotlin.collections.CollectionsKt; |
||||
|
||||
import static com.keylesspalace.tusky.viewdata.PollViewDataKt.buildDescription; |
||||
|
||||
public class MutedStatusViewHolder extends RecyclerView.ViewHolder { |
||||
public static class Key { |
||||
public static final String KEY_CREATED = "created"; |
||||
} |
||||
|
||||
private TextView displayName; |
||||
private TextView username; |
||||
private TextView message; |
||||
private ImageButton unmuteButton; |
||||
public TextView timestampInfo; |
||||
|
||||
private SimpleDateFormat shortSdf; |
||||
private SimpleDateFormat longSdf; |
||||
|
||||
protected MutedStatusViewHolder(View itemView) { |
||||
super(itemView); |
||||
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); |
||||
|
||||
this.shortSdf = new SimpleDateFormat("HH:mm:ss", Locale.getDefault()); |
||||
this.longSdf = new SimpleDateFormat("MM/dd HH:mm:ss", Locale.getDefault()); |
||||
} |
||||
|
||||
protected void setDisplayName(String name, List<Emoji> customEmojis) { |
||||
CharSequence emojifiedName = CustomEmojiHelper.emojifyString(name, customEmojis, displayName); |
||||
displayName.setText(emojifiedName); |
||||
} |
||||
|
||||
protected void setUsername(String name) { |
||||
Context context = username.getContext(); |
||||
String usernameText = context.getString(R.string.status_username_format, name); |
||||
username.setText(usernameText); |
||||
} |
||||
|
||||
protected void setCreatedAt(Date createdAt, StatusDisplayOptions statusDisplayOptions) { |
||||
if (statusDisplayOptions.useAbsoluteTime()) { |
||||
timestampInfo.setText(getAbsoluteTime(createdAt)); |
||||
} else { |
||||
if (createdAt == null) { |
||||
timestampInfo.setText("?m"); |
||||
} else { |
||||
long then = createdAt.getTime(); |
||||
long now = System.currentTimeMillis(); |
||||
String readout = TimestampUtils.getRelativeTimeSpanString(timestampInfo.getContext(), then, now); |
||||
timestampInfo.setText(readout); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private String getAbsoluteTime(Date createdAt) { |
||||
if (createdAt == null) { |
||||
return "??:??:??"; |
||||
} |
||||
if (DateUtils.isToday(createdAt.getTime())) { |
||||
return shortSdf.format(createdAt); |
||||
} else { |
||||
return longSdf.format(createdAt); |
||||
} |
||||
} |
||||
|
||||
private CharSequence getCreatedAtDescription(Date createdAt, |
||||
StatusDisplayOptions statusDisplayOptions) { |
||||
if (statusDisplayOptions.useAbsoluteTime()) { |
||||
return getAbsoluteTime(createdAt); |
||||
} else { |
||||
/* This one is for screen-readers. Frequently, they would mispronounce timestamps like "17m" |
||||
* as 17 meters instead of minutes. */ |
||||
|
||||
if (createdAt == null) { |
||||
return "? minutes"; |
||||
} else { |
||||
long then = createdAt.getTime(); |
||||
long now = System.currentTimeMillis(); |
||||
return DateUtils.getRelativeTimeSpanString(then, now, |
||||
DateUtils.SECOND_IN_MILLIS, |
||||
DateUtils.FORMAT_ABBREV_RELATIVE); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private void setDescriptionForStatus(@NonNull StatusViewData.Concrete status, |
||||
StatusDisplayOptions statusDisplayOptions) { |
||||
Context context = itemView.getContext(); |
||||
|
||||
String description = context.getString(R.string.description_muted_status, |
||||
status.getUserFullName(), |
||||
getCreatedAtDescription(status.getCreatedAt(), statusDisplayOptions), |
||||
status.getNickname() |
||||
); |
||||
itemView.setContentDescription(description); |
||||
} |
||||
|
||||
|
||||
protected void setupButtons(final StatusActionListener listener, final String accountId) { |
||||
|
||||
unmuteButton.setOnClickListener(v -> { |
||||
int position = getAdapterPosition(); |
||||
if (position != RecyclerView.NO_POSITION) { |
||||
listener.onMute(position, false); |
||||
} |
||||
}); |
||||
|
||||
itemView.setOnClickListener( v -> { |
||||
int position = getAdapterPosition(); |
||||
if (position != RecyclerView.NO_POSITION) { |
||||
listener.onViewThread(position); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
public void setupWithStatus(StatusViewData.Concrete status, final StatusActionListener listener, |
||||
StatusDisplayOptions statusDisplayOptions) { |
||||
this.setupWithStatus(status, listener, statusDisplayOptions, null); |
||||
} |
||||
|
||||
protected void setupWithStatus(StatusViewData.Concrete status, |
||||
final StatusActionListener listener, |
||||
StatusDisplayOptions statusDisplayOptions, |
||||
@Nullable Object payloads) { |
||||
if (payloads == null) { |
||||
setDisplayName(status.getUserFullName(), status.getAccountEmojis()); |
||||
setUsername(status.getNickname()); |
||||
setCreatedAt(status.getCreatedAt(), statusDisplayOptions); |
||||
|
||||
setupButtons(listener, status.getSenderId()); |
||||
setDescriptionForStatus(status, statusDisplayOptions); |
||||
|
||||
// Workaround for RecyclerView 1.0.0 / androidx.core 1.0.0
|
||||
// RecyclerView tries to set AccessibilityDelegateCompat to null
|
||||
// but ViewCompat code replaces is with the default one. RecyclerView never
|
||||
// fetches another one from its delegate because it checks that it's set so we remove it
|
||||
// and let RecyclerView ask for a new delegate.
|
||||
itemView.setAccessibilityDelegate(null); |
||||
} else { |
||||
if (payloads instanceof List) |
||||
for (Object item : (List) payloads) { |
||||
if (Key.KEY_CREATED.equals(item)) { |
||||
setCreatedAt(status.getCreatedAt(), statusDisplayOptions); |
||||
} |
||||
} |
||||
|
||||
} |
||||
} |
||||
} |
@ -0,0 +1,75 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
xmlns:sparkbutton="http://schemas.android.com/apk/res-auto" |
||||
xmlns:tools="http://schemas.android.com/tools" |
||||
android:id="@+id/status_container" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:clipChildren="false" |
||||
android:clipToPadding="false" |
||||
android:focusable="true" |
||||
android:paddingLeft="14dp" |
||||
android:paddingRight="14dp"> |
||||
|
||||
<androidx.emoji.widget.EmojiTextView |
||||
android:id="@+id/status_display_name" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginStart="14dp" |
||||
android:layout_marginTop="10dp" |
||||
android:ellipsize="end" |
||||
android:importantForAccessibility="no" |
||||
android:maxLines="1" |
||||
android:paddingEnd="@dimen/status_display_name_padding_end" |
||||
android:textColor="?android:textColorPrimary" |
||||
android:textSize="?attr/status_text_medium" |
||||
android:textStyle="normal|bold" |
||||
tools:text="Ente r the void you foooooo" |
||||
app:layout_constrainedWidth="true" |
||||
app:layout_constraintEnd_toStartOf="@id/status_unmute" |
||||
app:layout_constraintHorizontal_bias="0" |
||||
app:layout_constraintStart_toStartOf="parent" |
||||
app:layout_constraintLeft_toRightOf="parent" |
||||
app:layout_constraintTop_toTopOf="parent"/> |
||||
|
||||
<TextView |
||||
android:id="@+id/status_username" |
||||
android:layout_width="0dp" |
||||
android:layout_height="wrap_content" |
||||
android:ellipsize="end" |
||||
android:importantForAccessibility="no" |
||||
android:maxLines="1" |
||||
android:textColor="?android:textColorSecondary" |
||||
android:textSize="?attr/status_text_medium" |
||||
app:layout_constraintEnd_toStartOf="@id/status_unmute" |
||||
app:layout_constraintStart_toEndOf="@id/status_display_name" |
||||
app:layout_constraintBaseline_toBaselineOf="@id/status_display_name" |
||||
tools:text="\@Entenhausen@birbsarecooooooooooool.site" /> |
||||
|
||||
<ImageButton |
||||
android:id="@+id/status_unmute" |
||||
style="?attr/image_button_style" |
||||
android:layout_width="24dp" |
||||
android:layout_height="30dp" |
||||
android:layout_marginEnd="8dp" |
||||
android:contentDescription="@string/action_unmute" |
||||
android:importantForAccessibility="no" |
||||
android:padding="4dp" |
||||
app:layout_constraintEnd_toStartOf="@id/status_timestamp_info" |
||||
app:layout_constraintTop_toTopOf="@id/status_timestamp_info" |
||||
app:srcCompat="@drawable/ic_hide_media_24dp" /> |
||||
|
||||
<TextView |
||||
android:id="@+id/status_timestamp_info" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginStart="4dp" |
||||
android:importantForAccessibility="no" |
||||
android:textColor="?android:textColorSecondary" |
||||
android:textSize="?attr/status_text_medium" |
||||
app:layout_constraintEnd_toEndOf="parent" |
||||
app:layout_constraintBaseline_toBaselineOf="@id/status_display_name" |
||||
tools:text="13:37" /> |
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout> |
Loading…
Reference in new issue