From 3cfb7a0d1ee231b4ba8dc6c16ca0e41392018864 Mon Sep 17 00:00:00 2001 From: sanao Date: Tue, 17 Oct 2023 03:04:30 +0900 Subject: [PATCH] feat: Show announcement dates (#35) (#151) 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 --- .../announcements/AnnouncementAdapter.kt | 31 ++++++++++++++++++- .../announcements/AnnouncementsActivity.kt | 3 +- .../java/app/pachli/util/DateExtensions.kt | 18 +++++++++++ app/src/main/res/layout/item_announcement.xml | 16 +++++++++- app/src/main/res/values/strings.xml | 4 +++ 5 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/app/pachli/util/DateExtensions.kt diff --git a/app/src/main/java/app/pachli/components/announcements/AnnouncementAdapter.kt b/app/src/main/java/app/pachli/components/announcements/AnnouncementAdapter.kt index 8910d6c08..144ac18d3 100644 --- a/app/src/main/java/app/pachli/components/announcements/AnnouncementAdapter.kt +++ b/app/src/main/java/app/pachli/components/announcements/AnnouncementAdapter.kt @@ -27,9 +27,12 @@ import app.pachli.R import app.pachli.databinding.ItemAnnouncementBinding import app.pachli.entity.Announcement import app.pachli.interfaces.LinkListener +import app.pachli.util.AbsoluteTimeFormatter import app.pachli.util.BindingHolder import app.pachli.util.EmojiSpan import app.pachli.util.emojify +import app.pachli.util.equalByMinute +import app.pachli.util.getRelativeTimeSpanString import app.pachli.util.parseAsMastodonHtml import app.pachli.util.setClickableText import app.pachli.util.visible @@ -48,7 +51,9 @@ class AnnouncementAdapter( private val listener: AnnouncementActionListener, private val wellbeingEnabled: Boolean = false, private val animateEmojis: Boolean = false, + private val useAbsoluteTime: Boolean = false, ) : RecyclerView.Adapter>() { + private val absoluteTimeFormatter = AbsoluteTimeFormatter() override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingHolder { val binding = ItemAnnouncementBinding.inflate(LayoutInflater.from(parent.context), parent, false) @@ -57,6 +62,29 @@ class AnnouncementAdapter( override fun onBindViewHolder(holder: BindingHolder, position: Int) { 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 chips = holder.binding.chipGroup @@ -88,7 +116,8 @@ class AnnouncementAdapter( ) .apply { 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 { // we set the EmojiSpan on a space, because otherwise the Chip won't have the right size // https://github.com/tuskyapp/Tusky/issues/2308 diff --git a/app/src/main/java/app/pachli/components/announcements/AnnouncementsActivity.kt b/app/src/main/java/app/pachli/components/announcements/AnnouncementsActivity.kt index 63e8970f9..65f5767dd 100644 --- a/app/src/main/java/app/pachli/components/announcements/AnnouncementsActivity.kt +++ b/app/src/main/java/app/pachli/components/announcements/AnnouncementsActivity.kt @@ -98,8 +98,9 @@ class AnnouncementsActivity : val wellbeingEnabled = sharedPreferencesRepository.getBoolean(PrefKeys.WELLBEING_HIDE_STATS_POSTS, 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 diff --git a/app/src/main/java/app/pachli/util/DateExtensions.kt b/app/src/main/java/app/pachli/util/DateExtensions.kt new file mode 100644 index 000000000..8ce27ec5d --- /dev/null +++ b/app/src/main/java/app/pachli/util/DateExtensions.kt @@ -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 +} diff --git a/app/src/main/res/layout/item_announcement.xml b/app/src/main/res/layout/item_announcement.xml index 4e1d0df0d..b6021f990 100644 --- a/app/src/main/res/layout/item_announcement.xml +++ b/app/src/main/res/layout/item_announcement.xml @@ -6,6 +6,7 @@ + app:layout_constraintTop_toBottomOf="@id/text" + app:layout_constraintBottom_toTopOf="@id/announcementDate"> + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6929167d2..855bbc440 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -745,6 +745,8 @@ Compose Post Joined %1$s + (Updated: %1$s) + %1$s %2$s Saving draft… @@ -824,4 +826,6 @@ Delete filter \'%1$s\'?" Delete Do you want to save your profile changes? + + %1$s %2$d