Skip to content
Draft
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
1 change: 1 addition & 0 deletions mpd.tree
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@
<toc-element toc-title="Choose integration method" topic="multiplatform-ios-integration-overview.md"/>
<toc-element topic="multiplatform-direct-integration.md"/>
<toc-element toc-title="Remote SPM export" topic="multiplatform-spm-export.md"/>
<toc-element toc-title="Importing a Swift package" topic="multiplatform-spm-import.md"/>
<toc-element toc-title="CocoaPods integration">
<toc-element topic="multiplatform-cocoapods-overview.md"/>
<toc-element topic="multiplatform-cocoapods-libraries.md"/>
Expand Down
31 changes: 17 additions & 14 deletions topics/compose-onboard/compose-multiplatform-create-first-app.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,39 +71,42 @@ If you didn't select iOS in the wizard, you won't have the folders whose names b

The project contains two modules:

* _composeApp_ is a Kotlin module that contains the logic shared among the Android, desktop, iOS, and web applications – the code
* _shared_ is a Kotlin module that contains the logic shared among the Android, desktop, iOS, and web applications – the code
you use for all the platforms. It uses [Gradle](https://kotlinlang.org/docs/gradle.html) as the build system that helps
you automate your build process.
* _androidApp_ is the module that builds into an Android application.
* _iosApp_ is an Xcode project that builds into an iOS application. It depends on and uses the shared module as an iOS
framework.

![Compose Multiplatform project structure](compose-project-structure.png)
* _desktopApp_ is the module that builds into a desktop JVM application. It depends on the `shared` module.
* _webApp_ is the module that builds into web applications, both Kotlin/JS and Kotlin/Wasm.

The **shared** module contains the following source sets: `androidMain`, `commonMain`, `iosMain`, `jsMain`,
`jvmMain`, and `wasmJsMain` (with `-Test` companion source sets if you chose to include tests).

The **composeApp** module consists of the following source sets: `androidMain`, `commonMain`, `iosMain`, `jsMain`,
`jvmMain`, `wasmJsMain`, and `webMain` (with `commonTest` if you chose to include tests).
A _source set_ is a Gradle concept for a number of files logically grouped together, where each group has its own
dependencies. In Kotlin Multiplatform, different source sets can target different platforms.

The `commonMain` source set uses the common Kotlin code, and platform source sets use Kotlin code specific to each
target:
target:

* `jvmMain` is the source file for desktop, which uses Kotlin/JVM.
* `androidMain` also uses Kotlin/JVM.
* `iosMain` uses Kotlin/Native.
* `jsMain` uses Kotlin/JS.
* `wasmJsMain` uses Kotlin/Wasm.
* `webMain` is the web [intermediate source set](multiplatform-hierarchy.md#manual-configuration) that includes `jsMain` and `wasmJsMain`.

When the shared module is built into an Android library, common Kotlin code gets treated as Kotlin/JVM. When it is built
When the `shared` module is built into an Android library, common Kotlin code gets treated as Kotlin/JVM. When it is built
into an iOS framework, common Kotlin code gets treated as Kotlin/Native. When the shared module is built into a web app, common
Kotlin code can be treated as Kotlin/Wasm and Kotlin/JS.
Kotlin code can be treated as Kotlin/Wasm or Kotlin/JS.

![Common Kotlin, Kotlin/JVM, and Kotlin/Native](module-structure.svg){width=700}

In general, write your implementation as common code whenever possible instead of duplicating functionality
in platform-specific source sets.

In the `composeApp/src/commonMain/kotlin` directory, open the `App.kt` file. It contains the `App()` function, which implements a
In the `shared/src/commonMain/kotlin` directory, open the `App.kt` file. It contains the `App()` function, which implements a
minimalistic but complete Compose Multiplatform UI:

```kotlin
Expand All @@ -129,14 +132,14 @@ fun App() {
horizontalAlignment = Alignment.CenterHorizontally,
) {
Image(painterResource(Res.drawable.compose_multiplatform), null)
Text("Compose: $greeting")
Text("Compose: ${greeting}")
}
}
}
}
}
```
{initial-collapse-state="collapsed" collapsible="true" collapsed-title="fun App()"}
{id="common-app-composable"}

Let's run the application on all supported platforms.

Expand All @@ -155,7 +158,7 @@ order, so start with whichever platform you are most familiar with.

1. In the list of run configurations, select **composeApp**.
2. Choose your Android virtual device and then click **Run**: Your IDE starts the selected virtual device if it
is powered down, and runs the app.
is powered down and runs the app.

![Run the Compose Multiplatform app on Android](compose-run-android.png){width=350}

Expand Down Expand Up @@ -265,7 +268,7 @@ in IntelliJ IDEA and select your device in the **Execution target** list. Run th

### Run your application on desktop

Select **composeApp [desktop]** in the list of run configurations and click **Run**. By default, the run configuration
Select **desktopApp** (TODO verify) in the list of run configurations and click **Run**. By default, the run configuration
starts a desktop app in its own OS window:

![Run the Compose Multiplatform app on desktop](compose-run-desktop.png){width=350}
Expand All @@ -276,8 +279,8 @@ starts a desktop app in its own OS window:

1. In the list of run configurations, select:

* **composeApp[js]**: To run your Kotlin/JS application.
* **composeApp[wasmJs]**: To run your Kotlin/Wasm application.
* **webApp[js]**: To run your Kotlin/JS application.
* **webApp[wasmJs]**: To run your Kotlin/Wasm application.

![Run the Compose Multiplatform app on web](web-run-configuration.png){width=400}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,38 +20,9 @@ platform-specific code that launches this UI on each platform.

## Implementing composable functions

In the `composeApp/src/commonMain/kotlin/App.kt` file, take a look at the `App()` function:
In the `shared/src/commonMain/kotlin/App.kt` file, take a look at the `App()` function:

```kotlin
@Composable
@Preview
fun App() {
MaterialTheme {
var showContent by remember { mutableStateOf(false) }
Column(
modifier = Modifier
.background(MaterialTheme.colorScheme.primaryContainer)
.safeContentPadding()
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Button(onClick = { showContent = !showContent }) {
Text("Click me!")
}
AnimatedVisibility(showContent) {
val greeting = remember { Greeting().greet() }
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Image(painterResource(Res.drawable.compose_multiplatform), null)
Text("Compose: $greeting")
}
}
}
}
}
```
<include from="compose-multiplatform-create-first-app.md" element-id="common-app-composable" />

The `App()` function is a regular Kotlin function annotated with `@Composable`. These kinds of functions are referred to
as _composable
Expand All @@ -65,15 +36,17 @@ A composable function has the following general structure:
the `AnimatedVisibility` composable.
* The `Button` contains the `Text` composable, which renders some text.
* The `AnimatedVisibility` shows and hides the `Image` using an animation.
* The `painterResource` loads a vector icon stored in an XML resource.
* The `painterResource` loads a vector icon stored as an XML file.

The `horizontalAlignment` parameter of the `Column` centers its content. But for this to have any effect, the column
should take up the full width of its container. This is achieved using the `modifier` parameter.

Modifiers are a key component of Compose Multiplatform. This is a primary mechanism you use to adjust the appearance or
behavior of composables in the UI. Modifiers are created using methods of the `Modifier` type. When you chain these
Modifiers are a key component of Jetpack Compose and Compose Multiplatform.
This is the primary mechanism you use to adjust the appearance or behavior of composables in the UI.
Modifiers are created using methods of the `Modifier` type. When you chain these
methods, each call can change the `Modifier` returned from the previous call, making the order significant.
See the [JetPack Compose documentation](https://developer.android.com/jetpack/compose/modifiers) for more details.
See the [Compose Multiplatform introduction to modifiers](https://kotlinlang.org/docs/multiplatform/compose-layout-modifiers.html#built-in-modifiers)
and the extensive [Jetpack Compose modifier documentation](https://developer.android.com/jetpack/compose/modifiers) for more details.

### Managing the state

Expand Down Expand Up @@ -102,7 +75,7 @@ controller; on the desktop, by a window; and on the web, by a container. Let's e

### On Android

For Android, open the `MainActivity.kt` file in `composeApp/src/androidMain/kotlin`:
For Android, open the `MainActivity.kt` file within `androidApp/src/main/kotlin`:

```kotlin
class MainActivity : ComponentActivity() {
Expand All @@ -122,38 +95,42 @@ called `MainActivity` that invokes the `App` composable.

### On iOS

For iOS, open the `MainViewController.kt` file in `composeApp/src/iosMain/kotlin`:
For iOS, open the `MainViewController.kt` file within `shared/src/iosMain/kotlin`:

```kotlin
fun MainViewController() = ComposeUIViewController { App() }
```

This is a [view controller](https://developer.apple.com/documentation/uikit/view_controllers) that performs the same
role as an activity on Android. Notice that both the iOS and Android types simply invoke the `App` composable.
role as an activity on Android. Notice that both the iOS and Android types simply invoke the `App` composable from common code.

### On desktop

For desktop, look at the `main()` function in `composeApp/src/jvmMain/kotlin`:
For desktop, look for the `main.kt` file in `desktopApp/src/main/kotlin`:

```kotlin
fun main() = application {
Window(onCloseRequest = ::exitApplication, title = "ComposeDemo") {
Window(
onCloseRequest = ::exitApplication,
title = "ComposeDemo"
) {
App()
}
}
```

* Here, the `application()` function launches a new desktop application.
* This function takes a lambda, where you initialize the UI. Typically, you create a `Window` and specify properties and
instructions that dictate how the program should react when the window is closed. In this case, the whole application shuts down.
* Inside this window, you can place your content. As with Android and iOS, the only content is the `App()` function.
* This function takes a lambda, which initializes the UI. Typically, you create a `Window` and specify properties and
instructions that dictate how the program should react when the window is closed (`onCloseRequest`).
In this case, the whole application shuts down.
* Inside this window, you can place your content. As with Android and iOS, the only content is the UI provided by the `App()` function.

Currently, the `App` function doesn't declare any parameters. In a larger application, you typically pass parameters to
platform-specific dependencies. These dependencies could be created by hand or using a dependency injection library.
In this example, the `App()` function doesn't declare any parameters. In a larger application, you typically pass parameters to
platform-specific dependencies. These dependencies could be written manually or passed using a dependency injection library.

### On web

In the `composeApp/src/webMain/kotlin/main.kt` file, take a look at the `main()` function:
In the `main.kt` file within the `webApp/src/webMain/kotlin/` directory, take a look at the `main()` function:

```kotlin
@OptIn(ExperimentalComposeUiApi::class)
Expand All @@ -164,15 +141,12 @@ fun main() {
}
```

* The `@OptIn(ExperimentalComposeUiApi::class)` annotation tells the compiler that you are using an API marked as
* The `@OptIn(ExperimentalComposeUiApi::class)` annotation tells the compiler that you are using a Compose API marked as
experimental and may change in future releases.
* The `ComposeViewport{}` function sets up the Compose environment for the application.
* The web app is inserted into the container specified as a parameter for the `ComposeViewport` function.
* The `App()` function is responsible for building the UI components of your application using Jetpack Compose.

The `main.kt` file is located
in the `webMain` directory, which contains common code for the web targets.

## Next step

In the next part of the tutorial, you'll add a dependency to the project and modify the user interface.
Expand Down
44 changes: 27 additions & 17 deletions topics/compose-onboard/compose-multiplatform-modify-project.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,15 @@ But we recommend that you use this approach only when there's no Kotlin Multipla
you can rely on the [kotlinx-datetime](https://github.com/Kotlin/kotlinx-datetime) library.

> You can explore Kotlin Multiplatform libraries available for your target platforms on [klibs.io](https://klibs.io/),
> an experimental search service from JetBrains for discovering multiplatform libraries.
> a search service by JetBrains for discovering multiplatform libraries.
>
{style="tip"}

To use the `kotlinx-datetime` library:

1. Open the `composeApp/build.gradle.kts` file and add the dependencies to the project:

* Add the main `kotlinx-datetime` dependency to the section that configures the common code source set.
For simplicity, you can include the version number directly instead of adding it to the version catalog.
* For the web target, timezone support requires the `js-joda` library.
Add a reference to the `js-joda` npm package in the `webMain` dependencies.
1. Open the `shared/build.gradle.kts` file and add the main `kotlinx-datetime` dependency to the section that configures
the common code source set.
For simplicity, you can include the version number directly instead of adding it to the version catalog.

```kotlin
kotlin {
Expand All @@ -47,25 +44,39 @@ To use the `kotlinx-datetime` library:
// ...
implementation("org.jetbrains.kotlinx:kotlinx-datetime:%dateTimeVersion%")
}
webMain.dependencies {
}
}

```
2. For the web target, timezone support requires the `js-joda` library.
Add a reference to the `js-joda` npm package to the `webApp/build.gradle.kts file`:

```kotlin
kotlin {
// ...
sourceSets {
// ...
commonMain.dependencies {
// ...
implementation(npm("@js-joda/timezone", "2.22.0"))
}
}
}

```

2. Once the dependency is added, you're prompted to resync the project. Click the **Sync Gradle Changes** button to synchronize Gradle files: ![Synchronize Gradle files](gradle-sync.png){width=50}

3. In the **Terminal** tool window, run the following command:
Adding the dependency to the `commonMain` source set makes the library available both to the `wasmJs` and `js` targets.

3. Once the dependency is added, accept the IDE suggestion to sync the Gradle configuration
or press double **Shift** and execute the **Sync Project with Gradle Files** command.

4. In the **Terminal** tool window, run the following command to ensure that the `yarn.lock` file is updated with the latest dependency versions:

```shell
./gradlew kotlinUpgradeYarnLock kotlinWasmUpgradeYarnLock
```

This Gradle task ensures that the `yarn.lock` file is updated with the latest dependency versions.

4. In the `webMain` source set, use the `@JsModule` annotation to import the `js-joda` npm package:
5. In the `webApp/src/webMain/kotlin/.../main.kt` file, use the `@JsModule` annotation to import the `js-joda` npm package:

```kotlin
import androidx.compose.ui.ExperimentalComposeUiApi
Expand All @@ -90,7 +101,8 @@ To use the `kotlinx-datetime` library:

## Enhance the user interface

1. Open the `composeApp/src/commonMain/kotlin/App.kt` file and add the following function which returns a string containing the current date:
1. Open the `shared/src/commonMain/kotlin/App.kt` file and after the `App()` composable add the following function
which returns a string containing the current date:

```kotlin
fun todaysDate(): String {
Expand Down Expand Up @@ -138,8 +150,6 @@ To use the `kotlinx-datetime` library:
```

4. Follow the IDE's suggestions to import the missing dependencies.
Make sure to import all the missing dependencies for the `todaysDate()` function from the updated packages, and
opt in when prompted by the IDE.

![Unresolved references](compose-unresolved-references.png)

Expand Down
Loading