Refactor Widgets Gallery sample to use KMM structure and add iOS target (#2491)
Refactor Widgets Gallery sample to use KMM structure and add iOS target
15
experimental/examples/widgets-gallery/.gitignore
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/
|
||||
.DS_Store
|
||||
build/
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
.cxx
|
||||
iosApp/Podfile.lock
|
||||
iosApp/Pods/*
|
||||
iosApp/WidgetsGallery.xcworkspace/*
|
||||
iosApp/WidgetsGallery.xcodeproj/*
|
||||
!iosApp/WidgetsGallery.xcodeproj/project.pbxproj
|
||||
shared/shared.podspec
|
||||
@@ -0,0 +1,28 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="desktopApp" type="GradleRunConfiguration" factoryName="Gradle">
|
||||
<ExternalSystemSettings>
|
||||
<option name="env">
|
||||
<map>
|
||||
<entry key="DEVELOPER_DIR" value="/Applications/Xcode.app/Contents/Developer" />
|
||||
</map>
|
||||
</option>
|
||||
<option name="executionName" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="externalSystemIdString" value="GRADLE" />
|
||||
<option name="scriptParameters" value="" />
|
||||
<option name="taskDescriptions">
|
||||
<list />
|
||||
</option>
|
||||
<option name="taskNames">
|
||||
<list>
|
||||
<option value="desktopApp:run" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="vmOptions" />
|
||||
</ExternalSystemSettings>
|
||||
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||
<DebugAllEnabled>false</DebugAllEnabled>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -0,0 +1,8 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="iosApp" type="AppleRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="WidgetsGallery" TARGET_NAME="WidgetsGallery" CONFIG_NAME="Debug" IS_LOCATION_SIMULATION_SUPPORTED="true" SCHEME_NAME="iosApp" IS_LOCATION_SIMULATION_ALLOWED="true" LOCATION_SCENARIO_ID="com.apple.dt.IDEFoundation.CurrentLocationScenarioIdentifier" LOCATION_SCENARIO_TYPE="1" APPLICATION_LANGUAGE="IDELaunchSchemeLanguageUseSystemLanguage" APPLICATION_REGION="" RUN_TARGET_PROJECT_NAME="WidgetsGallery" RUN_TARGET_NAME="WidgetsGallery" MAKE_ACTIVE="TRUE" SHOULD_DEBUG_EXTENSIONS="false">
|
||||
<embedded_app_extension_list />
|
||||
<method v="2">
|
||||
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -0,0 +1,7 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="iosApp_" type="KmmRunConfiguration" factoryName="iOS Application" CONFIG_VERSION="1" EXEC_TARGET_ID="9003B6AD-4F7F-48D4-9988-383A8AFC72F5" XCODE_PROJECT="$PROJECT_DIR$/./iosApp/WidgetsGallery.xcworkspace" XCODE_CONFIGURATION="Debug" XCODE_SCHEME="iosApp">
|
||||
<method v="2">
|
||||
<option name="com.jetbrains.kmm.ios.BuildIOSAppTask" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
32
experimental/examples/widgets-gallery/README.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# Widgets gallery
|
||||
|
||||
This example is derived from
|
||||
[ComposeCookBook](https://github.com/Gurupreet/ComposeCookBook) project
|
||||
by Gurupreet Singh ([@Gurupreet](https://github.com/Gurupreet))
|
||||
published under [MIT license](third_party/ComposeCookBook_LICENSE.txt).
|
||||
|
||||
An example of Compose application for Desktop, Android and iOS platforms,
|
||||
demonstrating how to use various Material widgets.
|
||||
|
||||
## How to run
|
||||
|
||||
Choose a run configuration for an appropriate target in IDE and run it.
|
||||
|
||||

|
||||
|
||||
To run on iOS device, please correct `iosApp/Configuration/TeamId.xcconfig` with your Apple Team ID.
|
||||
Alternatively, you may setup signing within XCode opening `iosApp/WidgetsGallery.xcworkspace` and then
|
||||
using "Signing & Capabilities" tab of `WidgetsGallery` target.
|
||||
|
||||
Then choose **iosApp** configuration in IDE and run it
|
||||
(may also be referred as `WidgetsGallery` in the Run Configurations or `iosApp_` for Android studio).
|
||||
|
||||
## Run on desktop via Gradle
|
||||
|
||||
`./gradlew desktopApp:run`
|
||||
|
||||
### Building native desktop distribution
|
||||
```
|
||||
./gradlew :desktop:packageDistributionForCurrentOS
|
||||
# outputs are written to desktop/build/compose/binaries
|
||||
```
|
||||
@@ -0,0 +1,33 @@
|
||||
plugins {
|
||||
kotlin("multiplatform")
|
||||
id("com.android.application")
|
||||
id("org.jetbrains.compose")
|
||||
}
|
||||
|
||||
kotlin {
|
||||
android()
|
||||
sourceSets {
|
||||
val androidMain by getting {
|
||||
dependencies {
|
||||
implementation(project(":shared"))
|
||||
implementation("androidx.appcompat:appcompat:1.5.1")
|
||||
implementation("androidx.activity:activity-compose:1.6.1")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdk = 33
|
||||
defaultConfig {
|
||||
applicationId = "org.jetbrains.FallingBalls"
|
||||
minSdk = 24
|
||||
targetSdk = 33
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.jetbrains.compose.demo.widgets">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
|
||||
<activity
|
||||
android:exported="true"
|
||||
android:name="MainActivity"
|
||||
>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.jetbrains.compose.demo.widgets
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import MainView
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContent {
|
||||
MainView()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#3DDC84"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,0L9,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,0L19,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,0L29,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,0L39,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,0L49,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,0L59,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,0L69,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,0L79,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M89,0L89,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M99,0L99,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,9L108,9"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,19L108,19"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,29L108,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,39L108,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,49L108,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,59L108,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,69L108,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,79L108,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,89L108,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,99L108,99"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29L89,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,39L89,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,49L89,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,59L89,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,69L89,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,79L89,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,19L29,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,19L39,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,19L49,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,19L59,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,19L69,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,19L79,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
</vector>
|
||||
@@ -0,0 +1,30 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="85.84757"
|
||||
android:endY="92.4963"
|
||||
android:startX="42.9492"
|
||||
android:startY="49.59793"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0" />
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000" />
|
||||
</vector>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 16 KiB |
@@ -0,0 +1,16 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- <!– Base application theme. –>-->
|
||||
<!-- <style name="Theme.ComposeCookBook" parent="Theme.MaterialComponents.DayNight.DarkActionBar">-->
|
||||
<!-- <!– Primary brand color. –>-->
|
||||
<!-- <item name="colorPrimary">@color/green_200</item>-->
|
||||
<!-- <item name="colorPrimaryVariant">@color/green_700</item>-->
|
||||
<!-- <item name="colorOnPrimary">@color/black</item>-->
|
||||
<!-- <!– Secondary brand color. –>-->
|
||||
<!-- <item name="colorSecondary">@color/teal_200</item>-->
|
||||
<!-- <item name="colorSecondaryVariant">@color/teal_200</item>-->
|
||||
<!-- <item name="colorOnSecondary">@color/black</item>-->
|
||||
<!-- <!– Status bar color. –>-->
|
||||
<!-- <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>-->
|
||||
<!-- <!– Customize your theme here. –>-->
|
||||
<!-- </style>-->
|
||||
</resources>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="green_200">#ffa5d6a7</color>
|
||||
<color name="green_500">#ff4caf50</color>
|
||||
<color name="green_700">#ff388e3c</color>
|
||||
<color name="teal_200">#FF03DAC5</color>
|
||||
<color name="teal_700">#ff80deea</color>
|
||||
<color name="purple">#FF833AB4</color>
|
||||
<color name="black">#FF000000</color>
|
||||
<color name="white">#FFFFFFFF</color>
|
||||
</resources>
|
||||
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">ComposeWidgets</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,26 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- <!– Base application theme. –>-->
|
||||
<!-- <style name="Theme.ComposeCookBook" parent="Theme.MaterialComponents.DayNight.DarkActionBar">-->
|
||||
<!-- <!– Primary brand color. –>-->
|
||||
<!-- <item name="colorPrimary">@color/green_500</item>-->
|
||||
<!-- <item name="colorPrimaryVariant">@color/green_700</item>-->
|
||||
<!-- <item name="colorOnPrimary">@color/white</item>-->
|
||||
<!-- <!– Secondary brand color. –>-->
|
||||
<!-- <item name="colorSecondary">@color/teal_200</item>-->
|
||||
<!-- <item name="colorSecondaryVariant">@color/teal_700</item>-->
|
||||
<!-- <item name="colorOnSecondary">@color/black</item>-->
|
||||
<!-- <!– Status bar color. –>-->
|
||||
<!-- <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>-->
|
||||
<!-- <!– Customize your theme here. –>-->
|
||||
<!-- <item name="android:windowContentTransitions">true</item>-->
|
||||
<!-- </style>-->
|
||||
|
||||
<!-- <style name="Theme.ComposeCookBook.NoActionBar">-->
|
||||
<!-- <item name="windowActionBar">false</item>-->
|
||||
<!-- <item name="windowNoTitle">true</item>-->
|
||||
<!-- </style>-->
|
||||
|
||||
<!-- <style name="Theme.ComposeCookBook.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />-->
|
||||
|
||||
<!-- <style name="Theme.ComposeCookBook.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />-->
|
||||
</resources>
|
||||
22
experimental/examples/widgets-gallery/build.gradle.kts
Normal file
@@ -0,0 +1,22 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
google()
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
}
|
||||
dependencies {
|
||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20")
|
||||
classpath("com.android.tools.build:gradle:7.3.1")
|
||||
classpath("org.jetbrains.compose:compose-gradle-plugin:1.2.1")
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
|
||||
|
||||
plugins {
|
||||
kotlin("multiplatform")
|
||||
id("org.jetbrains.compose")
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvm {}
|
||||
sourceSets {
|
||||
val jvmMain by getting {
|
||||
dependencies {
|
||||
implementation(compose.desktop.currentOs)
|
||||
implementation(project(":shared"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
compose.desktop {
|
||||
application {
|
||||
mainClass = "org.jetbrains.compose.demo.widgets.MainKt"
|
||||
|
||||
nativeDistributions {
|
||||
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
|
||||
packageName = "ComposeWidgetsGallery"
|
||||
packageVersion = "1.0.0"
|
||||
|
||||
windows {
|
||||
menu = true
|
||||
// see https://wixtoolset.org/documentation/manual/v3/howtos/general/generate_guids.html
|
||||
upgradeUuid = "a61b72be-1b0c-4de5-9607-791c17687428"
|
||||
}
|
||||
|
||||
macOS {
|
||||
bundleID = "org.jetbrains.compose.demo.widgets"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.jetbrains.compose.demo.widgets
|
||||
|
||||
import androidx.compose.ui.unit.DpSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.WindowState
|
||||
import androidx.compose.ui.window.singleWindowApplication
|
||||
import MainView
|
||||
|
||||
fun main() = singleWindowApplication(
|
||||
title = "Widgets Gallery", state = WindowState(size = DpSize(800.dp, 800.dp))
|
||||
) {
|
||||
MainView()
|
||||
}
|
||||
14
experimental/examples/widgets-gallery/gradle.properties
Normal file
@@ -0,0 +1,14 @@
|
||||
kotlin.code.style=official
|
||||
xcodeproj=./iosApp
|
||||
kotlin.native.cocoapods.generate.wrapper=true
|
||||
android.useAndroidX=true
|
||||
org.gradle.jvmargs=-Xmx3g
|
||||
org.jetbrains.compose.experimental.jscanvas.enabled=true
|
||||
org.jetbrains.compose.experimental.macos.enabled=true
|
||||
org.jetbrains.compose.experimental.uikit.enabled=true
|
||||
kotlin.native.cacheKind=none
|
||||
kotlin.native.useEmbeddableCompilerJar=true
|
||||
kotlin.native.enableDependencyPropagation=false
|
||||
kotlin.mpp.enableGranularSourceSetsMetadata=true
|
||||
# Enable kotlin/native experimental memory model
|
||||
kotlin.native.binary.memoryModel=experimental
|
||||
BIN
experimental/examples/widgets-gallery/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
5
experimental/examples/widgets-gallery/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
240
experimental/examples/widgets-gallery/gradlew
vendored
Executable file
@@ -0,0 +1,240 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=${0##*/}
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
91
experimental/examples/widgets-gallery/gradlew.bat
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
@@ -0,0 +1 @@
|
||||
TEAM_ID=
|
||||
5
experimental/examples/widgets-gallery/iosApp/Podfile
Normal file
@@ -0,0 +1,5 @@
|
||||
target 'WidgetsGallery' do
|
||||
use_frameworks!
|
||||
platform :ios, '14.1'
|
||||
pod 'shared', :path => '../shared'
|
||||
end
|
||||
@@ -0,0 +1,380 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 50;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
2152FB042600AC8F00CF470E /* iosApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2152FB032600AC8F00CF470E /* iosApp.swift */; };
|
||||
C1FC908188C4E8695729CB06 /* Pods_WidgetsGallery.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DE96E47030356CE6AD9794A /* Pods_WidgetsGallery.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
1EB65E27D2C0F884D0A1A133 /* Pods-WidgetsGallery.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WidgetsGallery.debug.xcconfig"; path = "Target Support Files/Pods-WidgetsGallery/Pods-WidgetsGallery.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
2152FB032600AC8F00CF470E /* iosApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iosApp.swift; sourceTree = "<group>"; };
|
||||
3D7A606AB0AD7636269BD9D0 /* Pods-WidgetsGallery.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WidgetsGallery.release.xcconfig"; path = "Target Support Files/Pods-WidgetsGallery/Pods-WidgetsGallery.release.xcconfig"; sourceTree = "<group>"; };
|
||||
7555FF7B242A565900829871 /* WidgetsGallery.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WidgetsGallery.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
7555FF8C242A565B00829871 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
8DE96E47030356CE6AD9794A /* Pods_WidgetsGallery.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_WidgetsGallery.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
AB3632DC29227652001CCB65 /* TeamId.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = TeamId.xcconfig; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
9964867F0862B4D9FB6ABFC7 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
C1FC908188C4E8695729CB06 /* Pods_WidgetsGallery.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
7555FF72242A565900829871 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
AB1DB47929225F7C00F7AF9C /* Configuration */,
|
||||
7555FF7D242A565900829871 /* iosApp */,
|
||||
7555FF7C242A565900829871 /* Products */,
|
||||
E1DAFBE8E1CFC0878361EF0E /* Pods */,
|
||||
B62309C7396AD7BF607A63B2 /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
7555FF7C242A565900829871 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7555FF7B242A565900829871 /* WidgetsGallery.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
7555FF7D242A565900829871 /* iosApp */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
7555FF8C242A565B00829871 /* Info.plist */,
|
||||
2152FB032600AC8F00CF470E /* iosApp.swift */,
|
||||
);
|
||||
path = iosApp;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
AB1DB47929225F7C00F7AF9C /* Configuration */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
AB3632DC29227652001CCB65 /* TeamId.xcconfig */,
|
||||
);
|
||||
path = Configuration;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B62309C7396AD7BF607A63B2 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8DE96E47030356CE6AD9794A /* Pods_WidgetsGallery.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E1DAFBE8E1CFC0878361EF0E /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1EB65E27D2C0F884D0A1A133 /* Pods-WidgetsGallery.debug.xcconfig */,
|
||||
3D7A606AB0AD7636269BD9D0 /* Pods-WidgetsGallery.release.xcconfig */,
|
||||
);
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
7555FF7A242A565900829871 /* WidgetsGallery */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 7555FFA5242A565B00829871 /* Build configuration list for PBXNativeTarget "WidgetsGallery" */;
|
||||
buildPhases = (
|
||||
E8D673591E7196AEA2EA10E2 /* [CP] Check Pods Manifest.lock */,
|
||||
7555FF77242A565900829871 /* Sources */,
|
||||
7555FF79242A565900829871 /* Resources */,
|
||||
9964867F0862B4D9FB6ABFC7 /* Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = WidgetsGallery;
|
||||
productName = iosApp;
|
||||
productReference = 7555FF7B242A565900829871 /* WidgetsGallery.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
7555FF73242A565900829871 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 1130;
|
||||
LastUpgradeCheck = 1130;
|
||||
ORGANIZATIONNAME = org.jetbrains;
|
||||
TargetAttributes = {
|
||||
7555FF7A242A565900829871 = {
|
||||
CreatedOnToolsVersion = 11.3.1;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 7555FF76242A565900829871 /* Build configuration list for PBXProject "WidgetsGallery" */;
|
||||
compatibilityVersion = "Xcode 9.3";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 7555FF72242A565900829871;
|
||||
productRefGroup = 7555FF7C242A565900829871 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
7555FF7A242A565900829871 /* WidgetsGallery */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
7555FF79242A565900829871 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
E8D673591E7196AEA2EA10E2 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-WidgetsGallery-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
7555FF77242A565900829871 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
2152FB042600AC8F00CF470E /* iosApp.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
7555FFA3242A565B00829871 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = AB3632DC29227652001CCB65 /* TeamId.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
7555FFA4242A565B00829871 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = AB3632DC29227652001CCB65 /* TeamId.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
7555FFA6242A565B00829871 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 1EB65E27D2C0F884D0A1A133 /* Pods-WidgetsGallery.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
DEVELOPMENT_TEAM = "${TEAM_ID}";
|
||||
ENABLE_PREVIEWS = YES;
|
||||
INFOPLIST_FILE = iosApp/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.jetbrains.WidgetsGallery${TEAM_ID}";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
7555FFA7242A565B00829871 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 3D7A606AB0AD7636269BD9D0 /* Pods-WidgetsGallery.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
DEVELOPMENT_ASSET_PATHS = "";
|
||||
DEVELOPMENT_TEAM = "${TEAM_ID}";
|
||||
ENABLE_PREVIEWS = YES;
|
||||
INFOPLIST_FILE = iosApp/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.jetbrains.WidgetsGallery${TEAM_ID}";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
7555FF76242A565900829871 /* Build configuration list for PBXProject "WidgetsGallery" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
7555FFA3242A565B00829871 /* Debug */,
|
||||
7555FFA4242A565B00829871 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
7555FFA5242A565B00829871 /* Build configuration list for PBXNativeTarget "WidgetsGallery" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
7555FFA6242A565B00829871 /* Debug */,
|
||||
7555FFA7242A565B00829871 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 7555FF73242A565900829871 /* Project object */;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UIApplicationSceneManifest</key>
|
||||
<dict>
|
||||
<key>UIApplicationSupportsMultipleScenes</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<key>UILaunchScreen</key>
|
||||
<dict/>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,15 @@
|
||||
import UIKit
|
||||
import shared
|
||||
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
var window: UIWindow?
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
window = UIWindow(frame: UIScreen.main.bounds)
|
||||
let mainViewController = Main_iosKt.MainViewController()
|
||||
window?.rootViewController = mainViewController
|
||||
window?.makeKeyAndVisible()
|
||||
return true
|
||||
}
|
||||
}
|
||||
BIN
experimental/examples/widgets-gallery/run-configurations.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
14
experimental/examples/widgets-gallery/settings.gradle.kts
Normal file
@@ -0,0 +1,14 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
gradlePluginPortal()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
}
|
||||
rootProject.name = "widgets-gallery"
|
||||
|
||||
include(":androidApp")
|
||||
include(":shared")
|
||||
include(":desktopApp")
|
||||
@@ -0,0 +1,72 @@
|
||||
plugins {
|
||||
kotlin("multiplatform")
|
||||
kotlin("native.cocoapods")
|
||||
id("com.android.library")
|
||||
id("org.jetbrains.compose")
|
||||
}
|
||||
|
||||
version = "1.0-SNAPSHOT"
|
||||
|
||||
kotlin {
|
||||
android()
|
||||
|
||||
jvm("desktop")
|
||||
|
||||
ios()
|
||||
iosSimulatorArm64()
|
||||
|
||||
cocoapods {
|
||||
summary = "Shared code for the sample"
|
||||
homepage = "https://github.com/JetBrains/compose-jb"
|
||||
ios.deploymentTarget = "14.1"
|
||||
podfile = project.file("../iosApp/Podfile")
|
||||
framework {
|
||||
baseName = "shared"
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
val commonMain by getting {
|
||||
dependencies {
|
||||
implementation(compose.runtime)
|
||||
implementation(compose.foundation)
|
||||
implementation(compose.material)
|
||||
implementation(compose.materialIconsExtended)
|
||||
}
|
||||
}
|
||||
val androidMain by getting {
|
||||
dependencies {
|
||||
implementation("androidx.appcompat:appcompat:1.5.1")
|
||||
implementation("androidx.core:core-ktx:1.8.0")
|
||||
}
|
||||
}
|
||||
val iosMain by getting
|
||||
val iosTest by getting
|
||||
val iosSimulatorArm64Main by getting {
|
||||
dependsOn(iosMain)
|
||||
}
|
||||
val iosSimulatorArm64Test by getting {
|
||||
dependsOn(iosTest)
|
||||
}
|
||||
|
||||
val desktopMain by getting {
|
||||
dependencies {
|
||||
implementation(compose.desktop.common)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdk = 33
|
||||
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
|
||||
sourceSets["main"].res.srcDirs("src/androidMain/res", "src/commonMain/resources")
|
||||
defaultConfig {
|
||||
minSdk = 24
|
||||
targetSdk = 33
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="org.jetbrains.compose.demo.widgets.platform"/>
|
||||
@@ -0,0 +1,5 @@
|
||||
import androidx.compose.runtime.Composable
|
||||
import org.jetbrains.compose.demo.widgets.ui.MainView
|
||||
|
||||
@Composable
|
||||
fun MainView() = MainView()
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.jetbrains.compose.demo.widgets.platform
|
||||
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
|
||||
actual fun Modifier.cursorForHorizontalResize() = this
|
||||
@@ -0,0 +1,18 @@
|
||||
package org.jetbrains.compose.demo.widgets.platform
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
|
||||
@Composable
|
||||
actual fun painterResource(res: String): Painter {
|
||||
val id = drawableId(res)
|
||||
return androidx.compose.ui.res.painterResource(id)
|
||||
}
|
||||
|
||||
// TODO: improve resource loading
|
||||
private fun drawableId(res: String): Int {
|
||||
val imageName = res.substringAfterLast("/").substringBeforeLast(".")
|
||||
val drawableClass = R.drawable::class.java
|
||||
val field = drawableClass.getDeclaredField(imageName)
|
||||
return field.get(drawableClass) as Int
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.jetbrains.compose.demo.widgets.platform
|
||||
|
||||
import androidx.compose.foundation.ScrollState
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.Dp
|
||||
|
||||
@Composable
|
||||
actual fun VerticalScrollbar(
|
||||
modifier: Modifier,
|
||||
scrollState: ScrollState
|
||||
) = Unit
|
||||
|
||||
@Composable
|
||||
actual fun VerticalScrollbar(
|
||||
modifier: Modifier,
|
||||
scrollState: LazyListState,
|
||||
itemCount: Int,
|
||||
averageItemSize: Dp
|
||||
) = Unit
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.jetbrains.compose.demo.widgets.platform
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.foundation.isSystemInDarkTheme as androidSystemIsInDarkTheme
|
||||
|
||||
@Composable
|
||||
actual fun isSystemInDarkTheme(): Boolean =
|
||||
androidSystemIsInDarkTheme()
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.jetbrains.compose.demo.widgets.data
|
||||
|
||||
import org.jetbrains.compose.demo.widgets.data.model.Item
|
||||
import org.jetbrains.compose.demo.widgets.data.model.Tweet
|
||||
import org.jetbrains.compose.demo.widgets.platform.Res
|
||||
|
||||
object DemoDataProvider {
|
||||
val item = Item(
|
||||
1,
|
||||
"Awesome List Item",
|
||||
"Very awesome list item has very awesome subtitle. This is bit long",
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.jetbrains.compose.demo.widgets.data.model
|
||||
|
||||
data class Item(
|
||||
val id: Int,
|
||||
val title: String,
|
||||
val subtitle: String,
|
||||
val source: String = "demo source"
|
||||
)
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.jetbrains.compose.demo.widgets.data.model
|
||||
|
||||
data class Tweet(
|
||||
val id: Int,
|
||||
val text: String,
|
||||
val author: String,
|
||||
val handle: String,
|
||||
val time: String,
|
||||
val authorImageId: String,
|
||||
val likesCount: Int,
|
||||
val commentsCount: Int,
|
||||
val retweetCount: Int,
|
||||
val source: String,
|
||||
val tweetImageId: String? = null
|
||||
)
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.jetbrains.compose.demo.widgets.platform
|
||||
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
|
||||
expect fun Modifier.cursorForHorizontalResize(): Modifier
|
||||
@@ -0,0 +1,20 @@
|
||||
package org.jetbrains.compose.demo.widgets.platform
|
||||
|
||||
object Res {
|
||||
object drawable {
|
||||
val p1 = "drawable-nodpi/p1.jpeg"
|
||||
val p2 = "drawable-nodpi/p2.jpeg"
|
||||
val p3 = "drawable-nodpi/p3.jpeg"
|
||||
val p6 = "drawable-nodpi/p6.jpeg"
|
||||
|
||||
val ic_instagram = "drawable/ic_instagram.xml"
|
||||
val ic_send = "drawable/ic_send.xml"
|
||||
val ic_twitter = "drawable/ic_twitter.xml"
|
||||
}
|
||||
|
||||
object string {
|
||||
val spotify_nav_home = "Home"
|
||||
val spotify_nav_search = "Search"
|
||||
val spotify_nav_library = "Your Library"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.jetbrains.compose.demo.widgets.platform
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
|
||||
@Composable
|
||||
internal expect fun painterResource(res: String): Painter
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.jetbrains.compose.demo.widgets.platform
|
||||
|
||||
import androidx.compose.foundation.ScrollState
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.Dp
|
||||
|
||||
@Composable
|
||||
internal expect fun VerticalScrollbar(
|
||||
modifier: Modifier,
|
||||
scrollState: ScrollState
|
||||
)
|
||||
|
||||
@Composable
|
||||
internal expect fun VerticalScrollbar(
|
||||
modifier: Modifier,
|
||||
scrollState: LazyListState,
|
||||
itemCount: Int,
|
||||
averageItemSize: Dp
|
||||
)
|
||||
@@ -0,0 +1,3 @@
|
||||
package org.jetbrains.compose.demo.widgets.platform
|
||||
|
||||
internal expect fun isSystemInDarkTheme(): Boolean
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.jetbrains.compose.demo.widgets.theme
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
val green200 = Color(0xffa5d6a7)
|
||||
val green500 = Color(0xff4caf50)
|
||||
val green700 = Color(0xff388e3c)
|
||||
|
||||
val blue500 = Color(0xFF3F51B5)
|
||||
val blue200 = Color(0xFF9FA8DA)
|
||||
val blue700 = Color(0xFF303F9F)
|
||||
|
||||
val purple200 = Color(0xFFB39DDB)
|
||||
val purple = Color(0xFF833AB4)
|
||||
val purple700 = Color(0xFF512DA8)
|
||||
|
||||
val orange200 = Color(0xFFff7961)
|
||||
val orange500 = Color(0xFFf44336)
|
||||
val orange700 = Color(0xFFba000d)
|
||||
|
||||
|
||||
val teal200 = Color(0xff80deea)
|
||||
val twitterColor = Color(0xFF1DA1F2)
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.jetbrains.compose.demo.widgets.theme
|
||||
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Shapes
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
val shapes = Shapes(
|
||||
small = RoundedCornerShape(4.dp),
|
||||
medium = RoundedCornerShape(4.dp),
|
||||
large = RoundedCornerShape(0.dp)
|
||||
)
|
||||
@@ -0,0 +1,136 @@
|
||||
package org.jetbrains.compose.demo.widgets.theme
|
||||
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.darkColors
|
||||
import androidx.compose.material.lightColors
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import org.jetbrains.compose.demo.widgets.platform.isSystemInDarkTheme
|
||||
import org.jetbrains.compose.demo.widgets.theme.ColorPallet.*
|
||||
|
||||
// dark palettes
|
||||
private val DarkGreenColorPalette = darkColors(
|
||||
primary = green200,
|
||||
primaryVariant = green700,
|
||||
secondary = teal200,
|
||||
background = Color.Black,
|
||||
surface = Color.Black,
|
||||
onPrimary = Color.Black,
|
||||
onSecondary = Color.White,
|
||||
onBackground = Color.White,
|
||||
onSurface = Color.White,
|
||||
error = Color.Red,
|
||||
)
|
||||
|
||||
private val DarkPurpleColorPalette = darkColors(
|
||||
primary = purple200,
|
||||
primaryVariant = purple700,
|
||||
secondary = teal200,
|
||||
background = Color.Black,
|
||||
surface = Color.Black,
|
||||
onPrimary = Color.Black,
|
||||
onSecondary = Color.White,
|
||||
onBackground = Color.White,
|
||||
onSurface = Color.White,
|
||||
error = Color.Red,
|
||||
)
|
||||
|
||||
private val DarkBlueColorPalette = darkColors(
|
||||
primary = blue200,
|
||||
primaryVariant = blue700,
|
||||
secondary = teal200,
|
||||
background = Color.Black,
|
||||
surface = Color.Black,
|
||||
onPrimary = Color.Black,
|
||||
onSecondary = Color.White,
|
||||
onBackground = Color.White,
|
||||
onSurface = Color.White,
|
||||
error = Color.Red,
|
||||
)
|
||||
|
||||
private val DarkOrangeColorPalette = darkColors(
|
||||
primary = orange200,
|
||||
primaryVariant = orange700,
|
||||
secondary = teal200,
|
||||
background = Color.Black,
|
||||
surface = Color.Black,
|
||||
onPrimary = Color.Black,
|
||||
onSecondary = Color.White,
|
||||
onBackground = Color.White,
|
||||
onSurface = Color.White,
|
||||
error = Color.Red,
|
||||
)
|
||||
|
||||
// Light pallets
|
||||
private val LightGreenColorPalette = lightColors(
|
||||
primary = green500,
|
||||
primaryVariant = green700,
|
||||
secondary = teal200,
|
||||
background = Color.White,
|
||||
surface = Color.White,
|
||||
onPrimary = Color.White,
|
||||
onSecondary = Color.Black,
|
||||
onBackground = Color.Black,
|
||||
onSurface = Color.Black
|
||||
)
|
||||
|
||||
private val LightPurpleColorPalette = lightColors(
|
||||
primary = purple,
|
||||
primaryVariant = purple700,
|
||||
secondary = teal200,
|
||||
background = Color.White,
|
||||
surface = Color.White,
|
||||
onPrimary = Color.White,
|
||||
onSecondary = Color.Black,
|
||||
onBackground = Color.Black,
|
||||
onSurface = Color.Black
|
||||
)
|
||||
|
||||
private val LightBlueColorPalette = lightColors(
|
||||
primary = blue500,
|
||||
primaryVariant = blue700,
|
||||
secondary = teal200,
|
||||
background = Color.White,
|
||||
surface = Color.White,
|
||||
onPrimary = Color.White,
|
||||
onSecondary = Color.Black,
|
||||
onBackground = Color.Black,
|
||||
onSurface = Color.Black
|
||||
)
|
||||
|
||||
private val LightOrangeColorPalette = lightColors(
|
||||
primary = orange500,
|
||||
primaryVariant = orange700,
|
||||
secondary = teal200,
|
||||
background = Color.White,
|
||||
surface = Color.White,
|
||||
onPrimary = Color.White,
|
||||
onSecondary = Color.Black,
|
||||
onBackground = Color.Black,
|
||||
onSurface = Color.Black
|
||||
)
|
||||
|
||||
enum class ColorPallet {
|
||||
PURPLE, GREEN, ORANGE, BLUE
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun WidgetGalleryTheme(
|
||||
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||
colorPallet: ColorPallet = GREEN,
|
||||
content: @Composable() () -> Unit,
|
||||
) {
|
||||
val colors = when (colorPallet) {
|
||||
GREEN -> if (darkTheme) DarkGreenColorPalette else LightGreenColorPalette
|
||||
PURPLE -> if (darkTheme) DarkPurpleColorPalette else LightPurpleColorPalette
|
||||
ORANGE -> if (darkTheme) DarkOrangeColorPalette else LightOrangeColorPalette
|
||||
BLUE -> if (darkTheme) DarkBlueColorPalette else LightBlueColorPalette
|
||||
}
|
||||
|
||||
MaterialTheme(
|
||||
colors = colors,
|
||||
typography = typography,
|
||||
shapes = shapes,
|
||||
content = content
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package org.jetbrains.compose.demo.widgets.theme
|
||||
|
||||
import androidx.compose.material.Typography
|
||||
import androidx.compose.ui.graphics.Color
|
||||
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
|
||||
|
||||
val typography = Typography(
|
||||
body1 = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 16.sp
|
||||
),
|
||||
body2 = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 14.sp
|
||||
),
|
||||
button = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.W500,
|
||||
fontSize = 14.sp
|
||||
),
|
||||
caption = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 12.sp,
|
||||
),
|
||||
subtitle1 = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 16.sp,
|
||||
color = Color.Gray
|
||||
),
|
||||
subtitle2 = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 14.sp,
|
||||
color = Color.Gray
|
||||
),
|
||||
)
|
||||
@@ -0,0 +1,160 @@
|
||||
package org.jetbrains.compose.demo.widgets.ui
|
||||
|
||||
import androidx.compose.animation.core.Spring
|
||||
import androidx.compose.animation.core.SpringSpec
|
||||
import androidx.compose.animation.core.animateDpAsState
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.hoverable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.interaction.collectIsHoveredAsState
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material.LocalContentColor
|
||||
import androidx.compose.material.Surface
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clipToBounds
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.semantics.Role
|
||||
import androidx.compose.ui.semantics.SemanticsProperties
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.TextUnit
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import org.jetbrains.compose.demo.widgets.platform.VerticalScrollbar
|
||||
import org.jetbrains.compose.demo.widgets.theme.WidgetGalleryTheme
|
||||
import org.jetbrains.compose.demo.widgets.ui.utils.PanelState
|
||||
import org.jetbrains.compose.demo.widgets.ui.utils.ResizablePanel
|
||||
import org.jetbrains.compose.demo.widgets.ui.utils.VerticalSplittable
|
||||
import org.jetbrains.compose.demo.widgets.ui.utils.withoutWidthConstraints
|
||||
|
||||
@Composable
|
||||
internal fun MainView() {
|
||||
WidgetGalleryTheme {
|
||||
Surface {
|
||||
WidgetsPanel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun WidgetsPanel() {
|
||||
val widgetsTypeState = rememberSaveable { mutableStateOf(WidgetsType.sortedValues.first()) }
|
||||
val panelState = remember { PanelState() }
|
||||
|
||||
val animatedSize = if (panelState.splitter.isResizing) {
|
||||
if (panelState.isExpanded) panelState.expandedSize else panelState.collapsedSize
|
||||
} else {
|
||||
animateDpAsState(
|
||||
if (panelState.isExpanded) panelState.expandedSize else panelState.collapsedSize,
|
||||
SpringSpec(stiffness = Spring.StiffnessLow)
|
||||
).value
|
||||
}
|
||||
|
||||
VerticalSplittable(
|
||||
Modifier.fillMaxSize(),
|
||||
panelState.splitter,
|
||||
onResize = {
|
||||
panelState.expandedSize =
|
||||
(panelState.expandedSize + it).coerceAtLeast(panelState.expandedSizeMin)
|
||||
}
|
||||
) {
|
||||
ResizablePanel(
|
||||
Modifier.width(animatedSize).fillMaxHeight(),
|
||||
title = "Widgets",
|
||||
state = panelState
|
||||
) {
|
||||
WidgetsListView(widgetsTypeState)
|
||||
}
|
||||
|
||||
Box {
|
||||
Column {
|
||||
WidgetsView(
|
||||
widgetsTypeState,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun WidgetsListView(widgetsTypeState: MutableState<WidgetsType>) {
|
||||
Box {
|
||||
with(LocalDensity.current) {
|
||||
val scrollState = rememberLazyListState()
|
||||
|
||||
val fontSize = 14.sp
|
||||
val lineHeight = fontSize.toDp() * 1.5f
|
||||
|
||||
val sortedItems = WidgetsType.sortedValues
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize().withoutWidthConstraints(),
|
||||
state = scrollState
|
||||
) {
|
||||
items(sortedItems) {
|
||||
WidgetsListItemViewImpl(it, widgetsTypeState, fontSize, lineHeight)
|
||||
}
|
||||
}
|
||||
|
||||
VerticalScrollbar(
|
||||
Modifier.align(Alignment.CenterEnd),
|
||||
scrollState,
|
||||
sortedItems.size,
|
||||
lineHeight
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun WidgetsListItemViewImpl(
|
||||
widgetsType: WidgetsType,
|
||||
widgetsTypeState: MutableState<WidgetsType>,
|
||||
fontSize: TextUnit,
|
||||
height: Dp
|
||||
) {
|
||||
val isCurrent = widgetsTypeState.value == widgetsType
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.wrapContentHeight()
|
||||
.clickable { widgetsTypeState.value = widgetsType }
|
||||
.semantics {
|
||||
set(SemanticsProperties.Role, Role.Button)
|
||||
}
|
||||
.height(height)
|
||||
.padding(start = 16.dp)
|
||||
) {
|
||||
val inFocusInteractionSource = remember { MutableInteractionSource() }
|
||||
val inFocus by inFocusInteractionSource.collectIsHoveredAsState()
|
||||
val textColor = LocalContentColor.current.let {
|
||||
when {
|
||||
isCurrent -> it
|
||||
inFocus -> it.copy(alpha = 0.6f)
|
||||
else -> it.copy(alpha = 0.4f)
|
||||
}
|
||||
}
|
||||
|
||||
Text(
|
||||
text = widgetsType.readableName,
|
||||
color = textColor,
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterVertically)
|
||||
.clipToBounds()
|
||||
.hoverable(inFocusInteractionSource),
|
||||
softWrap = true,
|
||||
fontSize = fontSize,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.jetbrains.compose.demo.widgets.ui
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.ui.Modifier
|
||||
import org.jetbrains.compose.demo.widgets.ui.screens.*
|
||||
|
||||
@Composable
|
||||
internal fun WidgetsView(
|
||||
widgetsTypeState: MutableState<WidgetsType>,
|
||||
modifier: Modifier
|
||||
) {
|
||||
Column(modifier = modifier.verticalScroll(state = rememberScrollState())) {
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
val exhaustive = when (widgetsTypeState.value) {
|
||||
WidgetsType.APP_BARS -> AppBars()
|
||||
WidgetsType.BUTTONS -> Buttons()
|
||||
WidgetsType.CHIPS -> Chips()
|
||||
WidgetsType.LOADERS -> Loaders()
|
||||
WidgetsType.SNACK_BARS -> SnackBars()
|
||||
WidgetsType.TEXT_VIEWS -> TextViews()
|
||||
WidgetsType.TEXT_INPUTS -> TextInputs()
|
||||
WidgetsType.TOGGLES -> Toggles()
|
||||
WidgetsType.UI_CARDS -> UICards()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package org.jetbrains.compose.demo.widgets.ui
|
||||
|
||||
enum class WidgetsType(private val customTitle: String? = null) {
|
||||
APP_BARS,
|
||||
BUTTONS,
|
||||
CHIPS,
|
||||
LOADERS,
|
||||
SNACK_BARS,
|
||||
TEXT_VIEWS,
|
||||
TEXT_INPUTS,
|
||||
TOGGLES,
|
||||
UI_CARDS("UI Cards");
|
||||
|
||||
val readableName: String by lazy {
|
||||
name.split("_")
|
||||
.map { it.lowercase() }
|
||||
.mapIndexed { i, it ->
|
||||
if (i == 0) it.replaceFirstChar {
|
||||
if (it.isLowerCase()) it.titlecase() else it.toString()
|
||||
} else it
|
||||
}.joinToString(" ")
|
||||
}
|
||||
|
||||
val title: String
|
||||
get() = customTitle ?: readableName
|
||||
|
||||
companion object {
|
||||
val sortedValues: List<WidgetsType> by lazy {
|
||||
values().sortedBy { it.name }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
package org.jetbrains.compose.demo.widgets.ui.screens
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.MoreHoriz
|
||||
import androidx.compose.material.icons.filled.StarBorder
|
||||
import androidx.compose.material.icons.outlined.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.jetbrains.compose.demo.widgets.platform.Res
|
||||
import org.jetbrains.compose.demo.widgets.platform.painterResource
|
||||
import org.jetbrains.compose.demo.widgets.theme.twitterColor
|
||||
import org.jetbrains.compose.demo.widgets.ui.utils.SubtitleText
|
||||
import org.jetbrains.compose.demo.widgets.ui.utils.TitleText
|
||||
|
||||
@Composable
|
||||
internal fun AppBars() {
|
||||
TopAppBarsDemo()
|
||||
BottomAppBarDemo()
|
||||
NavigationBarDemo()
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TopAppBarsDemo() {
|
||||
SubtitleText(subtitle = "Top App bar")
|
||||
|
||||
TopAppBar(
|
||||
title = { Text(text = "Home") },
|
||||
elevation = 8.dp,
|
||||
navigationIcon = {
|
||||
IconButton(onClick = {}) {
|
||||
Icon(Icons.Default.ArrowBack, contentDescription = "ArrowBack")
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
TopAppBar(
|
||||
title = { Text(text = "Instagram") },
|
||||
backgroundColor = MaterialTheme.colors.surface,
|
||||
contentColor = MaterialTheme.colors.onSurface,
|
||||
elevation = 8.dp,
|
||||
navigationIcon = {
|
||||
IconButton(onClick = {}) {
|
||||
Icon(painterResource(Res.drawable.ic_instagram), contentDescription = "Instagram")
|
||||
}
|
||||
},
|
||||
actions = {
|
||||
IconButton(onClick = {}) {
|
||||
Icon(painterResource(Res.drawable.ic_send), contentDescription = "Send")
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
TopAppBar(
|
||||
title = {
|
||||
Icon(
|
||||
painterResource(Res.drawable.ic_twitter),
|
||||
contentDescription = "Twitter",
|
||||
tint = twitterColor,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
},
|
||||
backgroundColor = MaterialTheme.colors.surface,
|
||||
contentColor = MaterialTheme.colors.onSurface,
|
||||
elevation = 8.dp,
|
||||
navigationIcon = {
|
||||
Image(
|
||||
painterResource(Res.drawable.p6),
|
||||
contentDescription = "",
|
||||
modifier = Modifier.padding(vertical = 4.dp, horizontal = 8.dp)
|
||||
.requiredSize(32.dp).clip(CircleShape)
|
||||
)
|
||||
},
|
||||
actions = {
|
||||
Icon(
|
||||
Icons.Default.StarBorder,
|
||||
contentDescription = "",
|
||||
modifier = Modifier.padding(horizontal = 8.dp)
|
||||
)
|
||||
}
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BottomAppBarDemo() {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
SubtitleText("Bottom app bars: Note bottom app bar support FAB cutouts when used with scafolds see demoUI crypto app")
|
||||
|
||||
BottomAppBar(
|
||||
cutoutShape = CircleShape
|
||||
) {
|
||||
IconButton(onClick = {}) {
|
||||
Icon(Icons.Default.MoreHoriz, contentDescription = "")
|
||||
}
|
||||
TitleText(title = "Bottom App Bar")
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NavigationBarDemo() {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
SubtitleText(subtitle = "Bottom Navigation Bars")
|
||||
val navItemState = remember { mutableStateOf(NavType.HOME) }
|
||||
BottomNavigation(backgroundColor = MaterialTheme.colors.surface) {
|
||||
BottomNavigationItem(
|
||||
icon = { Icon(Icons.Outlined.Home, contentDescription = "Home") },
|
||||
selected = navItemState.value == NavType.HOME,
|
||||
onClick = { navItemState.value = NavType.HOME },
|
||||
label = { Text(text = Res.string.spotify_nav_home) },
|
||||
)
|
||||
BottomNavigationItem(
|
||||
icon = { Icon(Icons.Outlined.Search, contentDescription = "Search") },
|
||||
selected = navItemState.value == NavType.SEARCH,
|
||||
onClick = { navItemState.value = NavType.SEARCH },
|
||||
label = { Text(text = Res.string.spotify_nav_search) }
|
||||
)
|
||||
BottomNavigationItem(
|
||||
icon = { Icon(Icons.Outlined.LibraryMusic, contentDescription = "LibraryMusic") },
|
||||
selected = navItemState.value == NavType.LIBRARY,
|
||||
onClick = { navItemState.value = NavType.LIBRARY },
|
||||
label = { Text(text = Res.string.spotify_nav_library) }
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
BottomNavigation {
|
||||
BottomNavigationItem(
|
||||
icon = { Icon(Icons.Outlined.ReadMore, contentDescription = "ReadMore") },
|
||||
selected = navItemState.value == NavType.HOME,
|
||||
onClick = { navItemState.value = NavType.HOME },
|
||||
)
|
||||
BottomNavigationItem(
|
||||
icon = { Icon(Icons.Outlined.Search, contentDescription = "Search") },
|
||||
selected = navItemState.value == NavType.SEARCH,
|
||||
onClick = { navItemState.value = NavType.SEARCH },
|
||||
)
|
||||
BottomNavigationItem(
|
||||
icon = { Icon(Icons.Outlined.CleanHands, contentDescription = "CleanHands") },
|
||||
selected = navItemState.value == NavType.LIBRARY,
|
||||
onClick = { navItemState.value = NavType.LIBRARY },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private enum class NavType {
|
||||
HOME, SEARCH, LIBRARY
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package org.jetbrains.compose.demo.widgets.ui.screens
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.FavoriteBorder
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.jetbrains.compose.demo.widgets.theme.purple
|
||||
import org.jetbrains.compose.demo.widgets.theme.purple200
|
||||
import org.jetbrains.compose.demo.widgets.theme.typography
|
||||
|
||||
@Composable
|
||||
internal fun Buttons() {
|
||||
Column {
|
||||
Button(onClick = {}, modifier = Modifier.padding(8.dp)) {
|
||||
Text(text = "Main Button")
|
||||
}
|
||||
TextButton(onClick = {}, modifier = Modifier.padding(8.dp)) {
|
||||
Text(text = "Text Button")
|
||||
}
|
||||
TextButton(onClick = {}, modifier = Modifier.padding(8.dp), enabled = false) {
|
||||
Text(text = "Text Disabled")
|
||||
}
|
||||
Button(onClick = {}, modifier = Modifier.padding(8.dp), enabled = false) {
|
||||
Text(text = "Disabled")
|
||||
}
|
||||
Button(
|
||||
onClick = {},
|
||||
modifier = Modifier.padding(8.dp),
|
||||
elevation = ButtonDefaults.elevation()
|
||||
) {
|
||||
Text(text = "Flat")
|
||||
}
|
||||
Button(
|
||||
onClick = {},
|
||||
modifier = Modifier.padding(8.dp),
|
||||
shape = RoundedCornerShape(12.dp)
|
||||
) {
|
||||
Text(text = "Rounded")
|
||||
}
|
||||
OutlinedButton(onClick = {}, modifier = Modifier.padding(8.dp)) {
|
||||
Text(text = "Outline")
|
||||
}
|
||||
Button(onClick = {}, modifier = Modifier.padding(8.dp)) {
|
||||
Row {
|
||||
Icon(Icons.Default.FavoriteBorder, contentDescription = null, modifier = Modifier.padding(end = 4.dp))
|
||||
Text(text = "Icon Button")
|
||||
}
|
||||
}
|
||||
Button(onClick = {}, modifier = Modifier.padding(8.dp)) {
|
||||
Text(text = "Icon Button")
|
||||
Icon(Icons.Default.FavoriteBorder, contentDescription = null, modifier = Modifier.padding(start = 4.dp))
|
||||
}
|
||||
//custom background buttons
|
||||
val outlineButtonColor = ButtonDefaults.outlinedButtonColors(
|
||||
contentColor = purple200,
|
||||
)
|
||||
val mainButtonColor = ButtonDefaults.buttonColors(
|
||||
backgroundColor = purple,
|
||||
contentColor = MaterialTheme.colors.surface
|
||||
)
|
||||
OutlinedButton(
|
||||
colors = outlineButtonColor,
|
||||
onClick = {},
|
||||
modifier = Modifier.padding(8.dp)
|
||||
) {
|
||||
Text(text = "Outline colors")
|
||||
}
|
||||
Button(colors = mainButtonColor, onClick = {}, modifier = Modifier.padding(8.dp)) {
|
||||
Text(text = "Custom colors")
|
||||
}
|
||||
|
||||
val horizontalGradient = Brush.horizontalGradient(
|
||||
colors = listOf(MaterialTheme.colors.primary, MaterialTheme.colors.primaryVariant),
|
||||
0f,
|
||||
250f
|
||||
)
|
||||
val verticalGradient = Brush.verticalGradient(
|
||||
colors = listOf(MaterialTheme.colors.primary, MaterialTheme.colors.primaryVariant),
|
||||
startY = 0f,
|
||||
endY = 100f
|
||||
)
|
||||
Text(
|
||||
text = "Horizontal gradient",
|
||||
style = typography.body2.copy(color = Color.White),
|
||||
modifier = Modifier.padding(12.dp).clickable(onClick = {})
|
||||
.clip(RoundedCornerShape(4.dp))
|
||||
.background(brush = horizontalGradient).padding(12.dp)
|
||||
)
|
||||
Text(
|
||||
text = "Vertical gradient",
|
||||
style = typography.body1.copy(color = Color.White),
|
||||
modifier = Modifier.padding(12.dp).clickable(onClick = {})
|
||||
.clip(RoundedCornerShape(4.dp))
|
||||
.background(brush = verticalGradient).padding(12.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
package org.jetbrains.compose.demo.widgets.ui.screens
|
||||
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Surface
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.jetbrains.compose.demo.widgets.platform.Res
|
||||
import org.jetbrains.compose.demo.widgets.platform.painterResource
|
||||
import org.jetbrains.compose.demo.widgets.ui.utils.SubtitleText
|
||||
|
||||
@Composable
|
||||
internal fun Chips() {
|
||||
// There is no in-built chips but you can make yours like below
|
||||
SubtitleText(subtitle = "Custom chips with surface")
|
||||
Column(modifier = Modifier.padding(8.dp)) {
|
||||
YoutubeChip(selected = true, text = "Chip", modifier = Modifier.padding(horizontal = 8.dp))
|
||||
Spacer(modifier = Modifier.padding(8.dp))
|
||||
YoutubeChip(
|
||||
selected = false,
|
||||
text = "Inactive",
|
||||
modifier = Modifier.padding(horizontal = 8.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.padding(8.dp))
|
||||
CustomImageChip(text = "custom", imageId = Res.drawable.p2, selected = true)
|
||||
Spacer(modifier = Modifier.padding(8.dp))
|
||||
CustomImageChip(text = "custom2", imageId = Res.drawable.p6, selected = false)
|
||||
}
|
||||
SubtitleText(subtitle = "Buttons with circle clipping.")
|
||||
Column(modifier = Modifier.padding(8.dp)) {
|
||||
Button(
|
||||
onClick = {},
|
||||
modifier = Modifier.padding(8.dp).clip(CircleShape)
|
||||
) {
|
||||
Text(text = "Chip button")
|
||||
}
|
||||
Button(
|
||||
onClick = {},
|
||||
enabled = false,
|
||||
modifier = Modifier.padding(8.dp).clip(CircleShape)
|
||||
) {
|
||||
Text(text = "Disabled chip")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Inspired from jetcaster sample. I hope compose can add simple Chip UI element that can
|
||||
// support images or icons with multiple states.
|
||||
@Composable
|
||||
private fun CustomImageChip(
|
||||
text: String,
|
||||
imageId: String,
|
||||
selected: Boolean,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Surface(
|
||||
color = when {
|
||||
selected -> MaterialTheme.colors.primary
|
||||
else -> Color.Transparent
|
||||
},
|
||||
contentColor = when {
|
||||
selected -> MaterialTheme.colors.onPrimary
|
||||
else -> Color.LightGray
|
||||
},
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
border = BorderStroke(
|
||||
width = 1.dp,
|
||||
color = when {
|
||||
selected -> MaterialTheme.colors.primary
|
||||
else -> Color.LightGray
|
||||
}
|
||||
),
|
||||
modifier = modifier
|
||||
) {
|
||||
Row(modifier = Modifier) {
|
||||
Image(
|
||||
painterResource(imageId),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.padding(8.dp).requiredSize(20.dp).clip(CircleShape)
|
||||
)
|
||||
Text(
|
||||
text = text,
|
||||
style = MaterialTheme.typography.body2,
|
||||
modifier = Modifier.padding(end = 8.dp, top = 8.dp, bottom = 8.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun YoutubeChip(selected: Boolean, text: String, modifier: Modifier = Modifier) {
|
||||
Surface(
|
||||
color = when {
|
||||
selected -> MaterialTheme.colors.onSurface
|
||||
else -> Color.Transparent
|
||||
},
|
||||
contentColor = when {
|
||||
selected -> MaterialTheme.colors.onPrimary
|
||||
else -> Color.LightGray
|
||||
},
|
||||
shape = CircleShape,
|
||||
border = BorderStroke(
|
||||
width = 1.dp,
|
||||
color = when {
|
||||
selected -> MaterialTheme.colors.primary
|
||||
else -> Color.LightGray
|
||||
}
|
||||
),
|
||||
modifier = modifier
|
||||
) {
|
||||
Text(
|
||||
text = text,
|
||||
textAlign = TextAlign.Center,
|
||||
style = MaterialTheme.typography.body2,
|
||||
modifier = Modifier.padding(8.dp)
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package org.jetbrains.compose.demo.widgets.ui.screens
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.CircularProgressIndicator
|
||||
import androidx.compose.material.LinearProgressIndicator
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
internal fun Loaders() {
|
||||
AlignedColumn {
|
||||
CircularProgressIndicator()
|
||||
}
|
||||
|
||||
AlignedColumn {
|
||||
CircularProgressIndicator(strokeWidth = 8.dp)
|
||||
}
|
||||
|
||||
AlignedColumn {
|
||||
LinearProgressIndicator()
|
||||
}
|
||||
|
||||
AlignedColumn {
|
||||
LinearProgressIndicator()
|
||||
Text(text = "Loading with text...", modifier = Modifier.padding(8.dp))
|
||||
}
|
||||
}
|
||||
@Composable
|
||||
private fun AlignedColumn(content: @Composable () -> Unit) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth().padding(16.dp)
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.jetbrains.compose.demo.widgets.ui.screens
|
||||
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.Snackbar
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.jetbrains.compose.demo.widgets.theme.typography
|
||||
|
||||
@Composable
|
||||
internal fun SnackBars() {
|
||||
Snackbar(modifier = Modifier.padding(4.dp)) {
|
||||
Text(text = "This is a basic snackbar")
|
||||
}
|
||||
Snackbar(
|
||||
modifier = Modifier.padding(4.dp),
|
||||
action = {
|
||||
TextButton(onClick = {}) {
|
||||
Text(text = "Remove")
|
||||
}
|
||||
}
|
||||
) {
|
||||
Text(text = "This is a basic Snackbar with action item")
|
||||
}
|
||||
Snackbar(
|
||||
modifier = Modifier.padding(4.dp),
|
||||
actionOnNewLine = true,
|
||||
action = {
|
||||
TextButton(onClick = {}) {
|
||||
Text(text = "Remove")
|
||||
}
|
||||
}
|
||||
) {
|
||||
Text(text = "Snackbar with action item below text")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package org.jetbrains.compose.demo.widgets.ui.screens
|
||||
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.OutlinedTextField
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TextField
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Edit
|
||||
import androidx.compose.material.icons.filled.Email
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
internal fun TextInputs() {
|
||||
var text by remember { mutableStateOf(TextFieldValue("")) }
|
||||
|
||||
// TODO Explore CoreTextField
|
||||
// CoreTextField(
|
||||
// value = text,
|
||||
// onValueChange = { newValue -> text = newValue },
|
||||
// modifier = Modifier.padding(8.dp).preferredSize(0.dp),
|
||||
// cursorColor = Color.Magenta
|
||||
// )
|
||||
TextField(
|
||||
value = text,
|
||||
onValueChange = { newValue -> text = newValue },
|
||||
modifier = Modifier.padding(8.dp).fillMaxWidth(),
|
||||
label = { Text("label") },
|
||||
placeholder = { Text("placeholder") }
|
||||
)
|
||||
|
||||
OutlinedTextField(
|
||||
value = text,
|
||||
modifier = Modifier.padding(8.dp).fillMaxWidth(),
|
||||
label = { Text(text = "Password") },
|
||||
placeholder = { Text(text = "12334444") },
|
||||
visualTransformation = PasswordVisualTransformation(),
|
||||
onValueChange = {
|
||||
text = it
|
||||
},
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password)
|
||||
)
|
||||
|
||||
OutlinedTextField(
|
||||
value = text,
|
||||
leadingIcon = { Icon(Icons.Default.Email, contentDescription = "Email") },
|
||||
modifier = Modifier.padding(8.dp).fillMaxWidth(),
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text),
|
||||
label = { Text(text = "Email address") },
|
||||
placeholder = { Text(text = "Your email") },
|
||||
onValueChange = {
|
||||
text = it
|
||||
}
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = text,
|
||||
leadingIcon = { Icon(Icons.Default.Email, contentDescription = "Email") },
|
||||
trailingIcon = { Icon(Icons.Default.Edit, contentDescription = "Edit") },
|
||||
modifier = Modifier.padding(8.dp).fillMaxWidth(),
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text),
|
||||
label = { Text(text = "Email address") },
|
||||
placeholder = { Text(text = "Your email") },
|
||||
onValueChange = {
|
||||
text = it
|
||||
}
|
||||
)
|
||||
|
||||
var numberText by remember { mutableStateOf(TextFieldValue("")) }
|
||||
OutlinedTextField(value = numberText,
|
||||
modifier = Modifier.padding(8.dp).fillMaxWidth(),
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
||||
label = { Text(text = "Phone number") },
|
||||
placeholder = { Text(text = "88888888") },
|
||||
onValueChange = {
|
||||
numberText = it
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package org.jetbrains.compose.demo.widgets.ui.screens
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextDecoration
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.jetbrains.compose.demo.widgets.theme.typography
|
||||
import org.jetbrains.compose.demo.widgets.ui.utils.SubtitleText
|
||||
|
||||
@Composable
|
||||
internal fun TextViews() {
|
||||
Column {
|
||||
val textModifier = Modifier.padding(horizontal = 8.dp)
|
||||
|
||||
SubtitleText(subtitle = "Font weights")
|
||||
Text(text = "Plain", modifier = textModifier)
|
||||
Text(
|
||||
text = "Medium Bold",
|
||||
style = typography.body1.copy(fontWeight = FontWeight.Medium),
|
||||
modifier = textModifier
|
||||
)
|
||||
Text(
|
||||
text = "Bold",
|
||||
style = typography.body1.copy(fontWeight = FontWeight.Bold),
|
||||
modifier = textModifier
|
||||
)
|
||||
Text(
|
||||
text = "Extra Bold",
|
||||
style = typography.body1.copy(fontWeight = FontWeight.Bold),
|
||||
modifier = textModifier
|
||||
)
|
||||
|
||||
SubtitleText(subtitle = "Text decorations")
|
||||
Text(text = "Default", modifier = textModifier)
|
||||
Text(
|
||||
text = "Underline",
|
||||
textDecoration = TextDecoration.Underline,
|
||||
modifier = textModifier
|
||||
)
|
||||
Text(
|
||||
text = "LineThrough",
|
||||
textDecoration = TextDecoration.LineThrough,
|
||||
modifier = textModifier
|
||||
)
|
||||
Text(
|
||||
text = "UnderlineLineThrough",
|
||||
textDecoration = TextDecoration.combine(
|
||||
listOf(
|
||||
TextDecoration.Underline,
|
||||
TextDecoration.LineThrough
|
||||
)
|
||||
),
|
||||
modifier = textModifier
|
||||
)
|
||||
|
||||
SubtitleText(subtitle = "Overflow")
|
||||
Text(
|
||||
text = "Ellipsis: This text is supposed to ellipsis with max 1 line allowed for this",
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = textModifier,
|
||||
maxLines = 1
|
||||
)
|
||||
Text(
|
||||
text = "Clip: This text is supposed to clip with max 1 line allowed for this",
|
||||
overflow = TextOverflow.Clip,
|
||||
modifier = textModifier,
|
||||
maxLines = 1
|
||||
)
|
||||
}
|
||||
|
||||
/* TODO: https://github.com/JetBrains/compose-jb/issues/106
|
||||
SubtitleText(subtitle = "font family dynamic")
|
||||
Row {
|
||||
Text(text = "Default", modifier = textModifier)
|
||||
Text(
|
||||
text = "Cursive",
|
||||
style = typography.body1.copy(fontFamily = FontFamily.Cursive),
|
||||
modifier = textModifier
|
||||
)
|
||||
Text(
|
||||
text = "SansSerif",
|
||||
style = typography.body1.copy(fontFamily = FontFamily.SansSerif),
|
||||
modifier = textModifier
|
||||
)
|
||||
Text(
|
||||
text = "Monospace",
|
||||
style = typography.body1.copy(fontFamily = FontFamily.Monospace),
|
||||
modifier = textModifier
|
||||
)
|
||||
} */
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package org.jetbrains.compose.demo.widgets.ui.screens
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
internal fun Toggles() {
|
||||
Column {
|
||||
var checked by remember { mutableStateOf(true) }
|
||||
Checkbox(
|
||||
checked = checked,
|
||||
modifier = Modifier.padding(8.dp),
|
||||
onCheckedChange = { checked = !checked }
|
||||
)
|
||||
|
||||
var switched by remember { mutableStateOf(true) }
|
||||
Switch(
|
||||
checked = switched,
|
||||
colors = SwitchDefaults.colors(checkedThumbColor = MaterialTheme.colors.primary),
|
||||
modifier = Modifier.padding(8.dp),
|
||||
onCheckedChange = { switched = it }
|
||||
)
|
||||
|
||||
AlignedColumn {
|
||||
var selected by remember { mutableStateOf("Kotlin") }
|
||||
for (lang in arrayOf("Kotlin", "Java", "Swift")) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
RadioButton(selected = selected == lang, onClick = { selected = lang })
|
||||
Text(
|
||||
text = lang,
|
||||
modifier = Modifier.clickable(onClick = { selected = lang }).padding(start = 4.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var sliderState by remember { mutableStateOf(0f) }
|
||||
Slider(value = sliderState, modifier = Modifier.fillMaxWidth().padding(8.dp),
|
||||
onValueChange = { newValue ->
|
||||
sliderState = newValue
|
||||
}
|
||||
)
|
||||
|
||||
var sliderState2 by remember { mutableStateOf(20f) }
|
||||
Slider(value = sliderState2, modifier = Modifier.fillMaxWidth().padding(8.dp),
|
||||
valueRange = 0f..100f,
|
||||
steps = 5,
|
||||
colors = SliderDefaults.colors(thumbColor = MaterialTheme.colors.secondary),
|
||||
onValueChange = { newValue ->
|
||||
sliderState2 = newValue
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AlignedColumn(content: @Composable () -> Unit) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth().padding(16.dp)
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package org.jetbrains.compose.demo.widgets.ui.screens
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ShoppingCart
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.jetbrains.compose.demo.widgets.data.DemoDataProvider
|
||||
import org.jetbrains.compose.demo.widgets.platform.Res
|
||||
import org.jetbrains.compose.demo.widgets.platform.painterResource
|
||||
import org.jetbrains.compose.demo.widgets.theme.typography
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
internal fun UICards() {
|
||||
val item = remember { DemoDataProvider.item }
|
||||
|
||||
Text(
|
||||
text = "Inbuilt box as container for any Clipping/Alignment controls",
|
||||
style = typography.subtitle1,
|
||||
modifier = Modifier.padding(8.dp)
|
||||
)
|
||||
Card(
|
||||
modifier = Modifier.padding(8.dp).fillMaxWidth(),
|
||||
backgroundColor = MaterialTheme.colors.primary,
|
||||
shape = RoundedCornerShape(topStart = 16.dp, bottomEnd = 16.dp)
|
||||
) {
|
||||
Column {
|
||||
Text(
|
||||
text = item.title,
|
||||
modifier = Modifier.padding(8.dp),
|
||||
color = MaterialTheme.colors.onPrimary
|
||||
)
|
||||
Text(
|
||||
text = item.subtitle,
|
||||
modifier = Modifier.padding(8.dp),
|
||||
color = MaterialTheme.colors.onPrimary
|
||||
)
|
||||
}
|
||||
}
|
||||
Divider()
|
||||
|
||||
Text(text = "Inbuilt Card", style = typography.subtitle1, modifier = Modifier.padding(8.dp))
|
||||
Card(
|
||||
modifier = Modifier.padding(16.dp).fillMaxWidth(),
|
||||
shape = RoundedCornerShape(4.dp),
|
||||
elevation = 4.dp
|
||||
) {
|
||||
Row {
|
||||
Image(
|
||||
painterResource(Res.drawable.p3),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.requiredSize(60.dp)
|
||||
)
|
||||
Text(text = item.title, modifier = Modifier.padding(16.dp))
|
||||
}
|
||||
}
|
||||
Divider()
|
||||
|
||||
Text(
|
||||
text = "In-built ListItems",
|
||||
style = typography.subtitle1,
|
||||
modifier = Modifier.padding(8.dp)
|
||||
)
|
||||
ListItem(text = { Text(item.title) }, secondaryText = { Text(item.subtitle) })
|
||||
Divider(modifier = Modifier.padding(4.dp))
|
||||
ListItem(
|
||||
text = { Text(item.title) },
|
||||
secondaryText = { Text(item.subtitle) },
|
||||
singleLineSecondaryText = false
|
||||
)
|
||||
Divider(modifier = Modifier.padding(4.dp))
|
||||
ListItem(text = { Text(item.title) }, secondaryText = { Text(item.subtitle) }, icon = {
|
||||
Image(
|
||||
painterResource(Res.drawable.p3),
|
||||
contentDescription = null
|
||||
)
|
||||
})
|
||||
Divider(modifier = Modifier.padding(4.dp))
|
||||
//I am not sure why this is not going multiline for secondaryText...
|
||||
ListItem(
|
||||
text = { Text(item.title) },
|
||||
secondaryText = { Text(item.subtitle) },
|
||||
icon = { Image(painterResource(Res.drawable.p1), contentDescription = null) },
|
||||
overlineText = { Text("Overline text") },
|
||||
singleLineSecondaryText = false
|
||||
)
|
||||
Divider()
|
||||
ListItem(
|
||||
text = { Text(item.title) },
|
||||
secondaryText = { Text(item.subtitle) },
|
||||
icon = { Image(painterResource(Res.drawable.p2), contentDescription = null) },
|
||||
trailing = { Icon(Icons.Default.ShoppingCart, contentDescription = null) },
|
||||
singleLineSecondaryText = false
|
||||
)
|
||||
Divider()
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.jetbrains.compose.demo.widgets.ui.utils
|
||||
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.layout.layout
|
||||
|
||||
fun Modifier.withoutWidthConstraints() = layout { measurable, constraints ->
|
||||
val placeable = measurable.measure(constraints.copy(maxWidth = Int.MAX_VALUE))
|
||||
layout(constraints.maxWidth, placeable.height) {
|
||||
placeable.place(0, 0)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package org.jetbrains.compose.demo.widgets.ui.utils
|
||||
|
||||
import androidx.compose.animation.core.*
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.LocalContentColor
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.ArrowForward
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clipToBounds
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.semantics.Role
|
||||
import androidx.compose.ui.semantics.SemanticsProperties
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
|
||||
class PanelState {
|
||||
val collapsedSize = 40.dp
|
||||
var expandedSize by mutableStateOf(110.dp)
|
||||
val expandedSizeMin = 120.dp
|
||||
var isExpanded by mutableStateOf(true)
|
||||
val splitter = SplitterState()
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun ResizablePanel(
|
||||
modifier: Modifier,
|
||||
state: PanelState,
|
||||
title: String,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
val alpha = animateFloatAsState(
|
||||
if (state.isExpanded) 1f else 0f,
|
||||
SpringSpec(stiffness = Spring.StiffnessLow),
|
||||
).value
|
||||
|
||||
Box(modifier) {
|
||||
Column {
|
||||
Row(Modifier
|
||||
.height(32.dp)
|
||||
.padding(6.dp)
|
||||
.semantics(mergeDescendants = false) {
|
||||
val text = if (state.isExpanded) "Collapse" else "Expand"
|
||||
set(SemanticsProperties.Text, listOf(
|
||||
AnnotatedString("$text $title panel")
|
||||
))
|
||||
set(SemanticsProperties.Role, Role.Button)
|
||||
}
|
||||
.clickable { state.isExpanded = !state.isExpanded }
|
||||
) {
|
||||
Icon(
|
||||
if (state.isExpanded) Icons.Default.ArrowBack else Icons.Default.ArrowForward,
|
||||
contentDescription = if (state.isExpanded) "Collapse" else "Expand",
|
||||
tint = LocalContentColor.current,
|
||||
modifier = Modifier
|
||||
.size(24.dp)
|
||||
.padding(start = 2.dp, end = 2.dp, bottom = 2.dp)
|
||||
)
|
||||
Text(
|
||||
text = if (state.isExpanded) title else "",
|
||||
modifier = Modifier.fillMaxWidth().clipToBounds(),
|
||||
fontSize = 14.sp
|
||||
)
|
||||
}
|
||||
|
||||
if (state.isExpanded) {
|
||||
Box(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.height(1.dp)
|
||||
.background(Color.Gray)
|
||||
)
|
||||
|
||||
Column(Modifier.fillMaxSize().padding(top = 4.dp).graphicsLayer(alpha = alpha)) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.jetbrains.compose.demo.widgets.ui.utils
|
||||
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import org.jetbrains.compose.demo.widgets.theme.typography
|
||||
|
||||
@Composable
|
||||
internal fun SubtitleText(subtitle: String, modifier: Modifier = Modifier) {
|
||||
Text(text = subtitle, style = typography.subtitle2, modifier = modifier.padding(8.dp))
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun TitleText(title: String) {
|
||||
Text(
|
||||
text = title,
|
||||
style = typography.h6.copy(fontSize = 14.sp),
|
||||
modifier = Modifier.padding(8.dp)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package org.jetbrains.compose.demo.widgets.ui.utils
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.gestures.draggable
|
||||
import androidx.compose.foundation.gestures.Orientation
|
||||
import androidx.compose.foundation.gestures.rememberDraggableState
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.Layout
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.Constraints
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.jetbrains.compose.demo.widgets.platform.cursorForHorizontalResize
|
||||
|
||||
class SplitterState {
|
||||
var isResizing by mutableStateOf(false)
|
||||
var isResizeEnabled by mutableStateOf(true)
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun VerticalSplittable(
|
||||
modifier: Modifier,
|
||||
splitterState: SplitterState,
|
||||
onResize: (delta: Dp) -> Unit,
|
||||
children: @Composable () -> Unit
|
||||
) = Layout({
|
||||
children()
|
||||
VerticalSplitter(splitterState, onResize)
|
||||
}, modifier, measurePolicy = { measurables, constraints ->
|
||||
require(measurables.size == 3)
|
||||
|
||||
val firstPlaceable = measurables[0].measure(constraints.copy(minWidth = 0))
|
||||
val secondWidth = constraints.maxWidth - firstPlaceable.width
|
||||
val secondPlaceable = measurables[1].measure(
|
||||
Constraints(
|
||||
minWidth = secondWidth,
|
||||
maxWidth = secondWidth,
|
||||
minHeight = constraints.maxHeight,
|
||||
maxHeight = constraints.maxHeight
|
||||
)
|
||||
)
|
||||
val splitterPlaceable = measurables[2].measure(constraints)
|
||||
layout(constraints.maxWidth, constraints.maxHeight) {
|
||||
firstPlaceable.place(0, 0)
|
||||
secondPlaceable.place(firstPlaceable.width, 0)
|
||||
splitterPlaceable.place(firstPlaceable.width, 0)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
@Composable
|
||||
internal fun VerticalSplitter(
|
||||
splitterState: SplitterState,
|
||||
onResize: (delta: Dp) -> Unit,
|
||||
color: Color = Color.DarkGray
|
||||
) = Box {
|
||||
val density = LocalDensity.current
|
||||
Box(
|
||||
Modifier
|
||||
.width(8.dp)
|
||||
.fillMaxHeight()
|
||||
.run {
|
||||
if (splitterState.isResizeEnabled) {
|
||||
this.draggable(
|
||||
state = rememberDraggableState {
|
||||
with(density) {
|
||||
onResize(it.toDp())
|
||||
}
|
||||
},
|
||||
orientation = Orientation.Horizontal,
|
||||
startDragImmediately = true,
|
||||
onDragStarted = { splitterState.isResizing = true },
|
||||
onDragStopped = { splitterState.isResizing = false }
|
||||
).cursorForHorizontalResize()
|
||||
} else {
|
||||
this
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
Box(
|
||||
Modifier
|
||||
.width(1.dp)
|
||||
.fillMaxHeight()
|
||||
.background(color)
|
||||
)
|
||||
}
|
||||
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
@@ -0,0 +1,15 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="20dp"
|
||||
android:height="20dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M352,0H160C71.648,0 0,71.648 0,160v192c0,88.352 71.648,160 160,160h192c88.352,0 160,-71.648 160,-160V160C512,71.648 440.352,0 352,0zM464,352c0,61.76 -50.24,112 -112,112H160c-61.76,0 -112,-50.24 -112,-112V160C48,98.24 98.24,48 160,48h192c61.76,0 112,50.24 112,112V352z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M256,128c-70.688,0 -128,57.312 -128,128s57.312,128 128,128s128,-57.312 128,-128S326.688,128 256,128zM256,336c-44.096,0 -80,-35.904 -80,-80c0,-44.128 35.904,-80 80,-80s80,35.872 80,80C336,300.096 300.096,336 256,336z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M393.6,118.4m-17.056,0a17.056,17.056 0,1 1,34.112 0a17.056,17.056 0,1 1,-34.112 0" />
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="20dp"
|
||||
android:height="20dp"
|
||||
android:viewportWidth="512.001"
|
||||
android:viewportHeight="512.001">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M507.608,4.395c-4.243,-4.244 -10.609,-5.549 -16.177,-3.321L9.43,193.872c-5.515,2.206 -9.208,7.458 -9.42,13.395c-0.211,5.936 3.101,11.437 8.445,14.029l190.068,92.181l92.182,190.068c2.514,5.184 7.764,8.455 13.493,8.455c0.178,0 0.357,-0.003 0.536,-0.01c5.935,-0.211 11.189,-3.904 13.394,-9.419l192.8,-481.998C513.156,15.001 511.851,8.638 507.608,4.395zM52.094,209.118L434.72,56.069L206.691,284.096L52.094,209.118zM302.883,459.907l-74.979,-154.599l228.03,-228.027L302.883,459.907z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="20dp"
|
||||
android:height="20dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M459.37,151.716c0.325,4.548 0.325,9.097 0.325,13.645 0,138.72 -105.583,298.558 -298.558,298.558 -59.452,0 -114.68,-17.219 -161.137,-47.106 8.447,0.974 16.568,1.299 25.34,1.299 49.055,0 94.213,-16.568 130.274,-44.832 -46.132,-0.975 -84.792,-31.188 -98.112,-72.772 6.498,0.974 12.995,1.624 19.818,1.624 9.421,0 18.843,-1.3 27.614,-3.573 -48.081,-9.747 -84.143,-51.98 -84.143,-102.985v-1.299c13.969,7.797 30.214,12.67 47.431,13.319 -28.264,-18.843 -46.781,-51.005 -46.781,-87.391 0,-19.492 5.197,-37.36 14.294,-52.954 51.655,63.675 129.3,105.258 216.365,109.807 -1.624,-7.797 -2.599,-15.918 -2.599,-24.04 0,-57.828 46.782,-104.934 104.934,-104.934 30.213,0 57.502,12.67 76.67,33.137 23.715,-4.548 46.456,-13.32 66.599,-25.34 -7.798,24.366 -24.366,44.833 -46.132,57.827 21.117,-2.273 41.584,-8.122 60.426,-16.243 -14.292,20.791 -32.161,39.308 -52.628,54.253z" />
|
||||
</vector>
|
||||
@@ -0,0 +1,5 @@
|
||||
import androidx.compose.runtime.Composable
|
||||
import org.jetbrains.compose.demo.widgets.ui.MainView
|
||||
|
||||
@Composable
|
||||
fun MainView() = MainView()
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.jetbrains.compose.demo.widgets.platform
|
||||
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.input.pointer.PointerIcon
|
||||
import androidx.compose.ui.input.pointer.pointerHoverIcon
|
||||
import androidx.compose.ui.input.pointer.pointerMoveFilter
|
||||
import java.awt.Cursor
|
||||
|
||||
actual fun Modifier.cursorForHorizontalResize(): Modifier =
|
||||
this.pointerHoverIcon(PointerIcon(Cursor(Cursor.E_RESIZE_CURSOR)))
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.jetbrains.compose.demo.widgets.platform
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
|
||||
@Composable
|
||||
actual fun painterResource(res: String): Painter = androidx.compose.ui.res.painterResource(res)
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.jetbrains.compose.demo.widgets.platform
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.ScrollState
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.foundation.rememberScrollbarAdapter
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.Dp
|
||||
|
||||
@Composable
|
||||
actual fun VerticalScrollbar(
|
||||
modifier: Modifier,
|
||||
scrollState: ScrollState
|
||||
) = androidx.compose.foundation.VerticalScrollbar(
|
||||
rememberScrollbarAdapter(scrollState),
|
||||
modifier
|
||||
)
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
actual fun VerticalScrollbar(
|
||||
modifier: Modifier,
|
||||
scrollState: LazyListState,
|
||||
itemCount: Int,
|
||||
averageItemSize: Dp
|
||||
) = androidx.compose.foundation.VerticalScrollbar(
|
||||
rememberScrollbarAdapter(scrollState),
|
||||
modifier
|
||||
)
|
||||
@@ -0,0 +1,5 @@
|
||||
package org.jetbrains.compose.demo.widgets.platform
|
||||
|
||||
import org.jetbrains.skiko.SystemTheme
|
||||
|
||||
actual fun isSystemInDarkTheme(): Boolean = org.jetbrains.skiko.currentSystemTheme == SystemTheme.DARK
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2020-2021 JetBrains s.r.o. and respective authors and developers.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
|
||||
*/
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Application
|
||||
import org.jetbrains.compose.demo.widgets.ui.MainView
|
||||
import platform.UIKit.UIViewController
|
||||
|
||||
fun MainViewController() : UIViewController =
|
||||
Application("Widgets Gallery") {
|
||||
Column {
|
||||
// To skip upper part of screen.
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.height(30.dp)
|
||||
)
|
||||
MainView()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.jetbrains.compose.demo.widgets.platform
|
||||
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
|
||||
actual fun Modifier.cursorForHorizontalResize() = this
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.jetbrains.compose.demo.widgets.platform
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.drawscope.DrawScope
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
|
||||
@Composable
|
||||
internal actual fun painterResource(res: String): Painter =
|
||||
// TODO: use resource API
|
||||
object : Painter() {
|
||||
override val intrinsicSize: Size
|
||||
get() = Size(16f, 16f)
|
||||
|
||||
override fun DrawScope.onDraw() {
|
||||
drawRect(color = Color.Red)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.jetbrains.compose.demo.widgets.platform
|
||||
|
||||
import androidx.compose.foundation.ScrollState
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.Dp
|
||||
|
||||
@Composable
|
||||
internal actual fun VerticalScrollbar(
|
||||
modifier: Modifier,
|
||||
scrollState: ScrollState
|
||||
) = Unit
|
||||
|
||||
@Composable
|
||||
internal actual fun VerticalScrollbar(
|
||||
modifier: Modifier,
|
||||
scrollState: LazyListState,
|
||||
itemCount: Int,
|
||||
averageItemSize: Dp
|
||||
) = Unit
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.jetbrains.compose.demo.widgets.platform
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import org.jetbrains.skiko.SystemTheme
|
||||
|
||||
@Composable
|
||||
internal actual fun isSystemInDarkTheme(): Boolean = org.jetbrains.skiko.currentSystemTheme == SystemTheme.DARK
|
||||
21
experimental/examples/widgets-gallery/third_party/ComposeCookBook_LICENSE.txt
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Gurupreet Singh
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||