Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fleshing Out Examples for Preview Driven Development #164

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions android/app/src/main/java/com/emergetools/hackernews/data/Dates.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package com.emergetools.hackernews.data

import java.time.Instant
import java.time.LocalDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter

/**
* Convert the difference between two epoch second times
Expand All @@ -24,6 +27,28 @@ fun relativeTimeStamp(epochSeconds: Long): String {
return "${days.toInt()}d ago"
}

fun relativeTimeStamp(date: String): String {
val dateEpochs = LocalDateTime
.parse(date, DateTimeFormatter.ISO_DATE_TIME)
.toInstant(ZoneOffset.UTC)
.epochSecond
val now = Instant.now().epochSecond
val difference = now - dateEpochs

val minutes = difference / SECONDS_IN_MINUTE
if (minutes < 60) {
return "${minutes.toInt()}m ago"
}

val hours = minutes / MINUTES_IN_HOUR
if (hours < 24) {
return "${hours.toInt()}h ago"
}

val days = hours / HOURS_IN_DAY
return "${days.toInt()}d ago"
}

private const val SECONDS_IN_MINUTE = 60.0
private const val MINUTES_IN_HOUR = 60.0
private const val HOURS_IN_DAY = 24.0
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ sealed interface CommentState {
val id: Long,
val author: String,
val content: String,
val epochSeconds: Long,
val age: String,
val upvoted: Boolean,
val upvoteUrl: String,
override val children: List<CommentState>,
Expand Down Expand Up @@ -352,9 +352,7 @@ class CommentsViewModel(
id = id,
author = user,
content = text,
epochSeconds = LocalDateTime
.parse(age, DateTimeFormatter.ISO_DATE_TIME)
.toInstant(ZoneOffset.UTC).epochSecond,
age = age,
upvoted = upvoted,
upvoteUrl = upvoteUrl,
level = level,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ fun CommentsScreen(
) {
Box(
modifier = Modifier
.fillMaxSize()
.background(color = MaterialTheme.colorScheme.background),
.fillMaxSize()
.background(color = MaterialTheme.colorScheme.background),
) {
LazyColumn(
modifier = Modifier.fillMaxSize(),
Expand All @@ -54,8 +54,8 @@ fun CommentsScreen(
CommentsHeader(
state = state.headerState,
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight(),
.fillMaxWidth()
.wrapContentHeight(),
onLikeTapped = { item ->
if (state is CommentsState.Content && state.loggedIn) {
actions(
Expand All @@ -74,23 +74,23 @@ fun CommentsScreen(
item {
val lineColor = MaterialTheme.colorScheme.onBackground
Box(modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 8.dp)
.height(16.dp)
.drawBehind {
val lineStart = Offset(0f, size.center.y)
val lineEnd = Offset(size.width, size.center.y)
drawLine(
start = lineStart,
end = lineEnd,
color = lineColor,
strokeWidth = 4f,
cap = StrokeCap.Round,
pathEffect = PathEffect.dashPathEffect(
intervals = floatArrayOf(10f, 10f)
)
)
}
.fillMaxWidth()
.padding(horizontal = 8.dp)
.height(16.dp)
.drawBehind {
val lineStart = Offset(0f, size.center.y)
val lineEnd = Offset(size.width, size.center.y)
drawLine(
start = lineStart,
end = lineEnd,
color = lineColor,
strokeWidth = 4f,
cap = StrokeCap.Round,
pathEffect = PathEffect.dashPathEffect(
intervals = floatArrayOf(10f, 10f)
)
)
}
)
}
items(items = state.comments.filter { it.hidden != HiddenStatus.HiddenByParent }) { comment ->
Expand Down Expand Up @@ -171,7 +171,7 @@ private fun CommentsScreenPreview() {
level = 0,
author = "rikinm",
content = "Hello Child",
epochSeconds = Instant.now().minusSeconds(60 * 60 * 24 * 2).epochSecond,
age = "2024-09-05T17:48:25",
upvoted = false,
upvoteUrl = "",
children = listOf()
Expand All @@ -181,7 +181,7 @@ private fun CommentsScreenPreview() {
level = 1,
author = "vasantm",
content = "Hello Parent",
epochSeconds = Instant.now().minusSeconds(60 * 60 * 1).epochSecond,
age = "2024-09-05T17:48:25",
upvoted = false,
upvoteUrl = "",
children = listOf()
Expand Down Expand Up @@ -230,7 +230,7 @@ fun CommentsScreenAppStorePreview() {
level = 0,
author = "rikinm",
content = "My question is: why do an Oral-B app and a Colgate app even exist?",
epochSeconds = Instant.now().minusSeconds(60 * 60 * 2).epochSecond,
age = "2024-09-05T17:48:25",
upvoted = false,
upvoteUrl = "",
children = listOf()
Expand All @@ -240,7 +240,7 @@ fun CommentsScreenAppStorePreview() {
level = 1,
author = "telkins",
content = "The same reason they now have a toothbrush with AI. Because they are in a race to continuously re-invent the toothbrush every year to create new USPs, create new marketing angles and keep sales high.",
epochSeconds = Instant.now().minusSeconds(60 * 60 * 2).epochSecond,
age = "2024-09-05T17:48:25",
upvoted = false,
upvoteUrl = "",
children = listOf()
Expand All @@ -250,7 +250,7 @@ fun CommentsScreenAppStorePreview() {
level = 2,
author = "nhinderling",
content = "I'm surprised that health insurance companies haven't started offering \"good brusher\" discounts the way car insurance companies offer a \"good driver\" discount when you use their car data logging device/app.",
epochSeconds = Instant.now().minusSeconds(60 * 60 * 1).epochSecond,
age = "2024-09-05T17:48:25",
upvoted = false,
upvoteUrl = "",
children = listOf()
Expand All @@ -262,7 +262,7 @@ fun CommentsScreenAppStorePreview() {
author = "vasantm",
content = "So it’s all just stupidly big PDFs used as images of the different models?\n" +
"Not what I was expecting. I was expecting it to be more like the Colgate app mentioned later in thread.",
epochSeconds = Instant.now().minusSeconds(60 * 60 * 2).epochSecond,
age = "2024-09-05T17:48:25",
upvoted = false,
upvoteUrl = "",
children = listOf()
Expand All @@ -272,7 +272,7 @@ fun CommentsScreenAppStorePreview() {
level = 1,
author = "itaybre",
content = "I wonder if they generated the PDFs with a web browser's Print to PDF feature. Chrome's PDFs are massive.",
epochSeconds = Instant.now().minusSeconds(60 * 60 * 1).epochSecond,
age = "2024-09-05T17:48:25",
upvoted = false,
upvoteUrl = "",
children = listOf()
Expand All @@ -282,7 +282,7 @@ fun CommentsScreenAppStorePreview() {
level = 1,
author = "chromy",
content = "That’s insane. They should absolutely, 100% be pulled on demand.",
epochSeconds = Instant.now().minusSeconds(60 * 60 * 1).epochSecond,
age = "2024-09-05T17:48:25",
upvoted = false,
upvoteUrl = "",
children = listOf()
Expand All @@ -293,7 +293,7 @@ fun CommentsScreenAppStorePreview() {
author = "mptop27",
content = "I think there’s nothing wrong with shipping the images, why should you need an Internet connection to pair your toothbrush (which of your using the app you must want to do).\n" +
"But why can’t they be vector images? The pictures in the tweet looks like they could easily be replaced by vectors and the difference would be nearly unnoticeable.",
epochSeconds = Instant.now().minusSeconds(60 * 30).epochSecond,
age = "2024-09-05T17:48:25",
upvoted = false,
upvoteUrl = "",
children = listOf()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import com.emergetools.hackernews.R
Expand All @@ -43,7 +44,6 @@ import com.emergetools.hackernews.ui.components.MetadataTag
import com.emergetools.hackernews.ui.theme.HackerGreen
import com.emergetools.hackernews.ui.theme.HackerNewsTheme
import com.emergetools.hackernews.ui.util.parseAsHtml
import java.time.Instant

@Composable
fun CommentRow(
Expand Down Expand Up @@ -78,7 +78,7 @@ fun CommentRow(
fontWeight = FontWeight.Bold
)
MetadataTag(
label = relativeTimeStamp(state.epochSeconds),
label = relativeTimeStamp(state.age),
) {
Icon(
modifier = Modifier.size(12.dp),
Expand Down Expand Up @@ -237,7 +237,7 @@ fun CommentRowPreview() {
level = 0,
author = "rikinm",
content = "Hello Parent",
epochSeconds = Instant.now().minusSeconds(60 * 60 * 2).epochSecond,
age = "2024-09-05T17:48:25",
upvoted = false,
upvoteUrl = "",
children = listOf()
Expand All @@ -263,3 +263,27 @@ fun CommentRowLoadingPreview() {
}
}

@Preview
@Composable
private fun TestIsoDateTimeParsing() {
HackerNewsTheme {
Column {
val isoDateWithTimeZone = "2024-09-05T17:48:25.000000Z"
CommentRow(
state = CommentState.Content(
id = 1,
level = 0,
author = "rikinm",
content = "Hello Parent",
age = isoDateWithTimeZone,
upvoted = false,
upvoteUrl = "",
children = listOf()
),
onToggleHide = {},
onLikeTapped = {}
)
}
}
}

Loading