Skip to content

Commit

Permalink
refactor(m3): OpenFeedback components more customizable.
Browse files Browse the repository at this point in the history
* Be able to customize horizontal/vertical arrangement with OpenFeedbackLayout.
* Be able to customize a custom VoteCard with OpenFeedbackLayout.
* Use 2 or 4 columns according to the device orientation.
  • Loading branch information
GerardPaligot committed Nov 1, 2023
1 parent 159a211 commit 7fc6377
Show file tree
Hide file tree
Showing 3 changed files with 173 additions and 37 deletions.
Original file line number Diff line number Diff line change
@@ -1,23 +1,32 @@
package io.openfeedback.android.m3

import android.content.res.Configuration
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import io.openfeedback.android.FirebaseConfig
import io.openfeedback.android.viewmodels.OpenFeedbackUiState
import io.openfeedback.android.viewmodels.OpenFeedbackViewModel
import io.openfeedback.android.viewmodels.models.UIDot
import io.openfeedback.android.viewmodels.models.UISessionFeedback
import io.openfeedback.android.viewmodels.models.UIVoteItem

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun OpenFeedback(
config: FirebaseConfig,
Expand All @@ -27,6 +36,7 @@ fun OpenFeedback(
modifier: Modifier = Modifier,
loading: @Composable () -> Unit = { Loading(modifier = modifier) }
) {
val configuration = LocalConfiguration.current
val context = LocalContext.current
val viewModel: OpenFeedbackViewModel = viewModel(
factory = OpenFeedbackViewModel.Factory.create(
Expand All @@ -37,6 +47,7 @@ fun OpenFeedback(
language = language
)
)
val columnCount = if (configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) 4 else 2
val uiState = viewModel.uiState.collectAsState()
when (uiState.value) {
is OpenFeedbackUiState.Loading -> loading()
Expand All @@ -45,7 +56,16 @@ fun OpenFeedback(
OpenFeedbackLayout(
sessionFeedback = session,
modifier = modifier,
onClick = { voteItem -> viewModel.vote(voteItem = voteItem) }
columnCount = columnCount,
content = {
VoteCard(
voteModel = it,
onClick = { voteItem -> viewModel.vote(voteItem = voteItem) },
modifier = Modifier
.height(100.dp)
.fillMaxWidth()
)
}
)
}
}
Expand All @@ -56,10 +76,19 @@ fun OpenFeedback(
fun OpenFeedbackLayout(
sessionFeedback: UISessionFeedback,
modifier: Modifier = Modifier,
onClick: (voteItem: UIVoteItem) -> Unit
columnCount: Int = 2,
horizontalArrangement: Arrangement.Horizontal = Arrangement.spacedBy(8.dp),
verticalArrangement: Arrangement.Vertical = Arrangement.spacedBy(8.dp),
content: @Composable ColumnScope.(UIVoteItem) -> Unit
) {
Column(modifier = modifier) {
VoteItems(voteItems = sessionFeedback.voteItem, onClick = onClick)
VoteItems(
voteItems = sessionFeedback.voteItem,
columnCount = columnCount,
horizontalArrangement = horizontalArrangement,
verticalArrangement = verticalArrangement,
content = content
)
Box(
modifier = Modifier
.fillMaxWidth()
Expand All @@ -70,3 +99,40 @@ fun OpenFeedbackLayout(
}
}
}

@OptIn(ExperimentalMaterial3Api::class)
@Preview
@Composable
private fun OpenFeedbackLayoutPreview() {
MaterialTheme {
OpenFeedbackLayout(
sessionFeedback = UISessionFeedback(
comments = emptyList(),
listOf(
UIVoteItem(
id = "",
text = "Fun",
dots = listOf(UIDot(x = .5f, y = .5f, color = "FF00CC")),
votedByUser = true
),
UIVoteItem(
id = "",
text = "Fun",
dots = listOf(UIDot(x = .5f, y = .5f, color = "FF00CC")),
votedByUser = true
)
)
),
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
VoteCard(
voteModel = it,
onClick = {},
modifier = Modifier
.height(100.dp)
.fillMaxWidth()
)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,33 +1,35 @@
package io.openfeedback.android.m3

import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.contentColorFor
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.drawscope.Fill
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import io.openfeedback.android.viewmodels.models.UIDot
import io.openfeedback.android.viewmodels.models.UIVoteItem

@ExperimentalMaterial3Api
@Composable
internal fun VoteCard(
fun VoteCard(
voteModel: UIVoteItem,
modifier: Modifier = Modifier,
style: TextStyle = MaterialTheme.typography.bodyMedium,
backgroundColor: Color = MaterialTheme.colorScheme.surface,
contentColor: Color = MaterialTheme.colorScheme.onSurface,
contentColor: Color = contentColorFor(backgroundColor = backgroundColor),
shape: Shape = MaterialTheme.shapes.medium,
onClick: (voteItem: UIVoteItem) -> Unit
) {
Expand All @@ -39,23 +41,32 @@ internal fun VoteCard(
modifier = modifier,
onClick = { onClick(voteModel) }
) {
Box(modifier = Modifier.height(100.dp)) {
Canvas(modifier = Modifier.fillMaxSize()) {
voteModel.dots.forEach { dot ->
val offset = Offset(x = this.size.width * dot.x, y = this.size.height * dot.y)
drawCircle(
color = Color(
dot.color.substring(0, 2).toInt(16),
dot.color.substring(2, 4).toInt(16),
dot.color.substring(4, 6).toInt(16),
255 / 3
),
radius = 30.dp.value,
center = offset,
style = Fill
)
Box(
modifier = Modifier
.drawBehind {
voteModel.dots.forEach { dot ->
val offset =
Offset(x = this.size.width * dot.x, y = this.size.height * dot.y)
drawCircle(
color = Color(
dot.color
.substring(0, 2)
.toInt(16),
dot.color
.substring(2, 4)
.toInt(16),
dot.color
.substring(4, 6)
.toInt(16),
255 / 3
),
radius = 30.dp.value,
center = offset,
style = Fill
)
}
}
}
) {
Text(
text = voteModel.text,
style = style,
Expand All @@ -65,3 +76,21 @@ internal fun VoteCard(
}
}
}

@OptIn(ExperimentalMaterial3Api::class)
@Preview
@Composable
private fun VoteCardPreview() {
MaterialTheme {
VoteCard(
voteModel = UIVoteItem(
id = "",
text = "Fun",
dots = listOf(UIDot(x = .5f, y = .5f, color = "FF00CC")),
votedByUser = true
),
onClick = {},
modifier = Modifier.size(height = 100.dp, width = 200.dp)
)
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
package io.openfeedback.android.m3

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import io.openfeedback.android.viewmodels.models.UIDot
import io.openfeedback.android.viewmodels.models.UIVoteItem

@ExperimentalMaterial3Api
Expand All @@ -16,26 +21,62 @@ internal fun VoteItems(
voteItems: List<UIVoteItem>,
modifier: Modifier = Modifier,
columnCount: Int = 2,
onClick: (voteItem: UIVoteItem) -> Unit
horizontalArrangement: Arrangement.Horizontal = Arrangement.spacedBy(8.dp),
verticalArrangement: Arrangement.Vertical = Arrangement.spacedBy(8.dp),
content: @Composable ColumnScope.(UIVoteItem) -> Unit
) {
val spaceGrid = 8.dp
Row(
modifier = modifier,
horizontalArrangement = Arrangement.spacedBy(spaceGrid)
horizontalArrangement = horizontalArrangement
) {
0.until(columnCount).forEach { column ->
Box(modifier = Modifier.weight(1f)) {
Column(verticalArrangement = Arrangement.spacedBy(spaceGrid)) {
voteItems.filterIndexed { index, _ ->
Column(
verticalArrangement = verticalArrangement,
modifier = Modifier.weight(1f)
) {
voteItems
.filterIndexed { index, _ ->
index % columnCount == column
}.forEach { voteItem ->
VoteCard(
voteModel = voteItem,
onClick = onClick
)
}
}
.forEach { voteItem ->
content(voteItem)
}
}
}
}
}

@OptIn(ExperimentalMaterial3Api::class)
@Preview
@Composable
private fun VoteItemsPreview() {
MaterialTheme {
VoteItems(
voteItems = listOf(
UIVoteItem(
id = "",
text = "Fun",
dots = listOf(UIDot(x = .5f, y = .5f, color = "FF00CC")),
votedByUser = true
),
UIVoteItem(
id = "",
text = "Fun",
dots = listOf(UIDot(x = .5f, y = .5f, color = "FF00CC")),
votedByUser = true
)
),
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
content = {
VoteCard(
voteModel = it,
onClick = {},
modifier = Modifier
.height(100.dp)
.fillMaxWidth()
)
}
)
}
}

0 comments on commit 7fc6377

Please sign in to comment.