Skip to content
Open
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
23 changes: 18 additions & 5 deletions demo/android/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@ plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.compose.compiler)
alias(libs.plugins.compose.multiplatform)
}

val localProps = Properties().apply {
val f = rootProject.file("local.properties")
if (f.exists()) f.inputStream().use { load(it) }
alias(libs.plugins.buildconfig)
}

dependencies {
Expand All @@ -35,4 +31,21 @@ android {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
}

val localProps = Properties().apply {
val f = rootProject.file("local.properties")
if (f.exists()) f.inputStream().use { load(it) }
}

buildConfig {
packageName("nl.jacobras.cloudbridge.demo")
buildConfigField<String>(
"DROPBOX_CLIENT_ID",
localProps.getProperty("dropboxClientId") ?: ""
)
buildConfigField<String>(
"ONEDRIVE_CLIENT_ID",
localProps.getProperty("onedriveClientId") ?: ""
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,45 +10,31 @@ import androidx.activity.SystemBarStyle
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.browser.customtabs.CustomTabsIntent
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
import androidx.compose.foundation.layout.safeDrawingPadding
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.core.net.toUri
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.launch
import nl.jacobras.cloudbridge.CloudService
import nl.jacobras.cloudbridge.demo.persistence.DemoSettings
import nl.jacobras.cloudbridge.demo.ui.FileRow
import nl.jacobras.cloudbridge.demo.ui.MainViewModel
import nl.jacobras.cloudbridge.model.CloudItem
import nl.jacobras.cloudbridge.model.UserInfo
import nl.jacobras.cloudbridge.demo.ui.DemoScreen
import nl.jacobras.cloudbridge.demo.ui.DemoViewModel
import nl.jacobras.cloudbridge.service.dropbox.DropboxService
import nl.jacobras.cloudbridge.service.dropbox.authenticate
import nl.jacobras.cloudbridge.service.dropbox.completeAuthentication
import nl.jacobras.cloudbridge.service.googledrive.GoogleDriveAuthenticator
import nl.jacobras.cloudbridge.service.googledrive.GoogleDriveService
import nl.jacobras.cloudbridge.service.onedrive.OneDriveService
import nl.jacobras.cloudbridge.service.onedrive.authenticate
import nl.jacobras.cloudbridge.service.onedrive.completeAuthentication

class MainActivity : ComponentActivity() {

private val viewModel = MainViewModel()
private val viewModel = DemoViewModel()

private var authenticatingProvider: Provider? = null
private val scope = CoroutineScope(Dispatchers.Main)
Expand All @@ -57,7 +43,7 @@ class MainActivity : ComponentActivity() {
activity = this,
onSuccess = { token ->
DemoSettings.googleDriveToken = token
viewModel.refresh(viewModel.googleDrive)
viewModel.updateTokens()
},
onDenied = {},
onFailure = { error ->
Expand Down Expand Up @@ -109,23 +95,23 @@ class MainActivity : ComponentActivity() {
when (provider) {
Provider.Dropbox -> {
val token = viewModel.dropbox.completeAuthentication(
clientId = DROPBOX_CLIENT_ID,
clientId = BuildConfig.DROPBOX_CLIENT_ID,
redirectUri = REDIRECT_URI,
intentUri = uri
) ?: return@launch
DemoSettings.dropboxToken = token
viewModel.refresh(viewModel.dropbox)
viewModel.updateTokens()
}

Provider.OneDrive -> {
val oneDriveService = viewModel.oneDrive
val token = oneDriveService.completeAuthentication(
clientId = ONEDRIVE_CLIENT_ID,
clientId = BuildConfig.ONEDRIVE_CLIENT_ID,
redirectUri = REDIRECT_URI,
intentUri = uri
) ?: return@launch
DemoSettings.oneDriveToken = token
viewModel.refresh(oneDriveService)
viewModel.updateTokens()
}
}
}
Expand All @@ -134,128 +120,41 @@ class MainActivity : ComponentActivity() {
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun DemoApp(
viewModel: MainViewModel,
viewModel: DemoViewModel,
launchAuth: (Provider, String) -> Unit,
onAuthenticateGoogleDrive: () -> Unit
) {
val files by viewModel.files.collectAsState()
val userInfo by viewModel.userInfo.collectAsState()
val serviceErrors by viewModel.serviceErrors.collectAsState()

Scaffold(
modifier = Modifier.fillMaxSize(),
topBar = { TopAppBar(title = { Text("CloudBridge Demo") }) }
) { innerPadding ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(innerPadding)
.verticalScroll(rememberScrollState())
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(24.dp)
) {
val dropboxService = viewModel.dropbox
ServiceSection(
name = "Dropbox",
service = dropboxService,
userInfo = userInfo[dropboxService],
files = files[dropboxService] ?: emptyList(),
error = serviceErrors[dropboxService] ?: "",
onAuthenticate = {
DemoScreen(
viewModel = viewModel,
onAuthenticate = { service ->
when (service) {
is DropboxService -> {
launchAuth(
Provider.Dropbox,
viewModel.dropbox.authenticate(
DROPBOX_CLIENT_ID,
service.authenticate(
BuildConfig.DROPBOX_CLIENT_ID,
REDIRECT_URI
)
)
},
onLogOut = {
DemoSettings.dropboxToken = null
viewModel.refresh(dropboxService)
}
)
val googleDriveService = viewModel.googleDrive
ServiceSection(
name = "Google Drive",
service = googleDriveService,
userInfo = userInfo[googleDriveService],
files = files[googleDriveService] ?: emptyList(),
error = serviceErrors[googleDriveService] ?: "",
onAuthenticate = onAuthenticateGoogleDrive,
onLogOut = {
DemoSettings.googleDriveToken = null
viewModel.refresh(googleDriveService)
is GoogleDriveService -> {
onAuthenticateGoogleDrive()
}
)
val oneDriveService = viewModel.oneDrive
ServiceSection(
name = "OneDrive",
service = oneDriveService,
userInfo = userInfo[oneDriveService],
files = files[oneDriveService] ?: emptyList(),
error = serviceErrors[oneDriveService] ?: "",
onAuthenticate = {
is OneDriveService -> {
launchAuth(
Provider.OneDrive,
oneDriveService.authenticate(
ONEDRIVE_CLIENT_ID,
service.authenticate(
BuildConfig.ONEDRIVE_CLIENT_ID,
REDIRECT_URI
)
)
},
onLogOut = {
DemoSettings.oneDriveToken = null
viewModel.refresh(oneDriveService)
}
)
}
}
}

@Composable
private fun ServiceSection(
name: String,
service: CloudService,
userInfo: UserInfo?,
files: List<CloudItem>,
error: String,
onAuthenticate: () -> Unit,
onLogOut: () -> Unit
) {
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
Text(name, style = MaterialTheme.typography.headlineSmall)

if (!service.isAuthenticated()) {
Button(onClick = onAuthenticate) { Text("Authenticate with $name") }
return@Column
}

if (userInfo != null) {
SelectionContainer { Text("Authenticated as: $userInfo") }
}
Button(onClick = onLogOut) { Text("Log out") }

if (error.isNotEmpty()) {
Text(
text = error,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.error
)
}

for (item in files) {
FileRow(item = item, onClick = {})
if (item != files.last()) {
HorizontalDivider(Modifier.padding(vertical = 4.dp))
}
}
}
},
modifier = Modifier.safeDrawingPadding()
)
}

private enum class Provider { Dropbox, OneDrive }

private const val REDIRECT_URI = "nl.jacobras.cloudbridge.demo://cloudbridge-auth"

private const val DROPBOX_CLIENT_ID = "nw5f95uw77yrz3j"
private const val ONEDRIVE_CLIENT_ID = "40916102-96a6-46ca-929e-90cc62c3be9a"
private const val REDIRECT_URI = "nl.jacobras.cloudbridge.demo://cloudbridge-auth"
43 changes: 32 additions & 11 deletions demo/desktop/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
@file:Suppress("OPT_IN_USAGE")

import org.jetbrains.compose.desktop.application.dsl.TargetFormat
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import java.util.Properties

plugins {
Expand All @@ -10,20 +11,15 @@ plugins {
alias(libs.plugins.buildconfig)
}

val localProps = Properties().apply {
val f = rootProject.file("local.properties")
if (f.exists()) f.inputStream().use { load(it) }
}

kotlin {
jvm("desktop")
jvm("desktop") {
compilerOptions {
jvmTarget = JvmTarget.JVM_21
}
}

sourceSets {
named("desktopMain") {
buildConfig {
packageName("nl.jacobras.cloudbridge.demo")
buildConfigField<String>("DRIVE_DESKTOP_SECRET", localProps.getProperty("driveDesktopSecret") ?: "")
}
dependencies {
implementation(projects.demo.shared)
implementation(compose.desktop.currentOs)
Expand All @@ -37,9 +33,34 @@ kotlin {
}
}

val localProps = Properties().apply {
val f = rootProject.file("local.properties")
if (f.exists()) f.inputStream().use { load(it) }
}

buildConfig {
packageName("nl.jacobras.cloudbridge.demo")
buildConfigField<String>(
"DROPBOX_CLIENT_ID",
localProps.getProperty("dropboxClientId") ?: ""
)
buildConfigField<String>(
"GOOGLE_DRIVE_CLIENT_ID",
localProps.getProperty("googleDriveDesktopClientId") ?: ""
)
buildConfigField<String>(
"GOOGLE_DRIVE_CLIENT_SECRET",
localProps.getProperty("googleDriveDesktopSecret") ?: ""
)
buildConfigField<String>(
"ONEDRIVE_CLIENT_ID",
localProps.getProperty("onedriveClientId") ?: ""
)
}

compose.desktop {
application {
mainClass = "nl.jacobras.cloudbridge.demo.MainKt"
mainClass = "nl.jacobras.cloudbridge.demo.desktop.MainKt"

nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
Expand Down
Loading