Skip to content

Commit f0f971b

Browse files
committed
feat(ui): add visual indicator for recently updated repositories
This commit introduces a "hot" indicator (🔥) for repositories updated within the last week and cleans up unused resources and time formatting logic. - **feat(ui)**: Updated `RepositoryCard` to prepend a fire emoji to the release date if the repository was updated within the last 7 days. - **refactor(core)**: Introduced `hasWeekNotPassed` utility in `TimeFormatters.kt` to check repository update freshness. - **refactor(core)**: Removed unused `formatUpdatedAt` functions and simplified `TimeFormatters.kt`. - **chore(android)**: Removed default Android launcher background and foreground vector drawables. - **chore**: Cleaned up unused imports and Material3 Experimental APIs in `RepositoryCard.kt`.
1 parent 6b32a2c commit f0f971b

4 files changed

Lines changed: 25 additions & 259 deletions

File tree

composeApp/src/androidMain/res/drawable-v24/ic_launcher_foreground.xml

Lines changed: 0 additions & 30 deletions
This file was deleted.

composeApp/src/androidMain/res/drawable/ic_launcher_background.xml

Lines changed: 0 additions & 170 deletions
This file was deleted.

core/presentation/src/commonMain/kotlin/zed/rainxch/core/presentation/components/RepositoryCard.kt

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@ import androidx.compose.foundation.clickable
44
import androidx.compose.foundation.layout.Arrangement
55
import androidx.compose.foundation.layout.Box
66
import androidx.compose.foundation.layout.Column
7-
import androidx.compose.foundation.layout.Row
8-
import androidx.compose.foundation.layout.Spacer
9-
import androidx.compose.foundation.layout.fillMaxSize
107
import androidx.compose.foundation.layout.ExperimentalLayoutApi
118
import androidx.compose.foundation.layout.FlowRow
9+
import androidx.compose.foundation.layout.Row
10+
import androidx.compose.foundation.layout.Spacer
1211
import androidx.compose.foundation.layout.fillMaxWidth
1312
import androidx.compose.foundation.layout.height
1413
import androidx.compose.foundation.layout.offset
@@ -23,10 +22,8 @@ import androidx.compose.material.icons.filled.Favorite
2322
import androidx.compose.material.icons.filled.OpenInBrowser
2423
import androidx.compose.material.icons.filled.Star
2524
import androidx.compose.material.icons.filled.Update
26-
import androidx.compose.material.icons.outlined.CallSplit
2725
import androidx.compose.material3.Card
2826
import androidx.compose.material3.CardDefaults
29-
import androidx.compose.material3.CircularWavyProgressIndicator
3027
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
3128
import androidx.compose.material3.Icon
3229
import androidx.compose.material3.IconButton
@@ -39,21 +36,24 @@ import androidx.compose.ui.Alignment
3936
import androidx.compose.ui.Modifier
4037
import androidx.compose.ui.draw.clip
4138
import androidx.compose.ui.platform.LocalUriHandler
39+
import androidx.compose.ui.text.buildAnnotatedString
4240
import androidx.compose.ui.text.font.FontWeight
4341
import androidx.compose.ui.text.style.TextOverflow
4442
import androidx.compose.ui.unit.dp
45-
import com.skydoves.landscapist.coil3.CoilImage
46-
import com.skydoves.landscapist.components.rememberImageComponent
47-
import com.skydoves.landscapist.crossfade.CrossfadePlugin
48-
import zed.rainxch.githubstore.core.presentation.res.*
4943
import org.jetbrains.compose.resources.stringResource
5044
import org.jetbrains.compose.ui.tooling.preview.Preview
5145
import zed.rainxch.core.domain.model.GithubRepoSummary
5246
import zed.rainxch.core.domain.model.GithubUser
5347
import zed.rainxch.core.presentation.model.DiscoveryRepository
5448
import zed.rainxch.core.presentation.theme.GithubStoreTheme
5549
import zed.rainxch.core.presentation.utils.formatReleasedAt
56-
import zed.rainxch.core.presentation.utils.formatUpdatedAt
50+
import zed.rainxch.core.presentation.utils.hasWeekNotPassed
51+
import zed.rainxch.githubstore.core.presentation.res.Res
52+
import zed.rainxch.githubstore.core.presentation.res.forked_repository
53+
import zed.rainxch.githubstore.core.presentation.res.home_view_details
54+
import zed.rainxch.githubstore.core.presentation.res.installed
55+
import zed.rainxch.githubstore.core.presentation.res.open_in_browser
56+
import zed.rainxch.githubstore.core.presentation.res.update_available
5757

