Skip to content

Commit b699eba

Browse files
authored
Merge pull request #5 from CGreenP/dev
feat: Implement UI for Home and User Details screens
2 parents b668070 + c2fb002 commit b699eba

12 files changed

Lines changed: 919 additions & 1 deletion

File tree

.idea/misc.xml

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.example.techexactly.view.home
2+
3+
import androidx.compose.foundation.layout.Box
4+
import androidx.compose.foundation.layout.fillMaxSize
5+
import androidx.compose.foundation.layout.padding
6+
import androidx.compose.material3.ExperimentalMaterial3Api
7+
import androidx.compose.material3.Scaffold
8+
import androidx.compose.material3.TopAppBarDefaults
9+
import androidx.compose.runtime.Composable
10+
import androidx.compose.ui.Modifier
11+
import androidx.compose.ui.input.nestedscroll.nestedScroll
12+
import androidx.compose.ui.res.stringResource
13+
import com.example.techexactly.R
14+
import com.example.techexactly.model.dataclass.User
15+
import com.example.techexactly.viewmodel.MainViewModel
16+
import org.koin.androidx.compose.koinViewModel
17+
18+
@OptIn(ExperimentalMaterial3Api::class)
19+
@Composable
20+
fun HomeScreen(
21+
onUserClicked: (User) -> Unit, mainViewModel: MainViewModel = koinViewModel<MainViewModel>()
22+
) {
23+
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
24+
Scaffold(
25+
modifier = Modifier
26+
.fillMaxSize()
27+
.nestedScroll(scrollBehavior.nestedScrollConnection),
28+
topBar = {
29+
HomeScreenTopBar(
30+
title = stringResource(id = R.string.app_name),
31+
subtitle = "Users",
32+
scrollBehavior = scrollBehavior
33+
)
34+
}) { innerPadding ->
35+
Box(
36+
modifier = Modifier
37+
.fillMaxSize()
38+
.padding(innerPadding)
39+
) {
40+
HomeScreenContent(onUserClicked = onUserClicked, mainViewModel = mainViewModel)
41+
}
42+
}
43+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.example.techexactly.view.home
2+
3+
import androidx.compose.foundation.layout.Box
4+
import androidx.compose.foundation.layout.fillMaxSize
5+
import androidx.compose.material3.CircularProgressIndicator
6+
import androidx.compose.material3.MaterialTheme
7+
import androidx.compose.material3.Text
8+
import androidx.compose.runtime.Composable
9+
import androidx.compose.runtime.collectAsState
10+
import androidx.compose.runtime.getValue
11+
import androidx.compose.ui.Alignment
12+
import androidx.compose.ui.Modifier
13+
import com.example.techexactly.model.dataclass.User
14+
import com.example.techexactly.viewmodel.MainViewModel
15+
import com.example.techexactly.viewmodel.UiState
16+
17+
@Composable
18+
fun HomeScreenContent(
19+
onUserClicked: (User) -> Unit, mainViewModel: MainViewModel
20+
) {
21+
val uiState by mainViewModel.uiState.collectAsState()
22+
Box(
23+
modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center
24+
) {
25+
when (val state = uiState) {
26+
is UiState.Error -> {
27+
Text(
28+
text = state.errorMessage,
29+
modifier = Modifier.align(Alignment.Center),
30+
style = MaterialTheme.typography.bodyMedium
31+
)
32+
}
33+
34+
is UiState.Loading -> {
35+
CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
36+
}
37+
38+
is UiState.Success -> {
39+
UserList(users = state.users, onUserClicked = onUserClicked)
40+
}
41+
}
42+
}
43+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package com.example.techexactly.view.home
2+
3+
import androidx.compose.foundation.layout.Column
4+
import androidx.compose.material3.CenterAlignedTopAppBar
5+
import androidx.compose.material3.ExperimentalMaterial3Api
6+
import androidx.compose.material3.MaterialTheme
7+
import androidx.compose.material3.Text
8+
import androidx.compose.material3.TopAppBarDefaults
9+
import androidx.compose.material3.TopAppBarScrollBehavior
10+
import androidx.compose.runtime.Composable
11+
import androidx.compose.ui.Alignment
12+
import androidx.compose.ui.res.stringResource
13+
import androidx.compose.ui.text.style.TextOverflow
14+
import androidx.compose.ui.tooling.preview.Preview
15+
import com.example.techexactly.R
16+
17+
@OptIn(ExperimentalMaterial3Api::class)
18+
@Composable
19+
fun HomeScreenTopBar(
20+
title: String, subtitle: String, scrollBehavior: TopAppBarScrollBehavior
21+
) {
22+
CenterAlignedTopAppBar(
23+
title = {
24+
Column(
25+
horizontalAlignment = Alignment.CenterHorizontally
26+
) {
27+
Text(
28+
text = title, maxLines = 1, overflow = TextOverflow.Ellipsis
29+
)
30+
Text(
31+
text = subtitle, style = MaterialTheme.typography.labelMedium
32+
)
33+
}
34+
}, navigationIcon = {}, scrollBehavior = scrollBehavior
35+
)
36+
}
37+
38+
@Preview
39+
@OptIn(ExperimentalMaterial3Api::class)
40+
@Composable
41+
fun HomeScreenTopBarPreview() {
42+
HomeScreenTopBar(
43+
title = stringResource(id = R.string.app_name),
44+
subtitle = "Users",
45+
scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
46+
)
47+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package com.example.techexactly.view.home
2+
3+
import androidx.compose.foundation.layout.Arrangement
4+
import androidx.compose.foundation.layout.fillMaxWidth
5+
import androidx.compose.foundation.layout.padding
6+
import androidx.compose.foundation.lazy.LazyColumn
7+
import androidx.compose.foundation.lazy.items
8+
import androidx.compose.runtime.Composable
9+
import androidx.compose.ui.Alignment
10+
import androidx.compose.ui.Modifier
11+
import androidx.compose.ui.tooling.preview.Preview
12+
import androidx.compose.ui.unit.dp
13+
import com.example.techexactly.model.dataclass.Address
14+
import com.example.techexactly.model.dataclass.Company
15+
import com.example.techexactly.model.dataclass.Geo
16+
import com.example.techexactly.model.dataclass.User
17+
18+
@Composable
19+
fun UserList(users: List<User>, onUserClicked: (User) -> Unit) {
20+
LazyColumn(
21+
modifier = Modifier
22+
.fillMaxWidth()
23+
.padding(horizontal = 8.dp),
24+
verticalArrangement = Arrangement.spacedBy(8.dp),
25+
horizontalAlignment = Alignment.CenterHorizontally
26+
) {
27+
items(users, key = { it.id }) { user ->
28+
UserListItem(user = user, onUserClicked = onUserClicked)
29+
}
30+
item {
31+
UserListFooter()
32+
}
33+
}
34+
}
35+
36+
@Preview(showBackground = true)
37+
@Composable
38+
fun PreviewUserList() {
39+
val users = listOf(
40+
User(
41+
id = 1,
42+
name = "Leanne Graham",
43+
username = "Bret",
44+
email = "Sincere@april.biz",
45+
address = Address(
46+
"Kulas Light", "Apt. 556", "Gwenborough", "92998-3874", Geo("-37.3159", "81.1496")
47+
),
48+
phone = "1-770-736-8031 x56442",
49+
website = "hildegard.org",
50+
company = Company(
51+
"Romaguera-Crona",
52+
"Multi-layered client-server neural-net",
53+
"harness real-time e-markets"
54+
)
55+
), User(
56+
id = 2,
57+
name = "Ervin Howell",
58+
username = "Antonette",
59+
email = "Shanna@melissa.tv",
60+
address = Address(
61+
"Victor Plains",
62+
"Suite 879",
63+
"Wisokyburgh",
64+
"90566-7771",
65+
Geo("-43.9509", "-34.4618")
66+
),
67+
phone = "010-692-6593 x09125",
68+
website = "anastasia.net",
69+
company = Company(
70+
"Deckow-Crist", "Proactive didactic contingency", "synergize scalable supply-chains"
71+
),
72+
), User(
73+
id = 3,
74+
name = "Clementine Bauch",
75+
username = "Samantha",
76+
email = "Nathan@yesenia.net",
77+
address = Address(
78+
"Douglas Extension",
79+
"Suite 847",
80+
"McKenziehaven",
81+
"59590-4157",
82+
Geo("-68.6102", "-47.0653")
83+
),
84+
phone = "1-463-123-4447",
85+
website = "ramiro.info",
86+
company = Company(
87+
"Romaguera-Jacobson",
88+
"Face to face bifurcated interface",
89+
"e-enable strategic applications"
90+
)
91+
)
92+
)
93+
94+
UserList(users = users, onUserClicked = {})
95+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.example.techexactly.view.home
2+
3+
import androidx.compose.foundation.layout.Arrangement
4+
import androidx.compose.foundation.layout.Column
5+
import androidx.compose.foundation.layout.Spacer
6+
import androidx.compose.foundation.layout.fillMaxWidth
7+
import androidx.compose.foundation.layout.height
8+
import androidx.compose.material3.HorizontalDivider
9+
import androidx.compose.material3.MaterialTheme
10+
import androidx.compose.material3.Text
11+
import androidx.compose.runtime.Composable
12+
import androidx.compose.ui.Alignment
13+
import androidx.compose.ui.Modifier
14+
import androidx.compose.ui.tooling.preview.Preview
15+
import androidx.compose.ui.unit.dp
16+
17+
@Composable
18+
fun UserListFooter() {
19+
Column(
20+
modifier = Modifier.fillMaxWidth(),
21+
horizontalAlignment = Alignment.CenterHorizontally,
22+
verticalArrangement = Arrangement.Center
23+
) {
24+
HorizontalDivider(
25+
modifier = Modifier.fillMaxWidth(), thickness = 4.dp
26+
)
27+
Spacer(modifier = Modifier.height(16.dp))
28+
Text(
29+
text = "End of the list", style = MaterialTheme.typography.bodyMedium
30+
)
31+
Spacer(modifier = Modifier.height(16.dp))
32+
}
33+
}
34+
35+
@Preview(showBackground = true)
36+
@Composable
37+
fun PreviewUserListFooter() {
38+
UserListFooter()
39+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package com.example.techexactly.view.home
2+
3+
import androidx.compose.foundation.background
4+
import androidx.compose.foundation.clickable
5+
import androidx.compose.foundation.layout.Box
6+
import androidx.compose.foundation.layout.Row
7+
import androidx.compose.foundation.layout.Spacer
8+
import androidx.compose.foundation.layout.fillMaxWidth
9+
import androidx.compose.foundation.layout.size
10+
import androidx.compose.foundation.layout.width
11+
import androidx.compose.foundation.shape.CircleShape
12+
import androidx.compose.material.icons.Icons
13+
import androidx.compose.material.icons.filled.Email
14+
import androidx.compose.material3.ElevatedCard
15+
import androidx.compose.material3.Icon
16+
import androidx.compose.material3.ListItem
17+
import androidx.compose.material3.ListItemDefaults
18+
import androidx.compose.material3.MaterialTheme
19+
import androidx.compose.material3.Text
20+
import androidx.compose.runtime.Composable
21+
import androidx.compose.ui.Alignment
22+
import androidx.compose.ui.Modifier
23+
import androidx.compose.ui.draw.clip
24+
import androidx.compose.ui.tooling.preview.Preview
25+
import androidx.compose.ui.unit.dp
26+
import com.example.techexactly.model.dataclass.Address
27+
import com.example.techexactly.model.dataclass.Company
28+
import com.example.techexactly.model.dataclass.Geo
29+
import com.example.techexactly.model.dataclass.User
30+
31+
@Composable
32+
fun UserListItem(user: User, onUserClicked: (User) -> Unit) {
33+
ElevatedCard(
34+
modifier = Modifier.fillMaxWidth(),
35+
) {
36+
ListItem(
37+
modifier = Modifier.clickable { onUserClicked(user) },
38+
colors = ListItemDefaults.colors(
39+
containerColor = MaterialTheme.colorScheme.secondaryContainer,
40+
headlineColor = MaterialTheme.colorScheme.onSecondaryContainer,
41+
supportingColor = MaterialTheme.colorScheme.onSecondaryContainer,
42+
),
43+
leadingContent = {
44+
Box(
45+
modifier = Modifier
46+
.size(48.dp)
47+
.clip(CircleShape)
48+
.background(
49+
color = MaterialTheme.colorScheme.primary,
50+
), contentAlignment = Alignment.Center
51+
) {
52+
Text(
53+
text = user.name.first().toString(),
54+
style = MaterialTheme.typography.titleLarge,
55+
color = MaterialTheme.colorScheme.onPrimary,
56+
)
57+
}
58+
},
59+
headlineContent = {
60+
Text(
61+
text = user.name, style = MaterialTheme.typography.titleLarge
62+
)
63+
},
64+
supportingContent = {
65+
Row(
66+
verticalAlignment = Alignment.CenterVertically
67+
) {
68+
Icon(
69+
imageVector = Icons.Default.Email,
70+
contentDescription = "Email",
71+
tint = MaterialTheme.colorScheme.primary.copy(alpha = 0.7f)
72+
)
73+
Spacer(modifier = Modifier.width(8.dp))
74+
Text(
75+
text = user.email, style = MaterialTheme.typography.bodyMedium
76+
)
77+
}
78+
},
79+
)
80+
}
81+
}
82+
83+
@Preview(showBackground = true)
84+
@Composable
85+
fun PreviewUserListItem() {
86+
val user = User(
87+
id = 1,
88+
name = "Leanne Graham",
89+
username = "Bret",
90+
email = "Sincere@april.biz",
91+
address = Address(
92+
"Kulas Light", "Apt. 556", "Gwenborough", "92998-3874", Geo("-37.3159", "81.1496")
93+
),
94+
phone = "1-770-736-8031 x56442",
95+
website = "hildegard.org",
96+
company = Company(
97+
"Romaguera-Crona",
98+
"Multi-layered client-server neural-net",
99+
"harness real-time e-markets"
100+
)
101+
)
102+
UserListItem(user = user, onUserClicked = {})
103+
}

0 commit comments

Comments
 (0)