Skip to content

Commit a66ddfe

Browse files
committed
Better layout & style + adjust layout to tablet configuration
1 parent d8e5d7b commit a66ddfe

File tree

11 files changed

+604
-146
lines changed

11 files changed

+604
-146
lines changed

app/src/main/java/net/opatry/adoptacat/MainActivity.kt

Lines changed: 91 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,34 @@ package net.opatry.adoptacat
2424
import android.os.Bundle
2525
import androidx.activity.compose.setContent
2626
import androidx.appcompat.app.AppCompatActivity
27+
import androidx.compose.foundation.layout.Box
28+
import androidx.compose.foundation.layout.Column
29+
import androidx.compose.foundation.layout.Row
30+
import androidx.compose.foundation.layout.fillMaxHeight
31+
import androidx.compose.foundation.layout.fillMaxWidth
32+
import androidx.compose.foundation.layout.height
33+
import androidx.compose.foundation.layout.width
34+
import androidx.compose.material.Divider
2735
import androidx.compose.material.MaterialTheme
2836
import androidx.compose.material.Surface
2937
import androidx.compose.runtime.Composable
30-
import androidx.compose.ui.tooling.preview.Preview
38+
import androidx.compose.runtime.mutableStateOf
39+
import androidx.compose.runtime.getValue
40+
import androidx.compose.runtime.saveable.rememberSaveable
41+
import androidx.compose.runtime.setValue
42+
import androidx.compose.ui.Modifier
43+
import androidx.compose.ui.res.booleanResource
44+
import androidx.compose.ui.res.dimensionResource
45+
import androidx.compose.ui.unit.dp
3146
import androidx.lifecycle.viewmodel.compose.viewModel
3247
import androidx.navigation.compose.NavHost
3348
import androidx.navigation.compose.composable
3449
import androidx.navigation.compose.navigate
3550
import androidx.navigation.compose.rememberNavController
3651
import net.opatry.adoptacat.data.CatRepository
3752
import net.opatry.adoptacat.data.FakeCatDataSource
53+
import net.opatry.adoptacat.model.CatModel
54+
import net.opatry.adoptacat.ui.CatDetailsDispatcher
3855
import net.opatry.adoptacat.ui.CatDetailsScreen
3956
import net.opatry.adoptacat.ui.CatsScreen
4057
import net.opatry.adoptacat.ui.CatsViewModel
@@ -64,38 +81,91 @@ sealed class NavRoute(val path: String) {
6481

6582
@Composable
6683
fun MainLayout(catRepository: CatRepository = (CatRepository((FakeCatDataSource())))) {
67-
val navController = rememberNavController()
6884
val catsViewModel = viewModel<CatsViewModel>(factory = CatsViewModelFactory(catRepository))
6985
Surface(color = MaterialTheme.colors.background) {
70-
NavHost(navController, startDestination = NavRoute.CatsList.path) {
71-
composable(NavRoute.CatsList.path) {
72-
CatsScreen(catsViewModel,
73-
onCatSelected = { cat ->
74-
navController.navigate("${NavRoute.CatDetails.path}/${cat.uuid}")
75-
}
76-
)
86+
if (booleanResource(R.bool.is_tablet)) {
87+
var selectedCatUUID by rememberSaveable { mutableStateOf<UUID?>(null) }
88+
val selectedCat = selectedCatUUID?.let { uuid ->
89+
catsViewModel.findCatByUUID(uuid)
7790
}
78-
composable("${NavRoute.CatDetails.path}/{uuid}") { backStackEntry ->
79-
val uuid = UUID.fromString(backStackEntry.arguments?.get("uuid") as String)
80-
val cat = catsViewModel.findCatByUUID(uuid)
81-
CatDetailsScreen(cat) { navController.popBackStack() }
91+
if (booleanResource(R.bool.is_portrait)) {
92+
MainLayoutTabletPortrait(catsViewModel, selectedCat) { cat ->
93+
selectedCatUUID = cat.uuid
94+
}
95+
} else {
96+
MainLayoutTabletLandscape(catsViewModel, selectedCat) { cat ->
97+
selectedCatUUID = cat.uuid
98+
}
8299
}
100+
} else {
101+
MainLayoutTabletPhone(catsViewModel)
83102
}
84103
}
85104
}
86105

87-
@Preview("Light Theme", widthDp = 360, heightDp = 640)
88106
@Composable
89-
fun LightPreview() {
90-
AdoptACatTheme {
91-
MainLayout()
107+
fun MainLayoutTabletPortrait(catsViewModel: CatsViewModel, selectedCat: CatModel?, onCatSelected: (CatModel) -> Unit) {
108+
Column {
109+
Box(
110+
Modifier
111+
.fillMaxWidth()
112+
.fillMaxHeight(.5f)
113+
) {
114+
CatsScreen(catsViewModel, selectedCat) { onCatSelected(it) }
115+
}
116+
117+
Divider(
118+
Modifier
119+
.fillMaxWidth()
120+
.height(1.dp)
121+
)
122+
123+
Box(
124+
Modifier
125+
.fillMaxWidth()
126+
.fillMaxHeight(.5f)
127+
) {
128+
CatDetailsDispatcher(selectedCat)
129+
}
92130
}
93131
}
94132

95-
@Preview("Dark Theme", widthDp = 360, heightDp = 640)
96133
@Composable
97-
fun DarkPreview() {
98-
AdoptACatTheme(darkTheme = true) {
99-
MainLayout()
134+
fun MainLayoutTabletLandscape(catsViewModel: CatsViewModel, selectedCat: CatModel?, onCatSelected: (CatModel) -> Unit) {
135+
Row {
136+
Box(
137+
Modifier
138+
.width(dimensionResource(R.dimen.cat_list_width_side_by_side))
139+
.fillMaxHeight()
140+
) {
141+
CatsScreen(catsViewModel, selectedCat) { onCatSelected(it) }
142+
}
143+
144+
Divider(
145+
Modifier
146+
.width(1.dp)
147+
.fillMaxHeight()
148+
)
149+
150+
Box(Modifier.fillMaxHeight()) {
151+
CatDetailsDispatcher(selectedCat)
152+
}
153+
}
154+
}
155+
156+
@Composable
157+
fun MainLayoutTabletPhone(catsViewModel: CatsViewModel) {
158+
val navController = rememberNavController()
159+
NavHost(navController, startDestination = NavRoute.CatsList.path) {
160+
composable(NavRoute.CatsList.path) {
161+
CatsScreen(catsViewModel, null) { cat ->
162+
navController.navigate("${NavRoute.CatDetails.path}/${cat.uuid}")
163+
}
164+
}
165+
composable("${NavRoute.CatDetails.path}/{uuid}") { backStackEntry ->
166+
val uuid = UUID.fromString(backStackEntry.arguments?.get("uuid") as String)
167+
val cat = catsViewModel.findCatByUUID(uuid)
168+
CatDetailsScreen(cat) { navController.popBackStack() }
169+
}
100170
}
101171
}

app/src/main/java/net/opatry/adoptacat/data/FakeCatDataSource.kt

Lines changed: 137 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,34 +21,148 @@
2121
*/
2222
package net.opatry.adoptacat.data
2323

24-
import kotlinx.coroutines.delay
2524
import net.opatry.adoptacat.model.CatBreed
2625
import net.opatry.adoptacat.model.CatModel
2726
import net.opatry.adoptacat.model.Gender
2827
import java.util.UUID
2928
import kotlin.random.Random
29+
import kotlin.time.Duration
30+
import kotlin.time.ExperimentalTime
31+
import kotlin.time.days
32+
33+
val catNames = listOf("Alfie", "Angel", "Bella", "Charlie", "Chloe", "Coco", "Daisy", "Felix", "Jasper", "Lily", "Lucky", "Lucy", "Max", "Millie", "Milo", "Missy", "Misty", "Molly", "Oliver", "Oscar", "Poppy", "Sam", "Shadow", "Simba", "Smokey", "Smudge", "Sooty", "Tiger",)
34+
35+
val fakeColors = listOf("IndianRed", "LightCoral", "DarkRed", "PapayaWhip", "RosyBrown", "Sienna", "Brown", "Maroon", "AntiqueWhite", "Linen", "DarkGray", "DimGray", "SlateGray", "Black",)
36+
37+
@ExperimentalTime
38+
fun fakeCat(name: String, breed: CatBreed, pictureUrl: String, gender: Gender, age: Duration) =
39+
CatModel(
40+
uuid = UUID.randomUUID(),
41+
name = name,
42+
breed = breed,
43+
birthdate = System.currentTimeMillis() - age.inMilliseconds.toLong(),
44+
gender = gender,
45+
weightInGram = 0f,
46+
color = fakeColors[Random.nextInt(fakeColors.size)],
47+
pictureUrl = pictureUrl,
48+
adopted = false,
49+
description = "This $breed is a wonderful cat. Like all domestic cats, Turkish Angoras descended from the African wildcat (Felis silvestris lybica). Their ancestors were among the cats that were first domesticated in the Fertile Crescent. Cats from eastern mountainous regions of Anatolia developed into longhaired breeds like the Turkish Van and the Turkish Angora through inbreeding and natural selection. Longhaired cats were imported to Britain and France from Asia Minor, Persia and Russia as early as the late 16th century, though there are indications that they appeared in Europe as early as the 14th century due to the Crusades. The Turkish Angora was used to improve the coat on the Persian, almost to the point of extinction.",
50+
)
3051

3152
class FakeCatDataSource : CatDataSource {
32-
override suspend fun loadCats(): List<CatModel> {
33-
delay(500)
34-
return if (false && Random.nextBoolean())
35-
emptyList()
36-
else mutableListOf<CatModel>().apply {
37-
val breeds = CatBreed.values()
38-
var index = 0
39-
repeat(40) {
40-
this += CatModel(
41-
uuid = UUID.randomUUID(),
42-
name = "Cat ${index++}",
43-
breed = breeds[Random.nextInt(breeds.size)],
44-
birthdate = 0L,
45-
gender = if (Random.nextBoolean()) Gender.Male else Gender.Female,
46-
weightInGram = 0f,
47-
color = "",
48-
pictureUrl = if (Random.nextBoolean()) "https://cdn2.thecatapi.com/images/322.jpg" else "https://cdn2.thecatapi.com/images/a50.jpg",
49-
adopted = false
50-
)
51-
}
52-
}
53-
}
53+
@ExperimentalTime
54+
override suspend fun loadCats(): List<CatModel> = listOf(
55+
fakeCat(
56+
catNames[0],
57+
CatBreed.AmericanCurl,
58+
"https://upload.wikimedia.org/wikipedia/commons/thumb/b/bd/ACL_Pointocurl_Fiorentina.jpg/220px-ACL_Pointocurl_Fiorentina.jpg",
59+
Gender.Male,
60+
50.days,
61+
),
62+
fakeCat(
63+
catNames[1],
64+
CatBreed.Chartreux,
65+
"https://upload.wikimedia.org/wikipedia/commons/thumb/3/3c/IC_Blue_Melody_Flipper_CHA_male_EX1_CACIB.jpg/220px-IC_Blue_Melody_Flipper_CHA_male_EX1_CACIB.jpg",
66+
Gender.Female,
67+
3.days,
68+
),
69+
fakeCat(
70+
catNames[2],
71+
CatBreed.EgyptianMau,
72+
"https://upload.wikimedia.org/wikipedia/commons/thumb/3/3b/Egyptian-mau-Face.jpg/220px-Egyptian-mau-Face.jpg",
73+
Gender.Male,
74+
10.days,
75+
),
76+
fakeCat(
77+
catNames[3],
78+
CatBreed.JapaneseBobtail,
79+
"https://upload.wikimedia.org/wikipedia/commons/thumb/5/56/JapaneseBobtailBlueEyedMi-ke.JPG/220px-JapaneseBobtailBlueEyedMi-ke.JPG",
80+
Gender.Male,
81+
12.days,
82+
),
83+
fakeCat(
84+
catNames[4],
85+
CatBreed.Lykoi,
86+
"https://upload.wikimedia.org/wikipedia/commons/thumb/1/1e/8-month-old_male_Lykoi.jpg/220px-8-month-old_male_Lykoi.jpg",
87+
Gender.Male,
88+
93.days,
89+
),
90+
fakeCat(
91+
catNames[5],
92+
CatBreed.MekongBobtail,
93+
"https://upload.wikimedia.org/wikipedia/commons/thumb/6/65/Mekong_bobtail_%28Thai_bobtail%29._Tabby-point..jpg/220px-Mekong_bobtail_%28Thai_bobtail%29._Tabby-point..jpg",
94+
Gender.Female,
95+
40.days,
96+
),
97+
fakeCat(
98+
catNames[6],
99+
CatBreed.PersianModernPersianCat,
100+
"https://upload.wikimedia.org/wikipedia/commons/thumb/1/15/White_Persian_Cat.jpg/220px-White_Persian_Cat.jpg",
101+
Gender.Female,
102+
35.days,
103+
),
104+
fakeCat(
105+
catNames[7],
106+
CatBreed.Ragamuffin,
107+
"https://upload.wikimedia.org/wikipedia/commons/thumb/a/a1/Ragamuffin_kitten-GRACIE.png/220px-Ragamuffin_kitten-GRACIE.png",
108+
Gender.Female,
109+
120.days,
110+
),
111+
fakeCat(
112+
catNames[8],
113+
CatBreed.Savannah,
114+
"https://upload.wikimedia.org/wikipedia/commons/thumb/2/2c/Savannah.jpg/220px-Savannah.jpg",
115+
Gender.Male,
116+
6.days,
117+
),
118+
fakeCat(
119+
catNames[9],
120+
CatBreed.ScottishFold,
121+
"https://upload.wikimedia.org/wikipedia/commons/thumb/8/83/Lilac_Scottish_Fold.jpg/220px-Lilac_Scottish_Fold.jpg",
122+
Gender.Male,
123+
360.days,
124+
),
125+
fakeCat(
126+
catNames[10],
127+
CatBreed.Siamese,
128+
"https://upload.wikimedia.org/wikipedia/commons/thumb/1/14/Sealpoint-siamese-hybrid.jpg/150px-Sealpoint-siamese-hybrid.jpg",
129+
Gender.Female,
130+
8.days,
131+
),
132+
fakeCat(
133+
catNames[11],
134+
CatBreed.Singapura,
135+
"https://upload.wikimedia.org/wikipedia/commons/thumb/9/9b/Raw_Singapura.jpg/220px-Raw_Singapura.jpg",
136+
Gender.Male,
137+
950.days,
138+
),
139+
fakeCat(
140+
catNames[12],
141+
CatBreed.Sphynx,
142+
"https://upload.wikimedia.org/wikipedia/commons/thumb/6/60/Sphynx_cat_wearing_clothes.jpg/469px-Sphynx_cat_wearing_clothes.jpg",
143+
Gender.Female,
144+
90.days,
145+
),
146+
fakeCat(
147+
catNames[13],
148+
CatBreed.Thai,
149+
"https://upload.wikimedia.org/wikipedia/commons/thumb/5/57/Mimbi3.JPG/220px-Mimbi3.JPG",
150+
Gender.Male,
151+
3.days,
152+
),
153+
fakeCat(
154+
catNames[14],
155+
CatBreed.TurkishAngora,
156+
"https://upload.wikimedia.org/wikipedia/commons/thumb/d/df/TUA_Eur.Ch._Akkedi_Yuran_%2811322070486%29.jpg/220px-TUA_Eur.Ch._Akkedi_Yuran_%2811322070486%29.jpg",
157+
Gender.Female,
158+
1.days,
159+
),
160+
fakeCat(
161+
"Buggy",
162+
CatBreed.Sokoke,
163+
"BROKEN",
164+
Gender.Male,
165+
0.days,
166+
),
167+
)
54168
}

0 commit comments

Comments
 (0)