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

Commit 8cbe6dd

Browse files
Implement AboutAppDialog in ShareScreen
1 parent 17ee503 commit 8cbe6dd

File tree

6 files changed

+76
-7
lines changed

6 files changed

+76
-7
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,6 @@ internal sealed class ShareEvent {
55
data class OnEmailSharingChanged(val isShared: Boolean) : ShareEvent()
66
data class OnPhoneValueChanged(val value: String) : ShareEvent()
77
data class OnPhoneSharingChanged(val isShared: Boolean) : ShareEvent()
8+
data object OnAboutAppClicked : ShareEvent()
9+
data object OnDismissAboutAppDialog : ShareEvent()
810
}

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import androidx.compose.ui.tooling.preview.Preview
1515
import androidx.compose.ui.unit.dp
1616
import androidx.lifecycle.ViewModelStoreOwner
1717
import com.gravatar.app.design.theme.GravatarAppTheme
18+
import com.gravatar.app.homeUi.presentation.home.components.topbar.components.AboutAppDialog
1819
import com.gravatar.app.homeUi.presentation.home.share.components.ShareHeader
1920
import com.gravatar.app.homeUi.presentation.home.share.components.SharePrivateContactInfo
2021
import org.koin.androidx.compose.koinViewModel
@@ -46,7 +47,10 @@ internal fun ShareScreen(uiState: ShareUiState, onEvent: (ShareEvent) -> Unit) {
4647
ShareHeader(
4748
avatarUrl = uiState.avatarUrl.orEmpty(),
4849
modifier = Modifier
49-
.fillMaxWidth()
50+
.fillMaxWidth(),
51+
onAboutAppClicked = {
52+
onEvent(ShareEvent.OnAboutAppClicked)
53+
}
5054
)
5155

5256
SharePrivateContactInfo(
@@ -58,14 +62,21 @@ internal fun ShareScreen(uiState: ShareUiState, onEvent: (ShareEvent) -> Unit) {
5862
modifier = Modifier.padding(16.dp),
5963
)
6064
}
65+
66+
AboutAppDialog(
67+
visible = uiState.isAboutAppDialogVisible,
68+
onDismissRequest = {
69+
onEvent(ShareEvent.OnDismissAboutAppDialog)
70+
}
71+
)
6172
}
6273

6374
@Preview
6475
@Composable
6576
private fun ShareScreenPreview() {
6677
GravatarAppTheme {
6778
ShareScreen(
68-
uiState = ShareUiState(),
79+
uiState = ShareUiState(isAboutAppDialogVisible = false),
6980
onEvent = { }
7081
)
7182
}

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ 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()
8+
val isAboutAppDialogVisible: Boolean = false,
9+
val privateContactInfo: PrivateContactInfo = PrivateContactInfo(),
910
)
1011

1112
internal data class PrivateContactInfo(
1213
val emailValue: String = "",
1314
val isEmailShared: Boolean = false,
1415
val phoneValue: String = "",
15-
val isPhoneShared: Boolean = false
16+
val isPhoneShared: Boolean = false,
1617
)

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,20 @@ internal class ShareViewModel(
6262
)
6363
}
6464
}
65+
is ShareEvent.OnAboutAppClicked -> showAboutAppDialog()
66+
is ShareEvent.OnDismissAboutAppDialog -> hideAboutAppDialog()
67+
}
68+
}
69+
70+
private fun showAboutAppDialog() {
71+
_uiState.update { currentState ->
72+
currentState.copy(isAboutAppDialogVisible = true)
73+
}
74+
}
75+
76+
private fun hideAboutAppDialog() {
77+
_uiState.update { currentState ->
78+
currentState.copy(isAboutAppDialogVisible = false)
6579
}
6680
}
6781

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import com.gravatar.app.homeUi.presentation.home.profile.header.MENU_BUTTON_SIZE
3838
internal fun ShareHeader(
3939
avatarUrl: String,
4040
modifier: Modifier = Modifier,
41+
onAboutAppClicked: () -> Unit = {},
4142
) {
4243
var topBarMenuVisible by remember { mutableStateOf(false) }
4344

@@ -92,6 +93,10 @@ internal fun ShareHeader(
9293
anchorAlignment = Alignment.End,
9394
offset = DpOffset(0.dp, 6.dp),
9495
onDismissRequest = { topBarMenuVisible = false },
96+
onAboutAppClicked = {
97+
topBarMenuVisible = false
98+
onAboutAppClicked()
99+
}
95100
)
96101
}
97102
}

