Skip to content

Commit 37aae10

Browse files
committed
feat: introduce UI model for GitHub device authorization
- Create `GithubDeviceStartUi` and a corresponding mapper to decouple domain models from the presentation layer. - Update `AuthenticationViewModel`, `AuthenticationAction`, and `AuthLoginState` to use `GithubDeviceStartUi` instead of the domain `GithubDeviceStart`. - Refactor `AuthLoginState` from a sealed interface to a sealed class. - Clean up resource imports in `AuthenticationRoot` and update the preview data to use the new UI model.
1 parent 1e6463f commit 37aae10

6 files changed

Lines changed: 58 additions & 19 deletions

File tree

feature/auth/presentation/src/commonMain/kotlin/zed/rainxch/auth/presentation/AuthenticationAction.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
package zed.rainxch.auth.presentation
22

3-
import zed.rainxch.core.domain.model.GithubDeviceStart
3+
import zed.rainxch.auth.presentation.model.GithubDeviceStartUi
44

55
sealed interface AuthenticationAction {
66
data object StartLogin : AuthenticationAction
77

88
data class CopyCode(
9-
val start: GithubDeviceStart,
9+
val start: GithubDeviceStartUi,
1010
) : AuthenticationAction
1111

1212
data class OpenGitHub(
13-
val start: GithubDeviceStart,
13+
val start: GithubDeviceStartUi,
1414
) : AuthenticationAction
1515

1616
data object MarkLoggedOut : AuthenticationAction

feature/auth/presentation/src/commonMain/kotlin/zed/rainxch/auth/presentation/AuthenticationRoot.kt

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ import androidx.compose.ui.Alignment
3333
import androidx.compose.ui.Modifier
3434
import androidx.compose.ui.draw.clip
3535
import androidx.compose.ui.layout.ContentScale
36-
import androidx.compose.ui.res.painterResource
3736
import androidx.compose.ui.text.font.FontWeight
3837
import androidx.compose.ui.text.style.TextAlign
3938
import androidx.compose.ui.tooling.preview.Preview
@@ -43,11 +42,27 @@ import org.jetbrains.compose.resources.painterResource
4342
import org.jetbrains.compose.resources.stringResource
4443
import org.koin.compose.viewmodel.koinViewModel
4544
import zed.rainxch.auth.presentation.model.AuthLoginState
46-
import zed.rainxch.core.domain.model.GithubDeviceStart
45+
import zed.rainxch.auth.presentation.model.GithubDeviceStartUi
4746
import zed.rainxch.core.presentation.components.GithubStoreButton
4847
import zed.rainxch.core.presentation.theme.GithubStoreTheme
4948
import zed.rainxch.core.presentation.utils.ObserveAsEvents
50-
import zed.rainxch.githubstore.core.presentation.res.*
49+
import zed.rainxch.githubstore.core.presentation.res.Res
50+
import zed.rainxch.githubstore.core.presentation.res.app_icon
51+
import zed.rainxch.githubstore.core.presentation.res.auth_code_expires_in
52+
import zed.rainxch.githubstore.core.presentation.res.auth_error_with_message
53+
import zed.rainxch.githubstore.core.presentation.res.continue_as_guest
54+
import zed.rainxch.githubstore.core.presentation.res.copy_code
55+
import zed.rainxch.githubstore.core.presentation.res.enter_code_on_github
56+
import zed.rainxch.githubstore.core.presentation.res.ic_github
57+
import zed.rainxch.githubstore.core.presentation.res.more_requests
58+
import zed.rainxch.githubstore.core.presentation.res.more_requests_description
59+
import zed.rainxch.githubstore.core.presentation.res.open_github
60+
import zed.rainxch.githubstore.core.presentation.res.redirecting_message
61+
import zed.rainxch.githubstore.core.presentation.res.sign_in_with_github
62+
import zed.rainxch.githubstore.core.presentation.res.signed_in
63+
import zed.rainxch.githubstore.core.presentation.res.try_again
64+
import zed.rainxch.githubstore.core.presentation.res.unlock_full_experience
65+
import zed.rainxch.githubstore.core.presentation.res.waiting_for_authorization
5166

5267
@Composable
5368
fun AuthenticationRoot(
@@ -413,7 +428,7 @@ private fun Preview2() {
413428
AuthenticationState(
414429
loginState =
415430
AuthLoginState.DevicePrompt(
416-
GithubDeviceStart(
431+
GithubDeviceStartUi(
417432
deviceCode = "",
418433
userCode = "2102-UHHUF",
419434
verificationUri = "",

feature/auth/presentation/src/commonMain/kotlin/zed/rainxch/auth/presentation/AuthenticationViewModel.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ import kotlinx.coroutines.launch
1818
import kotlinx.coroutines.withContext
1919
import org.jetbrains.compose.resources.getString
2020
import zed.rainxch.auth.domain.repository.AuthenticationRepository
21+
import zed.rainxch.auth.presentation.mapper.toUi
2122
import zed.rainxch.auth.presentation.model.AuthLoginState
23+
import zed.rainxch.auth.presentation.model.GithubDeviceStartUi
2224
import zed.rainxch.core.domain.logging.GitHubStoreLogger
2325
import zed.rainxch.core.domain.model.GithubDeviceStart
2426
import zed.rainxch.core.domain.utils.BrowserHelper
@@ -149,7 +151,7 @@ class AuthenticationViewModel(
149151
it.copy(
150152
loginState =
151153
AuthLoginState.DevicePrompt(
152-
start = start,
154+
start = start.toUi(),
153155
remainingSeconds = start.expiresInSec,
154156
),
155157
copied = false,
@@ -230,7 +232,7 @@ class AuthenticationViewModel(
230232
countdownJob?.cancel()
231233
}
232234

233-
private fun openGitHub(start: GithubDeviceStart) {
235+
private fun openGitHub(start: GithubDeviceStartUi) {
234236
viewModelScope.launch(Dispatchers.Main.immediate) {
235237
try {
236238
val url = start.verificationUriComplete ?: start.verificationUri
@@ -241,7 +243,7 @@ class AuthenticationViewModel(
241243
}
242244
}
243245

244-
private fun copyCode(start: GithubDeviceStart) {
246+
private fun copyCode(start: GithubDeviceStartUi) {
245247
viewModelScope.launch(Dispatchers.Main.immediate) {
246248
try {
247249
clipboardHelper.copy(
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package zed.rainxch.auth.presentation.mapper
2+
3+
import zed.rainxch.auth.presentation.model.GithubDeviceStartUi
4+
import zed.rainxch.core.domain.model.GithubDeviceStart
5+
6+
fun GithubDeviceStart.toUi(): GithubDeviceStartUi =
7+
GithubDeviceStartUi(
8+
deviceCode = deviceCode,
9+
userCode = userCode,
10+
verificationUri = verificationUri,
11+
verificationUriComplete = verificationUriComplete,
12+
intervalSec = intervalSec,
13+
expiresInSec = expiresInSec,
14+
)
Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
11
package zed.rainxch.auth.presentation.model
22

3-
import zed.rainxch.core.domain.model.GithubDeviceStart
4-
5-
sealed interface AuthLoginState {
6-
data object LoggedOut : AuthLoginState
3+
sealed class AuthLoginState {
4+
data object LoggedOut : AuthLoginState()
75

86
data class DevicePrompt(
9-
val start: GithubDeviceStart,
7+
val start: GithubDeviceStartUi,
108
val remainingSeconds: Int = 0,
11-
) : AuthLoginState
9+
) : AuthLoginState()
1210

13-
data object Pending : AuthLoginState
11+
data object Pending : AuthLoginState()
1412

15-
data object LoggedIn : AuthLoginState
13+
data object LoggedIn : AuthLoginState()
1614

1715
data class Error(
1816
val message: String,
1917
val recoveryHint: String? = null,
20-
) : AuthLoginState
18+
) : AuthLoginState()
2119
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package zed.rainxch.auth.presentation.model
2+
3+
data class GithubDeviceStartUi(
4+
val deviceCode: String,
5+
val userCode: String,
6+
val verificationUri: String,
7+
val verificationUriComplete: String? = null,
8+
val intervalSec: Int = 5,
9+
val expiresInSec: Int,
10+
)

0 commit comments

Comments
 (0)