cook4me/android

View on GitHub
app/src/main/java/ch/epfl/sdp/cook4me/ui/recipe/feed/VoteIcon.kt

Summary

Maintainability
C
7 hrs
Test Coverage
A
91%
package ch.epfl.sdp.cook4me.ui.recipe.feed

import androidx.compose.foundation.layout.Row
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ThumbDown
import androidx.compose.material.icons.filled.ThumbUp
import androidx.compose.material.icons.outlined.ThumbDown
import androidx.compose.material.icons.outlined.ThumbUp
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview

/**
 * Component that shows an upvote/downvote icon (similar to reddit f.ex)
 * @param counterValue the current value of the counter
 * @param onChange the function that will be called when the counter changes, the int parameter is the relative change
 * @param userVote the current vote of the user (0 if none, 1 if upvote, -1 if downvote)
 * @param canClick true if the user can click on the buttons, false otherwise
 * @param uid a unique id for the component (trick to force re-rendering)
 */
@Preview(showBackground = true)
@Composable
fun VoteIcon(
    modifier: Modifier = Modifier,
    counterValue: Int = 0,
    onChange: (Int) -> Unit = {},
    userVote: Int = 0,
    canClick: Boolean = true,
    uid: Int = 0
) {
    val uidRem = remember { mutableStateOf(uid) }
    val upvote = remember { mutableStateOf(userVote == 1) }
    val downvote = remember { mutableStateOf(userVote == -1) }
    val notPressedColor = Color.White
    val pressedColor = Color.Red
    val localCounterValue = remember { mutableStateOf(counterValue) }
    // new uid -> reset the state
    if (uidRem.value != uid) {
        uidRem.value = uid
        upvote.value = userVote == 1
        downvote.value = userVote == -1
        localCounterValue.value = counterValue
    }
    /**
     * Function that is called when the user presses the upvote/downvote button
     * it will update the counter and the buttons color accordingly
     * it also calls the onChange function
     * @param isUpVote true if the upvote button was pressed, false if the downvote button was pressed1
     */
    fun onVote(isUpVote: Boolean) {
        val buttonPressed = if (isUpVote) upvote else downvote
        val otherButton = if (isUpVote) downvote else upvote
        val buttonPressedValue = if (isUpVote) 1 else -1
        // second time pressing the button -> revert the vote
        if (buttonPressed.value) {
            onChange(buttonPressedValue * -1)
            buttonPressed.value = false
            localCounterValue.value -= buttonPressedValue
        } else {
            // other button was pressed -> remove the vote from the other button
            if (otherButton.value) {
                onChange(buttonPressedValue * 2)
                otherButton.value = false
                localCounterValue.value += 2 * buttonPressedValue
            } else {
                onChange(buttonPressedValue * 1)
                localCounterValue.value += buttonPressedValue
            }
            buttonPressed.value = true
        }
    }
    val thumbsUp = if (upvote.value) Icons.Filled.ThumbUp else Icons.Outlined.ThumbUp
    val thumbsDown = if (downvote.value) Icons.Filled.ThumbDown else Icons.Outlined.ThumbDown
    Row(modifier = modifier, verticalAlignment = Alignment.CenterVertically) {
        IconButton(onClick = { onVote(true) }, enabled = canClick) {
            Icon(
                imageVector = thumbsUp,
                contentDescription = "Upvote",
                tint = if (upvote.value) pressedColor else notPressedColor
            )
        }
        Text(text = localCounterValue.value.toString(), color = notPressedColor)
        IconButton(onClick = { onVote(false) }, enabled = canClick) {
            Icon(
                imageVector = thumbsDown,
                contentDescription = "Downvote",
                tint = if (downvote.value) pressedColor else notPressedColor
            )
        }
    }
}