Skip to content

Commit 378f744

Browse files
authored
Merge pull request #6 from CGreenP/dev
feat: Implement Navigation and Update UI State Handling
2 parents b699eba + 9e0c5cb commit 378f744

7 files changed

Lines changed: 144 additions & 35 deletions

File tree

app/src/main/java/com/example/techexactly/MainActivity.kt

Lines changed: 4 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,44 +4,19 @@ import android.os.Bundle
44
import androidx.activity.ComponentActivity
55
import androidx.activity.compose.setContent
66
import androidx.activity.enableEdgeToEdge
7-
import androidx.compose.foundation.layout.fillMaxSize
8-
import androidx.compose.foundation.layout.padding
9-
import androidx.compose.material3.Scaffold
10-
import androidx.compose.material3.Text
11-
import androidx.compose.runtime.Composable
12-
import androidx.compose.ui.Modifier
13-
import androidx.compose.ui.tooling.preview.Preview
7+
import androidx.navigation.compose.rememberNavController
148
import com.example.techexactly.ui.theme.TechExactlyTheme
9+
import com.example.techexactly.view.navigation.SetupNavGraph
1510

1611
class MainActivity : ComponentActivity() {
1712
override fun onCreate(savedInstanceState: Bundle?) {
1813
super.onCreate(savedInstanceState)
1914
enableEdgeToEdge()
2015
setContent {
2116
TechExactlyTheme {
22-
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
23-
Greeting(
24-
name = "Android",
25-
modifier = Modifier.padding(innerPadding)
26-
)
27-
}
17+
val navController = rememberNavController()
18+
SetupNavGraph(navController = navController)
2819
}
2920
}
3021
}
31-
}
32-
33-
@Composable
34-
fun Greeting(name: String, modifier: Modifier = Modifier) {
35-
Text(
36-
text = "Hello $name!",
37-
modifier = modifier
38-
)
39-
}
40-
41-
@Preview(showBackground = true)
42-
@Composable
43-
fun GreetingPreview() {
44-
TechExactlyTheme {
45-
Greeting("Android")
46-
}
4722
}

app/src/main/java/com/example/techexactly/model/dataclass/User.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package com.example.techexactly.model.dataclass
22

