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
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,11 @@ class MainActivity : AppCompatActivity() {
WindowCompat.setDecorFitsSystemWindows(window, false)
enableEdgeToEdge()
val rootRouterContext: RouterContext = defaultRouterContext()
val supabase = get<SupabaseClient>()
val launchScreen = handleLaunchIntent(intent)
FileKit.init(this)

val supabase = get<SupabaseClient>()

supabase.handleDeeplinks(intent)

setContent {
Expand Down Expand Up @@ -101,6 +102,18 @@ class MainActivity : AppCompatActivity() {
}
}

Intent.ACTION_VIEW -> {

val uri = intent.data
Logger.d("DeepLink URI: $uri")

if (uri?.scheme == "app.morestuff" && uri.host == "login-callback") {
Screen.Home
} else {
null
}
}

ACTION_NOTIFICATION_REMINDER -> {
intent.getStringExtra(EXTRA_TASK_ID)?.let {
Screen.TaskChat(Uuid(it))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class NavigationHelper: ViewModel(), KoinComponent {

val shareable = MutableSharedFlow<Shareable>()
val navigation = MutableSharedFlow<Screen>()
val code = MutableSharedFlow<String>()
private val cancelActiveScheduleUseCase: CancelActiveScheduleUseCase by inject()


Expand Down Expand Up @@ -65,6 +66,21 @@ class NavigationHelper: ViewModel(), KoinComponent {
}
}

fun navigateToHome(accessToken: String? = null) {
logger.d { "este es el accessToken: $accessToken" }
viewModelScope.launch {
if (accessToken != null) {
logger.d { "Emitting Screen.Home with access token" }
code.emit(accessToken)
navigation.emit(Screen.Home)
} else {
logger.d { "Emitting Screen.Home without token" }
navigation.emit(Screen.Home)
}
}
}



}

Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import co.touchlab.kermit.Logger
import com.arkivanov.decompose.router.stack.navigate
import io.github.jan.supabase.SupabaseClient
import io.github.xxfast.decompose.router.stack.Router
import io.github.xxfast.decompose.router.stack.rememberRouter
import io.middlepoint.morestuff.shared.domain.nav.Screen
Expand All @@ -25,14 +25,25 @@ import io.middlepoint.morestuff.shared.ui.screen.main.MainEvent
import io.middlepoint.morestuff.shared.ui.screen.main.MainViewModel
import io.middlepoint.morestuff.shared.ui.screen.settings.koinInjectOnRoute
import io.middlepoint.morestuff.shared.ui.theme.MoreStuffTheme
import io.middlepoint.morestuff.shared.ui.utils.handleDeeplinkFragment
import org.koin.compose.KoinContext
import org.koin.compose.koinInject

@Composable
fun App(screen: Screen? = null) {
fun App(screen: Screen? = null, accessToken: String? = null) {
KoinContext {
val router: Router<Screen> = rememberRouter { listOf(Screen.Home) }
val viewModel = koinInjectOnRoute(MainViewModel::class)
val model by viewModel.models.collectAsState()
val supabase: SupabaseClient = koinInject()

LaunchedEffect(accessToken) {
if (!accessToken.isNullOrBlank()) {
supabase.handleDeeplinkFragment(accessToken) { session ->
viewModel.take(MainEvent.OnBoardingComplete)
}
}
}

ProvideAppTheme(model.theme) {
MoreStuffTheme {
Expand All @@ -59,13 +70,23 @@ fun App(screen: Screen? = null) {
}
}
}

LaunchedEffect(screen) {
if (screen != null) {
router.navigate {
listOf(Screen.Home, screen)
if (screen == Screen.Home) {
router.navigate { listOf(screen) }
} else {
router.navigate { listOf(Screen.Home, screen) }
}
}
}


/* LaunchedEffect(screen) {
if (screen != null) {
router.navigate {
listOf(Screen.Home, screen)
}
}
}*/
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package io.middlepoint.morestuff.shared.ui.utils

import io.github.jan.supabase.SupabaseClient
import io.github.jan.supabase.annotations.SupabaseInternal
import io.github.jan.supabase.auth.FlowType
import io.github.jan.supabase.auth.auth
import io.github.jan.supabase.auth.parseFragmentAndImportSession
import io.github.jan.supabase.auth.user.UserSession

@OptIn(SupabaseInternal::class)
suspend fun SupabaseClient.handleDeeplinkFragment(
fragmentOrUrl: String,
onSessionSuccess: (UserSession) -> Unit = {}
) {
when (auth.config.flowType) {
FlowType.IMPLICIT -> {
auth.parseFragmentAndImportSession(fragmentOrUrl, onSessionSuccess)

}

FlowType.PKCE -> {
val code = extractAccessToken(fragmentOrUrl) ?: return

auth.exchangeCodeForSession(code)
val session = auth.currentSessionOrNull() ?: error("No session available after code exchange")
onSessionSuccess(session)
}
}
}

private fun extractQueryParam(url: String, param: String): String? {
val queryPart = url.substringAfter('?', missingDelimiterValue = "")
return queryPart
.split('&').firstNotNullOfOrNull {
val parts = it.split('=')
if (parts.size == 2 && parts[0] == param) parts[1] else null
}
}

private fun extractAccessToken(url: String): String? {
val fragment = url.substringAfter('#', "")
return extractQueryParam(fragment, "access_token")
}
83 changes: 45 additions & 38 deletions composeApp/src/iosMain/kotlin/MainViewController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,51 +19,58 @@ import org.koin.compose.koinInject

@OptIn(ExperimentalDecomposeApi::class)
fun MainViewController(routerContext: RouterContext) = ComposeUIViewController {
CompositionLocalProvider(LocalRouterContext provides routerContext) {
CompositionLocalProvider(LocalRouterContext provides routerContext) {
val navigationHelper = koinInject<NavigationHelper>()
val initialScreen = remember { mutableStateOf<Screen?>(null) }
val accessToken = remember { mutableStateOf<String?>(null) }
LaunchedEffect(Unit) {
navigationHelper.shareable.collect { shareable ->
initialScreen.value = when (shareable) {
is Shareable.Image -> {
Screen.Share(shareable, shareable.uri)
}

val navigationHelper = koinInject<NavigationHelper>()
val initialScreen = remember { mutableStateOf<Screen?>(null) }
is Shareable.Pdf -> {
Screen.Share(shareable, shareable.uri)
}

LaunchedEffect(Unit) {
navigationHelper.shareable.collect { shareable ->
initialScreen.value = when (shareable) {
is Shareable.Image -> {
Screen.Share(shareable, shareable.uri)
}
is Shareable.Text -> {
Screen.Share(shareable, shareable.message)
}

is Shareable.Pdf -> {
Screen.Share(shareable, shareable.uri)
}
else -> {
null
}
}
}
}
LaunchedEffect(Unit) {
navigationHelper.navigation.collect { screen ->
initialScreen.value = screen
}
}

is Shareable.Text -> {
Screen.Share(shareable, shareable.message)
}
LaunchedEffect(Unit) {
navigationHelper.code.collect { code ->
accessToken.value = code
}
}

else -> {
null
}
}
}
}
LaunchedEffect(Unit) {
navigationHelper.navigation.collect { screen ->
initialScreen.value = screen
}
}
PredictiveBackGestureOverlay(
backDispatcher = routerContext.backHandler as BackDispatcher,
backIcon = { progress, _ ->
/*PredictiveBackGestureIcon(
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
progress = progress,
)*/
},
modifier = Modifier.fillMaxSize(),
){
App(screen = initialScreen.value)
}

PredictiveBackGestureOverlay(
backDispatcher = routerContext.backHandler as BackDispatcher,
backIcon = { progress, _ ->
/*PredictiveBackGestureIcon(
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
progress = progress,
)*/
},
modifier = Modifier.fillMaxSize(),
) {
App(screen = initialScreen.value, accessToken = accessToken.value)
}

}
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,7 @@ class SchedulerImpl(
}*/
}

/* override fun cancelSchedule(scheduleId: Uuid) {
TODO("Not yet implemented")
}*/


override fun cancelSchedule(scheduleId: Uuid) {
UNUserNotificationCenter.currentNotificationCenter()
Expand Down Expand Up @@ -146,15 +144,6 @@ class SchedulerImpl(
}
}*/

override fun cancelSchedule(scheduleId: Uuid) {
UNUserNotificationCenter.currentNotificationCenter()
.removePendingNotificationRequestsWithIdentifiers(
listOf(getScheduleWorkTag(scheduleId))
)
logger.i { "Cancelled notification with scheduleId= $scheduleId" }

}

override fun cancelPlannedPriorityUpdate() {
UNUserNotificationCenter.currentNotificationCenter()
.removePendingNotificationRequestsWithIdentifiers(
Expand Down
1 change: 1 addition & 0 deletions iosApp/iosApp/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
<key>CFBundleURLSchemes</key>
<array>
<string>morestuff</string>
<string>app.morestuff</string>
<string>com.googleusercontent.apps.895634462091-qr6urlar6kjek2q0k3s7m1ctse48vgpf</string>
</array>
</dict>
Expand Down
20 changes: 19 additions & 1 deletion iosApp/iosApp/iOSApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,18 @@ struct SwiftUIApp: App {
.ignoresSafeArea(edges: .all)
.ignoresSafeArea(.keyboard)
.onOpenURL { url in
print("url type: \(url)")

handleFileURL(url, navigationHelper: navigationHelper)
if url.absoluteString.contains("app.morestuff://login-callback") && url.absoluteString.contains("access_token=") {
if let fragment = url.fragment {
print("Fragment: \(fragment)")
delegate.navigateHome(accessToken: fragment)
} else {
print("No fragment found in URL")
}
} else {
handleFileURL(url, navigationHelper: navigationHelper)
}
}
}

Expand All @@ -36,6 +46,7 @@ struct SwiftUIApp: App {
}
}


private func handleFileURL(_ url: URL, navigationHelper: NavigationHelper) {
let filePath: String?

Expand Down Expand Up @@ -146,6 +157,13 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele
self.navigationHelper.cancelTaskSchedule(taskId: taskId)
}
}

func navigateHome(accessToken: String? = nil) {
DispatchQueue.main.async {
print("token de acceso: \(accessToken)")
self.navigationHelper.navigateToHome(accessToken: accessToken)
}
}



Expand Down
Loading