From 7ee3c0a9ecf30b7cc9ffbbbe4c2280e2c00e3af5 Mon Sep 17 00:00:00 2001
From: Aleksei Tiurin
Date: Mon, 24 Jun 2024 13:20:34 +0300
Subject: [PATCH] Kotlin Multiplatform Support (#72)
* Compose Multiplatform
KMP support & WebSite
* 2.5.0-alpha05
---
.github/workflows/android-pipeline.yml | 4 +-
.github/workflows/docs.yml | 25 +
.github/workflows/publish.yml | 66 +
.gitignore | 3 +-
README.md | 21 +-
build.gradle.kts | 35 +-
buildSrc/src/main/kotlin/Versions.kt | 6 +-
composeApp/build.gradle.kts | 133 +
.../src/androidMain/AndroidManifest.xml | 23 +
.../androidMain/kotlin/Platform.android.kt | 7 +
.../com/atiurin/samplekmp/MainActivity.kt | 24 +
.../drawable-v24/ic_launcher_foreground.xml | 30 +
.../res/drawable/ic_launcher_background.xml | 170 +
.../res/mipmap-anydpi-v26/ic_launcher.xml | 5 +
.../mipmap-anydpi-v26/ic_launcher_round.xml | 5 +
.../res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3593 bytes
.../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 5339 bytes
.../res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2636 bytes
.../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 3388 bytes
.../res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4926 bytes
.../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 7472 bytes
.../res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 7909 bytes
.../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 11873 bytes
.../res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 10652 bytes
.../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 16570 bytes
.../src/androidMain/res/values/strings.xml | 3 +
.../drawable/compose-multiplatform.xml | 36 +
composeApp/src/commonMain/kotlin/App.kt | 39 +
composeApp/src/commonMain/kotlin/Greeting.kt | 7 +
composeApp/src/commonMain/kotlin/Platform.kt | 5 +
.../kotlin/repositories/ContactRepository.kt | 17 +
.../commonMain/kotlin/repositories/Storage.kt | 52 +
.../kotlin/ui/screens/ContactsListScreen.kt | 83 +
composeApp/src/commonTest/kotlin/AppTest.kt | 58 +
.../src/commonTest/kotlin/ExampleTest.kt | 32 +
.../src/desktopMain/kotlin/Platform.jvm.kt | 5 +
composeApp/src/desktopMain/kotlin/main.kt | 11 +
.../desktopTest/kotlin/DesktopSampleTest.kt | 39 +
.../src/iosMain/kotlin/MainViewController.kt | 3 +
composeApp/src/iosMain/kotlin/Platform.ios.kt | 7 +
.../src/wasmJsMain/kotlin/Platform.wasmJs.kt | 5 +
composeApp/src/wasmJsMain/kotlin/main.kt | 10 +
.../src/wasmJsMain/resources/index.html | 12 +
.../src/wasmJsMain/resources/styles.css | 7 +
docs/.gitignore | 20 +
docs/README.md | 41 +
docs/babel.config.js | 3 +
docs/docs/android/_category_.json | 5 +
docs/docs/android/espress.md | 231 +
docs/docs/android/recyclerview.md | 198 +
docs/docs/android/rootview.md | 53 +
docs/docs/android/uiautomator.md | 220 +
docs/docs/android/webview.md | 136 +
docs/docs/common/_category_.json | 5 +
docs/docs/common/allure.md | 164 +
docs/docs/common/extension.md | 224 +
docs/docs/common/listeners.md | 168 +
docs/docs/compose/_category_.json | 5 +
docs/docs/compose/android.md | 64 +
docs/docs/compose/api.md | 206 +
docs/docs/compose/index.md | 8 +
docs/docs/compose/lazylist.md | 301 +
docs/docs/compose/multiplatform.md | 101 +
docs/docs/index.md | 253 +
docs/docs/intro/_category_.json | 5 +
docs/docs/intro/configuration.md | 149 +
docs/docs/intro/connect.md | 39 +
docs/docs/intro/dependencies.md | 53 +
docs/docusaurus.config.ts | 113 +
docs/package-lock.json | 14562 ++++++++++++++++
docs/package.json | 48 +
docs/sidebars.ts | 31 +
.../src/components/HomepageFeatures/index.tsx | 83 +
.../HomepageFeatures/styles.module.css | 33 +
docs/src/css/custom.css | 62 +
docs/src/pages/index.module.css | 23 +
docs/src/pages/index.tsx | 43 +
docs/src/pages/markdown-page.md | 7 +
docs/static/.nojekyll | 0
docs/static/img/favicon.ico | Bin 0 -> 15406 bytes
docs/static/img/kotlin.png | Bin 0 -> 29501 bytes
docs/static/img/logo.svg | 1 +
docs/static/img/maintainability.webp | Bin 0 -> 270674 bytes
docs/static/img/report.svg | 1 +
docs/static/img/simple.webp | Bin 0 -> 224468 bytes
docs/static/img/stable.webp | Bin 0 -> 154566 bytes
docs/static/img/ultron_banner_dark.png | Bin 0 -> 235649 bytes
docs/static/img/ultron_banner_light.png | Bin 0 -> 254018 bytes
docs/static/img/ultron_full_light.png | Bin 0 -> 496481 bytes
docs/tsconfig.json | 7 +
gradle.properties | 46 +-
gradle/libs.versions.toml | 63 +
iosApp/Configuration/Config.xcconfig | 3 +
iosApp/iosApp.xcodeproj/project.pbxproj | 403 +
.../AccentColor.colorset/Contents.json | 11 +
.../AppIcon.appiconset/Contents.json | 14 +
.../AppIcon.appiconset/app-icon-1024.png | Bin 0 -> 67285 bytes
iosApp/iosApp/Assets.xcassets/Contents.json | 6 +
iosApp/iosApp/ContentView.swift | 21 +
iosApp/iosApp/Info.plist | 50 +
.../Preview Assets.xcassets/Contents.json | 6 +
iosApp/iosApp/iOSApp.swift | 10 +
sample-app/build.gradle.kts | 7 +-
.../framework/ultronext/UltronComposeExt.kt | 1 -
.../sampleapp/framework/utils/AssertUtils.kt | 2 +-
.../com/atiurin/sampleapp/tests/BaseTest.kt | 10 +-
.../atiurin/sampleapp/tests/UiElementsTest.kt | 2 -
.../tests/compose/ComposeConfigTest.kt | 7 +-
.../tests/compose/ComposeEmptyListTest.kt | 1 -
.../tests/compose/ComposeUIElementsTest.kt | 8 -
.../espresso/UltronEspressoConfigTest.kt | 10 +-
.../espresso/ViewInteractionActionsTest.kt | 2 -
sample-app/src/main/AndroidManifest.xml | 3 +-
.../data/repositories/ContactRepositoty.kt | 9 -
settings.gradle.kts | 20 +-
ultron-allure/build.gradle.kts | 100 +-
ultron-allure/gradle.properties | 2 +-
.../allure/config/UltronAllureConfig.kt | 16 +-
.../UltronAllureResultsTransferListener.kt | 9 +
.../runner/UltronLogAttachRunListener.kt | 11 +-
.../runner/UltronLogCleanerRunListener.kt | 4 +-
{ultron => ultron-android}/.gitignore | 0
ultron-android/build.gradle.kts | 118 +
ultron-android/gradle.properties | 8 +
.../ultron/core/config/UltronConfig.kt | 151 +-
.../ultron/core/config/UltronConfigParams.kt | 13 +
.../espresso/EspressoOperationExecutor.kt | 7 +
.../core/espresso/EspressoOperationResult.kt | 0
.../ultron/core/espresso/UltronEspresso.kt | 0
.../espresso/UltronEspressoInteraction.kt | 0
.../core/espresso/UltronEspressoOperation.kt | 0
.../UltronEspressoOperationLifecycle.kt | 1 +
.../espresso/action/EspressoActionExecutor.kt | 5 +-
.../espresso/action/EspressoActionType.kt | 0
.../action/UltronCustomClickAction.kt | 0
.../action/UltronEspressoActionParams.kt | 0
.../assertion/EspressoAssertionExecutor.kt | 5 +-
.../assertion/EspressoAssertionType.kt | 0
.../UltronEspressoAssertionParams.kt | 0
.../recyclerview/RecyclerViewItemExecutor.kt | 0
.../RecyclerViewItemMatchingExecutor.kt | 0
.../RecyclerViewItemPositionalExecutor.kt | 0
.../recyclerview/RecyclerViewScrollAction.kt | 0
.../recyclerview/RecyclerViewUtils.kt | 0
.../recyclerview/UltronRecyclerView.kt | 44 +-
.../recyclerview/UltronRecyclerViewItem.kt | 0
.../core/espressoweb/UltronWebLifecycle.kt | 0
.../operation/EspressoWebOperationType.kt | 0
.../operation/WebInteractionOperation.kt | 0
.../WebInteractionOperationExecutor.kt | 7 +-
.../WebInteractionOperationIterationResult.kt | 0
.../operation/WebOperationExecutor.kt | 6 +
.../operation/WebOperationResult.kt | 0
.../webelement/UltronWebDocument.kt | 0
.../webelement/UltronWebElement.kt | 0
.../webelement/UltronWebElementId.kt | 0
.../webelement/UltronWebElementXpath.kt | 0
.../webelement/UltronWebElements.kt | 0
.../core/uiautomator/UiAutomatorActionType.kt | 0
.../uiautomator/UiAutomatorAssertionType.kt | 0
.../core/uiautomator/UiAutomatorOperation.kt | 0
.../UiAutomatorOperationExecutor.kt | 6 +
.../uiautomator/UiAutomatorOperationResult.kt | 0
.../uiautomator/UltronUiAutomatorLifecycle.kt | 0
.../UiAutomatorUiSelectorOperation.kt | 0
.../UiAutomatorUiSelectorOperationExecutor.kt | 5 +-
.../uiautomator/uiobject/UltronUiObject.kt | 0
.../uiobject2/UiAutomatorBySelectorAction.kt | 0
.../UiAutomatorBySelectorActionExecutor.kt | 5 +-
.../UiAutomatorBySelectorAssertion.kt | 0
.../UiAutomatorBySelectorAssertionExecutor.kt | 5 +-
.../uiautomator/uiobject2/UltronUiObject2.kt | 0
.../espresso/action/AnonymousViewAction.kt | 0
.../action/CustomEspressoActionType.kt | 0
.../action/GetContentDescriptionAction.kt | 0
.../espresso/action/GetDrawableAction.kt | 0
.../custom/espresso/action/GetTextAction.kt | 0
.../custom/espresso/action/GetViewAction.kt | 0
.../espresso/assertion/AnyRootAssertions.kt | 0
.../assertion/CustomEspressoAssertionType.kt | 0
.../espresso/assertion/DrawableAssertion.kt | 0
.../assertion/ExistsEspressoViewAssertion.kt | 0
.../espresso/assertion/TextColorAssertion.kt | 0
.../espresso/base/RootViewPickerCreator.kt | 0
.../espresso/base/UltronRootViewFinder.kt | 0
.../custom/espresso/base/UltronViewFinder.kt | 0
.../espresso/matcher/AppCompatTextMatcher.kt | 0
.../espresso/matcher/DrawableMatchers.kt | 0
.../matcher/ElementWithAttributeMatcher.kt | 0
.../espresso/matcher/NotUniqueViewMatchers.kt | 0
.../espresso/matcher/SuitableRootMatcher.kt | 0
.../espresso/matcher/TextColorMatchers.kt | 0
.../atiurin/ultron/extensions/BitmapExt.kt | 0
.../ultron/extensions/DataInterationExt.kt | 0
.../atiurin/ultron/extensions/DrawableExt.kt | 0
.../ultron/extensions/MatcherViewExt.kt | 0
.../ultron/extensions/PerfomOnViewExt.kt | 0
.../ultron/extensions/ReflectionExt.kt | 23 -
.../ultron/extensions/ViewInteractionExt.kt | 0
.../atiurin/ultron/utils/ViewGroupUtils.kt | 0
.../com/atiurin/ultron/utils/ViewUtils.kt | 0
.../src/main/res/values/strings.xml | 0
.../com/atiurin/ultron/ExampleUnitTest.java | 0
ultron-common/.gitignore | 1 +
ultron-common/build.gradle.kts | 154 +
.../core/config/UltronAndroidCommonConfig.kt | 15 +
.../ultron/extensions/AnyExt.android.kt | 24 +
.../atiurin/ultron/extensions/BundleExt.kt | 0
.../ultron/extensions/DescriptionExt.kt | 0
.../ultron/extensions/FileExt.android.kt | 0
.../ultron/hierarchy/HierarchyDumpResult.kt | 0
.../ultron/hierarchy/HierarchyDumper.kt | 0
.../hierarchy/UiDeviceHierarchyDumper.kt | 4 +-
.../log/UltronFileLoggerImpl.android.kt.kt | 13 +-
.../atiurin/ultron/log/UltronLog.android.kt | 3 +
.../ultron/log/UltronLogcatLogger.android.kt | 0
.../com/atiurin/ultron/runner/RunListener.kt | 0
.../ultron/runner/UltronLogRunListener.kt | 0
.../ultron/runner/UltronRunInformer.kt | 0
.../ultron/runner/UltronRunListener.kt | 0
.../ultron/screenshot/ScreenshotResult.kt | 0
.../atiurin/ultron/screenshot/Screenshoter.kt | 0
.../screenshot/UiAutomationScreenshoter.kt | 0
.../ultron/screenshot/ViewScreenshoter.kt | 2 -
.../rulesequence/RuleSequence.kt | 0
.../testlifecycle/setupteardown/Condition.kt | 0
.../setupteardown/ConditionExecutorWrapper.kt | 0
.../setupteardown/ConditionRule.kt | 4 +-
.../setupteardown/ConditionsExecutor.kt | 0
.../DefaultConditionExecutorWrapper.kt | 7 +-
.../DefaultConditionsExecutor.kt | 10 +-
.../setupteardown/RuleSequenceTearDown.kt | 0
.../testlifecycle/setupteardown/SetUp.kt | 0
.../testlifecycle/setupteardown/SetUpRule.kt | 0
.../testlifecycle/setupteardown/TearDown.kt | 0
.../setupteardown/TearDownRule.kt | 0
.../ultron/utils/ActivityUtil.android.kt.kt | 0
.../utils/InstrumentationUtil.android.kt | 2 +-
.../ultron/utils/ThreadUtil.android.kt | 7 +
.../core/common/AbstractOperationLifecycle.kt | 16 +-
.../common/CheckOperationResultAnalyzer.kt | 0
.../ultron/core/common/DefaultElementInfo.kt | 0
.../common/DefaultOperationIterationResult.kt | 0
.../atiurin/ultron/core/common/ElementInfo.kt | 0
.../atiurin/ultron/core/common/Operation.kt | 0
.../ultron/core/common/OperationExecutor.kt | 72 +-
.../core/common/OperationIterationResult.kt | 0
.../ultron/core/common/OperationProcessor.kt | 0
.../ultron/core/common/OperationResult.kt | 0
.../core/common/OperationResultAnalyzer.kt | 0
.../ultron/core/common/ResultDescriptor.kt | 6 +-
.../UltronDefaultOperationResultAnalyzer.kt | 3 +-
.../ultron/core/common/UltronOperationType.kt | 0
.../assertion/DefaultOperationAssertion.kt | 0
.../assertion/EmptyOperationAssertion.kt | 0
.../NoListenersOperationAssertion.kt | 0
.../common/assertion/OperationAssertion.kt | 0
.../ultron/core/common/options/ClickOption.kt | 0
.../ContentDescriptionContainsOption.kt | 0
.../core/common/options/DoubleClickOption.kt | 0
.../core/common/options/LongClickOption.kt | 0
.../options/PerformCustomBlockOption.kt | 0
.../core/common/options/TextContainsOption.kt | 0
.../core/common/options/TextEqualsOption.kt | 0
.../ultron/core/config/UltronCommonConfig.kt | 20 +
.../UltronAssertionBlockException.kt | 0
.../exceptions/UltronAssertionException.kt | 0
.../ultron/exceptions/UltronException.kt | 0
.../exceptions/UltronOperationException.kt | 2 -
.../exceptions/UltronUiAutomatorException.kt | 0
.../exceptions/UltronWrapperException.kt | 0
.../atiurin/ultron/extensions/AnyCommonExt.kt | 3 +
.../com/atiurin/ultron/file/MimeType.kt | 0
.../ultron/listeners/AbstractListener.kt | 2 +-
.../listeners/AbstractListenersContainer.kt | 6 +-
.../ultron/listeners/LifecycleListener.kt | 0
.../ultron/listeners/LogLifecycleListener.kt | 0
.../listeners/UltronLifecycleListener.kt | 0
.../ultron/listeners/UltronListenerUtil.kt | 9 +-
.../com/atiurin/ultron/log/LogLevel.kt | 0
.../kotlin}/com/atiurin/ultron/log/ULogger.kt | 2 +-
.../atiurin/ultron/log/UltronFileLogger.kt | 7 +
.../com/atiurin/ultron/log/UltronLog.kt | 23 +-
.../com/atiurin/ultron/log/UltronLogUtil.kt | 0
.../kotlin}/com/atiurin/ultron/page/Page.kt | 0
.../kotlin}/com/atiurin/ultron/page/Screen.kt | 0
.../com/atiurin/ultron/utils/AssertUtils.kt | 25 +-
.../com/atiurin/ultron/utils/ThreadUtil.kt | 3 +
.../com/atiurin/ultron/utils/TimeUtil.kt | 12 +
.../com/atiurin/ultron/log/UltronLog.js.kt | 5 +
.../com/atiurin/ultron/utils/ThreadUtil.js.kt | 4 +
.../atiurin/ultron/extensions/AnyExt.jvm.kt | 9 +
.../com/atiurin/ultron/log/UltronLog.jvm.kt | 5 +
.../atiurin/ultron/utils/ThreadUtil.jvm.kt | 5 +
.../atiurin/ultron/log/UltronLog.native.kt | 5 +
.../atiurin/ultron/utils/ThreadUtil.native.kt | 12 +
.../atiurin/ultron/log/UltronLog.wasmJs.kt | 5 +
.../atiurin/ultron/utils/ThreadUtil.wasmJs.kt | 4 +
ultron-compose/build.gradle.kts | 146 +-
ultron-compose/gradle.properties | 4 +-
.../compose/ComposeRuleContainer.android.kt} | 13 +-
.../ItemChildInteractionProvider.android.kt | 42 +
...ComposeSemanticsNodeInteraction.android.kt | 37 +
.../ReflectionComposeExt.android.kt} | 3 +-
.../extensions/SemanticsMatcherExt.android.kt | 11 +
.../SemanticsNodeInteractionExt.android.kt} | 38 +-
...manticsNodeInteractionProviderContainer.kt | 15 +
.../ultron/core/compose/UltronUiTest.kt | 18 +
.../compose/config/UltronComposeConfig.kt | 40 +-
.../config/UltronComposeConfigParams.kt | 3 +-
.../core/compose/list/ComposeItemExecutor.kt | 0
.../compose/list/IndexComposeItemExecutor.kt | 3 +-
.../list/ItemChildInteractionProvider.kt | 64 +
.../list/MatcherComposeItemExecutor.kt | 0
.../list/PositionComposeItemExecutor.kt | 0
.../core/compose/list/UltronComposeList.kt | 68 +-
.../compose/list/UltronComposeListItem.kt | 0
.../compose/nodeinteraction/SwipePosition.kt | 0
.../nodeinteraction/UltronComposeOffsets.kt | 0
.../UltronComposeSemanticsNodeInteraction.kt | 64 +-
...onComposeSemanticsNodeInteractionClicks.kt | 0
.../operation/ComposeOperationExecutor.kt | 4 +-
.../operation/ComposeOperationResult.kt | 0
.../compose/operation/ComposeOperationType.kt | 0
.../UltronComposeCollectionInteraction.kt | 8 +-
.../operation/UltronComposeOperation.kt | 0
.../UltronComposeOperationLifecycle.kt | 0
.../operation/UltronComposeOperationParams.kt | 0
.../core/compose/option/ComposeSwipeOption.kt | 0
.../ultron/extensions/SemanticsMatcherExt.kt | 1 -
.../ultron/extensions/SemanticsNodeExt.kt | 0
.../extensions/SemanticsNodeInteractionExt.kt | 36 +
.../ultron/extensions/SemanticsSelectorExt.kt | 0
.../extensions/TouchInjectionScopeExt.kt | 0
.../list/ItemChildInteractionProvider.js.kt | 5 +
.../SemanticsNodeInteractionCommonExt.js.kt | 5 +
.../list/ItemChildInteractionProvider.jvm.kt | 5 +
.../SemanticsNodeInteractionExt.jvm.kt | 15 +
.../ItemChildInteractionProvider.native.kt | 5 +
...emanticsNodeInteractionCommonExt.native.kt | 5 +
.../ItemChildInteractionProvider.wasmJs.kt | 5 +
...emanticsNodeInteractionCommonExt.wasmJs.kt | 5 +
ultron/build.gradle.kts | 86 -
.../ultron/core/config/UltronConfigParams.kt | 9 -
.../com/atiurin/ultron/extensions/AnyExt.kt | 3 -
.../atiurin/ultron/listeners/TimeListener.kt | 22 -
.../com/atiurin/ultron/log/UFileLogger.kt | 8 -
347 files changed, 20566 insertions(+), 661 deletions(-)
create mode 100644 .github/workflows/docs.yml
create mode 100644 .github/workflows/publish.yml
create mode 100644 composeApp/build.gradle.kts
create mode 100644 composeApp/src/androidMain/AndroidManifest.xml
create mode 100644 composeApp/src/androidMain/kotlin/Platform.android.kt
create mode 100644 composeApp/src/androidMain/kotlin/com/atiurin/samplekmp/MainActivity.kt
create mode 100644 composeApp/src/androidMain/res/drawable-v24/ic_launcher_foreground.xml
create mode 100644 composeApp/src/androidMain/res/drawable/ic_launcher_background.xml
create mode 100644 composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml
create mode 100644 composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher_round.xml
create mode 100644 composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher.png
create mode 100644 composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher_round.png
create mode 100644 composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher.png
create mode 100644 composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher_round.png
create mode 100644 composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher.png
create mode 100644 composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.png
create mode 100644 composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher.png
create mode 100644 composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.png
create mode 100644 composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.png
create mode 100644 composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.png
create mode 100644 composeApp/src/androidMain/res/values/strings.xml
create mode 100644 composeApp/src/commonMain/composeResources/drawable/compose-multiplatform.xml
create mode 100644 composeApp/src/commonMain/kotlin/App.kt
create mode 100644 composeApp/src/commonMain/kotlin/Greeting.kt
create mode 100644 composeApp/src/commonMain/kotlin/Platform.kt
create mode 100644 composeApp/src/commonMain/kotlin/repositories/ContactRepository.kt
create mode 100644 composeApp/src/commonMain/kotlin/repositories/Storage.kt
create mode 100644 composeApp/src/commonMain/kotlin/ui/screens/ContactsListScreen.kt
create mode 100644 composeApp/src/commonTest/kotlin/AppTest.kt
create mode 100644 composeApp/src/commonTest/kotlin/ExampleTest.kt
create mode 100644 composeApp/src/desktopMain/kotlin/Platform.jvm.kt
create mode 100644 composeApp/src/desktopMain/kotlin/main.kt
create mode 100644 composeApp/src/desktopTest/kotlin/DesktopSampleTest.kt
create mode 100644 composeApp/src/iosMain/kotlin/MainViewController.kt
create mode 100644 composeApp/src/iosMain/kotlin/Platform.ios.kt
create mode 100644 composeApp/src/wasmJsMain/kotlin/Platform.wasmJs.kt
create mode 100644 composeApp/src/wasmJsMain/kotlin/main.kt
create mode 100644 composeApp/src/wasmJsMain/resources/index.html
create mode 100644 composeApp/src/wasmJsMain/resources/styles.css
create mode 100644 docs/.gitignore
create mode 100644 docs/README.md
create mode 100644 docs/babel.config.js
create mode 100644 docs/docs/android/_category_.json
create mode 100644 docs/docs/android/espress.md
create mode 100644 docs/docs/android/recyclerview.md
create mode 100644 docs/docs/android/rootview.md
create mode 100644 docs/docs/android/uiautomator.md
create mode 100644 docs/docs/android/webview.md
create mode 100644 docs/docs/common/_category_.json
create mode 100644 docs/docs/common/allure.md
create mode 100644 docs/docs/common/extension.md
create mode 100644 docs/docs/common/listeners.md
create mode 100644 docs/docs/compose/_category_.json
create mode 100644 docs/docs/compose/android.md
create mode 100644 docs/docs/compose/api.md
create mode 100644 docs/docs/compose/index.md
create mode 100644 docs/docs/compose/lazylist.md
create mode 100644 docs/docs/compose/multiplatform.md
create mode 100644 docs/docs/index.md
create mode 100644 docs/docs/intro/_category_.json
create mode 100644 docs/docs/intro/configuration.md
create mode 100644 docs/docs/intro/connect.md
create mode 100644 docs/docs/intro/dependencies.md
create mode 100644 docs/docusaurus.config.ts
create mode 100644 docs/package-lock.json
create mode 100644 docs/package.json
create mode 100644 docs/sidebars.ts
create mode 100644 docs/src/components/HomepageFeatures/index.tsx
create mode 100644 docs/src/components/HomepageFeatures/styles.module.css
create mode 100644 docs/src/css/custom.css
create mode 100644 docs/src/pages/index.module.css
create mode 100644 docs/src/pages/index.tsx
create mode 100644 docs/src/pages/markdown-page.md
create mode 100644 docs/static/.nojekyll
create mode 100644 docs/static/img/favicon.ico
create mode 100644 docs/static/img/kotlin.png
create mode 100644 docs/static/img/logo.svg
create mode 100644 docs/static/img/maintainability.webp
create mode 100644 docs/static/img/report.svg
create mode 100644 docs/static/img/simple.webp
create mode 100644 docs/static/img/stable.webp
create mode 100644 docs/static/img/ultron_banner_dark.png
create mode 100644 docs/static/img/ultron_banner_light.png
create mode 100644 docs/static/img/ultron_full_light.png
create mode 100644 docs/tsconfig.json
create mode 100644 gradle/libs.versions.toml
create mode 100644 iosApp/Configuration/Config.xcconfig
create mode 100644 iosApp/iosApp.xcodeproj/project.pbxproj
create mode 100644 iosApp/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json
create mode 100644 iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json
create mode 100644 iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/app-icon-1024.png
create mode 100644 iosApp/iosApp/Assets.xcassets/Contents.json
create mode 100644 iosApp/iosApp/ContentView.swift
create mode 100644 iosApp/iosApp/Info.plist
create mode 100644 iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json
create mode 100644 iosApp/iosApp/iOSApp.swift
rename {ultron => ultron-android}/.gitignore (100%)
create mode 100644 ultron-android/build.gradle.kts
create mode 100644 ultron-android/gradle.properties
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/config/UltronConfig.kt (69%)
create mode 100644 ultron-android/src/main/kotlin/com/atiurin/ultron/core/config/UltronConfigParams.kt
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espresso/EspressoOperationExecutor.kt (83%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espresso/EspressoOperationResult.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espresso/UltronEspresso.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espresso/UltronEspressoInteraction.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espresso/UltronEspressoOperation.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espresso/UltronEspressoOperationLifecycle.kt (99%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espresso/action/EspressoActionExecutor.kt (87%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espresso/action/EspressoActionType.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espresso/action/UltronCustomClickAction.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espresso/action/UltronEspressoActionParams.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espresso/assertion/EspressoAssertionExecutor.kt (86%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espresso/assertion/EspressoAssertionType.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espresso/assertion/UltronEspressoAssertionParams.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espresso/recyclerview/RecyclerViewItemExecutor.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espresso/recyclerview/RecyclerViewItemMatchingExecutor.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espresso/recyclerview/RecyclerViewItemPositionalExecutor.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espresso/recyclerview/RecyclerViewScrollAction.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espresso/recyclerview/RecyclerViewUtils.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espresso/recyclerview/UltronRecyclerView.kt (95%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espresso/recyclerview/UltronRecyclerViewItem.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espressoweb/UltronWebLifecycle.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espressoweb/operation/EspressoWebOperationType.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espressoweb/operation/WebInteractionOperation.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espressoweb/operation/WebInteractionOperationExecutor.kt (83%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espressoweb/operation/WebInteractionOperationIterationResult.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espressoweb/operation/WebOperationExecutor.kt (85%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espressoweb/operation/WebOperationResult.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espressoweb/webelement/UltronWebDocument.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espressoweb/webelement/UltronWebElement.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espressoweb/webelement/UltronWebElementId.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espressoweb/webelement/UltronWebElementXpath.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/espressoweb/webelement/UltronWebElements.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/uiautomator/UiAutomatorActionType.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/uiautomator/UiAutomatorAssertionType.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/uiautomator/UiAutomatorOperation.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/uiautomator/UiAutomatorOperationExecutor.kt (86%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/uiautomator/UiAutomatorOperationResult.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/uiautomator/UltronUiAutomatorLifecycle.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/uiautomator/uiobject/UiAutomatorUiSelectorOperation.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/uiautomator/uiobject/UiAutomatorUiSelectorOperationExecutor.kt (86%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/uiautomator/uiobject/UltronUiObject.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/uiautomator/uiobject2/UiAutomatorBySelectorAction.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/uiautomator/uiobject2/UiAutomatorBySelectorActionExecutor.kt (87%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/uiautomator/uiobject2/UiAutomatorBySelectorAssertion.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/uiautomator/uiobject2/UiAutomatorBySelectorAssertionExecutor.kt (87%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/core/uiautomator/uiobject2/UltronUiObject2.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/custom/espresso/action/AnonymousViewAction.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/custom/espresso/action/CustomEspressoActionType.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/custom/espresso/action/GetContentDescriptionAction.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/custom/espresso/action/GetDrawableAction.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/custom/espresso/action/GetTextAction.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/custom/espresso/action/GetViewAction.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/custom/espresso/assertion/AnyRootAssertions.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/custom/espresso/assertion/CustomEspressoAssertionType.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/custom/espresso/assertion/DrawableAssertion.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/custom/espresso/assertion/ExistsEspressoViewAssertion.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/custom/espresso/assertion/TextColorAssertion.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/custom/espresso/base/RootViewPickerCreator.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/custom/espresso/base/UltronRootViewFinder.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/custom/espresso/base/UltronViewFinder.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/custom/espresso/matcher/AppCompatTextMatcher.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/custom/espresso/matcher/DrawableMatchers.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/custom/espresso/matcher/ElementWithAttributeMatcher.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/custom/espresso/matcher/NotUniqueViewMatchers.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/custom/espresso/matcher/SuitableRootMatcher.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/custom/espresso/matcher/TextColorMatchers.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/extensions/BitmapExt.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/extensions/DataInterationExt.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/extensions/DrawableExt.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/extensions/MatcherViewExt.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/extensions/PerfomOnViewExt.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/extensions/ReflectionExt.kt (70%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/extensions/ViewInteractionExt.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/utils/ViewGroupUtils.kt (100%)
rename {ultron/src/main/java => ultron-android/src/main/kotlin}/com/atiurin/ultron/utils/ViewUtils.kt (100%)
rename {ultron => ultron-android}/src/main/res/values/strings.xml (100%)
rename {ultron => ultron-android}/src/test/java/com/atiurin/ultron/ExampleUnitTest.java (100%)
create mode 100644 ultron-common/.gitignore
create mode 100644 ultron-common/build.gradle.kts
create mode 100644 ultron-common/src/androidMain/kotlin/com/atiurin/ultron/core/config/UltronAndroidCommonConfig.kt
create mode 100644 ultron-common/src/androidMain/kotlin/com/atiurin/ultron/extensions/AnyExt.android.kt
rename {ultron/src/main/java => ultron-common/src/androidMain/kotlin}/com/atiurin/ultron/extensions/BundleExt.kt (100%)
rename {ultron/src/main/java => ultron-common/src/androidMain/kotlin}/com/atiurin/ultron/extensions/DescriptionExt.kt (100%)
rename ultron/src/main/java/com/atiurin/ultron/extensions/FileExt.kt => ultron-common/src/androidMain/kotlin/com/atiurin/ultron/extensions/FileExt.android.kt (100%)
rename {ultron/src/main/java => ultron-common/src/androidMain/kotlin}/com/atiurin/ultron/hierarchy/HierarchyDumpResult.kt (100%)
rename {ultron/src/main/java => ultron-common/src/androidMain/kotlin}/com/atiurin/ultron/hierarchy/HierarchyDumper.kt (100%)
rename {ultron/src/main/java => ultron-common/src/androidMain/kotlin}/com/atiurin/ultron/hierarchy/UiDeviceHierarchyDumper.kt (75%)
rename ultron/src/main/java/com/atiurin/ultron/log/UltronFileLogger.kt => ultron-common/src/androidMain/kotlin/com/atiurin/ultron/log/UltronFileLoggerImpl.android.kt.kt (79%)
create mode 100644 ultron-common/src/androidMain/kotlin/com/atiurin/ultron/log/UltronLog.android.kt
rename ultron/src/main/java/com/atiurin/ultron/log/UltronLogcatLogger.kt => ultron-common/src/androidMain/kotlin/com/atiurin/ultron/log/UltronLogcatLogger.android.kt (100%)
rename {ultron/src/main/java => ultron-common/src/androidMain/kotlin}/com/atiurin/ultron/runner/RunListener.kt (100%)
rename {ultron/src/main/java => ultron-common/src/androidMain/kotlin}/com/atiurin/ultron/runner/UltronLogRunListener.kt (100%)
rename {ultron/src/main/java => ultron-common/src/androidMain/kotlin}/com/atiurin/ultron/runner/UltronRunInformer.kt (100%)
rename {ultron/src/main/java => ultron-common/src/androidMain/kotlin}/com/atiurin/ultron/runner/UltronRunListener.kt (100%)
rename {ultron/src/main/java => ultron-common/src/androidMain/kotlin}/com/atiurin/ultron/screenshot/ScreenshotResult.kt (100%)
rename {ultron/src/main/java => ultron-common/src/androidMain/kotlin}/com/atiurin/ultron/screenshot/Screenshoter.kt (100%)
rename {ultron/src/main/java => ultron-common/src/androidMain/kotlin}/com/atiurin/ultron/screenshot/UiAutomationScreenshoter.kt (100%)
rename {ultron/src/main/java => ultron-common/src/androidMain/kotlin}/com/atiurin/ultron/screenshot/ViewScreenshoter.kt (97%)
rename {ultron/src/main/java => ultron-common/src/androidMain/kotlin}/com/atiurin/ultron/testlifecycle/rulesequence/RuleSequence.kt (100%)
rename {ultron/src/main/java => ultron-common/src/androidMain/kotlin}/com/atiurin/ultron/testlifecycle/setupteardown/Condition.kt (100%)
rename {ultron/src/main/java => ultron-common/src/androidMain/kotlin}/com/atiurin/ultron/testlifecycle/setupteardown/ConditionExecutorWrapper.kt (100%)
rename {ultron/src/main/java => ultron-common/src/androidMain/kotlin}/com/atiurin/ultron/testlifecycle/setupteardown/ConditionRule.kt (96%)
rename {ultron/src/main/java => ultron-common/src/androidMain/kotlin}/com/atiurin/ultron/testlifecycle/setupteardown/ConditionsExecutor.kt (100%)
rename {ultron/src/main/java => ultron-common/src/androidMain/kotlin}/com/atiurin/ultron/testlifecycle/setupteardown/DefaultConditionExecutorWrapper.kt (52%)
rename {ultron/src/main/java => ultron-common/src/androidMain/kotlin}/com/atiurin/ultron/testlifecycle/setupteardown/DefaultConditionsExecutor.kt (62%)
rename {ultron/src/main/java => ultron-common/src/androidMain/kotlin}/com/atiurin/ultron/testlifecycle/setupteardown/RuleSequenceTearDown.kt (100%)
rename {ultron/src/main/java => ultron-common/src/androidMain/kotlin}/com/atiurin/ultron/testlifecycle/setupteardown/SetUp.kt (100%)
rename {ultron/src/main/java => ultron-common/src/androidMain/kotlin}/com/atiurin/ultron/testlifecycle/setupteardown/SetUpRule.kt (100%)
rename {ultron/src/main/java => ultron-common/src/androidMain/kotlin}/com/atiurin/ultron/testlifecycle/setupteardown/TearDown.kt (100%)
rename {ultron/src/main/java => ultron-common/src/androidMain/kotlin}/com/atiurin/ultron/testlifecycle/setupteardown/TearDownRule.kt (100%)
rename ultron/src/main/java/com/atiurin/ultron/utils/ActivityUtil.kt => ultron-common/src/androidMain/kotlin/com/atiurin/ultron/utils/ActivityUtil.android.kt.kt (100%)
rename ultron/src/main/java/com/atiurin/ultron/utils/InstrumentationUtil.kt => ultron-common/src/androidMain/kotlin/com/atiurin/ultron/utils/InstrumentationUtil.android.kt (97%)
create mode 100644 ultron-common/src/androidMain/kotlin/com/atiurin/ultron/utils/ThreadUtil.android.kt
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/core/common/AbstractOperationLifecycle.kt (64%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/core/common/CheckOperationResultAnalyzer.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/core/common/DefaultElementInfo.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/core/common/DefaultOperationIterationResult.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/core/common/ElementInfo.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/core/common/Operation.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/core/common/OperationExecutor.kt (67%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/core/common/OperationIterationResult.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/core/common/OperationProcessor.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/core/common/OperationResult.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/core/common/OperationResultAnalyzer.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/core/common/ResultDescriptor.kt (89%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/core/common/UltronDefaultOperationResultAnalyzer.kt (95%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/core/common/UltronOperationType.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/core/common/assertion/DefaultOperationAssertion.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/core/common/assertion/EmptyOperationAssertion.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/core/common/assertion/NoListenersOperationAssertion.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/core/common/assertion/OperationAssertion.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/core/common/options/ClickOption.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/core/common/options/ContentDescriptionContainsOption.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/core/common/options/DoubleClickOption.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/core/common/options/LongClickOption.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/core/common/options/PerformCustomBlockOption.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/core/common/options/TextContainsOption.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/core/common/options/TextEqualsOption.kt (100%)
create mode 100644 ultron-common/src/commonMain/kotlin/com/atiurin/ultron/core/config/UltronCommonConfig.kt
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/exceptions/UltronAssertionBlockException.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/exceptions/UltronAssertionException.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/exceptions/UltronException.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/exceptions/UltronOperationException.kt (76%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/exceptions/UltronUiAutomatorException.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/exceptions/UltronWrapperException.kt (100%)
create mode 100644 ultron-common/src/commonMain/kotlin/com/atiurin/ultron/extensions/AnyCommonExt.kt
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/file/MimeType.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/listeners/AbstractListener.kt (76%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/listeners/AbstractListenersContainer.kt (80%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/listeners/LifecycleListener.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/listeners/LogLifecycleListener.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/listeners/UltronLifecycleListener.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/listeners/UltronListenerUtil.kt (75%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/log/LogLevel.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/log/ULogger.kt (91%)
create mode 100644 ultron-common/src/commonMain/kotlin/com/atiurin/ultron/log/UltronFileLogger.kt
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/log/UltronLog.kt (72%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/log/UltronLogUtil.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/page/Page.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/page/Screen.kt (100%)
rename {ultron/src/main/java => ultron-common/src/commonMain/kotlin}/com/atiurin/ultron/utils/AssertUtils.kt (58%)
create mode 100644 ultron-common/src/commonMain/kotlin/com/atiurin/ultron/utils/ThreadUtil.kt
create mode 100644 ultron-common/src/commonMain/kotlin/com/atiurin/ultron/utils/TimeUtil.kt
create mode 100644 ultron-common/src/jsMain/kotlin/com/atiurin/ultron/log/UltronLog.js.kt
create mode 100644 ultron-common/src/jsMain/kotlin/com/atiurin/ultron/utils/ThreadUtil.js.kt
create mode 100644 ultron-common/src/jvmMain/kotlin/com/atiurin/ultron/extensions/AnyExt.jvm.kt
create mode 100644 ultron-common/src/jvmMain/kotlin/com/atiurin/ultron/log/UltronLog.jvm.kt
create mode 100644 ultron-common/src/jvmMain/kotlin/com/atiurin/ultron/utils/ThreadUtil.jvm.kt
create mode 100644 ultron-common/src/nativeMain/kotlin/com/atiurin/ultron/log/UltronLog.native.kt
create mode 100644 ultron-common/src/nativeMain/kotlin/com/atiurin/ultron/utils/ThreadUtil.native.kt
create mode 100644 ultron-common/src/wasmJsMain/kotlin/com/atiurin/ultron/log/UltronLog.wasmJs.kt
create mode 100644 ultron-common/src/wasmJsMain/kotlin/com/atiurin/ultron/utils/ThreadUtil.wasmJs.kt
rename ultron-compose/src/{main/java/com/atiurin/ultron/core/compose/ComposeRuleContainer.kt => androidMain/kotlin/com/atiurin/ultron/core/compose/ComposeRuleContainer.android.kt} (88%)
create mode 100644 ultron-compose/src/androidMain/kotlin/com/atiurin/ultron/core/compose/list/ItemChildInteractionProvider.android.kt
create mode 100644 ultron-compose/src/androidMain/kotlin/com/atiurin/ultron/core/compose/nodeinteraction/UltronComposeSemanticsNodeInteraction.android.kt
rename ultron-compose/src/{main/java/com/atiurin/ultron/extensions/ReflectionComposeExt.kt => androidMain/kotlin/com/atiurin/ultron/extensions/ReflectionComposeExt.android.kt} (88%)
create mode 100644 ultron-compose/src/androidMain/kotlin/com/atiurin/ultron/extensions/SemanticsMatcherExt.android.kt
rename ultron-compose/src/{main/java/com/atiurin/ultron/extensions/SemanticsNodeInteractionExt.kt => androidMain/kotlin/com/atiurin/ultron/extensions/SemanticsNodeInteractionExt.android.kt} (57%)
create mode 100644 ultron-compose/src/commonMain/kotlin/com/atiurin/ultron/core/compose/SemanticsNodeInteractionProviderContainer.kt
create mode 100644 ultron-compose/src/commonMain/kotlin/com/atiurin/ultron/core/compose/UltronUiTest.kt
rename ultron-compose/src/{main/java => commonMain/kotlin}/com/atiurin/ultron/core/compose/config/UltronComposeConfig.kt (72%)
rename ultron-compose/src/{main/java => commonMain/kotlin}/com/atiurin/ultron/core/compose/config/UltronComposeConfigParams.kt (78%)
rename ultron-compose/src/{main/java => commonMain/kotlin}/com/atiurin/ultron/core/compose/list/ComposeItemExecutor.kt (100%)
rename ultron-compose/src/{main/java => commonMain/kotlin}/com/atiurin/ultron/core/compose/list/IndexComposeItemExecutor.kt (83%)
create mode 100644 ultron-compose/src/commonMain/kotlin/com/atiurin/ultron/core/compose/list/ItemChildInteractionProvider.kt
rename ultron-compose/src/{main/java => commonMain/kotlin}/com/atiurin/ultron/core/compose/list/MatcherComposeItemExecutor.kt (100%)
rename ultron-compose/src/{main/java => commonMain/kotlin}/com/atiurin/ultron/core/compose/list/PositionComposeItemExecutor.kt (100%)
rename ultron-compose/src/{main/java => commonMain/kotlin}/com/atiurin/ultron/core/compose/list/UltronComposeList.kt (95%)
rename ultron-compose/src/{main/java => commonMain/kotlin}/com/atiurin/ultron/core/compose/list/UltronComposeListItem.kt (100%)
rename ultron-compose/src/{main/java => commonMain/kotlin}/com/atiurin/ultron/core/compose/nodeinteraction/SwipePosition.kt (100%)
rename ultron-compose/src/{main/java => commonMain/kotlin}/com/atiurin/ultron/core/compose/nodeinteraction/UltronComposeOffsets.kt (100%)
rename ultron-compose/src/{main/java => commonMain/kotlin}/com/atiurin/ultron/core/compose/nodeinteraction/UltronComposeSemanticsNodeInteraction.kt (94%)
rename ultron-compose/src/{main/java => commonMain/kotlin}/com/atiurin/ultron/core/compose/nodeinteraction/UltronComposeSemanticsNodeInteractionClicks.kt (100%)
rename ultron-compose/src/{main/java => commonMain/kotlin}/com/atiurin/ultron/core/compose/operation/ComposeOperationExecutor.kt (96%)
rename ultron-compose/src/{main/java => commonMain/kotlin}/com/atiurin/ultron/core/compose/operation/ComposeOperationResult.kt (100%)
rename ultron-compose/src/{main/java => commonMain/kotlin}/com/atiurin/ultron/core/compose/operation/ComposeOperationType.kt (100%)
rename ultron-compose/src/{main/java => commonMain/kotlin}/com/atiurin/ultron/core/compose/operation/UltronComposeCollectionInteraction.kt (64%)
rename ultron-compose/src/{main/java => commonMain/kotlin}/com/atiurin/ultron/core/compose/operation/UltronComposeOperation.kt (100%)
rename ultron-compose/src/{main/java => commonMain/kotlin}/com/atiurin/ultron/core/compose/operation/UltronComposeOperationLifecycle.kt (100%)
rename ultron-compose/src/{main/java => commonMain/kotlin}/com/atiurin/ultron/core/compose/operation/UltronComposeOperationParams.kt (100%)
rename ultron-compose/src/{main/java => commonMain/kotlin}/com/atiurin/ultron/core/compose/option/ComposeSwipeOption.kt (100%)
rename ultron-compose/src/{main/java => commonMain/kotlin}/com/atiurin/ultron/extensions/SemanticsMatcherExt.kt (99%)
rename ultron-compose/src/{main/java => commonMain/kotlin}/com/atiurin/ultron/extensions/SemanticsNodeExt.kt (100%)
create mode 100644 ultron-compose/src/commonMain/kotlin/com/atiurin/ultron/extensions/SemanticsNodeInteractionExt.kt
rename ultron-compose/src/{main/java => commonMain/kotlin}/com/atiurin/ultron/extensions/SemanticsSelectorExt.kt (100%)
rename ultron-compose/src/{main/java => commonMain/kotlin}/com/atiurin/ultron/extensions/TouchInjectionScopeExt.kt (100%)
create mode 100644 ultron-compose/src/jsMain/kotlin/com/atiurin/ultron/core/compose/list/ItemChildInteractionProvider.js.kt
create mode 100644 ultron-compose/src/jsMain/kotlin/com/atiurin/ultron/extensions/SemanticsNodeInteractionCommonExt.js.kt
create mode 100644 ultron-compose/src/jvmMain/kotlin/com/atiurin/ultron/core/compose/list/ItemChildInteractionProvider.jvm.kt
create mode 100644 ultron-compose/src/jvmMain/kotlin/com/atiurin/ultron/extensions/SemanticsNodeInteractionExt.jvm.kt
create mode 100644 ultron-compose/src/nativeMain/kotlin/com/atiurin/ultron/core/compose/list/ItemChildInteractionProvider.native.kt
create mode 100644 ultron-compose/src/nativeMain/kotlin/com/atiurin/ultron/extensions/SemanticsNodeInteractionCommonExt.native.kt
create mode 100644 ultron-compose/src/wasmJsMain/kotlin/com/atiurin/ultron/core/compose/list/ItemChildInteractionProvider.wasmJs.kt
create mode 100644 ultron-compose/src/wasmJsMain/kotlin/com/atiurin/ultron/extensions/SemanticsNodeInteractionCommonExt.wasmJs.kt
delete mode 100644 ultron/build.gradle.kts
delete mode 100644 ultron/src/main/java/com/atiurin/ultron/core/config/UltronConfigParams.kt
delete mode 100644 ultron/src/main/java/com/atiurin/ultron/extensions/AnyExt.kt
delete mode 100644 ultron/src/main/java/com/atiurin/ultron/listeners/TimeListener.kt
delete mode 100644 ultron/src/main/java/com/atiurin/ultron/log/UFileLogger.kt
diff --git a/.github/workflows/android-pipeline.yml b/.github/workflows/android-pipeline.yml
index 2ace6acb..7302d7fa 100644
--- a/.github/workflows/android-pipeline.yml
+++ b/.github/workflows/android-pipeline.yml
@@ -7,7 +7,7 @@ on:
branches: [ master ]
jobs:
- run_tests_on_api_29:
+ compileKotlin:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
@@ -17,4 +17,4 @@ jobs:
java-version: '17'
- name: Compile framework
- run: ./gradlew :ultron:compileDebugKotlin
+ run: ./gradlew compileDebugKotlin
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
new file mode 100644
index 00000000..4964e8d7
--- /dev/null
+++ b/.github/workflows/docs.yml
@@ -0,0 +1,25 @@
+name: Build and deploy docs
+
+on:
+ push:
+ branches:
+ - master
+
+jobs:
+ github-pages:
+ runs-on: ubuntu-22.04
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 22
+ - run: npm install
+ working-directory: ./docs
+ - run: npm run build
+ working-directory: ./docs
+
+ - name: Deploy to GitHub Pages
+ uses: peaceiris/actions-gh-pages@v3
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+ publish_dir: ./docs/build
\ No newline at end of file
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
new file mode 100644
index 00000000..012728c0
--- /dev/null
+++ b/.github/workflows/publish.yml
@@ -0,0 +1,66 @@
+name: Publish to Maven Central
+
+permissions:
+ contents: read
+
+on:
+ push:
+ tags:
+ - 'v*'
+
+jobs:
+ publish:
+ env:
+ OSSRH_TOKEN: ${{ secrets.OSSRH_TOKEN }}
+ OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
+ OSSRH_STAGING_PROFILE_ID: ${{ secrets.OSSRH_STAGING_PROFILE_ID }}
+ OSSRH_GPG_SECRET_KEY_PASSWORD: ${{ secrets.OSSRH_GPG_SECRET_KEY_PASSWORD }}
+ OSSRH_GPG_SECRET_KEY_ID: ${{ secrets.OSSRH_GPG_SECRET_KEY_ID }}
+
+ strategy:
+ matrix:
+ include:
+ - target: :ultron-compose:publishToSonatype
+ os: ubuntu-latest
+ - target: :ultron-android:publishToSonatype
+ os: ubuntu-latest
+ - target: :ultron-allure:publishToSonatype
+ os: ubuntu-latest
+ - target: :ultron-common:publishToSonatype
+ os: ubuntu-latest
+ runs-on: ${{ matrix.os }}
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ - name: Validate Gradle Wrapper
+ uses: gradle/wrapper-validation-action@v1
+
+ - name: Setup JDK 17
+ uses: actions/setup-java@v3
+ with:
+ java-version: '17'
+ distribution: "zulu"
+
+ - name: Setup Gradle cache
+ uses: actions/cache@v3
+ with:
+ path: |
+ ~/.konan
+ key: ${{ runner.os }}-${{ hashFiles('**/.lock') }}
+
+ - name: Import GPG key
+ uses: crazy-max/ghaction-import-gpg@v6
+ with:
+ gpg_private_key: ${{ secrets.OSSRH_GPG_SECRET_KEY }}
+ passphrase: ${{ secrets.OSSRH_GPG_SECRET_KEY_PASSWORD }}
+
+ - name: Gradle publish
+ run: ./gradlew "${{ matrix.target }}" closeAndReleaseSonatypeStagingRepository
+ env:
+ OSSRH_USERNAME: ${{ secrets.OSSRH_TOKEN }}
+ OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
+ OSSRH_STAGING_PROFILE_ID: ${{ secrets.OSSRH_STAGING_PROFILE_ID }}
+ SIGNING_KEY: ${{ secrets.OSSRH_GPG_SECRET_KEY }}
+ SIGNING_PASSWORD: ${{ secrets.OSSRH_GPG_SECRET_KEY_PASSWORD }}
diff --git a/.gitignore b/.gitignore
index 653b7b8d..af5b6da0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,4 +12,5 @@
build/
/captures
.externalNativeBuild
-/allure-results
\ No newline at end of file
+/allure-results
+/.kotlin
\ No newline at end of file
diff --git a/README.md b/README.md
index 418178af..5b03a597 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,8 @@ Ultron can be easially customised and extended. Wish you exclusively stable test
+## [Documentation](https://open-tool.github.io/ultron/) | [Releases](https://github.com/open-tool/ultron/releases)
+
## What are the benefits of using the framework?
- Exceptional support for [**Compose**](https://github.com/open-tool/ultron/wiki/Compose)
@@ -247,21 +249,11 @@ For the complete guide, refer to the [wiki](https://github.com/open-tool/ultron/
fun setConfig() {
UltronConfig.applyRecommended()
UltronAllureConfig.applyRecommended()
+ UltronComposeConfig.applyRecommended()
}
```
![allure](https://github.com/open-tool/ultron/assets/12834123/c05c813a-ece6-45e6-a04f-e1c92b82ffb1)
-for Compose add 4 lines more
-```kotlin
-@BeforeClass @JvmStatic
-fun setConfig() {
- ...
- UltronComposeConfig.applyRecommended()
- UltronComposeConfig.addListener(ScreenshotAttachListener())
- UltronComposeConfig.addListener(WindowHierarchyAttachListener())
- UltronComposeConfig.addListener(DetailedOperationAllureListener())
-}
-```
![allure compose](https://github.com/open-tool/ultron/assets/12834123/1f751f3d-fc58-4874-a850-acd9181bfb70)
@@ -274,7 +266,7 @@ repositories {
}
dependencies {
- androidTestImplementation 'com.atiurin:ultron:'
+ androidTestImplementation 'com.atiurin:ultron-android:'
androidTestImplementation 'com.atiurin:ultron-allure:'
androidTestImplementation 'com.atiurin:ultron-compose:'
}
@@ -284,8 +276,3 @@ Please, read [gradle dependencies management](https://github.com/open-tool/ultro
## AndroidX
It is required to use AndroidX libraries. You can get some problems with Android Support ones.
-
-## Roadmap
-
-- https://github.com/open-tool/ultron/issues/50 Meta information for UI elements
-- https://github.com/open-tool/ultron/issues/33 Screenshot testign ?
diff --git a/build.gradle.kts b/build.gradle.kts
index 57612bbb..0bbf722d 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,3 +1,5 @@
+import org.jetbrains.compose.internal.utils.getLocalProperty
+
buildscript {
extra.apply {
set("RELEASE_REPOSITORY_URL", "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/")
@@ -7,6 +9,7 @@ buildscript {
repositories {
google()
mavenCentral()
+ mavenLocal()
}
dependencies {
classpath(Plugins.kotlinGradle)
@@ -17,14 +20,36 @@ buildscript {
}
}
+plugins {
+ //trick: for the same plugin versions in all sub-modules
+ alias(libs.plugins.androidLibrary) apply false
+ alias(libs.plugins.kotlinMultiplatform) apply false
+ alias(libs.plugins.androidApplication) apply false
+ alias(libs.plugins.jetbrainsCompose) apply false
+ alias(libs.plugins.kotlinJvm) apply false
+ alias(libs.plugins.compose.compiler) apply false
+ id("io.github.gradle-nexus.publish-plugin").version("2.0.0-rc-1")
+}
+
+nexusPublishing {
+ repositories {
+ sonatype {
+ username
+ nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/"))
+ snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/"))
+ username.set(getLocalProperty("ossrhToken") ?: System.getenv("OSSRH_TOKEN"))
+ password.set(getLocalProperty("ossrhTokenPassword") ?: System.getenv("OSSRH_PASSWORD"))
+ stagingProfileId.set(getLocalProperty("sonatype.stagingProfileId") ?: System.getenv("OSSRH_STAGING_PROFILE_ID"))
+ }
+ }
+}
+
+
allprojects {
repositories {
google()
mavenCentral()
+ mavenLocal()
gradlePluginPortal()
}
-}
-
-tasks.register("clean", Delete::class) {
- delete(rootProject.buildDir)
-}
+}
\ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt
index df03972d..2e4eca29 100644
--- a/buildSrc/src/main/kotlin/Versions.kt
+++ b/buildSrc/src/main/kotlin/Versions.kt
@@ -1,9 +1,9 @@
object Versions {
- const val kotlin = "1.8.0"
+ const val kotlin = "2.0.0"
const val androidToolsBuildGradle = "8.3.1"
const val androidMavenGradlePlugin = "2.1"
- const val publishPlugin = "0.13.0"
- const val dokkaPlugin = "1.4.30"
+ const val publishPlugin = "0.29.0"
+ const val dokkaPlugin = "1.9.20"
const val recyclerView = "1.2.1"
const val espresso = "3.4.0"
diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts
new file mode 100644
index 00000000..8d406a78
--- /dev/null
+++ b/composeApp/build.gradle.kts
@@ -0,0 +1,133 @@
+import org.jetbrains.compose.ExperimentalComposeLibrary
+import org.jetbrains.compose.desktop.application.dsl.TargetFormat
+import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
+import org.jetbrains.kotlin.gradle.dsl.JvmTarget
+import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetTree
+import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl
+import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig
+
+plugins {
+ alias(libs.plugins.kotlinMultiplatform)
+ alias(libs.plugins.androidApplication)
+ alias(libs.plugins.jetbrainsCompose)
+ alias(libs.plugins.compose.compiler)
+}
+
+kotlin {
+ androidTarget {
+ @OptIn(ExperimentalKotlinGradlePluginApi::class)
+ compilerOptions {
+ jvmTarget.set(JvmTarget.JVM_17)
+ }
+ @OptIn(ExperimentalKotlinGradlePluginApi::class)
+ instrumentedTestVariant {
+ sourceSetTree.set(KotlinSourceSetTree.test)
+
+ dependencies {
+ implementation(libs.androidx.ui.test.junit4.android)
+ debugImplementation(libs.androidx.ui.test.manifest)
+ }
+ }
+ }
+
+ jvm("desktop")
+
+// listOf(
+// iosX64(),
+// iosArm64(),
+// iosSimulatorArm64()
+// ).forEach { iosTarget ->
+// iosTarget.binaries.framework {
+// baseName = "ComposeApp"
+// isStatic = true
+// }
+// }
+
+ sourceSets {
+ val desktopMain by getting
+
+ androidMain.dependencies {
+ implementation(compose.preview)
+ implementation(libs.androidx.activity.compose)
+ }
+ commonMain.dependencies {
+ implementation(compose.runtime)
+ implementation(compose.foundation)
+ implementation(compose.material)
+ implementation(compose.ui)
+ implementation(compose.components.resources)
+ implementation(compose.components.uiToolingPreview)
+ implementation(libs.androidx.lifecycle.runtime.compose)
+ implementation(libs.androidx.lifecycle.viewmodel.compose)
+ implementation(libs.androidx.navigation.compose)
+ }
+ commonTest.dependencies {
+ @OptIn(ExperimentalComposeLibrary::class)
+ implementation(compose.uiTest)
+ implementation(kotlin("test"))
+ implementation(project(":ultron-compose"))
+ }
+ desktopMain.dependencies {
+ implementation(compose.desktop.currentOs)
+ }
+ // Adds the desktop test dependency
+ val desktopTest by getting {
+ dependencies {
+ implementation(compose.desktop.uiTestJUnit4)
+ implementation(compose.desktop.currentOs)
+ }
+ }
+ }
+}
+
+android {
+ namespace = "com.atiurin.samplekmp"
+ compileSdk = libs.versions.android.compileSdk.get().toInt()
+
+ sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
+ sourceSets["main"].res.srcDirs("src/androidMain/res")
+ sourceSets["main"].resources.srcDirs("src/commonMain/resources")
+
+ defaultConfig {
+ applicationId = "com.atiurin.samplekmp"
+ minSdk = libs.versions.android.minSdk.get().toInt()
+ targetSdk = libs.versions.android.targetSdk.get().toInt()
+ versionCode = 1
+ versionName = "1.0"
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+ packaging {
+ resources {
+ excludes += "/META-INF/{AL2.0,LGPL2.1}"
+ }
+ }
+ buildTypes {
+ getByName("release") {
+ isMinifyEnabled = false
+ }
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+ buildFeatures {
+ compose = true
+ }
+// dependencies {
+// debugImplementation(compose.uiTooling)
+// }
+
+}
+
+
+compose.desktop {
+ application {
+ mainClass = "MainKt"
+
+ nativeDistributions {
+ targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
+ packageName = "com.atiurin.samplekmp"
+ packageVersion = "1.0.0"
+ }
+ }
+}
diff --git a/composeApp/src/androidMain/AndroidManifest.xml b/composeApp/src/androidMain/AndroidManifest.xml
new file mode 100644
index 00000000..c5db0b15
--- /dev/null
+++ b/composeApp/src/androidMain/AndroidManifest.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/composeApp/src/androidMain/kotlin/Platform.android.kt b/composeApp/src/androidMain/kotlin/Platform.android.kt
new file mode 100644
index 00000000..4f3ea051
--- /dev/null
+++ b/composeApp/src/androidMain/kotlin/Platform.android.kt
@@ -0,0 +1,7 @@
+import android.os.Build
+
+class AndroidPlatform : Platform {
+ override val name: String = "Android ${Build.VERSION.SDK_INT}"
+}
+
+actual fun getPlatform(): Platform = AndroidPlatform()
\ No newline at end of file
diff --git a/composeApp/src/androidMain/kotlin/com/atiurin/samplekmp/MainActivity.kt b/composeApp/src/androidMain/kotlin/com/atiurin/samplekmp/MainActivity.kt
new file mode 100644
index 00000000..459a1bfa
--- /dev/null
+++ b/composeApp/src/androidMain/kotlin/com/atiurin/samplekmp/MainActivity.kt
@@ -0,0 +1,24 @@
+package com.atiurin.samplekmp
+
+import App
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.tooling.preview.Preview
+
+class MainActivity : ComponentActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ setContent {
+ App()
+ }
+ }
+}
+
+@Preview
+@Composable
+fun AppAndroidPreview() {
+ App()
+}
\ No newline at end of file
diff --git a/composeApp/src/androidMain/res/drawable-v24/ic_launcher_foreground.xml b/composeApp/src/androidMain/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 00000000..2b068d11
--- /dev/null
+++ b/composeApp/src/androidMain/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/composeApp/src/androidMain/res/drawable/ic_launcher_background.xml b/composeApp/src/androidMain/res/drawable/ic_launcher_background.xml
new file mode 100644
index 00000000..e93e11ad
--- /dev/null
+++ b/composeApp/src/androidMain/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml b/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 00000000..eca70cfe
--- /dev/null
+++ b/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher_round.xml b/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 00000000..eca70cfe
--- /dev/null
+++ b/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher.png b/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000000000000000000000000000000000000..a571e60098c92c2baca8a5df62f2929cbff01b52
GIT binary patch
literal 3593
zcmV+k4)*bhP){4Q1@|o^l5vR(0JRNCL<7M6}UD`@%^5zYjRJ-VNC3qn#9n=m>>ACRx!M
zlW3!lO>#0MCAqh6PU7cMP#aQ`+zp##c~|0RJc4JAuaV=qZS|vg8XJ$1pYxc-u~Q5j
z%Ya4ddEvZow!floOU_jrlE84*Kfv6!kMK^%#}A$Bjrna`@pk(TS$jA@P;|iPUR-x)_r4ELtL9aUonVhI31zFsJ96
z|5S{%9|FB-SsuD=#0u1WU!W6fcXF)#63D7tvwg%1l(}|SzXh_Z(5234`w*&@ctO>g
z0Aug~xs*zAjCpNau(Ul@mR~?6dNGx9Ii5MbMvmvUxeqy>$Hrrn;v8G!g*o~UV4mr_
zyWaviS4O6Kb?ksg`)0wj?E@IYiw3az(r1w37|S|7!ODxfW%>6m?!@woyJUIh_!>E$
z+vYyxcpe*%QHt~E*etx=mI~XG8~QJhRar>tNMB;pPOKRfXjGt4fkp)y6=*~XIJC&C!aaha9k7~UP9;`q;1n9prU@a%Kg%gDW+xy9n`kiOj8WIs;+T>HrW
znVTomw_2Yd%+r4at4zQC3*=Z4naYE7H*Dlv4=@IEtH_H;af}t@W7@mE$1xI#XM-`%
z0le3-Q}*@D@ioThJ*cgm>kVSt+=txjd2BpJDbBrpqp-xV9X6Rm?1Mh~?li96xq(IP
z+n(4GTXktSt_z*meC5=$pMzMKGuIn&_IeX6Wd!2$md%l{x(|LXClGVhzqE^Oa@!*!
zN%O7K8^SHD|9aoAoT4QLzF+Uh_V03V;KyQ|__-RTH(F72qnVypVei#KZ2K-7YiPS*
z-4gZd>%uRm<0iGmZH|~KW<>#hP9o@UT@gje_^AR{?p(v|y8`asyNi4G?n#2V+jsBa
z+uJ|m;EyHnA%QR7{z(*%+Z;Ip(Xt5n<`4yZ51n^!%L?*a=)Bt{J_b`;+~$Z7h^x@&
zSBr2>_@&>%7=zp5Ho5H~6-Y@wXkpt{s9Tc+7RnfWuZC|&NO6p{m-gU%=cPw3qyB>1
zto@}!>_e`99vhEQic{;8goXMo1NA`>sch8T3@O44!$uf`IlgBj#c@Ku*!9B`7seRe
z2j?cKG4R-Uj8dFidy25wu#J3>-_u`WT%NfU54JcxsJv;A^i#t!2XXn%zE=O##OXoy
zwR2+M!(O12D_LUsHV)v2&TBZ*di1$c8
z+_~Oo@HcOFV&TasjNRjf*;zVV?|S@-_EXmlIG@&F!WS#yU9<_Ece?sq^L^Jf%(##=
zdTOpA6uXwXx3O|`C-Dbl~`~#9yjlFN>;Yr?Kv68=F`fQLW
z(x40UIAuQRN~Y|fpCi2++qHWrXd&S*NS$z8V+YP
zSX7#fxfebdJfrw~mzZr!thk9BE&_eic@-9C0^nK@0o$T5nAK~CHV4fzY#KJ=^uV!D
z3)jL(DDpL!TDSq`=e0v8(8`Wo_~p*6KHyT!kmCCCU48I?mw-UrBj8=Vg#?O%Z2<|C
z?+4Q&W09VsK<14)vHY^n;Zi3%4Q?s4x^$3;acx76-t*K|3^MUKELf>Jew${&!(xTD_PD>KINXl?sUX;X6(}jr
zKrxdFCW8)!)dz>b!b9nBj1uYxc;
zCkmbfhwNZDp*
zIG07ixjYK$3PNQx)KxK1*Te{mTeb}BZJ++Waj0sFgVkw&DAWDnl0pBiBWqxObPX)h
z*TN!$aBLmH2kNX4xMpc!d15^*Gksy1l@P~U&INWk{u*%*5>+Aqn=LEne
zClEHdguEb8oEZgNsY0NjWUMIEh&hLsm2Ght7L+H$y*w6nWjffE>tJ6IF2bRboPSlg
z;8~Xh^J6|kbIX-0hD~-L?Y;aST2{Rivf_k4>}dA%URJ#mvcu^R*wO6iy{vjCWaoSe
zIzRNGW!00Ad0EXUi-mouPFz-|lzU9e0x_*DNL*smDnbNRbrdEYSuu3?q}5FcaLx&n
z6o+$;B9jEl3Xl|sbB;2b1fnV>B@X8tbpg!?+EPe~!#T&jf&`-3(^s5eOsfnL9BZO5
z<?!X^iNgt5T^IrT!Z1m3I3c@N#=*Wk
zTtb{+Os~=ijjE^lB2QE@pTLB>vqLE(X}Ul(PxsQZDCnRJoyWpo%5ub6koe;ZUTN6o;49
z%&K@2C_+LULQSaPbZ$5a#EF|k;vjo+j;&bEgJpe=Dlb&rmCN}Yml6`FSSKkCFRPi=
z31Y?SD~<-!YoCBXgYhw7kJe3M?qILPK4)%D3{=?~aXC5Wgu;<#4Lf9~Ghw37nNM&o
z(80MdTm&yGb#a6!4*MJ~aIJ`eYb7HVu2r#ctB!;Bxoucjw;3~P<1wQy0q*sQ
z-8i2F_l87aanncS%?9u}>B0ISxxWC)h0qo
zrToFN(!i`X6lQgyd`nhvZivH_^!NKOkY(B6epkb-IT>nNDsn!@k(QQ{wh(eY$F)2L
z%JK*qpF;wXQ&v$amkWn9MR
zaNbc-m6G;3A@HbAhN>=FN*tK8Kuz(Oa%{~&W>Cn+r}2e4u5KK(akX-yq^zQ4DCcwB
zC?TsVB4vEeeSxS_^$~}*LFNtJ0!>a^k=k#8$c8T#XHavvV16Nda6bl2B5~loOSuzO
zELE{i*5|lY#X(gWDdTfA@Hn5+Es&8oX6Na#Nhdn#w^HUT=U69h_kQVdztsB&!awcK
zhE$2-v_uFjRBxzT6NNb)AND!l0}@y8&8iWGR`$$Kl_KCnY(6UaWtqaj6b
zs*e#kA#=_#KTn{U!{V4VXkq!qx>|~Hj2P?V{?LHuK~EOwt8K?a=Xztlp31x-RhD0*-wJ+j>Y?-0hXd`O?21C+SsD+I(m2?agwd{C
zOB+u@xsG_9xP@3yLwmg%s#MkFt7;-CAxBZpA)JebBVkF?7I-#pgkwW2oEiyDaUzt}
zk+4W#SNAW)n+lH6T5J8{bNxA9w|@PP^za&C{2LmVpz%AG?wzpT`>@HLcMqBD^G-9}
zw>-__!0I%9ZnAe-_hZjZP4nNGYJ^AgtAO?>Uo^!N|Le+X|9-g?II=KWY+eRb@sf8iJh{v#I?
zC%*LZ_}5?l+Z(UF^4EXA`uArU90SL~F%8D=fjmD#FnWw0qsQp+OdS6QzyUa+`7Q|u
P00000NkvXXu0mjfP=x?Y
literal 0
HcmV?d00001
diff --git a/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher_round.png b/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000000000000000000000000000000000000..61da551c5594a1f9d26193983d2cd69189014603
GIT binary patch
literal 5339
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