Display the time that an announcement was posted, as well as the most recent update to the announcement (if there is one). Time display honours the user's "use absolute time" preference. Fixes #35
This commit is contained in:
parent
db2bd3199e
commit
3cfb7a0d1e
|
@ -27,9 +27,12 @@ import app.pachli.R
|
||||||
import app.pachli.databinding.ItemAnnouncementBinding
|
import app.pachli.databinding.ItemAnnouncementBinding
|
||||||
import app.pachli.entity.Announcement
|
import app.pachli.entity.Announcement
|
||||||
import app.pachli.interfaces.LinkListener
|
import app.pachli.interfaces.LinkListener
|
||||||
|
import app.pachli.util.AbsoluteTimeFormatter
|
||||||
import app.pachli.util.BindingHolder
|
import app.pachli.util.BindingHolder
|
||||||
import app.pachli.util.EmojiSpan
|
import app.pachli.util.EmojiSpan
|
||||||
import app.pachli.util.emojify
|
import app.pachli.util.emojify
|
||||||
|
import app.pachli.util.equalByMinute
|
||||||
|
import app.pachli.util.getRelativeTimeSpanString
|
||||||
import app.pachli.util.parseAsMastodonHtml
|
import app.pachli.util.parseAsMastodonHtml
|
||||||
import app.pachli.util.setClickableText
|
import app.pachli.util.setClickableText
|
||||||
import app.pachli.util.visible
|
import app.pachli.util.visible
|
||||||
|
@ -48,7 +51,9 @@ class AnnouncementAdapter(
|
||||||
private val listener: AnnouncementActionListener,
|
private val listener: AnnouncementActionListener,
|
||||||
private val wellbeingEnabled: Boolean = false,
|
private val wellbeingEnabled: Boolean = false,
|
||||||
private val animateEmojis: Boolean = false,
|
private val animateEmojis: Boolean = false,
|
||||||
|
private val useAbsoluteTime: Boolean = false,
|
||||||
) : RecyclerView.Adapter<BindingHolder<ItemAnnouncementBinding>>() {
|
) : RecyclerView.Adapter<BindingHolder<ItemAnnouncementBinding>>() {
|
||||||
|
private val absoluteTimeFormatter = AbsoluteTimeFormatter()
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingHolder<ItemAnnouncementBinding> {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingHolder<ItemAnnouncementBinding> {
|
||||||
val binding = ItemAnnouncementBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
val binding = ItemAnnouncementBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
|
@ -57,6 +62,29 @@ class AnnouncementAdapter(
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: BindingHolder<ItemAnnouncementBinding>, position: Int) {
|
override fun onBindViewHolder(holder: BindingHolder<ItemAnnouncementBinding>, position: Int) {
|
||||||
val item = items[position]
|
val item = items[position]
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
|
||||||
|
val publishTimeToDisplay = if (useAbsoluteTime) {
|
||||||
|
absoluteTimeFormatter.format(item.publishedAt, shortFormat = item.allDay)
|
||||||
|
} else {
|
||||||
|
getRelativeTimeSpanString(holder.binding.root.context, item.publishedAt.time, now)
|
||||||
|
}
|
||||||
|
|
||||||
|
val updatedAtText = if (item.updatedAt.equalByMinute(item.publishedAt)) {
|
||||||
|
// they're the same, don't show the "updated" indicator
|
||||||
|
""
|
||||||
|
} else {
|
||||||
|
// they're a minute or more apart, show the "updated" indicator
|
||||||
|
val formattedUpdatedAt = if (useAbsoluteTime) {
|
||||||
|
absoluteTimeFormatter.format(item.updatedAt, item.allDay)
|
||||||
|
} else {
|
||||||
|
getRelativeTimeSpanString(holder.binding.root.context, item.updatedAt.time, now)
|
||||||
|
}
|
||||||
|
holder.binding.root.context.getString(R.string.announcement_date_updated, formattedUpdatedAt)
|
||||||
|
}
|
||||||
|
|
||||||
|
val announcementDate = holder.binding.root.context.getString(R.string.announcement_date, publishTimeToDisplay, updatedAtText)
|
||||||
|
holder.binding.announcementDate.text = announcementDate
|
||||||
|
|
||||||
val text = holder.binding.text
|
val text = holder.binding.text
|
||||||
val chips = holder.binding.chipGroup
|
val chips = holder.binding.chipGroup
|
||||||
|
@ -88,7 +116,8 @@ class AnnouncementAdapter(
|
||||||
)
|
)
|
||||||
.apply {
|
.apply {
|
||||||
if (reaction.url == null) {
|
if (reaction.url == null) {
|
||||||
this.text = "${reaction.name} ${reaction.count}"
|
val reactionNameAndCountText = holder.binding.root.context.getString(R.string.reaction_name_and_count, reaction.name, reaction.count)
|
||||||
|
this.text = reactionNameAndCountText
|
||||||
} else {
|
} else {
|
||||||
// we set the EmojiSpan on a space, because otherwise the Chip won't have the right size
|
// we set the EmojiSpan on a space, because otherwise the Chip won't have the right size
|
||||||
// https://github.com/tuskyapp/Tusky/issues/2308
|
// https://github.com/tuskyapp/Tusky/issues/2308
|
||||||
|
|
|
@ -98,8 +98,9 @@ class AnnouncementsActivity :
|
||||||
|
|
||||||
val wellbeingEnabled = sharedPreferencesRepository.getBoolean(PrefKeys.WELLBEING_HIDE_STATS_POSTS, false)
|
val wellbeingEnabled = sharedPreferencesRepository.getBoolean(PrefKeys.WELLBEING_HIDE_STATS_POSTS, false)
|
||||||
val animateEmojis = sharedPreferencesRepository.getBoolean(PrefKeys.ANIMATE_CUSTOM_EMOJIS, false)
|
val animateEmojis = sharedPreferencesRepository.getBoolean(PrefKeys.ANIMATE_CUSTOM_EMOJIS, false)
|
||||||
|
val useAbsoluteTime = sharedPreferencesRepository.getBoolean(PrefKeys.ABSOLUTE_TIME_VIEW, false)
|
||||||
|
|
||||||
adapter = AnnouncementAdapter(emptyList(), this, wellbeingEnabled, animateEmojis)
|
adapter = AnnouncementAdapter(emptyList(), this, wellbeingEnabled, animateEmojis, useAbsoluteTime)
|
||||||
|
|
||||||
binding.announcementsList.adapter = adapter
|
binding.announcementsList.adapter = adapter
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
package app.pachli.util
|
||||||
|
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares this [Date] with [other], and returns true if they are equal to within the same
|
||||||
|
* minute.
|
||||||
|
*
|
||||||
|
* "Same minute" means "they are within the same clock minute", not "they are within 60 seconds
|
||||||
|
* of each other".
|
||||||
|
*/
|
||||||
|
fun Date.equalByMinute(other: Date): Boolean {
|
||||||
|
return this.minutes == other.minutes &&
|
||||||
|
this.hours == other.hours &&
|
||||||
|
this.date == other.date &&
|
||||||
|
this.month == other.month &&
|
||||||
|
this.year == other.year
|
||||||
|
}
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/text"
|
android:id="@+id/text"
|
||||||
|
android:textIsSelectable="true"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:lineSpacingMultiplier="1.1"
|
android:lineSpacingMultiplier="1.1"
|
||||||
|
@ -22,7 +23,8 @@
|
||||||
android:padding="8dp"
|
android:padding="8dp"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/text">
|
app:layout_constraintTop_toBottomOf="@id/text"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/announcementDate">
|
||||||
|
|
||||||
<com.google.android.material.chip.Chip
|
<com.google.android.material.chip.Chip
|
||||||
android:id="@+id/addReactionChip"
|
android:id="@+id/addReactionChip"
|
||||||
|
@ -39,4 +41,16 @@
|
||||||
|
|
||||||
</com.google.android.material.chip.ChipGroup>
|
</com.google.android.material.chip.ChipGroup>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/announcementDate"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingHorizontal="8dp"
|
||||||
|
android:paddingBottom="8dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/chipGroup"
|
||||||
|
/>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
|
@ -745,6 +745,8 @@
|
||||||
<string name="pachli_compose_post_quicksetting_label">Compose Post</string>
|
<string name="pachli_compose_post_quicksetting_label">Compose Post</string>
|
||||||
|
|
||||||
<string name="account_date_joined">Joined %1$s</string>
|
<string name="account_date_joined">Joined %1$s</string>
|
||||||
|
<string name="announcement_date_updated">(Updated: %1$s)</string>
|
||||||
|
<string name="announcement_date">%1$s %2$s</string>
|
||||||
|
|
||||||
<string name="saving_draft">Saving draft…</string>
|
<string name="saving_draft">Saving draft…</string>
|
||||||
|
|
||||||
|
@ -824,4 +826,6 @@
|
||||||
<string name="dialog_delete_filter_text">Delete filter \'%1$s\'?"</string>
|
<string name="dialog_delete_filter_text">Delete filter \'%1$s\'?"</string>
|
||||||
<string name="dialog_delete_filter_positive_action">Delete</string>
|
<string name="dialog_delete_filter_positive_action">Delete</string>
|
||||||
<string name="dialog_save_profile_changes_message">Do you want to save your profile changes?</string>
|
<string name="dialog_save_profile_changes_message">Do you want to save your profile changes?</string>
|
||||||
|
|
||||||
|
<string name="reaction_name_and_count">%1$s %2$d</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in New Issue