Skip to content

Commit 0706bfa

Browse files
authored
Lazy Grid Image Demo with three different implementations (#5274)
- CMP, native iOS, native Android with the same functionality - supposed to be used to compare Compose Multiplatform performance metrics with native counter-parts. Required for [CMP-7682](https://youtrack.jetbrains.com/issue/CMP-7682/Create-benchmarks-for-marketing-purposes). ## Testing Manually ## Release Notes N/A
1 parent 7908e64 commit 0706bfa

File tree

89 files changed

+3128
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+3128
-0
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
.kotlin
2+
.gradle
3+
.idea
4+
**/build/
5+
local.properties
6+
iosApp/iosApp.xcworkspace/*
7+
iosApp/iosApp.xcodeproj/*
8+
!iosApp/iosApp.xcodeproj/project.pbxproj
9+
nativeiosApp/nativeiosApp.xcworkspace/*
10+
nativeiosApp/nativeiosApp.xcodeproj/*
11+
!nativeiosApp/nativeiosApp.xcodeproj/project.pbxproj
12+
13+
# Ignore downloaded images except the first one
14+
composeApp/src/commonMain/composeResources/drawable/downloaded_image*.jpg
15+
nativeiosApp/nativeiosApp/Assets.xcassets/downloaded_image*.imageset
16+
nativeAndroidApp/app/src/main/res/drawable/downloaded_image*.jpg
17+
!composeApp/src/commonMain/composeResources/drawable/downloaded_image001.jpg
18+
!nativeiosApp/nativeiosApp/Assets.xcassets/downloaded_image001.imageset
19+
!nativeAndroidApp/app/src/main/res/drawable/downloaded_image001.jpg
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<component name="ProjectRunConfigurationManager">
2+
<configuration default="false" name="desktopApp" type="GradleRunConfiguration" factoryName="Gradle">
3+
<ExternalSystemSettings>
4+
<option name="executionName" />
5+
<option name="externalProjectPath" value="$PROJECT_DIR$/composeApp" />
6+
<option name="externalSystemIdString" value="GRADLE" />
7+
<option name="scriptParameters" value="" />
8+
<option name="taskDescriptions">
9+
<list />
10+
</option>
11+
<option name="taskNames">
12+
<list>
13+
<option value="run" />
14+
</list>
15+
</option>
16+
<option name="vmOptions" value="" />
17+
</ExternalSystemSettings>
18+
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
19+
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
20+
<DebugAllEnabled>false</DebugAllEnabled>
21+
<method v="2" />
22+
</configuration>
23+
</component>
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Lazy Grid Image Demo
2+
3+
This project demonstrates how to display a grid of images across multiple platforms: Android, iOS, and Desktop.
4+
5+
The project includes three different implementations of the same functionality:
6+
7+
1. **Kotlin Multiplatform with Compose** - a shared implementation using Compose Multiplatform
8+
2. **Native Android** - a pure Android implementation using Jetpack Compose
9+
3. **Native iOS** - a pure iOS implementation using SwiftUI
10+
11+
The application displays 999 images in a LazyVerticalGrid (or equivalent on each platform) with 3 columns.
12+
The images are loaded from local resources:
13+
14+
- In the Compose Multiplatform version, images are loaded using the Compose Multiplatform resource system
15+
- In the native Android version, images are loaded using the Android resource system
16+
- In the native iOS version, images are loaded from the iOS asset catalog
17+
18+
The project is used to compare Compose Multiplatform performance metrics with native counter-parts such us
19+
size, startup time, FPS, CPU/GPU usage, etc.
20+
21+
## Project Structure
22+
23+
* `/composeApp` - Contains the Kotlin Multiplatform implementation using Compose Multiplatform
24+
- `commonMain` - Code shared across all platforms
25+
- `androidMain` - Android-specific code
26+
- `iosMain` - iOS-specific code
27+
- `desktopMain` - Desktop-specific code
28+
29+
* `/nativeAndroidApp` - Contains a native Android implementation using Jetpack Compose
30+
- Uses Android's resource system to load images
31+
32+
* `/nativeiosApp` - Contains a native iOS implementation using SwiftUI
33+
- Uses iOS asset catalog to load images
34+
35+
## Downloading Images
36+
37+
This project includes a script to download 999 different images
38+
from [Picsum Photos](https://picsum.photos/) with 512x512 resolution:
39+
40+
`./download_images.sh`
41+
42+
Please run the script before building the project.
43+
44+
## Building and Running
45+
46+
### Compose Multiplatform App
47+
- For Android: Run the `composeApp` configuration from Android Studio
48+
- For iOS: Open the Xcode project in the `iosApp` directory
49+
- For Desktop: Run the `desktopApp` configuration from IntelliJ IDEA or Android Studio
50+
51+
### Native Android App
52+
- Open the `nativeAndroidApp` directory in Android Studio and run the app
53+
54+
### Native iOS App
55+
- Open the `nativeiosApp/nativeiosApp.xcodeproj` in Xcode and run the app
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
plugins {
2+
// this is necessary to avoid the plugins to be loaded multiple times
3+
// in each subproject's classloader
4+
alias(libs.plugins.androidApplication) apply false
5+
alias(libs.plugins.androidLibrary) apply false
6+
alias(libs.plugins.composeMultiplatform) apply false
7+
alias(libs.plugins.composeCompiler) apply false
8+
alias(libs.plugins.kotlinMultiplatform) apply false
9+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
2+
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
3+
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
4+
5+
plugins {
6+
alias(libs.plugins.kotlinMultiplatform)
7+
alias(libs.plugins.androidApplication)
8+
alias(libs.plugins.composeMultiplatform)
9+
alias(libs.plugins.composeCompiler)
10+
}
11+
12+
kotlin {
13+
androidTarget {
14+
@OptIn(ExperimentalKotlinGradlePluginApi::class)
15+
compilerOptions {
16+
jvmTarget.set(JvmTarget.JVM_11)
17+
}
18+
}
19+
20+
listOf(
21+
iosX64(),
22+
iosArm64(),
23+
iosSimulatorArm64()
24+
).forEach { iosTarget ->
25+
iosTarget.binaries.framework {
26+
baseName = "ComposeApp"
27+
isStatic = true
28+
}
29+
}
30+
31+
jvm("desktop")
32+
33+
sourceSets {
34+
val desktopMain by getting
35+
36+
androidMain.dependencies {
37+
implementation(compose.preview)
38+
implementation(libs.androidx.activity.compose)
39+
}
40+
commonMain.dependencies {
41+
implementation(compose.runtime)
42+
implementation(compose.foundation)
43+
implementation(compose.material3)
44+
implementation(compose.ui)
45+
implementation(compose.components.resources)
46+
implementation(compose.components.uiToolingPreview)
47+
implementation(libs.androidx.lifecycle.viewmodel)
48+
implementation(libs.androidx.lifecycle.runtime.compose)
49+
}
50+
desktopMain.dependencies {
51+
implementation(compose.desktop.currentOs)
52+
implementation(libs.kotlinx.coroutines.swing)
53+
}
54+
}
55+
}
56+
57+
android {
58+
namespace = "org.jetbrains.lazygridimage"
59+
compileSdk = libs.versions.android.compileSdk.get().toInt()
60+
61+
defaultConfig {
62+
applicationId = "org.jetbrains.lazygridimage"
63+
minSdk = libs.versions.android.minSdk.get().toInt()
64+
targetSdk = libs.versions.android.targetSdk.get().toInt()
65+
versionCode = 1
66+
versionName = "1.0"
67+
}
68+
packaging {
69+
resources {
70+
excludes += "/META-INF/{AL2.0,LGPL2.1}"
71+
}
72+
}
73+
buildTypes {
74+
getByName("release") {
75+
isMinifyEnabled = false
76+
}
77+
}
78+
compileOptions {
79+
sourceCompatibility = JavaVersion.VERSION_11
80+
targetCompatibility = JavaVersion.VERSION_11
81+
}
82+
}
83+
84+
compose.desktop {
85+
application {
86+
mainClass = "org.jetbrains.lazygridimage.MainKt"
87+
}
88+
}
89+
90+
dependencies {
91+
debugImplementation(compose.uiTooling)
92+
}
93+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
3+
4+
<application
5+
android:allowBackup="true"
6+
android:icon="@mipmap/ic_launcher"
7+
android:label="@string/app_name"
8+
android:roundIcon="@mipmap/ic_launcher_round"
9+
android:supportsRtl="true"
10+
android:theme="@android:style/Theme.Material.Light.NoActionBar">
11+
<activity
12+
android:exported="true"
13+
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden|mnc|colorMode|density|fontScale|fontWeightAdjustment|keyboard|layoutDirection|locale|mcc|navigation|smallestScreenSize|touchscreen|uiMode"
14+
android:name=".MainActivity">
15+
<intent-filter>
16+
<action android:name="android.intent.action.MAIN" />
17+
18+
<category android:name="android.intent.category.LAUNCHER" />
19+
</intent-filter>
20+
</activity>
21+
</application>
22+
23+
</manifest>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package org.jetbrains.lazygridimage
2+
3+
import android.os.Bundle
4+
import androidx.activity.ComponentActivity
5+
import androidx.activity.compose.setContent
6+
import androidx.compose.runtime.Composable
7+
import androidx.compose.ui.tooling.preview.Preview
8+
9+
class MainActivity : ComponentActivity() {
10+
override fun onCreate(savedInstanceState: Bundle?) {
11+
super.onCreate(savedInstanceState)
12+
13+
setContent {
14+
App()
15+
}
16+
}
17+
}
18+
19+
@Preview
20+
@Composable
21+
fun AppAndroidPreview() {
22+
App()
23+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
xmlns:aapt="http://schemas.android.com/aapt"
3+
android:width="108dp"
4+
android:height="108dp"
5+
android:viewportWidth="108"
6+
android:viewportHeight="108">
7+
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
8+
<aapt:attr name="android:fillColor">
9+
<gradient
10+
android:endX="85.84757"
11+
android:endY="92.4963"
12+
android:startX="42.9492"
13+
android:startY="49.59793"
14+
android:type="linear">
15+
<item
16+
android:color="#44000000"
17+
android:offset="0.0" />
18+
<item
19+
android:color="#00000000"
20+
android:offset="1.0" />
21+
</gradient>
22+
</aapt:attr>
23+
</path>
24+
<path
25+
android:fillColor="#FFFFFF"
26+
android:fillType="nonZero"
27+
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
28+
android:strokeWidth="1"
29+
android:strokeColor="#00000000" />
30+
</vector>

0 commit comments

Comments
 (0)