Skip to content
This repository was archived by the owner on Aug 21, 2025. It is now read-only.

Commit aa73bd7

Browse files
committed
Implement SharedPrivateContactInfo
This commit will keep the info in the ViewModel. We still need to persist that info locally. # Conflicts: # homeUi/src/main/kotlin/com/gravatar/app/homeUi/presentation/home/share/ShareScreen.kt # homeUi/src/main/kotlin/com/gravatar/app/homeUi/presentation/home/share/ShareUiState.kt # homeUi/src/main/res/values/strings.xml
1 parent d5b22ce commit aa73bd7

15 files changed

+504
-5
lines changed
Loading
Loading
Loading
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
package com.gravatar.app.homeUi.presentation.home.share
22

3-
internal sealed class ShareEvent
3+
internal sealed class ShareEvent {
4+
data class OnEmailValueChanged(val value: String) : ShareEvent()
5+
data class OnEmailSharingChanged(val isShared: Boolean) : ShareEvent()
6+
data class OnPhoneValueChanged(val value: String) : ShareEvent()
7+
data class OnPhoneSharingChanged(val isShared: Boolean) : ShareEvent()
8+
}

homeUi/src/main/kotlin/com/gravatar/app/homeUi/presentation/home/share/ShareScreen.kt

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.gravatar.app.homeUi.presentation.home.share
33
import androidx.compose.foundation.layout.Column
44
import androidx.compose.foundation.layout.fillMaxSize
55
import androidx.compose.foundation.layout.fillMaxWidth
6+
import androidx.compose.foundation.layout.padding
67
import androidx.compose.foundation.rememberScrollState
78
import androidx.compose.foundation.verticalScroll
89
import androidx.compose.material3.SnackbarHostState
@@ -11,9 +12,11 @@ import androidx.compose.runtime.collectAsState
1112
import androidx.compose.runtime.getValue
1213
import androidx.compose.ui.Modifier
1314
import androidx.compose.ui.tooling.preview.Preview
15+
import androidx.compose.ui.unit.dp
1416
import androidx.lifecycle.ViewModelStoreOwner
1517
import com.gravatar.app.design.theme.GravatarAppTheme
1618
import com.gravatar.app.homeUi.presentation.home.share.components.ShareHeader
19+
import com.gravatar.app.homeUi.presentation.home.share.components.SharePrivateContactInfo
1720
import org.koin.androidx.compose.koinViewModel
1821

1922
@Suppress("UnusedParameter")
@@ -33,7 +36,6 @@ internal fun ShareScreen(
3336
)
3437
}
3538

36-
@Suppress("UnusedParameter")
3739
@Composable
3840
internal fun ShareScreen(uiState: ShareUiState, onEvent: (ShareEvent) -> Unit) {
3941
Column(
@@ -46,6 +48,18 @@ internal fun ShareScreen(uiState: ShareUiState, onEvent: (ShareEvent) -> Unit) {
4648
modifier = Modifier
4749
.fillMaxWidth()
4850
)
51+
52+
SharePrivateContactInfo(
53+
emailValue = uiState.emailValue,
54+
onEmailValueChange = { onEvent(ShareEvent.OnEmailValueChanged(it)) },
55+
emailSwitchChecked = uiState.isEmailShared,
56+
onEmailSwitchCheckedChange = { onEvent(ShareEvent.OnEmailSharingChanged(it)) },
57+
phoneValue = uiState.phoneValue,
58+
onPhoneValueChange = { onEvent(ShareEvent.OnPhoneValueChanged(it)) },
59+
phoneSwitchChecked = uiState.isPhoneShared,
60+
onPhoneSwitchCheckedChange = { onEvent(ShareEvent.OnPhoneSharingChanged(it)) },
61+
modifier = Modifier.padding(16.dp),
62+
)
4963
}
5064
}
5165

homeUi/src/main/kotlin/com/gravatar/app/homeUi/presentation/home/share/ShareUiState.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,8 @@ import com.gravatar.restapi.models.Profile
55
internal data class ShareUiState(
66
val profile: Profile? = null,
77
val avatarUrl: String? = null,
8+
val emailValue: String = "",
9+
val isEmailShared: Boolean = false,
10+
val phoneValue: String = "",
11+
val isPhoneShared: Boolean = false
812
)

homeUi/src/main/kotlin/com/gravatar/app/homeUi/presentation/home/share/ShareViewModel.kt

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,22 @@ internal class ShareViewModel(
2424
collectAvatarUrl()
2525
}
2626

