-
Notifications
You must be signed in to change notification settings - Fork 0
OAuth - request the token via REST API #19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
53fbcc0
d4e6a2f
ea901c1
83268db
9d160e2
7739174
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,5 +10,6 @@ val appModule = module { | |
homeUiModule, | ||
loginUiModule, | ||
analyticsModule, | ||
dispatcherModule, | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package com.gravatar.app.di | ||
|
||
import com.gravatar.app.foundations.DispatcherProvider | ||
import kotlinx.coroutines.CoroutineDispatcher | ||
import kotlinx.coroutines.Dispatchers | ||
import org.koin.dsl.module | ||
|
||
val dispatcherModule = module { | ||
single<DispatcherProvider> { | ||
AppDispatcherProvider( | ||
main = Dispatchers.Main, | ||
io = Dispatchers.IO, | ||
default = Dispatchers.Default | ||
) | ||
} | ||
} | ||
|
||
data class AppDispatcherProvider( | ||
override val main: CoroutineDispatcher, | ||
override val io: CoroutineDispatcher, | ||
override val default: CoroutineDispatcher | ||
) : DispatcherProvider |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
<network-security-config> | ||
<debug-overrides> | ||
<trust-anchors> | ||
<!-- Trust user added CAs while debuggable only --> | ||
<certificates src="user" /> | ||
</trust-anchors> | ||
</debug-overrides> | ||
</network-security-config> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/build |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
plugins { | ||
id("java-library") | ||
alias(libs.plugins.kotlin.jvm) | ||
} | ||
java { | ||
sourceCompatibility = JavaVersion.VERSION_17 | ||
targetCompatibility = JavaVersion.VERSION_17 | ||
|
||
dependencies { | ||
implementation(libs.kotlinx.coroutines) | ||
} | ||
} | ||
kotlin { | ||
compilerOptions { | ||
jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17 | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.gravatar.app.foundations | ||
|
||
import kotlinx.coroutines.CoroutineDispatcher | ||
|
||
interface DispatcherProvider { | ||
val main: CoroutineDispatcher | ||
val io: CoroutineDispatcher | ||
val default: CoroutineDispatcher | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,12 @@ | ||
package com.gravatar.app.loginUi.di | ||
|
||
import com.gravatar.app.loginUi.presentation.login.LoginViewModel | ||
import com.gravatar.app.usercomponent.di.userComponentModule | ||
import org.koin.core.module.dsl.viewModelOf | ||
import org.koin.dsl.module | ||
|
||
val loginUiModule = module { | ||
includes(buildConfigModule) | ||
includes(buildConfigModule, userComponentModule) | ||
|
||
viewModelOf(::LoginViewModel) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,38 +7,79 @@ import androidx.compose.foundation.layout.Column | |
import androidx.compose.foundation.layout.fillMaxSize | ||
import androidx.compose.foundation.layout.padding | ||
import androidx.compose.material3.Button | ||
import androidx.compose.material3.CircularProgressIndicator | ||
import androidx.compose.material3.Scaffold | ||
import androidx.compose.material3.Surface | ||
import androidx.compose.material3.Text | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.LaunchedEffect | ||
import androidx.compose.runtime.collectAsState | ||
import androidx.compose.runtime.getValue | ||
import androidx.compose.ui.Alignment | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.platform.LocalContext | ||
import androidx.compose.ui.tooling.preview.Preview | ||
import com.gravatar.app.loginUi.presentation.oauth.OAuthResult | ||
import androidx.lifecycle.Lifecycle | ||
import androidx.lifecycle.compose.LocalLifecycleOwner | ||
import androidx.lifecycle.repeatOnLifecycle | ||
import com.gravatar.app.loginUi.presentation.oauth.OAuthResultContract | ||
import kotlinx.coroutines.Dispatchers | ||
import kotlinx.coroutines.withContext | ||
import org.koin.androidx.compose.koinViewModel | ||
|
||
@Composable | ||
fun LoginScreen( | ||
onLoggedIn: () -> Unit, | ||
) { | ||
LoginScreen( | ||
onLoggedIn = onLoggedIn, | ||
viewModel = koinViewModel(), | ||
) | ||
} | ||
|
||
@Composable | ||
internal fun LoginScreen( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Preview in this class no longer works, as Koin won't be initialized. We could use KoinAppApplicationPreview: @Preview
@Composable
private fun LoginScreenPreview() {
KoinApplicationPreview(application = { modules(loginUiModule) }) {
LoginScreen(
onLoggedIn = { },
)
}
} However, if you try that code, it will fail because it doesn't know how to resolve
I wonder if Something like this: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be fixed now. I didn't update the test to use the proper composable that doesn't rely on ViewModel, but rather on a ui state class. |
||
onLoggedIn: () -> Unit, | ||
viewModel: LoginViewModel, | ||
) { | ||
val uiState by viewModel.uiState.collectAsState() | ||
val context = LocalContext.current | ||
val lifecycle = LocalLifecycleOwner.current.lifecycle | ||
|
||
val oAuthLauncher = rememberLauncherForActivityResult(OAuthResultContract()) { result -> | ||
when (result) { | ||
OAuthResult.DISMISSED -> Unit | ||
is OAuthResult.TOKEN -> { | ||
Toast.makeText(context, "Logged in successfully!", Toast.LENGTH_SHORT).show() | ||
onLoggedIn() | ||
} | ||
LaunchedEffect(Unit) { | ||
withContext(Dispatchers.Main.immediate) { | ||
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { | ||
viewModel.actions.collect { action -> | ||
when (action) { | ||
LoginAction.UserLoggedIn -> { | ||
onLoggedIn() | ||
} | ||
|
||
OAuthResult.ERROR -> { | ||
Toast.makeText(context, "Login failed. Please try again.", Toast.LENGTH_SHORT) | ||
.show() | ||
LoginAction.ShowError -> { | ||
Toast.makeText(context, "Login error", Toast.LENGTH_SHORT) | ||
.show() | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
LoginScreen( | ||
uiState = uiState, | ||
onEvent = viewModel::onEvent | ||
) | ||
} | ||
|
||
@Composable | ||
internal fun LoginScreen( | ||
uiState: LoginUiState, | ||
onEvent: (LoginEvent) -> Unit, | ||
) { | ||
val oAuthLauncher = rememberLauncherForActivityResult(OAuthResultContract()) { result -> | ||
onEvent(LoginEvent.OAuthResultReceived(result)) | ||
} | ||
|
||
Scaffold { innerPadding -> | ||
Surface( | ||
modifier = Modifier.padding(innerPadding) | ||
|
@@ -47,14 +88,22 @@ fun LoginScreen( | |
modifier = Modifier.fillMaxSize(), | ||
contentAlignment = Alignment.Center | ||
) { | ||
Column { | ||
Text("Login Screen") | ||
Button( | ||
onClick = { | ||
oAuthLauncher.launch(Unit) | ||
when { | ||
uiState.isLoading -> { | ||
CircularProgressIndicator() | ||
} | ||
|
||
else -> { | ||
Column { | ||
Text("Login Screen") | ||
Button( | ||
onClick = { | ||
oAuthLauncher.launch(Unit) | ||
} | ||
) { | ||
Text("Log In") | ||
} | ||
} | ||
) { | ||
Text("Log In") | ||
} | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remember to add this to your
local.properties