Skip to content

Commit

Permalink
Kotlin weekly issue screen with basic presenter + VM and API integrat…
Browse files Browse the repository at this point in the history
…ion.
  • Loading branch information
ychescale9 committed Dec 27, 2023
1 parent 29ba821 commit 8eb709e
Show file tree
Hide file tree
Showing 47 changed files with 966 additions and 211 deletions.
2 changes: 2 additions & 0 deletions android/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ plugins {
id("kstreamlined.android.application")
id("kstreamlined.android.application.compose")
id("kstreamlined.ksp")
id("kotlin-parcelize")
id("com.google.dagger.hilt.android")
id("com.google.firebase.firebase-perf")
id("com.google.firebase.crashlytics")
Expand Down Expand Up @@ -236,6 +237,7 @@ dependencies {
implementation(project(":feature:common"))
implementation(project(":feature:content-viewer"))
implementation(project(":feature:home"))
implementation(project(":feature:kotlin-weekly-issue"))
implementation(project(":feature:saved-for-later"))

// Firebase
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import io.github.reactivecircus.kstreamlined.kmp.feed.datasource.EdgeFeedDataSource
import io.github.reactivecircus.kstreamlined.kmp.feed.datasource.FeedDataSource
import io.github.reactivecircus.kstreamlined.kmp.feed.datasource.util.ApiErrorChecker
import io.github.reactivecircus.kstreamlined.kmp.feed.datasource.util.KtorApiErrorChecker
import javax.inject.Singleton

@Module
Expand All @@ -19,10 +17,4 @@ object EdgeDataModule {
fun feedDataSource(): FeedDataSource {
return EdgeFeedDataSource()
}

@Provides
@Singleton
fun apiErrorChecker(): ApiErrorChecker {
return KtorApiErrorChecker
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import io.github.reactivecircus.kstreamlined.kmp.feed.datasource.CloudFeedDataSource
import io.github.reactivecircus.kstreamlined.kmp.feed.datasource.FeedDataSource
import io.github.reactivecircus.kstreamlined.kmp.feed.datasource.util.ApiErrorChecker
import io.github.reactivecircus.kstreamlined.kmp.feed.datasource.util.ApolloApiErrorChecker
import javax.inject.Singleton

@Module
Expand All @@ -20,10 +18,4 @@ object CloudDataModule {
fun feedDataSource(apolloClient: ApolloClient): FeedDataSource {
return CloudFeedDataSource(apolloClient)
}

@Provides
@Singleton
fun apiErrorChecker(): ApiErrorChecker {
return ApolloApiErrorChecker
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package io.github.reactivecircus.kstreamlined.android

import android.content.Context
import android.os.Bundle
import android.os.Parcelable
import android.provider.Settings
import androidx.activity.ComponentActivity
import androidx.activity.compose.BackHandler
Expand All @@ -25,6 +26,9 @@ import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import dagger.hilt.android.AndroidEntryPoint
import io.github.reactivecircus.kstreamlined.android.designsystem.foundation.KSTheme
import io.github.reactivecircus.kstreamlined.android.feature.contentviewer.ContentViewerScreen
import io.github.reactivecircus.kstreamlined.android.feature.kotlinweeklyissue.KotlinWeeklyIssueScreen
import io.github.reactivecircus.kstreamlined.kmp.model.feed.FeedItem
import kotlinx.parcelize.Parcelize

@AndroidEntryPoint
class KSActivity : ComponentActivity() {
Expand All @@ -49,7 +53,11 @@ class KSActivity : ComponentActivity() {
window.navigationBarColor = navigationBarColor.toArgb()
}

var navDestination by rememberSaveable { mutableStateOf(NavDestination.Main) }
var navDestination: NavDestination by rememberSaveable {
mutableStateOf(
NavDestination.Main
)
}

AnimatedContent(
navDestination,
Expand All @@ -60,16 +68,38 @@ class KSActivity : ComponentActivity() {
label = "NavTransition",
) {
when (it) {
NavDestination.Main -> {
is NavDestination.Main -> {
MainScreen(
onViewContent = {
navDestination = NavDestination.ContentViewer
onViewItem = { feedItem ->
navDestination = if (feedItem is FeedItem.KotlinWeekly) {
NavDestination.KotlinWeeklyIssue(
id = feedItem.id,
title = feedItem.title,
)
} else {
NavDestination.ContentViewer(
title = feedItem.title,
url = feedItem.contentUrl,
)
}
},
)
}

NavDestination.ContentViewer -> {
is NavDestination.ContentViewer -> {
ContentViewerScreen(
title = it.title,
url = it.url,
onNavigateUp = {
navDestination = NavDestination.Main
},
)
}

is NavDestination.KotlinWeeklyIssue -> {
KotlinWeeklyIssueScreen(
title = it.title,
id = it.id,
onNavigateUp = {
navDestination = NavDestination.Main
},
Expand All @@ -88,9 +118,22 @@ class KSActivity : ComponentActivity() {
}
}

enum class NavDestination {
Main,
ContentViewer,
private sealed interface NavDestination : Parcelable {

@Parcelize
data object Main : NavDestination

@Parcelize
data class ContentViewer(
val title: String,
val url: String,
) : NavDestination

@Parcelize
data class KotlinWeeklyIssue(
val id: String,
val title: String,
) : NavDestination
}

enum class SystemNavigationMode {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,13 @@ import io.github.reactivecircus.kstreamlined.android.designsystem.foundation.ico
import io.github.reactivecircus.kstreamlined.android.designsystem.foundation.icon.Kotlin
import io.github.reactivecircus.kstreamlined.android.feature.home.HomeScreen
import io.github.reactivecircus.kstreamlined.android.feature.savedforlater.SavedForLaterScreen
import io.github.reactivecircus.kstreamlined.kmp.model.feed.FeedItem
import kotlin.math.absoluteValue

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun MainScreen(
onViewContent: (id: String) -> Unit,
onViewItem: (FeedItem) -> Unit,
modifier: Modifier = Modifier,
) {
Box(modifier = modifier.fillMaxSize()) {
Expand All @@ -50,14 +51,14 @@ fun MainScreen(
when (it) {
NavItemKey.Home.ordinal -> {
HomeScreen(
onViewContent = onViewContent,
onViewItem = onViewItem,
modifier = Modifier.pagerScaleTransition(it, pagerState)
)
}

NavItemKey.Saved.ordinal -> {
SavedForLaterScreen(
onViewContent = onViewContent,
onViewItem = onViewItem,
modifier = Modifier.pagerScaleTransition(it, pagerState)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import io.github.reactivecircus.kstreamlined.kmp.feed.datasource.FakeFeedDataSource
import io.github.reactivecircus.kstreamlined.kmp.feed.datasource.FeedDataSource
import io.github.reactivecircus.kstreamlined.kmp.feed.datasource.util.ApiErrorChecker
import io.github.reactivecircus.kstreamlined.kmp.feed.datasource.util.NoOpApiErrorChecker
import javax.inject.Singleton

@Module
Expand All @@ -19,10 +17,4 @@ object MockDataModule {
fun feedDataSource(): FeedDataSource {
return FakeFeedDataSource()
}

@Provides
@Singleton
fun apiErrorChecker(): ApiErrorChecker {
return NoOpApiErrorChecker
}
}
3 changes: 3 additions & 0 deletions android/feature/common/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ plugins {

android {
namespace = "io.github.reactivecircus.kstreamlined.android.feature.common"
buildFeatures {
androidResources = true
}
}

androidComponents {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.github.reactivecircus.kstreamlined.android.feature.common

import android.content.Context
import android.content.Intent

public fun Context.openShareSheet(title: String, url: String) {
val intent = Intent(Intent.ACTION_SEND).apply {
type = "text/plain"
putExtra(Intent.EXTRA_TITLE, title)
putExtra(Intent.EXTRA_TEXT, url)
}
startActivity(Intent.createChooser(intent, null))
}
5 changes: 5 additions & 0 deletions android/feature/common/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="error_message">Something went wrong. Please try again later.</string>
<string name="empty_state_message">Nothing to see here.</string>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,12 @@ import io.github.reactivecircus.kstreamlined.android.designsystem.foundation.ico

@Composable
public fun ContentViewerScreen(
// TODO replace title and url with id and load FeedItem
title: String, // TODO load FeedItem by id
url: String, // TODO load FeedItem by id
onNavigateUp: () -> Unit,
modifier: Modifier = Modifier,
) {
// TODO load FeedItem by id
val title = "Kotlin Multiplatform Development Roadmap for 2024"
val url = "https://blog.jetbrains.com/kotlin/2023/11/kotlin-multiplatform-development-roadmap-for-2024/"

var saved by remember { mutableStateOf(false) }
Column(
modifier = modifier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,11 @@ import io.github.reactivecircus.kstreamlined.kmp.presentation.home.HomeFeedItem
import io.github.reactivecircus.kstreamlined.kmp.presentation.home.HomeUiState
import kotlinx.coroutines.delay
import kotlin.random.Random
import io.github.reactivecircus.kstreamlined.android.feature.common.R as CommonR

@Composable
public fun HomeScreen(
onViewContent: (id: String) -> Unit,
onViewItem: (FeedItem) -> Unit,
modifier: Modifier = Modifier,
) {
var syncing by remember { mutableStateOf(true) }
Expand All @@ -76,11 +77,7 @@ public fun HomeScreen(
uiState = if (Random.nextBoolean()) {
HomeUiState.Content(FakeHomeFeedItems)
} else {
if (Random.nextBoolean()) {
HomeUiState.Error.Network
} else {
HomeUiState.Error.Server
}
HomeUiState.Error
}
}
syncing = false
Expand Down Expand Up @@ -130,13 +127,13 @@ public fun HomeScreen(
}

is HomeUiState.Error -> {
ErrorUi(state, onRetry = { syncing = true })
ErrorUi(onRetry = { syncing = true })
}

is HomeUiState.Content -> {
ContentUi(
items = state.feedItems,
onItemClick = { onViewContent(it.contentUrl) },
onItemClick = onViewItem,
)
}
}
Expand Down Expand Up @@ -247,7 +244,6 @@ private const val SkeletonItemCount = 10

@Composable
private fun ErrorUi(
uiState: HomeUiState.Error,
onRetry: () -> Unit,
modifier: Modifier = Modifier,
) {
Expand All @@ -259,16 +255,13 @@ private fun ErrorUi(
verticalArrangement = Arrangement.Center,
) {
AsyncImage(
R.drawable.ic_kodee_broken_hearted,
CommonR.drawable.ic_kodee_broken_hearted,
contentDescription = null,
modifier = Modifier.size(160.dp),
)
Spacer(modifier = Modifier.height(36.dp))
Text(
text = when (uiState) {
is HomeUiState.Error.Network -> stringResource(id = R.string.error_message_network)
is HomeUiState.Error.Server -> stringResource(id = R.string.error_message_server)
},
text = stringResource(id = CommonR.string.error_message),
style = KSTheme.typography.bodyLarge,
modifier = Modifier.padding(horizontal = 24.dp),
textAlign = TextAlign.Center,
Expand Down
3 changes: 0 additions & 3 deletions android/feature/home/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,4 @@
<string name="title_home">KStreamlined</string>
<string name="feeds_selected">%1$d Feeds selected</string>
<string name="sync">Sync</string>

<string name="error_message_network">Looks like you\'re offline.</string>
<string name="error_message_server">Something went wrong. Please try again later.</string>
</resources>
22 changes: 22 additions & 0 deletions android/feature/kotlin-weekly-issue/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
plugins {
id("kstreamlined.android.library")
id("kstreamlined.android.library.compose")
id("kstreamlined.ksp")
}

android {
namespace = "io.github.reactivecircus.kstreamlined.android.feature.kotlinweeklyissue"
buildFeatures {
androidResources = true
}
}

dependencies {
implementation(project(":feature:common"))
implementation(project(":kmp:data"))
implementation(project(":kmp:presentation:kotlin-weekly-issue"))

// Hilt
implementation(libs.hilt.android)
ksp(libs.hilt.compiler)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest />
Loading

0 comments on commit 8eb709e

Please sign in to comment.