Browse Source

Graphics2D example (#3770)

COMPOSE-357

- Merged non UI examples visual-effects, falling-balls and minesweeper
into one graphics2d
 - Removed deprecated function calls `kotlin.system.getTimeNanos()`
 - Little bit simplifyed code
 - Used Material3

Co-authored-by: Igor Demin <igordmn@users.noreply.github.com>
pull/3798/head
dima.avdeev 1 year ago committed by GitHub
parent
commit
d7a82a4732
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      examples/README.md
  2. 21
      examples/falling-balls/README.md
  3. 3
      examples/falling-balls/androidApp/src/androidMain/res/values/strings.xml
  4. 19
      examples/falling-balls/desktopApp/src/jvmMain/kotlin/Main.kt
  5. 3
      examples/falling-balls/iosApp/Configuration/Config.xcconfig
  6. 15
      examples/falling-balls/jsApp/src/jsMain/kotlin/main.js.kt
  7. 32
      examples/falling-balls/jsApp/src/jsMain/resources/index.html
  8. 32
      examples/falling-balls/settings.gradle.kts
  9. 125
      examples/falling-balls/shared/build.gradle.kts
  10. 12
      examples/falling-balls/shared/src/androidMain/kotlin/main.android.kt
  11. 24
      examples/falling-balls/shared/src/desktopMain/kotlin/main.desktop.kt
  12. 19
      examples/falling-balls/shared/src/iosMain/kotlin/main.ios.kt
  13. 65
      examples/falling-balls/shared/src/jsMain/kotlin/main.js.kt
  14. 23
      examples/falling-balls/shared/src/macosMain/kotlin/main.macos.kt
  15. 0
      examples/graphics-2d/.gitignore
  16. 0
      examples/graphics-2d/.run/desktopApp.run.xml
  17. 24
      examples/graphics-2d/README.md
  18. 4
      examples/graphics-2d/androidApp/build.gradle.kts
  19. 0
      examples/graphics-2d/androidApp/src/androidMain/AndroidManifest.xml
  20. 2
      examples/graphics-2d/androidApp/src/androidMain/kotlin/org/jetbrains/graphics2d/MainActivity.kt
  21. 3
      examples/graphics-2d/androidApp/src/androidMain/res/values/strings.xml
  22. 0
      examples/graphics-2d/apple-id.png
  23. 0
      examples/graphics-2d/build.gradle.kts
  24. 2
      examples/graphics-2d/desktopApp/build.gradle.kts
  25. 30
      examples/graphics-2d/desktopApp/src/jvmMain/kotlin/Main.kt
  26. 0
      examples/graphics-2d/gradle.properties
  27. 0
      examples/graphics-2d/gradle/wrapper/gradle-wrapper.jar
  28. 0
      examples/graphics-2d/gradle/wrapper/gradle-wrapper.properties
  29. 0
      examples/graphics-2d/gradlew
  30. 0
      examples/graphics-2d/gradlew.bat
  31. 0
      examples/graphics-2d/ios-app.png
  32. 3
      examples/graphics-2d/iosApp/Configuration/Config.xcconfig
  33. 6
      examples/graphics-2d/iosApp/iosApp.xcodeproj/project.pbxproj
  34. 0
      examples/graphics-2d/iosApp/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json
  35. 0
      examples/graphics-2d/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json
  36. 0
      examples/graphics-2d/iosApp/iosApp/Assets.xcassets/Contents.json
  37. 2
      examples/graphics-2d/iosApp/iosApp/ContentView.swift
  38. 0
      examples/graphics-2d/iosApp/iosApp/Info.plist
  39. 0
      examples/graphics-2d/iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json
  40. 0
      examples/graphics-2d/iosApp/iosApp/iOSApp.swift
  41. 0
      examples/graphics-2d/jsApp/build.gradle.kts
  42. 10
      examples/graphics-2d/jsApp/src/jsMain/kotlin/main.js.kt
  43. 0
      examples/graphics-2d/jsApp/src/jsMain/resources/assets/clock.png
  44. 0
      examples/graphics-2d/jsApp/src/jsMain/resources/assets/flag.png
  45. 0
      examples/graphics-2d/jsApp/src/jsMain/resources/assets/mine.png
  46. 0
      examples/graphics-2d/jsApp/src/jsMain/resources/compose-community-primary.xml
  47. 16
      examples/graphics-2d/jsApp/src/jsMain/resources/index.html
  48. 0
      examples/graphics-2d/jsApp/src/jsMain/resources/styles.css
  49. 0
      examples/graphics-2d/run-configurations.png
  50. 2
      examples/graphics-2d/settings.gradle.kts
  51. 9
      examples/graphics-2d/shared/build.gradle.kts
  52. 0
      examples/graphics-2d/shared/src/androidMain/AndroidManifest.xml
  53. 6
      examples/graphics-2d/shared/src/androidMain/kotlin/main.android.kt
  54. 3
      examples/graphics-2d/shared/src/androidMain/kotlin/minesweeper/MineSweeper.android.kt
  55. 2
      examples/graphics-2d/shared/src/androidMain/kotlin/platform/PointerEventKind.android.kt
  56. 110
      examples/graphics-2d/shared/src/commonMain/kotlin/Graphics2D.kt
  57. 32
      examples/graphics-2d/shared/src/commonMain/kotlin/bouncingballs/BouncingBalls.kt
  58. 48
      examples/graphics-2d/shared/src/commonMain/kotlin/fallingballs/FallingBalls.common.kt
  59. 43
      examples/graphics-2d/shared/src/commonMain/kotlin/fallingballs/Game.kt
  60. 5
      examples/graphics-2d/shared/src/commonMain/kotlin/fallingballs/Piece.kt
  61. 2
      examples/graphics-2d/shared/src/commonMain/kotlin/minesweeper/BoardView.kt
  62. 16
      examples/graphics-2d/shared/src/commonMain/kotlin/minesweeper/GameController.kt
  63. 2
      examples/graphics-2d/shared/src/commonMain/kotlin/minesweeper/GameInteraction.kt
  64. 13
      examples/graphics-2d/shared/src/commonMain/kotlin/minesweeper/MineSweeper.common.kt
  65. 4
      examples/graphics-2d/shared/src/commonMain/kotlin/minesweeper/Widgets.kt
  66. 200
      examples/graphics-2d/shared/src/commonMain/kotlin/visualeffects/HappyNY.kt
  67. 14
      examples/graphics-2d/shared/src/commonMain/kotlin/visualeffects/PointerEvent.common.kt
  68. 26
      examples/graphics-2d/shared/src/commonMain/kotlin/visualeffects/RotatingWords.kt
  69. 41
      examples/graphics-2d/shared/src/commonMain/kotlin/visualeffects/WaveEffect.kt
  70. 0
      examples/graphics-2d/shared/src/commonMain/resources/assets/clock.png
  71. 0
      examples/graphics-2d/shared/src/commonMain/resources/assets/flag.png
  72. 0
      examples/graphics-2d/shared/src/commonMain/resources/assets/mine.png
  73. 36
      examples/graphics-2d/shared/src/commonMain/resources/compose-community-primary.xml
  74. 2
      examples/graphics-2d/shared/src/commonTest/kotlin/minesweeper/GameControllerTest.kt
  75. 3
      examples/graphics-2d/shared/src/desktopMain/kotlin/minesweeper/MineSweeper.desktop.kt
  76. 2
      examples/graphics-2d/shared/src/desktopMain/kotlin/visualeffects/PointerEvent.desktop.kt
  77. 6
      examples/graphics-2d/shared/src/iosMain/kotlin/main.ios.kt
  78. 3
      examples/graphics-2d/shared/src/iosMain/kotlin/minesweeper/MineSweeper.ios.kt
  79. 2
      examples/graphics-2d/shared/src/iosMain/kotlin/visualeffects/PointerEvent.ios.kt
  80. 6
      examples/graphics-2d/shared/src/jsMain/kotlin/main.js.kt
  81. 3
      examples/graphics-2d/shared/src/jsMain/kotlin/minesweeper/MineSweeepr.js.kt
  82. 26
      examples/graphics-2d/shared/src/jsMain/kotlin/visualeffects/PointerEvent.js.kt
  83. 11
      examples/graphics-2d/shared/src/macosMain/kotlin/main.macos.kt
  84. 3
      examples/graphics-2d/shared/src/macosMain/kotlin/minesweeper/MineSweeper.macos.kt
  85. 27
      examples/graphics-2d/shared/src/macosMain/kotlin/visualeffects/PointerEventKind.macos.kt
  86. 7
      examples/minesweeper/.gitignore
  87. 28
      examples/minesweeper/.run/desktopApp.run.xml
  88. 25
      examples/minesweeper/README.md
  89. 35
      examples/minesweeper/androidApp/build.gradle.kts
  90. 21
      examples/minesweeper/androidApp/src/androidMain/AndroidManifest.xml
  91. 15
      examples/minesweeper/androidApp/src/androidMain/kotlin/MainActivity.kt
  92. 3
      examples/minesweeper/androidApp/src/androidMain/res/values/strings.xml
  93. 18
      examples/minesweeper/build.gradle.kts
  94. 35
      examples/minesweeper/desktopApp/build.gradle.kts
  95. 22
      examples/minesweeper/desktopApp/src/jvmMain/kotlin/Main.kt
  96. 19
      examples/minesweeper/gradle.properties
  97. BIN
      examples/minesweeper/gradle/wrapper/gradle-wrapper.jar
  98. 5
      examples/minesweeper/gradle/wrapper/gradle-wrapper.properties
  99. 240
      examples/minesweeper/gradlew
  100. 91
      examples/minesweeper/gradlew.bat
  101. Some files were not shown because too many files have changed in this diff Show More

4
examples/README.md

@ -4,9 +4,7 @@
| [Imageviewer](imageviewer) | Image Viewer application | Android, iOS, Desktop |
| [Codeviewer](codeviewer) | File browser and code viewer application | Android, iOS, Desktop |
| [Chat](chat) | A simple chat | Android, iOS, Desktop |
| [Minesweeper](minesweeper) | A simple game where you need to find hidden mines | Android, iOS, Desktop |
| [Falling Balls](falling-balls) | A simple game | Android, iOS, Desktop |
| [Visual effects](visual-effects) | Visual effects | Android, iOS, Desktop |
| [Graphics2D](graphics-2d) | 2D Games and graphics examples | Android, iOS, Desktop |
| [Widgets Gallery](widgets-gallery) | Gallery of standard widgets | Android, iOS, Desktop |
| [Todoapp Lite](todoapp-lite) | A simple todo app fully based on Compose | Android, iOS, Desktop |
| [Issues tracker](issues) | GitHub issue tracker with an adaptive UI and ktor-client | Android, Desktop |

21
examples/falling-balls/README.md

@ -1,21 +0,0 @@
# Falling Balls game
Game can run on Android, iOS, desktop or in a browser.
## Setting up your development environment
To setup the environment, please consult these [instructions](https://github.com/JetBrains/compose-multiplatform-template#setting-up-your-development-environment).
## How to run
Choose a run configuration for an appropriate target in Android Studio and run it.
![run-configurations.png](run-configurations.png)
## Run on desktop via Gradle
`./gradlew desktopApp:run`
## Run native on MacOS
Choose **shared[macosX64]** or **shared[macosArm64]** configuration in IDE and run it.

3
examples/falling-balls/androidApp/src/androidMain/res/values/strings.xml

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

19
examples/falling-balls/desktopApp/src/jvmMain/kotlin/Main.kt

@ -1,19 +0,0 @@
/*
* 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.ui.ExperimentalComposeUiApi
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.WindowState
import androidx.compose.ui.window.singleWindowApplication
@OptIn(ExperimentalComposeUiApi::class)
fun main() =
singleWindowApplication(
title = "Falling Balls",
state = WindowState(size = DpSize(800.dp, 800.dp))
) {
MainView()
}

3
examples/falling-balls/iosApp/Configuration/Config.xcconfig

@ -1,3 +0,0 @@
TEAM_ID=
BUNDLE_ID=org.jetbrains.FallingBalls
APP_NAME=FallingBalls

15
examples/falling-balls/jsApp/src/jsMain/kotlin/main.js.kt

@ -1,15 +0,0 @@
/*
* 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.ui.window.Window
import org.jetbrains.skiko.wasm.onWasmReady
fun main() {
onWasmReady {
Window("Falling Balls") {
MainView()
}
}
}

32
examples/falling-balls/jsApp/src/jsMain/resources/index.html

@ -1,32 +0,0 @@
<!--
~ Copyright 2021 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>compose multiplatform web demo</title>
<script src="skiko.js"> </script>
<link type="text/css" rel="stylesheet" href="styles.css" />
</head>
<body>
<h1>compose multiplatform web demo</h1>
<div>
<canvas id="ComposeTarget" width="800" height="600"></canvas>
</div>
<script src="jsApp.js"> </script>
</body>
</html>

32
examples/falling-balls/settings.gradle.kts

@ -1,32 +0,0 @@
pluginManagement {
repositories {
gradlePluginPortal()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
google()
}
plugins {
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)
}
}
plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version("0.4.0")
}
rootProject.name = "falling-balls-mpp"
include(":androidApp")
include(":shared")
include(":desktopApp")
include(":jsApp")

125
examples/falling-balls/shared/build.gradle.kts

@ -1,125 +0,0 @@
@file:Suppress("OPT_IN_IS_NOT_ENABLED")
import org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler
plugins {
kotlin("multiplatform")
id("com.android.library")
id("org.jetbrains.compose")
}
version = "1.0-SNAPSHOT"
kotlin {
androidTarget()
jvm("desktop")
js(IR) {
browser()
}
macosX64 {
binaries {
executable {
entryPoint = "main"
}
}
}
macosArm64 {
binaries {
executable {
entryPoint = "main"
}
}
}
listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
).forEach { iosTarget ->
iosTarget.binaries.framework {
baseName = "shared"
isStatic = true
}
}
val enableKjsWorkaround = project.properties["workaround.kotlin.js.kt60852"] == "true"
fun KotlinDependencyHandler.addCommonDependencies() {
implementation(compose.ui)
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material)
@OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class)
implementation(compose.components.resources)
}
sourceSets {
val commonMain by getting {
dependencies {
if (!enableKjsWorkaround) {
addCommonDependencies()
}
}
}
val androidMain by getting {
dependencies {
api("androidx.activity:activity-compose:1.7.2")
api("androidx.appcompat:appcompat:1.6.1")
api("androidx.core:core-ktx:1.10.1")
}
}
val iosMain by creating {
dependsOn(commonMain)
}
val iosX64Main by getting {
dependsOn(iosMain)
}
val iosArm64Main by getting {
dependsOn(iosMain)
}
val iosSimulatorArm64Main by getting {
dependsOn(iosMain)
}
val desktopMain by getting {
dependencies {
implementation(compose.desktop.common)
}
}
val macosMain by creating {
dependsOn(commonMain)
}
val macosArm64Main by getting {
dependsOn(macosMain)
}
val jsMain by getting {
dependencies {
if (enableKjsWorkaround) {
addCommonDependencies()
}
}
}
}
}
android {
compileSdk = 34
namespace = "org.jetbrains.fallingballs"
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
sourceSets["main"].res.srcDirs("src/androidMain/res")
sourceSets["main"].resources.srcDirs("src/commonMain/resources")
defaultConfig {
minSdk = 26
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlin {
jvmToolchain(17)
}
}

12
examples/falling-balls/shared/src/androidMain/kotlin/main.android.kt

@ -1,12 +0,0 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
object AndroidTime : Time {
override fun now(): Long = System.nanoTime()
}
@Composable
fun MainView() {
val game = remember { Game(AndroidTime) }
FallingBalls(game)
}

24
examples/falling-balls/shared/src/desktopMain/kotlin/main.desktop.kt

@ -1,24 +0,0 @@
/*
* 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.desktop.ui.tooling.preview.Preview
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
object JvmTime : Time {
override fun now(): Long = System.nanoTime()
}
@Composable
fun MainView() {
val game = remember { Game(JvmTime) }
FallingBalls(game)
}
@Preview
@Composable
fun GamePreview() {
MainView()
}

19
examples/falling-balls/shared/src/iosMain/kotlin/main.ios.kt

@ -1,19 +0,0 @@
/*
* 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.runtime.remember
import androidx.compose.ui.window.ComposeUIViewController
import platform.UIKit.UIViewController
object IosTime : Time {
override fun now(): Long = kotlin.system.getTimeNanos()
}
fun MainViewController() : UIViewController = ComposeUIViewController {
val game = remember { Game(IosTime) }
FallingBalls(game)
}

65
examples/falling-balls/shared/src/jsMain/kotlin/main.js.kt

@ -1,65 +0,0 @@
/*
* 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.*
import androidx.compose.material.RadioButton
import androidx.compose.material.Text
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
import bouncingBalls.BouncingBallsApp
object JsTime : Time {
override fun now(): Long = kotlinx.browser.window.performance.now().toLong()
}
@Composable
fun MainView() {
val selectedExample = remember { mutableStateOf(Examples.FallingBalls) }
Column(modifier = Modifier.fillMaxSize()) {
ExamplesChooser(selectedExample)
Spacer(modifier = Modifier.height(24.dp))
when (selectedExample.value) {
Examples.FallingBalls -> {
val game = remember { Game(JsTime) }
FallingBalls(game)
}
Examples.BouncingBalls -> {
BouncingBallsApp(10)
}
}
}
}
@Composable
private fun ExamplesChooser(selected: MutableState<Examples>) {
Column {
Row(verticalAlignment = Alignment.CenterVertically) {
Text("Choose an example: ", fontSize = 16.sp)
Examples.values().forEach {
Row(verticalAlignment = Alignment.CenterVertically) {
RadioButton(selected = selected.value == it, onClick = {
selected.value = it
})
Text(it.name)
}
}
}
}
}
private enum class Examples {
FallingBalls,
BouncingBalls
}

23
examples/falling-balls/shared/src/macosMain/kotlin/main.macos.kt

@ -1,23 +0,0 @@
/*
* 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.ui.window.Window
import androidx.compose.runtime.remember
import androidx.compose.ui.unit.dp
import platform.AppKit.NSApp
import platform.AppKit.NSApplication
object MacosTime : Time {
override fun now(): Long = kotlin.system.getTimeNanos()
}
fun main() {
NSApplication.sharedApplication()
Window("Falling Balls") {
val game = remember { Game(MacosTime) }
FallingBalls(game)
}
NSApp?.run()
}

0
examples/falling-balls/.gitignore → examples/graphics-2d/.gitignore vendored

0
examples/falling-balls/.run/desktopApp.run.xml → examples/graphics-2d/.run/desktopApp.run.xml

24
examples/graphics-2d/README.md

@ -0,0 +1,24 @@
# Graphics2D
Example can run on Android, iOS, desktop or in a browser.
## Setting up your development environment
To setup the environment, please consult
these [instructions](https://github.com/JetBrains/compose-multiplatform-template#setting-up-your-development-environment).
## How to run
Choose a run configuration for an appropriate target in Android Studio and run it.
![run-configurations.png](run-configurations.png)
## Run on desktop via Gradle
`./gradlew desktopApp:run`
## Run experimental native on MacOS
`./gradlew runDebugExecutableMacosX64` (Works on Intel processors)
`./gradlew runDebugExecutableMacosArm64` (Works on Arm processors)

4
examples/falling-balls/androidApp/build.gradle.kts → examples/graphics-2d/androidApp/build.gradle.kts

@ -17,9 +17,9 @@ kotlin {
android {
compileSdk = 34
namespace = "org.jetbrains.fallingballs"
namespace = "org.jetbrains.graphics2d"
defaultConfig {
applicationId = "org.jetbrains.FallingBalls"
applicationId = "org.jetbrains.Graphics2D"
minSdk = 26
targetSdk = 34
versionCode = 1

0
examples/falling-balls/androidApp/src/androidMain/AndroidManifest.xml → examples/graphics-2d/androidApp/src/androidMain/AndroidManifest.xml

2
examples/falling-balls/androidApp/src/androidMain/kotlin/org/jetbrains/fallingballs/MainActivity.kt → examples/graphics-2d/androidApp/src/androidMain/kotlin/org/jetbrains/graphics2d/MainActivity.kt

@ -1,4 +1,4 @@
package org.jetbrains.fallingballs
package org.jetbrains.graphics2d
import MainView
import android.os.Bundle

3
examples/graphics-2d/androidApp/src/androidMain/res/values/strings.xml

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

0
examples/falling-balls/apple-id.png → examples/graphics-2d/apple-id.png

Before

Width:  |  Height:  |  Size: 213 KiB

After

Width:  |  Height:  |  Size: 213 KiB

0
examples/falling-balls/build.gradle.kts → examples/graphics-2d/build.gradle.kts

2
examples/falling-balls/desktopApp/build.gradle.kts → examples/graphics-2d/desktopApp/build.gradle.kts

@ -23,7 +23,7 @@ compose.desktop {
nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "Falling Balls"
packageName = "Graphics2D"
packageVersion = "1.0.0"
windows {

30
examples/graphics-2d/desktopApp/src/jvmMain/kotlin/Main.kt

@ -0,0 +1,30 @@
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.coerceIn
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
import androidx.compose.ui.window.rememberWindowState
private val INIT_SIZE = DpSize(800.dp, 800.dp)
fun main() =
application {
val windowState = rememberWindowState(width = 800.dp, height = 800.dp)
Window(
onCloseRequest = ::exitApplication,
resizable = false,
title = "Graphics2D",
state = windowState,
) {
Graphics2D(
requestWindowSize = { w, h ->
windowState.size = windowState.size.copy(
width = w.coerceIn(INIT_SIZE.width, Float.MAX_VALUE.dp),
height = h.coerceIn(INIT_SIZE.height, Float.MAX_VALUE.dp)
)
}
)
}
}

0
examples/falling-balls/gradle.properties → examples/graphics-2d/gradle.properties

0
examples/falling-balls/gradle/wrapper/gradle-wrapper.jar → examples/graphics-2d/gradle/wrapper/gradle-wrapper.jar vendored

0
examples/falling-balls/gradle/wrapper/gradle-wrapper.properties → examples/graphics-2d/gradle/wrapper/gradle-wrapper.properties vendored

0
examples/falling-balls/gradlew → examples/graphics-2d/gradlew vendored

0
examples/falling-balls/gradlew.bat → examples/graphics-2d/gradlew.bat vendored

0
examples/falling-balls/ios-app.png → examples/graphics-2d/ios-app.png

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

3
examples/graphics-2d/iosApp/Configuration/Config.xcconfig

@ -0,0 +1,3 @@
TEAM_ID=
BUNDLE_ID=org.jetbrains.Graphics2D
APP_NAME=Graphics2D

6
examples/falling-balls/iosApp/iosApp.xcodeproj/project.pbxproj → examples/graphics-2d/iosApp/iosApp.xcodeproj/project.pbxproj

@ -17,7 +17,7 @@
058557BA273AAA24004C7B11 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
2152FB032600AC8F00CF470E /* iOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOSApp.swift; sourceTree = "<group>"; };
7555FF7B242A565900829871 /* FallingBalls.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FallingBalls.app; sourceTree = BUILT_PRODUCTS_DIR; };
7555FF7B242A565900829871 /* Graphics2D.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Graphics2D.app; sourceTree = BUILT_PRODUCTS_DIR; };
7555FF82242A565900829871 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
7555FF8C242A565B00829871 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
AB3632DC29227652001CCB65 /* Config.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; };
@ -54,7 +54,7 @@
7555FF7C242A565900829871 /* Products */ = {
isa = PBXGroup;
children = (
7555FF7B242A565900829871 /* FallingBalls.app */,
7555FF7B242A565900829871 /* Graphics2D.app */,
);
name = Products;
sourceTree = "<group>";
@ -97,7 +97,7 @@
);
name = iosApp;
productName = iosApp;
productReference = 7555FF7B242A565900829871 /* FallingBalls.app */;
productReference = 7555FF7B242A565900829871 /* Graphics2D.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */

0
examples/falling-balls/iosApp/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json → examples/graphics-2d/iosApp/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json

0
examples/falling-balls/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json → examples/graphics-2d/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json

0
examples/falling-balls/iosApp/iosApp/Assets.xcassets/Contents.json → examples/graphics-2d/iosApp/iosApp/Assets.xcassets/Contents.json

2
examples/falling-balls/iosApp/iosApp/ContentView.swift → examples/graphics-2d/iosApp/iosApp/ContentView.swift

@ -5,7 +5,7 @@ import shared
struct ContentView: View {
var body: some View {
ComposeView()
.ignoresSafeArea(.keyboard) // Compose has own keyboard handler
.ignoresSafeArea(.all) // Compose has own keyboard handler
}
}

0
examples/falling-balls/iosApp/iosApp/Info.plist → examples/graphics-2d/iosApp/iosApp/Info.plist

0
examples/falling-balls/iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json → examples/graphics-2d/iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json

0
examples/falling-balls/iosApp/iosApp/iOSApp.swift → examples/graphics-2d/iosApp/iosApp/iOSApp.swift

0
examples/falling-balls/jsApp/build.gradle.kts → examples/graphics-2d/jsApp/build.gradle.kts

10
examples/graphics-2d/jsApp/src/jsMain/kotlin/main.js.kt

@ -0,0 +1,10 @@
import androidx.compose.ui.window.Window
import org.jetbrains.skiko.wasm.onWasmReady
fun main() {
onWasmReady {
Window("Graphics2D") {
MainView()
}
}
}

0
examples/minesweeper/jsApp/src/jsMain/resources/assets/clock.png → examples/graphics-2d/jsApp/src/jsMain/resources/assets/clock.png

Before

Width:  |  Height:  |  Size: 896 B

After

Width:  |  Height:  |  Size: 896 B

0
examples/minesweeper/jsApp/src/jsMain/resources/assets/flag.png → examples/graphics-2d/jsApp/src/jsMain/resources/assets/flag.png

Before

Width:  |  Height:  |  Size: 780 B

After

Width:  |  Height:  |  Size: 780 B

0
examples/minesweeper/jsApp/src/jsMain/resources/assets/mine.png → examples/graphics-2d/jsApp/src/jsMain/resources/assets/mine.png

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

0
examples/visual-effects/shared/src/commonMain/resources/compose-community-primary.xml → examples/graphics-2d/jsApp/src/jsMain/resources/compose-community-primary.xml

16
examples/graphics-2d/jsApp/src/jsMain/resources/index.html

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>compose multiplatform web demo</title>
<script src="skiko.js"> </script>
<link type="text/css" rel="stylesheet" href="styles.css" />
</head>
<body>
<h1>compose multiplatform web demo</h1>
<div>
<canvas id="ComposeTarget" width="800" height="600"></canvas>
</div>
<script src="jsApp.js"> </script>
</body>
</html>

0
examples/falling-balls/jsApp/src/jsMain/resources/styles.css → examples/graphics-2d/jsApp/src/jsMain/resources/styles.css

0
examples/falling-balls/run-configurations.png → examples/graphics-2d/run-configurations.png

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

2
examples/minesweeper/settings.gradle.kts → examples/graphics-2d/settings.gradle.kts

@ -24,7 +24,7 @@ plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version("0.4.0")
}
rootProject.name = "minesweeper"
rootProject.name = "graphics-2d"
include(":androidApp")
include(":shared")

9
examples/minesweeper/shared/build.gradle.kts → examples/graphics-2d/shared/build.gradle.kts

@ -15,7 +15,6 @@ kotlin {
androidTarget()
jvm("desktop")
js(IR) {
browser()
}
@ -52,7 +51,7 @@ kotlin {
implementation(compose.ui)
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material)
implementation(compose.material3)
@OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class)
implementation(compose.components.resources)
}
@ -95,13 +94,9 @@ kotlin {
implementation(compose.desktop.common)
}
}
val macosMain by creating {
dependsOn(commonMain)
}
val macosX64Main by getting {
dependsOn(macosMain)
}
val macosArm64Main by getting {
dependsOn(macosMain)
}
@ -117,7 +112,7 @@ kotlin {
android {
compileSdk = 34
namespace = "org.jetbrains.minesweeper"
namespace = "org.jetbrains.Graphics2D"
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
sourceSets["main"].res.srcDirs("src/androidMain/res")
sourceSets["main"].resources.srcDirs("src/commonMain/resources")

0
examples/falling-balls/shared/src/androidMain/AndroidManifest.xml → examples/graphics-2d/shared/src/androidMain/AndroidManifest.xml

6
examples/graphics-2d/shared/src/androidMain/kotlin/main.android.kt

@ -0,0 +1,6 @@
import androidx.compose.runtime.Composable
@Composable
fun MainView() {
Graphics2D()
}

3
examples/graphics-2d/shared/src/androidMain/kotlin/minesweeper/MineSweeper.android.kt

@ -0,0 +1,3 @@
package minesweeper
actual fun hasRightClick() = false

2
examples/visual-effects/shared/src/androidMain/kotlin/platform/PointerEventKind.android.kt → examples/graphics-2d/shared/src/androidMain/kotlin/platform/PointerEventKind.android.kt

@ -1,4 +1,4 @@
package org.jetbrains.compose.demo.visuals.platform
package visualeffects
import androidx.compose.ui.Modifier

110
examples/graphics-2d/shared/src/commonMain/kotlin/Graphics2D.kt

@ -0,0 +1,110 @@
import androidx.compose.foundation.clickable
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import bouncingballs.BouncingBallsApp
import fallingballs.FallingBalls
import minesweeper.MineSweeper
import visualeffects.NYContent
import visualeffects.RotatingWords
import visualeffects.WaveEffectGrid
private val TOP_APP_BAR_HEIGHT = 100.dp
private val EMPTY_WINDOW_RESIZER: (width: Dp, height: Dp) -> Unit = { w, h -> }
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun Graphics2D(requestWindowSize: ((width: Dp, height: Dp) -> Unit) = EMPTY_WINDOW_RESIZER) {
val exampleState: MutableState<Example?> = remember { mutableStateOf(null) }
val example = exampleState.value
MaterialTheme(
colorScheme = if (isSystemInDarkTheme()) darkColorScheme() else lightColorScheme()
) {
Scaffold(
topBar = {
TopAppBar(
navigationIcon = {
if (example != null) {
Icon(
imageVector = Icons.Default.ArrowBack,
contentDescription = "Back",
modifier = Modifier.clickable {
exampleState.value = null
}
)
}
},
title = {
Text(example?.name ?: "Choose example")
}
)
}
) {
Box(Modifier.padding(it)) {
if (example == null) {
LazyColumn(Modifier.padding(horizontal = 16.dp)) {
items(examples) {
Button(onClick = {
exampleState.value = it
}) {
Text(it.name)
}
}
}
} else {
example.content { w, h ->
requestWindowSize(w, h + TOP_APP_BAR_HEIGHT)
}
}
}
}
}
}
private class Example(
val name: String,
val content: @Composable (requestWindowSize: ((width: Dp, height: Dp) -> Unit)) -> Unit
)
private val examples: List<Example> = listOf(
Example("FallingBalls") {
FallingBalls()
},
Example("BouncingBalls") {
BouncingBallsApp()
},
Example("MineSweeper") {
MineSweeper(it)
},
Example("RotatingWords") {
RotatingWords()
},
Example("WaveEffectGrid") {
WaveEffectGrid()
},
Example("Happy New Year!") {
NYContent()
},
)

32
examples/falling-balls/shared/src/commonMain/kotlin/bouncingBalls/BouncingBalls.kt → examples/graphics-2d/shared/src/commonMain/kotlin/bouncingballs/BouncingBalls.kt

@ -1,28 +1,35 @@
/*
* 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 bouncingBalls
package bouncingballs
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.runtime.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.key
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.withFrameNanos
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.unit.dp
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.max
import kotlin.math.roundToInt
import kotlin.math.sin
import kotlin.random.Random
@ -52,17 +59,16 @@ fun BouncingBallsApp(initialBallsCount: Int = 5) {
list
}
Box(
BoxWithConstraints(
modifier = Modifier.fillMaxWidth()
.fillMaxHeight()
.border(width = 1.dp, color = Color.Black)
.noRippleClickable {
items += BouncingBall.createBouncingBall(offset = it)
}.onSizeChanged {
areaWidth = it.width
areaHeight = it.height
}
) {
areaWidth = maxWidth.value.roundToInt()
areaHeight = maxHeight.value.roundToInt()
Balls(items)
}

48
examples/falling-balls/shared/src/commonMain/kotlin/fallingBalls/FallingBalls.kt → examples/graphics-2d/shared/src/commonMain/kotlin/fallingballs/FallingBalls.common.kt

@ -1,11 +1,20 @@
package fallingballs
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.*
import androidx.compose.material.Button
import androidx.compose.material.Slider
import androidx.compose.material.Text
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Button
import androidx.compose.material3.Slider
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.runtime.withFrameNanos
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@ -15,7 +24,8 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@Composable
fun FallingBalls(game: Game) {
fun FallingBalls() {
val game = remember { Game() }
val density = LocalDensity.current
Column {
Text(
@ -23,7 +33,10 @@ fun FallingBalls(game: Game) {
fontSize = 20.sp,
color = Color(218, 120, 91)
)
Text("Score: ${game.score} Time: ${game.elapsed / 1_000_000} Blocks: ${game.numBlocks.toInt()}", fontSize = 20.sp)
Text(
"Score: ${game.score} Time: ${game.elapsed / 1_000_000} Blocks: ${game.numBlocks.toInt()}",
fontSize = 20.sp
)
Row {
if (!game.started) {
Slider(
@ -33,9 +46,6 @@ fun FallingBalls(game: Game) {
)
}
Button(
modifier = Modifier
.border(2.dp, Color(255, 215, 0))
.background(Color.Yellow),
onClick = {
game.started = !game.started
if (game.started) {
@ -45,18 +55,6 @@ fun FallingBalls(game: Game) {
) {
Text(if (game.started) "Stop" else "Start", fontSize = 25.sp)
}
if (game.started) {
Button(
modifier = Modifier
.offset(10.dp, 0.dp)
.border(2.dp, Color(255, 215, 0))
.background(Color.Yellow),
onClick = {
game.togglePause()
}) {
Text(if (game.paused) "Resume" else "Pause", fontSize = 25.sp)
}
}
}
if (game.started) {
Box(modifier = Modifier.height(20.dp))
@ -76,12 +74,14 @@ fun FallingBalls(game: Game) {
LaunchedEffect(Unit) {
while (true) {
var previousTimeNanos = withFrameNanos { it }
withFrameNanos {
if (game.started && !game.paused && !game.finished)
game.update(it)
if (game.started && !game.paused && !game.finished) {
game.update((it - previousTimeNanos).coerceAtLeast(0))
previousTimeNanos = it
}
}
}
}
}
}

43
examples/falling-balls/shared/src/commonMain/kotlin/fallingBalls/Game.kt → examples/graphics-2d/shared/src/commonMain/kotlin/fallingballs/Game.kt

@ -1,23 +1,18 @@
/*
* 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.runtime.*
package fallingballs
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.*
import androidx.compose.ui.unit.dp
import kotlin.random.Random
interface Time {
fun now(): Long
}
class Game(val time: Time) {
private var previousTimeNanos: Long = Long.MAX_VALUE
class Game() {
private val colors = arrayOf(
Color.Red, Color.Blue, Color.Cyan,
Color.Magenta, Color.Yellow, Color.Black
)
private var startTime = 0L
var width by mutableStateOf(0.dp)
var height by mutableStateOf(0.dp)
@ -36,30 +31,26 @@ class Game(val time: Time) {
var numBlocks by mutableStateOf(5f)
fun start() {
previousTimeNanos = time.now()
startTime = previousTimeNanos
clicked = 0
started = true
finished = false
paused = false
pieces.clear()
repeat(numBlocks.toInt()) { index ->
pieces.add(PieceData(this, index * 1.5f + 5f, colors[index % colors.size]).also { piece ->
pieces.add(
PieceData(
this,
index * 1.5f + 5f,
colors[index % colors.size]
).also { piece ->
piece.position = Random.nextDouble(0.0, 100.0).toFloat()
})
}
}
fun togglePause() {
paused = !paused
previousTimeNanos = time.now()
}
fun update(nanos: Long) {
val dt = (nanos - previousTimeNanos).coerceAtLeast(0)
previousTimeNanos = nanos
elapsed = nanos - startTime
pieces.forEach { it.update(dt) }
fun update(deltaTimeNanos: Long) {
elapsed += deltaTimeNanos
pieces.forEach { it.update(deltaTimeNanos) }
}
fun clicked(piece: PieceData) {

5
examples/falling-balls/shared/src/commonMain/kotlin/fallingBalls/Piece.kt → examples/graphics-2d/shared/src/commonMain/kotlin/fallingballs/Piece.kt

@ -1,7 +1,4 @@
/*
* 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.
*/
package fallingballs
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable

2
examples/minesweeper/shared/src/commonMain/kotlin/BoardView.kt → examples/graphics-2d/shared/src/commonMain/kotlin/minesweeper/BoardView.kt

@ -1,3 +1,5 @@
package minesweeper
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Box

16
examples/minesweeper/shared/src/commonMain/kotlin/GameController.kt → examples/graphics-2d/shared/src/commonMain/kotlin/minesweeper/GameController.kt

@ -1,36 +1,50 @@
package minesweeper
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import kotlin.random.Random
class GameController(private val options: GameSettings, private val onWin: (() -> Unit)? = null, private val onLose: (() -> Unit)? = null) {
class GameController(
private val options: GameSettings,
private val onWin: (() -> Unit)? = null,
private val onLose: (() -> Unit)? = null
) {
/** Number of rows in current board */
val rows: Int
get() = options.rows
/** Number of columns in current board */
val columns: Int
get() = options.columns
/** Number of bombs in current board */
val bombs: Int
get() = options.mines
/** True if current game has started, false if game is finished or until first cell is opened or flagged */
var running by mutableStateOf(false)
private set
/** True if game is ended (win or lose) */
var finished by mutableStateOf(false)
private set
/** Total number of flags set on cells, used for calculation of number of remaining bombs */
var flagsSet by mutableStateOf(0)
private set
/** Number of remaining cells */
var cellsToOpen by mutableStateOf(options.rows * options.columns - options.mines)
private set
/** Game timer, increments every second while game is running */
var seconds by mutableStateOf(0)
private set
/** Global monotonic time, updated with [onTimeTick] */
private var time = 0L
/** The time when user starts the game by opening or flagging any cell */
private var startTime = 0L

2
examples/minesweeper/shared/src/commonMain/kotlin/gameInteraction.kt → examples/graphics-2d/shared/src/commonMain/kotlin/minesweeper/GameInteraction.kt

@ -1,3 +1,5 @@
package minesweeper
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.combinedClickable
import androidx.compose.runtime.Composable

13
examples/minesweeper/shared/src/commonMain/kotlin/game.kt → examples/graphics-2d/shared/src/commonMain/kotlin/minesweeper/MineSweeper.common.kt

@ -1,12 +1,14 @@
@file:Suppress("FunctionName")
import androidx.compose.runtime.*
package minesweeper
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.*
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.unit.*
import org.jetbrains.compose.resources.ExperimentalResourceApi
@ -39,7 +41,7 @@ object GameStyles {
}
@Composable
fun Game(requestWindowSize: ((width: Dp, height: Dp) -> Unit)? = null) = MainLayout {
fun MineSweeper(requestWindowSize: ((width: Dp, height: Dp) -> Unit)? = null) = MainLayout {
var message by remember { mutableStateOf<String?>(null) }
val onWin = { message = "You win!" }
@ -101,7 +103,8 @@ fun Game(requestWindowSize: ((width: Dp, height: Dp) -> Unit)? = null) = MainLay
}
// Cells
Box(modifier = Modifier
Box(
modifier = Modifier
.border(GameStyles.boardBorderWidth, Color.White)
.padding(GameStyles.boardPadding)
) {

4
examples/minesweeper/shared/src/commonMain/kotlin/widgets.kt → examples/graphics-2d/shared/src/commonMain/kotlin/minesweeper/Widgets.kt

@ -1,11 +1,13 @@
@file:Suppress("FunctionName")
package minesweeper
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.material.Text
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier

200
examples/visual-effects/shared/src/commonMain/kotlin/HappyNY.kt → examples/graphics-2d/shared/src/commonMain/kotlin/visualeffects/HappyNY.kt

@ -1,25 +1,45 @@
package org.jetbrains.compose.demo.visuals
package visualeffects
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.compose.runtime.withFrameNanos
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.*
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.draw.scale
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
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.math.PI
import kotlin.math.abs
import kotlin.math.cos
import kotlin.math.sin
import kotlin.random.Random
const val width = 1200
@ -97,16 +117,16 @@ class DoubleRocket(val particle: Particle) {
state = STATE_SMALL_ROCKETS
}
fun move(time: Long, prevTime: Long) {
fun move(timeElapsed: Long, deltaNanos: Long) {
if (rocket.state == rocket.STATE_ROCKET) {
rocket.particle.move(time, prevTime)
rocket.particle.gravity(time, prevTime)
rocket.particle.move(deltaNanos)
rocket.particle.gravity(deltaNanos)
} else {
rocket.rockets.forEach {
it.move(time, prevTime)
it.move(timeElapsed, deltaNanos)
}
}
rocket.checkState(time)
rocket.checkState(timeElapsed)
}
@Composable
@ -126,8 +146,8 @@ class Rocket(val particle: Particle, val color: Color, val startTime: Long = 0)
var exploded = false
var parts: Array<Particle> = emptyArray()
fun checkExplode(time: Long) {
if (time - startTime > 1200000000) {
fun checkExplode(timeElapsed: Long) {
if (timeElapsed - startTime > 1200000000) {
explode()
}
}
@ -136,7 +156,14 @@ class Rocket(val particle: Particle, val color: Color, val startTime: Long = 0)
parts = Array(rocketPartsCount) {
val v = 0.5f + 1.5 * random()
val angle = 2 * PI * random()
Particle(particle.x, particle.y, v * sin(angle) + particle.vx, v * cos(angle) + particle.vy, color, 1)
Particle(
particle.x,
particle.y,
v * sin(angle) + particle.vx,
v * cos(angle) + particle.vy,
color,
1
)
}
exploded = true
}
@ -149,15 +176,15 @@ class Rocket(val particle: Particle, val color: Color, val startTime: Long = 0)
return true
}
fun move(time: Long, prevTime: Long) {
fun move(timeElapsed: Long, deltaNanos: Long) {
if (!exploded) {
particle.move(time, prevTime)
particle.gravity(time, prevTime)
checkExplode(time)
particle.move(deltaNanos)
particle.gravity(deltaNanos)
checkExplode(timeElapsed)
} else {
parts.forEach {
it.move(time, prevTime)
it.gravity(time, prevTime)
it.move(deltaNanos)
it.gravity(deltaNanos)
}
}
}
@ -174,20 +201,30 @@ class Rocket(val particle: Particle, val color: Color, val startTime: Long = 0)
}
}
class Particle(var x: Double, var y: Double, var vx: Double, var vy: Double, val color: Color, val type: Int = 0) {
fun move(time: Long, prevTime: Long) {
x = (x + vx * (time - prevTime) / 30000000)
y = (y + vy * (time - prevTime) / 30000000)
class Particle(
var x: Double,
var y: Double,
var vx: Double,
var vy: Double,
val color: Color,
val type: Int = 0
) {
fun move(deltaNanos: Long) {
x = (x + vx * deltaNanos / 30000000)
y = (y + vy * deltaNanos / 30000000)
}
fun gravity(time: Long, prevTime: Long) {
vy = vy + 1.0f * (time - prevTime) / 300000000
fun gravity(deltaNanos: Long) {
vy = vy + 1.0f * deltaNanos / 300000000
}
@Composable
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))
Box(
Modifier.size(5.dp).offset(x.dp, y.dp).alpha(alphaFactor).clip(CircleShape)
.background(color)
)
for (i in 1..5) {
Box(
Modifier.size(4.dp).offset((x - vx / 2 * i).dp, (y - vy / 2 * i).dp)
@ -199,7 +236,10 @@ 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))
fun prepareStarsAndSnowFlakes(stars: SnapshotStateList<Star>, snowFlakes: SnapshotStateList<SnowFlake>) {
fun prepareStarsAndSnowFlakes(
stars: SnapshotStateList<Star>,
snowFlakes: SnapshotStateList<SnowFlake>
) {
for (i in 0..snowCount) {
snowFlakes.add(
SnowFlake(
@ -214,7 +254,15 @@ fun prepareStarsAndSnowFlakes(stars: SnapshotStateList<Star>, snowFlakes: Snapsh
)
)
}
val colors = arrayOf(Color.Red, Color.Yellow, Color.Green, Color.Yellow, Color.Cyan, Color.Magenta, Color.White)
val colors = arrayOf(
Color.Red,
Color.Yellow,
Color.Green,
Color.Yellow,
Color.Cyan,
Color.Magenta,
Color.White
)
for (i in 0..starCount) {
stars.add(
Star(
@ -227,58 +275,58 @@ fun prepareStarsAndSnowFlakes(stars: SnapshotStateList<Star>, snowFlakes: Snapsh
}
}
@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun NYContent() {
var time by remember { mutableStateOf(nanoTime()) }
var started by remember { mutableStateOf(false) }
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) }
val snowFlakes = remember { mutableStateListOf<SnowFlake>() }
remember { prepareStarsAndSnowFlakes(stars, snowFlakes) }
var timeElapsedNanos by remember { mutableStateOf(0L) }
Surface(
modifier = Modifier.fillMaxSize().padding(5.dp).shadow(3.dp, RoundedCornerShape(20.dp)),
color = Color.Black,
shape = RoundedCornerShape(20.dp)
) {
LaunchedEffect(Unit) {
while (true) {
var previousTimeNanos = withFrameNanos { it }
withFrameNanos {
prevTime = time
time = it
val deltaTimeNanos = it - previousTimeNanos
timeElapsedNanos += deltaTimeNanos
previousTimeNanos = it
if (flickering2) {
if (timeElapsedNanos > 15500000000) { //note, that startTime has been updated above
flickering2 = false
}
}
if (started) {
rocket.move(timeElapsedNanos, deltaTimeNanos)
}
if (!started) { //animation starts with delay, so there is some time to start recording
if (time - startTime in 7000000001..7099999999) println("ready!")
if (time - startTime > 10000000000) {
startTime = time //restarting timer
started = true
snowFlakes.forEach {
var y = it.y + ((it.v * deltaTimeNanos) / 30000000).dp
if (y > (height + 20).dp) {
y = -20.dp
}
it.y = y
}
if (flickering2) {
if (time - startTime > 15500000000) { //note, that startTime has been updated above
flickering2 = false
}
}
if (started) {
rocket.move(time, prevTime)
}
with(LocalDensity.current) {
Box(Modifier.fillMaxSize()) {
snow(time, prevTime, snowFlakes, startTime)
snow(timeElapsedNanos, snowFlakes)
starrySky(stars)
Row(modifier = Modifier.fillMaxSize(), verticalAlignment = Alignment.Bottom, horizontalArrangement = Arrangement.Center) {
Row(
modifier = Modifier.fillMaxSize(),
verticalAlignment = Alignment.Bottom,
horizontalArrangement = Arrangement.Center
) {
Text(
fontSize = 10.em,
text = "202",
@ -287,10 +335,10 @@ fun NYContent() {
color = Color.White
)
val alpha = if (flickering2) flickeringAlpha(time) else 1.0f
val alpha = if (flickering2) flickeringAlpha(timeElapsedNanos) else 1.0f
Text(
fontSize = 10.em,
text = "3",
text = "4",
modifier = Modifier.alpha(alpha).offset(0.dp, -15.dp),
color = Color.White
)
@ -300,14 +348,15 @@ fun NYContent() {
//HNY
var i = 0
val angle = (HNYString.length / 2 * 5) * -1.0f
val color = colorHNY(time, startTime)
val color = colorHNY(timeElapsedNanos)
HNYString.forEach {
val alpha = alphaHNY(i, time, startTime)
val alpha = alphaHNY(i, timeElapsedNanos)
Text(
fontSize = 14.sp,
text = it.toString(),
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)
)
i++
@ -326,9 +375,9 @@ fun NYContent() {
}
}
fun colorHNY(time: Long, startTime: Long): Color {
fun colorHNY(timeElapsed: Long): Color {
val periodLength = 60
val offset = ((time - startTime) / 80000000).toFloat() / periodLength
val offset = (timeElapsed.toFloat() / 80000000) / periodLength
val color1 = Color.Red
val color2 = Color.Yellow
val color3 = Color.Magenta
@ -348,16 +397,16 @@ fun blend(color1: Color, color2: Color, fraction: Float): Color {
)
}
fun alphaHNY(i: Int, time: Long, startTime: Long): Float {
val period = period(time, startTime, 200) - i
fun alphaHNY(i: Int, timeElapsed: Long): Float {
val period = period(timeElapsed, 200) - i
if (period < 0) return 0.0f
if (period > 10) return 1.0f
return 0.1f * period
}
fun period(time: Long, startTime: Long, periodLength: Int, speed: Int = 1): Int {
fun period(timeElapsed: Long, periodLength: Int, speed: Int = 1): Int {
val period = 200000000 / speed
return (((time - startTime) / period) % periodLength).toInt()
return ((timeElapsed / period) % periodLength).toInt()
}
fun flickeringAlpha(time: Long): Float {
@ -384,17 +433,15 @@ fun star(x: Dp, y: Dp, color: Color = Color.White, size: Dp) {
}
@Composable
fun snow(time: Long, prevTime: Long, snowFlakes: SnapshotStateList<SnowFlake>, startTime: Long) {
val deltaAngle = (time - startTime) / 100000000
fun snow(timeElapsed: Long, snowFlakes: SnapshotStateList<SnowFlake>) {
val deltaAngle = timeElapsed.toFloat() / 100000000
with(LocalDensity.current) {
snowFlakes.forEach {
var y = it.y + ((it.v * (time - prevTime)) / 300000000).dp
if (y > (height + 20).dp) {
y = -20.dp
}
it.y = y
val x = it.x + (15 * sin(time.toDouble() / 3000000000 + it.phase)).dp
snowFlake(Modifier.offset(x, y).scale(it.scale).rotate(it.angle + deltaAngle * it.rotate), it.alpha)
val x = it.x + (15 * sin(timeElapsed.toDouble() / 3000000000 + it.phase)).dp
snowFlake(
Modifier.offset(x, it.y).scale(it.scale).rotate(it.angle + deltaAngle * it.rotate),
it.alpha
)
}
}
}
@ -416,7 +463,8 @@ fun snowFlake(modifier: Modifier, alpha: Float = 0.8f) {
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)
Modifier.offset(shiftX, shiftY).rotate(angle).width(100.dp).height(10.dp).scale(0.6f)
.alpha(1f)
.background(Color.White.copy(alpha = alpha))
) {
snowFlakeInt(level + 1, 30f, 12.dp, 20.dp, alpha * 0.8f)

14
examples/visual-effects/shared/src/commonMain/kotlin/platform/PointerEventKind.kt → examples/graphics-2d/shared/src/commonMain/kotlin/visualeffects/PointerEvent.common.kt

@ -1,4 +1,4 @@
package org.jetbrains.compose.demo.visuals.platform
package visualeffects
import androidx.compose.foundation.gestures.awaitFirstDown
import androidx.compose.foundation.gestures.forEachGesture
@ -6,6 +6,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.input.pointer.PointerEvent
import androidx.compose.ui.input.pointer.pointerInput
enum class PointerEventKind {
Move,
In,
@ -14,7 +15,10 @@ enum class PointerEventKind {
class Position(val x: Int, val y: Int)
expect fun Modifier.onPointerEvent(eventKind: PointerEventKind, onEvent: Position.() -> Unit): Modifier
expect fun Modifier.onPointerEvent(
eventKind: PointerEventKind,
onEvent: Position.() -> Unit
): Modifier
fun Modifier.onPointerEventMobileImpl(
eventKind: PointerEventKind,
@ -37,7 +41,10 @@ fun Modifier.onPointerEventMobileImpl(
val event: PointerEvent = awaitPointerEvent()
if (eventKind == PointerEventKind.Move) {
Position(event.changes.first().position.x.toInt(), event.changes.first().position.y.toInt()).onEvent()
Position(
event.changes.first().position.x.toInt(),
event.changes.first().position.y.toInt()
).onEvent()
}
} while (event.changes.any { it.pressed })
@ -49,4 +56,3 @@ fun Modifier.onPointerEventMobileImpl(
}
}
}

26
examples/visual-effects/shared/src/commonMain/kotlin/RotatingWords.kt → examples/graphics-2d/shared/src/commonMain/kotlin/visualeffects/RotatingWords.kt

@ -1,11 +1,11 @@
package org.jetbrains.compose.demo.visuals
package visualeffects
import androidx.compose.animation.core.*
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.Text
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
@ -62,7 +62,8 @@ fun Words() {
val color3 = Color(0xFD, 0xB6, 0x0D)
val color4 = Color(0xFC, 0xF8, 0x4A)
Column(modifier = Modifier
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
) {
@ -70,11 +71,18 @@ fun Words() {
Word(position = baseEn, angle = angle, scale = scale, text = "Your", color = color2)
Word(position = baseCh, angle = angle, scale = scale, text = "您的", color = color3)
Word(position = baseJa, angle = angle, scale = scale, text = "あなたの", color = color4)
Word(position = baseText, angle = 0f, scale = 6f, text = " Compose\nMultiplatform", color = Color(52, 67, 235),
alpha = 0.4f)
Word(
position = baseText,
angle = 0f,
scale = 6f,
text = " Compose\nMultiplatform",
color = Color(52, 67, 235),
alpha = 0.4f
)
val size = 80.dp * scale
Image(logoImg, contentDescription = "Logo",
Image(
logoImg, contentDescription = "Logo",
modifier = Modifier
.offset(baseLogo.x - size / 2, baseLogo.y - size / 2)
.size(size)
@ -84,8 +92,10 @@ fun Words() {
}
@Composable
fun Word(position: DpOffset, angle: Float, scale: Float, text: String,
color: Color, alpha: Float = 0.8f) {
fun Word(
position: DpOffset, angle: Float, scale: Float, text: String,
color: Color, alpha: Float = 0.8f
) {
Text(
modifier = Modifier
.offset(position.x, position.y)

41
examples/visual-effects/shared/src/commonMain/kotlin/WaveEffect.kt → examples/graphics-2d/shared/src/commonMain/kotlin/visualeffects/WaveEffect.kt

@ -1,9 +1,9 @@
package org.jetbrains.compose.demo.visuals
package visualeffects
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
@ -11,9 +11,6 @@ import androidx.compose.ui.draw.*
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
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.*
@OptIn(ExperimentalComposeUiApi::class)
@ -25,23 +22,31 @@ fun WaveEffectGrid() {
var centerY by remember { mutableStateOf(900) }
var vX by remember { mutableStateOf(0) }
var vY by remember { mutableStateOf(0) }
var timeElapsedNanos by remember { mutableStateOf(0L) }
var time by remember { mutableStateOf(nanoTime()) }
var prevTime by remember { mutableStateOf(nanoTime()) }
LaunchedEffect(Unit) {
while (true) {
var previousTimeNanos = withFrameNanos { it }
withFrameNanos {
val deltaTimeNanos = it - previousTimeNanos
timeElapsedNanos += deltaTimeNanos
previousTimeNanos = it
if (State.entered) {
centerX = (centerX + vX * (time - prevTime) / 1000000000).toInt()
centerX = (centerX + vX * deltaTimeNanos / 1000000000).toInt()
if (centerX < -100) centerX = -100
if (centerX > 2600) centerX = 2600
vX =
(vX * (1 - (time - prevTime).toDouble() / 500000000) + 10 * (mouseX - centerX) * (time - prevTime) / 1000000000).toInt()
centerY = (centerY + vY * (time - prevTime) / 1000000000).toInt()
(vX * (1 - deltaTimeNanos.toDouble() / 500000000) + 10 * (mouseX - centerX) * deltaTimeNanos / 1000000000).toInt()
centerY = (centerY + vY * deltaTimeNanos / 1000000000).toInt()
if (centerY < -100) centerY = -100
if (centerY > 1800) centerY = 1800
vY =
(vY * (1 - (time - prevTime).toDouble() / 500000000) + 5 * (mouseY - centerY) * (time - prevTime) / 1000000000).toInt()
(vY * (1 - deltaTimeNanos.toDouble() / 500000000) + 5 * (mouseY - centerY) * deltaTimeNanos / 1000000000).toInt()
prevTime = time
}
}
}
}
Surface(
@ -71,8 +76,8 @@ fun WaveEffectGrid() {
x = if (evenRow) 10 + shift else 10
while (x < 1190) {
val size: Int = size(x, y, pointerOffsetX, pointerOffsety)
val color = boxColor(x, y, time, pointerOffsetX, pointerOffsety)
Dot(size, Modifier.offset(x.dp, y.dp), color, time)
val color = boxColor(x, y, timeElapsedNanos, pointerOffsetX, pointerOffsety)
Dot(size, Modifier.offset(x.dp, y.dp), color, timeElapsedNanos)
x += shift * 2
}
y += shift
@ -81,14 +86,6 @@ fun WaveEffectGrid() {
HighPanel(pointerOffsetX, pointerOffsety)
}
LaunchedEffect(Unit) {
while (true) {
withFrameNanos {
time = it
}
}
}
}
}

0
examples/minesweeper/shared/src/commonMain/resources/assets/clock.png → examples/graphics-2d/shared/src/commonMain/resources/assets/clock.png

Before

Width:  |  Height:  |  Size: 896 B

After

Width:  |  Height:  |  Size: 896 B

0
examples/minesweeper/shared/src/commonMain/resources/assets/flag.png → examples/graphics-2d/shared/src/commonMain/resources/assets/flag.png

Before

Width:  |  Height:  |  Size: 780 B

After

Width:  |  Height:  |  Size: 780 B

0
examples/minesweeper/shared/src/commonMain/resources/assets/mine.png → examples/graphics-2d/shared/src/commonMain/resources/assets/mine.png

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

36
examples/graphics-2d/shared/src/commonMain/resources/compose-community-primary.xml

@ -0,0 +1,36 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="600dp"
android:height="600dp"
android:viewportWidth="600"
android:viewportHeight="600">
<path
android:pathData="M301.21,418.53C300.97,418.54 300.73,418.56 300.49,418.56C297.09,418.59 293.74,417.72 290.79,416.05L222.6,377.54C220.63,376.43 219,374.82 217.85,372.88C216.7,370.94 216.09,368.73 216.07,366.47L216.07,288.16C216.06,287.32 216.09,286.49 216.17,285.67C216.38,283.54 216.91,281.5 217.71,279.6L199.29,268.27L177.74,256.19C175.72,260.43 174.73,265.23 174.78,270.22L174.79,387.05C174.85,393.89 178.57,400.2 184.53,403.56L286.26,461.02C290.67,463.51 295.66,464.8 300.73,464.76C300.91,464.76 301.09,464.74 301.27,464.74C301.24,449.84 301.22,439.23 301.22,439.23L301.21,418.53Z"
android:fillColor="#041619"
android:fillType="nonZero"/>
<path
android:pathData="M409.45,242.91L312.64,188.23C303.64,183.15 292.58,183.26 283.68,188.51L187.92,245C183.31,247.73 179.93,251.62 177.75,256.17L177.74,256.19L199.29,268.27L217.71,279.6C217.83,279.32 217.92,279.02 218.05,278.74C218.24,278.36 218.43,277.98 218.64,277.62C219.06,276.88 219.52,276.18 220.04,275.51C221.37,273.8 223.01,272.35 224.87,271.25L289.06,233.39C290.42,232.59 291.87,231.96 293.39,231.51C295.53,230.87 297.77,230.6 300,230.72C302.98,230.88 305.88,231.73 308.47,233.2L373.37,269.85C375.54,271.08 377.49,272.68 379.13,274.57C379.68,275.19 380.18,275.85 380.65,276.53C380.86,276.84 381.05,277.15 381.24,277.47L397.79,266.39L420.34,252.93L420.31,252.88C417.55,248.8 413.77,245.35 409.45,242.91Z"
android:fillColor="#37BF6E"
android:fillType="nonZero"/>
<path
android:pathData="M381.24,277.47C381.51,277.92 381.77,278.38 382.01,278.84C382.21,279.24 382.39,279.65 382.57,280.06C382.91,280.88 383.19,281.73 383.41,282.59C383.74,283.88 383.92,285.21 383.93,286.57L383.93,361.1C383.96,363.95 383.35,366.77 382.16,369.36C381.93,369.86 381.69,370.35 381.42,370.83C379.75,373.79 377.32,376.27 374.39,378L310.2,415.87C307.47,417.48 304.38,418.39 301.21,418.53L301.22,439.23C301.22,439.23 301.24,449.84 301.27,464.74C306.1,464.61 310.91,463.3 315.21,460.75L410.98,404.25C419.88,399 425.31,389.37 425.22,379.03L425.22,267.85C425.17,262.48 423.34,257.34 420.34,252.93L397.79,266.39L381.24,277.47Z"
android:fillColor="#3870B2"
android:fillType="nonZero"/>
<path
android:pathData="M177.75,256.17C179.93,251.62 183.31,247.73 187.92,245L283.68,188.51C292.58,183.26 303.64,183.15 312.64,188.23L409.45,242.91C413.77,245.35 417.55,248.8 420.31,252.88L420.34,252.93L498.59,206.19C494.03,199.46 487.79,193.78 480.67,189.75L320.86,99.49C306.01,91.1 287.75,91.27 273.07,99.95L114.99,193.2C107.39,197.69 101.81,204.11 98.21,211.63L177.74,256.19L177.75,256.17ZM301.27,464.74C301.09,464.74 300.91,464.76 300.73,464.76C295.66,464.8 290.67,463.51 286.26,461.02L184.53,403.56C178.57,400.2 174.85,393.89 174.79,387.05L174.78,270.22C174.73,265.23 175.72,260.43 177.74,256.19L98.21,211.63C94.86,218.63 93.23,226.58 93.31,234.82L93.31,427.67C93.42,438.97 99.54,449.37 109.4,454.92L277.31,549.77C284.6,553.88 292.84,556.01 301.2,555.94L301.2,555.8C301.39,543.78 301.33,495.26 301.27,464.74Z"
android:strokeWidth="10"
android:fillColor="#00000000"
android:strokeColor="#083042"
android:fillType="nonZero"/>
<path
android:pathData="M498.59,206.19L420.34,252.93C423.34,257.34 425.17,262.48 425.22,267.85L425.22,379.03C425.31,389.37 419.88,399 410.98,404.25L315.21,460.75C310.91,463.3 306.1,464.61 301.27,464.74C301.33,495.26 301.39,543.78 301.2,555.8L301.2,555.94C309.48,555.87 317.74,553.68 325.11,549.32L483.18,456.06C497.87,447.39 506.85,431.49 506.69,414.43L506.69,230.91C506.6,222.02 503.57,213.5 498.59,206.19Z"
android:strokeWidth="10"
android:fillColor="#00000000"
android:strokeColor="#083042"
android:fillType="nonZero"/>
<path
android:pathData="M301.2,555.94C292.84,556.01 284.6,553.88 277.31,549.76L109.4,454.92C99.54,449.37 93.42,438.97 93.31,427.67L93.31,234.82C93.23,226.58 94.86,218.63 98.21,211.63C101.81,204.11 107.39,197.69 114.99,193.2L273.07,99.95C287.75,91.27 306.01,91.1 320.86,99.49L480.67,189.75C487.79,193.78 494.03,199.46 498.59,206.19C503.57,213.5 506.6,222.02 506.69,230.91L506.69,414.43C506.85,431.49 497.87,447.39 483.18,456.06L325.11,549.32C317.74,553.68 309.48,555.87 301.2,555.94Z"
android:strokeWidth="10"
android:fillColor="#00000000"
android:strokeColor="#083042"
android:fillType="nonZero"/>
</vector>

2
examples/minesweeper/shared/src/commonTest/kotlin/GameControllerTest.kt → examples/graphics-2d/shared/src/commonTest/kotlin/minesweeper/GameControllerTest.kt

@ -1,3 +1,5 @@
package minesweeper
import kotlin.test.*
class GameControllerTest {

3
examples/graphics-2d/shared/src/desktopMain/kotlin/minesweeper/MineSweeper.desktop.kt

@ -0,0 +1,3 @@
package minesweeper
actual fun hasRightClick() = true

2
examples/visual-effects/shared/src/desktopMain/kotlin/platform/PointerEventKind.desktop.kt → examples/graphics-2d/shared/src/desktopMain/kotlin/visualeffects/PointerEvent.desktop.kt

@ -1,4 +1,4 @@
package org.jetbrains.compose.demo.visuals.platform
package visualeffects
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier

6
examples/graphics-2d/shared/src/iosMain/kotlin/main.ios.kt

@ -0,0 +1,6 @@
import androidx.compose.ui.window.ComposeUIViewController
import platform.UIKit.UIViewController
fun MainViewController(): UIViewController = ComposeUIViewController {
Graphics2D()
}

3
examples/graphics-2d/shared/src/iosMain/kotlin/minesweeper/MineSweeper.ios.kt

@ -0,0 +1,3 @@
package minesweeper
actual fun hasRightClick() = false

2
examples/visual-effects/shared/src/iosMain/kotlin/platform/PointerEventKind.ios.kt → examples/graphics-2d/shared/src/iosMain/kotlin/visualeffects/PointerEvent.ios.kt

@ -1,4 +1,4 @@
package org.jetbrains.compose.demo.visuals.platform
package visualeffects
import androidx.compose.ui.Modifier

6
examples/graphics-2d/shared/src/jsMain/kotlin/main.js.kt

@ -0,0 +1,6 @@
import androidx.compose.runtime.Composable
@Composable
fun MainView() {
Graphics2D()
}

3
examples/graphics-2d/shared/src/jsMain/kotlin/minesweeper/MineSweeepr.js.kt

@ -0,0 +1,3 @@
package minesweeper
actual fun hasRightClick() = false

26
examples/graphics-2d/shared/src/jsMain/kotlin/visualeffects/PointerEvent.js.kt

@ -0,0 +1,26 @@
package visualeffects
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()
}
}

11
examples/graphics-2d/shared/src/macosMain/kotlin/main.macos.kt

@ -0,0 +1,11 @@
import androidx.compose.ui.window.Window
import platform.AppKit.NSApp
import platform.AppKit.NSApplication
fun main() {
NSApplication.sharedApplication()
Window("Graphics2D") {
Graphics2D()
}
NSApp?.run()
}

3
examples/graphics-2d/shared/src/macosMain/kotlin/minesweeper/MineSweeper.macos.kt

@ -0,0 +1,3 @@
package minesweeper
actual fun hasRightClick() = false

27
examples/graphics-2d/shared/src/macosMain/kotlin/visualeffects/PointerEventKind.macos.kt

@ -0,0 +1,27 @@
package visualeffects
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()
}
}

7
examples/minesweeper/.gitignore vendored

@ -1,7 +0,0 @@
local.properties
iosApp/Podfile.lock
iosApp/Pods/*
iosApp/iosApp.xcworkspace/*
iosApp/iosApp.xcodeproj/*
!iosApp/iosApp.xcodeproj/project.pbxproj
shared/shared.podspec

28
examples/minesweeper/.run/desktopApp.run.xml

@ -1,28 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="desktopApp" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="env">
<map>
<entry key="DEVELOPER_DIR" value="/Applications/Xcode.app/Contents/Developer" />
</map>
</option>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="desktopApp:run" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2" />
</configuration>
</component>

25
examples/minesweeper/README.md

@ -1,25 +0,0 @@
# Minesweeper
A simple game powered by Compose Multiplatform.
Game can run on Android, iOS, desktop or in a browser.
## Setting up your development environment
To setup the environment, please consult these [instructions](https://github.com/JetBrains/compose-multiplatform-template#setting-up-your-development-environment).
## How to run
Choose a run configuration for an appropriate target in Android Studio and run it.
![run-configurations.png](run-configurations.png)
## Run on desktop via Gradle
`./gradlew desktopApp:run`
## Run native on MacOS
`./gradlew runDebugExecutableMacosX64` (Works on Intel processors)
## Credits
<div>Icons made by <a href="https://www.flaticon.com/authors/creaticca-creative-agency" title="Creaticca Creative Agency">Creaticca Creative Agency</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a></div>

35
examples/minesweeper/androidApp/build.gradle.kts

@ -1,35 +0,0 @@
plugins {
kotlin("multiplatform")
id("com.android.application")
id("org.jetbrains.compose")
}
kotlin {
androidTarget()
sourceSets {
val androidMain by getting {
dependencies {
implementation(project(":shared"))
}
}
}
}
android {
compileSdk = 34
namespace = "org.jetbrains.minesweeper"
defaultConfig {
applicationId = "org.jetbrains.ComposeMinesweeper"
minSdk = 26
targetSdk = 34
versionCode = 1
versionName = "1.0"
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlin {
jvmToolchain(17)
}
}

21
examples/minesweeper/androidApp/src/androidMain/AndroidManifest.xml

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<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"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

15
examples/minesweeper/androidApp/src/androidMain/kotlin/MainActivity.kt

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

3
examples/minesweeper/androidApp/src/androidMain/res/values/strings.xml

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

18
examples/minesweeper/build.gradle.kts

@ -1,18 +0,0 @@
plugins {
// 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
}
allprojects {
repositories {
google()
mavenCentral()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
}
}

35
examples/minesweeper/desktopApp/build.gradle.kts

@ -1,35 +0,0 @@
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 = "MainKt"
nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "Minesweeper"
packageVersion = "1.0.0"
windows {
menuGroup = "Compose Examples"
// see https://wixtoolset.org/documentation/manual/v3/howtos/general/generate_guids.html
upgradeUuid = "2bf169f9-d851-49f0-b3a1-308966d473ca"
}
}
}
}

22
examples/minesweeper/desktopApp/src/jvmMain/kotlin/Main.kt

@ -1,22 +0,0 @@
/*
* 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.ui.ExperimentalComposeUiApi
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.window.*
fun main() = application {
val windowState = rememberWindowState()
Window(
onCloseRequest = ::exitApplication,
resizable = false,
title = "Minesweeper",
icon = painterResource("assets/mine.png"),
state = windowState
) {
MainView(windowState)
}
}

19
examples/minesweeper/gradle.properties

@ -1,19 +0,0 @@
kotlin.code.style=official
xcodeproj=./iosApp
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.useEmbeddableCompilerJar=true
kotlin.mpp.androidSourceSetLayoutVersion=2
# Enable kotlin/native experimental memory model
kotlin.native.binary.memoryModel=experimental
kotlin.version=1.9.10
agp.version=8.0.2
compose.version=1.5.2
# TODO: remove when switching to 1.9.10. See: https://youtrack.jetbrains.com/issue/KT-60852
# usage: ./gradlew :jsApp:jsBrowserRun -Pworkaround.kotlin.js.kt60852=true
# setting it to `true` breaks other targets (see shared/build.gradle.kts), so it should be used to run the web app only.
workaround.kotlin.js.kt60852=false

BIN
examples/minesweeper/gradle/wrapper/gradle-wrapper.jar vendored

Binary file not shown.

5
examples/minesweeper/gradle/wrapper/gradle-wrapper.properties vendored

@ -1,5 +0,0 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

240
examples/minesweeper/gradlew vendored

@ -1,240 +0,0 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

91
examples/minesweeper/gradlew.bat vendored

@ -1,91 +0,0 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save