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

Commit 4e14840

Browse files
authored
Merge pull request #74 from Automattic/hamorillo/GRA-576
Implement SharedPrivateContactInfo
2 parents d5b22ce + 600c2b2 commit 4e14840

15 files changed

+539
-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: 12 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,15 @@ internal fun ShareScreen(uiState: ShareUiState, onEvent: (ShareEvent) -> Unit) {
4648
modifier = Modifier
4749
.fillMaxWidth()
4850
)
51+
52+
SharePrivateContactInfo(
53+
privateContactInfo = uiState.privateContactInfo,
54+
onEmailValueChange = { onEvent(ShareEvent.OnEmailValueChanged(it)) },
55+
onEmailSwitchCheckedChange = { onEvent(ShareEvent.OnEmailSharingChanged(it)) },
56+
onPhoneValueChange = { onEvent(ShareEvent.OnPhoneValueChanged(it)) },
57+
onPhoneSwitchCheckedChange = { onEvent(ShareEvent.OnPhoneSharingChanged(it)) },
58+
modifier = Modifier.padding(16.dp),
59+
)
4960
}
5061
}
5162

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

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

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

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,46 @@ 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 {
31+
it.copy(
32+
privateContactInfo = it.privateContactInfo.copy(
33+
emailValue = shareEvent.value
34+
)
35+
)
36+
}
37+
}
38+
is ShareEvent.OnEmailSharingChanged -> {
39+
_uiState.update {
40+
it.copy(
41+
privateContactInfo = it.privateContactInfo.copy(
42+
isEmailShared = shareEvent.isShared
43+
)
44+
)
45+
}
46+
}
47+
is ShareEvent.OnPhoneValueChanged -> {
48+
_uiState.update {
49+
it.copy(
50+
privateContactInfo = it.privateContactInfo.copy(
51+
phoneValue = shareEvent.value
52+
)
53+
)
54+
}
55+
}
56+
is ShareEvent.OnPhoneSharingChanged -> {
57+
_uiState.update {
58+
it.copy(
59+
privateContactInfo = it.privateContactInfo.copy(
60+
isPhoneShared = shareEvent.isShared
61+
)
62+
)
63+
}
64+
}
65+
}
66+
}
2967

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