3+
import kotlinx.serialization.Serializable
4+
5+
@Serializable
36
data class User(
47
val id: Long,
58
val name: String,
@@ -11,6 +14,7 @@ data class User(
1114
val company: Company,
1215
)
1316

17+
@Serializable
1418
data class Address(
1519
val street: String,
1620
val suite: String,
@@ -19,11 +23,13 @@ data class Address(
1923
val geo: Geo,
2024
)
2125

26+
@Serializable
2227
data class Geo(
2328
val lat: String,
2429
val lng: String,
2530
)
2631

32+
@Serializable
2733
data class Company(
2834
val name: String,
2935
val catchPhrase: String,

app/src/main/java/com/example/techexactly/view/home/HomeScreenContent.kt

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,27 @@
11
package com.example.techexactly.view.home
22

3+
import androidx.compose.foundation.layout.Arrangement
34
import androidx.compose.foundation.layout.Box
5+
import androidx.compose.foundation.layout.Column
6+
import androidx.compose.foundation.layout.Spacer
47
import androidx.compose.foundation.layout.fillMaxSize
8+
import androidx.compose.foundation.layout.fillMaxWidth
9+
import androidx.compose.foundation.layout.height
10+
import androidx.compose.foundation.layout.size
11+
import androidx.compose.material.icons.Icons
12+
import androidx.compose.material.icons.filled.Warning
13+
import androidx.compose.material3.Button
514
import androidx.compose.material3.CircularProgressIndicator
15+
import androidx.compose.material3.Icon
616
import androidx.compose.material3.MaterialTheme
717
import androidx.compose.material3.Text
818
import androidx.compose.runtime.Composable
919
import androidx.compose.runtime.collectAsState
1020
import androidx.compose.runtime.getValue
1121
import androidx.compose.ui.Alignment
1222
import androidx.compose.ui.Modifier
23+
import androidx.compose.ui.text.style.TextAlign
24+
import androidx.compose.ui.unit.dp
1325
import com.example.techexactly.model.dataclass.User
1426
import com.example.techexactly.viewmodel.MainViewModel
1527
import com.example.techexactly.viewmodel.UiState
@@ -24,15 +36,45 @@ fun HomeScreenContent(
2436
) {
2537
when (val state = uiState) {
2638
is UiState.Error -> {
27-
Text(
28-
text = state.errorMessage,
29-
modifier = Modifier.align(Alignment.Center),
30-
style = MaterialTheme.typography.bodyMedium
31-
)
39+
Column(
40+
horizontalAlignment = Alignment.CenterHorizontally,
41+
verticalArrangement = Arrangement.Center,
42+
) {
43+
Icon(
44+
imageVector = Icons.Default.Warning,
45+
contentDescription = "ERROR",
46+
modifier = Modifier.size(48.dp),
47+
tint = MaterialTheme.colorScheme.error
48+
)
49+
Spacer(modifier = Modifier.height(8.dp))
50+
Text(
51+
text = "Error",
52+
modifier = Modifier.fillMaxWidth(),
53+
style = MaterialTheme.typography.headlineSmall,
54+
textAlign = TextAlign.Center,
55+
color = MaterialTheme.colorScheme.error
56+
)
57+
Spacer(modifier = Modifier.height(8.dp))
58+
Text(
59+
text = state.errorMessage,
60+
modifier = Modifier.fillMaxWidth(),
61+
style = MaterialTheme.typography.bodyMedium,
62+
textAlign = TextAlign.Center,
63+
)
64+
Spacer(modifier = Modifier.height(8.dp))
65+
Button(onClick = { mainViewModel.fetchUsers() }) {
66+
Text(text = "Retry?")
67+
}
68+
}
3269
}
3370

3471
is UiState.Loading -> {
35-
CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
72+
CircularProgressIndicator(
73+
modifier = Modifier
74+
.align(Alignment.Center)
75+
.size(48.dp),
76+
color = MaterialTheme.colorScheme.primary,
77+
)
3678
}
3779

3880
is UiState.Success -> {
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.example.techexactly.view.navigation
2+
3+
import android.net.Uri
4+
import android.os.Bundle
5+
import androidx.navigation.NavType
6+
import com.example.techexactly.model.dataclass.User
7+
import kotlinx.serialization.json.Json
8+
9+
object CustomNavType {
10+
val UserType = object : NavType<User>(
11+
isNullableAllowed = false
12+
) {
13+
override fun get(
14+
bundle: Bundle, key: String
15+
): User? {
16+
return Json.decodeFromString(bundle.getString(key) ?: return null)
17+
}
18+
19+
override fun parseValue(value: String): User {
20+
return Json.decodeFromString(Uri.decode(value))
21+
}
22+
23+
override fun serializeAsValue(value: User): String {
24+
return Uri.encode(Json.encodeToString(value))
25+
}
26+
27+
override fun put(
28+
bundle: Bundle, key: String, value: User
29+
) {
30+
bundle.putString(key, Json.encodeToString(value))
31+
}
32+
33+
}
34+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.example.techexactly.view.navigation
2+
3+
import androidx.compose.runtime.Composable
4+
import androidx.navigation.NavHostController
5+
import androidx.navigation.compose.NavHost
6+
import androidx.navigation.compose.composable
7+
import androidx.navigation.toRoute
8+
import com.example.techexactly.model.dataclass.User
9+
import com.example.techexactly.view.home.HomeScreen
10+
import com.example.techexactly.view.user.UserDetailsScreen
11+
import kotlin.reflect.typeOf
12+
13+
14+
@Composable
15+
fun SetupNavGraph(
16+
navController: NavHostController
17+
) {
18+
NavHost(
19+
navController = navController, startDestination = Dest.HomeScreen
20+
) {
21+
composable<Dest.HomeScreen> {
22+
HomeScreen(
23+
onUserClicked = { user ->
24+
navController.navigate(Dest.UserDetailsScreen(user))
25+
})
26+
}
27+
composable<Dest.UserDetailsScreen>(
28+
typeMap = mapOf(
29+
typeOf<User>() to CustomNavType.UserType
30+
)
31+
) {
32+
val args = it.toRoute<Dest.UserDetailsScreen>()
33+
UserDetailsScreen(
34+
user = args.user, onBackClicked = { navController.popBackStack() })
35+
}
36+
}
37+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.example.techexactly.view.navigation
2+
3+
import com.example.techexactly.model.dataclass.User
4+
import kotlinx.serialization.Serializable
5+
6+
sealed class Dest {
7+
8+
@Serializable
9+
data object HomeScreen : Dest()
10+
11+
@Serializable
12+
data class UserDetailsScreen(val user: User) : Dest()
13+
14+
}

app/src/main/java/com/example/techexactly/viewmodel/MainViewModel.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class MainViewModel(private val userRepository: UserRepository) : ViewModel() {
1818

1919
fun fetchUsers() {
2020
viewModelScope.launch {
21+
_uiState.value = UiState.Loading
2122
userRepository.getUsers().collect { result ->
2223
when (result.isSuccess) {
2324
true -> {

0 commit comments

Comments
 (0)