Browse Source
Move https://github.com/MatkovIvan/nav_cupcake repo to the examples folder. This is a Compose Multiplatform adaptation of [Navigate between screens with Compose](https://developer.android.com/codelabs/basic-android-kotlin-compose-navigation) codelab <img width="2040" alt="multiplatform_screenshot_light" src="https://github.com/JetBrains/compose-multiplatform/assets/1836384/a579574a-44fe-414c-8a89-1507aaeea250"> <img width="2040" alt="multiplatform_screenshot_dark" src="https://github.com/JetBrains/compose-multiplatform/assets/1836384/a216841a-958e-4597-a98b-2198a203228e">igor.demin/fix-skiko-api-2
Ivan Matkov
6 months ago
committed by
GitHub
45 changed files with 5312 additions and 0 deletions
@ -0,0 +1,18 @@ |
|||||||
|
*.iml |
||||||
|
.gradle |
||||||
|
.kotlin |
||||||
|
**/build/ |
||||||
|
xcuserdata |
||||||
|
!src/**/build/ |
||||||
|
local.properties |
||||||
|
.idea |
||||||
|
.DS_Store |
||||||
|
captures |
||||||
|
.externalNativeBuild |
||||||
|
.cxx |
||||||
|
*.xcodeproj/* |
||||||
|
!*.xcodeproj/project.pbxproj |
||||||
|
!*.xcodeproj/xcshareddata/ |
||||||
|
!*.xcodeproj/project.xcworkspace/ |
||||||
|
!*.xcworkspace/contents.xcworkspacedata |
||||||
|
**/xcshareddata/WorkspaceSettings.xcsettings |
@ -0,0 +1,4 @@ |
|||||||
|
This is a Compose Multiplatform adaptation of [Navigate between screens with Compose](https://developer.android.com/codelabs/basic-android-kotlin-compose-navigation) codelab |
||||||
|
|
||||||
|
![Multiplatform Screenshot - Light](images/multiplatform_screenshot_light.png) |
||||||
|
![Multiplatform Screenshot - Dark](images/multiplatform_screenshot_dark.png) |
@ -0,0 +1,9 @@ |
|||||||
|
plugins { |
||||||
|
// this is necessary to avoid the plugins to be loaded multiple times |
||||||
|
// in each subproject's classloader |
||||||
|
alias(libs.plugins.androidApplication) apply false |
||||||
|
alias(libs.plugins.androidLibrary) apply false |
||||||
|
alias(libs.plugins.kotlinMultiplatform) apply false |
||||||
|
alias(libs.plugins.composeMultiplatform) apply false |
||||||
|
alias(libs.plugins.composeCompiler) apply false |
||||||
|
} |
@ -0,0 +1,149 @@ |
|||||||
|
import org.jetbrains.compose.desktop.application.dsl.TargetFormat |
||||||
|
import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl |
||||||
|
import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig |
||||||
|
|
||||||
|
plugins { |
||||||
|
alias(libs.plugins.kotlinMultiplatform) |
||||||
|
alias(libs.plugins.androidApplication) |
||||||
|
alias(libs.plugins.composeMultiplatform) |
||||||
|
alias(libs.plugins.composeCompiler) |
||||||
|
} |
||||||
|
|
||||||
|
kotlin { |
||||||
|
@OptIn(ExperimentalWasmDsl::class) |
||||||
|
wasmJs { |
||||||
|
moduleName = "composeApp" |
||||||
|
browser { |
||||||
|
commonWebpackConfig { |
||||||
|
outputFileName = "composeApp.js" |
||||||
|
devServer = (devServer ?: KotlinWebpackConfig.DevServer()).apply { |
||||||
|
static = (static ?: mutableListOf()).apply { |
||||||
|
// Serve sources to debug inside browser |
||||||
|
add(project.projectDir.path) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
binaries.executable() |
||||||
|
} |
||||||
|
|
||||||
|
androidTarget { |
||||||
|
compilations.all { |
||||||
|
kotlinOptions { |
||||||
|
jvmTarget = "11" |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
jvm("desktop") |
||||||
|
|
||||||
|
listOf( |
||||||
|
iosX64(), |
||||||
|
iosArm64(), |
||||||
|
iosSimulatorArm64() |
||||||
|
).forEach { iosTarget -> |
||||||
|
iosTarget.binaries.framework { |
||||||
|
baseName = "ComposeApp" |
||||||
|
isStatic = true |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
sourceSets { |
||||||
|
all { |
||||||
|
languageSettings { |
||||||
|
optIn("androidx.compose.material3.ExperimentalMaterial3Api") |
||||||
|
optIn("org.jetbrains.compose.resources.ExperimentalResourceApi") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
val commonMain by getting |
||||||
|
val jbMain by creating { |
||||||
|
dependsOn(commonMain) |
||||||
|
} |
||||||
|
val desktopMain by getting { |
||||||
|
dependsOn(jbMain) |
||||||
|
} |
||||||
|
val iosX64Main by getting |
||||||
|
val iosArm64Main by getting |
||||||
|
val iosSimulatorArm64Main by getting |
||||||
|
val iosMain by creating { |
||||||
|
dependsOn(jbMain) |
||||||
|
iosX64Main.dependsOn(this) |
||||||
|
iosArm64Main.dependsOn(this) |
||||||
|
iosSimulatorArm64Main.dependsOn(this) |
||||||
|
} |
||||||
|
val wasmJsMain by getting { |
||||||
|
dependsOn(jbMain) |
||||||
|
} |
||||||
|
|
||||||
|
androidMain.dependencies { |
||||||
|
implementation(libs.compose.ui.tooling.preview) |
||||||
|
implementation(libs.androidx.activity.compose) |
||||||
|
} |
||||||
|
commonMain.dependencies { |
||||||
|
implementation(libs.kotlinx.datetime) |
||||||
|
|
||||||
|
implementation(compose.foundation) |
||||||
|
implementation(compose.material3) |
||||||
|
implementation(compose.components.resources) |
||||||
|
implementation(compose.components.uiToolingPreview) |
||||||
|
|
||||||
|
implementation(libs.androidx.lifecycle.runtime.compose) |
||||||
|
implementation(libs.androidx.lifecycle.viewmodel.compose) |
||||||
|
implementation(libs.androidx.navigation.compose) |
||||||
|
} |
||||||
|
desktopMain.dependencies { |
||||||
|
implementation(compose.desktop.currentOs) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
android { |
||||||
|
namespace = "org.jetbrains.nav_cupcake" |
||||||
|
compileSdk = libs.versions.android.compileSdk.get().toInt() |
||||||
|
|
||||||
|
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml") |
||||||
|
sourceSets["main"].res.srcDirs("src/androidMain/res") |
||||||
|
sourceSets["main"].resources.srcDirs("src/commonMain/resources") |
||||||
|
|
||||||
|
defaultConfig { |
||||||
|
applicationId = "org.jetbrains.nav_cupcake" |
||||||
|
minSdk = libs.versions.android.minSdk.get().toInt() |
||||||
|
targetSdk = libs.versions.android.targetSdk.get().toInt() |
||||||
|
versionCode = 1 |
||||||
|
versionName = "1.0" |
||||||
|
} |
||||||
|
packaging { |
||||||
|
resources { |
||||||
|
excludes += "/META-INF/{AL2.0,LGPL2.1}" |
||||||
|
} |
||||||
|
} |
||||||
|
buildTypes { |
||||||
|
getByName("release") { |
||||||
|
isMinifyEnabled = false |
||||||
|
} |
||||||
|
} |
||||||
|
compileOptions { |
||||||
|
sourceCompatibility = JavaVersion.VERSION_11 |
||||||
|
targetCompatibility = JavaVersion.VERSION_11 |
||||||
|
} |
||||||
|
dependencies { |
||||||
|
debugImplementation(libs.compose.ui.tooling) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
compose.desktop { |
||||||
|
application { |
||||||
|
mainClass = "MainKt" |
||||||
|
|
||||||
|
nativeDistributions { |
||||||
|
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb) |
||||||
|
packageName = "org.jetbrains.nav_cupcake" |
||||||
|
packageVersion = "1.0.0" |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
compose.experimental { |
||||||
|
web.application {} |
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
<?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="@android:style/Theme.Material.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> |
@ -0,0 +1,26 @@ |
|||||||
|
package org.jetbrains.nav_cupcake |
||||||
|
|
||||||
|
import App |
||||||
|
import android.os.Bundle |
||||||
|
import androidx.activity.ComponentActivity |
||||||
|
import androidx.activity.compose.setContent |
||||||
|
import androidx.activity.enableEdgeToEdge |
||||||
|
import androidx.compose.runtime.Composable |
||||||
|
import androidx.compose.ui.tooling.preview.Preview |
||||||
|
|
||||||
|
class MainActivity : ComponentActivity() { |
||||||
|
override fun onCreate(savedInstanceState: Bundle?) { |
||||||
|
enableEdgeToEdge() |
||||||
|
super.onCreate(savedInstanceState) |
||||||
|
|
||||||
|
setContent { |
||||||
|
App() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Preview |
||||||
|
@Composable |
||||||
|
fun AppAndroidPreview() { |
||||||
|
App() |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
<resources> |
||||||
|
<string name="app_name">Cupcake</string> |
||||||
|
</resources> |
@ -0,0 +1,44 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<!-- |
||||||
|
Copyright (C) 2023 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 |
||||||
|
|
||||||
|
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. |
||||||
|
--> |
||||||
|
<!-- Cupcake icon for the start fragment --> |
||||||
|
<vector android:height="200dp" android:viewportHeight="413.71" |
||||||
|
android:viewportWidth="308.15" android:width="148.96909dp" xmlns:android="http://schemas.android.com/apk/res/android"> |
||||||
|
<path android:fillColor="#4fc3f7" android:pathData="M34.33,218.79l-27.63,-11.72l-6.7,27.68l34.33,-15.96z"/> |
||||||
|
<path android:fillColor="#4fc3f7" android:pathData="M273.75,218.79l27.63,-11.72l6.69,27.68l-34.32,-15.96z"/> |
||||||
|
<path android:fillColor="#4fc3f7" android:pathData="M27.22,225.91l20.35,-30.56l29.24,22.58l24.1,-27.94l27.32,24.84l25.84,-26.36l25.85,26.36l27.32,-24.84l24.1,27.94l29.24,-22.58l20.35,30.56"/> |
||||||
|
<path android:fillColor="#03a9f4" android:pathData="M280.93,233.84l-20.35,30.57l-29.24,-22.59l-24.1,27.95l-27.32,-24.84l-25.85,26.36l-25.84,-26.36l-27.32,24.84l-24.1,-27.95l-29.24,22.59l-20.35,-30.57"/> |
||||||
|
<path android:fillColor="#ffe0b2" android:pathData="M6.72,245.77a147.35,49.81 0,1 0,294.7 0a147.35,49.81 0,1 0,-294.7 0z"/> |
||||||
|
<path android:fillColor="#81d4fa" android:pathData="M308.15,234.77 L289.5,219.22l-21.58,31L237.06,228l-25.52,28.14 -28.88,-24.72L155.3,257.8 128,231.41 99.07,256.13 73.54,228 42.68,250.25l-21.58,-31L0,234.75 29.3,380.43C41,424.8 268.46,424.8 281,380.43Z"/> |
||||||
|
<path android:fillColor="#4fc3f7" android:pathData="M296.79,290a177.71,177.71 0,0 1,-14.08 22.93c-6.49,8.8 -12.95,17.78 -20.38,25.84 -7.2,7.83 -16.18,14 -24.61,20.32 -26.6,19.82 -63.2,26.79 -95.82,20.47C119.55,377.93 101.2,373 81.14,362c-27.72,-15.16 -49.54,-41.31 -65.72,-67.86 -1.86,-3.05 -3.63,-6.14 -5.34,-9.27L29.3,380.43C41,424.8 268.46,424.8 281,380.43l17.45,-93.7C297.92,287.82 297.36,288.91 296.79,290Z"/> |
||||||
|
<path android:fillColor="#29b6f6" android:pathData="M58.88,378.74a2,2 0,0 1,-2 -1.74L42.39,263.14a2,2 0,1 1,4 -0.51L60.87,376.49a2,2 0,0 1,-1.73 2.24Z"/> |
||||||
|
<path android:fillColor="#29b6f6" android:pathData="M104.17,385.44a2,2 0,0 1,-2 -1.92l-4.5,-116.09a2,2 0,1 1,4 -0.16l4.51,116.09a2,2 0,0 1,-1.92 2.08Z"/> |
||||||
|
<path android:fillColor="#29b6f6" android:pathData="M252.08,378.74h-0.26a2,2 0,0 1,-1.73 -2.24L264.6,262.63a2,2 0,1 1,4 0.51L254.06,377A2,2 0,0 1,252.08 378.74Z"/> |
||||||
|
<path android:fillColor="#29b6f6" android:pathData="M206.79,385.44h-0.08a2,2 0,0 1,-1.92 -2.08l4.5,-116.09a2,2 0,0 1,4 0.16l-4.5,116.09A2,2 0,0 1,206.79 385.44Z"/> |
||||||
|
<path android:fillColor="#29b6f6" android:pathData="M155.18,388.79a2,2 0,0 1,-2 -2V270.14a2,2 0,0 1,4 0V386.79A2,2 0,0 1,155.18 388.79Z"/> |
||||||
|
<path android:fillColor="#f06292" android:pathData="M174.42,0.11S186.94,47.44 104,57.92c0,0 -48.29,5.29 -33.19,37.35a21.64,21.64 0,0 1,-5.47 25.88C47.92,135.74 24.89,164.84 46.08,207a13.44,13.44 0,0 0,7.28 6.57c20.12,7.53 101.54,33.31 201.88,1.32a13.21,13.21 0,0 0,6.3 -4.34c6.57,-8.21 20.38,-31.37 -2.24,-60.91A26.16,26.16 0,0 1,254 135.12c-0.51,-9.9 -4.73,-27.17 -25.88,-39.45a13.57,13.57 0,0 1,-5.69 -16.92c4,-9.75 7.66,-24.1 2,-36.44C214.6,21.28 174.42,0.11 174.42,0.11Z"/> |
||||||
|
<path android:fillColor="#ec407a" android:pathData="M256,204.18c-18.82,3.85 -38.66,6.32 -58,5.56a342.08,342.08 0,0 1,-54.75 -7,191.23 191.23,0 0,1 -31,-9 372.7,372.7 0,0 1,-43.43 -19.84c-9.64,-5.25 -19.52,-11.32 -28.07,-18.59 -4.75,14.09 -4.81,31.38 5.4,51.71a13.44,13.44 0,0 0,7.28 6.57c20.12,7.53 101.54,33.31 201.88,1.31a13.12,13.12 0,0 0,6.3 -4.33,48.91 48.91,0 0,0 5.89,-9.43A105.18,105.18 0,0 1,256 204.18Z"/> |
||||||
|
<path android:fillColor="#f48fb1" android:pathData="M222.18,89c-28,24.79 -65.43,27.57 -102.41,21.79 -15.62,-2.44 -28.25,-11.48 -42.54,-4.72 -2.93,1.38 -6,4 -5.48,7.19 15.75,0.68 27.44,6.57 42.6,10.88 22.47,6.38 43.32,17.56 65.72,24.18s48,8.13 67.88,-4.07c2.46,-1.51 4.94,-3.39 5.87,-6.13a12.71,12.71 0,0 0,0.06 -6.31c-3.28,-18.77 -15,-33 -31.43,-42.81"/> |
||||||
|
<path android:fillColor="#673ab7" android:pathData="M108.057,137.999L141.83,124.422A3.105,3.11 68.099,0 1,145.874 126.143L145.874,126.143A3.105,3.11 68.099,0 1,144.146 130.184L110.373,143.761A3.105,3.11 68.099,0 1,106.329 142.04L106.329,142.04A3.105,3.11 68.099,0 1,108.057 137.999z"/> |
||||||
|
<path android:fillColor="#ffee58" android:pathData="M63.656,78.785L63.656,78.785A3.105,3.11 110.731,0 1,67.664 76.982L101.707,89.866A3.105,3.11 110.731,0 1,103.517 93.871L103.517,93.871A3.105,3.11 110.731,0 1,99.509 95.674L65.466,82.79A3.105,3.11 110.731,0 1,63.656 78.785z"/> |
||||||
|
<path android:fillColor="#80deea" android:pathData="M223.715,131.605L241.916,99.937A3.121,3.116 119.885,0 1,246.172 98.784L246.172,98.784A3.121,3.116 119.885,0 1,247.318 103.042L229.118,134.71A3.121,3.116 119.885,0 1,224.862 135.864L224.862,135.864A3.121,3.116 119.885,0 1,223.715 131.605z"/> |
||||||
|
<path android:fillColor="#8bc34a" android:pathData="M158.163,63.484L158.163,63.484A3.105,3.11 107.861,0 1,162.076 61.482L196.722,72.646A3.105,3.11 107.861,0 1,198.729 76.555L198.729,76.555A3.105,3.11 107.861,0 1,194.817 78.557L160.171,67.393A3.105,3.11 107.861,0 1,158.163 63.484z"/> |
||||||
|
<path android:fillColor="#673ab7" android:pathData="M181.372,45.493L201.621,15.246A3.11,3.105 123.799,0 1,205.931 14.389L205.931,14.389A3.11,3.105 123.799,0 1,206.781 18.7L186.532,48.948A3.11,3.105 123.799,0 1,182.222 49.805L182.222,49.805A3.11,3.105 123.799,0 1,181.372 45.493z"/> |
||||||
|
<path android:fillColor="#8bc34a" android:pathData="M132.014,205.938L152.263,175.691A3.11,3.105 123.799,0 1,156.574 174.834L156.574,174.834A3.11,3.105 123.799,0 1,157.424 179.145L137.175,209.393A3.11,3.105 123.799,0 1,132.864 210.25L132.864,210.25A3.11,3.105 123.799,0 1,132.014 205.938z"/> |
||||||
|
<path android:fillColor="#ffee58" android:pathData="M203.177,166.031L203.177,166.031A3.105,3.11 104.521,0 1,206.966 163.805L242.204,172.931A3.105,3.11 104.521,0 1,244.436 176.716L244.436,176.716A3.105,3.11 104.521,0 1,240.647 178.942L205.409,169.816A3.105,3.11 104.521,0 1,203.177 166.031z"/> |
||||||
|
<path android:fillColor="#80deea" android:pathData="M34.294,179.55L56.164,150.453A3.11,3.105 126.929,0 1,60.515 149.832L60.515,149.832A3.11,3.105 126.929,0 1,61.128 154.184L39.258,183.281A3.11,3.105 126.929,0 1,34.907 183.902L34.907,183.902A3.11,3.105 126.929,0 1,34.294 179.55z"/> |
||||||
|
<path android:fillColor="#f48fb1" android:pathData="M174.6,0.19c5.85,5.93 5.7,15.41 2.45,23.08a51.17,51.17 0,0 1,-16 20c-22,16.43 -49.79,24.94 -77.21,24.27 -1.61,0 -3.64,-0.43 -4,-2 1.47,-2.29 4.27,-3.29 6.89,-4 12.66,-3.58 26,-5.8 38.46,-10.07C148.61,43.36 169,33.86 174.42,0"/> |
||||||
|
</vector> |
@ -0,0 +1,28 @@ |
|||||||
|
<resources> |
||||||
|
<string name="app_name">Cupcake</string> |
||||||
|
<string name="order_cupcakes">Order Cupcakes</string> |
||||||
|
<string name="one_cupcake">One Cupcake</string> |
||||||
|
<string name="six_cupcakes">Six Cupcakes</string> |
||||||
|
<string name="twelve_cupcakes">Twelve Cupcakes</string> |
||||||
|
<string name="choose_flavor">Choose Flavor</string> |
||||||
|
<string name="vanilla">Vanilla</string> |
||||||
|
<string name="chocolate">Chocolate</string> |
||||||
|
<string name="red_velvet">Red Velvet</string> |
||||||
|
<string name="salted_caramel">Salted Caramel</string> |
||||||
|
<string name="coffee">Coffee</string> |
||||||
|
<string name="special_flavor">Special Flavor</string> |
||||||
|
<string name="cancel">Cancel</string> |
||||||
|
<string name="next">Next</string> |
||||||
|
<string name="choose_pickup_date">Choose Pickup Date</string> |
||||||
|
<string name="order_summary">Order Summary</string> |
||||||
|
<string name="send">Send Order to Another App</string> |
||||||
|
<string name="quantity">Quantity</string> |
||||||
|
<string name="flavor">Flavor</string> |
||||||
|
<string name="pickup_date">Pickup date</string> |
||||||
|
<string name="subtotal_price">Subtotal %1$s</string> |
||||||
|
<string name="total_price">Total %1$s</string> |
||||||
|
<string name="new_cupcake_order">New Cupcake Order</string> |
||||||
|
<string name="order_details">Quantity: %1$s \nFlavor: %2$s \nPickup date: %3$s \nTotal: %4$s \n\nThank you!</string> |
||||||
|
<string name="back_button">Back</string> |
||||||
|
<string name="cupcakes">%1$d cupcakes</string> |
||||||
|
</resources> |
@ -0,0 +1,10 @@ |
|||||||
|
import androidx.compose.runtime.Composable |
||||||
|
import org.jetbrains.nav_cupcake.CupcakeApp |
||||||
|
import org.jetbrains.nav_cupcake.ui.theme.CupcakeTheme |
||||||
|
|
||||||
|
@Composable |
||||||
|
fun App() { |
||||||
|
CupcakeTheme { |
||||||
|
CupcakeApp() |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,185 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2023 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 |
||||||
|
* |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
package org.jetbrains.nav_cupcake |
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.fillMaxHeight |
||||||
|
import androidx.compose.foundation.layout.fillMaxSize |
||||||
|
import androidx.compose.foundation.layout.padding |
||||||
|
import androidx.compose.foundation.rememberScrollState |
||||||
|
import androidx.compose.foundation.verticalScroll |
||||||
|
import androidx.compose.material.icons.Icons |
||||||
|
import androidx.compose.material.icons.filled.ArrowBack |
||||||
|
import androidx.compose.material3.* |
||||||
|
import androidx.compose.runtime.Composable |
||||||
|
import androidx.compose.runtime.collectAsState |
||||||
|
import androidx.compose.runtime.getValue |
||||||
|
import androidx.compose.ui.Modifier |
||||||
|
import androidx.compose.ui.unit.dp |
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel |
||||||
|
import androidx.navigation.NavHostController |
||||||
|
import androidx.navigation.compose.NavHost |
||||||
|
import androidx.navigation.compose.composable |
||||||
|
import androidx.navigation.compose.currentBackStackEntryAsState |
||||||
|
import androidx.navigation.compose.rememberNavController |
||||||
|
import org.jetbrains.nav_cupcake.data.DataSource |
||||||
|
import org.jetbrains.nav_cupcake.data.OrderUiState |
||||||
|
import org.jetbrains.nav_cupcake.ui.OrderSummaryScreen |
||||||
|
import org.jetbrains.nav_cupcake.ui.OrderViewModel |
||||||
|
import org.jetbrains.nav_cupcake.ui.SelectOptionScreen |
||||||
|
import org.jetbrains.nav_cupcake.ui.StartOrderScreen |
||||||
|
import cupcake.composeapp.generated.resources.* |
||||||
|
import org.jetbrains.compose.resources.StringResource |
||||||
|
import org.jetbrains.compose.resources.stringResource |
||||||
|
|
||||||
|
/** |
||||||
|
* enum values that represent the screens in the app |
||||||
|
*/ |
||||||
|
enum class CupcakeScreen(val title: StringResource) { |
||||||
|
Start(title = Res.string.app_name), |
||||||
|
Flavor(title = Res.string.choose_flavor), |
||||||
|
Pickup(title = Res.string.choose_pickup_date), |
||||||
|
Summary(title = Res.string.order_summary) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Composable that displays the topBar and displays back button if back navigation is possible. |
||||||
|
*/ |
||||||
|
@Composable |
||||||
|
fun CupcakeAppBar( |
||||||
|
currentScreen: CupcakeScreen, |
||||||
|
canNavigateBack: Boolean, |
||||||
|
navigateUp: () -> Unit, |
||||||
|
modifier: Modifier = Modifier |
||||||
|
) { |
||||||
|
TopAppBar( |
||||||
|
title = { Text(stringResource(currentScreen.title)) }, |
||||||
|
colors = TopAppBarDefaults.mediumTopAppBarColors( |
||||||
|
containerColor = MaterialTheme.colorScheme.primaryContainer |
||||||
|
), |
||||||
|
modifier = modifier, |
||||||
|
navigationIcon = { |
||||||
|
if (canNavigateBack) { |
||||||
|
IconButton(onClick = navigateUp) { |
||||||
|
Icon( |
||||||
|
imageVector = Icons.Filled.ArrowBack, |
||||||
|
contentDescription = stringResource(Res.string.back_button) |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
@Composable |
||||||
|
fun CupcakeApp( |
||||||
|
viewModel: OrderViewModel = viewModel { OrderViewModel() }, |
||||||
|
navController: NavHostController = rememberNavController() |
||||||
|
) { |
||||||
|
// Get current back stack entry |
||||||
|
val backStackEntry by navController.currentBackStackEntryAsState() |
||||||
|
// Get the name of the current screen |
||||||
|
val currentScreen = CupcakeScreen.valueOf( |
||||||
|
backStackEntry?.destination?.route ?: CupcakeScreen.Start.name |
||||||
|
) |
||||||
|
|
||||||
|
Scaffold( |
||||||
|
topBar = { |
||||||
|
CupcakeAppBar( |
||||||
|
currentScreen = currentScreen, |
||||||
|
canNavigateBack = navController.previousBackStackEntry != null, |
||||||
|
navigateUp = { navController.navigateUp() } |
||||||
|
) |
||||||
|
} |
||||||
|
) { innerPadding -> |
||||||
|
val uiState by viewModel.uiState.collectAsState() |
||||||
|
|
||||||
|
NavHost( |
||||||
|
navController = navController, |
||||||
|
startDestination = CupcakeScreen.Start.name, |
||||||
|
modifier = Modifier |
||||||
|
.fillMaxSize() |
||||||
|
.verticalScroll(rememberScrollState()) |
||||||
|
.padding(innerPadding) |
||||||
|
) { |
||||||
|
composable(route = CupcakeScreen.Start.name) { |
||||||
|
StartOrderScreen( |
||||||
|
quantityOptions = DataSource.quantityOptions, |
||||||
|
onNextButtonClicked = { |
||||||
|
viewModel.setQuantity(it) |
||||||
|
navController.navigate(CupcakeScreen.Flavor.name) |
||||||
|
}, |
||||||
|
modifier = Modifier |
||||||
|
.fillMaxSize() |
||||||
|
.padding(16.dp) |
||||||
|
) |
||||||
|
} |
||||||
|
composable(route = CupcakeScreen.Flavor.name) { |
||||||
|
SelectOptionScreen( |
||||||
|
subtotal = uiState.price, |
||||||
|
onNextButtonClicked = { navController.navigate(CupcakeScreen.Pickup.name) }, |
||||||
|
onCancelButtonClicked = { |
||||||
|
cancelOrderAndNavigateToStart(viewModel, navController) |
||||||
|
}, |
||||||
|
options = DataSource.flavors.map { id -> stringResource(id) }, |
||||||
|
onSelectionChanged = { viewModel.setFlavor(it) }, |
||||||
|
modifier = Modifier.fillMaxHeight() |
||||||
|
) |
||||||
|
} |
||||||
|
composable(route = CupcakeScreen.Pickup.name) { |
||||||
|
SelectOptionScreen( |
||||||
|
subtotal = uiState.price, |
||||||
|
onNextButtonClicked = { navController.navigate(CupcakeScreen.Summary.name) }, |
||||||
|
onCancelButtonClicked = { |
||||||
|
cancelOrderAndNavigateToStart(viewModel, navController) |
||||||
|
}, |
||||||
|
options = uiState.pickupOptions, |
||||||
|
onSelectionChanged = { viewModel.setDate(it) }, |
||||||
|
modifier = Modifier.fillMaxHeight() |
||||||
|
) |
||||||
|
} |
||||||
|
composable(route = CupcakeScreen.Summary.name) { |
||||||
|
OrderSummaryScreen( |
||||||
|
orderUiState = uiState, |
||||||
|
onCancelButtonClicked = { |
||||||
|
cancelOrderAndNavigateToStart(viewModel, navController) |
||||||
|
}, |
||||||
|
onSendButtonClicked = { subject: String, summary: String -> |
||||||
|
shareOrder(subject = subject, summary = summary) |
||||||
|
}, |
||||||
|
modifier = Modifier.fillMaxHeight() |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Resets the [OrderUiState] and pops up to [CupcakeScreen.Start] |
||||||
|
*/ |
||||||
|
private fun cancelOrderAndNavigateToStart( |
||||||
|
viewModel: OrderViewModel, |
||||||
|
navController: NavHostController |
||||||
|
) { |
||||||
|
viewModel.resetOrder() |
||||||
|
navController.popBackStack(CupcakeScreen.Start.name, inclusive = false) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates an intent to share order details |
||||||
|
*/ |
||||||
|
private fun shareOrder(subject: String, summary: String) { |
||||||
|
// TODO |
||||||
|
} |
@ -0,0 +1,35 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2023 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 |
||||||
|
* |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
package org.jetbrains.nav_cupcake.data |
||||||
|
|
||||||
|
import cupcake.composeapp.generated.resources.Res |
||||||
|
import cupcake.composeapp.generated.resources.* |
||||||
|
|
||||||
|
object DataSource { |
||||||
|
val flavors = listOf( |
||||||
|
Res.string.vanilla, |
||||||
|
Res.string.red_velvet, |
||||||
|
Res.string.chocolate, |
||||||
|
Res.string.salted_caramel, |
||||||
|
Res.string.coffee |
||||||
|
) |
||||||
|
|
||||||
|
val quantityOptions = listOf( |
||||||
|
Pair(Res.string.one_cupcake, 1), |
||||||
|
Pair(Res.string.six_cupcakes, 6), |
||||||
|
Pair(Res.string.twelve_cupcakes, 12) |
||||||
|
) |
||||||
|
} |
@ -0,0 +1,33 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2023 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 |
||||||
|
* |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
package org.jetbrains.nav_cupcake.data |
||||||
|
|
||||||
|
/** |
||||||
|
* Data class that represents the current UI state in terms of [quantity], [flavor], |
||||||
|
* [dateOptions], selected pickup [date] and [price] |
||||||
|
*/ |
||||||
|
data class OrderUiState( |
||||||
|
/** Selected cupcake quantity (1, 6, 12) */ |
||||||
|
val quantity: Int = 0, |
||||||
|
/** Flavor of the cupcakes in the order (such as "Chocolate", "Vanilla", etc..) */ |
||||||
|
val flavor: String = "", |
||||||
|
/** Selected date for pickup (such as "Jan 1") */ |
||||||
|
val date: String = "", |
||||||
|
/** Total price for the order */ |
||||||
|
val price: String = "", |
||||||
|
/** Available pickup dates for the order*/ |
||||||
|
val pickupOptions: List<String> = listOf() |
||||||
|
) |
@ -0,0 +1,114 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2023 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 |
||||||
|
* |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
package org.jetbrains.nav_cupcake.ui |
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel |
||||||
|
import org.jetbrains.nav_cupcake.data.OrderUiState |
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow |
||||||
|
import kotlinx.coroutines.flow.StateFlow |
||||||
|
import kotlinx.coroutines.flow.asStateFlow |
||||||
|
import kotlinx.coroutines.flow.update |
||||||
|
import kotlinx.datetime.* |
||||||
|
|
||||||
|
/** Price for a single cupcake */ |
||||||
|
private const val PRICE_PER_CUPCAKE = 2.00 |
||||||
|
|
||||||
|
/** Additional cost for same day pickup of an order */ |
||||||
|
private const val PRICE_FOR_SAME_DAY_PICKUP = 3.00 |
||||||
|
|
||||||
|
/** |
||||||
|
* [OrderViewModel] holds information about a cupcake order in terms of quantity, flavor, and |
||||||
|
* pickup date. It also knows how to calculate the total price based on these order details. |
||||||
|
*/ |
||||||
|
class OrderViewModel : ViewModel() { |
||||||
|
|
||||||
|
/** |
||||||
|
* Cupcake state for this order |
||||||
|
*/ |
||||||
|
private val _uiState = MutableStateFlow(OrderUiState(pickupOptions = pickupOptions())) |
||||||
|
val uiState: StateFlow<OrderUiState> = _uiState.asStateFlow() |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the quantity [numberCupcakes] of cupcakes for this order's state and update the price |
||||||
|
*/ |
||||||
|
fun setQuantity(numberCupcakes: Int) { |
||||||
|
_uiState.update { currentState -> |
||||||
|
currentState.copy( |
||||||
|
quantity = numberCupcakes, |
||||||
|
price = calculatePrice(quantity = numberCupcakes) |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the [desiredFlavor] of cupcakes for this order's state. |
||||||
|
* Only 1 flavor can be selected for the whole order. |
||||||
|
*/ |
||||||
|
fun setFlavor(desiredFlavor: String) { |
||||||
|
_uiState.update { currentState -> |
||||||
|
currentState.copy(flavor = desiredFlavor) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the [pickupDate] for this order's state and update the price |
||||||
|
*/ |
||||||
|
fun setDate(pickupDate: String) { |
||||||
|
_uiState.update { currentState -> |
||||||
|
currentState.copy( |
||||||
|
date = pickupDate, |
||||||
|
price = calculatePrice(pickupDate = pickupDate) |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Reset the order state |
||||||
|
*/ |
||||||
|
fun resetOrder() { |
||||||
|
_uiState.value = OrderUiState(pickupOptions = pickupOptions()) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the calculated price based on the order details. |
||||||
|
*/ |
||||||
|
private fun calculatePrice( |
||||||
|
quantity: Int = _uiState.value.quantity, |
||||||
|
pickupDate: String = _uiState.value.date |
||||||
|
): String { |
||||||
|
var calculatedPrice = quantity * PRICE_PER_CUPCAKE |
||||||
|
// If the user selected the first option (today) for pickup, add the surcharge |
||||||
|
if (pickupOptions()[0] == pickupDate) { |
||||||
|
calculatedPrice += PRICE_FOR_SAME_DAY_PICKUP |
||||||
|
} |
||||||
|
return "$calculatedPrice€" |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns a list of date options starting with the current date and the following 3 dates. |
||||||
|
*/ |
||||||
|
private fun pickupOptions(): List<String> { |
||||||
|
val dateOptions = mutableListOf<String>() |
||||||
|
val now = Clock.System.now() |
||||||
|
val timeZone = TimeZone.currentSystemDefault() |
||||||
|
// add current date and the following 3 dates. |
||||||
|
repeat(4) { |
||||||
|
val day = now.plus(it, DateTimeUnit.DAY, timeZone) |
||||||
|
dateOptions.add(day.toLocalDateTime(timeZone).date.toString()) |
||||||
|
} |
||||||
|
return dateOptions |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,135 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2023 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 |
||||||
|
* |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
package org.jetbrains.nav_cupcake.ui |
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Arrangement |
||||||
|
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.padding |
||||||
|
import androidx.compose.foundation.selection.selectable |
||||||
|
import androidx.compose.material3.* |
||||||
|
import androidx.compose.runtime.Composable |
||||||
|
import androidx.compose.runtime.getValue |
||||||
|
import androidx.compose.runtime.mutableStateOf |
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable |
||||||
|
import androidx.compose.runtime.setValue |
||||||
|
import androidx.compose.ui.Alignment |
||||||
|
import androidx.compose.ui.Modifier |
||||||
|
import androidx.compose.ui.unit.dp |
||||||
|
import org.jetbrains.nav_cupcake.ui.components.FormattedPriceLabel |
||||||
|
import org.jetbrains.nav_cupcake.ui.theme.CupcakeTheme |
||||||
|
import cupcake.composeapp.generated.resources.Res |
||||||
|
import cupcake.composeapp.generated.resources.cancel |
||||||
|
import cupcake.composeapp.generated.resources.next |
||||||
|
import org.jetbrains.compose.resources.stringResource |
||||||
|
import org.jetbrains.compose.ui.tooling.preview.Preview |
||||||
|
|
||||||
|
/** |
||||||
|
* Composable that displays the list of items as [RadioButton] options, |
||||||
|
* [onSelectionChanged] lambda that notifies the parent composable when a new value is selected, |
||||||
|
* [onCancelButtonClicked] lambda that cancels the order when user clicks cancel and |
||||||
|
* [onNextButtonClicked] lambda that triggers the navigation to next screen |
||||||
|
*/ |
||||||
|
@Composable |
||||||
|
fun SelectOptionScreen( |
||||||
|
subtotal: String, |
||||||
|
options: List<String>, |
||||||
|
onSelectionChanged: (String) -> Unit = {}, |
||||||
|
onCancelButtonClicked: () -> Unit = {}, |
||||||
|
onNextButtonClicked: () -> Unit = {}, |
||||||
|
modifier: Modifier = Modifier |
||||||
|
) { |
||||||
|
var selectedValue by rememberSaveable { mutableStateOf("") } |
||||||
|
|
||||||
|
Column( |
||||||
|
modifier = modifier, |
||||||
|
verticalArrangement = Arrangement.SpaceBetween |
||||||
|
) { |
||||||
|
Column(modifier = Modifier.padding(16.dp)) { |
||||||
|
options.forEach { item -> |
||||||
|
Row( |
||||||
|
modifier = Modifier.selectable( |
||||||
|
selected = selectedValue == item, |
||||||
|
onClick = { |
||||||
|
selectedValue = item |
||||||
|
onSelectionChanged(item) |
||||||
|
} |
||||||
|
), |
||||||
|
verticalAlignment = Alignment.CenterVertically |
||||||
|
) { |
||||||
|
RadioButton( |
||||||
|
selected = selectedValue == item, |
||||||
|
onClick = { |
||||||
|
selectedValue = item |
||||||
|
onSelectionChanged(item) |
||||||
|
} |
||||||
|
) |
||||||
|
Text(item) |
||||||
|
} |
||||||
|
} |
||||||
|
HorizontalDivider( |
||||||
|
thickness = 1.dp, |
||||||
|
modifier = Modifier.padding(bottom = 16.dp) |
||||||
|
) |
||||||
|
FormattedPriceLabel( |
||||||
|
subtotal = subtotal, |
||||||
|
modifier = Modifier |
||||||
|
.align(Alignment.End) |
||||||
|
.padding( |
||||||
|
top = 16.dp, |
||||||
|
bottom = 16.dp |
||||||
|
) |
||||||
|
) |
||||||
|
} |
||||||
|
Row( |
||||||
|
modifier = Modifier |
||||||
|
.fillMaxWidth() |
||||||
|
.padding(16.dp), |
||||||
|
horizontalArrangement = Arrangement.spacedBy(16.dp), |
||||||
|
verticalAlignment = Alignment.Bottom |
||||||
|
) { |
||||||
|
OutlinedButton( |
||||||
|
modifier = Modifier.weight(1f), |
||||||
|
onClick = onCancelButtonClicked |
||||||
|
) { |
||||||
|
Text(stringResource(Res.string.cancel)) |
||||||
|
} |
||||||
|
Button( |
||||||
|
modifier = Modifier.weight(1f), |
||||||
|
// the button is enabled when the user makes a selection |
||||||
|
enabled = selectedValue.isNotEmpty(), |
||||||
|
onClick = onNextButtonClicked |
||||||
|
) { |
||||||
|
Text(stringResource(Res.string.next)) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Preview |
||||||
|
@Composable |
||||||
|
fun SelectOptionPreview() { |
||||||
|
CupcakeTheme { |
||||||
|
SelectOptionScreen( |
||||||
|
subtotal = "299.99", |
||||||
|
options = listOf("Option 1", "Option 2", "Option 3", "Option 4"), |
||||||
|
modifier = Modifier.fillMaxHeight() |
||||||
|
) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,116 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2023 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 |
||||||
|
* |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
package org.jetbrains.nav_cupcake.ui |
||||||
|
|
||||||
|
import androidx.compose.foundation.Image |
||||||
|
import androidx.compose.foundation.layout.* |
||||||
|
import androidx.compose.material3.Button |
||||||
|
import androidx.compose.material3.MaterialTheme |
||||||
|
import androidx.compose.material3.Text |
||||||
|
import androidx.compose.runtime.Composable |
||||||
|
import androidx.compose.ui.Alignment |
||||||
|
import androidx.compose.ui.Modifier |
||||||
|
import androidx.compose.ui.unit.dp |
||||||
|
import org.jetbrains.nav_cupcake.data.DataSource |
||||||
|
import org.jetbrains.nav_cupcake.ui.theme.CupcakeTheme |
||||||
|
import cupcake.composeapp.generated.resources.Res |
||||||
|
import cupcake.composeapp.generated.resources.cupcake |
||||||
|
import cupcake.composeapp.generated.resources.order_cupcakes |
||||||
|
import org.jetbrains.compose.resources.StringResource |
||||||
|
import org.jetbrains.compose.resources.painterResource |
||||||
|
import org.jetbrains.compose.resources.stringResource |
||||||
|
import org.jetbrains.compose.ui.tooling.preview.Preview |
||||||
|
|
||||||
|
/** |
||||||
|
* Composable that allows the user to select the desired cupcake quantity and expects |
||||||
|
* [onNextButtonClicked] lambda that expects the selected quantity and triggers the navigation to |
||||||
|
* next screen |
||||||
|
*/ |
||||||
|
@Composable |
||||||
|
fun StartOrderScreen( |
||||||
|
quantityOptions: List<Pair<StringResource, Int>>, |
||||||
|
onNextButtonClicked: (Int) -> Unit, |
||||||
|
modifier: Modifier = Modifier |
||||||
|
) { |
||||||
|
Column( |
||||||
|
modifier = modifier, |
||||||
|
verticalArrangement = Arrangement.SpaceBetween |
||||||
|
) { |
||||||
|
Column( |
||||||
|
modifier = Modifier.fillMaxWidth(), |
||||||
|
horizontalAlignment = Alignment.CenterHorizontally, |
||||||
|
verticalArrangement = Arrangement.spacedBy(8.dp) |
||||||
|
) { |
||||||
|
Spacer(modifier = Modifier.height(16.dp)) |
||||||
|
Image( |
||||||
|
painter = painterResource(Res.drawable.cupcake), |
||||||
|
contentDescription = null, |
||||||
|
modifier = Modifier.width(300.dp) |
||||||
|
) |
||||||
|
Spacer(modifier = Modifier.height(16.dp)) |
||||||
|
Text( |
||||||
|
text = stringResource(Res.string.order_cupcakes), |
||||||
|
style = MaterialTheme.typography.headlineSmall |
||||||
|
) |
||||||
|
Spacer(modifier = Modifier.height(8.dp)) |
||||||
|
} |
||||||
|
Column( |
||||||
|
modifier = Modifier.fillMaxWidth(), |
||||||
|
horizontalAlignment = Alignment.CenterHorizontally, |
||||||
|
verticalArrangement = Arrangement.spacedBy(16.dp) |
||||||
|
) { |
||||||
|
quantityOptions.forEach { item -> |
||||||
|
SelectQuantityButton( |
||||||
|
labelResource = item.first, |
||||||
|
onClick = { onNextButtonClicked(item.second) }, |
||||||
|
modifier = Modifier.fillMaxWidth(), |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Customizable button composable that displays the [labelResourceId] |
||||||
|
* and triggers [onClick] lambda when this composable is clicked |
||||||
|
*/ |
||||||
|
@Composable |
||||||
|
fun SelectQuantityButton( |
||||||
|
labelResource: StringResource, |
||||||
|
onClick: () -> Unit, |
||||||
|
modifier: Modifier = Modifier |
||||||
|
) { |
||||||
|
Button( |
||||||
|
onClick = onClick, |
||||||
|
modifier = modifier.widthIn(min = 250.dp) |
||||||
|
) { |
||||||
|
Text(stringResource(labelResource)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Preview |
||||||
|
@Composable |
||||||
|
fun StartOrderPreview() { |
||||||
|
CupcakeTheme { |
||||||
|
StartOrderScreen( |
||||||
|
quantityOptions = DataSource.quantityOptions, |
||||||
|
onNextButtonClicked = {}, |
||||||
|
modifier = Modifier |
||||||
|
.fillMaxSize() |
||||||
|
.padding(16.dp) |
||||||
|
) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,123 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2023 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 |
||||||
|
* |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
package org.jetbrains.nav_cupcake.ui |
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.* |
||||||
|
import androidx.compose.material3.Button |
||||||
|
import androidx.compose.material3.HorizontalDivider |
||||||
|
import androidx.compose.material3.OutlinedButton |
||||||
|
import androidx.compose.material3.Text |
||||||
|
import androidx.compose.runtime.Composable |
||||||
|
import androidx.compose.ui.Alignment |
||||||
|
import androidx.compose.ui.Modifier |
||||||
|
import androidx.compose.ui.text.font.FontWeight |
||||||
|
import androidx.compose.ui.unit.dp |
||||||
|
import org.jetbrains.nav_cupcake.data.OrderUiState |
||||||
|
import org.jetbrains.nav_cupcake.ui.components.FormattedPriceLabel |
||||||
|
import org.jetbrains.nav_cupcake.ui.theme.CupcakeTheme |
||||||
|
import cupcake.composeapp.generated.resources.* |
||||||
|
import org.jetbrains.compose.resources.stringResource |
||||||
|
import org.jetbrains.compose.ui.tooling.preview.Preview |
||||||
|
|
||||||
|
/** |
||||||
|
* This composable expects [orderUiState] that represents the order state, [onCancelButtonClicked] |
||||||
|
* lambda that triggers canceling the order and passes the final order to [onSendButtonClicked] |
||||||
|
* lambda |
||||||
|
*/ |
||||||
|
@Composable |
||||||
|
fun OrderSummaryScreen( |
||||||
|
orderUiState: OrderUiState, |
||||||
|
onCancelButtonClicked: () -> Unit, |
||||||
|
onSendButtonClicked: (String, String) -> Unit, |
||||||
|
modifier: Modifier = Modifier |
||||||
|
) { |
||||||
|
val numberOfCupcakes = stringResource( |
||||||
|
Res.string.cupcakes, // TODO: plurals |
||||||
|
orderUiState.quantity |
||||||
|
) |
||||||
|
//Load and format a string resource with the parameters. |
||||||
|
val orderSummary = stringResource( |
||||||
|
Res.string.order_details, |
||||||
|
numberOfCupcakes, |
||||||
|
orderUiState.flavor, |
||||||
|
orderUiState.date, |
||||||
|
orderUiState.quantity |
||||||
|
) |
||||||
|
val newOrder = stringResource(Res.string.new_cupcake_order) |
||||||
|
//Create a list of order summary to display |
||||||
|
val items = listOf( |
||||||
|
// Summary line 1: display selected quantity |
||||||
|
Pair(stringResource(Res.string.quantity), numberOfCupcakes), |
||||||
|
// Summary line 2: display selected flavor |
||||||
|
Pair(stringResource(Res.string.flavor), orderUiState.flavor), |
||||||
|
// Summary line 3: display selected pickup date |
||||||
|
Pair(stringResource(Res.string.pickup_date), orderUiState.date) |
||||||
|
) |
||||||
|
|
||||||
|
Column( |
||||||
|
modifier = modifier, |
||||||
|
verticalArrangement = Arrangement.SpaceBetween |
||||||
|
) { |
||||||
|
Column( |
||||||
|
modifier = Modifier.padding(16.dp), |
||||||
|
verticalArrangement = Arrangement.spacedBy(8.dp) |
||||||
|
) { |
||||||
|
items.forEach { item -> |
||||||
|
Text(item.first.uppercase()) |
||||||
|
Text(text = item.second, fontWeight = FontWeight.Bold) |
||||||
|
HorizontalDivider(thickness = 1.dp) |
||||||
|
} |
||||||
|
Spacer(modifier = Modifier.height(8.dp)) |
||||||
|
FormattedPriceLabel( |
||||||
|
subtotal = orderUiState.price, |
||||||
|
modifier = Modifier.align(Alignment.End) |
||||||
|
) |
||||||
|
} |
||||||
|
Row( |
||||||
|
modifier = Modifier.padding(16.dp) |
||||||
|
) { |
||||||
|
Column( |
||||||
|
verticalArrangement = Arrangement.spacedBy(8.dp) |
||||||
|
) { |
||||||
|
Button( |
||||||
|
modifier = Modifier.fillMaxWidth(), |
||||||
|
onClick = { onSendButtonClicked(newOrder, orderSummary) } |
||||||
|
) { |
||||||
|
Text(stringResource(Res.string.send)) |
||||||
|
} |
||||||
|
OutlinedButton( |
||||||
|
modifier = Modifier.fillMaxWidth(), |
||||||
|
onClick = onCancelButtonClicked |
||||||
|
) { |
||||||
|
Text(stringResource(Res.string.cancel)) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Preview |
||||||
|
@Composable |
||||||
|
fun OrderSummaryPreview() { |
||||||
|
CupcakeTheme { |
||||||
|
OrderSummaryScreen( |
||||||
|
orderUiState = OrderUiState(0, "Test", "Test", "$300.00"), |
||||||
|
onSendButtonClicked = { subject: String, summary: String -> }, |
||||||
|
onCancelButtonClicked = {}, |
||||||
|
modifier = Modifier.fillMaxHeight() |
||||||
|
) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,36 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2023 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 |
||||||
|
* |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
package org.jetbrains.nav_cupcake.ui.components |
||||||
|
|
||||||
|
import androidx.compose.material3.MaterialTheme |
||||||
|
import androidx.compose.material3.Text |
||||||
|
import androidx.compose.runtime.Composable |
||||||
|
import androidx.compose.ui.Modifier |
||||||
|
import cupcake.composeapp.generated.resources.Res |
||||||
|
import cupcake.composeapp.generated.resources.subtotal_price |
||||||
|
import org.jetbrains.compose.resources.stringResource |
||||||
|
|
||||||
|
/** |
||||||
|
* Composable that displays formatted [price] that will be formatted and displayed on screen |
||||||
|
*/ |
||||||
|
@Composable |
||||||
|
fun FormattedPriceLabel(subtotal: String, modifier: Modifier = Modifier) { |
||||||
|
Text( |
||||||
|
text = stringResource(Res.string.subtotal_price, subtotal), |
||||||
|
modifier = modifier, |
||||||
|
style = MaterialTheme.typography.headlineSmall |
||||||
|
) |
||||||
|
} |
@ -0,0 +1,78 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2023 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 |
||||||
|
* |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
package org.jetbrains.nav_cupcake.ui.theme |
||||||
|
|
||||||
|
import androidx.compose.ui.graphics.Color |
||||||
|
|
||||||
|
val md_theme_light_primary = Color(0xFF984062) |
||||||
|
val md_theme_light_onPrimary = Color(0xFFFFFFFF) |
||||||
|
val md_theme_light_primaryContainer = Color(0xFFFFD9E2) |
||||||
|
val md_theme_light_onPrimaryContainer = Color(0xFF3E001E) |
||||||
|
val md_theme_light_secondary = Color(0xFF74565F) |
||||||
|
val md_theme_light_onSecondary = Color(0xFFFFFFFF) |
||||||
|
val md_theme_light_secondaryContainer = Color(0xFFFFD9E2) |
||||||
|
val md_theme_light_onSecondaryContainer = Color(0xFF2B151C) |
||||||
|
val md_theme_light_tertiary = Color(0xFF7C5635) |
||||||
|
val md_theme_light_onTertiary = Color(0xFFFFFFFF) |
||||||
|
val md_theme_light_tertiaryContainer = Color(0xFFFFDCC2) |
||||||
|
val md_theme_light_onTertiaryContainer = Color(0xFF2E1500) |
||||||
|
val md_theme_light_error = Color(0xFFBA1A1A) |
||||||
|
val md_theme_light_errorContainer = Color(0xFFFFDAD6) |
||||||
|
val md_theme_light_onError = Color(0xFFFFFFFF) |
||||||
|
val md_theme_light_onErrorContainer = Color(0xFF410002) |
||||||
|
val md_theme_light_background = Color(0xFFFFFBFF) |
||||||
|
val md_theme_light_onBackground = Color(0xFF201A1B) |
||||||
|
val md_theme_light_surface = Color(0xFFFFFBFF) |
||||||
|
val md_theme_light_onSurface = Color(0xFF201A1B) |
||||||
|
val md_theme_light_surfaceVariant = Color(0xFFF2DDE2) |
||||||
|
val md_theme_light_onSurfaceVariant = Color(0xFF514347) |
||||||
|
val md_theme_light_outline = Color(0xFF837377) |
||||||
|
val md_theme_light_inverseOnSurface = Color(0xFFFAEEEF) |
||||||
|
val md_theme_light_inverseSurface = Color(0xFF352F30) |
||||||
|
val md_theme_light_inversePrimary = Color(0xFFFFB0C9) |
||||||
|
val md_theme_light_surfaceTint = Color(0xFF984062) |
||||||
|
val md_theme_light_outlineVariant = Color(0xFFD5C2C6) |
||||||
|
val md_theme_light_scrim = Color(0xFF000000) |
||||||
|
|
||||||
|
val md_theme_dark_primary = Color(0xFFFFB0C9) |
||||||
|
val md_theme_dark_onPrimary = Color(0xFF5E1133) |
||||||
|
val md_theme_dark_primaryContainer = Color(0xFF7B294A) |
||||||
|
val md_theme_dark_onPrimaryContainer = Color(0xFFFFD9E2) |
||||||
|
val md_theme_dark_secondary = Color(0xFFE2BDC7) |
||||||
|
val md_theme_dark_onSecondary = Color(0xFF422931) |
||||||
|
val md_theme_dark_secondaryContainer = Color(0xFF5A3F47) |
||||||
|
val md_theme_dark_onSecondaryContainer = Color(0xFFFFD9E2) |
||||||
|
val md_theme_dark_tertiary = Color(0xFFEFBD94) |
||||||
|
val md_theme_dark_onTertiary = Color(0xFF48290C) |
||||||
|
val md_theme_dark_tertiaryContainer = Color(0xFF623F20) |
||||||
|
val md_theme_dark_onTertiaryContainer = Color(0xFFFFDCC2) |
||||||
|
val md_theme_dark_error = Color(0xFFFFB4AB) |
||||||
|
val md_theme_dark_errorContainer = Color(0xFF93000A) |
||||||
|
val md_theme_dark_onError = Color(0xFF690005) |
||||||
|
val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6) |
||||||
|
val md_theme_dark_background = Color(0xFF201A1B) |
||||||
|
val md_theme_dark_onBackground = Color(0xFFEBE0E1) |
||||||
|
val md_theme_dark_surface = Color(0xFF201A1B) |
||||||
|
val md_theme_dark_onSurface = Color(0xFFEBE0E1) |
||||||
|
val md_theme_dark_surfaceVariant = Color(0xFF514347) |
||||||
|
val md_theme_dark_onSurfaceVariant = Color(0xFFD5C2C6) |
||||||
|
val md_theme_dark_outline = Color(0xFF9E8C90) |
||||||
|
val md_theme_dark_inverseOnSurface = Color(0xFF201A1B) |
||||||
|
val md_theme_dark_inverseSurface = Color(0xFFEBE0E1) |
||||||
|
val md_theme_dark_inversePrimary = Color(0xFF984062) |
||||||
|
val md_theme_dark_surfaceTint = Color(0xFFFFB0C9) |
||||||
|
val md_theme_dark_outlineVariant = Color(0xFF514347) |
||||||
|
val md_theme_dark_scrim = Color(0xFF000000) |
@ -0,0 +1,102 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2023 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 |
||||||
|
* |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
package org.jetbrains.nav_cupcake.ui.theme |
||||||
|
|
||||||
|
import androidx.compose.foundation.isSystemInDarkTheme |
||||||
|
import androidx.compose.material3.MaterialTheme |
||||||
|
import androidx.compose.material3.darkColorScheme |
||||||
|
import androidx.compose.material3.lightColorScheme |
||||||
|
import androidx.compose.runtime.Composable |
||||||
|
|
||||||
|
private val LightColors = lightColorScheme( |
||||||
|
primary = md_theme_light_primary, |
||||||
|
onPrimary = md_theme_light_onPrimary, |
||||||
|
primaryContainer = md_theme_light_primaryContainer, |
||||||
|
onPrimaryContainer = md_theme_light_onPrimaryContainer, |
||||||
|
secondary = md_theme_light_secondary, |
||||||
|
onSecondary = md_theme_light_onSecondary, |
||||||
|
secondaryContainer = md_theme_light_secondaryContainer, |
||||||
|
onSecondaryContainer = md_theme_light_onSecondaryContainer, |
||||||
|
tertiary = md_theme_light_tertiary, |
||||||
|
onTertiary = md_theme_light_onTertiary, |
||||||
|
tertiaryContainer = md_theme_light_tertiaryContainer, |
||||||
|
onTertiaryContainer = md_theme_light_onTertiaryContainer, |
||||||
|
error = md_theme_light_error, |
||||||
|
errorContainer = md_theme_light_errorContainer, |
||||||
|
onError = md_theme_light_onError, |
||||||
|
onErrorContainer = md_theme_light_onErrorContainer, |
||||||
|
background = md_theme_light_background, |
||||||
|
onBackground = md_theme_light_onBackground, |
||||||
|
surface = md_theme_light_surface, |
||||||
|
onSurface = md_theme_light_onSurface, |
||||||
|
surfaceVariant = md_theme_light_surfaceVariant, |
||||||
|
onSurfaceVariant = md_theme_light_onSurfaceVariant, |
||||||
|
outline = md_theme_light_outline, |
||||||
|
inverseOnSurface = md_theme_light_inverseOnSurface, |
||||||
|
inverseSurface = md_theme_light_inverseSurface, |
||||||
|
inversePrimary = md_theme_light_inversePrimary, |
||||||
|
surfaceTint = md_theme_light_surfaceTint, |
||||||
|
outlineVariant = md_theme_light_outlineVariant, |
||||||
|
scrim = md_theme_light_scrim, |
||||||
|
) |
||||||
|
|
||||||
|
private val DarkColors = darkColorScheme( |
||||||
|
primary = md_theme_dark_primary, |
||||||
|
onPrimary = md_theme_dark_onPrimary, |
||||||
|
primaryContainer = md_theme_dark_primaryContainer, |
||||||
|
onPrimaryContainer = md_theme_dark_onPrimaryContainer, |
||||||
|
secondary = md_theme_dark_secondary, |
||||||
|
onSecondary = md_theme_dark_onSecondary, |
||||||
|
secondaryContainer = md_theme_dark_secondaryContainer, |
||||||
|
onSecondaryContainer = md_theme_dark_onSecondaryContainer, |
||||||
|
tertiary = md_theme_dark_tertiary, |
||||||
|
onTertiary = md_theme_dark_onTertiary, |
||||||
|
tertiaryContainer = md_theme_dark_tertiaryContainer, |
||||||
|
onTertiaryContainer = md_theme_dark_onTertiaryContainer, |
||||||
|
error = md_theme_dark_error, |
||||||
|
errorContainer = md_theme_dark_errorContainer, |
||||||
|
onError = md_theme_dark_onError, |
||||||
|
onErrorContainer = md_theme_dark_onErrorContainer, |
||||||
|
background = md_theme_dark_background, |
||||||
|
onBackground = md_theme_dark_onBackground, |
||||||
|
surface = md_theme_dark_surface, |
||||||
|
onSurface = md_theme_dark_onSurface, |
||||||
|
surfaceVariant = md_theme_dark_surfaceVariant, |
||||||
|
onSurfaceVariant = md_theme_dark_onSurfaceVariant, |
||||||
|
outline = md_theme_dark_outline, |
||||||
|
inverseOnSurface = md_theme_dark_inverseOnSurface, |
||||||
|
inverseSurface = md_theme_dark_inverseSurface, |
||||||
|
inversePrimary = md_theme_dark_inversePrimary, |
||||||
|
surfaceTint = md_theme_dark_surfaceTint, |
||||||
|
outlineVariant = md_theme_dark_outlineVariant, |
||||||
|
scrim = md_theme_dark_scrim, |
||||||
|
) |
||||||
|
|
||||||
|
@Composable |
||||||
|
fun CupcakeTheme( |
||||||
|
darkTheme: Boolean = isSystemInDarkTheme(), |
||||||
|
content: @Composable () -> Unit |
||||||
|
) { |
||||||
|
val colorScheme = when { |
||||||
|
darkTheme -> DarkColors |
||||||
|
else -> LightColors |
||||||
|
} |
||||||
|
MaterialTheme( |
||||||
|
colorScheme = colorScheme, |
||||||
|
typography = Typography, |
||||||
|
content = content |
||||||
|
) |
||||||
|
} |
@ -0,0 +1,33 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2023 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 |
||||||
|
* |
||||||
|
* 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. |
||||||
|
*/ |
||||||
|
package org.jetbrains.nav_cupcake.ui.theme |
||||||
|
|
||||||
|
import androidx.compose.material3.Typography |
||||||
|
import androidx.compose.ui.text.TextStyle |
||||||
|
import androidx.compose.ui.text.font.FontFamily |
||||||
|
import androidx.compose.ui.text.font.FontWeight |
||||||
|
import androidx.compose.ui.unit.sp |
||||||
|
|
||||||
|
// Set of Material typography styles to start with |
||||||
|
val Typography = Typography( |
||||||
|
bodyLarge = TextStyle( |
||||||
|
fontFamily = FontFamily.Default, |
||||||
|
fontWeight = FontWeight.Normal, |
||||||
|
fontSize = 16.sp, |
||||||
|
lineHeight = 24.sp, |
||||||
|
letterSpacing = 0.5.sp |
||||||
|
) |
||||||
|
) |
@ -0,0 +1,9 @@ |
|||||||
|
import androidx.compose.runtime.Composable |
||||||
|
import androidx.compose.ui.window.Window |
||||||
|
import androidx.compose.ui.window.application |
||||||
|
|
||||||
|
fun main() = application { |
||||||
|
Window(onCloseRequest = ::exitApplication, title = "Cupcake") { |
||||||
|
App() |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
import androidx.compose.ui.window.ComposeUIViewController |
||||||
|
|
||||||
|
fun MainViewController() = ComposeUIViewController { App() } |
@ -0,0 +1,7 @@ |
|||||||
|
import androidx.compose.ui.ExperimentalComposeUiApi |
||||||
|
import androidx.compose.ui.window.CanvasBasedWindow |
||||||
|
|
||||||
|
@OptIn(ExperimentalComposeUiApi::class) |
||||||
|
fun main() { |
||||||
|
CanvasBasedWindow(canvasElementId = "ComposeTarget") { App() } |
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html lang="en"> |
||||||
|
<head> |
||||||
|
<meta charset="UTF-8"> |
||||||
|
<title>Compose App</title> |
||||||
|
<script type="application/javascript" src="skiko.js"></script> |
||||||
|
<script type="application/javascript" src="composeApp.js"></script> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<canvas id="ComposeTarget"></canvas> |
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,19 @@ |
|||||||
|
kotlin.code.style=official |
||||||
|
|
||||||
|
#Gradle |
||||||
|
org.gradle.jvmargs=-Xmx4G -Dfile.encoding=UTF-8 -Dkotlin.daemon.jvm.options\="-Xmx4G" |
||||||
|
|
||||||
|
|
||||||
|
#Android |
||||||
|
android.nonTransitiveRClass=true |
||||||
|
android.useAndroidX=true |
||||||
|
|
||||||
|
#Compose |
||||||
|
org.jetbrains.compose.experimental.wasm.enabled=true |
||||||
|
|
||||||
|
#MPP |
||||||
|
kotlin.mpp.androidSourceSetLayoutVersion=2 |
||||||
|
kotlin.mpp.enableCInteropCommonization=true |
||||||
|
|
||||||
|
#Development |
||||||
|
development=true |
@ -0,0 +1,32 @@ |
|||||||
|
[versions] |
||||||
|
agp = "8.2.0" |
||||||
|
android-compileSdk = "34" |
||||||
|
android-minSdk = "24" |
||||||
|
android-targetSdk = "34" |
||||||
|
androidx-activity = "1.8.2" |
||||||
|
androidx-lifecycle = "2.8.0-rc03" |
||||||
|
androidx-navigation = "2.7.0-alpha06" |
||||||
|
compose-android = "1.6.7" |
||||||
|
compose-multiplatform = "1.6.10-rc03" |
||||||
|
junit = "4.13.2" |
||||||
|
kotlin = "2.0.0-RC3" |
||||||
|
kotlinx-datetime = "0.6.0" |
||||||
|
|
||||||
|
[libraries] |
||||||
|
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } |
||||||
|
kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" } |
||||||
|
kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinx-datetime" } |
||||||
|
junit = { group = "junit", name = "junit", version.ref = "junit" } |
||||||
|
androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activity" } |
||||||
|
androidx-lifecycle-runtime-compose = { module = "org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose", version.ref = "androidx-lifecycle" } |
||||||
|
androidx-lifecycle-viewmodel-compose = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "androidx-lifecycle" } |
||||||
|
androidx-navigation-compose = { module = "org.jetbrains.androidx.navigation:navigation-compose", version.ref = "androidx-navigation" } |
||||||
|
compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "compose-android" } |
||||||
|
compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "compose-android" } |
||||||
|
|
||||||
|
[plugins] |
||||||
|
androidApplication = { id = "com.android.application", version.ref = "agp" } |
||||||
|
androidLibrary = { id = "com.android.library", version.ref = "agp" } |
||||||
|
kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } |
||||||
|
composeMultiplatform = { id = "org.jetbrains.compose", version.ref = "compose-multiplatform" } |
||||||
|
composeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } |
Binary file not shown.
@ -0,0 +1,7 @@ |
|||||||
|
distributionBase=GRADLE_USER_HOME |
||||||
|
distributionPath=wrapper/dists |
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip |
||||||
|
networkTimeout=10000 |
||||||
|
validateDistributionUrl=true |
||||||
|
zipStoreBase=GRADLE_USER_HOME |
||||||
|
zipStorePath=wrapper/dists |
@ -0,0 +1,248 @@ |
|||||||
|
#!/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/HEAD/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 |
||||||
|
|
||||||
|
# This is normally unused |
||||||
|
# shellcheck disable=SC2034 |
||||||
|
APP_BASE_NAME=${0##*/} |
||||||
|
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit |
||||||
|
|
||||||
|
# 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 |
||||||
|
if ! command -v java >/dev/null 2>&1 |
||||||
|
then |
||||||
|
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 |
||||||
|
fi |
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can. |
||||||
|
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then |
||||||
|
case $MAX_FD in #( |
||||||
|
max*) |
||||||
|
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. |
||||||
|
# shellcheck disable=SC3045 |
||||||
|
MAX_FD=$( ulimit -H -n ) || |
||||||
|
warn "Could not query maximum file descriptor limit" |
||||||
|
esac |
||||||
|
case $MAX_FD in #( |
||||||
|
'' | soft) :;; #( |
||||||
|
*) |
||||||
|
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. |
||||||
|
# shellcheck disable=SC3045 |
||||||
|
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 |
||||||
|
|
||||||
|
|
||||||
|
# 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"' |
||||||
|
|
||||||
|
# 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" "$@" |
@ -0,0 +1,92 @@ |
|||||||
|
@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=. |
||||||
|
@rem This is normally unused |
||||||
|
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 |
After Width: | Height: | Size: 1.6 MiB |
After Width: | Height: | Size: 1.9 MiB |
@ -0,0 +1,3 @@ |
|||||||
|
TEAM_ID= |
||||||
|
BUNDLE_ID=org.jetbrains.nav_cupcake.Cupcake |
||||||
|
APP_NAME=Cupcake |
@ -0,0 +1,398 @@ |
|||||||
|
// !$*UTF8*$! |
||||||
|
{ |
||||||
|
archiveVersion = 1; |
||||||
|
classes = { |
||||||
|
}; |
||||||
|
objectVersion = 54; |
||||||
|
objects = { |
||||||
|
|
||||||
|
/* Begin PBXBuildFile section */ |
||||||
|
058557BB273AAA24004C7B11 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 058557BA273AAA24004C7B11 /* Assets.xcassets */; }; |
||||||
|
058557D9273AAEEB004C7B11 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */; }; |
||||||
|
2152FB042600AC8F00CF470E /* iOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2152FB032600AC8F00CF470E /* iOSApp.swift */; }; |
||||||
|
7555FF83242A565900829871 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7555FF82242A565900829871 /* ContentView.swift */; }; |
||||||
|
/* End PBXBuildFile section */ |
||||||
|
|
||||||
|
/* Begin PBXFileReference section */ |
||||||
|
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 /* iosApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iosApp.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>"; }; |
||||||
|
/* End PBXFileReference section */ |
||||||
|
|
||||||
|
/* Begin PBXFrameworksBuildPhase section */ |
||||||
|
B92378962B6B1156000C7307 /* Frameworks */ = { |
||||||
|
isa = PBXFrameworksBuildPhase; |
||||||
|
buildActionMask = 2147483647; |
||||||
|
files = ( |
||||||
|
); |
||||||
|
runOnlyForDeploymentPostprocessing = 0; |
||||||
|
}; |
||||||
|
/* End PBXFrameworksBuildPhase section */ |
||||||
|
|
||||||
|
/* Begin PBXGroup section */ |
||||||
|
058557D7273AAEEB004C7B11 /* Preview Content */ = { |
||||||
|
isa = PBXGroup; |
||||||
|
children = ( |
||||||
|
058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */, |
||||||
|
); |
||||||
|
path = "Preview Content"; |
||||||
|
sourceTree = "<group>"; |
||||||
|
}; |
||||||
|
42799AB246E5F90AF97AA0EF /* Frameworks */ = { |
||||||
|
isa = PBXGroup; |
||||||
|
children = ( |
||||||
|
); |
||||||
|
name = Frameworks; |
||||||
|
sourceTree = "<group>"; |
||||||
|
}; |
||||||
|
7555FF72242A565900829871 = { |
||||||
|
isa = PBXGroup; |
||||||
|
children = ( |
||||||
|
AB1DB47929225F7C00F7AF9C /* Configuration */, |
||||||
|
7555FF7D242A565900829871 /* iosApp */, |
||||||
|
7555FF7C242A565900829871 /* Products */, |
||||||
|
42799AB246E5F90AF97AA0EF /* Frameworks */, |
||||||
|
); |
||||||
|
sourceTree = "<group>"; |
||||||
|
}; |
||||||
|
7555FF7C242A565900829871 /* Products */ = { |
||||||
|
isa = PBXGroup; |
||||||
|
children = ( |
||||||
|
7555FF7B242A565900829871 /* iosApp.app */, |
||||||
|
); |
||||||
|
name = Products; |
||||||
|
sourceTree = "<group>"; |
||||||
|
}; |
||||||
|
7555FF7D242A565900829871 /* iosApp */ = { |
||||||
|
isa = PBXGroup; |
||||||
|
children = ( |
||||||
|
058557BA273AAA24004C7B11 /* Assets.xcassets */, |
||||||
|
7555FF82242A565900829871 /* ContentView.swift */, |
||||||
|
7555FF8C242A565B00829871 /* Info.plist */, |
||||||
|
2152FB032600AC8F00CF470E /* iOSApp.swift */, |
||||||
|
058557D7273AAEEB004C7B11 /* Preview Content */, |
||||||
|
); |
||||||
|
path = iosApp; |
||||||
|
sourceTree = "<group>"; |
||||||
|
}; |
||||||
|
AB1DB47929225F7C00F7AF9C /* Configuration */ = { |
||||||
|
isa = PBXGroup; |
||||||
|
children = ( |
||||||
|
AB3632DC29227652001CCB65 /* Config.xcconfig */, |
||||||
|
); |
||||||
|
path = Configuration; |
||||||
|
sourceTree = "<group>"; |
||||||
|
}; |
||||||
|
/* End PBXGroup section */ |
||||||
|
|
||||||
|
/* Begin PBXNativeTarget section */ |
||||||
|
7555FF7A242A565900829871 /* iosApp */ = { |
||||||
|
isa = PBXNativeTarget; |
||||||
|
buildConfigurationList = 7555FFA5242A565B00829871 /* Build configuration list for PBXNativeTarget "iosApp" */; |
||||||
|
buildPhases = ( |
||||||
|
F36B1CEB2AD83DDC00CB74D5 /* Compile Kotlin Framework */, |
||||||
|
7555FF77242A565900829871 /* Sources */, |
||||||
|
B92378962B6B1156000C7307 /* Frameworks */, |
||||||
|
7555FF79242A565900829871 /* Resources */, |
||||||
|
); |
||||||
|
buildRules = ( |
||||||
|
); |
||||||
|
dependencies = ( |
||||||
|
); |
||||||
|
name = iosApp; |
||||||
|
packageProductDependencies = ( |
||||||
|
); |
||||||
|
productName = iosApp; |
||||||
|
productReference = 7555FF7B242A565900829871 /* iosApp.app */; |
||||||
|
productType = "com.apple.product-type.application"; |
||||||
|
}; |
||||||
|
/* End PBXNativeTarget section */ |
||||||
|
|
||||||
|
/* Begin PBXProject section */ |
||||||
|
7555FF73242A565900829871 /* Project object */ = { |
||||||
|
isa = PBXProject; |
||||||
|
attributes = { |
||||||
|
LastSwiftUpdateCheck = 1130; |
||||||
|
LastUpgradeCheck = 1130; |
||||||
|
ORGANIZATIONNAME = orgName; |
||||||
|
TargetAttributes = { |
||||||
|
7555FF7A242A565900829871 = { |
||||||
|
CreatedOnToolsVersion = 11.3.1; |
||||||
|
}; |
||||||
|
}; |
||||||
|
}; |
||||||
|
buildConfigurationList = 7555FF76242A565900829871 /* Build configuration list for PBXProject "iosApp" */; |
||||||
|
compatibilityVersion = "Xcode 12.0"; |
||||||
|
developmentRegion = en; |
||||||
|
hasScannedForEncodings = 0; |
||||||
|
knownRegions = ( |
||||||
|
en, |
||||||
|
Base, |
||||||
|
); |
||||||
|
mainGroup = 7555FF72242A565900829871; |
||||||
|
packageReferences = ( |
||||||
|
); |
||||||
|
productRefGroup = 7555FF7C242A565900829871 /* Products */; |
||||||
|
projectDirPath = ""; |
||||||
|
projectRoot = ""; |
||||||
|
targets = ( |
||||||
|
7555FF7A242A565900829871 /* iosApp */, |
||||||
|
); |
||||||
|
}; |
||||||
|
/* End PBXProject section */ |
||||||
|
|
||||||
|
/* Begin PBXResourcesBuildPhase section */ |
||||||
|
7555FF79242A565900829871 /* Resources */ = { |
||||||
|
isa = PBXResourcesBuildPhase; |
||||||
|
buildActionMask = 2147483647; |
||||||
|
files = ( |
||||||
|
058557D9273AAEEB004C7B11 /* Preview Assets.xcassets in Resources */, |
||||||
|
058557BB273AAA24004C7B11 /* Assets.xcassets in Resources */, |
||||||
|
); |
||||||
|
runOnlyForDeploymentPostprocessing = 0; |
||||||
|
}; |
||||||
|
/* End PBXResourcesBuildPhase section */ |
||||||
|
|
||||||
|
/* Begin PBXShellScriptBuildPhase section */ |
||||||
|
F36B1CEB2AD83DDC00CB74D5 /* Compile Kotlin Framework */ = { |
||||||
|
isa = PBXShellScriptBuildPhase; |
||||||
|
buildActionMask = 2147483647; |
||||||
|
files = ( |
||||||
|
); |
||||||
|
inputFileListPaths = ( |
||||||
|
); |
||||||
|
inputPaths = ( |
||||||
|
); |
||||||
|
name = "Compile Kotlin Framework"; |
||||||
|
outputFileListPaths = ( |
||||||
|
); |
||||||
|
outputPaths = ( |
||||||
|
); |
||||||
|
runOnlyForDeploymentPostprocessing = 0; |
||||||
|
shellPath = /bin/sh; |
||||||
|
shellScript = "if [ \"YES\" = \"$OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED\" ]; then\n echo \"Skipping Gradle build task invocation due to OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED environment variable set to \\\"YES\\\"\"\n exit 0\nfi\ncd \"$SRCROOT/..\"\n./gradlew :composeApp:embedAndSignAppleFrameworkForXcode\n"; |
||||||
|
}; |
||||||
|
/* End PBXShellScriptBuildPhase section */ |
||||||
|
|
||||||
|
/* Begin PBXSourcesBuildPhase section */ |
||||||
|
7555FF77242A565900829871 /* Sources */ = { |
||||||
|
isa = PBXSourcesBuildPhase; |
||||||
|
buildActionMask = 2147483647; |
||||||
|
files = ( |
||||||
|
2152FB042600AC8F00CF470E /* iOSApp.swift in Sources */, |
||||||
|
7555FF83242A565900829871 /* ContentView.swift in Sources */, |
||||||
|
); |
||||||
|
runOnlyForDeploymentPostprocessing = 0; |
||||||
|
}; |
||||||
|
/* End PBXSourcesBuildPhase section */ |
||||||
|
|
||||||
|
/* Begin XCBuildConfiguration section */ |
||||||
|
7555FFA3242A565B00829871 /* Debug */ = { |
||||||
|
isa = XCBuildConfiguration; |
||||||
|
baseConfigurationReference = AB3632DC29227652001CCB65 /* Config.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 = 15.3; |
||||||
|
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 /* Config.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 = 15.3; |
||||||
|
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; |
||||||
|
buildSettings = { |
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; |
||||||
|
CODE_SIGN_IDENTITY = "Apple Development"; |
||||||
|
CODE_SIGN_STYLE = Automatic; |
||||||
|
DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\""; |
||||||
|
DEVELOPMENT_TEAM = "${TEAM_ID}"; |
||||||
|
ENABLE_PREVIEWS = YES; |
||||||
|
FRAMEWORK_SEARCH_PATHS = ( |
||||||
|
"$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)\n$(SRCROOT)/../composeApp/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)", |
||||||
|
); |
||||||
|
INFOPLIST_FILE = iosApp/Info.plist; |
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 15.3; |
||||||
|
LD_RUNPATH_SEARCH_PATHS = ( |
||||||
|
"$(inherited)", |
||||||
|
"@executable_path/Frameworks", |
||||||
|
); |
||||||
|
OTHER_LDFLAGS = ( |
||||||
|
"$(inherited)", |
||||||
|
"-framework", |
||||||
|
composeApp, |
||||||
|
); |
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = "${BUNDLE_ID}${TEAM_ID}"; |
||||||
|
PRODUCT_NAME = "${APP_NAME}"; |
||||||
|
PROVISIONING_PROFILE_SPECIFIER = ""; |
||||||
|
SWIFT_VERSION = 5.0; |
||||||
|
TARGETED_DEVICE_FAMILY = "1,2"; |
||||||
|
}; |
||||||
|
name = Debug; |
||||||
|
}; |
||||||
|
7555FFA7242A565B00829871 /* Release */ = { |
||||||
|
isa = XCBuildConfiguration; |
||||||
|
buildSettings = { |
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; |
||||||
|
CODE_SIGN_IDENTITY = "Apple Development"; |
||||||
|
CODE_SIGN_STYLE = Automatic; |
||||||
|
DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\""; |
||||||
|
DEVELOPMENT_TEAM = "${TEAM_ID}"; |
||||||
|
ENABLE_PREVIEWS = YES; |
||||||
|
FRAMEWORK_SEARCH_PATHS = ( |
||||||
|
"$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)\n$(SRCROOT)/../composeApp/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)", |
||||||
|
); |
||||||
|
INFOPLIST_FILE = iosApp/Info.plist; |
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 15.3; |
||||||
|
LD_RUNPATH_SEARCH_PATHS = ( |
||||||
|
"$(inherited)", |
||||||
|
"@executable_path/Frameworks", |
||||||
|
); |
||||||
|
OTHER_LDFLAGS = ( |
||||||
|
"$(inherited)", |
||||||
|
"-framework", |
||||||
|
composeApp, |
||||||
|
); |
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = "${BUNDLE_ID}${TEAM_ID}"; |
||||||
|
PRODUCT_NAME = "${APP_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 "iosApp" */ = { |
||||||
|
isa = XCConfigurationList; |
||||||
|
buildConfigurations = ( |
||||||
|
7555FFA3242A565B00829871 /* Debug */, |
||||||
|
7555FFA4242A565B00829871 /* Release */, |
||||||
|
); |
||||||
|
defaultConfigurationIsVisible = 0; |
||||||
|
defaultConfigurationName = Release; |
||||||
|
}; |
||||||
|
7555FFA5242A565B00829871 /* Build configuration list for PBXNativeTarget "iosApp" */ = { |
||||||
|
isa = XCConfigurationList; |
||||||
|
buildConfigurations = ( |
||||||
|
7555FFA6242A565B00829871 /* Debug */, |
||||||
|
7555FFA7242A565B00829871 /* Release */, |
||||||
|
); |
||||||
|
defaultConfigurationIsVisible = 0; |
||||||
|
defaultConfigurationName = Release; |
||||||
|
}; |
||||||
|
/* End XCConfigurationList section */ |
||||||
|
}; |
||||||
|
rootObject = 7555FF73242A565900829871 /* Project object */; |
||||||
|
} |
@ -0,0 +1,11 @@ |
|||||||
|
{ |
||||||
|
"colors" : [ |
||||||
|
{ |
||||||
|
"idiom" : "universal" |
||||||
|
} |
||||||
|
], |
||||||
|
"info" : { |
||||||
|
"author" : "xcode", |
||||||
|
"version" : 1 |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,14 @@ |
|||||||
|
{ |
||||||
|
"images" : [ |
||||||
|
{ |
||||||
|
"filename" : "app-icon-1024.png", |
||||||
|
"idiom" : "universal", |
||||||
|
"platform" : "ios", |
||||||
|
"size" : "1024x1024" |
||||||
|
} |
||||||
|
], |
||||||
|
"info" : { |
||||||
|
"author" : "xcode", |
||||||
|
"version" : 1 |
||||||
|
} |
||||||
|
} |
After Width: | Height: | Size: 66 KiB |
@ -0,0 +1,6 @@ |
|||||||
|
{ |
||||||
|
"info" : { |
||||||
|
"author" : "xcode", |
||||||
|
"version" : 1 |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,21 @@ |
|||||||
|
import UIKit |
||||||
|
import SwiftUI |
||||||
|
import ComposeApp |
||||||
|
|
||||||
|
struct ComposeView: UIViewControllerRepresentable { |
||||||
|
func makeUIViewController(context: Context) -> UIViewController { |
||||||
|
MainViewControllerKt.MainViewController() |
||||||
|
} |
||||||
|
|
||||||
|
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {} |
||||||
|
} |
||||||
|
|
||||||
|
struct ContentView: View { |
||||||
|
var body: some View { |
||||||
|
ComposeView() |
||||||
|
.ignoresSafeArea(.all) // Compose has own insets handler |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,50 @@ |
|||||||
|
<?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>CADisableMinimumFrameDurationOnPhone</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> |
@ -0,0 +1,6 @@ |
|||||||
|
{ |
||||||
|
"info" : { |
||||||
|
"author" : "xcode", |
||||||
|
"version" : 1 |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,10 @@ |
|||||||
|
import SwiftUI |
||||||
|
|
||||||
|
@main |
||||||
|
struct iOSApp: App { |
||||||
|
var body: some Scene { |
||||||
|
WindowGroup { |
||||||
|
ContentView() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,21 @@ |
|||||||
|
rootProject.name = "Cupcake" |
||||||
|
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") |
||||||
|
|
||||||
|
pluginManagement { |
||||||
|
repositories { |
||||||
|
google() |
||||||
|
gradlePluginPortal() |
||||||
|
mavenCentral() |
||||||
|
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
dependencyResolutionManagement { |
||||||
|
repositories { |
||||||
|
google() |
||||||
|
mavenCentral() |
||||||
|
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
include(":composeApp") |
Loading…
Reference in new issue