Highlight your own votes when displaying poll results (#2242)

* Highlight your own votes when displaying poll results

* Unbreak tests

* Add a checkmark to the description of self-voted options
This commit is contained in:
Levi Bard 2021-09-17 22:12:17 +02:00 committed by GitHub
parent 45598cf047
commit d07c1b098e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 47 additions and 15 deletions

View File

@ -18,8 +18,10 @@ package com.keylesspalace.tusky.adapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.emoji.text.EmojiCompat
import androidx.recyclerview.widget.RecyclerView
import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.databinding.ItemPollBinding
import com.keylesspalace.tusky.entity.Emoji
import com.keylesspalace.tusky.util.BindingHolder
@ -85,13 +87,19 @@ class PollAdapter : RecyclerView.Adapter<BindingHolder<ItemPollBinding>>() {
when (mode) {
RESULT -> {
val percent = calculatePercent(option.votesCount, votersCount, voteCount)
val emojifiedPollOptionText = buildDescription(option.title, percent, resultTextView.context)
val emojifiedPollOptionText = buildDescription(option.title, percent, option.voted, resultTextView.context)
.emojify(emojis, resultTextView, animateEmojis)
resultTextView.text = EmojiCompat.get().process(emojifiedPollOptionText)
val level = percent * 100
val optionColor = if (option.voted) {
R.color.colorBackgroundHighlight
} else {
R.color.colorBackgroundAccent
}
resultTextView.background.level = level
resultTextView.background.setTint(ContextCompat.getColor(resultTextView.context, optionColor))
resultTextView.setOnClickListener(resultClickListener)
}
SINGLE -> {

View File

@ -889,7 +889,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
for (int i = 0; i < args.length; i++) {
if (i < options.size()) {
int percent = PollViewDataKt.calculatePercent(options.get(i).getVotesCount(), poll.getVotersCount(), poll.getVotesCount());
args[i] = buildDescription(options.get(i).getTitle(), percent, context);
args[i] = buildDescription(options.get(i).getTitle(), percent, options.get(i).getVoted(), context);
} else {
args[i] = "";
}

View File

@ -659,9 +659,12 @@ public class NotificationHelper {
StringBuilder builder = new StringBuilder(notification.getStatus().getContent());
builder.append('\n');
Poll poll = notification.getStatus().getPoll();
for(PollOption option: poll.getOptions()) {
List<PollOption> options = poll.getOptions();
for(int i = 0; i < options.size(); ++i) {
PollOption option = options.get(i);
builder.append(buildDescription(option.getTitle(),
PollViewDataKt.calculatePercent(option.getVotesCount(), poll.getVotersCount(), poll.getVotesCount()),
poll.getOwnVotes() != null && poll.getOwnVotes().contains(i),
context));
builder.append('\n');
}

View File

@ -11,7 +11,8 @@ data class Poll(
@SerializedName("votes_count") val votesCount: Int,
@SerializedName("voters_count") val votersCount: Int?, // nullable for compatibility with Pleroma
val options: List<PollOption>,
val voted: Boolean
val voted: Boolean,
@SerializedName("own_votes") val ownVotes: List<Int>?
) {
fun votedCopy(choices: List<Int>): Poll {

View File

@ -23,6 +23,7 @@ import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat
import com.bumptech.glide.Glide
import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.entity.Attachment
@ -310,13 +311,19 @@ class StatusViewHelper(private val itemView: View) {
if (i < options.size) {
val percent = calculatePercent(options[i].votesCount, poll.votersCount, poll.votesCount)
val pollOptionText = buildDescription(options[i].title, percent, pollResults[i].context)
val pollOptionText = buildDescription(options[i].title, percent, options[i].voted, pollResults[i].context)
pollResults[i].text = pollOptionText.emojify(emojis, pollResults[i], animateEmojis)
pollResults[i].visibility = View.VISIBLE
val level = percent * 100
val optionColor = if (options[i].voted) {
R.color.colorBackgroundHighlight
} else {
R.color.colorBackgroundAccent
}
pollResults[i].background.level = level
pollResults[i].background.setTint(ContextCompat.getColor(pollResults[i].context, optionColor))
} else {
pollResults[i].visibility = View.GONE
}

View File

@ -39,7 +39,8 @@ data class PollViewData(
data class PollOptionViewData(
val title: String,
var votesCount: Int,
var selected: Boolean
var selected: Boolean,
var voted: Boolean
)
fun calculatePercent(fraction: Int, totalVoters: Int?, totalVotes: Int): Int {
@ -51,10 +52,14 @@ fun calculatePercent(fraction: Int, totalVoters: Int?, totalVotes: Int): Int {
}
}
fun buildDescription(title: String, percent: Int, context: Context): Spanned {
return SpannableStringBuilder(context.getString(R.string.poll_percent_format, percent).parseAsHtml())
.append(" ")
.append(title)
fun buildDescription(title: String, percent: Int, voted: Boolean, context: Context): Spanned {
val builder = SpannableStringBuilder(context.getString(R.string.poll_percent_format, percent).parseAsHtml())
if (voted) {
builder.append("")
} else {
builder.append(" ")
}
return builder.append(title)
}
fun Poll?.toViewData(): PollViewData? {
@ -66,15 +71,16 @@ fun Poll?.toViewData(): PollViewData? {
multiple = multiple,
votesCount = votesCount,
votersCount = votersCount,
options = options.map { it.toViewData() },
voted = voted
options = options.mapIndexed { index, option -> option.toViewData(ownVotes?.contains(index) == true) },
voted = voted,
)
}
fun PollOption.toViewData(): PollOptionViewData {
fun PollOption.toViewData(voted: Boolean): PollOptionViewData {
return PollOptionViewData(
title = title,
votesCount = votesCount,
selected = false
selected = false,
voted = voted
)
}

View File

@ -15,6 +15,7 @@
<color name="iconColor">@color/tusky_grey_70</color>
<color name="colorBackgroundAccent">@color/tusky_grey_30</color>
<color name="colorBackgroundHighlight">@color/tusky_grey_50</color>
<color name="dividerColor">@color/tusky_grey_25</color>
<color name="favoriteButtonActiveColor">@color/tusky_orange</color>

View File

@ -10,6 +10,7 @@
<!--Themed Attributes-->
<attr name="colorBackgroundAccent" format="reference|color" />
<attr name="colorBackgroundHighlight" format="reference|color" />
<attr name="textColorDisabled" format="reference|color" />
<attr name="iconColor" format="reference|color" />
<attr name="windowBackgroundColor" format="reference|color" />

View File

@ -54,6 +54,7 @@
<item name="android:colorBackground">@color/colorBackground</item>
<item name="colorBackgroundAccent">@color/colorBackgroundAccent</item>
<item name="colorBackgroundHighlight">@color/colorBackgroundHighlight</item>
<item name="windowBackgroundColor">@color/windowBackground</item>
<item name="android:textColorPrimary">@color/textColorPrimary</item>
@ -142,6 +143,7 @@
<item name="colorSurface">@color/tusky_grey_10</item>
<item name="iconColor">@color/tusky_grey_40</item>
<item name="colorBackgroundHighlight">@color/tusky_grey_40</item>
<item name="colorBackgroundAccent">@color/tusky_grey_20</item>
<item name="dividerColor">@color/tusky_grey_10</item>

View File

@ -15,6 +15,7 @@
<color name="iconColor">@color/tusky_grey_50</color>
<color name="colorBackgroundAccent">@color/tusky_grey_70</color>
<color name="colorBackgroundHighlight">@color/tusky_grey_50</color>
<color name="dividerColor">@color/tusky_grey_80</color>
<color name="favoriteButtonActiveColor">@color/tusky_orange_light</color>

View File

@ -173,7 +173,8 @@ class FilterTest {
options = pollOptions.map {
PollOption(it, 0)
},
voted = false
voted = false,
ownVotes = null
)
} else null,
card = null

View File

@ -697,6 +697,7 @@ class TimelineViewModelTest {
votesCount = 1,
voted = false,
options = listOf(PollOption("1", 1), PollOption("2", 2)),
ownVotes = null
)
val status4 = makeStatus("4").copy(poll = poll)
val status3 = makeStatus("3")