homeUi/src/test/kotlin/com/gravatar/app/homeUi/presentation/home/share/ShareViewModelTest.kt

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,17 @@ import io.mockk.every
1010
import io.mockk.mockk
1111
import kotlinx.coroutines.ExperimentalCoroutinesApi
1212
import kotlinx.coroutines.flow.MutableSharedFlow
13-
import kotlinx.coroutines.flow.flowOf
1413
import kotlinx.coroutines.test.StandardTestDispatcher
1514
import kotlinx.coroutines.test.advanceUntilIdle
1615
import kotlinx.coroutines.test.runTest
1716
import org.junit.Assert.assertEquals
17+
import org.junit.Assert.assertFalse
18+
import org.junit.Assert.assertTrue
1819
import org.junit.Before
1920
import org.junit.Rule
2021
import org.junit.Test
2122
import java.net.URI
23+
import java.net.URL
2224

2325
@OptIn(ExperimentalCoroutinesApi::class)
2426
class ShareViewModelTest {
@@ -27,16 +29,19 @@ class ShareViewModelTest {
2729
@get:Rule
2830
var coroutineTestRule = CoroutineTestRule(testDispatcher)
2931

32+
private val getAvatarUrl: GetAvatarUrl = object : GetAvatarUrl {
33+
override fun invoke() = avatarUrlFlow
34+
}
3035
private val userRepository = mockk<UserRepository>()
36+
3137
private lateinit var viewModel: ShareViewModel
3238

39+
private val avatarUrlFlow: MutableSharedFlow<URL?> = MutableSharedFlow()
3340
private val profileFlow: MutableSharedFlow<Profile?> = MutableSharedFlow()
34-
private val getAvatarUrl = mockk<GetAvatarUrl>()
3541

3642
@Before
3743
fun setup() {
3844
every { userRepository.getProfile() } returns profileFlow
39-
every { getAvatarUrl.invoke() } returns flowOf(null)
4045
viewModel = ShareViewModel(userRepository, getAvatarUrl)
4146
}
4247

@@ -120,6 +125,37 @@ class ShareViewModelTest {
120125
}
121126
}
122127

128+
@Test
129+
fun `when OnAboutAppClicked event is triggered then isAboutAppDialogVisible is set to true`() = runTest {
130+
// When
131+
viewModel.onEvent(ShareEvent.OnAboutAppClicked)
132+
advanceUntilIdle()
133+
134+
// Then
135+
viewModel.uiState.test {
136+
val state = awaitItem()
137+
assertTrue(state.isAboutAppDialogVisible)
138+
}
139+
}
140+
141+
@Test
142+
fun `when OnDismissAboutAppDialog event is triggered then isAboutAppDialogVisible is set to false`() = runTest {
143+
// First show the dialog
144+
viewModel.onEvent(ShareEvent.OnAboutAppClicked)
145+
advanceUntilIdle()
146+
147+
// Verify dialog is visible
148+
viewModel.uiState.test {
149+
assertTrue(awaitItem().isAboutAppDialogVisible)
150+
151+
// When
152+
viewModel.onEvent(ShareEvent.OnDismissAboutAppDialog)
153+
154+
// Then
155+
assertFalse(awaitItem().isAboutAppDialogVisible)
156+
}
157+
}
158+
123159
private fun createTestProfile() = Profile {
124160
hash = "test-hash"
125161
displayName = "Test User"

0 commit comments

Comments
 (0)