mirror of
https://github.com/msfjarvis/compose-lobsters
synced 2025-08-14 19:57:04 +05:30
common: initial commit of LobstersItem
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
This commit is contained in:
parent
9cb43dec7a
commit
284dd8c67a
4 changed files with 553 additions and 7 deletions
|
@ -21,16 +21,13 @@ kotlin {
|
||||||
api(compose.runtime)
|
api(compose.runtime)
|
||||||
api(compose.foundation)
|
api(compose.foundation)
|
||||||
api(compose.material)
|
api(compose.material)
|
||||||
|
api(projects.database)
|
||||||
|
implementation("com.alialbaali.kamel:kamel-image:0.2.1")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val commonTest by getting { dependencies { implementation(kotlin("test")) } }
|
val commonTest by getting { dependencies { implementation(kotlin("test")) } }
|
||||||
val androidMain by getting {
|
val androidMain by getting
|
||||||
dependencies {
|
val androidTest by getting
|
||||||
api("androidx.appcompat:appcompat:1.4.0-alpha02")
|
|
||||||
api("androidx.core:core-ktx:1.6.0-beta02")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val androidTest by getting { dependencies { implementation("junit:junit:4.13.2") } }
|
|
||||||
val desktopMain by getting
|
val desktopMain by getting
|
||||||
val desktopTest by getting
|
val desktopTest by getting
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,306 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.google.accompanist.flowlayout
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.layout.Layout
|
||||||
|
import androidx.compose.ui.layout.Placeable
|
||||||
|
import androidx.compose.ui.unit.Constraints
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
import androidx.compose.ui.unit.IntSize
|
||||||
|
import androidx.compose.ui.unit.LayoutDirection
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A composable that places its children in a horizontal flow. Unlike [Row], if the horizontal space
|
||||||
|
* is too small to put all the children in one row, multiple rows may be used.
|
||||||
|
*
|
||||||
|
* Note that just like [Row], flex values cannot be used with [FlowRow].
|
||||||
|
*
|
||||||
|
* @param modifier The modifier to be applied to the FlowRow.
|
||||||
|
* @param mainAxisSize The size of the layout in the main axis direction.
|
||||||
|
* @param mainAxisAlignment The alignment of each row's children in the main axis direction.
|
||||||
|
* @param mainAxisSpacing The main axis spacing between the children of each row.
|
||||||
|
* @param crossAxisAlignment The alignment of each row's children in the cross axis direction.
|
||||||
|
* @param crossAxisSpacing The cross axis spacing between the rows of the layout.
|
||||||
|
* @param lastLineMainAxisAlignment Overrides the main axis alignment of the last row.
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
public fun FlowRow(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
mainAxisSize: SizeMode = SizeMode.Wrap,
|
||||||
|
mainAxisAlignment: FlowMainAxisAlignment = FlowMainAxisAlignment.Start,
|
||||||
|
mainAxisSpacing: Dp = 0.dp,
|
||||||
|
crossAxisAlignment: FlowCrossAxisAlignment = FlowCrossAxisAlignment.Start,
|
||||||
|
crossAxisSpacing: Dp = 0.dp,
|
||||||
|
lastLineMainAxisAlignment: FlowMainAxisAlignment = mainAxisAlignment,
|
||||||
|
content: @Composable () -> Unit
|
||||||
|
) {
|
||||||
|
Flow(
|
||||||
|
modifier = modifier,
|
||||||
|
orientation = LayoutOrientation.Horizontal,
|
||||||
|
mainAxisSize = mainAxisSize,
|
||||||
|
mainAxisAlignment = mainAxisAlignment,
|
||||||
|
mainAxisSpacing = mainAxisSpacing,
|
||||||
|
crossAxisAlignment = crossAxisAlignment,
|
||||||
|
crossAxisSpacing = crossAxisSpacing,
|
||||||
|
lastLineMainAxisAlignment = lastLineMainAxisAlignment,
|
||||||
|
content = content
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A composable that places its children in a vertical flow. Unlike [Column], if the vertical space
|
||||||
|
* is too small to put all the children in one column, multiple columns may be used.
|
||||||
|
*
|
||||||
|
* Note that just like [Column], flex values cannot be used with [FlowColumn].
|
||||||
|
*
|
||||||
|
* @param modifier The modifier to be applied to the FlowColumn.
|
||||||
|
* @param mainAxisSize The size of the layout in the main axis direction.
|
||||||
|
* @param mainAxisAlignment The alignment of each column's children in the main axis direction.
|
||||||
|
* @param mainAxisSpacing The main axis spacing between the children of each column.
|
||||||
|
* @param crossAxisAlignment The alignment of each column's children in the cross axis direction.
|
||||||
|
* @param crossAxisSpacing The cross axis spacing between the columns of the layout.
|
||||||
|
* @param lastLineMainAxisAlignment Overrides the main axis alignment of the last column.
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
public fun FlowColumn(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
mainAxisSize: SizeMode = SizeMode.Wrap,
|
||||||
|
mainAxisAlignment: FlowMainAxisAlignment = FlowMainAxisAlignment.Start,
|
||||||
|
mainAxisSpacing: Dp = 0.dp,
|
||||||
|
crossAxisAlignment: FlowCrossAxisAlignment = FlowCrossAxisAlignment.Start,
|
||||||
|
crossAxisSpacing: Dp = 0.dp,
|
||||||
|
lastLineMainAxisAlignment: FlowMainAxisAlignment = mainAxisAlignment,
|
||||||
|
content: @Composable () -> Unit
|
||||||
|
) {
|
||||||
|
Flow(
|
||||||
|
modifier = modifier,
|
||||||
|
orientation = LayoutOrientation.Vertical,
|
||||||
|
mainAxisSize = mainAxisSize,
|
||||||
|
mainAxisAlignment = mainAxisAlignment,
|
||||||
|
mainAxisSpacing = mainAxisSpacing,
|
||||||
|
crossAxisAlignment = crossAxisAlignment,
|
||||||
|
crossAxisSpacing = crossAxisSpacing,
|
||||||
|
lastLineMainAxisAlignment = lastLineMainAxisAlignment,
|
||||||
|
content = content
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Used to specify the alignment of a layout's children, in cross axis direction. */
|
||||||
|
public enum class FlowCrossAxisAlignment {
|
||||||
|
/** Place children such that their center is in the middle of the cross axis. */
|
||||||
|
Center,
|
||||||
|
/** Place children such that their start edge is aligned to the start edge of the cross axis. */
|
||||||
|
Start,
|
||||||
|
/** Place children such that their end edge is aligned to the end edge of the cross axis. */
|
||||||
|
End,
|
||||||
|
}
|
||||||
|
|
||||||
|
public typealias FlowMainAxisAlignment = MainAxisAlignment
|
||||||
|
|
||||||
|
/** Layout model that arranges its children in a horizontal or vertical flow. */
|
||||||
|
@Composable
|
||||||
|
private fun Flow(
|
||||||
|
modifier: Modifier,
|
||||||
|
orientation: LayoutOrientation,
|
||||||
|
mainAxisSize: SizeMode,
|
||||||
|
mainAxisAlignment: FlowMainAxisAlignment,
|
||||||
|
mainAxisSpacing: Dp,
|
||||||
|
crossAxisAlignment: FlowCrossAxisAlignment,
|
||||||
|
crossAxisSpacing: Dp,
|
||||||
|
lastLineMainAxisAlignment: FlowMainAxisAlignment,
|
||||||
|
content: @Composable () -> Unit
|
||||||
|
) {
|
||||||
|
fun Placeable.mainAxisSize() = if (orientation == LayoutOrientation.Horizontal) width else height
|
||||||
|
fun Placeable.crossAxisSize() = if (orientation == LayoutOrientation.Horizontal) height else width
|
||||||
|
|
||||||
|
Layout(content, modifier) { measurables, outerConstraints ->
|
||||||
|
val sequences = mutableListOf<List<Placeable>>()
|
||||||
|
val crossAxisSizes = mutableListOf<Int>()
|
||||||
|
val crossAxisPositions = mutableListOf<Int>()
|
||||||
|
|
||||||
|
var mainAxisSpace = 0
|
||||||
|
var crossAxisSpace = 0
|
||||||
|
|
||||||
|
val currentSequence = mutableListOf<Placeable>()
|
||||||
|
var currentMainAxisSize = 0
|
||||||
|
var currentCrossAxisSize = 0
|
||||||
|
|
||||||
|
val constraints = OrientationIndependentConstraints(outerConstraints, orientation)
|
||||||
|
|
||||||
|
val childConstraints =
|
||||||
|
if (orientation == LayoutOrientation.Horizontal) {
|
||||||
|
Constraints(maxWidth = constraints.mainAxisMax)
|
||||||
|
} else {
|
||||||
|
Constraints(maxHeight = constraints.mainAxisMax)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return whether the placeable can be added to the current sequence.
|
||||||
|
fun canAddToCurrentSequence(placeable: Placeable) =
|
||||||
|
currentSequence.isEmpty() ||
|
||||||
|
currentMainAxisSize + mainAxisSpacing.roundToPx() + placeable.mainAxisSize() <=
|
||||||
|
constraints.mainAxisMax
|
||||||
|
|
||||||
|
// Store current sequence information and start a new sequence.
|
||||||
|
fun startNewSequence() {
|
||||||
|
if (sequences.isNotEmpty()) {
|
||||||
|
crossAxisSpace += crossAxisSpacing.roundToPx()
|
||||||
|
}
|
||||||
|
sequences += currentSequence.toList()
|
||||||
|
crossAxisSizes += currentCrossAxisSize
|
||||||
|
crossAxisPositions += crossAxisSpace
|
||||||
|
|
||||||
|
crossAxisSpace += currentCrossAxisSize
|
||||||
|
mainAxisSpace = max(mainAxisSpace, currentMainAxisSize)
|
||||||
|
|
||||||
|
currentSequence.clear()
|
||||||
|
currentMainAxisSize = 0
|
||||||
|
currentCrossAxisSize = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
for (measurable in measurables) {
|
||||||
|
// Ask the child for its preferred size.
|
||||||
|
val placeable = measurable.measure(childConstraints)
|
||||||
|
|
||||||
|
// Start a new sequence if there is not enough space.
|
||||||
|
if (!canAddToCurrentSequence(placeable)) startNewSequence()
|
||||||
|
|
||||||
|
// Add the child to the current sequence.
|
||||||
|
if (currentSequence.isNotEmpty()) {
|
||||||
|
currentMainAxisSize += mainAxisSpacing.roundToPx()
|
||||||
|
}
|
||||||
|
currentSequence.add(placeable)
|
||||||
|
currentMainAxisSize += placeable.mainAxisSize()
|
||||||
|
currentCrossAxisSize = max(currentCrossAxisSize, placeable.crossAxisSize())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentSequence.isNotEmpty()) startNewSequence()
|
||||||
|
|
||||||
|
val mainAxisLayoutSize =
|
||||||
|
if (constraints.mainAxisMax != Constraints.Infinity && mainAxisSize == SizeMode.Expand) {
|
||||||
|
constraints.mainAxisMax
|
||||||
|
} else {
|
||||||
|
max(mainAxisSpace, constraints.mainAxisMin)
|
||||||
|
}
|
||||||
|
val crossAxisLayoutSize = max(crossAxisSpace, constraints.crossAxisMin)
|
||||||
|
|
||||||
|
val layoutWidth =
|
||||||
|
if (orientation == LayoutOrientation.Horizontal) {
|
||||||
|
mainAxisLayoutSize
|
||||||
|
} else {
|
||||||
|
crossAxisLayoutSize
|
||||||
|
}
|
||||||
|
val layoutHeight =
|
||||||
|
if (orientation == LayoutOrientation.Horizontal) {
|
||||||
|
crossAxisLayoutSize
|
||||||
|
} else {
|
||||||
|
mainAxisLayoutSize
|
||||||
|
}
|
||||||
|
|
||||||
|
layout(layoutWidth, layoutHeight) {
|
||||||
|
sequences.forEachIndexed { i, placeables ->
|
||||||
|
val childrenMainAxisSizes =
|
||||||
|
IntArray(placeables.size) { j ->
|
||||||
|
placeables[j].mainAxisSize() +
|
||||||
|
if (j < placeables.lastIndex) mainAxisSpacing.roundToPx() else 0
|
||||||
|
}
|
||||||
|
val arrangement =
|
||||||
|
if (i < sequences.lastIndex) {
|
||||||
|
mainAxisAlignment.arrangement
|
||||||
|
} else {
|
||||||
|
lastLineMainAxisAlignment.arrangement
|
||||||
|
}
|
||||||
|
// TODO(soboleva): rtl support
|
||||||
|
// Handle vertical direction
|
||||||
|
val mainAxisPositions = IntArray(childrenMainAxisSizes.size) { 0 }
|
||||||
|
with(arrangement) { arrange(mainAxisLayoutSize, childrenMainAxisSizes, mainAxisPositions) }
|
||||||
|
placeables.forEachIndexed { j, placeable ->
|
||||||
|
val crossAxis =
|
||||||
|
when (crossAxisAlignment) {
|
||||||
|
FlowCrossAxisAlignment.Start -> 0
|
||||||
|
FlowCrossAxisAlignment.End -> crossAxisSizes[i] - placeable.crossAxisSize()
|
||||||
|
FlowCrossAxisAlignment.Center ->
|
||||||
|
Alignment.Center.align(
|
||||||
|
IntSize.Zero,
|
||||||
|
IntSize(width = 0, height = crossAxisSizes[i] - placeable.crossAxisSize()),
|
||||||
|
LayoutDirection.Ltr
|
||||||
|
)
|
||||||
|
.y
|
||||||
|
}
|
||||||
|
if (orientation == LayoutOrientation.Horizontal) {
|
||||||
|
placeable.place(x = mainAxisPositions[j], y = crossAxisPositions[i] + crossAxis)
|
||||||
|
} else {
|
||||||
|
placeable.place(x = crossAxisPositions[i] + crossAxis, y = mainAxisPositions[j])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Used to specify how a layout chooses its own size when multiple behaviors are possible. */
|
||||||
|
// TODO(popam): remove this when Flow is reworked
|
||||||
|
public enum class SizeMode {
|
||||||
|
/**
|
||||||
|
* Minimize the amount of free space by wrapping the children, subject to the incoming layout
|
||||||
|
* constraints.
|
||||||
|
*/
|
||||||
|
Wrap,
|
||||||
|
/**
|
||||||
|
* Maximize the amount of free space by expanding to fill the available space, subject to the
|
||||||
|
* incoming layout constraints.
|
||||||
|
*/
|
||||||
|
Expand
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Used to specify the alignment of a layout's children, in main axis direction. */
|
||||||
|
public enum class MainAxisAlignment(internal val arrangement: Arrangement.Vertical) {
|
||||||
|
// TODO(soboleva) support RTl in Flow
|
||||||
|
// workaround for now - use Arrangement that equals to previous Arrangement
|
||||||
|
/** Place children such that they are as close as possible to the middle of the main axis. */
|
||||||
|
Center(Arrangement.Center),
|
||||||
|
|
||||||
|
/** Place children such that they are as close as possible to the start of the main axis. */
|
||||||
|
Start(Arrangement.Top),
|
||||||
|
|
||||||
|
/** Place children such that they are as close as possible to the end of the main axis. */
|
||||||
|
End(Arrangement.Bottom),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Place children such that they are spaced evenly across the main axis, including free space
|
||||||
|
* before the first child and after the last child.
|
||||||
|
*/
|
||||||
|
SpaceEvenly(Arrangement.SpaceEvenly),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Place children such that they are spaced evenly across the main axis, without free space before
|
||||||
|
* the first child or after the last child.
|
||||||
|
*/
|
||||||
|
SpaceBetween(Arrangement.SpaceBetween),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Place children such that they are spaced evenly across the main axis, including free space
|
||||||
|
* before the first child and after the last child, but half the amount of space existing
|
||||||
|
* otherwise between two consecutive children.
|
||||||
|
*/
|
||||||
|
SpaceAround(Arrangement.SpaceAround)
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2021 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.google.accompanist.flowlayout
|
||||||
|
|
||||||
|
import androidx.compose.ui.unit.Constraints
|
||||||
|
|
||||||
|
internal enum class LayoutOrientation {
|
||||||
|
Horizontal,
|
||||||
|
Vertical
|
||||||
|
}
|
||||||
|
|
||||||
|
internal data class OrientationIndependentConstraints(
|
||||||
|
val mainAxisMin: Int,
|
||||||
|
val mainAxisMax: Int,
|
||||||
|
val crossAxisMin: Int,
|
||||||
|
val crossAxisMax: Int
|
||||||
|
) {
|
||||||
|
constructor(
|
||||||
|
c: Constraints,
|
||||||
|
orientation: LayoutOrientation
|
||||||
|
) : this(
|
||||||
|
if (orientation === LayoutOrientation.Horizontal) c.minWidth else c.minHeight,
|
||||||
|
if (orientation === LayoutOrientation.Horizontal) c.maxWidth else c.maxHeight,
|
||||||
|
if (orientation === LayoutOrientation.Horizontal) c.minHeight else c.minWidth,
|
||||||
|
if (orientation === LayoutOrientation.Horizontal) c.maxHeight else c.maxWidth
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,202 @@
|
||||||
|
@file:Suppress("FunctionName")
|
||||||
|
|
||||||
|
package dev.msfjarvis.claw.common.posts
|
||||||
|
|
||||||
|
import androidx.compose.animation.Crossfade
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.requiredSize
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.IconButton
|
||||||
|
import androidx.compose.material.IconToggleButton
|
||||||
|
import androidx.compose.material.MaterialTheme
|
||||||
|
import androidx.compose.material.Surface
|
||||||
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.google.accompanist.flowlayout.FlowRow
|
||||||
|
import dev.msfjarvis.lobsters.data.local.SavedPost
|
||||||
|
import io.kamel.image.KamelImage
|
||||||
|
import io.kamel.image.lazyImageResource
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun LobstersItem(
|
||||||
|
post: SavedPost,
|
||||||
|
isSaved: Boolean,
|
||||||
|
viewPost: () -> Unit,
|
||||||
|
viewComments: (String) -> Unit,
|
||||||
|
toggleSave: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
Surface(
|
||||||
|
modifier = Modifier.clickable { viewPost.invoke() }.then(modifier),
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(horizontal = 12.dp, vertical = 4.dp),
|
||||||
|
) {
|
||||||
|
PostTitle(
|
||||||
|
title = post.title,
|
||||||
|
modifier = Modifier.padding(bottom = 4.dp),
|
||||||
|
)
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
TagRow(
|
||||||
|
tags = post.tags,
|
||||||
|
modifier = Modifier.weight(0.65f),
|
||||||
|
)
|
||||||
|
SaveButton(
|
||||||
|
isSaved = isSaved,
|
||||||
|
onClick = toggleSave,
|
||||||
|
)
|
||||||
|
Spacer(
|
||||||
|
modifier = Modifier.width(8.dp),
|
||||||
|
)
|
||||||
|
CommentsButton(
|
||||||
|
onClick = { viewComments(post.shortId) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
SubmitterName(
|
||||||
|
text = "Submitted by %s".format(post.submitterName),
|
||||||
|
avatarUrl = post.submitterAvatarUrl,
|
||||||
|
contentDescription = "Submitted by %s".format(post.submitterName),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun PostTitle(
|
||||||
|
title: String,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = title,
|
||||||
|
color = Color.Black,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
modifier = Modifier.then(modifier),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SubmitterName(
|
||||||
|
text: String,
|
||||||
|
avatarUrl: String,
|
||||||
|
contentDescription: String,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.then(modifier),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
SubmitterAvatar(
|
||||||
|
avatarUrl = avatarUrl,
|
||||||
|
contentDescription = contentDescription,
|
||||||
|
)
|
||||||
|
SubmitterNameText(
|
||||||
|
text = text,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SubmitterAvatar(
|
||||||
|
avatarUrl: String,
|
||||||
|
contentDescription: String,
|
||||||
|
) {
|
||||||
|
KamelImage(
|
||||||
|
resource = lazyImageResource(avatarUrl),
|
||||||
|
contentDescription = contentDescription,
|
||||||
|
modifier = Modifier.requiredSize(24.dp),
|
||||||
|
crossfade = true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SubmitterNameText(
|
||||||
|
text: String,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = text,
|
||||||
|
modifier = Modifier.padding(start = 4.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SaveButton(
|
||||||
|
isSaved: Boolean,
|
||||||
|
onClick: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
IconToggleButton(
|
||||||
|
checked = isSaved,
|
||||||
|
onCheckedChange = { onClick.invoke() },
|
||||||
|
modifier = Modifier.requiredSize(32.dp).then(modifier),
|
||||||
|
) {
|
||||||
|
Crossfade(targetState = isSaved) { saved ->
|
||||||
|
/*IconResource(
|
||||||
|
resourceId = if (saved) R.drawable.ic_favorite_24px else R.drawable.ic_favorite_border_24px,
|
||||||
|
tint = MaterialTheme.colors.secondary,
|
||||||
|
contentDescription =
|
||||||
|
if (saved) Strings.RemoveFromSavedPosts.get() else Strings.AddToSavedPosts.get(),
|
||||||
|
)*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CommentsButton(
|
||||||
|
onClick: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
IconButton(
|
||||||
|
onClick = onClick,
|
||||||
|
modifier = Modifier.requiredSize(32.dp).then(modifier),
|
||||||
|
) {
|
||||||
|
/*IconResource(
|
||||||
|
resourceId = R.drawable.ic_insert_comment_24px,
|
||||||
|
tint = MaterialTheme.colors.secondary,
|
||||||
|
contentDescription = Strings.OpenComments.get(),
|
||||||
|
)*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun TagRow(
|
||||||
|
tags: List<String>,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.then(modifier),
|
||||||
|
) {
|
||||||
|
FlowRow(
|
||||||
|
mainAxisSpacing = 8.dp,
|
||||||
|
crossAxisSpacing = 8.dp,
|
||||||
|
) {
|
||||||
|
tags.forEach { tag ->
|
||||||
|
Text(
|
||||||
|
text = tag,
|
||||||
|
modifier =
|
||||||
|
Modifier.background(
|
||||||
|
MaterialTheme.colors.secondary.copy(alpha = 0.75f),
|
||||||
|
RoundedCornerShape(8.dp)
|
||||||
|
)
|
||||||
|
.padding(vertical = 2.dp, horizontal = 6.dp),
|
||||||
|
color = MaterialTheme.colors.onSecondary,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue