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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
26 changes: 13 additions & 13 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,47 +39,47 @@ jobs:
run: |
echo -n "${{ secrets.ANDROID_KEYSTORE }}" | base64 -d > $RUNNER_TEMP/key.jks
- name: Build APK
run: ./gradlew composeApp:assembleRelease
run: ./gradlew androidApp:assembleRelease
- name: Build Deb
run: ./gradlew composeApp:packageDeb
run: ./gradlew desktopApp:packageDeb
- name: Build WASM
run: ./gradlew composeApp:wasmJsBrowserDistribution
run: ./gradlew webApp:wasmJsBrowserDistribution
- name: Build JS
run: ./gradlew composeApp:jsBrowserDistribution
run: ./gradlew webApp:jsBrowserDistribution
- name: Generate release assets
if: ${{ startsWith(github.ref, 'refs/tags/') }}
env:
VERSION: ${{ github.ref_name }}
run: |
JS_ZIP="com.shreyashkore.wonderouscompose_$VERSION-JS.zip"
WASM_ZIP="com.shreyashkore.wonderouscompose_$VERSION-WASM.zip"
(cd ./composeApp/build/dist && zip -r $JS_ZIP js)
(cd ./composeApp/build/dist && zip -r $WASM_ZIP wasmJs)
(cd ./webApp/build/dist && zip -r $JS_ZIP js)
(cd ./webApp/build/dist && zip -r $WASM_ZIP wasmJs)
- name: Release
if: ${{ startsWith(github.ref, 'refs/tags/') }}
uses: softprops/action-gh-release@v2.0.8
with:
token: ${{ secrets.TOKEN }}
files: |
./composeApp/build/outputs/apk/release/composeApp-release.apk
./composeApp/build/compose/binaries/main/deb/*.deb
./composeApp/build/dist/*.zip
./androidApp/build/outputs/apk/release/androidApp-release.apk
./desktopApp/build/compose/binaries/main/deb/*.deb
./webApp/build/dist/*.zip

- name: Deploy Wasm
if: ${{ github.event_name == 'release' }}
uses: JamesIves/github-pages-deploy-action@4.1.5
with:
token: ${{ secrets.TOKEN }}
branch: main
folder: composeApp/build/dist/wasmJs/productionExecutable
folder: webApp/build/dist/wasmJs/productionExecutable
repository-name: ShreyashKore/wonderous-compose-wasm
- name: Deploy JS
if: ${{ github.event_name == 'release' }}
uses: JamesIves/github-pages-deploy-action@4.1.5
with:
token: ${{ secrets.TOKEN }}
branch: main
folder: composeApp/build/dist/js/productionExecutable
folder: webApp/build/dist/js/productionExecutable
repository-name: ShreyashKore/wonderous-compose-js

build_windows:
Expand All @@ -103,14 +103,14 @@ jobs:
run: echo "sdk.dir=some_location" > ./local.properties
- name: Build MSI
run: |
./gradlew composeApp:packageMsi
./gradlew desktopApp:packageMsi
- name: Upload Release Asset
if: ${{ startsWith(github.ref, 'refs/tags/') }}
uses: softprops/action-gh-release@v2.0.8
with:
token: ${{ secrets.TOKEN }}
files: |
./composeApp/build/compose/binaries/main/msi/*.msi
./desktopApp/build/compose/binaries/main/msi/*.msi

# build_ios:
# runs-on: macos-latest
Expand Down
6 changes: 2 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
*.iml
.kotlin
.gradle
**/build/
xcuserdata
!src/**/build/
local.properties
/key.properties
.idea
.DS_Store
captures
Expand All @@ -16,6 +16,4 @@ captures
!*.xcodeproj/project.xcworkspace/
!*.xcworkspace/contents.xcworkspacedata
**/xcshareddata/WorkspaceSettings.xcsettings
journey/
.kotlin/
composeApp/release/
node_modules/
189 changes: 35 additions & 154 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,165 +1,46 @@
[![Banner](./readme_images/banner.png)](https://youtube.com/shorts/f-wM_MCiQmo?feature=share)
This is a Kotlin Multiplatform project targeting Android, iOS, Web, Desktop (JVM).

# Wonderous Compose
* [/iosApp](./iosApp/iosApp) contains an iOS application. Even if you’re sharing your UI with Compose Multiplatform,
you need this entry point for your iOS app. This is also where you should add SwiftUI code for your project.

![badge android][badge-android]
![badge ios][badge-ios]
![badge linux][badge-linux]
![badge windows][badge-windows]
![badge macos][badge-macos]
![badge web javascript][badge-js]
![badge web wasm][badge-wasm]
* [/shared](./shared/src) is for code that will be shared across your Compose Multiplatform applications.
It contains several subfolders:
- [commonMain](./shared/src/commonMain/kotlin) is for code that’s common for all targets.
- Other folders are for Kotlin code that will be compiled for only the platform indicated in the folder name.
For example, if you want to use Apple’s CoreCrypto for the iOS part of your Kotlin app,
the [iosMain](./shared/src/iosMain/kotlin) folder would be the right place for such calls.
Similarly, if you want to edit the Desktop (JVM) specific part, the [jvmMain](./shared/src/jvmMain/kotlin)
folder is the appropriate location.

Checkout live web version based on WASM here
[shreyashkore.github.io/wonderous-compose-wasm/](https://shreyashkore.github.io/wonderous-compose-wasm/)
### Running the apps

For the version based on JS see
[shreyashkore.github.io/wonderous-compose-js/](https://shreyashkore.github.io/wonderous-compose-js/)
Use the run configurations provided by the run widget in your IDE's toolbar. You can also use these commands and options:

> Note: Some gestures do not work on the web/desktop platforms. For scrolling horizontally
> use `Shift + Scroll`.
- Android app: `./gradlew :androidApp:assembleDebug`
- Desktop app:
- Hot reload: `./gradlew :desktopApp:hotRun --auto`
- Standard run: `./gradlew :desktopApp:run`
- Web app:
- Wasm target (faster, modern browsers): `./gradlew :webApp:wasmJsBrowserDevelopmentRun`
- JS target (slower, supports older browsers): `./gradlew :webApp:jsBrowserDevelopmentRun`
- iOS app: open the [/iosApp](./iosApp) directory in Xcode and run it from there.

> 🚧 WORK IN PROGRESS 🚧
### Running tests

> Contributions are welcome!
Use the run button in your IDE's editor gutter, or run tests using Gradle tasks:

Wonderous Compose is a port of Wonderous
in [Compose Multiplatform.](https://www.jetbrains.com/lp/compose-multiplatform/)
Wonderous Compose is a visual showcase of eight wonders of the world.
The [original project](https://flutter.gskinner.com/wonderous/) was built
by team [gskinner](https://gskinner.com/flutter/)
using [Flutter.](https://flutter.dev/) This project is a tribute to their original
work, with an aim to explore the design possibilities with Compose.
- Android tests: `./gradlew :shared:testAndroidHostTest`
- Desktop tests: `./gradlew :shared:jvmTest`
- Web tests:
- Wasm target: `./gradlew :shared:wasmJsTest`
- JS target: `./gradlew :shared:jsTest`
- iOS tests: `./gradlew :shared:iosSimulatorArm64Test`

Artworks and logos are taken from the original
project's [GitHub repo.](https://github.com/gskinnerTeam/flutter-wonderous-app)
Public-domain artwork from
[The Metropolitan Museum of Art, New Your.](https://www.metmuseum.org/about-the-met/policies-and-documents/open-access")
Photography from [Unsplash.](https://unsplash.com/@gskinner/collections)
---

![Wonderous Collage](./readme_images/wonderous_collage.png)
Learn more about [Kotlin Multiplatform](https://www.jetbrains.com/help/kotlin-multiplatform-dev/get-started.html),
[Compose Multiplatform](https://github.com/JetBrains/compose-multiplatform/#compose-multiplatform),
[Kotlin/Wasm](https://kotl.in/wasm/)…

## Outline

* [Home Screen](composeApp/src/commonMain/kotlin/ui/screens/home/HomeScreen.kt) shows the usage of
HorizontalPager along with AnimatedVisibility for animating
foreground and background elements.
* [ArtifactList Screen](composeApp/src/commonMain/kotlin/ui/screens/ArtifactListScreen.kt)
uses [`ArtifactListViewModel`](composeApp/src/commonMain/kotlin/ui/screens/ArtifactListViewModel.kt)
view model for business logic.
* [ArtifactDetails Screen](composeApp/src/commonMain/kotlin/ui/screens/ArtifactDetailsScreen.kt)
demonstrates writing business logic in the UI layer itself.
* [Editorial Screen](composeApp/src/commonMain/kotlin/ui/screens/EditorialScreen.kt) uses LazyColumn
layout and its scroll APIs to
drive animations/transitions for elements
when they appear on the screen.
* Map View demonstrates how KMP and Compose's interoperability layer can be used to embed native UIs
in Compose.
* For
Android [Google Map compose](https://developers.google.com/maps/documentation/android-sdk/maps-compose)
library is used.
* For IOS [MKMapView](https://developer.apple.com/documentation/mapkit/mkmapview) is used.
* For web [Wasm Html interop](https://github.com/Hamamas/Kotlin-Wasm-Html-Interop) library is
used to draw DOM elements on canvas. This allows us to
use [OpenLayers](https://openlayers.org/) for displaying OpenStreet maps.
* For desktop; mapview-desktop module is
copied from the official
[compose samples](https://github.com/JetBrains/compose-multiplatform/tree/master/examples/imageviewer/mapview-desktop).
This sample uses OpenStreetMap data to draw map tiles on Compose Canvas.
* The [Photo Gallery screen](composeApp/src/commonMain/kotlin/ui/screens/PhotoGalleryScreen.kt)
makes use of a custom layout and also uses a custom gesture detection
modifier.
* [Timeline screen](composeApp/src/commonMain/kotlin/ui/screens/timeline/TimelineScreen.kt)
uses [`TimelineState`](composeApp/src/commonMain/kotlin/ui/screens/timeline/TimelineScreen.kt)
which
is kind of a view controller for managing state of timeline. It manages conversion
of year to scroll position and vice versa.

## Libraries Used

- [Ktor](https://ktor.io/): HTTP networking
- [AndroidX Navigation](https://www.jetbrains.com/help/kotlin-multiplatform-dev/compose-navigation-routing.html):
Navigation
- [Compose Image Loader](https://github.com/qdsfdhvh/compose-imageloader): Image Loading
- [compose-webview-multiplatform](https://github.com/KevinnZou/compose-webview-multiplatform):
WebView for Android, IOS
and Desktop
- [maps-compose](https://developers.google.com/maps/documentation/android-sdk/maps-compose): Maps on
Android

## Source Sets

This project uses experimental DSL to configure custom hierarchy.

```kotlin
applyDefaultHierarchyTemplate {
common {
group("nonWeb") {
withAndroidTarget()
withNative()
withJvm()
}
group("web") {
withJs()
withWasm()
}
}
}
```

Here 2 additional intermediate source sets are created to share code among web platforms.

- `nonWeb` contains all the targets except JS and WASM.
- `web` contains only the JS and WASM targets

## TODO

- [x] WASM support

- [ ] Collectibles and My Collection Screen

- [x] Localization

- [ ] Gesture support on Web and Desktop platforms

- [X] Shared Element Transition on the home screen

- [x] Haptics

## Set up the environment

> For compose multiplatform setup information
> checkout the
> [documentation](https://www.jetbrains.com/help/kotlin-multiplatform-dev/compose-multiplatform-setup.html).

- Add Google Maps key in `local.properties` at the project root.

```properties
MAPS_API_KEY=YOUR_KEY
```

- Add `key.properties` at the project root (For the lazy ones like me; Just remove `signingConfigs`
and `keyProp` block from `composeApp/build.gradle.kts`).

```properties
storePassword=storePassword
keyPassword=keyPassword
alias=myKey
path=path/To/key.jks
```

[badge-android]: http://img.shields.io/badge/platform-android-6EDB8D.svg?style=flat

[badge-ios]: http://img.shields.io/badge/platform-ios-CDCDCD.svg?style=flat

[badge-js]: http://img.shields.io/badge/platform-js-F8DB5D.svg?style=flat

[badge-jvm]: http://img.shields.io/badge/platform-jvm-DB413D.svg?style=flat

[badge-linux]: http://img.shields.io/badge/platform-linux-2D3F6C.svg?style=flat

[badge-windows]: http://img.shields.io/badge/platform-windows-4D76CD.svg?style=flat

[badge-macos]: http://img.shields.io/badge/platform-macos-111111.svg?style=flat

[badge-wasm]: https://img.shields.io/badge/platform-wasm-624FE8.svg?style=flat
We would appreciate your feedback on Compose/Web and Kotlin/Wasm in the public Slack channel [#compose-web](https://slack-chats.kotlinlang.org/c/compose-web).
If you face any issues, please report them on [YouTrack](https://youtrack.jetbrains.com/newIssue?project=CMP).
71 changes: 71 additions & 0 deletions androidApp/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import java.util.Properties

plugins {
alias(libs.plugins.androidApplication)
alias(libs.plugins.composeMultiplatform)
alias(libs.plugins.composeCompiler)
alias(libs.plugins.androidMapsSecrets)
}

val keystorePropertiesFile = rootProject.file("key.properties")
val keystoreProperties = Properties().apply {
if (keystorePropertiesFile.exists()) {
load(keystorePropertiesFile.inputStream())
}
}

kotlin {
compilerOptions {
jvmTarget = JvmTarget.JVM_11
}
}
dependencies {
implementation(projects.shared)

implementation(libs.androidx.activity.compose)
implementation(libs.androidx.appcompat)

implementation(libs.compose.uiToolingPreview)
debugImplementation(libs.compose.uiTooling)
}

android {
namespace = "dev.shreyash.wonderouscompose"
compileSdk = libs.versions.android.compileSdk.get().toInt()

defaultConfig {
applicationId = "dev.shreyash.wonderouscompose"
minSdk = libs.versions.android.minSdk.get().toInt()
targetSdk = libs.versions.android.targetSdk.get().toInt()
versionCode = libs.versions.versionCode.get().toInt()
versionName = libs.versions.versionName.get()
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}
signingConfigs {
if (keystorePropertiesFile.exists()) {
create("release") {
storeFile = file(keystoreProperties.getProperty("path"))
storePassword = keystoreProperties.getProperty("storePassword")
keyAlias = keystoreProperties.getProperty("alias")
keyPassword = keystoreProperties.getProperty("keyPassword")
}
}
}
buildTypes {
getByName("release") {
isMinifyEnabled = false
if (keystorePropertiesFile.exists()) {
signingConfig = signingConfigs.getByName("release")
}
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package com.shreyashkore.wonderouscompose
package dev.shreyash.wonderouscompose

import App
import android.annotation.SuppressLint
import android.content.Context
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.WindowCompat.enableEdgeToEdge
import dev.shreyash.wonderouscompose.App

@SuppressLint("StaticFieldLeak")
private var _context: Context? = null
Expand Down
Loading
Loading