Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show toot stat inline #3413

Merged
merged 17 commits into from
Mar 18, 2023
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import com.keylesspalace.tusky.util.CustomEmojiHelper;
import com.keylesspalace.tusky.util.ImageLoadingHelper;
import com.keylesspalace.tusky.util.LinkHelper;
import com.keylesspalace.tusky.util.NumberUtils;
import com.keylesspalace.tusky.util.StatusDisplayOptions;
import com.keylesspalace.tusky.util.TimestampUtils;
import com.keylesspalace.tusky.util.TouchDelegateHelper;
Expand Down Expand Up @@ -388,10 +389,10 @@ protected void setIsReply(boolean isReply) {

}

private void setReplyCount(int repliesCount) {
protected void setReplyCount(int repliesCount) {
// This label only exists in the non-detailed view (to match the web ui)
if (replyCountLabel != null) {
replyCountLabel.setText((repliesCount > 1 ? replyCountLabel.getContext().getString(R.string.status_count_one_plus) : Integer.toString(repliesCount)));
replyCountLabel.setText(NumberUtils.shortNumber(repliesCount));
}
}

Expand Down Expand Up @@ -626,12 +627,18 @@ protected void setupButtons(final StatusActionListener listener,
avatar.setOnClickListener(profileButtonClickListener);
displayName.setOnClickListener(profileButtonClickListener);

if (replyCountLabel != null) {
replyCountLabel.setVisibility(statusDisplayOptions.showStatsInline() ? View.VISIBLE : View.INVISIBLE);
}

replyButton.setOnClickListener(v -> {
int position = getBindingAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
listener.onReply(position);
}
});


if (reblogButton != null) {
reblogButton.setEventListener((button, buttonState) -> {
// return true to play animation
Expand All @@ -650,6 +657,7 @@ protected void setupButtons(final StatusActionListener listener,
});
}


favouriteButton.setEventListener((button, buttonState) -> {
// return true to play animation
int position = getBindingAdapterPosition();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import com.keylesspalace.tusky.entity.Status;
import com.keylesspalace.tusky.interfaces.StatusActionListener;
import com.keylesspalace.tusky.util.CustomEmojiHelper;
import com.keylesspalace.tusky.util.NumberUtils;
import com.keylesspalace.tusky.util.SmartLengthInputFilter;
import com.keylesspalace.tusky.util.StatusDisplayOptions;
import com.keylesspalace.tusky.util.StringUtils;
Expand All @@ -47,11 +48,15 @@ public class StatusViewHolder extends StatusBaseViewHolder {

private final TextView statusInfo;
private final Button contentCollapseButton;
private final TextView favouritedCountLabel;
private final TextView reblogsCountLabel;

public StatusViewHolder(View itemView) {
super(itemView);
statusInfo = itemView.findViewById(R.id.status_info);
contentCollapseButton = itemView.findViewById(R.id.button_toggle_content);
favouritedCountLabel = itemView.findViewById(R.id.status_favourites_count);
reblogsCountLabel = itemView.findViewById(R.id.status_insets);
}

@Override
Expand All @@ -77,6 +82,12 @@ public void setupWithStatus(@NonNull StatusViewData.Concrete status,
}

}

reblogsCountLabel.setVisibility(statusDisplayOptions.showStatsInline() ? View.VISIBLE : View.INVISIBLE);
favouritedCountLabel.setVisibility(statusDisplayOptions.showStatsInline() ? View.VISIBLE : View.INVISIBLE);
setFavouritedCount(status.getActionable().getFavouritesCount());
setReblogsCount(status.getActionable().getReblogsCount());

super.setupWithStatus(status, listener, statusDisplayOptions, payloads);
}

Expand All @@ -102,6 +113,14 @@ protected void setPollInfo(final boolean ownPoll) {
statusInfo.setVisibility(View.VISIBLE);
}

protected void setReblogsCount(int reblogsCount) {
reblogsCountLabel.setText(NumberUtils.shortNumber(reblogsCount));
}

protected void setFavouritedCount(int favouritedCount) {
favouritedCountLabel.setText(NumberUtils.shortNumber(favouritedCount));
}

protected void hideStatusInfo() {
statusInfo.setVisibility(View.GONE);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ class ConversationsFragment :
confirmFavourites = preferences.getBoolean("confirmFavourites", false),
hideStats = preferences.getBoolean(PrefKeys.WELLBEING_HIDE_STATS_POSTS, false),
animateEmojis = preferences.getBoolean(PrefKeys.ANIMATE_CUSTOM_EMOJIS, false),
showStatsInline = preferences.getBoolean(PrefKeys.SHOW_STATS_INLINE, false),
showSensitiveMedia = accountManager.activeAccount!!.alwaysShowSensitiveMedia,
openSpoiler = accountManager.activeAccount!!.alwaysOpenSpoiler
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ class PreferencesActivity :
}
"statusTextSize", "absoluteTimeView", "showBotOverlay", "animateGifAvatars", "useBlurhash",
"showSelfUsername", "showCardsInTimelines", "confirmReblogs", "confirmFavourites",
"enableSwipeForTabs", "mainNavPosition", PrefKeys.HIDE_TOP_TOOLBAR -> {
"enableSwipeForTabs", "mainNavPosition", PrefKeys.HIDE_TOP_TOOLBAR, PrefKeys.SHOW_STATS_INLINE -> {
restartActivitiesOnBackPressedCallback.isEnabled = true
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,13 @@ class PreferencesFragment : PreferenceFragmentCompat(), Injectable {
setTitle(R.string.pref_title_enable_swipe_for_tabs)
isSingleLineTitle = false
}

switchPreference {
setDefaultValue(false)
key = PrefKeys.SHOW_STATS_INLINE
setTitle(R.string.pref_title_show_stat_inline)
isSingleLineTitle = false
}
}

preferenceCategory(R.string.pref_title_browser_settings) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ class ReportStatusesFragment :
confirmFavourites = preferences.getBoolean("confirmFavourites", false),
hideStats = preferences.getBoolean(PrefKeys.WELLBEING_HIDE_STATS_POSTS, false),
animateEmojis = preferences.getBoolean(PrefKeys.ANIMATE_CUSTOM_EMOJIS, false),
showStatsInline = preferences.getBoolean(PrefKeys.SHOW_STATS_INLINE, false),
showSensitiveMedia = accountManager.activeAccount!!.alwaysShowSensitiveMedia,
openSpoiler = accountManager.activeAccount!!.alwaysOpenSpoiler
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ class SearchStatusesFragment : SearchFragment<StatusViewData.Concrete>(), Status
confirmFavourites = preferences.getBoolean("confirmFavourites", false),
hideStats = preferences.getBoolean(PrefKeys.WELLBEING_HIDE_STATS_POSTS, false),
animateEmojis = preferences.getBoolean(PrefKeys.ANIMATE_CUSTOM_EMOJIS, false),
showStatsInline = preferences.getBoolean(PrefKeys.SHOW_STATS_INLINE, false),
showSensitiveMedia = accountManager.activeAccount!!.alwaysShowSensitiveMedia,
openSpoiler = accountManager.activeAccount!!.alwaysOpenSpoiler
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ class TimelineFragment :
confirmFavourites = preferences.getBoolean(PrefKeys.CONFIRM_FAVOURITES, false),
hideStats = preferences.getBoolean(PrefKeys.WELLBEING_HIDE_STATS_POSTS, false),
animateEmojis = preferences.getBoolean(PrefKeys.ANIMATE_CUSTOM_EMOJIS, false),
showStatsInline = preferences.getBoolean(PrefKeys.SHOW_STATS_INLINE, false),
showSensitiveMedia = accountManager.activeAccount!!.alwaysShowSensitiveMedia,
openSpoiler = accountManager.activeAccount!!.alwaysOpenSpoiler
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ class ViewThreadFragment :
confirmFavourites = preferences.getBoolean("confirmFavourites", false),
hideStats = preferences.getBoolean(PrefKeys.WELLBEING_HIDE_STATS_POSTS, false),
animateEmojis = preferences.getBoolean(PrefKeys.ANIMATE_CUSTOM_EMOJIS, false),
showStatsInline = preferences.getBoolean(PrefKeys.SHOW_STATS_INLINE, false),
showSensitiveMedia = accountManager.activeAccount!!.alwaysShowSensitiveMedia,
openSpoiler = accountManager.activeAccount!!.alwaysOpenSpoiler
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ object PrefKeys {
const val CONFIRM_FAVOURITES = "confirmFavourites"
const val ENABLE_SWIPE_FOR_TABS = "enableSwipeForTabs"
const val ANIMATE_CUSTOM_EMOJIS = "animateCustomEmojis"
const val SHOW_STATS_INLINE = "showStatsInline"

const val CUSTOM_TABS = "customTabs"
const val WELLBEING_LIMITED_NOTIFICATIONS = "wellbeingModeLimitedNotifications"
Expand Down
26 changes: 26 additions & 0 deletions app/src/main/java/com/keylesspalace/tusky/util/NumberUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
@file:JvmName("NumberUtils")

package com.keylesspalace.tusky.util
zikasak marked this conversation as resolved.
Show resolved Hide resolved

import java.text.DecimalFormat
import kotlin.math.abs
import kotlin.math.floor
import kotlin.math.log10
import kotlin.math.pow
import kotlin.math.sign

val shortLetters = arrayOf(' ', 'K', 'M', 'B', 'T', 'P', 'E')

fun shortNumber(number: Number): String {
zikasak marked this conversation as resolved.
Show resolved Hide resolved
val numberAsDouble = number.toDouble()
val nonNegativeValue = abs(numberAsDouble)
var sign = ""
if (numberAsDouble.sign < 0) { sign = "-" }
val value = floor(log10(nonNegativeValue)).toInt()
val base = value / 3
if (value >= 3 && base < shortLetters.size) {
return DecimalFormat("$sign#0.0").format(nonNegativeValue / 10.0.pow((base * 3).toDouble())) + shortLetters[base]
} else {
return DecimalFormat("$sign#,##0").format(nonNegativeValue)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ data class StatusDisplayOptions(
val hideStats: Boolean,
@get:JvmName("animateEmojis")
val animateEmojis: Boolean,
@get:JvmName("showStatsInline")
val showStatsInline: Boolean,
@get:JvmName("showSensitiveMedia")
val showSensitiveMedia: Boolean,
@get:JvmName("openSpoiler")
Expand Down Expand Up @@ -119,6 +121,7 @@ data class StatusDisplayOptions(
confirmReblogs = preferences.getBoolean(PrefKeys.CONFIRM_REBLOGS, true),
confirmFavourites = preferences.getBoolean(PrefKeys.CONFIRM_FAVOURITES, false),
hideStats = preferences.getBoolean(PrefKeys.WELLBEING_HIDE_STATS_POSTS, false),
showStatsInline = preferences.getBoolean(PrefKeys.SHOW_STATS_INLINE, false),
showSensitiveMedia = account.alwaysShowSensitiveMedia,
openSpoiler = account.alwaysOpenSpoiler
)
Expand Down
24 changes: 23 additions & 1 deletion app/src/main/res/layout/item_status.xml
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@
android:id="@+id/status_replies"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="40dp"
android:layout_marginStart="45dp"
android:textSize="?attr/status_text_medium"
app:layout_constraintBottom_toBottomOf="@id/status_reply"
app:layout_constraintStart_toStartOf="@id/status_reply"
Expand All @@ -353,6 +353,17 @@
sparkbutton:primaryColor="@color/tusky_blue"
sparkbutton:secondaryColor="@color/tusky_blue_light" />

<TextView
zikasak marked this conversation as resolved.
Show resolved Hide resolved
android:id="@+id/status_insets"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="45dp"
android:textSize="?attr/status_text_medium"
app:layout_constraintBottom_toBottomOf="@id/status_inset"
app:layout_constraintStart_toStartOf="@id/status_inset"
app:layout_constraintTop_toTopOf="@id/status_inset"
tools:text="1+" />

<at.connyduck.sparkbutton.SparkButton
android:id="@+id/status_favourite"
android:layout_width="52dp"
Expand All @@ -370,6 +381,17 @@
sparkbutton:primaryColor="@color/tusky_orange"
sparkbutton:secondaryColor="@color/tusky_orange_light" />

<TextView
android:id="@+id/status_favourites_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="45dp"
android:textSize="?attr/status_text_medium"
app:layout_constraintBottom_toBottomOf="@id/status_inset"
app:layout_constraintStart_toStartOf="@id/status_favourite"
app:layout_constraintTop_toTopOf="@id/status_inset"
tools:text="" />

<at.connyduck.sparkbutton.SparkButton
android:id="@+id/status_bookmark"
android:layout_width="52dp"
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,7 @@

<string name="pref_title_show_notifications_filter">Show Notifications filter</string>
<string name="pref_title_enable_swipe_for_tabs">Enable swipe gesture to switch between tabs</string>
<string name="pref_title_show_stat_inline">Show post statistics in timeline</string>


<string name="create_poll_title">Poll</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class NotificationsViewModelTestStatusDisplayOptions : NotificationsViewModelTes
confirmFavourites = false,
hideStats = false,
animateEmojis = false,
showStatsInline = false,
showSensitiveMedia = true, // setting in NotificationsViewModelTestBase
openSpoiler = true // setting in NotificationsViewModelTestBase
)
Expand Down
49 changes: 49 additions & 0 deletions app/src/test/java/com/keylesspalace/tusky/util/NumberUtilsTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.keylesspalace.tusky.util

import org.junit.Assert
import org.junit.Test
import kotlin.math.pow

class NumberUtilsTest {

@Test
fun zeroShouldBeFormattedAsZero() {
val shortNumber = shortNumber(0)
Assert.assertEquals("0", shortNumber)
}

@Test
fun negativeValueShouldBeFormattedToNegativeValue() {
val shortNumber = shortNumber(-1)
Assert.assertEquals("-1", shortNumber)
}

@Test
fun positiveValueShouldBeFormattedToPositiveValue() {
val shortNumber = shortNumber(1)
Assert.assertEquals("1", shortNumber)
}

@Test
fun bigNumbersShouldBeShortened() {
var shortNumber = 1L
Assert.assertEquals("1", shortNumber(shortNumber))
for (i in shortLetters.indices) {
if (i == 0) {
continue
}
shortNumber = 1000.0.pow(i.toDouble()).toLong()
Assert.assertEquals("1.0" + shortLetters[i], shortNumber(shortNumber))
}
}

@Test
fun roundingForNegativeAndPositiveValuesShouldBeTheSame() {
var value = 3492
Assert.assertEquals("-3.5K", shortNumber(-value))
Assert.assertEquals("3.5K", shortNumber(value))
value = 1501
Assert.assertEquals("-1.5K", shortNumber(-value))
Assert.assertEquals("1.5K", shortNumber(value))
}
}