Skip to content

Commit 8b3efbc

Browse files
committed
feat(nav): Hide 'Apps' tab on non-Android platforms
This commit hides the "Apps" tab from the bottom navigation bar on all platforms except for Android, as app installation functionality is platform-specific. - **feat(nav)**: Updated `BottomNavigationUtils` to filter out the 'Apps' screen based on the current platform. - **refactor(dev-profile)**: Improved error handling in `DeveloperProfileViewModel` to catch and display generic exceptions. - **feat(ui)**: Added a new `formatReleasedAt` time formatter to display relative release times (e.g., "Released just now", "Released yesterday") and updated the `RepositoryCard` to use it. - **fix(details)**: Ensured the `rateLimited` flag in `DetailsViewModel` is reset when data loading begins. - **chore(ui)**: Removed an unused `liquefiable` modifier from the `AppsRoot` screen. - **chore(strings)**: Added new string resources for the relative release time formats.
1 parent 32ca8a0 commit 8b3efbc

7 files changed

Lines changed: 50 additions & 10 deletions

File tree

composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/navigation/BottomNavigationUtils.kt

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import githubstore.composeapp.generated.resources.search_repositories_hint
2626
import githubstore.composeapp.generated.resources.settings_title
2727
import githubstore.composeapp.generated.resources.stars
2828
import org.jetbrains.compose.resources.StringResource
29+
import zed.rainxch.core.domain.getPlatform
30+
import zed.rainxch.core.domain.model.Platform
2931

3032
data class BottomNavigationItem(
3133
val titleRes: StringResource,
@@ -62,10 +64,10 @@ object BottomNavigationUtils {
6264
)
6365
)
6466

65-
fun allowedScreens(): List<GithubStoreGraph> = listOf(
66-
GithubStoreGraph.HomeScreen,
67-
GithubStoreGraph.SearchScreen,
68-
GithubStoreGraph.AppsScreen,
69-
GithubStoreGraph.SettingsScreen,
70-
)
67+
fun allowedScreens(): List<GithubStoreGraph> = items()
68+
.filterNot {
69+
getPlatform() != Platform.ANDROID &&
70+
it.screen == GithubStoreGraph.AppsScreen
71+
}
72+
.map { it.screen }
7173
}

core/presentation/src/commonMain/composeResources/values/strings.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,4 +322,10 @@
322322
<!-- Developer Profile - Count Formatting -->
323323
<string name="count_millions">%1$dM</string>
324324
<string name="count_thousands">%1$dk</string>
325+
326+
<string name="released_just_now">Released just now</string>
327+
<string name="released_hours_ago">Released %1$d hour(s) ago</string>
328+
<string name="released_yesterday">Released yesterday</string>
329+
<string name="released_days_ago">Released %1$d day(s) ago</string>
330+
<string name="released_on_date">Released on %1$s</string>
325331
</resources>

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import zed.rainxch.core.domain.model.GithubRepoSummary
4848
import zed.rainxch.core.domain.model.GithubUser
4949
import zed.rainxch.core.presentation.model.DiscoveryRepository
5050
import zed.rainxch.core.presentation.theme.GithubStoreTheme
51+
import zed.rainxch.core.presentation.utils.formatReleasedAt
5152
import zed.rainxch.core.presentation.utils.formatUpdatedAt
5253

5354
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@@ -220,7 +221,7 @@ fun RepositoryCard(
220221
Spacer(Modifier.height(12.dp))
221222

222223
Text(
223-
text = formatUpdatedAt(discoveryRepository.repository.updatedAt),
224+
text = formatReleasedAt(discoveryRepository.repository.updatedAt),
224225
style = MaterialTheme.typography.titleMedium,
225226
color = MaterialTheme.colorScheme.outline,
226227
maxLines = 1,

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,27 @@ fun formatUpdatedAt(isoInstant: String): String {
3232
}
3333
}
3434
}
35+
@OptIn(ExperimentalTime::class)
36+
@Composable
37+
fun formatReleasedAt(isoInstant: String): String {
38+
val updated = Instant.parse(isoInstant)
39+
val now = Instant.fromEpochMilliseconds(Clock.System.now().toEpochMilliseconds())
40+
val diff: Duration = now - updated
41+
42+
val hoursDiff = diff.inWholeHours
43+
val daysDiff = diff.inWholeDays
44+
45+
return when {
46+
hoursDiff < 1 -> stringResource(Res.string.released_just_now)
47+
hoursDiff < 24 -> stringResource(Res.string.released_hours_ago, hoursDiff)
48+
daysDiff == 1L -> stringResource(Res.string.released_yesterday)
49+
daysDiff < 7 -> stringResource(Res.string.released_days_ago, daysDiff)
50+
else -> {
51+
val date = updated.toLocalDateTime(TimeZone.currentSystemDefault()).date
52+
stringResource(Res.string.released_on_date, date.toString())
53+
}
54+
}
55+
}
3556

3657
@OptIn(ExperimentalTime::class)
3758
suspend fun formatUpdatedAt(epochMillis: Long): String {

feature/apps/presentation/src/commonMain/kotlin/zed/rainxch/apps/presentation/AppsRoot.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,6 @@ fun AppsScreen(
166166
modifier = Modifier
167167
.fillMaxSize()
168168
.padding(innerPadding)
169-
.liquefiable(liquidState)
170169
) {
171170
TextField(
172171
value = state.searchQuery,

feature/details/presentation/src/commonMain/kotlin/zed/rainxch/details/presentation/DetailsViewModel.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,14 @@ class DetailsViewModel(
7878
private val _events = Channel<DetailsEvent>()
7979
val events = _events.receiveAsFlow()
8080

81-
val rateLimited = AtomicBoolean(false)
81+
private val rateLimited = AtomicBoolean(false)
8282

8383
@OptIn(ExperimentalTime::class)
8484
private fun loadInitial() {
8585
viewModelScope.launch {
8686
try {
87+
rateLimited.set(false)
88+
8789
_state.value = _state.value.copy(isLoading = true, errorMessage = null)
8890

8991
val syncResult = syncInstalledAppsUseCase()

feature/dev-profile/presentation/src/commonMain/kotlin/zed/rainxch/devprofile/presentation/DeveloperProfileViewModel.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,21 @@ class DeveloperProfileViewModel(
102102
)
103103
}
104104
}
105-
} catch (e: RateLimitException) {
105+
} catch (_: RateLimitException) {
106106
_state.update {
107107
it.copy(isLoading = false, isLoadingRepos = false)
108108
}
109109
} catch (e: CancellationException) {
110110
throw e
111+
} catch (e: Exception) {
112+
_state.update {
113+
it.copy(
114+
isLoading = false,
115+
isLoadingRepos = false,
116+
errorMessage = e.message ?: "Unexpected error"
117+
)
118+
}
119+
111120
}
112121
}
113122
}

0 commit comments

Comments
 (0)