Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions config/detekt/detekt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ exceptions:
active: true
ignoreLabeled: false
SwallowedException:
active: true
active: false
ignoredExceptionTypes:
- 'InterruptedException'
- 'MalformedURLException'
Expand All @@ -283,7 +283,7 @@ exceptions:
ThrowingNewInstanceOfSameException:
active: true
TooGenericExceptionCaught:
active: true
active: false
excludes: [ '**/test/**', '**/androidTest/**', '**/commonTest/**', '**/jvmTest/**', '**/androidUnitTest/**', '**/androidInstrumentedTest/**', '**/jsTest/**', '**/iosTest/**' ]
exceptionNames:
- 'ArrayIndexOutOfBoundsException'
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
kotlin.code.style=official
# Determines whether this project should use hardcoded mocks or Supabase-CLI.
# See https://github.com/PPartisan/Roky/wiki/Project-Setup
USE_LOCAL_MOCKS=true
USE_LOCAL_MOCKS=false
9 changes: 7 additions & 2 deletions src/main/kotlin/authentication/Auth.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package authentication

import Secrets
import io.github.jan.supabase.SupabaseClient
import kotlinx.coroutines.CoroutineScope

interface Auth {
suspend fun login(
Expand All @@ -12,7 +14,10 @@ interface Auth {

suspend fun isLoggedIn(): Boolean

class Factory {
fun create(): Auth = if (Secrets.USE_LOCAL_MOCKS) LocalAuth else RemoteAuth
class Factory(
private val client: SupabaseClient,
private val coroutineScope: CoroutineScope,
) {
fun create(): Auth = if (Secrets.USE_LOCAL_MOCKS) LocalAuth else RemoteAuth(client, coroutineScope)
}
}
5 changes: 4 additions & 1 deletion src/main/kotlin/authentication/Authentication.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package authentication

import arch.RokyDispatchers
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import org.koin.dsl.module

val authenticationModule =
module {
factory { Auth.Factory() }
factory { Auth.Factory(get(), CoroutineScope(SupervisorJob() + get<RokyDispatchers>().io)) }
factory<Auth> { get<Auth.Factory>().create() }
}
69 changes: 56 additions & 13 deletions src/main/kotlin/authentication/RemoteAuth.kt
Original file line number Diff line number Diff line change
@@ -1,32 +1,75 @@
package authentication

import kotlinx.coroutines.delay
import kotlin.time.Duration.Companion.seconds
import io.github.jan.supabase.SupabaseClient
import io.github.jan.supabase.auth.auth
import io.github.jan.supabase.auth.providers.builtin.Email
import io.github.jan.supabase.auth.status.SessionStatus
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch

// SUPABASEEEE
object RemoteAuth : Auth {
private var isLoggedIn: Boolean = false
class RemoteAuth(
private val client: SupabaseClient,
private val scope: CoroutineScope,
) : Auth {
private val _state: MutableStateFlow<AuthState> = MutableStateFlow(AuthState.InitState)
val state: StateFlow<AuthState> = _state.asStateFlow()

init {
scope.launch {
client.auth.sessionStatus.collect {
_state.value = it.toRokyState()
println("Current State: ${state.value}")
}
}
}

override suspend fun login(
email: String,
password: String,
) {
println("Remote Auth login")
delay(3.seconds)
isLoggedIn = (email in validUsers && password == PASSWORD)
_state.value = AuthState.Authenticating
try {
client.auth.signInWith(Email) {
this.email = email
this.password = password
}
} catch (e: Exception) {
_state.value = AuthState.InvalidCredentials
}
}

override suspend fun logout() {
println("Remote Auth logout")
isLoggedIn = false
}

override suspend fun isLoggedIn(): Boolean {
println("Remote Auth is logged in")
return isLoggedIn
return state.value is AuthState.SignIn
}

companion object {
fun SessionStatus.toRokyState(): AuthState =
when (this) {
is SessionStatus.Authenticated -> AuthState.SignIn(session.user?.id ?: "Unknown User")
is SessionStatus.NotAuthenticated -> AuthState.InvalidCredentials
else -> {
println("Unrecognised State: $this")
AuthState.InvalidCredentials
}
}
}
}

sealed interface AuthState {
data class SignIn(val user: String) : AuthState

data object InvalidCredentials : AuthState

data object Authenticating : AuthState

private val validUsers =
listOf("Robert", "Dunia", "Tom", "Max", "Casper", "Ed", "Kai", "Laura", "Niamh", "Sofia")
private const val PASSWORD = "ILoveRoky"
data object InitState : AuthState
}