Skip to content

Commit 5de34bb

Browse files
committed
Complete README and add screenshots
1 parent 2803fab commit 5de34bb

File tree

8 files changed

+105
-4
lines changed

8 files changed

+105
-4
lines changed

README.md

Lines changed: 105 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,118 @@
33
[![Workflow result](https://github.com/opatry/android-dev-challenge-compose-week1/workflows/Check/badge.svg)](https://github.com/opatry/android-dev-challenge-compose-week1/actions/workflows/Check.yaml)
44

55
## :scroll: Description
6-
<!--- Describe your app in one or two sentences -->
76

7+
This is a simple master/detail app with a fake list of clickable data displaying more detailed information about it.
88

99
## :bulb: Motivation and Context
10-
<!--- Optionally point readers to interesting parts of your submission. -->
11-
<!--- What are you especially proud of? -->
1210

11+
My goal was mainly to see how Jetpack Compose handles Navigation and Multiple form factor/layouts.
12+
13+
I'm proud of my work because I started late (was in holiday when challenge was first announced) and didn't spent a lot of time on this.
14+
Still, I managed to submit a working version on time implementing Jetpack navigation and dedicated support of tablet.
15+
16+
---
17+
18+
I used MVVM, Unidirectional Data Flow and UI State pattern.
19+
Each state has its own composable, see `CatsScreen.kt`.
20+
21+
<details>
22+
<summary>Show me the code!</summary>
23+
24+
```kotlin
25+
@Composable
26+
fun CatsScreen(viewModel: CatsViewModel, selectedCat: CatModel?, onCatSelected: (CatModel) -> Unit) {
27+
Scaffold(
28+
topBar = { /* */ },
29+
content = {
30+
val state by viewModel.catsState.observeAsState(CatsScreenState.Loading)
31+
CatsStateDispatcher(uiState = state, selectedCat, onCatSelected)
32+
}
33+
)
34+
}
35+
36+
@Composable
37+
fun CatsStateDispatcher(uiState: CatsScreenState, selectedCat: CatModel?, onCatSelected: (CatModel) -> Unit) {
38+
when (uiState) {
39+
CatsScreenState.Loading -> LoadingCatsContent()
40+
is CatsScreenState.Error -> ErrorCatsContent(uiState.cause)
41+
CatsScreenState.Empty -> EmptyCatsContent()
42+
is CatsScreenState.Loaded -> LoadedCatsContent(uiState.cats, selectedCat, onCatSelected)
43+
}
44+
}
45+
```
46+
47+
</details>
48+
49+
---
50+
51+
I implemented a `MainLayout` composable to choose how to present the UI depending on device configuration, see `MainActivity.kt/MainLayout`.
52+
53+
<details>
54+
<summary>Show me the code!</summary>
55+
56+
```kotlin
57+
sealed class NavRoute(val path: String) {
58+
object CatsList : NavRoute("cats")
59+
object CatDetails : NavRoute("cat.details")
60+
}
61+
62+
@Composable
63+
fun MainLayout(catRepository: CatRepository = (CatRepository((FakeCatDataSource())))) {
64+
val catsViewModel = viewModel<CatsViewModel>(factory = CatsViewModelFactory(catRepository))
65+
Surface(color = MaterialTheme.colors.background) {
66+
if (booleanResource(R.bool.is_tablet)) {
67+
var selectedCatUUID by rememberSaveable { mutableStateOf<UUID?>(null) }
68+
val selectedCat = selectedCatUUID?.let { uuid ->
69+
catsViewModel.findCatByUUID(uuid)
70+
}
71+
if (booleanResource(R.bool.is_portrait)) {
72+
MainLayoutTabletPortrait(catsViewModel, selectedCat) { cat ->
73+
selectedCatUUID = cat.uuid
74+
}
75+
} else {
76+
MainLayoutTabletLandscape(catsViewModel, selectedCat) { cat ->
77+
selectedCatUUID = cat.uuid
78+
}
79+
}
80+
} else {
81+
val navController = rememberNavController()
82+
NavHost(navController, startDestination = NavRoute.CatsList.path) {
83+
composable(NavRoute.CatsList.path) {
84+
CatsScreen(catsViewModel, null) { cat ->
85+
navController.navigate("${NavRoute.CatDetails.path}/${cat.uuid}")
86+
}
87+
}
88+
composable("${NavRoute.CatDetails.path}/{uuid}") { backStackEntry ->
89+
val uuid = UUID.fromString(backStackEntry.arguments?.get("uuid") as String)
90+
val cat = catsViewModel.findCatByUUID(uuid)
91+
CatDetailsScreen(cat) { navController.popBackStack() }
92+
}
93+
}
94+
}
95+
}
96+
}
97+
```
98+
</details>
99+
100+
I didn't see guidelines regarding how to handle tablet and side-by-side layouts, maybe there is something better 🤷‍♂️.
13101

14102
## :camera_flash: Screenshots
15103

16-
<img src="/results/screenshot_1.png" width="260">&emsp;<img src="/results/screenshot_2.png" width="260">
104+
## 🌞 Light Mode
105+
List | Details | Tablet
106+
--- | --- | --- |
107+
<img src="/results/screenshot_1.png" width="260"> | <img src="/results/screenshot_2.png" width="260"> | <img src="/results/screenshot_3.png" width="520">
108+
109+
<br />
110+
111+
## 🌚 Dark Mode
112+
List | Details | Tablet
113+
--- | --- | --- |
114+
<img src="/results/screenshot_1_dark.png" width="260"> | <img src="/results/screenshot_2_dark.png" width="260"> | <img src="/results/screenshot_3_dark.png" width="520">
115+
116+
<br />
117+
17118

18119
## License
19120
```

results/screenshot_1.png

530 KB
Loading

results/screenshot_1_dark.png

561 KB
Loading

results/screenshot_2.png

322 KB
Loading

results/screenshot_2_dark.png

352 KB
Loading

results/screenshot_3.png

517 KB
Loading

results/screenshot_3_dark.png

513 KB
Loading

results/video.mp4

7.57 MB
Binary file not shown.

0 commit comments

Comments
 (0)