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 missing default router context and lifecycle extensions for ios target #74

Merged
merged 9 commits into from
Oct 22, 2023
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
17 changes: 10 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,13 +195,10 @@ class DetailInstance(savedState: SavedStateHandle, detail: String) : InstanceKee
**build.gradle.kts**
```kotlin
fun main() {
val lifecycle = LifecycleRegistry()
val rootRouterContext = RouterContext(lifecycle = lifecycle)
val windowState: WindowState = rememberWindowState()
val rootRouterContext: RouterContext = defaultRouterContext(windowState = windowState)

application {
val windowState: WindowState = rememberWindowState()
LifecycleController(lifecycle, windowState)

Window(state = windowState) {
CompositionLocalProvider(LocalRouterContext provides rootRouterContext) {
MaterialTheme {
Expand Down Expand Up @@ -230,8 +227,14 @@ class DetailInstance(savedState: SavedStateHandle, detail: String) : InstanceKee
}
```
> [!IMPORTANT]
> You will need to tie root `RouterContext`'s lifecycle to an `AppDelegate`. See example kotlin app delegate [here](https://github.com/xxfast/Decompose-Router/blob/main/app/src/iosMain/kotlin/io/github/xxfast/decompose/router/app/AppDelegate.kt), or swift delegate [here](https://github.com/xxfast/Decompose-Router/blob/main/app/ios/ios/AppDelegate.swift). Read more on the docs [here](https://arkivanov.github.io/Decompose/getting-started/quick-start/#ios-with-swiftui)