5858
@OptIn(ExperimentalMaterial3ExpressiveApi::class, ExperimentalLayoutApi::class)
5959
@Composable
@@ -237,8 +237,16 @@ fun RepositoryCard(
237237

238238
Spacer(Modifier.height(12.dp))
239239

240+
val releasedAtText = buildAnnotatedString {
241+
if (hasWeekNotPassed(discoveryRepository.repository.updatedAt)) {
242+
append("🔥 ")
243+
}
244+
245+
append(formatReleasedAt(discoveryRepository.repository.updatedAt))
246+
}
247+
240248
Text(
241-
text = formatReleasedAt(discoveryRepository.repository.updatedAt),
249+
text = releasedAtText,
242250
style = MaterialTheme.typography.titleMedium,
243251
color = MaterialTheme.colorScheme.outline,
244252
maxLines = 1,

core/presentation/src/commonMain/kotlin/zed/rainxch/core/presentation/utils/TimeFormatters.kt

Lines changed: 6 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,18 @@ import org.jetbrains.compose.resources.getString
88
import org.jetbrains.compose.resources.stringResource
99
import kotlin.time.Clock
1010
import kotlin.time.Duration
11+
import kotlin.time.Duration.Companion.days
1112
import kotlin.time.ExperimentalTime
1213
import kotlin.time.Instant
1314

14-
@OptIn(ExperimentalTime::class)
15-
@Composable
16-
fun formatUpdatedAt(isoInstant: String): String {
15+
fun hasWeekNotPassed(isoInstant: String): Boolean {
1716
val updated = Instant.parse(isoInstant)
18-
val now = Instant.fromEpochMilliseconds(Clock.System.now().toEpochMilliseconds())
19-
val diff: Duration = now - updated
20-
21-
val hoursDiff = diff.inWholeHours
22-
val daysDiff = diff.inWholeDays
17+
val now = Clock.System.now()
18+
val diff = now - updated
2319

24-
return when {
25-
hoursDiff < 1 -> stringResource(Res.string.updated_just_now)
26-
hoursDiff < 24 -> stringResource(Res.string.updated_hours_ago, hoursDiff)
27-
daysDiff == 1L -> stringResource(Res.string.updated_yesterday)
28-
daysDiff < 7 -> stringResource(Res.string.updated_days_ago, daysDiff)
29-
else -> {
30-
val date = updated.toLocalDateTime(TimeZone.currentSystemDefault()).date
31-
stringResource(Res.string.updated_on_date, date.toString())
32-
}
33-
}
20+
return diff < 7.days
3421
}
22+
3523
@OptIn(ExperimentalTime::class)
3624
@Composable
3725
fun formatReleasedAt(isoInstant: String): String {
@@ -54,36 +42,6 @@ fun formatReleasedAt(isoInstant: String): String {
5442
}
5543
}
5644

57-
@OptIn(ExperimentalTime::class)
58-
suspend fun formatUpdatedAt(epochMillis: Long): String {
59-
val updated = Instant.fromEpochMilliseconds(epochMillis)
60-
val now = Clock.System.now()
61-
val diff: Duration = now - updated
62-
63-
val hoursDiff = diff.inWholeHours
64-
val daysDiff = diff.inWholeDays
65-
66-
return when {
67-
hoursDiff < 1 ->
68-
getString(Res.string.updated_just_now)
69-
70-
hoursDiff < 24 ->
71-
getString(Res.string.updated_hours_ago, hoursDiff)
72-
73-
daysDiff == 1L ->
74-
getString(Res.string.updated_yesterday)
75-
76-
daysDiff < 7 ->
77-
getString(Res.string.updated_days_ago, daysDiff)
78-
79-
else -> {
80-
val date = updated
81-
.toLocalDateTime(TimeZone.currentSystemDefault())
82-
.date
83-
getString(Res.string.updated_on_date, date.toString())
84-
}
85-
}
86-
}
8745
@OptIn(ExperimentalTime::class)
8846
suspend fun formatAddedAt(epochMillis: Long): String {
8947
val updated = Instant.fromEpochMilliseconds(epochMillis)

0 commit comments

Comments
 (0)