From 7ba117ec25f846fc85215c01148fa04e49c993ba Mon Sep 17 00:00:00 2001 From: rebelonion <87634197+rebelonion@users.noreply.github.com> Date: Fri, 23 Feb 2024 18:13:00 -0600 Subject: [PATCH] feat: set comment name color above WCAG Guidelines --- .../dantotsu/media/comments/CommentItem.kt | 69 +++++++++++++++++-- .../media/comments/CommentsActivity.kt | 52 +++++++++++--- app/src/main/res/layout/activity_comments.xml | 1 + 3 files changed, 106 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/ani/dantotsu/media/comments/CommentItem.kt b/app/src/main/java/ani/dantotsu/media/comments/CommentItem.kt index b77386ea8b..462136802a 100644 --- a/app/src/main/java/ani/dantotsu/media/comments/CommentItem.kt +++ b/app/src/main/java/ani/dantotsu/media/comments/CommentItem.kt @@ -27,12 +27,14 @@ import java.text.SimpleDateFormat import java.util.Date import java.util.TimeZone import kotlin.math.abs +import kotlin.math.pow import kotlin.math.sqrt class CommentItem(val comment: Comment, private val markwon: Markwon, private val section: Section, private val commentsActivity: CommentsActivity, + private val backgroundColor: Int ) : BindableItem() { var binding: ItemCommentsBinding? = null val adapter = GroupieAdapter() @@ -162,7 +164,7 @@ class CommentItem(val comment: Comment, viewBinding.commentUserAvatar comment.profilePictureUrl?.let { viewBinding.commentUserAvatar.loadImage(it) } viewBinding.commentUserName.text = comment.username - viewBinding.commentUserName.setTextColor(getAvatarColor(comment.upvotes - comment.downvotes)) + viewBinding.commentUserName.setTextColor(getAvatarColor(comment.upvotes - comment.downvotes, backgroundColor)) viewBinding.commentUserTime.text = "● ${formatTimestamp(comment.timestamp)}" } @@ -236,16 +238,69 @@ class CommentItem(val comment: Comment, } } - private fun getAvatarColor(voteCount: Int): Int { - //0.8x^{2} where x is the level + private fun getLuminance(color: Int): Double { + val r = Color.red(color) / 255.0 + val g = Color.green(color) / 255.0 + val b = Color.blue(color) / 255.0 + + val rL = if (r <= 0.03928) r / 12.92 else ((r + 0.055) / 1.055).pow(2.4) + val gL = if (g <= 0.03928) g / 12.92 else ((g + 0.055) / 1.055).pow(2.4) + val bL = if (b <= 0.03928) b / 12.92 else ((b + 0.055) / 1.055).pow(2.4) + + return 0.2126 * rL + 0.7152 * gL + 0.0722 * bL + } + + private fun getContrastRatio(color1: Int, color2: Int): Double { + val l1 = getLuminance(color1) + val l2 = getLuminance(color2) + + return if (l1 > l2) (l1 + 0.05) / (l2 + 0.05) else (l2 + 0.05) / (l1 + 0.05) + } + + private fun getAvatarColor(voteCount: Int, backgroundColor: Int): Int { val level = sqrt(abs(voteCount.toDouble()) / 0.8).toInt() - return if (level > usernameColors.size - 1) { - Color.parseColor(usernameColors[usernameColors.size - 1]) - } else { - Color.parseColor(usernameColors[level]) + val colorString = if (level > usernameColors.size - 1) usernameColors[usernameColors.size - 1] else usernameColors[level] + var color = Color.parseColor(colorString) + val ratio = getContrastRatio(color, backgroundColor) + if (ratio < 4.5) { + color = adjustColorForContrast(color, backgroundColor) + } + + return color + } + + private fun adjustColorForContrast(originalColor: Int, backgroundColor: Int): Int { + var adjustedColor = originalColor + var contrastRatio = getContrastRatio(adjustedColor, backgroundColor) + val isBackgroundDark = getLuminance(backgroundColor) < 0.5 + + while (contrastRatio < 4.5) { + // Adjust brightness by modifying the RGB values + val r = Color.red(adjustedColor) + val g = Color.green(adjustedColor) + val b = Color.blue(adjustedColor) + + // Calculate the amount to adjust + val adjustment = if (isBackgroundDark) 10 else -10 + + // Adjust the color + val newR = (r + adjustment).coerceIn(0, 255) + val newG = (g + adjustment).coerceIn(0, 255) + val newB = (b + adjustment).coerceIn(0, 255) + + adjustedColor = Color.rgb(newR, newG, newB) + contrastRatio = getContrastRatio(adjustedColor, backgroundColor) + + // Break the loop if the color adjustment does not change (to avoid infinite loop) + if (newR == r && newG == g && newB == b) { + break + } } + return adjustedColor } + + private val usernameColors: Array = arrayOf( "#9932cc", "#a020f0", diff --git a/app/src/main/java/ani/dantotsu/media/comments/CommentsActivity.kt b/app/src/main/java/ani/dantotsu/media/comments/CommentsActivity.kt index a98b1f851b..6c4dc62f7c 100644 --- a/app/src/main/java/ani/dantotsu/media/comments/CommentsActivity.kt +++ b/app/src/main/java/ani/dantotsu/media/comments/CommentsActivity.kt @@ -1,5 +1,6 @@ package ani.dantotsu.media.comments +import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable import android.os.Bundle import android.text.TextWatcher @@ -55,6 +56,7 @@ class CommentsActivity : AppCompatActivity() { private val section = Section() private val adapter = GroupieAdapter() private var mediaId: Int = -1 + private var backgroundColor: Int = 0 var pagesLoaded = 1 var totalPages = 1 @@ -71,6 +73,7 @@ class CommentsActivity : AppCompatActivity() { finish() } this.mediaId = mediaId + backgroundColor = (binding.root.background as? ColorDrawable)?.color ?: 0 val markwon = buildMarkwon() @@ -129,10 +132,15 @@ class CommentsActivity : AppCompatActivity() { popup.show() } - var isFetching = false + var isFetching = false //if we have scrolled to the bottom of the list, load more comments - binding.commentsList.addOnScrollListener(object : androidx.recyclerview.widget.RecyclerView.OnScrollListener() { - override fun onScrolled(recyclerView: androidx.recyclerview.widget.RecyclerView, dx: Int, dy: Int) { + binding.commentsList.addOnScrollListener(object : + androidx.recyclerview.widget.RecyclerView.OnScrollListener() { + override fun onScrolled( + recyclerView: androidx.recyclerview.widget.RecyclerView, + dx: Int, + dy: Int + ) { super.onScrolled(recyclerView, dx, dy) if (shouldLoadMoreComments(recyclerView)) { loadMoreComments() @@ -164,7 +172,15 @@ class CommentsActivity : AppCompatActivity() { private suspend fun updateUIWithComment(comment: Comment) { withContext(Dispatchers.Main) { - section.add(CommentItem(comment, buildMarkwon(), section, this@CommentsActivity)) + section.add( + CommentItem( + comment, + buildMarkwon(), + section, + this@CommentsActivity, + backgroundColor + ) + ) } } }) @@ -215,7 +231,15 @@ class CommentsActivity : AppCompatActivity() { val sortedComments = sortComments(comments?.comments) sortedComments.forEach { withContext(Dispatchers.Main) { - section.add(CommentItem(it, buildMarkwon(), section, this@CommentsActivity)) + section.add( + CommentItem( + it, + buildMarkwon(), + section, + this@CommentsActivity, + backgroundColor + ) + ) } } @@ -309,7 +333,9 @@ class CommentsActivity : AppCompatActivity() { it, buildMarkwon(), comment.repliesSection, - this@CommentsActivity) + this@CommentsActivity, + backgroundColor + ) ) } } @@ -366,7 +392,9 @@ class CommentsActivity : AppCompatActivity() { private suspend fun handleEditComment(commentText: String) { val success = withContext(Dispatchers.IO) { - CommentsAPI.editComment(commentWithInteraction?.comment?.commentId ?: return@withContext false, commentText) + CommentsAPI.editComment( + commentWithInteraction?.comment?.commentId ?: return@withContext false, commentText + ) } if (success) { updateCommentInSection(commentText) @@ -403,12 +431,18 @@ class CommentsActivity : AppCompatActivity() { if (interactionState == InteractionState.REPLY) { commentWithInteraction?.repliesSection?.add( 0, - CommentItem(it, buildMarkwon(), commentWithInteraction!!.repliesSection, this@CommentsActivity) + CommentItem( + it, + buildMarkwon(), + commentWithInteraction!!.repliesSection, + this@CommentsActivity, + backgroundColor + ) ) } else { section.add( 0, - CommentItem(it, buildMarkwon(), section, this@CommentsActivity) + CommentItem(it, buildMarkwon(), section, this@CommentsActivity, backgroundColor) ) } } diff --git a/app/src/main/res/layout/activity_comments.xml b/app/src/main/res/layout/activity_comments.xml index 04f2a927a7..b584d59f38 100644 --- a/app/src/main/res/layout/activity_comments.xml +++ b/app/src/main/res/layout/activity_comments.xml @@ -5,6 +5,7 @@ android:id="@+id/commentsLayout" android:layout_width="match_parent" android:layout_height="match_parent" + android:background="?android:colorBackground" android:fitsSystemWindows="true">