Refactor Widgets Gallery sample to use KMM structure and add iOS targetpull/2497/head
@ -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> |
@ -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. |
||||||
|
|
||||||
|
![run-configurations.png](run-configurations.png) |
||||||
|
|
||||||
|
To run on iOS device, please correct `iosApp/Configuration/TeamId.xcconfig` with your Apple Team ID. |
||||||
|
Alternatively, you may setup signing within XCode opening `iosApp/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> |
@ -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() |
||||||
|
} |
@ -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 |
@ -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 |
@ -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" "$@" |
@ -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= |
@ -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 |
||||||
|
} |
||||||
|
} |
After Width: | Height: | Size: 15 KiB |
@ -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 |
@ -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. |