Skip to content
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

Add account switcher #28

Merged
merged 13 commits into from
Sep 6, 2023
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
fragment UserAccount on User {
login
name
avatarUrl
id
notificationListsWithThreadCount(statuses: UNREAD) {
totalCount
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
query AccountInfo {
viewer {
...UserAccount
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
query Accounts($ids: [ID!]!) {
nodes(ids: $ids) {
...UserAccount
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ class GraphQLRepository(
private val service: GraphQLService
) {

suspend fun getAccountInfo(token: String) =
service.getAccountInfo(token).transform { it.viewer.userAccount }

suspend fun getAccountsByIds(ids: List<String>) = service.getAccountsByIds(ids).transform {
it.nodes.mapNotNull { it?.userAccount }
}

suspend fun getCurrentProfile() =
service.getCurrentProfile().transform { ModelUser.fromProfileQuery(it) }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ import com.apollographql.apollo3.ApolloCall
import com.apollographql.apollo3.ApolloClient
import com.apollographql.apollo3.api.Operation
import com.apollographql.apollo3.api.Optional
import com.apollographql.apollo3.cache.normalized.doNotStore
import com.materiiapps.gloom.api.utils.response
import com.materiiapps.gloom.api.utils.toOptional
import com.materiiapps.gloom.domain.manager.AuthManager
import com.materiiapps.gloom.gql.AccountInfoQuery
import com.materiiapps.gloom.gql.AccountsQuery
import com.materiiapps.gloom.gql.DefaultBranchQuery
import com.materiiapps.gloom.gql.FeedQuery
import com.materiiapps.gloom.gql.FollowUserMutation
Expand Down Expand Up @@ -46,6 +49,19 @@ class GraphQLService(
private fun <D : Operation.Data> ApolloCall<D>.addToken() =
addHttpHeader(HttpHeaders.Authorization, "Bearer ${authManager.authToken}")

suspend fun getAccountInfo(token: String) = withContext(Dispatchers.IO) {
client.query(AccountInfoQuery())
.doNotStore(true)
.addHttpHeader(HttpHeaders.Authorization, "Bearer ${token}")
.response()
}

suspend fun getAccountsByIds(ids: List<String>) = withContext(Dispatchers.IO) {
client.query(AccountsQuery(ids))
.addToken()
.response()
}

suspend fun getCurrentProfile() = withContext(Dispatchers.IO) {
client.query(ProfileQuery())
.addToken()
Expand Down
56 changes: 45 additions & 11 deletions app/src/main/java/com/materiiapps/gloom/ui/GloomActivity.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.materiiapps.gloom.ui

import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.SideEffect
Expand All @@ -17,6 +17,8 @@ import cafe.adriel.voyager.navigator.Navigator
import cafe.adriel.voyager.navigator.NavigatorDisposeBehavior
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import com.materiiapps.gloom.api.repository.GithubAuthRepository
import com.materiiapps.gloom.api.repository.GraphQLRepository
import com.materiiapps.gloom.api.utils.fold
import com.materiiapps.gloom.api.utils.ifSuccessful
import com.materiiapps.gloom.domain.manager.AuthManager
import com.materiiapps.gloom.domain.manager.PreferenceManager
Expand All @@ -25,27 +27,31 @@ import com.materiiapps.gloom.ui.screens.auth.LandingScreen
import com.materiiapps.gloom.ui.screens.root.RootScreen
import com.materiiapps.gloom.ui.theme.GloomTheme
import com.materiiapps.gloom.ui.transitions.SlideTransition
import com.materiiapps.gloom.ui.utils.clearRootNavigation
import com.materiiapps.gloom.utils.LinkHandler
import com.materiiapps.gloom.utils.LocalLinkHandler
import com.materiiapps.gloom.utils.deeplinks.DeepLinkWrapper
import com.materiiapps.gloom.utils.deeplinks.addAllRoutes
import kotlinx.coroutines.Dispatchers
import com.materiiapps.gloom.utils.getOAuthCode
import com.materiiapps.gloom.utils.isOAuthUri
import kotlinx.coroutines.launch
import org.koin.android.ext.android.getKoin
import org.koin.android.ext.android.inject

class GloomActivity : ComponentActivity() {

private val authRepo: GithubAuthRepository by inject()
private val gqlRepo: GraphQLRepository by inject()
private val auth: AuthManager by inject()
private val prefs: PreferenceManager by inject()
private lateinit var navigator: Navigator

@OptIn(ExperimentalAnimationApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
installSplashScreen()
super.onCreate(savedInstanceState)

WindowCompat.setDecorFitsSystemWindows(window, false)
getKoin().declare<Context>(this@GloomActivity)
rushiiMachine marked this conversation as resolved.
Show resolved Hide resolved

setContent {
val isDark = when (prefs.theme) {
Expand Down Expand Up @@ -94,20 +100,48 @@ class GloomActivity : ComponentActivity() {

override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
this.intent = intent
println("Activity re-entered")
wingio marked this conversation as resolved.
Show resolved Hide resolved
intent?.let {
if (it.data.toString().startsWith("github://com.github.android/oauth")) {
println(it.data.toString())
it.data!!.getQueryParameter("code")?.let {
lifecycleScope.launch(Dispatchers.IO) {
if (it.isOAuthUri()) {
if (auth.awaitingAuthType == null) return
it.getOAuthCode()?.let {
lifecycleScope.launch {
auth.setAuthState(loading = true)
val res = authRepo.getAccessToken(it)
res.ifSuccessful { token ->
auth.authToken = token.accessToken
navigator.replace(RootScreen())
}
res.fold(
success = { token ->
wingio marked this conversation as resolved.
Show resolved Hide resolved
gqlRepo.getAccountInfo(token.accessToken).ifSuccessful { account ->
auth.addAccount(
id = account.id,
token = token.accessToken,
type = auth.awaitingAuthType!!,
username = account.login,
avatarUrl = account.avatarUrl,
displayName = account.name,
notificationCount = account.notificationListsWithThreadCount.totalCount
)
auth.switchToAccount(account.id)
clearRootNavigation()
navigator.replaceAll(RootScreen())
}
auth.setAuthState(authType = null, loading = false)
},
error = { auth.setAuthState(authType = null, loading = false) },
failure = { auth.setAuthState(authType = null, loading = false) },
empty = { auth.setAuthState(authType = null, loading = false) }
)
}
}
}
}
}

override fun onResume() {
super.onResume()
if (!intent.isOAuthUri()) {
wingio marked this conversation as resolved.
Show resolved Hide resolved
auth.setAuthState(authType = null)
}
}

}
10 changes: 10 additions & 0 deletions app/src/main/java/com/materiiapps/gloom/utils/OAuthUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.materiiapps.gloom.utils

import android.content.Intent

fun Intent.isOAuthUri() = data.toString().startsWith("github://com.github.android/oauth")

fun Intent.getOAuthCode(): String? {
if(!isOAuthUri()) return null
return data?.getQueryParameter("code")
wingio marked this conversation as resolved.
Show resolved Hide resolved
}
1 change: 1 addition & 0 deletions shared/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.compose)
alias(libs.plugins.kotlin.multiplatform)
alias(libs.plugins.kotlin.serialization)
}

android {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ fun Context.openCustomTab(url: String, force: Boolean) = CustomTabsIntent.Builde
launchUrl(this@openCustomTab, Uri.parse(url))
}

fun Context.openLink(url: Uri) {
fun Context.openLink(url: Uri, forceCustomTab: Boolean = false) {
// TODO: Setting to disable custom tabs
openCustomTab(url.toString(), force = false)
openCustomTab(url.toString(), force = forceCustomTab)
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import androidx.core.net.toUri

actual class LinkHandler(private val ctx: Context) {

actual fun openLink(link: String) {
actual fun openLink(link: String, forceCustomTab: Boolean) {
try {
ctx.openLink(link.toUri())
ctx.openLink(link.toUri(), forceCustomTab)
} catch (e: Throwable) {
Log.e("LinkHandler", "Failed to open link", e)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
package com.materiiapps.gloom.di.modules

import com.apollographql.apollo3.ApolloClient
import com.materiiapps.gloom.domain.manager.AuthManager
import com.materiiapps.gloom.domain.manager.DialogManager
import com.materiiapps.gloom.domain.manager.DownloadManager
import com.materiiapps.gloom.domain.manager.PreferenceManager
import com.materiiapps.gloom.domain.manager.ShareManager
import com.materiiapps.gloom.domain.manager.ToastManager
import com.materiiapps.gloom.utils.Logger
import com.materiiapps.gloom.utils.SettingsProvider
import kotlinx.serialization.json.Json
import org.koin.core.module.dsl.singleOf
import org.koin.core.qualifier.named
import org.koin.dsl.module

fun managerModule() = module {

singleOf(::AuthManager)
singleOf(::DownloadManager)
singleOf(::ShareManager)
singleOf(::ToastManager)

fun providePreferenceManager(settings: SettingsProvider) = PreferenceManager(settings)
fun provideDialogManager(settings: SettingsProvider) = DialogManager(settings)
fun provideAuthManager(settings: SettingsProvider, apollo: ApolloClient, json: Json, logger: Logger) = AuthManager(settings, apollo, json, logger)

single { providePreferenceManager(get(named("prefs"))) }
single { provideDialogManager(get(named("dialogs"))) }
single { provideAuthManager(get(named("auth")), get(), get(), get()) }

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,8 @@ fun settingsModule() = module {
SettingsProvider(get(), "dialogs")
}

single(named("auth")) {
SettingsProvider(get(), "auth")
}

}
Loading
Loading