Skip to content

Commit da928b9

Browse files
leandroBorgesFerreiraLeandro Ferreira
andauthored
Intro auth (#459)
* Intro auth * Update MainDesktop.kt * Removing intro screen * Update AuthMenuScreen.kt * Logout send user to register screen * Logging out * Saving and deleting token correctly * code clean * Saving tier locally * Update SqlDelightRepository.kt * Routing from first screen --------- Co-authored-by: Leandro Ferreira <[email protected]>
1 parent bb0e461 commit da928b9

File tree

27 files changed

+199
-94
lines changed

27 files changed

+199
-94
lines changed

application/common_flows/wide_screen_common/src/commonMain/kotlin/io/writeopia/notes/desktop/components/App.kt

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@ import androidx.compose.ui.unit.dp
2828
import androidx.navigation.NavHostController
2929
import androidx.navigation.compose.rememberNavController
3030
import io.writeopia.account.ui.SettingsDialog
31+
import io.writeopia.auth.core.di.AuthCoreInjectionNeo
3132
import io.writeopia.common.utils.Destinations
3233
import io.writeopia.common.utils.NotesNavigation
3334
import io.writeopia.common.utils.NotesNavigationType
35+
import io.writeopia.di.AppConnectionInjection
3436
import io.writeopia.documents.graph.di.DocumentsGraphInjection
3537
import io.writeopia.editor.di.EditorKmpInjector
3638
import io.writeopia.features.search.di.KmpSearchInjection
@@ -81,6 +83,12 @@ fun DesktopApp(
8183
WriteopiaDbInjector.initialize(writeopiaDb)
8284
}
8385

86+
LaunchedEffect("JWTToken") {
87+
AuthCoreInjectionNeo.singleton().provideAuthRepository().getAuthToken()?.let { token ->
88+
AppConnectionInjection.singleton().setJwtToken(token)
89+
}
90+
}
91+
8492
val editorInjector = remember {
8593
EditorKmpInjector.desktop(
8694
selectionState = selectionState,
@@ -233,10 +241,16 @@ fun DesktopApp(
233241
deleteModel = globalShellViewModel::deleteModel,
234242
signIn = navigateToRegister,
235243
resetPassword = navigateToResetPassword,
236-
logout = globalShellViewModel::logout,
244+
logout = {
245+
globalShellViewModel.logout(sideEffect = navigateToRegister)
246+
},
237247
showDeleteConfirm = globalShellViewModel::showDeleteConfirm,
238248
dismissDeleteConfirm = globalShellViewModel::dismissDeleteConfirm,
239-
deleteAccount = globalShellViewModel::deleteAccount
249+
deleteAccount = {
250+
globalShellViewModel.deleteAccount(
251+
sideEffect = navigateToRegister
252+
)
253+
}
240254
)
241255
}
242256

application/composeApp/build.gradle.kts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ kotlin {
3838
implementation(project(":writeopia_models"))
3939

4040
implementation(project(":application:core:persistence_sqldelight"))
41-
implementation(project(":application:core:theme"))
4241
implementation(project(":application:core:utils"))
4342
implementation(project(":application:core:navigation"))
4443
implementation(project(":application:core:documents"))

application/composeApp/src/jvmMain/kotlin/io/writeopia/desktop/MainDesktop.kt

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import androidx.compose.foundation.background
44
import androidx.compose.foundation.layout.Box
55
import androidx.compose.foundation.layout.fillMaxSize
66
import androidx.compose.material.CircularProgressIndicator
7+
import androidx.compose.material3.MaterialTheme
78
import androidx.compose.runtime.Composable
89
import androidx.compose.runtime.LaunchedEffect
910
import androidx.compose.runtime.collectAsState
@@ -24,11 +25,13 @@ import androidx.navigation.compose.rememberNavController
2425
import io.github.kdroidfilter.platformtools.darkmodedetector.isSystemInDarkMode
2526
import io.github.kdroidfilter.platformtools.darkmodedetector.windows.setWindowsAdaptiveTitleBar
2627
import io.writeopia.auth.di.AuthInjection
28+
import io.writeopia.auth.menu.AuthMenuViewModel
2729
import io.writeopia.auth.navigation.authNavigation
2830
import io.writeopia.common.utils.Destinations
2931
import io.writeopia.common.utils.keyboard.KeyboardCommands
3032
import io.writeopia.common.utils.keyboard.isMultiSelectionTrigger
3133
import io.writeopia.common.utils.ui.GlobalToastBox
34+
import io.writeopia.model.ColorThemeOption
3235
import io.writeopia.model.isDarkTheme
3336
import io.writeopia.notemenu.di.UiConfigurationInjector
3437
import io.writeopia.notes.desktop.components.DesktopApp
@@ -210,6 +213,8 @@ private fun ApplicationScope.App(onCloseRequest: () -> Unit = ::exitApplication)
210213
WriteopiaDbInjector.initialize(database)
211214
WriteopiaConnectionInjector.setBaseUrl("http://localhost:8080")
212215

216+
val authInjection = AuthInjection()
217+
213218
val uiConfigurationInjector = UiConfigurationInjector.singleton()
214219

215220
val uiConfigurationViewModel = uiConfigurationInjector
@@ -230,13 +235,34 @@ private fun ApplicationScope.App(onCloseRequest: () -> Unit = ::exitApplication)
230235
startDestination = Destinations.START_APP.id
231236
) {
232237
composable(route = Destinations.START_APP.id) {
238+
val authMenuViewModel: AuthMenuViewModel =
239+
authInjection.provideAuthMenuViewModel()
240+
241+
IntroScreen(colorTheme.value)
242+
243+
LaunchedEffect(Unit) {
244+
authMenuViewModel.isLoggedIn().collect { loggedIn ->
245+
delay(300)
246+
navigationController.navigate(
247+
if (loggedIn) {
248+
Destinations.CHOOSE_NOTE.id
249+
} else {
250+
Destinations.AUTH_MENU_INNER_NAVIGATION.id
251+
}
252+
)
253+
}
254+
}
255+
}
256+
257+
composable(route = Destinations.CHOOSE_NOTE.id) {
233258
DesktopApp(
234259
writeopiaDb = database,
235260
selectionState = selectionState,
236261
keyboardEventFlow = keyboardEventFlow.filterNotNull(),
237262
coroutineScope = coroutineScope,
238263
colorThemeOption = colorTheme,
239-
selectColorTheme = uiConfigurationViewModel::changeColorTheme,
264+
selectColorTheme =
265+
uiConfigurationViewModel::changeColorTheme,
240266
toggleMaxScreen = topDoubleBarClick,
241267
navigateToRegister = {
242268
navigationController.navigate(
@@ -253,10 +279,10 @@ private fun ApplicationScope.App(onCloseRequest: () -> Unit = ::exitApplication)
253279

254280
authNavigation(
255281
navController = navigationController,
256-
authInjection = AuthInjection(),
282+
authInjection = authInjection,
257283
colorThemeOption = colorTheme
258284
) {
259-
navigationController.navigate(Destinations.START_APP.id)
285+
navigationController.navigate(Destinations.CHOOSE_NOTE.id)
260286
}
261287
}
262288
}
@@ -277,3 +303,21 @@ private fun ScreenLoading() {
277303
CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
278304
}
279305
}
306+
307+
@Composable
308+
private fun IntroScreen(colorThemeOption: ColorThemeOption?) {
309+
WrieopiaTheme(darkTheme = colorThemeOption.isDarkTheme()) {
310+
Box(
311+
modifier = Modifier
312+
.fillMaxSize()
313+
.background(
314+
WriteopiaTheme.colorScheme.globalBackground
315+
)
316+
) {
317+
CircularProgressIndicator(
318+
modifier = Modifier.align(Alignment.Center),
319+
color = MaterialTheme.colorScheme.onBackground
320+
)
321+
}
322+
}
323+
}

application/core/auth_core/src/commonMain/kotlin/io/writeopia/auth/core/manager/SqlDelightRepository.kt

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,7 @@ internal class SqlDelightRepository(
1717
?.toModel()
1818
?: WriteopiaUser.disconnectedUser()
1919

20-
override suspend fun isLoggedIn(): Boolean =
21-
writeopiaDb?.writeopiaUserEntityQueries
22-
?.selectCurrentUser()
23-
?.executeAsOneOrNull()
24-
?.toModel() == null
20+
override suspend fun isLoggedIn(): Boolean = getAuthToken() != null
2521

2622
override suspend fun logout(): ResultData<Boolean> {
2723
getUser().let { user ->
@@ -31,6 +27,7 @@ internal class SqlDelightRepository(
3127
name = user.name,
3228
email = user.email,
3329
selected = 0,
30+
tier = user.tier.name
3431
)
3532
}
3633

@@ -44,6 +41,7 @@ internal class SqlDelightRepository(
4441
name = user.name,
4542
email = user.email,
4643
selected = selected.toLong(),
44+
tier = user.tier.tierName()
4745
)
4846
}
4947

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package io.writeopia.auth.core.utils
22

33
import io.writeopia.app.sql.Writeopia_user_entity
4+
import io.writeopia.sdk.models.user.Tier
45
import io.writeopia.sdk.models.user.WriteopiaUser
56

67
fun Writeopia_user_entity.toModel(): WriteopiaUser {
78
return WriteopiaUser(
89
id = this.id,
910
email = this.email,
1011
name = this.name,
12+
tier = Tier.valueOf(this.tier)
1113
)
1214
}

application/core/connection/src/commonMain/kotlin/io/writeopia/di/AppConnectionInjection.kt

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package io.writeopia.di
22

33
import io.ktor.client.HttpClient
4+
import io.ktor.client.plugins.DefaultRequest
45
import io.ktor.client.plugins.HttpTimeout
56
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
67
import io.ktor.client.plugins.logging.DEFAULT
78
import io.ktor.client.plugins.logging.LogLevel
89
import io.ktor.client.plugins.logging.Logger
910
import io.ktor.client.plugins.logging.Logging
11+
import io.ktor.client.request.header
1012
import io.ktor.http.HttpHeaders
1113
import io.ktor.serialization.kotlinx.json.json
1214
import kotlinx.serialization.json.Json
@@ -20,9 +22,17 @@ class AppConnectionInjection private constructor(
2022
},
2123
private val apiLogger: Logger = Logger.DEFAULT
2224
) {
25+
private var _tokenJwt: String? = null
26+
private fun token() = _tokenJwt
27+
28+
fun setJwtToken(token: String) {
29+
_tokenJwt = token
30+
}
31+
2332
fun provideJson() = json
2433

25-
fun provideHttpClient(): HttpClient = ApiInjectorDefaults.httpClient(json, apiLogger)
34+
fun provideHttpClient(): HttpClient =
35+
ApiInjectorDefaults.httpClient(json, apiLogger, token() ?: "")
2636

2737
companion object {
2838
private var instance: AppConnectionInjection? = null
@@ -37,12 +47,18 @@ object ApiInjectorDefaults {
3747
fun httpClient(
3848
json: Json,
3949
apiLogger: Logger,
50+
tokenJwt: String
4051
) = HttpClient {
4152
install(HttpTimeout) {
4253
requestTimeoutMillis = 300000
4354
socketTimeoutMillis = 300000
4455
}
4556

57+
install(DefaultRequest) {
58+
println("Bearer $tokenJwt")
59+
header(HttpHeaders.Authorization, "Bearer $tokenJwt")
60+
}
61+
4662
install(ContentNegotiation) {
4763
json(json = json)
4864
}

application/core/documents/src/commonMain/kotlin/io/writeopia/core/folders/api/DocumentsApi.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,14 @@ import io.writeopia.sdk.models.document.Document
1313
import io.writeopia.sdk.serialization.data.DocumentApi
1414
import io.writeopia.sdk.serialization.extensions.toApi
1515
import io.writeopia.sdk.serialization.extensions.toModel
16+
import io.writeopia.sdk.serialization.json.SendDocumentsRequest
1617
import kotlinx.datetime.Instant
1718

1819
class DocumentsApi(private val client: HttpClient, private val baseUrl: String) {
1920

2021
suspend fun getNewDocuments(folderId: String, lastSync: Instant): ResultData<List<Document>> {
22+
println("get new documents. $lastSync")
23+
2124
val response = client.post("$baseUrl/api/document/folder/diff") {
2225
contentType(ContentType.Application.Json)
2326
setBody(FolderDiffRequest(folderId, lastSync.toEpochMilliseconds()))
@@ -34,7 +37,7 @@ class DocumentsApi(private val client: HttpClient, private val baseUrl: String)
3437
suspend fun sendDocuments(documents: List<Document>): ResultData<Unit> {
3538
val response = client.post("$baseUrl/api/document") {
3639
contentType(ContentType.Application.Json)
37-
setBody(documents.map { it.toApi() })
40+
setBody(SendDocumentsRequest(documents.map { it.toApi() }))
3841
}
3942

4043
return if (response.status.isSuccess()) {

application/core/persistence_sqldelight/src/commonMain/sqldelight/io/writeopia/app/sql/WriteopiaUserEntity.sq

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ CREATE TABLE writeopia_user_entity (
22
id TEXT PRIMARY KEY,
33
name TEXT NOT NULL,
44
email TEXT NOT NULL,
5-
selected INTEGER NOT NULL
5+
selected INTEGER NOT NULL,
6+
tier TEXT NOT NULL
67
);
78

89
selectUserByEmail:
@@ -18,10 +19,10 @@ WHERE selected = 1
1819
LIMIT 1;
1920

2021
insertUser:
21-
INSERT INTO writeopia_user_entity(id, name, email, selected)
22-
VALUES (?, ?, ?, ?)
22+
INSERT INTO writeopia_user_entity(id, name, email, selected, tier)
23+
VALUES (?, ?, ?, ?, ?)
2324
ON CONFLICT(id) DO
24-
UPDATE SET id=excluded.id, name=excluded.name, email=excluded.email, selected=excluded.selected;
25+
UPDATE SET id=excluded.id, name=excluded.name, email=excluded.email, selected=excluded.selected, tier=excluded.tier;
2526

2627
deleteUser:
2728
DELETE

application/features/auth/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ kotlin {
3636
implementation(project(":writeopia_models"))
3737
implementation(project(":application:core:utils"))
3838
implementation(project(":application:core:navigation"))
39+
implementation(project(":application:core:connection"))
3940
implementation(project(":application:core:auth_core"))
4041
implementation(project(":application:core:persistence_bridge"))
4142
implementation(project(":application:core:theme"))

application/features/auth/src/commonMain/kotlin/io/writeopia/auth/di/AuthInjection.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class AuthInjection(
2626
): ResetPasswordViewModel = viewModel { ResetPasswordViewModel(authApi, authRepository) }
2727

2828
@Composable
29-
internal fun provideAuthMenuViewModel(
29+
fun provideAuthMenuViewModel(
3030
authManager: AuthRepository = authCoreInjection.provideAuthRepository(),
3131
authApi: AuthApi = authCoreInjection.provideAuthApi()
3232
): AuthMenuViewModel = viewModel { AuthMenuViewModel(authManager, authApi) }

0 commit comments

Comments
 (0)