Browse Source

Move visual-effects sample to KMM structure and add Android/iOS targets (#2573)

* Put all samples to one with a simple navigation

* Move desktop dependencies to main.kt and Wave settings panel to a separate class

* Use common resource API instead of desktop only for RotatingWords

* Move project to KMM structure and add iOS/Android target

* Change year for Happy New Year!

* Correct README.md
pull/2575/head
Nikita Lipsky 2 years ago committed by GitHub
parent
commit
55d97d0091
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      experimental/examples/visual-effects/.gitignore
  2. 4
      experimental/examples/visual-effects/.run/desktopApp.run.xml
  3. 7
      experimental/examples/visual-effects/.run/iosApp (Android Studio).run.xml
  4. 8
      experimental/examples/visual-effects/.run/iosApp.run.xml
  5. 28
      experimental/examples/visual-effects/README.md
  6. 33
      experimental/examples/visual-effects/androidApp/build.gradle.kts
  7. 21
      experimental/examples/visual-effects/androidApp/src/main/AndroidManifest.xml
  8. 15
      experimental/examples/visual-effects/androidApp/src/main/kotlin/MainActivity.kt
  9. 3
      experimental/examples/visual-effects/androidApp/src/main/res/values/strings.xml
  10. 69
      experimental/examples/visual-effects/build.gradle.kts
  11. 55
      experimental/examples/visual-effects/desktopApp/build.gradle.kts
  12. 12
      experimental/examples/visual-effects/desktopApp/src/jvmMain/kotlin/main.kt
  13. 16
      experimental/examples/visual-effects/gradle.properties
  14. 1
      experimental/examples/visual-effects/iosApp/Configuration/TeamId.xcconfig
  15. 5
      experimental/examples/visual-effects/iosApp/Podfile
  16. 398
      experimental/examples/visual-effects/iosApp/VisualEffects.xcodeproj/project.pbxproj
  17. 48
      experimental/examples/visual-effects/iosApp/iosApp/Info.plist
  18. 15
      experimental/examples/visual-effects/iosApp/iosApp/iosApp.swift
  19. BIN
      experimental/examples/visual-effects/run-configurations.png
  20. BIN
      experimental/examples/visual-effects/screenshots/desktop-run-configuration.png
  21. 18
      experimental/examples/visual-effects/settings.gradle.kts
  22. 77
      experimental/examples/visual-effects/shared/build.gradle.kts
  23. 2
      experimental/examples/visual-effects/shared/src/androidMain/AndroidManifest.xml
  24. 5
      experimental/examples/visual-effects/shared/src/androidMain/kotlin/main.android.kt
  25. 3
      experimental/examples/visual-effects/shared/src/androidMain/kotlin/platform/NanoTime.kt
  26. 8
      experimental/examples/visual-effects/shared/src/androidMain/kotlin/platform/PointerEventKind.android.kt
  27. 90
      experimental/examples/visual-effects/shared/src/commonMain/kotlin/AllSamlesView.kt
  28. 62
      experimental/examples/visual-effects/shared/src/commonMain/kotlin/HappyNY.kt
  29. 43
      experimental/examples/visual-effects/shared/src/commonMain/kotlin/RotatingWords.kt
  30. 101
      experimental/examples/visual-effects/shared/src/commonMain/kotlin/WaveEffect.kt
  31. 3
      experimental/examples/visual-effects/shared/src/commonMain/kotlin/platform/NanoTime.kt
  32. 52
      experimental/examples/visual-effects/shared/src/commonMain/kotlin/platform/PointerEventKind.kt
  33. 0
      experimental/examples/visual-effects/shared/src/commonMain/resources/compose-community-primary.png
  34. 0
      experimental/examples/visual-effects/shared/src/commonMain/resources/compose-community-primary.svg
  35. 52
      experimental/examples/visual-effects/shared/src/desktopMain/kotlin/WaveSettings.kt
  36. 59
      experimental/examples/visual-effects/shared/src/desktopMain/kotlin/main.desktop.kt
  37. 3
      experimental/examples/visual-effects/shared/src/desktopMain/kotlin/platform/NanoTime.kt
  38. 23
      experimental/examples/visual-effects/shared/src/desktopMain/kotlin/platform/PointerEventKind.desktop.kt
  39. 22
      experimental/examples/visual-effects/shared/src/iosMain/kotlin/main.ios.kt
  40. 3
      experimental/examples/visual-effects/shared/src/iosMain/kotlin/platform/NanoTime.kt
  41. 8
      experimental/examples/visual-effects/shared/src/iosMain/kotlin/platform/PointerEventKind.ios.kt
  42. 32
      experimental/examples/visual-effects/src/main/kotlin/main.kt

6
experimental/examples/visual-effects/.gitignore vendored

@ -13,3 +13,9 @@ build/
/captures
.externalNativeBuild
.cxx
iosApp/Podfile.lock
iosApp/Pods/*
iosApp/VisualEffects.xcworkspace/*
iosApp/VisualEffects.xcodeproj/*
!iosApp/VisualEffects.xcodeproj/project.pbxproj
shared/shared.podspec

4
experimental/examples/visual-effects/.run/desktop.run.xml → experimental/examples/visual-effects/.run/desktopApp.run.xml

@ -1,5 +1,5 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="desktop" type="GradleRunConfiguration" factoryName="Gradle">
<configuration default="false" name="desktopApp" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
@ -10,7 +10,7 @@
</option>
<option name="taskNames">
<list>
<option value=":run" />
<option value=":desktopApp:run" />
</list>
</option>
<option name="vmOptions" />

7
experimental/examples/visual-effects/.run/iosApp (Android Studio).run.xml

@ -0,0 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="iosApp (Android Studio)" type="KmmRunConfiguration" factoryName="iOS Application" CONFIG_VERSION="1" EXEC_TARGET_ID="00008110-000A683A0CE0401E" XCODE_PROJECT="$PROJECT_DIR$/./iosApp/VisualEffects.xcworkspace" XCODE_CONFIGURATION="Debug" XCODE_SCHEME="iosApp">
<method v="2">
<option name="com.jetbrains.kmm.ios.BuildIOSAppTask" enabled="true" />
</method>
</configuration>
</component>

8
experimental/examples/visual-effects/.run/iosApp.run.xml

@ -0,0 +1,8 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="iosApp" type="AppleRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="VisualEffects" TARGET_NAME="VisualEffects" CONFIG_NAME="Debug" IS_LOCATION_SIMULATION_SUPPORTED="true" SCHEME_NAME="iosApp" IS_LOCATION_SIMULATION_ALLOWED="true" LOCATION_SCENARIO_ID="com.apple.dt.IDEFoundation.CurrentLocationScenarioIdentifier" LOCATION_SCENARIO_TYPE="1" APPLICATION_LANGUAGE="IDELaunchSchemeLanguageUseSystemLanguage" APPLICATION_REGION="" RUN_TARGET_PROJECT_NAME="VisualEffects" RUN_TARGET_NAME="VisualEffects" MAKE_ACTIVE="TRUE" SHOULD_DEBUG_EXTENSIONS="false">
<embedded_app_extension_list />
<method v="2">
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
</method>
</configuration>
</component>

28
experimental/examples/visual-effects/README.md

@ -1,7 +1,25 @@
Several visual effects implmented with Compose Multiplatform, used in 1.0 release announce video.
# Visual Effects
### Running desktop application
* To run, launch command: `./gradlew run`
* Or choose **desktop** configuration in IDE and run it.
![desktop-run-configuration.png](screenshots/desktop-run-configuration.png)
Several visual effects implemented with Compose Multiplatform, used in 1.0 release announce video.
*Prerequisites*: to run on iOS and Android, you should have "Kotlin Multiplatform Mobile" plugin installed either
in Android Studio or in AppCode with [installed CocoaPods](https://kotlinlang.org/docs/native-cocoapods.html).
## How to run
Choose a run configuration for an appropriate target in IDE and run it.
![run-configurations.png](run-configurations.png)
To run on iOS device, please correct `iosApp/Configuration/TeamId.xcconfig` with your Apple Team ID.
Alternatively, you may setup signing within XCode opening `iosApp/VisualEffects.xcworkspace` and then
using "Signing & Capabilities" tab of `VisualEffects` target.
Then choose **iosApp** configuration in IDE and run it
(may also be referred as `VisualEffects` in the Run Configurations or `iosApp (Android Studio)` for Android Studio).
## Run on desktop via Gradle
`./gradlew desktopApp:run`

33
experimental/examples/visual-effects/androidApp/build.gradle.kts

@ -0,0 +1,33 @@
plugins {
kotlin("multiplatform")
id("com.android.application")
id("org.jetbrains.compose")
}
kotlin {
android()
sourceSets {
val androidMain by getting {
dependencies {
implementation(project(":shared"))
implementation("androidx.appcompat:appcompat:1.5.1")
implementation("androidx.activity:activity-compose:1.6.1")
}
}
}
}
android {
compileSdk = 33
defaultConfig {
applicationId = "org.jetbrains.VisualEffects"
minSdk = 24
targetSdk = 33
versionCode = 1
versionName = "1.0"
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
}

21
experimental/examples/visual-effects/androidApp/src/main/AndroidManifest.xml

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.jetbrains.compose.demo.visuals">
<application
android:allowBackup="true"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
<activity
android:exported="true"
android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

15
experimental/examples/visual-effects/androidApp/src/main/kotlin/MainActivity.kt

@ -0,0 +1,15 @@
package org.jetbrains.compose.demo.visuals
import MainView
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MainView()
}
}
}

3
experimental/examples/visual-effects/androidApp/src/main/res/values/strings.xml

@ -0,0 +1,3 @@
<resources>
<string name="app_name">Visual Effects</string>
</resources>

69
experimental/examples/visual-effects/build.gradle.kts

@ -1,62 +1,19 @@
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm")
id("org.jetbrains.compose")
// this is necessary to avoid the plugins to be loaded multiple times
// in each subproject's classloader
kotlin("jvm") apply false
kotlin("multiplatform") apply false
kotlin("android") apply false
id("com.android.application") apply false
id("com.android.library") apply false
id("org.jetbrains.compose") apply false
}
group = "me.user"
version = "1.0"
repositories {
mavenCentral()
allprojects {
repositories {
google()
maven { url = uri("https://maven.pkg.jetbrains.space/public/p/compose/dev") }
}
dependencies {
implementation(compose.desktop.currentOs)
}
tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "11"
kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
}
compose.desktop {
application {
mainClass = "org.jetbrains.compose.demo.visuals.MainKt"
nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "compose-demo"
packageVersion = "1.0.0"
}
}
}
afterEvaluate {
val additionalArguments = mutableListOf<String>()
val runTask = tasks.named<JavaExec>("run") {
this.args = additionalArguments
}
tasks.register("runWords") {
additionalArguments.add("words")
group = "compose desktop"
dependsOn(runTask)
}
tasks.register("runWave") {
additionalArguments.add("wave")
group = "compose desktop"
dependsOn(runTask)
}
tasks.register("runNewYear") {
additionalArguments.add("NY")
group = "compose desktop"
dependsOn(runTask)
mavenCentral()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
mavenLocal()
}
}

55
experimental/examples/visual-effects/desktopApp/build.gradle.kts

@ -0,0 +1,55 @@
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
plugins {
kotlin("multiplatform")
id("org.jetbrains.compose")
}
kotlin {
jvm {}
sourceSets {
val jvmMain by getting {
dependencies {
implementation(compose.desktop.currentOs)
implementation(project(":shared"))
}
}
}
}
compose.desktop {
application {
mainClass = "org.jetbrains.compose.demo.visuals.MainKt"
nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "compose-demo"
packageVersion = "1.0.0"
}
}
}
afterEvaluate {
val additionalArguments = mutableListOf<String>()
val runTask = tasks.named<JavaExec>("run") {
this.args = additionalArguments
}
tasks.register("runWords") {
additionalArguments.add("words")
group = "compose desktop"
dependsOn(runTask)
}
tasks.register("runWave") {
additionalArguments.add("wave")
group = "compose desktop"
dependsOn(runTask)
}
tasks.register("runNewYear") {
additionalArguments.add("NY")
group = "compose desktop"
dependsOn(runTask)
}
}

12
experimental/examples/visual-effects/desktopApp/src/jvmMain/kotlin/main.kt

@ -0,0 +1,12 @@
package org.jetbrains.compose.demo.visuals
fun main(args: Array<String>) {
if (args.isEmpty()) return allSamples()
when (val effect = args[0]) {
"words" -> mainWords()
"wave" -> mainWave(false)
"wave-controls" -> mainWave(true)
"NY" -> mainNY()
else -> throw Error("Unknown effect: $effect")
}
}

16
experimental/examples/visual-effects/gradle.properties

@ -1,3 +1,17 @@
kotlin.code.style=official
xcodeproj=./iosApp
kotlin.native.cocoapods.generate.wrapper=true
android.useAndroidX=true
org.gradle.jvmargs=-Xmx3g
org.jetbrains.compose.experimental.jscanvas.enabled=true
org.jetbrains.compose.experimental.macos.enabled=true
org.jetbrains.compose.experimental.uikit.enabled=true
kotlin.native.cacheKind=none
kotlin.native.useEmbeddableCompilerJar=true
kotlin.native.enableDependencyPropagation=false
kotlin.mpp.enableGranularSourceSetsMetadata=true
# Enable kotlin/native experimental memory model
kotlin.native.binary.memoryModel=experimental
kotlin.version=1.7.20
compose.version=1.2.2
agp.version=7.1.3
compose.version=1.2.1

1
experimental/examples/visual-effects/iosApp/Configuration/TeamId.xcconfig

@ -0,0 +1 @@
TEAM_ID=

5
experimental/examples/visual-effects/iosApp/Podfile

@ -0,0 +1,5 @@
target 'VisualEffects' do
use_frameworks!
platform :ios, '14.1'
pod 'shared', :path => '../shared'
end

398
experimental/examples/visual-effects/iosApp/VisualEffects.xcodeproj/project.pbxproj

@ -0,0 +1,398 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
2152FB042600AC8F00CF470E /* iosApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2152FB032600AC8F00CF470E /* iosApp.swift */; };
C1FC908188C4E8695729CB06 /* Pods_VisualEffects.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DE96E47030356CE6AD9794A /* Pods_VisualEffects.framework */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
1EB65E27D2C0F884D0A1A133 /* Pods-VisualEffects.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VisualEffects.debug.xcconfig"; path = "Target Support Files/Pods-VisualEffects/Pods-VisualEffects.debug.xcconfig"; sourceTree = "<group>"; };
2152FB032600AC8F00CF470E /* iosApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iosApp.swift; sourceTree = "<group>"; };
3D7A606AB0AD7636269BD9D0 /* Pods-VisualEffects.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VisualEffects.release.xcconfig"; path = "Target Support Files/Pods-VisualEffects/Pods-VisualEffects.release.xcconfig"; sourceTree = "<group>"; };
7555FF7B242A565900829871 /* VisualEffects.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = VisualEffects.app; sourceTree = BUILT_PRODUCTS_DIR; };
7555FF8C242A565B00829871 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
8DE96E47030356CE6AD9794A /* Pods_VisualEffects.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_VisualEffects.framework; sourceTree = BUILT_PRODUCTS_DIR; };
AB3632DC29227652001CCB65 /* TeamId.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = TeamId.xcconfig; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
9964867F0862B4D9FB6ABFC7 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
C1FC908188C4E8695729CB06 /* Pods_VisualEffects.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
7555FF72242A565900829871 = {
isa = PBXGroup;
children = (
AB1DB47929225F7C00F7AF9C /* Configuration */,
7555FF7D242A565900829871 /* iosApp */,
7555FF7C242A565900829871 /* Products */,
E1DAFBE8E1CFC0878361EF0E /* Pods */,
B62309C7396AD7BF607A63B2 /* Frameworks */,
);
sourceTree = "<group>";
};
7555FF7C242A565900829871 /* Products */ = {
isa = PBXGroup;
children = (
7555FF7B242A565900829871 /* VisualEffects.app */,
);
name = Products;
sourceTree = "<group>";
};
7555FF7D242A565900829871 /* iosApp */ = {
isa = PBXGroup;
children = (
7555FF8C242A565B00829871 /* Info.plist */,
2152FB032600AC8F00CF470E /* iosApp.swift */,
);
path = iosApp;
sourceTree = "<group>";
};
AB1DB47929225F7C00F7AF9C /* Configuration */ = {
isa = PBXGroup;
children = (
AB3632DC29227652001CCB65 /* TeamId.xcconfig */,
);
path = Configuration;
sourceTree = "<group>";
};
B62309C7396AD7BF607A63B2 /* Frameworks */ = {
isa = PBXGroup;
children = (
8DE96E47030356CE6AD9794A /* Pods_VisualEffects.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
E1DAFBE8E1CFC0878361EF0E /* Pods */ = {
isa = PBXGroup;
children = (
1EB65E27D2C0F884D0A1A133 /* Pods-VisualEffects.debug.xcconfig */,
3D7A606AB0AD7636269BD9D0 /* Pods-VisualEffects.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
7555FF7A242A565900829871 /* VisualEffects */ = {
isa = PBXNativeTarget;
buildConfigurationList = 7555FFA5242A565B00829871 /* Build configuration list for PBXNativeTarget "VisualEffects" */;
buildPhases = (
E8D673591E7196AEA2EA10E2 /* [CP] Check Pods Manifest.lock */,
7555FF77242A565900829871 /* Sources */,
7555FF79242A565900829871 /* Resources */,
9964867F0862B4D9FB6ABFC7 /* Frameworks */,
C64736A3E64D105DF1EF6621 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
);
name = VisualEffects;
productName = iosApp;
productReference = 7555FF7B242A565900829871 /* VisualEffects.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
7555FF73242A565900829871 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1130;
LastUpgradeCheck = 1130;
ORGANIZATIONNAME = org.jetbrains;
TargetAttributes = {
7555FF7A242A565900829871 = {
CreatedOnToolsVersion = 11.3.1;
};
};
};
buildConfigurationList = 7555FF76242A565900829871 /* Build configuration list for PBXProject "VisualEffects" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 7555FF72242A565900829871;
productRefGroup = 7555FF7C242A565900829871 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
7555FF7A242A565900829871 /* VisualEffects */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
7555FF79242A565900829871 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
C64736A3E64D105DF1EF6621 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-VisualEffects/Pods-VisualEffects-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-VisualEffects/Pods-VisualEffects-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-VisualEffects/Pods-VisualEffects-resources.sh\"\n";
showEnvVarsInLog = 0;
};
E8D673591E7196AEA2EA10E2 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-VisualEffects-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
7555FF77242A565900829871 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
2152FB042600AC8F00CF470E /* iosApp.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
7555FFA3242A565B00829871 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = AB3632DC29227652001CCB65 /* TeamId.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
7555FFA4242A565B00829871 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = AB3632DC29227652001CCB65 /* TeamId.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
7555FFA6242A565B00829871 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 1EB65E27D2C0F884D0A1A133 /* Pods-VisualEffects.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = "${TEAM_ID}";
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = iosApp/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.jetbrains.VisualEffects${TEAM_ID}";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
7555FFA7242A565B00829871 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 3D7A606AB0AD7636269BD9D0 /* Pods-VisualEffects.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_ASSET_PATHS = "";
DEVELOPMENT_TEAM = "${TEAM_ID}";
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = iosApp/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.jetbrains.VisualEffects${TEAM_ID}";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
7555FF76242A565900829871 /* Build configuration list for PBXProject "VisualEffects" */ = {
isa = XCConfigurationList;
buildConfigurations = (
7555FFA3242A565B00829871 /* Debug */,
7555FFA4242A565B00829871 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
7555FFA5242A565B00829871 /* Build configuration list for PBXNativeTarget "VisualEffects" */ = {
isa = XCConfigurationList;
buildConfigurations = (
7555FFA6242A565B00829871 /* Debug */,
7555FFA7242A565B00829871 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 7555FF73242A565900829871 /* Project object */;
}

48
experimental/examples/visual-effects/iosApp/iosApp/Info.plist

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
</dict>
<key>UILaunchScreen</key>
<dict/>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

15
experimental/examples/visual-effects/iosApp/iosApp/iosApp.swift

@ -0,0 +1,15 @@
import UIKit
import shared
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
let mainViewController = Main_iosKt.MainViewController()
window?.rootViewController = mainViewController
window?.makeKeyAndVisible()
return true
}
}

BIN
experimental/examples/visual-effects/run-configurations.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
experimental/examples/visual-effects/screenshots/desktop-run-configuration.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

18
experimental/examples/visual-effects/settings.gradle.kts

@ -2,12 +2,26 @@ pluginManagement {
repositories {
gradlePluginPortal()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
google()
}
plugins {
kotlin("jvm").version(extra["kotlin.version"] as String)
id("org.jetbrains.compose").version(extra["compose.version"] as String)
val kotlinVersion = extra["kotlin.version"] as String
val agpVersion = extra["agp.version"] as String
val composeVersion = extra["compose.version"] as String
kotlin("jvm").version(kotlinVersion)
kotlin("multiplatform").version(kotlinVersion)
kotlin("android").version(kotlinVersion)
id("com.android.base").version(agpVersion)
id("com.android.application").version(agpVersion)
id("com.android.library").version(agpVersion)
id("org.jetbrains.compose").version(composeVersion)
}
}
rootProject.name = "visual-effects"
include(":androidApp")
include(":shared")
include(":desktopApp")

77
experimental/examples/visual-effects/shared/build.gradle.kts

@ -0,0 +1,77 @@
plugins {
kotlin("multiplatform")
kotlin("native.cocoapods")
id("com.android.library")
id("org.jetbrains.compose")
}
version = "1.0-SNAPSHOT"
kotlin {
android()
jvm("desktop")
ios()
iosSimulatorArm64()
cocoapods {
summary = "Shared code for the sample"
homepage = "https://github.com/JetBrains/compose-jb"
ios.deploymentTarget = "14.1"
podfile = project.file("../iosApp/Podfile")
framework {
baseName = "shared"
isStatic = true
}
extraSpecAttributes["resources"] = "['src/commonMain/resources/**', 'src/iosMain/resources/**']"
}
sourceSets {
val commonMain by getting {
dependencies {
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material)
implementation(compose.materialIconsExtended)
implementation("org.jetbrains.compose.components:components-resources:1.3.0-beta04-dev879")
}
}
val androidMain by getting {
dependencies {
implementation("androidx.appcompat:appcompat:1.5.1")
implementation("androidx.core:core-ktx:1.8.0")
}
}
val iosMain by getting
val iosTest by getting
val iosSimulatorArm64Main by getting {
dependsOn(iosMain)
}
val iosSimulatorArm64Test by getting {
dependsOn(iosTest)
}
val desktopMain by getting {
dependencies {
implementation(compose.desktop.common)
}
}
}
}
android {
compileSdk = 33
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
sourceSets["main"].res.srcDirs("src/androidMain/res")
sourceSets["main"].resources.srcDirs("src/commonMain/resources")
defaultConfig {
minSdk = 24
targetSdk = 33
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
}

2
experimental/examples/visual-effects/shared/src/androidMain/AndroidManifest.xml

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.jetbrains.visualeffects"/>

5
experimental/examples/visual-effects/shared/src/androidMain/kotlin/main.android.kt

@ -0,0 +1,5 @@
import androidx.compose.runtime.Composable
import org.jetbrains.compose.demo.visuals.AllSamplesView
@Composable
fun MainView() = AllSamplesView()

3
experimental/examples/visual-effects/shared/src/androidMain/kotlin/platform/NanoTime.kt

@ -0,0 +1,3 @@
package org.jetbrains.compose.demo.visuals.platform
actual fun nanoTime(): Long = System.nanoTime()

8
experimental/examples/visual-effects/shared/src/androidMain/kotlin/platform/PointerEventKind.android.kt

@ -0,0 +1,8 @@
package org.jetbrains.compose.demo.visuals.platform
import androidx.compose.ui.Modifier
actual fun Modifier.onPointerEvent(
eventKind: PointerEventKind,
onEvent: Position.() -> Unit
): Modifier = this.onPointerEventMobileImpl(eventKind, onEvent)

90
experimental/examples/visual-effects/shared/src/commonMain/kotlin/AllSamlesView.kt

@ -0,0 +1,90 @@
package org.jetbrains.compose.demo.visuals
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@Composable
internal fun SampleWithTopAppBar(sample: Screen, state: MutableState<Screen>, content: @Composable (PaddingValues) -> Unit) {
Box(modifier = Modifier.fillMaxSize()) {
Scaffold(
topBar = {
TopAppBar(
title = { Text(text = sample.screen) },
navigationIcon =
{
IconButton(onClick = {state.value = Screen.CHOOSE_SAMPLE}) {
Icon(
imageVector = Icons.Filled.ArrowBack,
contentDescription = "Back"
)
}
}
)
},
content = content
)
}
}
enum class Screen(val screen: String) {
CHOOSE_SAMPLE("Choose a demo:"),
WORDS("Rotating Words"),
WAVE("Wave Effect"),
NY("Happy New Year!");
}
@Composable
internal fun MyButton(screenState: MutableState<Screen>, to: Screen) {
Button(onClick = {
screenState.value = to
}) {
Text(fontSize = 20.sp, text = to.screen)
}
}
@Composable
internal fun AllSamplesView() {
MaterialTheme {
val screenState: MutableState<Screen> = remember { mutableStateOf(Screen.CHOOSE_SAMPLE) }
when (screenState.value) {
Screen.CHOOSE_SAMPLE -> {
Column(modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally)
{
Text(modifier = Modifier.padding(10.dp), fontSize = 30.sp, text = Screen.CHOOSE_SAMPLE.screen)
MyButton(screenState, Screen.WORDS)
MyButton(screenState, Screen.WAVE)
MyButton(screenState, Screen.NY)
}
}
Screen.WORDS -> {
SampleWithTopAppBar(Screen.WORDS, screenState) {
RotatingWords()
}
}
Screen.WAVE -> {
SampleWithTopAppBar(Screen.WAVE, screenState) {
WaveEffectGrid()
}
}
Screen.NY -> {
SampleWithTopAppBar(Screen.NY, screenState) {
NYContent()
}
}
}
}
}

62
experimental/examples/visual-effects/src/main/kotlin/HappyNY.kt → experimental/examples/visual-effects/shared/src/commonMain/kotlin/HappyNY.kt

@ -1,6 +1,5 @@
package org.jetbrains.compose.demo.visuals
import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
@ -14,12 +13,12 @@ import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.*
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerMoveFilter
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.*
import java.lang.Math.random
import androidx.compose.ui.unit.em
import androidx.compose.ui.unit.sp
import org.jetbrains.compose.demo.visuals.platform.nanoTime
import kotlin.math.*
import kotlin.random.Random
@ -44,6 +43,8 @@ data class Star(val x: Dp, val y: Dp, val color: Color, val size: Dp)
const val HNYString = "Happy New Year!"
fun random(): Float = Random.nextFloat()
class DoubleRocket(val particle: Particle) {
private val STATE_ROCKET = 0
private val STATE_SMALL_ROCKETS = 1
@ -70,7 +71,7 @@ class DoubleRocket(val particle: Particle) {
}
private fun reset() {
if (particle.vx < 0) return //to stop drawing after the second rocket. This could be commented out
// if (particle.vx < 0) return //to stop drawing after the second rocket. This could be commented out
state = STATE_ROCKET
particle.x = if (particle.vx > 0) width - 0.0 else 0.0
particle.y = 1000.0
@ -109,7 +110,7 @@ class DoubleRocket(val particle: Particle) {
}
@Composable
fun draw() {
internal fun draw() {
if (state == rocket.STATE_ROCKET) {
particle.draw()
} else {
@ -162,7 +163,7 @@ class Rocket(val particle: Particle, val color: Color, val startTime: Long = 0)
}
@Composable
fun draw() {
internal fun draw() {
if (!exploded) {
particle.draw()
} else {
@ -184,7 +185,7 @@ class Particle(var x: Double, var y: Double, var vx: Double, var vy: Double, val
}
@Composable
fun draw() {
internal fun draw() {
val alphaFactor = if (type == 0) 1.0f else 1 / (1 + abs(vy / 5)).toFloat()
Box(Modifier.size(5.dp).offset(x.dp, y.dp).alpha(alphaFactor).clip(CircleShape).background(color))
for (i in 1..5) {
@ -198,15 +199,6 @@ class Particle(var x: Double, var y: Double, var vx: Double, var vy: Double, val
val rocket = DoubleRocket(Particle(0.0, 1000.0, 2.1, -12.5, Color.White))
@Composable
fun NYWindow(onCloseRequest: () -> Unit) {
val windowState = remember { WindowState(width = width.dp, height = height.dp) }
Window(onCloseRequest = onCloseRequest, undecorated = true, transparent = true, state = windowState) {
NYContent()
}
}
fun prepareStarsAndSnowFlakes(stars: SnapshotStateList<Star>, snowFlakes: SnapshotStateList<SnowFlake>) {
for (i in 0..snowCount) {
snowFlakes.add(
@ -237,12 +229,11 @@ fun prepareStarsAndSnowFlakes(stars: SnapshotStateList<Star>, snowFlakes: Snapsh
@OptIn(ExperimentalComposeUiApi::class)
@Composable
@Preview
fun NYContent() {
var time by remember { mutableStateOf(System.nanoTime()) }
internal fun NYContent() {
var time by remember { mutableStateOf(nanoTime()) }
var started by remember { mutableStateOf(false) }
var startTime = remember { System.nanoTime() }
var prevTime by remember { mutableStateOf(System.nanoTime()) }
var startTime = remember { nanoTime() }
var prevTime by remember { mutableStateOf(nanoTime()) }
val snowFlakes = remember { mutableStateListOf<SnowFlake>() }
val stars = remember { mutableStateListOf<Star>() }
var flickering2 by remember { mutableStateOf(true) }
@ -287,19 +278,23 @@ fun NYContent() {
starrySky(stars)
Row(modifier = Modifier.fillMaxSize(), verticalAlignment = Alignment.Bottom, horizontalArrangement = Arrangement.Center) {
Text(
"202",
Modifier.scale(10f).align(Alignment.Center).offset(-2.dp, 15.dp)
.alpha(if (flickering2) 0.8f else 1.0f),
fontSize = 10.em,
text = "202",
modifier = Modifier
.alpha(if (flickering2) 0.8f else 1.0f).offset(0.dp, -15.dp),
color = Color.White
)
val alpha = if (flickering2) flickeringAlpha(time) else 1.0f
Text(
"2",
Modifier.scale(10f).align(Alignment.Center).offset(14.dp, 15.dp).alpha(alpha),
fontSize = 10.em,
text = "3",
modifier = Modifier.alpha(alpha).offset(0.dp, -15.dp),
color = Color.White
)
}
if (started) { //delay to be able to start recording
//HNY
@ -309,7 +304,8 @@ fun NYContent() {
HNYString.forEach {
val alpha = alphaHNY(i, time, startTime)
Text(
it.toString(),
fontSize = 14.sp,
text= it.toString(),
color = color,
modifier = Modifier.scale(5f).align(Alignment.Center).offset(0.dp, 85.dp)
.rotate((angle + 5.0f * i)).offset(0.dp, -90.dp).alpha(alpha)
@ -375,20 +371,20 @@ fun flickeringAlpha(time: Long): Float {
@Composable
fun starrySky(stars: SnapshotStateList<Star>) {
internal fun starrySky(stars: SnapshotStateList<Star>) {
stars.forEach {
star(it.x, it.y, it.color, size = it.size)
}
}
@Composable
fun star(x: Dp, y: Dp, color: Color = Color.White, size: Dp) {
internal fun star(x: Dp, y: Dp, color: Color = Color.White, size: Dp) {
Box(Modifier.offset(x, y).scale(1.0f, 0.2f).rotate(45f).size(size).background(color))
Box(Modifier.offset(x, y).scale(0.2f, 1.0f).rotate(45f).size(size).background(color))
}
@Composable
fun snow(time: Long, prevTime: Long, snowFlakes: SnapshotStateList<SnowFlake>, startTime: Long) {
internal fun snow(time: Long, prevTime: Long, snowFlakes: SnapshotStateList<SnowFlake>, startTime: Long) {
val deltaAngle = (time - startTime) / 100000000
with(LocalDensity.current) {
snowFlakes.forEach {
@ -404,7 +400,7 @@ fun snow(time: Long, prevTime: Long, snowFlakes: SnapshotStateList<SnowFlake>, s
}
@Composable
fun snowFlake(modifier: Modifier, alpha: Float = 0.8f) {
internal fun snowFlake(modifier: Modifier, alpha: Float = 0.8f) {
Box(modifier) {
snowFlakeInt(0, 0f, 30.dp, 0.dp, alpha)
snowFlakeInt(0, 60f, 15.dp, 25.dp, alpha)
@ -417,7 +413,7 @@ fun snowFlake(modifier: Modifier, alpha: Float = 0.8f) {
}
@Composable
fun snowFlakeInt(level: Int, angle: Float, shiftX: Dp, shiftY: Dp, alpha: Float) {
internal fun snowFlakeInt(level: Int, angle: Float, shiftX: Dp, shiftY: Dp, alpha: Float) {
if (level > 3) return
Box(
Modifier.offset(shiftX, shiftY).rotate(angle).width(100.dp).height(10.dp).scale(0.6f).alpha(1f)

43
experimental/examples/visual-effects/src/main/kotlin/RotatingWords.kt → experimental/examples/visual-effects/shared/src/commonMain/kotlin/RotatingWords.kt

@ -1,18 +1,14 @@
package org.jetbrains.compose.demo.visuals
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.core.*
import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
@ -20,20 +16,15 @@ import androidx.compose.ui.draw.rotate
import androidx.compose.ui.draw.scale
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.loadSvgPainter
import androidx.compose.ui.res.useResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.WindowState
import androidx.compose.ui.window.singleWindowApplication
import org.jetbrains.compose.resources.*
@OptIn(ExperimentalAnimationApi::class, ExperimentalMaterialApi::class)
@Preview
@OptIn(ExperimentalResourceApi::class)
@Composable
fun Words() {
internal fun Words() {
val density = LocalDensity.current
val duration = 5000
@ -55,9 +46,8 @@ fun Words() {
)
)
val logoSvg = remember {
useResource("compose-community-primary.svg") { loadSvgPainter(it, density) }
}
// TODO: use vector image (.svg or .xml)
val logoImg = resource("compose-community-primary.png").rememberImageBitmap().orEmpty()
val baseLogo = DpOffset(350.dp, 270.dp)
@ -85,7 +75,7 @@ fun Words() {
alpha = 0.4f)
val size = 80.dp * scale
Image(logoSvg, contentDescription = "Logo",
Image(logoImg, contentDescription = "Logo",
modifier = Modifier
.offset(baseLogo.x - size / 2, baseLogo.y - size / 2)
.size(size)
@ -95,7 +85,7 @@ fun Words() {
}
@Composable
fun Word(position: DpOffset, angle: Float, scale: Float, text: String,
internal fun Word(position: DpOffset, angle: Float, scale: Float, text: String,
color: Color, alpha: Float = 0.8f) {
Text(
modifier = Modifier
@ -110,25 +100,24 @@ fun Word(position: DpOffset, angle: Float, scale: Float, text: String,
}
@Composable
@Preview
fun FallingSnow() {
internal fun FallingSnow() {
BoxWithConstraints(Modifier.fillMaxSize()) {
repeat(50) {
val size = remember { 20.dp + 10.dp * Math.random().toFloat() }
val alpha = remember { 0.10f + 0.15f * Math.random().toFloat() }
val size = remember { 20.dp + 10.dp * random() }
val alpha = remember { 0.10f + 0.15f * random() }
val sizePx = with(LocalDensity.current) { size.toPx() }
val x = remember { (constraints.maxWidth * Math.random()).toInt() }
val x = remember { (constraints.maxWidth * random()).toInt() }
val infiniteTransition = rememberInfiniteTransition()
val t by infiniteTransition.animateFloat(
initialValue = 0f,
targetValue = 1f,
animationSpec = infiniteRepeatable(
animation = tween(16000 + (16000 * Math.random()).toInt(), easing = LinearEasing),
animation = tween(16000 + (16000 * random()).toInt(), easing = LinearEasing),
repeatMode = RepeatMode.Restart
)
)
val initialT = remember { Math.random().toFloat() }
val initialT = remember { random() }
val actualT = (initialT + t) % 1f
val y = (-sizePx + (constraints.maxHeight + sizePx) * actualT).toInt()
@ -146,16 +135,14 @@ fun FallingSnow() {
}
@Composable
@Preview
fun Background() = Box(
internal fun Background() = Box(
Modifier
.fillMaxSize()
.background(Color(0xFF6F97FF))
)
@Composable
@Preview
fun RotatingWords() {
internal fun RotatingWords() {
Background()
FallingSnow()
Words()

101
experimental/examples/visual-effects/src/main/kotlin/WaveEffect.kt → experimental/examples/visual-effects/shared/src/commonMain/kotlin/WaveEffect.kt

@ -1,6 +1,5 @@
package org.jetbrains.compose.demo.visuals
import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
@ -10,41 +9,16 @@ import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.*
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.PointerEventType
import androidx.compose.ui.input.pointer.onPointerEvent
import androidx.compose.ui.input.pointer.pointerMoveFilter
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.WindowPosition
import androidx.compose.ui.window.WindowState
import org.jetbrains.compose.demo.visuals.platform.PointerEventKind
import org.jetbrains.compose.demo.visuals.platform.nanoTime
import org.jetbrains.compose.demo.visuals.platform.onPointerEvent
import kotlin.math.*
@Composable
fun WaveEffect(onCloseRequest: () -> Unit, showControls: Boolean) {
val windowState = remember { WindowState(width = 1200.dp, height = 800.dp) }
Window(onCloseRequest = {}, undecorated = true, transparent = true, state = windowState) {
Grid()
}
if (showControls) {
Window(
onCloseRequest = onCloseRequest,
state = WindowState(width = 200.dp, height = 400.dp, position = WindowPosition(1400.dp, 200.dp))
) {
Column {
SettingsPanel(State.red, "Red")
SettingsPanel(State.green, "Green")
SettingsPanel(State.blue, "Blue")
}
}
}
}
@OptIn(ExperimentalComposeUiApi::class)
@Composable
@Preview
fun Grid() {
internal fun WaveEffectGrid() {
var mouseX by remember { mutableStateOf(0) }
var mouseY by remember { mutableStateOf(0) }
var centerX by remember { mutableStateOf(1200) }
@ -52,10 +26,10 @@ fun Grid() {
var vX by remember { mutableStateOf(0) }
var vY by remember { mutableStateOf(0) }
var time by remember { mutableStateOf(System.nanoTime()) }
var prevTime by remember { mutableStateOf(System.nanoTime()) }
var time by remember { mutableStateOf(nanoTime()) }
var prevTime by remember { mutableStateOf(nanoTime()) }
if (State.mouseUsed) {
if (State.entered) {
centerX = (centerX + vX * (time - prevTime) / 1000000000).toInt()
if (centerX < -100) centerX = -100
if (centerX > 2600) centerX = 2600
@ -72,16 +46,17 @@ fun Grid() {
Surface(
modifier = Modifier.fillMaxSize().padding(5.dp).shadow(3.dp, RoundedCornerShape(20.dp))
.onPointerEvent(PointerEventType.Move) {
mouseX = it.changes.first().position.x.toInt()
mouseY = it.changes.first().position.y.toInt()
.onPointerEvent(PointerEventKind.Move) {
mouseX = x
mouseY = y
}
.onPointerEvent(PointerEventKind.In) {
State.entered = true
}
.onPointerEvent(PointerEventType.Enter) {
State.mouseUsed = true
.onPointerEvent(PointerEventKind.Out) {
State.entered = false
}
.onPointerEvent(PointerEventType.Exit) {
State.mouseUsed = false
},
,
color = Color(0, 0, 0),
shape = RoundedCornerShape(20.dp)
) {
@ -118,7 +93,7 @@ fun Grid() {
}
@Composable
fun HighPanel(mouseX: Int, mouseY: Int) {
internal fun HighPanel(mouseX: Int, mouseY: Int) {
Text(
"Compose",
Modifier.offset(270.dp, 600.dp).scale(7.0f).alpha(alpha(mouseX, mouseY, 270, 700)),
@ -133,7 +108,7 @@ fun HighPanel(mouseX: Int, mouseY: Int) {
)
Text(
"1.0",
Modifier.offset(800.dp, 700.dp).scale(7.0f).alpha(alpha(mouseX, mouseY, 800, 800)),
Modifier.offset(850.dp, 700.dp).scale(7.0f).alpha(alpha(mouseX, mouseY, 800, 800)),
color = colorMouse(mouseX, mouseY, 800, 800),
fontWeight = FontWeight.Bold
)
@ -173,7 +148,7 @@ private fun distance(x1: Int, y1: Int, x2: Int, y2: Int): Double {
}
@Composable
fun Dot(size: Int, modifier: Modifier, color: Color, time: Long) {
internal fun Dot(size: Int, modifier: Modifier, color: Color, time: Long) {
Box(
modifier.rotate(time.toFloat() / (15 * 10000000)).clip(RoundedCornerShape((3 + size / 20).dp))
.size(width = size.dp, height = size.dp)
@ -192,12 +167,12 @@ private fun size(x: Int, y: Int, mouseX: Int, mouseY: Int): Int {
val scale: Double = (if (distance2 < 1) {
addSize * (1 - distance2)
} else 0.toDouble())
result += (if (State.mouseUsed) round(7.5 * scale).toInt() else 0)
result += (if (State.entered) round(7.5 * scale).toInt() else 0)
return result
}
private fun boxColor(x: Int, y: Int, time: Long, mouseX: Int, mouseY: Int): Color {
if (!State.mouseUsed) return Color.White
if (!State.entered) return Color.White
val color1 = Color(0x6B, 0x57, 0xFF)
val color2 = Color(0xFE, 0x28, 0x57)
@ -228,38 +203,8 @@ private fun boxColor(x: Int, y: Int, time: Long, mouseX: Int, mouseY: Int): Colo
return balancedColor(fade, color, Color.White)
}
internal class ColorSettings {
var enabled by mutableStateOf(true)
var waveLength by mutableStateOf(30.0)
var simple by mutableStateOf(true)
var period by mutableStateOf(80.0)
}
private class State {
internal class State {
companion object {
var red by mutableStateOf(ColorSettings())
var green by mutableStateOf(ColorSettings())
var blue by mutableStateOf(ColorSettings())
var mouseUsed by mutableStateOf(false)
var entered by mutableStateOf(false)
}
}
@Composable
internal fun SettingsPanel(settings: ColorSettings, name: String) {
Row {
Text(name)
Checkbox(settings.enabled, onCheckedChange = { settings.enabled = it })
Checkbox(settings.simple, onCheckedChange = { settings.simple = it })
Slider(
(settings.waveLength.toFloat() - 10) / 90,
{ settings.waveLength = 10 + 90 * it.toDouble() },
Modifier.width(100.dp)
)
Slider(
(settings.period.toFloat() - 10) / 90,
{ settings.period = 10 + 90 * it.toDouble() },
Modifier.width(100.dp)
)
}
}

3
experimental/examples/visual-effects/shared/src/commonMain/kotlin/platform/NanoTime.kt

@ -0,0 +1,3 @@
package org.jetbrains.compose.demo.visuals.platform
expect fun nanoTime(): Long

52
experimental/examples/visual-effects/shared/src/commonMain/kotlin/platform/PointerEventKind.kt

@ -0,0 +1,52 @@
package org.jetbrains.compose.demo.visuals.platform
import androidx.compose.foundation.gestures.awaitFirstDown
import androidx.compose.foundation.gestures.forEachGesture
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.pointer.PointerEvent
import androidx.compose.ui.input.pointer.pointerInput
enum class PointerEventKind {
Move,
In,
Out
}
class Position(val x: Int, val y: Int)
expect fun Modifier.onPointerEvent(eventKind: PointerEventKind, onEvent: Position.() -> Unit): Modifier
fun Modifier.onPointerEventMobileImpl(
eventKind: PointerEventKind,
onEvent: Position.() -> Unit
): Modifier {
return this.pointerInput(Unit) {
forEachGesture {
awaitPointerEventScope {
awaitFirstDown()
if (eventKind == PointerEventKind.In) {
Position(0, 0).onEvent()
return@awaitPointerEventScope
}
do {
val event: PointerEvent = awaitPointerEvent()
if (eventKind == PointerEventKind.Move) {
Position(event.changes.first().position.x.toInt(), event.changes.first().position.y.toInt()).onEvent()
}
} while (event.changes.any { it.pressed })
if (eventKind == PointerEventKind.Out) {
Position(0, 0).onEvent()
}
}
}
}
}

0
experimental/examples/visual-effects/src/main/resources/compose-community-primary.png → experimental/examples/visual-effects/shared/src/commonMain/resources/compose-community-primary.png

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

0
experimental/examples/visual-effects/src/main/resources/compose-community-primary.svg → experimental/examples/visual-effects/shared/src/commonMain/resources/compose-community-primary.svg

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

52
experimental/examples/visual-effects/shared/src/desktopMain/kotlin/WaveSettings.kt

@ -0,0 +1,52 @@
/*
* Copyright 2020-2022 JetBrains s.r.o. and respective authors and developers.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
*/
package org.jetbrains.compose.demo.visuals
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.width
import androidx.compose.material.Checkbox
import androidx.compose.material.Slider
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
internal class ColorSettings {
var enabled by mutableStateOf(true)
var waveLength by mutableStateOf(30.0)
var simple by mutableStateOf(true)
var period by mutableStateOf(80.0)
}
internal class SettingsState {
companion object {
var red by mutableStateOf(ColorSettings())
var green by mutableStateOf(ColorSettings())
var blue by mutableStateOf(ColorSettings())
}
}
@Composable
internal fun SettingsPanel(settings: ColorSettings, name: String) {
Row {
Text(name)
Checkbox(settings.enabled, onCheckedChange = { settings.enabled = it })
Checkbox(settings.simple, onCheckedChange = { settings.simple = it })
Slider(
(settings.waveLength.toFloat() - 10) / 90,
{ settings.waveLength = 10 + 90 * it.toDouble() },
Modifier.width(100.dp)
)
Slider(
(settings.period.toFloat() - 10) / 90,
{ settings.period = 10 + 90 * it.toDouble() },
Modifier.width(100.dp)
)
}
}

59
experimental/examples/visual-effects/shared/src/desktopMain/kotlin/main.desktop.kt

@ -0,0 +1,59 @@
package org.jetbrains.compose.demo.visuals
import androidx.compose.foundation.layout.Column
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.*
fun mainWords() = singleWindowApplication(
title = "Compose Demo", state = WindowState(size = DpSize(830.dp, 830.dp))
) {
RotatingWords()
}
@Composable
fun WaveEffect(onCloseRequest: () -> Unit, showControls: Boolean) {
val windowState = remember { WindowState(width = 1200.dp, height = 800.dp) }
Window(onCloseRequest = {}, undecorated = true, transparent = true, state = windowState) {
WaveEffectGrid()
}
if (showControls) {
Window(
onCloseRequest = onCloseRequest,
state = WindowState(width = 200.dp, height = 400.dp, position = WindowPosition(1400.dp, 200.dp))
) {
Column {
SettingsPanel(SettingsState.red, "Red")
SettingsPanel(SettingsState.green, "Green")
SettingsPanel(SettingsState.blue, "Blue")
}
}
}
}
fun mainWave(controls: Boolean) = application {
WaveEffect(::exitApplication, controls)
}
@Composable
fun NYWindow(onCloseRequest: () -> Unit) {
val windowState = remember { WindowState(width = width.dp, height = height.dp) }
Window(onCloseRequest = onCloseRequest, undecorated = true, transparent = true, state = windowState) {
NYContent()
}
}
fun mainNY() = application {
NYWindow(::exitApplication)
}
fun allSamples() = application {
val windowState = remember { WindowState(width = 1200.dp, height = 900.dp) }
Window(onCloseRequest = ::exitApplication, title = "Visual effects", undecorated = false, transparent = false, state = windowState) {
AllSamplesView()
}
}

3
experimental/examples/visual-effects/shared/src/desktopMain/kotlin/platform/NanoTime.kt

@ -0,0 +1,3 @@
package org.jetbrains.compose.demo.visuals.platform
actual fun nanoTime(): Long = System.nanoTime()

23
experimental/examples/visual-effects/shared/src/desktopMain/kotlin/platform/PointerEventKind.desktop.kt

@ -0,0 +1,23 @@
package org.jetbrains.compose.demo.visuals.platform
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.pointer.PointerEventType
import androidx.compose.ui.input.pointer.onPointerEvent
@OptIn(ExperimentalComposeUiApi::class)
actual fun Modifier.onPointerEvent(
eventKind: PointerEventKind,
onEvent: Position.() -> Unit
): Modifier {
val eventType: PointerEventType = when (eventKind) {
PointerEventKind.Move -> PointerEventType.Move
PointerEventKind.In -> PointerEventType.Enter
PointerEventKind.Out -> PointerEventType.Exit
}
return this.onPointerEvent(eventType) {
Position(it.changes.first().position.x.toInt(), it.changes.first().position.y.toInt()).onEvent()
}
}

22
experimental/examples/visual-effects/shared/src/iosMain/kotlin/main.ios.kt

@ -0,0 +1,22 @@
/*
* Copyright 2020-2021 JetBrains s.r.o. and respective authors and developers.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
*/
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.height
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Application
import org.jetbrains.compose.demo.visuals.AllSamplesView
import platform.UIKit.UIViewController
fun MainViewController() : UIViewController =
Application("Visual Effects") {
Column {
// To skip upper part of screen.
Box(modifier = Modifier.height(30.dp))
AllSamplesView()
}
}

3
experimental/examples/visual-effects/shared/src/iosMain/kotlin/platform/NanoTime.kt

@ -0,0 +1,3 @@
package org.jetbrains.compose.demo.visuals.platform
actual fun nanoTime(): Long = kotlin.system.getTimeNanos()

8
experimental/examples/visual-effects/shared/src/iosMain/kotlin/platform/PointerEventKind.ios.kt

@ -0,0 +1,8 @@
package org.jetbrains.compose.demo.visuals.platform
import androidx.compose.ui.Modifier
actual fun Modifier.onPointerEvent(
eventKind: PointerEventKind,
onEvent: Position.() -> Unit
): Modifier = this.onPointerEventMobileImpl(eventKind, onEvent)

32
experimental/examples/visual-effects/src/main/kotlin/main.kt

@ -1,32 +0,0 @@
package org.jetbrains.compose.demo.visuals
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.WindowState
import androidx.compose.ui.window.application
import androidx.compose.ui.window.singleWindowApplication
fun mainWords() = singleWindowApplication(
title = "Compose Demo", state = WindowState(size = DpSize(830.dp, 830.dp))
) {
RotatingWords()
}
fun mainWave(controls: Boolean) = application {
WaveEffect(::exitApplication, controls)
}
fun mainNY() = application {
NYWindow(::exitApplication)
}
fun main(args: Array<String>) {
if (args.isEmpty()) return mainWords()
when (val effect = args[0]) {
"words" -> mainWords()
"wave" -> mainWave(false)
"wave-controls" -> mainWave(true)
"NY" -> mainNY()
else -> throw Error("Unknown effect: $effect")
}
}
Loading…
Cancel
Save