Skip to content
Merged
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
10 changes: 9 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ plugins {
id "org.jetbrains.kotlin.plugin.compose" version "$kotlin_version"
id "dagger.hilt.android.plugin"
id "kotlin-parcelize"
id 'org.jetbrains.kotlin.plugin.serialization' version '2.0.21'
}

android {
Expand Down Expand Up @@ -70,7 +71,6 @@ dependencies {
implementation 'androidx.compose.material3.adaptive:adaptive-layout'
implementation 'androidx.compose.material3.adaptive:adaptive-navigation'


// Jetpack Compose BOM
implementation platform("androidx.compose:compose-bom:$compose_bom_version")
implementation "androidx.compose.ui:ui"
Expand All @@ -95,6 +95,14 @@ dependencies {
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
implementation "androidx.navigation:navigation-compose:$nav_version"
implementation("androidx.navigation:navigation-runtime-ktx:$nav_version") {
version {
// 'strictly' forces this version. No other version is allowed.
strictly nav_version
}
because("blah!")
}
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3"

// Dagger Hilt
implementation "com.google.dagger:hilt-android:$hilt_version"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.Home
import androidx.compose.ui.graphics.vector.ImageVector
import com.mohitb117.demo_omdb_api.R
import kotlinx.serialization.Serializable

@Serializable
enum class AppDestinations(
@param:StringRes val label: Int,
val icon: ImageVector,
Expand All @@ -16,4 +18,15 @@ enum class AppDestinations(
HOME(R.string.home, Icons.Default.Home, R.string.home),
FAVORITES(R.string.favorites, Icons.Default.Favorite, R.string.favorites),
Feed(R.string.feed, Icons.Default.DynamicFeed, R.string.feed)
}

@Serializable
sealed class ItemDetailDestination {
@Serializable
data object Home: ItemDetailDestination()

@Serializable
data class Details(
val name: String
): ItemDetailDestination()
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffo
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
Expand All @@ -35,6 +34,10 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.compose.rememberNavController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.toRoute
import com.mohitb117.demo_omdb_api.activities.ui.theme.DEMO_OMDB_APITheme
import com.mohitb117.demo_omdb_api.activities.ui.theme.Purple80
import com.mohitb117.demo_omdb_api.datamodels.SearchResult
Expand Down Expand Up @@ -99,77 +102,37 @@ class LaunchingActivity : ComponentActivity() {
onToggleMovieFavorited: suspend (SearchResult) -> Boolean = { false },
) {
var currentDestination by rememberSaveable { mutableStateOf(AppDestinations.HOME) }
val navController = rememberNavController()
val onItemTapped: (ItemDetailDestination.Details) -> Unit = { navController.navigate(it) }
val onDestinationChanged: (AppDestinations) -> Unit = { currentDestination = it }

NavigationSuiteScaffold(
navigationSuiteItems = {
AppDestinations.entries.forEach {
item(
icon = {
Icon(it.icon, stringResource(it.contentDescription))
},
modifier = Modifier,
label = { Text(stringResource(it.label)) },
selected = it == currentDestination,
onClick = { currentDestination = it },
)
}
}) {
val searchResultError = (searchUiState as? Result.Failure)?.error

Scaffold(
modifier = Modifier.fillMaxSize(),
topBar = {
Text(
modifier = Modifier
.fillMaxWidth()
.windowInsetsPadding(WindowInsets.statusBars)
.padding(horizontal = 16.dp, vertical = 8.dp),
text = searchResultError?.localizedMessage ?: stringResource(currentDestination.label),
color = if (searchResultError != null) Color.Red else Color.Unspecified,
)
},
bottomBar = {
if (currentDestination == AppDestinations.HOME) {
OutlinedTextField(
modifier = Modifier
.fillMaxWidth()
.background(color = Purple80),
value = searchQuery,
onValueChange = { onSearchQueryChanged(it) },
label = { Text(text = "Search Movie!") })
}
}
) { innerPadding ->
when (currentDestination) {
AppDestinations.HOME -> {
SearchMovieInfoLayout(
modifier = Modifier.padding(innerPadding),
searchQuery = searchQuery,
searchUiState = searchUiState,
isRefreshing = isRefreshing,
onRefresh = onRefresh,
isMovieFavourited = isMovieFavourited,
onToggleMovieFavorited = onToggleMovieFavorited,
)
}
NavHost(navController, startDestination = ItemDetailDestination.Home) {
composable<ItemDetailDestination.Home> {
HomeComposable(
currentDestination = currentDestination,
searchUiState = searchUiState,
searchQuery = searchQuery,
onSearchQueryChanged = onSearchQueryChanged,
isRefreshing = isRefreshing,
onRefresh = onRefresh,
isMovieFavourited = isMovieFavourited,
onToggleMovieFavorited = onToggleMovieFavorited,
onItemTapped = onItemTapped,
favouritesUiState = favouritesUiState,
onDestinationChanged = onDestinationChanged,
)
}

AppDestinations.Feed -> {
FeedComposableLayout(
modifier = Modifier.padding(innerPadding),
uiState = favouritesUiState,
isMovieFavourited = isMovieFavourited,
onToggleMovieFavorited = onToggleMovieFavorited,
)
}
composable<ItemDetailDestination.Details> { backStackEntry ->
val movie: ItemDetailDestination.Details = backStackEntry.toRoute()

AppDestinations.FAVORITES -> {
FavouritesComposableLayout(
modifier = Modifier.padding(innerPadding),
uiState = favouritesUiState,
isMovieFavourited = isMovieFavourited,
onToggleMovieFavorited = onToggleMovieFavorited,
)
}
val windowInset = WindowInsets.statusBars
Column(
modifier = Modifier
.fillMaxSize()
.windowInsetsPadding(windowInset),
) {
Text("You tapped on ${movie.name}")
}
}
}
Expand All @@ -184,6 +147,7 @@ class LaunchingActivity : ComponentActivity() {
onRefresh: () -> Unit = {},
isMovieFavourited: (SearchResult) -> Boolean = { false },
onToggleMovieFavorited: suspend (SearchResult) -> Boolean = { false },
onItemTapped: (ItemDetailDestination.Details) -> Unit = {}
) {
Column(
modifier = modifier.fillMaxSize(),
Expand All @@ -207,6 +171,7 @@ class LaunchingActivity : ComponentActivity() {
isRefreshing = isRefreshing,
onToggleMovieFavorited = onToggleMovieFavorited,
isMovieFavourited = isMovieFavourited,
onItemTapped = onItemTapped,
)

} else {
Expand All @@ -221,6 +186,7 @@ class LaunchingActivity : ComponentActivity() {
modifier: Modifier = Modifier,
isMovieFavourited: (SearchResult) -> Boolean = { false },
onToggleMovieFavorited: suspend (SearchResult) -> Boolean = { false },
onItemTapped: (ItemDetailDestination.Details) -> Unit = {}
) {
Column(
modifier = modifier.fillMaxSize(),
Expand All @@ -233,6 +199,7 @@ class LaunchingActivity : ComponentActivity() {
uiState = uiState,
onToggleMovieFavorited = onToggleMovieFavorited,
isMovieFavourited = isMovieFavourited,
onItemTapped = onItemTapped,
)
}
}
Expand All @@ -243,6 +210,7 @@ class LaunchingActivity : ComponentActivity() {
modifier: Modifier = Modifier,
isMovieFavourited: (SearchResult) -> Boolean = { false },
onToggleMovieFavorited: suspend (SearchResult) -> Boolean = { false },
onItemTapped: (ItemDetailDestination.Details) -> Unit = {}
) {
Column(
modifier = modifier.fillMaxSize(),
Expand All @@ -255,6 +223,7 @@ class LaunchingActivity : ComponentActivity() {
uiState = uiState,
onToggleMovieFavorited = onToggleMovieFavorited,
isMovieFavourited = isMovieFavourited,
onItemTapped = onItemTapped,
)
}
}
Expand All @@ -281,4 +250,98 @@ class LaunchingActivity : ComponentActivity() {
)
}
}
}

@Composable
private fun HomeComposable(
currentDestination: AppDestinations,
searchUiState: Result<SearchResultsBody>,
searchQuery: String,
onSearchQueryChanged: (String) -> Unit,
isRefreshing: Boolean,
onRefresh: () -> Unit,
isMovieFavourited: (SearchResult) -> Boolean,
onToggleMovieFavorited: suspend (SearchResult) -> Boolean,
onItemTapped: (ItemDetailDestination.Details) -> Unit,
favouritesUiState: Set<SearchResult>,
onDestinationChanged: (AppDestinations) -> Unit
) {
NavigationSuiteScaffold(
navigationSuiteItems = {
AppDestinations.entries.forEach {
item(
icon = {
Icon(it.icon, stringResource(it.contentDescription))
},
modifier = Modifier,
label = { Text(stringResource(it.label)) },
selected = it == currentDestination,
onClick = { onDestinationChanged(it) },
)
}
}) {
val searchResultError = (searchUiState as? Result.Failure)?.error

Scaffold(
modifier = Modifier.fillMaxSize(),
topBar = {
Text(
modifier = Modifier
.fillMaxWidth()
.windowInsetsPadding(WindowInsets.statusBars)
.padding(horizontal = 16.dp, vertical = 8.dp),
text = searchResultError?.localizedMessage ?: stringResource(
currentDestination.label
),
color = if (searchResultError != null) Color.Red else Color.Unspecified,
)
},
bottomBar = {
if (currentDestination == AppDestinations.HOME) {
OutlinedTextField(
modifier = Modifier
.fillMaxWidth()
.background(color = Purple80),
value = searchQuery,
onValueChange = { onSearchQueryChanged(it) },
label = { Text(text = "Search Movie!") })
}
}
) { innerPadding ->
when (currentDestination) {
AppDestinations.HOME -> {
SearchMovieInfoLayout(
modifier = Modifier.padding(innerPadding),
searchQuery = searchQuery,
searchUiState = searchUiState,
isRefreshing = isRefreshing,
onRefresh = onRefresh,
isMovieFavourited = isMovieFavourited,
onToggleMovieFavorited = onToggleMovieFavorited,
onItemTapped = onItemTapped,
)
}

AppDestinations.Feed -> {
FeedComposableLayout(
modifier = Modifier.padding(innerPadding),
uiState = favouritesUiState,
isMovieFavourited = isMovieFavourited,
onToggleMovieFavorited = onToggleMovieFavorited,
onItemTapped = onItemTapped,
)
}

AppDestinations.FAVORITES -> {
FavouritesComposableLayout(
modifier = Modifier.padding(innerPadding),
uiState = favouritesUiState,
isMovieFavourited = isMovieFavourited,
onToggleMovieFavorited = onToggleMovieFavorited,
onItemTapped = onItemTapped,
)
}
}
}
}
}
}
Loading