> You will need to tie root `RouterContext`'s lifecycle to an `AppDelegate`.
> * See Kotlin app delegate [here](https://github.com/xxfast/Decompose-Router/blob/main/app/src/iosMain/kotlin/io/github/xxfast/decompose/router/app/AppDelegate.kt),
> * See Swift UIKit AppDelegate [here](https://github.com/xxfast/Decompose-Router/blob/main/app/ios/ios/UIKitAppDelegate.swift).
> * See SwiftUI App [here](https://github.com/xxfast/Decompose-Router/blob/main/app/ios/ios/SwiftUIApp.swift).
> * Read more on the docs [here](https://arkivanov.github.io/Decompose/getting-started/quick-start/#ios-with-swiftui)

> [!NOTE]
> To invoke decompose router's `defaultRouterContext()` from swift, you will need to export decompose-router from your shared module
</details>

<details>
Expand Down
6 changes: 5 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ kotlin {
it.binaries{
framework {
baseName = "app"

// Only need this if you wish to add your own AppDelegate in swift
export(project(":decompose-router"))
}

executable {
Expand Down Expand Up @@ -59,7 +62,8 @@ kotlin {
sourceSets {
val commonMain by getting {
dependencies {
implementation(project(":decompose-router"))
// Only need to add this as api if you wish to add your own AppDelegate in swift
api(project(":decompose-router"))

implementation(compose.runtime)
implementation(compose.foundation)
Expand Down
12 changes: 8 additions & 4 deletions app/ios/ios.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
/* Begin PBXBuildFile section */
058557BB273AAA24004C7B11 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 058557BA273AAA24004C7B11 /* Assets.xcassets */; };
058557D9273AAEEB004C7B11 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */; };
2152FB042600AC8F00CF470E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2152FB032600AC8F00CF470E /* AppDelegate.swift */; };
2152FB042600AC8F00CF470E /* UIKitAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2152FB032600AC8F00CF470E /* UIKitAppDelegate.swift */; };
DB85742B2AE2331E0069250C /* SwiftUIApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB85742A2AE2331E0069250C /* SwiftUIApp.swift */; };
/* End PBXBuildFile section */

/* Begin PBXCopyFilesBuildPhase section */
Expand All @@ -28,9 +29,10 @@
/* Begin PBXFileReference section */
058557BA273AAA24004C7B11 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
2152FB032600AC8F00CF470E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
2152FB032600AC8F00CF470E /* UIKitAppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIKitAppDelegate.swift; sourceTree = "<group>"; };
7555FF7B242A565900829871 /* ios.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ios.app; sourceTree = BUILT_PRODUCTS_DIR; };
7555FF8C242A565B00829871 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
DB85742A2AE2331E0069250C /* SwiftUIApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIApp.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -74,8 +76,9 @@
children = (
058557BA273AAA24004C7B11 /* Assets.xcassets */,
7555FF8C242A565B00829871 /* Info.plist */,
2152FB032600AC8F00CF470E /* AppDelegate.swift */,
2152FB032600AC8F00CF470E /* UIKitAppDelegate.swift */,
058557D7273AAEEB004C7B11 /* Preview Content */,
DB85742A2AE2331E0069250C /* SwiftUIApp.swift */,
);
path = ios;
sourceTree = "<group>";
Expand Down Expand Up @@ -179,7 +182,8 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
2152FB042600AC8F00CF470E /* AppDelegate.swift in Sources */,
2152FB042600AC8F00CF470E /* UIKitAppDelegate.swift in Sources */,
DB85742B2AE2331E0069250C /* SwiftUIApp.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
56 changes: 56 additions & 0 deletions app/ios/ios/SwiftUIApp.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//
// App.swift
// ios
//
// Created by Rajapaksage Isuru Rajapakse on 20/10/2023.
// Copyright © 2023 orgName. All rights reserved.
//

import SwiftUI
import app

class DefaultRouterHolder : ObservableObject {
let defaultRouterContext: RouterContext = DefaultRouterContextKt.defaultRouterContext()

deinit {
// Destroy the root component before it is deallocated
defaultRouterContext.destroy()
}
}

class AppDelegate: NSObject, UIApplicationDelegate {
let holder: DefaultRouterHolder = DefaultRouterHolder()
}

@main
struct SwiftUIApp: App {
@UIApplicationDelegateAdaptor var delegate: AppDelegate
@Environment(\.scenePhase) var scenePhase: ScenePhase

var defaultRouterContext: RouterContext { delegate.holder.defaultRouterContext }

var body: some Scene {
WindowGroup {
HomeView(routerContext: defaultRouterContext)
}
.onChange(of: scenePhase) { newPhase in
switch newPhase {
case .background: defaultRouterContext.stop()
case .inactive: defaultRouterContext.pause()
case .active: defaultRouterContext.resume()
@unknown default: break
}
}
}
}

struct HomeView: UIViewControllerRepresentable {
let routerContext: RouterContext

func makeUIViewController(context: Context) -> UIViewController {
return ApplicationKt.HomeUIViewController(routerContext: routerContext)
}

func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
}

Original file line number Diff line number Diff line change
@@ -1,31 +1,30 @@
import SwiftUI
import app

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
//@UIApplicationMain
class UIKitAppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?

var rootRouterContext = RouterContextKt.defaultRouterContext()
var rootRouterContext = DefaultRouterContextKt.defaultRouterContext()

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
let mainViewController = ApplicationKt.MainUIController(routerContext: rootRouterContext)
let mainViewController = ApplicationKt.HomeUIViewController(routerContext: rootRouterContext)
window?.rootViewController = mainViewController
window?.makeKeyAndVisible()
return true
}


func applicationDidBecomeActive(_ application: UIApplication) {
RouterContextKt.resume(rootRouterContext.lifecycle)
rootRouterContext.resume()
}

func applicationWillResignActive(_ application: UIApplication) {
RouterContextKt.stop(rootRouterContext.lifecycle)
rootRouterContext.stop()
}

func applicationWillTerminate(_ application: UIApplication) {
RouterContextKt.destroy(rootRouterContext.lifecycle)
rootRouterContext.destroy()
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,12 @@ import com.arkivanov.essenty.lifecycle.LifecycleRegistry
import io.github.xxfast.decompose.router.LocalRouterContext
import io.github.xxfast.decompose.router.RouterContext
import io.github.xxfast.decompose.router.app.screens.HomeScreen
import io.github.xxfast.decompose.router.defaultRouterContext

@OptIn(ExperimentalDecomposeApi::class)
fun main() {
val lifecycle = LifecycleRegistry()
val rootRouterContext = RouterContext(lifecycle = lifecycle)

application {
val windowState: WindowState = rememberWindowState()
LifecycleController(lifecycle, windowState)
val rootRouterContext: RouterContext = defaultRouterContext(windowState = windowState)

Window(
title = "App",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package io.github.xxfast.decompose.router.app

import com.arkivanov.essenty.lifecycle.destroy
import com.arkivanov.essenty.lifecycle.resume
import com.arkivanov.essenty.lifecycle.stop
import io.github.xxfast.decompose.router.RouterContext
import io.github.xxfast.decompose.router.app.utils.registry
import io.github.xxfast.decompose.router.defaultRouterContext
import io.github.xxfast.decompose.router.destroy
import io.github.xxfast.decompose.router.resume
import io.github.xxfast.decompose.router.stop
import kotlinx.cinterop.BetaInteropApi
import kotlinx.cinterop.ExperimentalForeignApi
import platform.UIKit.UIApplication
Expand Down Expand Up @@ -34,20 +33,20 @@ class AppDelegate @OverrideInit constructor() : UIResponder(), UIApplicationDele
didFinishLaunchingWithOptions: Map<Any?, *>?
): Boolean {
window = UIWindow(frame = UIScreen.mainScreen.bounds)
window!!.rootViewController = MainUIController(routerContext)
window!!.rootViewController = HomeUIViewController(routerContext)
window!!.makeKeyAndVisible()
return true
}

override fun applicationDidBecomeActive(application: UIApplication) {
routerContext.lifecycle.registry.resume()
routerContext.resume()
}

override fun applicationWillResignActive(application: UIApplication) {
routerContext.lifecycle.registry.stop()
routerContext.stop()
}

override fun applicationWillTerminate(application: UIApplication) {
routerContext.lifecycle.registry.destroy()
routerContext.destroy()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ fun main() {
}

@OptIn(ExperimentalDecomposeApi::class)
fun MainUIController(routerContext: RouterContext): UIViewController = ComposeUIViewController {
fun HomeUIViewController(routerContext: RouterContext): UIViewController = ComposeUIViewController {
CompositionLocalProvider(
LocalRouterContext provides routerContext,
) {
Expand Down

This file was deleted.

10 changes: 5 additions & 5 deletions decompose-router/api/android/decompose-router.api
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
public final class io/github/xxfast/decompose/router/DefaultRouterContextKt {
public static final fun defaultRouterContext (Landroidx/activity/ComponentActivity;)Lio/github/xxfast/decompose/router/RouterContext;
public static final fun defaultRouterContext (Landroidx/fragment/app/Fragment;Landroidx/activity/OnBackPressedDispatcher;)Lio/github/xxfast/decompose/router/RouterContext;
}

public final class io/github/xxfast/decompose/router/Router : com/arkivanov/decompose/router/stack/StackNavigation {
public static final field $stable I
public fun <init> (Lcom/arkivanov/decompose/router/stack/StackNavigation;Landroidx/compose/runtime/State;)V
Expand All @@ -17,11 +22,6 @@ public final class io/github/xxfast/decompose/router/RouterContext : com/arkivan
public fun getStateKeeper ()Lcom/arkivanov/essenty/statekeeper/StateKeeper;
}

public final class io/github/xxfast/decompose/router/RouterContextExtKt {
public static final fun defaultRouterContext (Landroidx/activity/ComponentActivity;)Lio/github/xxfast/decompose/router/RouterContext;
public static final fun defaultRouterContext (Landroidx/fragment/app/Fragment;Landroidx/activity/OnBackPressedDispatcher;)Lio/github/xxfast/decompose/router/RouterContext;
}

public final class io/github/xxfast/decompose/router/RouterContextKt {
public static final fun getLocalRouterContext ()Landroidx/compose/runtime/ProvidableCompositionLocal;
}
Expand Down
4 changes: 4 additions & 0 deletions decompose-router/api/desktop/decompose-router.api
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
public final class io/github/xxfast/decompose/router/DefaultRouterContextKt {
public static final fun defaultRouterContext (Lcom/arkivanov/essenty/backhandler/BackDispatcher;Lcom/arkivanov/essenty/lifecycle/LifecycleRegistry;Landroidx/compose/ui/window/WindowState;Landroidx/compose/runtime/Composer;II)Lio/github/xxfast/decompose/router/RouterContext;
}

public final class io/github/xxfast/decompose/router/Router : com/arkivanov/decompose/router/stack/StackNavigation {
public static final field $stable I
public fun <init> (Lcom/arkivanov/decompose/router/stack/StackNavigation;Landroidx/compose/runtime/State;)V
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.github.xxfast.decompose.router

import androidx.compose.runtime.Composable
import androidx.compose.ui.window.WindowState
import androidx.compose.ui.window.rememberWindowState
import com.arkivanov.decompose.ExperimentalDecomposeApi
import com.arkivanov.decompose.extensions.compose.jetbrains.lifecycle.LifecycleController
import com.arkivanov.essenty.backhandler.BackDispatcher
import com.arkivanov.essenty.lifecycle.LifecycleRegistry

@OptIn(ExperimentalDecomposeApi::class)
@Composable
fun defaultRouterContext(
backDispatcher: BackDispatcher = BackDispatcher(),
lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(),
windowState: WindowState = rememberWindowState(),
): RouterContext {
LifecycleController(lifecycleRegistry, windowState)
return RouterContext(lifecycle = lifecycleRegistry, backHandler = backDispatcher)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.github.xxfast.decompose.router

import com.arkivanov.essenty.backhandler.BackDispatcher
import com.arkivanov.essenty.lifecycle.Lifecycle
import com.arkivanov.essenty.lifecycle.LifecycleRegistry
import com.arkivanov.essenty.lifecycle.destroy
import com.arkivanov.essenty.lifecycle.pause
import com.arkivanov.essenty.lifecycle.resume
import com.arkivanov.essenty.lifecycle.stop

fun defaultRouterContext(): RouterContext {
val backDispatcher = BackDispatcher()
val lifecycle = LifecycleRegistry()
return RouterContext(lifecycle = lifecycle, backHandler = backDispatcher)
}

private val RouterContext.lifecycleRegistry: LifecycleRegistry get() = this.lifecycle as LifecycleRegistry
fun RouterContext.destroy() = lifecycleRegistry.destroy()
fun RouterContext.resume() = lifecycleRegistry.resume()
fun RouterContext.stop() = lifecycleRegistry.stop()
fun RouterContext.pause() = lifecycleRegistry.pause()

This file was deleted.