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. 71
      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. 78
      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 /captures
.externalNativeBuild .externalNativeBuild
.cxx .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"> <component name="ProjectRunConfigurationManager">
<configuration default="false" name="desktop" type="GradleRunConfiguration" factoryName="Gradle"> <configuration default="false" name="desktopApp" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings> <ExternalSystemSettings>
<option name="executionName" /> <option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="externalProjectPath" value="$PROJECT_DIR$" />
@ -10,7 +10,7 @@
</option> </option>
<option name="taskNames"> <option name="taskNames">
<list> <list>
<option value=":run" /> <option value=":desktopApp:run" />
</list> </list>
</option> </option>
<option name="vmOptions" /> <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 Several visual effects implemented with Compose Multiplatform, used in 1.0 release announce video.
* To run, launch command: `./gradlew run`
* Or choose **desktop** configuration in IDE and run it. *Prerequisites*: to run on iOS and Android, you should have "Kotlin Multiplatform Mobile" plugin installed either
![desktop-run-configuration.png](screenshots/desktop-run-configuration.png) 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>

71
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 { plugins {
kotlin("jvm") // this is necessary to avoid the plugins to be loaded multiple times
id("org.jetbrains.compose") // in each subproject's classloader
} kotlin("jvm") apply false
kotlin("multiplatform") apply false
group = "me.user" kotlin("android") apply false
version = "1.0" id("com.android.application") apply false
id("com.android.library") apply false
repositories { id("org.jetbrains.compose") apply false
mavenCentral()
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 { allprojects {
val additionalArguments = mutableListOf<String>() repositories {
google()
val runTask = tasks.named<JavaExec>("run") { mavenCentral()
this.args = additionalArguments maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
} mavenLocal()
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)
} }
} }

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 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 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 { repositories {
gradlePluginPortal() gradlePluginPortal()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
google()
} }
plugins { plugins {
kotlin("jvm").version(extra["kotlin.version"] as String) val kotlinVersion = extra["kotlin.version"] as String
id("org.jetbrains.compose").version(extra["compose.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" 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()
}
}
}
}
}