27-
@Suppress("UnusedParameter")
28-
fun onEvent(shareEvent: ShareEvent) = Unit
27+
fun onEvent(shareEvent: ShareEvent) {
28+
when (shareEvent) {
29+
is ShareEvent.OnEmailValueChanged -> {
30+
_uiState.update { it.copy(emailValue = shareEvent.value) }
31+
}
32+
is ShareEvent.OnEmailSharingChanged -> {
33+
_uiState.update { it.copy(isEmailShared = shareEvent.isShared) }
34+
}
35+
is ShareEvent.OnPhoneValueChanged -> {
36+
_uiState.update { it.copy(phoneValue = shareEvent.value) }
37+
}
38+
is ShareEvent.OnPhoneSharingChanged -> {
39+
_uiState.update { it.copy(isPhoneShared = shareEvent.isShared) }
40+
}
41+
}
42+
}
2943

3044
private fun collectAvatarUrl() {
3145
getAvatarUrl()
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package com.gravatar.app.homeUi.presentation.home.share.components
2+
3+
import androidx.annotation.StringRes
4+
import androidx.compose.foundation.background
5+
import androidx.compose.foundation.layout.Box
6+
import androidx.compose.foundation.layout.Row
7+
import androidx.compose.foundation.layout.fillMaxWidth
8+
import androidx.compose.foundation.layout.padding
9+
import androidx.compose.foundation.shape.RoundedCornerShape
10+
import androidx.compose.foundation.text.BasicTextField
11+
import androidx.compose.material3.MaterialTheme
12+
import androidx.compose.material3.Switch
13+
import androidx.compose.material3.Text
14+
import androidx.compose.runtime.Composable
15+
import androidx.compose.ui.Alignment
16+
import androidx.compose.ui.Modifier
17+
import androidx.compose.ui.graphics.SolidColor
18+
import androidx.compose.ui.res.stringResource
19+
import androidx.compose.ui.tooling.preview.Preview
20+
import androidx.compose.ui.unit.dp
21+
import com.gravatar.app.homeUi.R
22+
23+
@Composable
24+
internal fun ShareEditableField(
25+
@StringRes placeholder: Int,
26+
value: String,
27+
onValueChange: (String) -> Unit,
28+
switchChecked: Boolean,
29+
onSwitchCheckedChange: (Boolean) -> Unit,
30+
modifier: Modifier = Modifier
31+
) {
32+
Row(
33+
modifier = modifier.fillMaxWidth(),
34+
verticalAlignment = Alignment.CenterVertically
35+
) {
36+
BasicTextField(
37+
value = value,
38+
onValueChange = onValueChange,
39+
textStyle = MaterialTheme.typography.bodyLarge.copy(color = MaterialTheme.colorScheme.onSurface),
40+
singleLine = true,
41+
cursorBrush = SolidColor(MaterialTheme.colorScheme.primary),
42+
modifier = Modifier.weight(1f),
43+
decorationBox = { innerTextField ->
44+
Box(
45+
modifier = Modifier
46+
.fillMaxWidth()
47+
.background(MaterialTheme.colorScheme.surfaceContainerHigh, RoundedCornerShape(8.dp))
48+
.padding(horizontal = 12.dp, vertical = 12.dp)
49+
) {
50+
if (value.isEmpty()) {
51+
Text(
52+
text = stringResource(placeholder),
53+
style = MaterialTheme.typography.bodyLarge,
54+
color = MaterialTheme.colorScheme.onSurfaceVariant
55+
)
56+
}
57+
innerTextField()
58+
}
59+
}
60+
)
61+
Switch(
62+
checked = switchChecked,
63+
onCheckedChange = onSwitchCheckedChange,
64+
modifier = Modifier.padding(start = 8.dp)
65+
)
66+
}
67+
}
68+
69+
@Preview
70+
@Composable
71+
private fun ShareEditableInfoPreview() {
72+
ShareEditableField(
73+
placeholder = R.string.share_tab_private_contact_email_placeholder,
74+
value = "gravatar@a8c.com",
75+
onValueChange = {},
76+
switchChecked = true,
77+
onSwitchCheckedChange = {}
78+
)
79+
}
80+
81+
@Preview
82+
@Composable
83+
private fun ShareEditableInfoEmptyPreview() {
84+
ShareEditableField(
85+
placeholder = R.string.share_tab_private_contact_phone_number_placeholder,
86+
value = "",
87+
onValueChange = {},
88+
switchChecked = false,
89+
onSwitchCheckedChange = {}
90+
)
91+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package com.gravatar.app.homeUi.presentation.home.share.components
2+
3+
import androidx.compose.foundation.layout.Arrangement
4+
import androidx.compose.foundation.layout.Column
5+
import androidx.compose.foundation.layout.fillMaxWidth
6+
import androidx.compose.runtime.Composable
7+
import androidx.compose.ui.Modifier
8+
import androidx.compose.ui.tooling.preview.Preview
9+
import androidx.compose.ui.unit.dp
10+
import com.gravatar.app.homeUi.R
11+
12+
@Composable
13+
internal fun SharePrivateContactInfo(
14+
// Email state and callbacks
15+
emailValue: String,
16+
onEmailValueChange: (String) -> Unit,
17+
emailSwitchChecked: Boolean,
18+
onEmailSwitchCheckedChange: (Boolean) -> Unit,
19+
// Phone number state and callbacks
20+
phoneValue: String,
21+
onPhoneValueChange: (String) -> Unit,
22+
phoneSwitchChecked: Boolean,
23+
onPhoneSwitchCheckedChange: (Boolean) -> Unit,
24+
modifier: Modifier = Modifier
25+
) {
26+
Column(verticalArrangement = Arrangement.spacedBy(16.dp), modifier = modifier) {
27+
ShareSectionTitle(
28+
leftIcon = R.drawable.share_section_title_warning,
29+
title = R.string.share_tab_private_contact_info_title,
30+
rightIcon = R.drawable.share_section_title_lock,
31+
modifier = Modifier.fillMaxWidth()
32+
)
33+
ShareEditableField(
34+
placeholder = R.string.share_tab_private_contact_email_placeholder,
35+
value = emailValue,
36+
onValueChange = onEmailValueChange,
37+
switchChecked = emailSwitchChecked,
38+
onSwitchCheckedChange = onEmailSwitchCheckedChange,
39+
)
40+
ShareEditableField(
41+
placeholder = R.string.share_tab_private_contact_phone_number_placeholder,
42+
value = phoneValue,
43+
onValueChange = onPhoneValueChange,
44+
switchChecked = phoneSwitchChecked,
45+
onSwitchCheckedChange = onPhoneSwitchCheckedChange,
46+
)
47+
}
48+
}
49+
50+
@Preview(showBackground = true)
51+
@Composable
52+
private fun SharePrivateContactInfoPreview() {
53+
SharePrivateContactInfo(
54+
emailValue = "example@email.com",
55+
onEmailValueChange = {},
56+
emailSwitchChecked = true,
57+
onEmailSwitchCheckedChange = {},
58+
phoneValue = "123-456-7890",
59+
onPhoneValueChange = {},
60+
phoneSwitchChecked = false,
61+
onPhoneSwitchCheckedChange = {}
62+
)
63+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package com.gravatar.app.homeUi.presentation.home.share.components
2+
3+
import androidx.annotation.DrawableRes
4+
import androidx.annotation.StringRes
5+
import androidx.compose.foundation.layout.Row
6+
import androidx.compose.foundation.layout.fillMaxWidth
7+
import androidx.compose.foundation.layout.padding
8+
import androidx.compose.foundation.text.BasicText
9+
import androidx.compose.foundation.text.TextAutoSize
10+
import androidx.compose.material3.Icon
11+
import androidx.compose.material3.MaterialTheme
12+
import androidx.compose.runtime.Composable
13+
import androidx.compose.ui.Alignment
14+
import androidx.compose.ui.Modifier
15+
import androidx.compose.ui.res.painterResource
16+
import androidx.compose.ui.res.stringResource
17+
import androidx.compose.ui.text.style.TextOverflow
18+
import androidx.compose.ui.tooling.preview.Preview
19+
import androidx.compose.ui.unit.dp
20+
import androidx.compose.ui.unit.sp
21+
import com.gravatar.app.design.theme.GravatarAppTheme
22+
import com.gravatar.app.homeUi.R
23+
24+
@Composable
25+
internal fun ShareSectionTitle(
26+
@DrawableRes leftIcon: Int?,
27+
@StringRes title: Int,
28+
@DrawableRes rightIcon: Int?,
29+
modifier: Modifier = Modifier
30+
) {
31+
Row(
32+
verticalAlignment = Alignment.CenterVertically,
33+
modifier = modifier.fillMaxWidth()
34+
) {
35+
leftIcon?.let {
36+
Icon(
37+
painter = painterResource(id = it),
38+
contentDescription = null,
39+
tint = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f),
40+
modifier = Modifier.padding(end = 6.dp)
41+
)
42+
}
43+
BasicText(
44+
text = stringResource(title),
45+
style = MaterialTheme.typography.bodyMedium.copy(
46+
fontSize = 12.sp,
47+
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f)
48+
),
49+
overflow = TextOverflow.Ellipsis,
50+
maxLines = 1,
51+
autoSize = TextAutoSize.StepBased(
52+
maxFontSize = 16.sp
53+
),
54+
modifier = Modifier.weight(1f),
55+
)
56+
rightIcon?.let {
57+
Icon(
58+
painter = painterResource(id = it),
59+
contentDescription = null
60+
)
61+
}
62+
}
63+
}
64+
65+
@Preview(showBackground = true)
66+
@Composable
67+
private fun ShareSectionTitlePreview() {
68+
GravatarAppTheme {
69+
ShareSectionTitle(
70+
leftIcon = R.drawable.share_section_title_warning,
71+
title = R.string.share_tab_private_contact_info_title,
72+
rightIcon = R.drawable.share_section_title_lock,
73+
modifier = Modifier.fillMaxWidth()
74+
)
75+
}
76+
}

0 commit comments

Comments
 (0)