78
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 package org.jetbrains.compose.demo.visuals
import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
@ -14,12 +13,12 @@ import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.* import androidx.compose.ui.draw.*
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerMoveFilter
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.* import androidx.compose.ui.unit.em
import java.lang.Math.random import androidx.compose.ui.unit.sp
import org.jetbrains.compose.demo.visuals.platform.nanoTime
import kotlin.math.* import kotlin.math.*
import kotlin.random.Random 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!" const val HNYString = "Happy New Year!"
fun random(): Float = Random.nextFloat()
class DoubleRocket(val particle: Particle) { class DoubleRocket(val particle: Particle) {
private val STATE_ROCKET = 0 private val STATE_ROCKET = 0
private val STATE_SMALL_ROCKETS = 1 private val STATE_SMALL_ROCKETS = 1
@ -70,7 +71,7 @@ class DoubleRocket(val particle: Particle) {
} }
private fun reset() { 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 state = STATE_ROCKET
particle.x = if (particle.vx > 0) width - 0.0 else 0.0 particle.x = if (particle.vx > 0) width - 0.0 else 0.0
particle.y = 1000.0 particle.y = 1000.0
@ -109,7 +110,7 @@ class DoubleRocket(val particle: Particle) {
} }
@Composable @Composable
fun draw() { internal fun draw() {
if (state == rocket.STATE_ROCKET) { if (state == rocket.STATE_ROCKET) {
particle.draw() particle.draw()
} else { } else {
@ -162,7 +163,7 @@ class Rocket(val particle: Particle, val color: Color, val startTime: Long = 0)
} }
@Composable @Composable
fun draw() { internal fun draw() {
if (!exploded) { if (!exploded) {
particle.draw() particle.draw()
} else { } else {
@ -184,7 +185,7 @@ class Particle(var x: Double, var y: Double, var vx: Double, var vy: Double, val
} }
@Composable @Composable
fun draw() { internal fun draw() {
val alphaFactor = if (type == 0) 1.0f else 1 / (1 + abs(vy / 5)).toFloat() 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)) Box(Modifier.size(5.dp).offset(x.dp, y.dp).alpha(alphaFactor).clip(CircleShape).background(color))
for (i in 1..5) { 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)) 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>) { fun prepareStarsAndSnowFlakes(stars: SnapshotStateList<Star>, snowFlakes: SnapshotStateList<SnowFlake>) {
for (i in 0..snowCount) { for (i in 0..snowCount) {
snowFlakes.add( snowFlakes.add(
@ -237,12 +229,11 @@ fun prepareStarsAndSnowFlakes(stars: SnapshotStateList<Star>, snowFlakes: Snapsh
@OptIn(ExperimentalComposeUiApi::class) @OptIn(ExperimentalComposeUiApi::class)
@Composable @Composable
@Preview internal fun NYContent() {
fun NYContent() { var time by remember { mutableStateOf(nanoTime()) }
var time by remember { mutableStateOf(System.nanoTime()) }
var started by remember { mutableStateOf(false) } var started by remember { mutableStateOf(false) }
var startTime = remember { System.nanoTime() } var startTime = remember { nanoTime() }
var prevTime by remember { mutableStateOf(System.nanoTime()) } var prevTime by remember { mutableStateOf(nanoTime()) }
val snowFlakes = remember { mutableStateListOf<SnowFlake>() } val snowFlakes = remember { mutableStateListOf<SnowFlake>() }
val stars = remember { mutableStateListOf<Star>() } val stars = remember { mutableStateListOf<Star>() }
var flickering2 by remember { mutableStateOf(true) } var flickering2 by remember { mutableStateOf(true) }
@ -287,19 +278,23 @@ fun NYContent() {
starrySky(stars) starrySky(stars)
Text( Row(modifier = Modifier.fillMaxSize(), verticalAlignment = Alignment.Bottom, horizontalArrangement = Arrangement.Center) {
"202", Text(
Modifier.scale(10f).align(Alignment.Center).offset(-2.dp, 15.dp) fontSize = 10.em,
.alpha(if (flickering2) 0.8f else 1.0f), text = "202",
color = Color.White 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", val alpha = if (flickering2) flickeringAlpha(time) else 1.0f
Modifier.scale(10f).align(Alignment.Center).offset(14.dp, 15.dp).alpha(alpha), Text(
color = Color.White 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 if (started) { //delay to be able to start recording
//HNY //HNY
@ -309,7 +304,8 @@ fun NYContent() {
HNYString.forEach { HNYString.forEach {
val alpha = alphaHNY(i, time, startTime) val alpha = alphaHNY(i, time, startTime)
Text( Text(
it.toString(), fontSize = 14.sp,
text= it.toString(),
color = color, color = color,
modifier = Modifier.scale(5f).align(Alignment.Center).offset(0.dp, 85.dp) modifier = Modifier.scale(5f).align(Alignment.Center).offset(0.dp, 85.dp)
.rotate((angle + 5.0f * i)).offset(0.dp, -90.dp).alpha(alpha) .rotate((angle + 5.0f * i)).offset(0.dp, -90.dp).alpha(alpha)
@ -375,20 +371,20 @@ fun flickeringAlpha(time: Long): Float {
@Composable @Composable
fun starrySky(stars: SnapshotStateList<Star>) { internal fun starrySky(stars: SnapshotStateList<Star>) {
stars.forEach { stars.forEach {
star(it.x, it.y, it.color, size = it.size) star(it.x, it.y, it.color, size = it.size)
} }
} }
@Composable @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(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)) Box(Modifier.offset(x, y).scale(0.2f, 1.0f).rotate(45f).size(size).background(color))
} }
@Composable @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 val deltaAngle = (time - startTime) / 100000000
with(LocalDensity.current) { with(LocalDensity.current) {
snowFlakes.forEach { snowFlakes.forEach {
@ -404,7 +400,7 @@ fun snow(time: Long, prevTime: Long, snowFlakes: SnapshotStateList<SnowFlake>, s
} }
@Composable @Composable
fun snowFlake(modifier: Modifier, alpha: Float = 0.8f) { internal fun snowFlake(modifier: Modifier, alpha: Float = 0.8f) {
Box(modifier) { Box(modifier) {
snowFlakeInt(0, 0f, 30.dp, 0.dp, alpha) snowFlakeInt(0, 0f, 30.dp, 0.dp, alpha)
snowFlakeInt(0, 60f, 15.dp, 25.dp, alpha) snowFlakeInt(0, 60f, 15.dp, 25.dp, alpha)
@ -417,7 +413,7 @@ fun snowFlake(modifier: Modifier, alpha: Float = 0.8f) {
} }
@Composable @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 if (level > 3) return
Box( Box(
Modifier.offset(shiftX, shiftY).rotate(angle).width(100.dp).height(10.dp).scale(0.6f).alpha(1f) 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 package org.jetbrains.compose.demo.visuals
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.core.* import androidx.compose.animation.core.*
import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Text import androidx.compose.material.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip 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.draw.scale
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity 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.text.font.FontWeight
import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.WindowState import org.jetbrains.compose.resources.*
import androidx.compose.ui.window.singleWindowApplication
@OptIn(ExperimentalAnimationApi::class, ExperimentalMaterialApi::class) @OptIn(ExperimentalResourceApi::class)
@Preview
@Composable @Composable
fun Words() { internal fun Words() {
val density = LocalDensity.current val density = LocalDensity.current
val duration = 5000 val duration = 5000
@ -55,9 +46,8 @@ fun Words() {
) )
) )
val logoSvg = remember { // TODO: use vector image (.svg or .xml)
useResource("compose-community-primary.svg") { loadSvgPainter(it, density) } val logoImg = resource("compose-community-primary.png").rememberImageBitmap().orEmpty()
}
val baseLogo = DpOffset(350.dp, 270.dp) val baseLogo = DpOffset(350.dp, 270.dp)
@ -85,7 +75,7 @@ fun Words() {
alpha = 0.4f) alpha = 0.4f)
val size = 80.dp * scale val size = 80.dp * scale
Image(logoSvg, contentDescription = "Logo", Image(logoImg, contentDescription = "Logo",
modifier = Modifier modifier = Modifier
.offset(baseLogo.x - size / 2, baseLogo.y - size / 2) .offset(baseLogo.x - size / 2, baseLogo.y - size / 2)
.size(size) .size(size)
@ -95,7 +85,7 @@ fun Words() {
} }
@Composable @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) { color: Color, alpha: Float = 0.8f) {
Text( Text(
modifier = Modifier modifier = Modifier
@ -110,25 +100,24 @@ fun Word(position: DpOffset, angle: Float, scale: Float, text: String,
} }
@Composable @Composable
@Preview internal fun FallingSnow() {
fun FallingSnow() {
BoxWithConstraints(Modifier.fillMaxSize()) { BoxWithConstraints(Modifier.fillMaxSize()) {
repeat(50) { repeat(50) {
val size = remember { 20.dp + 10.dp * Math.random().toFloat() } val size = remember { 20.dp + 10.dp * random() }
val alpha = remember { 0.10f + 0.15f * Math.random().toFloat() } val alpha = remember { 0.10f + 0.15f * random() }
val sizePx = with(LocalDensity.current) { size.toPx() } 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 infiniteTransition = rememberInfiniteTransition()
val t by infiniteTransition.animateFloat( val t by infiniteTransition.animateFloat(
initialValue = 0f, initialValue = 0f,
targetValue = 1f, targetValue = 1f,
animationSpec = infiniteRepeatable( animationSpec = infiniteRepeatable(
animation = tween(16000 + (16000 * Math.random()).toInt(), easing = LinearEasing), animation = tween(16000 + (16000 * random()).toInt(), easing = LinearEasing),
repeatMode = RepeatMode.Restart repeatMode = RepeatMode.Restart
) )
) )
val initialT = remember { Math.random().toFloat() } val initialT = remember { random() }
val actualT = (initialT + t) % 1f val actualT = (initialT + t) % 1f
val y = (-sizePx + (constraints.maxHeight + sizePx) * actualT).toInt() val y = (-sizePx + (constraints.maxHeight + sizePx) * actualT).toInt()
@ -146,16 +135,14 @@ fun FallingSnow() {
} }
@Composable @Composable
@Preview internal fun Background() = Box(
fun Background() = Box(
Modifier Modifier
.fillMaxSize() .fillMaxSize()
.background(Color(0xFF6F97FF)) .background(Color(0xFF6F97FF))
) )
@Composable @Composable
@Preview internal fun RotatingWords() {
fun RotatingWords() {
Background() Background()
FallingSnow() FallingSnow()
Words() 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 package org.jetbrains.compose.demo.visuals
import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
@ -10,41 +9,16 @@ import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.* import androidx.compose.ui.draw.*
import androidx.compose.ui.graphics.Color 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.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Window import org.jetbrains.compose.demo.visuals.platform.PointerEventKind
import androidx.compose.ui.window.WindowPosition import org.jetbrains.compose.demo.visuals.platform.nanoTime
import androidx.compose.ui.window.WindowState import org.jetbrains.compose.demo.visuals.platform.onPointerEvent
import kotlin.math.* 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) @OptIn(ExperimentalComposeUiApi::class)
@Composable @Composable
@Preview internal fun WaveEffectGrid() {
fun Grid() {
var mouseX by remember { mutableStateOf(0) } var mouseX by remember { mutableStateOf(0) }
var mouseY by remember { mutableStateOf(0) } var mouseY by remember { mutableStateOf(0) }
var centerX by remember { mutableStateOf(1200) } var centerX by remember { mutableStateOf(1200) }
@ -52,10 +26,10 @@ fun Grid() {
var vX by remember { mutableStateOf(0) } var vX by remember { mutableStateOf(0) }
var vY by remember { mutableStateOf(0) } var vY by remember { mutableStateOf(0) }
var time by remember { mutableStateOf(System.nanoTime()) } var time by remember { mutableStateOf(nanoTime()) }
var prevTime by remember { mutableStateOf(System.nanoTime()) } var prevTime by remember { mutableStateOf(nanoTime()) }
if (State.mouseUsed) { if (State.entered) {
centerX = (centerX + vX * (time - prevTime) / 1000000000).toInt() centerX = (centerX + vX * (time - prevTime) / 1000000000).toInt()
if (centerX < -100) centerX = -100 if (centerX < -100) centerX = -100
if (centerX > 2600) centerX = 2600 if (centerX > 2600) centerX = 2600
@ -72,16 +46,17 @@ fun Grid() {
Surface( Surface(
modifier = Modifier.fillMaxSize().padding(5.dp).shadow(3.dp, RoundedCornerShape(20.dp)) modifier = Modifier.fillMaxSize().padding(5.dp).shadow(3.dp, RoundedCornerShape(20.dp))
.onPointerEvent(PointerEventType.Move) { .onPointerEvent(PointerEventKind.Move) {
mouseX = it.changes.first().position.x.toInt() mouseX = x
mouseY = it.changes.first().position.y.toInt() mouseY = y
} }
.onPointerEvent(PointerEventType.Enter) { .onPointerEvent(PointerEventKind.In) {
State.mouseUsed = true State.entered = true
} }
.onPointerEvent(PointerEventType.Exit) { .onPointerEvent(PointerEventKind.Out) {
State.mouseUsed = false State.entered = false
}, }
,
color = Color(0, 0, 0), color = Color(0, 0, 0),
shape = RoundedCornerShape(20.dp) shape = RoundedCornerShape(20.dp)
) { ) {
@ -118,7 +93,7 @@ fun Grid() {
} }
@Composable @Composable
fun HighPanel(mouseX: Int, mouseY: Int) { internal fun HighPanel(mouseX: Int, mouseY: Int) {
Text( Text(
"Compose", "Compose",
Modifier.offset(270.dp, 600.dp).scale(7.0f).alpha(alpha(mouseX, mouseY, 270, 700)), 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( Text(
"1.0", "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), color = colorMouse(mouseX, mouseY, 800, 800),
fontWeight = FontWeight.Bold fontWeight = FontWeight.Bold
) )
@ -173,7 +148,7 @@ private fun distance(x1: Int, y1: Int, x2: Int, y2: Int): Double {
} }
@Composable @Composable
fun Dot(size: Int, modifier: Modifier, color: Color, time: Long) { internal fun Dot(size: Int, modifier: Modifier, color: Color, time: Long) {
Box( Box(
modifier.rotate(time.toFloat() / (15 * 10000000)).clip(RoundedCornerShape((3 + size / 20).dp)) modifier.rotate(time.toFloat() / (15 * 10000000)).clip(RoundedCornerShape((3 + size / 20).dp))
.size(width = size.dp, height = size.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) { val scale: Double = (if (distance2 < 1) {
addSize * (1 - distance2) addSize * (1 - distance2)
} else 0.toDouble()) } 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 return result
} }
private fun boxColor(x: Int, y: Int, time: Long, mouseX: Int, mouseY: Int): Color { 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 color1 = Color(0x6B, 0x57, 0xFF)
val color2 = Color(0xFE, 0x28, 0x57) 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) return balancedColor(fade, color, Color.White)
} }
internal class ColorSettings { internal class State {
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 {
companion object { companion object {
var red by mutableStateOf(ColorSettings()) var entered by mutableStateOf(false)
var green by mutableStateOf(ColorSettings())
var blue by mutableStateOf(ColorSettings())
var mouseUsed 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