Browse Source

Merge branch 'master' into support/1.5.0

support/1.5.0-replace-warnings-with-errors
Alexey Tsvetkov 1 year ago
parent
commit
6127a29700
  1. 48
      .github/ISSUE_TEMPLATE/performance.md
  2. 195
      CHANGELOG.md
  3. 4
      VERSIONING.md
  4. 2
      ci/compose-uber-jar/gradle.properties
  5. 4
      ci/templates/desktop-template/gradle.properties
  6. 4
      ci/templates/html-library-template/gradle.properties
  7. 4
      ci/templates/multiplatform-template/gradle.properties
  8. 2
      components/gradle.properties
  9. 2
      components/resources/library/build.gradle.kts
  10. 2
      components/resources/library/src/iosMain/kotlin/org/jetbrains/compose/resources/Resource.ios.kt
  11. 2
      components/resources/library/src/macosMain/kotlin/org/jetbrains/compose/resources/Resource.macos.kt
  12. 6
      compose/integrations/composable-test-cases/build.gradle.kts
  13. 6
      compose/integrations/composable-test-cases/gradle.properties
  14. 3
      compose/integrations/composable-test-cases/settings.gradle.kts
  15. 39
      compose/integrations/composable-test-cases/testcases/expectActual/lib/build.gradle.kts
  16. 10
      compose/integrations/composable-test-cases/testcases/expectActual/lib/src/commonMain/kotlin/Dependencies.kt
  17. 4
      compose/integrations/composable-test-cases/testcases/expectActual/lib/src/desktopMain/kotlin/Actuals.kt
  18. 4
      compose/integrations/composable-test-cases/testcases/expectActual/lib/src/jsMain/kotlin/Actuals.kt
  19. 4
      compose/integrations/composable-test-cases/testcases/expectActual/lib/src/nativeMain/kotlin/Actuals.kt
  20. 21
      compose/integrations/composable-test-cases/testcases/expectActual/main/build.gradle.kts
  21. 32
      compose/integrations/composable-test-cases/testcases/expectActual/main/src/commonTest/kotlin/Tests.kt
  22. 29
      examples/README.md
  23. 4
      examples/chat/gradle.properties
  24. 4
      examples/codeviewer/gradle.properties
  25. 4
      examples/falling-balls/gradle.properties
  26. 4
      examples/html/compose-bird/gradle.properties
  27. 4
      examples/html/compose-in-js/gradle.properties
  28. 4
      examples/html/landing/gradle.properties
  29. 4
      examples/html/with-react/gradle.properties
  30. 4
      examples/intellij-plugin/gradle.properties
  31. 4
      examples/issues/gradle.properties
  32. 4
      examples/minesweeper/gradle.properties
  33. 4
      examples/notepad/gradle.properties
  34. 4
      examples/todoapp-lite/gradle.properties
  35. 15
      examples/todoapp/.gitignore
  36. 23
      examples/todoapp/.run/browser.run.xml
  37. 23
      examples/todoapp/.run/desktop.run.xml
  38. 61
      examples/todoapp/README.md
  39. 44
      examples/todoapp/android/build.gradle.kts
  40. 28
      examples/todoapp/android/src/main/AndroidManifest.xml
  41. 13
      examples/todoapp/android/src/main/java/example/todo/android/App.kt
  42. 8
      examples/todoapp/android/src/main/java/example/todo/android/Color.kt
  43. 39
      examples/todoapp/android/src/main/java/example/todo/android/MainActivity.kt
  44. 11
      examples/todoapp/android/src/main/java/example/todo/android/Shape.kt
  45. 35
      examples/todoapp/android/src/main/java/example/todo/android/Theme.kt
  46. 16
      examples/todoapp/android/src/main/java/example/todo/android/Type.kt
  47. 34
      examples/todoapp/android/src/main/res/drawable-v24/ic_launcher_foreground.xml
  48. 170
      examples/todoapp/android/src/main/res/drawable/ic_launcher_background.xml
  49. 5
      examples/todoapp/android/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
  50. 5
      examples/todoapp/android/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
  51. BIN
      examples/todoapp/android/src/main/res/mipmap-hdpi/ic_launcher.png
  52. BIN
      examples/todoapp/android/src/main/res/mipmap-hdpi/ic_launcher_round.png
  53. BIN
      examples/todoapp/android/src/main/res/mipmap-mdpi/ic_launcher.png
  54. BIN
      examples/todoapp/android/src/main/res/mipmap-mdpi/ic_launcher_round.png
  55. BIN
      examples/todoapp/android/src/main/res/mipmap-xhdpi/ic_launcher.png
  56. BIN
      examples/todoapp/android/src/main/res/mipmap-xhdpi/ic_launcher_round.png
  57. BIN
      examples/todoapp/android/src/main/res/mipmap-xxhdpi/ic_launcher.png
  58. BIN
      examples/todoapp/android/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
  59. BIN
      examples/todoapp/android/src/main/res/mipmap-xxxhdpi/ic_launcher.png
  60. BIN
      examples/todoapp/android/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
  61. 4
      examples/todoapp/android/src/main/res/values/strings.xml
  62. 19
      examples/todoapp/build.gradle.kts
  63. 24
      examples/todoapp/buildSrc/build.gradle.kts
  64. 12
      examples/todoapp/buildSrc/buildSrc/build.gradle.kts
  65. 101
      examples/todoapp/buildSrc/buildSrc/src/main/kotlin/Deps.kt
  66. 17
      examples/todoapp/buildSrc/buildSrc/src/main/kotlin/IosWorkaroundSupportArm64Simulator.kt
  67. 3
      examples/todoapp/buildSrc/gradle.properties
  68. 26
      examples/todoapp/buildSrc/src/main/kotlin/android-setup.gradle.kts
  69. 39
      examples/todoapp/buildSrc/src/main/kotlin/multiplatform-compose-setup.gradle.kts
  70. 75
      examples/todoapp/buildSrc/src/main/kotlin/multiplatform-setup.gradle.kts
  71. 25
      examples/todoapp/common/compose-ui/build.gradle.kts
  72. 2
      examples/todoapp/common/compose-ui/src/androidMain/AndroidManifest.xml
  73. 26
      examples/todoapp/common/compose-ui/src/androidMain/kotlin/example/todo/common/ui/Scrollbars.kt
  74. 23
      examples/todoapp/common/compose-ui/src/commonMain/kotlin/example/todo/common/ui/Scrollbars.kt
  75. 15
      examples/todoapp/common/compose-ui/src/commonMain/kotlin/example/todo/common/ui/ShortcutHandler.kt
  76. 60
      examples/todoapp/common/compose-ui/src/commonMain/kotlin/example/todo/common/ui/TodoEditUi.kt
  77. 158
      examples/todoapp/common/compose-ui/src/commonMain/kotlin/example/todo/common/ui/TodoMainUi.kt
  78. 25
      examples/todoapp/common/compose-ui/src/commonMain/kotlin/example/todo/common/ui/TodoRootUi.kt
  79. 34
      examples/todoapp/common/compose-ui/src/desktopMain/kotlin/example/todo/common/ui/Scrollbars.kt
  80. 28
      examples/todoapp/common/compose-ui/src/desktopMain/kotlin/example/todo/common/ui/TodoEditPreview.kt
  81. 37
      examples/todoapp/common/compose-ui/src/desktopMain/kotlin/example/todo/common/ui/TodoMainPreview.kt
  82. 46
      examples/todoapp/common/database/build.gradle.kts
  83. 2
      examples/todoapp/common/database/src/androidMain/AndroidManifest.xml
  84. 14
      examples/todoapp/common/database/src/androidMain/kotlin/example/todo/common/database/TodoDatabaseDriverFactory.kt
  85. 91
      examples/todoapp/common/database/src/commonMain/kotlin/example/todo/common/database/DefaultTodoSharedDatabase.kt
  86. 105
      examples/todoapp/common/database/src/commonMain/kotlin/example/todo/common/database/TestTodoSharedDatabase.kt
  87. 22
      examples/todoapp/common/database/src/commonMain/kotlin/example/todo/common/database/TodoSharedDatabase.kt
  88. 39
      examples/todoapp/common/database/src/commonMain/sqldelight/example/todo/common/database/TodoDatabase.sq
  89. 15
      examples/todoapp/common/database/src/desktopMain/kotlin/example/todo/common/database/TodoDatabaseDriverFactory.kt
  90. 9
      examples/todoapp/common/database/src/iosMain/kotlin/example/todo/common/database/TodoDatabaseDriverFactory.kt
  91. 10
      examples/todoapp/common/database/src/jsMain/kotlin/example/todo/common/database/TodoDatabaseDriverFactory.kt
  92. 19
      examples/todoapp/common/edit/build.gradle.kts
  93. 2
      examples/todoapp/common/edit/src/androidMain/AndroidManifest.xml
  94. 23
      examples/todoapp/common/edit/src/commonMain/kotlin/example/todo/common/edit/TodoEdit.kt
  95. 6
      examples/todoapp/common/edit/src/commonMain/kotlin/example/todo/common/edit/TodoItem.kt
  96. 12
      examples/todoapp/common/edit/src/commonMain/kotlin/example/todo/common/edit/integration/Mappers.kt
  97. 48
      examples/todoapp/common/edit/src/commonMain/kotlin/example/todo/common/edit/integration/TodoEditComponent.kt
  98. 31
      examples/todoapp/common/edit/src/commonMain/kotlin/example/todo/common/edit/integration/TodoEditStoreDatabase.kt
  99. 24
      examples/todoapp/common/edit/src/commonMain/kotlin/example/todo/common/edit/store/TodoEditStore.kt
  100. 83
      examples/todoapp/common/edit/src/commonMain/kotlin/example/todo/common/edit/store/TodoEditStoreProvider.kt
  101. Some files were not shown because too many files have changed in this diff Show More

48
.github/ISSUE_TEMPLATE/performance.md

@ -0,0 +1,48 @@
---
name: Performance problem
about: Create a report to help us improve
title: ''
labels: ['submitted', 'performance']
assignees: ''
---
**Describe the problem**
Explain the performance issue you're experiencing, including the following details:
- What specific issue did you encounter? (e.g. missing frames, high CPU usage, memory leaks)
- Have you noticed any patterns or specific circumstances under which the problem occurs?
**Affected platforms**
Select one of the platforms below:
- All
- Desktop
- Web (K/Wasm) - Canvas based API
- Web (K/JS) - Canvas based API
- Web (K/JS) - HTML library
- iOS
- Other
If the problem is Android-only, report it in the [Jetpack Compose tracker](https://issuetracker.google.com/issues/new?component=612128)
**Versions**
- Kotlin version:
- Compose Multiplatform version:
- OS version(s) (required for Desktop and iOS issues):
- OS architecture (x86 or arm64):
- JDK (for desktop issues):
**Sample code**
If possible, provide a small piece of code that reproduces the problem. If the code snippet is too large to paste here, please link to a Gist, a GitHub repo, or any other public code repository.
**Reproduction steps**
Please provide a detailed step-by-step guide on how to reproduce the issue you are experiencing.
**Video**
If you're reporting slow app work or missing frames, please provide a video of the problem.
**Profiling data**
Please provide any relevant profiling data that might be helpful. This could include information like FPS, memory usage, CPU time, or any other data that could provide insight into the performance issue.
**Additional information**
Provide any other details that you think might be helpful for us to understand the problem. This could include things like the system configuration, external factors, etc.

195
CHANGELOG.md

@ -1,3 +1,198 @@
# 1.5.0-beta02 (August 2023)
## Common
### Features
- [`androidx.compose.material.DropdownMenu` is available to use from common source set](https://github.com/JetBrains/compose-multiplatform-core/pull/738)
- [`androidx.compose.material3.DropdownMenu` is available to use from common source set](https://github.com/JetBrains/compose-multiplatform-core/pull/737)
- [`androidx.compose.material.AlertDialog` is available to use from common source set](https://github.com/JetBrains/compose-multiplatform-core/pull/708)
- [`androidx.compose.material3.AlertDialog` is available to use from common source set](https://github.com/JetBrains/compose-multiplatform-core/pull/710)
- [Add `PopupProperties.clippingEnabled` setting](https://github.com/JetBrains/compose-multiplatform-core/pull/740)
- material3. Support [`DatePicker`](https://github.com/JetBrains/compose-multiplatform-core/pull/717), [`DatePickerDialog`](https://github.com/JetBrains/compose-multiplatform-core/pull/745) and `TimePicker`
### API Changes
- [Change the default layout behavior of `AlertDialog`](https://github.com/JetBrains/compose-multiplatform-core/pull/708)
## iOS
### Features
- [Support singleLine and `KeyboardAction`](https://github.com/JetBrains/compose-multiplatform-core/pull/699)
### Fixes
- [Fix memory leak in `ComposeUIViewController`](https://github.com/JetBrains/compose-multiplatform/issues/3201)
- [Manage Kotlin native cache kind automatically based on Kotlin version](https://github.com/JetBrains/compose-multiplatform/pull/3477) (`kotlin.native.cacheKind=none` is no longer needed)
- [Limit max `Dialog` and `Popup` size by safe area on iOS](https://github.com/JetBrains/compose-multiplatform-core/pull/732)
- [`TextField`, Korean characters are not normally entered](https://github.com/JetBrains/compose-multiplatform/issues/3101)
- [`ColorMatrix` value range for 5th column was incorrect on Skiko backed platforms](https://github.com/JetBrains/compose-multiplatform/issues/3461)
- [`isSystemDarkTheme` now automatically react to the system theme changes](https://github.com/JetBrains/compose-multiplatform-core/pull/715)
### API Changes
- [`ComposeUIViewController`. Dispose composition on `viewDidDisappear`](https://github.com/JetBrains/compose-multiplatform-core/pull/747)
## Web
### Features
- [Make `CanvasBasedWindow` apply default styles, set title](https://github.com/JetBrains/compose-multiplatform-core/pull/722)
## Gradle Plugin
### Features
- [Add `runtimeSaveable` to Dependencies in compose gradle plugin](https://github.com/JetBrains/compose-multiplatform/pull/3449)
### API Changes
- [Raise error when Homebrew JDK is used for packaging](https://github.com/JetBrains/compose-multiplatform/pull/3451/files)
## Dependencies
This version of Compose Multiplatform is based on the next Jetpack Compose libraries:
- [Compiler 1.5.0](https://developer.android.com/jetpack/androidx/releases/compose-compiler#1.5.0)
- [Runtime 1.5.0](https://developer.android.com/jetpack/androidx/releases/compose-runtime#1.5.0)
- [UI 1.5.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.5.0)
- [Foundation 1.5.0](https://developer.android.com/jetpack/androidx/releases/compose-foundation#1.5.0)
- [Material 1.5.0](https://developer.android.com/jetpack/androidx/releases/compose-material#1.5.0)
- [Material3 1.1.1](https://developer.android.com/jetpack/androidx/releases/compose-material3#1.1.1)
# 1.5.0-beta01 (July 2023)
## Common
### Features
- [`Dialog` API is available to use from common source set](https://github.com/JetBrains/compose-multiplatform-core/pull/632)
- [`Popup` API is available to use from common source set](https://github.com/JetBrains/compose-multiplatform-core/pull/611)
- [`WindowInsets` API is available to use from common source set](https://github.com/JetBrains/compose-multiplatform-core/pull/586)
- [A warning if `compose.kotlinCompilerPlugin` is set to `androidx.compose.compiler.compiler`](https://github.com/JetBrains/compose-multiplatform/pull/3313)
### Fixes
- [`Popup`. Fix overriding `pressOwner` on multitouch](https://github.com/JetBrains/compose-multiplatform-core/pull/704)
- [Fix sending multiple touches in tests](https://github.com/JetBrains/compose-multiplatform-core/pull/688)
- [Fix multi-owner input processing](https://github.com/JetBrains/compose-multiplatform-core/pull/634)
- [Fix paragraph word boundary unicode handling](https://github.com/JetBrains/compose-multiplatform-core/pull/541)
- [Optimize the `Canvas` transformation functions](https://github.com/JetBrains/skiko/pull/724)
- [Fix click outside of common `Dialog` behaviour](https://github.com/JetBrains/compose-multiplatform-core/pull/707)
## iOS
### Features
- [iOS native scroll and feel](https://github.com/JetBrains/compose-multiplatform-core/pull/609)
- [Simplify resource management](https://github.com/JetBrains/compose-multiplatform/pull/3340) (works without CocoaPods now)
- [`TextField` keyboardOptions, capitalization](https://github.com/JetBrains/compose-multiplatform/issues/2735)
- [`TextField`, keyboard behavior when have fullscreen size TextField](https://github.com/JetBrains/compose-multiplatform/issues/2752)
- [`TextField`, different behavior strategies on appearing the keyboard](https://github.com/JetBrains/compose-multiplatform/issues/3128)
- [Insets on iOS](https://github.com/JetBrains/compose-multiplatform-core/pull/577)
- [Support `Density.textSize` (Dynamic Type)](https://github.com/JetBrains/compose-multiplatform/issues/2567)
- [Change default fonts](https://github.com/JetBrains/compose-multiplatform-core/pull/552) (San Francisco is the default font)
- [UIKit public `LocalUIViewController`](https://github.com/JetBrains/compose-multiplatform-core/pull/501)
### Fixes
- [Fix dynamic framework support](https://github.com/JetBrains/skiko/pull/763)
- [Fix `TextField` context menu](https://github.com/JetBrains/compose-multiplatform/issues/3276)
- [Fix complex blending on iOS](https://github.com/JetBrains/skiko/pull/728)
- [`ViewConfiguration.touchSlop` value is quite low on iOS](https://github.com/JetBrains/compose-multiplatform/issues/3397)
- [Fix `topLeftOffset` calculation on iOS in Split View](https://github.com/JetBrains/compose-multiplatform-core/pull/678)
- [`Modifier.draggable` `onDragStopped` not called](https://github.com/JetBrains/compose-multiplatform/issues/3310)
- [`UIKitView`. Fix lifetime discrepancy within the composition](https://github.com/JetBrains/compose-multiplatform-core/pull/576/files)
- [Support 120hz screens](https://github.com/JetBrains/compose-multiplatform-ios-android-template/pull/17)
- [Fix incorrect Skiko render target on iOS Metal](https://github.com/JetBrains/compose-multiplatform-core/pull/554)
- [Properly detect content based text direction on native](https://github.com/JetBrains/compose-multiplatform-core/pull/514)
- Implemented all low-level functions to avoid random crashes
- [Implement `TreeSet`](https://github.com/JetBrains/compose-multiplatform/issues/2878)
- [Implement `AnnotatedString.transform`](https://github.com/JetBrains/compose-multiplatform-core/pull/523)
- [Implement `WeakHashMap`](https://github.com/JetBrains/compose-multiplatform/issues/2877)
- [Implement `typefacesCache`](https://github.com/JetBrains/compose-multiplatform/issues/2873)
- [Implement `ExpireAfterAccessCache`](https://github.com/JetBrains/compose-multiplatform/issues/2871)
- [Implement `NativeStringDelegate`](https://github.com/JetBrains/compose-multiplatform/issues/2876)
### API Changes
- Resource management was reimplemented. Follow [the guide in the PR](https://github.com/JetBrains/compose-multiplatform/pull/3340) to support new feautures
## Desktop
### Features
- [Swing interop. Experimental off-screen rendering on graphics](https://github.com/JetBrains/compose-multiplatform-core/pull/601) (hardware accelerated only on macOs at the moment)
- [Swing interop. `ComposePanel` that can be disposed manually](https://github.com/JetBrains/compose-multiplatform-core/pull/620)
- [Add semantic properties to `DialogWindow`, `Popup` and `Dialog`](https://github.com/JetBrains/compose-multiplatform-core/pull/698)
- [Use `Segoe UI` as sans serif font on Windows](https://github.com/JetBrains/compose-multiplatform-core/pull/557)
- [Add ProGuard optimize flag](https://github.com/JetBrains/compose-multiplatform/pull/3408)
### Fixes
- [Fix loosing frames on macOs](https://github.com/JetBrains/skiko/pull/753)
- [Scrolling `LazyColumn` via mouse wheel stops working](https://github.com/JetBrains/compose-multiplatform/issues/3366)
- [`Slider` can be moved using keyboard, but cannot be submitted](https://github.com/JetBrains/compose-multiplatform/issues/2798)
- [Make one pixel beyond the scrollbar thumb react correctly to clicks](https://github.com/JetBrains/compose-multiplatform-core/pull/505)
- [`VerticalScrollbar` doesn't work properly when `LazyColumn` exists `StickyHeader`](https://github.com/JetBrains/compose-multiplatform/issues/2940)
- [All `Popup` overloads call dismiss on `Esc` key by default](https://github.com/JetBrains/compose-multiplatform-core/pull/712)
- [Fix Could not infer Java runtime version for Java home directory](https://github.com/JetBrains/compose-multiplatform/issues/3133)
- [Usage of deprecated `forEachGesture` in `Scrollbar.desktop.kt`](https://github.com/JetBrains/compose-multiplatform/issues/3045)
- Test framework fixes
- [Implement idling resources for tests](https://github.com/JetBrains/compose-multiplatform-core/pull/599)
- [Implement `SemanticsNodeInteraction.captureToImage()`](https://github.com/JetBrains/compose-multiplatform-core/pull/589)
- [Wait until compose is idle before returning from `DesktopTestOwner.getRoots()`](https://github.com/JetBrains/compose-multiplatform-core/pull/588)
- [When the test main clock is advanced, call `ComposeScene.render` with the current test time](https://github.com/JetBrains/compose-multiplatform-core/pull/584)
- [Add timestamps to batched test input events, and advance the test clock accordingly when sending them](https://github.com/JetBrains/compose-multiplatform-core/pull/578)
- [Tests support semanatic nodes inside `Window` and `DialogWindow`](https://github.com/JetBrains/compose-multiplatform-core/pull/697)
### API Changes
- [Rename desktop's `Dialog` to `DialogWindow`](https://github.com/JetBrains/compose-multiplatform-core/pull/661)
## Web
### Features
- [Let `ComposeWindow` accept a custom canvas id (html canvas element id)](https://github.com/JetBrains/compose-multiplatform-core/pull/626)
- [Support `Scrollbar`](https://github.com/JetBrains/compose-multiplatform-core/pull/571)
### Fixes
- [Workaround `ComposeWindow` multiple event listeners on resize](https://github.com/JetBrains/compose-multiplatform-core/pull/692)
- [Fix `Modifier.pointerHoverIcon` for browser apps](https://github.com/JetBrains/compose-multiplatform-core/pull/629)
- [Fux `RoundedCornerShape` with zero corners](https://github.com/JetBrains/compose-multiplatform/issues/3013)
- [Fix `ScrollConfig` in web target](https://github.com/JetBrains/compose-multiplatform-core/pull/628)
- Implemented low-level functions to avoid random crashes:
- [Implement cache key in `PlatformFont`](https://github.com/JetBrains/compose-multiplatform-core/pull/671)
- [implement platform detection to apply correct `KeyMapping` and `FontFamiliesMapping`](https://github.com/JetBrains/compose-multiplatform-core/pull/637)
- [Implement `PlatformLocale` and `StringDelegate` for k/wasm](https://github.com/JetBrains/compose-multiplatform-core/pull/625)
- [Add missing `getAndIncrement` in `AtomicLong` implementation for web](https://github.com/JetBrains/compose-multiplatform-core/pull/570)
## HTML library
### Features
- [Make HTML `TestUtils` wait functions cancellable](https://github.com/JetBrains/compose-multiplatform/pull/3320)
## Dependencies
This version of Compose Multiplatform is based on the next Jetpack Compose libraries:
- [Compiler 1.5.0](https://developer.android.com/jetpack/androidx/releases/compose-compiler#1.5.0)
- [Runtime 1.5.0-beta03](https://developer.android.com/jetpack/androidx/releases/compose-runtime#1.5.0-beta03)
- [UI 1.5.0-beta03](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.5.0-beta03)
- [Foundation 1.5.0-beta03](https://developer.android.com/jetpack/androidx/releases/compose-foundation#1.5.0-beta03)
- [Material 1.5.0-beta03](https://developer.android.com/jetpack/androidx/releases/compose-material#1.5.0-beta03)
- [Material3 1.1.1](https://developer.android.com/jetpack/androidx/releases/compose-material3#1.1.1)
# 1.4.3 (July 2023)
## Common
### Features
- Support Kotlin 1.8.21, 1.8.22, 1.9.0
## iOS
### Fixes
- [Using Indication as a parameter in extension function doesn't compile on iOS](https://github.com/JetBrains/compose-multiplatform/issues/3086)
- [Compile error when using delegated property with @Composable getters in objects](https://github.com/JetBrains/compose-multiplatform/issues/3216)
- [Using a public property extensions inside a class or object with a @Composable backing delegate fails to link for iOS targets](https://github.com/JetBrains/compose-multiplatform/issues/3084)
## Dependencies
This version of Compose Multiplatform is based on the next Jetpack Compose libraries:
- [Compiler 1.4.4](https://developer.android.com/jetpack/androidx/releases/compose-compiler#1.4.4)
- [Runtime 1.4.3](https://developer.android.com/jetpack/androidx/releases/compose-runtime#1.4.3)
- [UI 1.4.3](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.4.3)
- [Foundation 1.4.3](https://developer.android.com/jetpack/androidx/releases/compose-foundation#1.4.3)
- [Material 1.4.3](https://developer.android.com/jetpack/androidx/releases/compose-material#1.4.3)
- [Material3 1.0.1](https://developer.android.com/jetpack/androidx/releases/compose-material3#1.0.1)
# 1.4.1 (June 2023)
## Common

4
VERSIONING.md

@ -37,7 +37,9 @@ Kotlin version | Minimal Compose version | Notes
1.8.0 | 1.3.0 | 1.3.0 is not supported by earlier k/native versions
1.8.10 | 1.3.1
1.8.20 | 1.4.0
1.8.20 | 1.4.1
1.8.21 | 1.4.3
1.8.22 | 1.4.3
1.9.0 | 1.4.3
### Using the latest Kotlin version

2
ci/compose-uber-jar/gradle.properties

@ -1,2 +1,2 @@
compose.version=1.4.1
compose.version=1.4.3
kotlin.code.style=official

4
ci/templates/desktop-template/gradle.properties

@ -1,4 +1,4 @@
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
kotlin.code.style=official
kotlin.version=1.8.20
compose.version=1.4.1
kotlin.version=1.9.0
compose.version=1.4.3

4
ci/templates/html-library-template/gradle.properties

@ -1,4 +1,4 @@
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
kotlin.code.style=official
kotlin.version=1.8.20
compose.version=1.4.1
kotlin.version=1.9.0
compose.version=1.4.3

4
ci/templates/multiplatform-template/gradle.properties

@ -2,6 +2,6 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
android.useAndroidX=true
android.enableJetifier=true
kotlin.code.style=official
kotlin.version=1.8.20
kotlin.version=1.9.0
agp.version=7.1.3
compose.version=1.4.1
compose.version=1.4.3

2
components/gradle.properties

@ -3,7 +3,7 @@ android.useAndroidX=true
android.enableJetifier=true
kotlin.code.style=official
# __KOTLIN_COMPOSE_VERSION__
kotlin.version=1.9.0
kotlin.version=1.8.22
# __LATEST_COMPOSE_RELEASE_VERSION__
compose.version=1.5.0-dev1112
agp.version=7.3.1

2
components/resources/library/build.gradle.kts

@ -63,7 +63,7 @@ kotlin {
dependsOn(jvmAndAndroidMain)
dependsOn(commonButJSMain)
}
val androidUnitTest by getting {
val androidTest by getting {
dependencies {
}

2
components/resources/library/src/iosMain/kotlin/org/jetbrains/compose/resources/Resource.ios.kt

@ -5,7 +5,6 @@
package org.jetbrains.compose.resources
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.addressOf
import kotlinx.cinterop.usePinned
import platform.Foundation.NSBundle
@ -18,7 +17,6 @@ actual fun resource(path: String): Resource = UIKitResourceImpl(path)
@ExperimentalResourceApi
private class UIKitResourceImpl(path: String) : AbstractResourceImpl(path) {
@OptIn(ExperimentalForeignApi::class)
override suspend fun readBytes(): ByteArray {
val fileManager = NSFileManager.defaultManager()
// todo: support fallback path at bundle root?

2
components/resources/library/src/macosMain/kotlin/org/jetbrains/compose/resources/Resource.macos.kt

@ -5,7 +5,6 @@
package org.jetbrains.compose.resources
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.addressOf
import kotlinx.cinterop.usePinned
import platform.Foundation.NSData
@ -17,7 +16,6 @@ actual fun resource(path: String): Resource = MacOSResourceImpl(path)
@ExperimentalResourceApi
private class MacOSResourceImpl(path: String) : AbstractResourceImpl(path) {
@OptIn(ExperimentalForeignApi::class)
override suspend fun readBytes(): ByteArray {
val currentDirectoryPath = NSFileManager.defaultManager().currentDirectoryPath
val contentsAtPath: NSData? = NSFileManager.defaultManager().run {

6
compose/integrations/composable-test-cases/build.gradle.kts

@ -1,3 +1,4 @@
import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
import org.jetbrains.kotlin.gradle.dsl.KotlinJsCompile
group "com.example"
@ -8,6 +9,7 @@ allprojects {
google()
mavenCentral()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev/") // to test with kotlin dev builds
// mavenLocal()
}
@ -28,6 +30,10 @@ allprojects {
"-Xklib-enable-signature-clash-checks=false",
)
}
tasks.withType<KotlinCompile<*>>().configureEach {
kotlinOptions.freeCompilerArgs += "-Xpartial-linkage=disable"
}
}
disableYarnLockMismatchReport()
}

6
compose/integrations/composable-test-cases/gradle.properties

@ -2,13 +2,13 @@ org.gradle.jvmargs=-Xmx2048M -XX:MaxMetaspaceSize=512m
kotlin.code.style=official
kotlin.native.enableDependencyPropagation=false
android.useAndroidX=true
kotlin.version=1.8.20
kotlin.version=1.9.0
agp.version=7.3.0
compose.version=1.5.0-dev1063
compose.version=1.5.0-beta01
kotlin.native.cacheKind=none
#empty by default - a default version will be used
compose.kotlinCompilerPluginVersion=1.4.2
compose.kotlinCompilerPluginVersion=1.5.0
# default|failingJs - see enum class CasesToRun
tests.casesToRun=default

3
compose/integrations/composable-test-cases/settings.gradle.kts

@ -118,6 +118,9 @@ if (casesToRun.isDefault()) {
module(":testcase-lambdas-lib", "testcases/lambdas/lib")
module(":testcase-lambdas-main", "testcases/lambdas/main")
module(":testcase-expectActual-lib", "testcases/expectActual/lib")
module(":testcase-expectActual-main", "testcases/expectActual/main")
}
/**

39
compose/integrations/composable-test-cases/testcases/expectActual/lib/build.gradle.kts

@ -0,0 +1,39 @@
plugins {
kotlin("multiplatform")
id("org.jetbrains.compose")
}
kotlin {
configureTargets()
sourceSets {
val commonMain by getting {
dependencies {
implementation(compose.runtime)
implementation(getCommonLib())
}
}
val commonTest by getting {
configureCommonTestDependencies()
}
val nativeMain by creating {
dependsOn(commonMain)
}
val iosMain by getting {
dependsOn(nativeMain)
}
val linuxX64Main by getting {
dependsOn(nativeMain)
}
val macosX64Main by getting {
dependsOn(nativeMain)
}
val macosArm64Main by getting {
dependsOn(nativeMain)
}
val mingwX64Main by getting {
dependsOn(nativeMain)
}
}
}

10
compose/integrations/composable-test-cases/testcases/expectActual/lib/src/commonMain/kotlin/Dependencies.kt

@ -0,0 +1,10 @@
import androidx.compose.runtime.Composable
class Abc
val Abc.commonIntVal: Int
@Composable get() = 1000
expect val Abc.composableIntVal: Int
@Composable get

4
compose/integrations/composable-test-cases/testcases/expectActual/lib/src/desktopMain/kotlin/Actuals.kt

@ -0,0 +1,4 @@
import androidx.compose.runtime.Composable
actual val Abc.composableIntVal: Int
@Composable get () = 100

4
compose/integrations/composable-test-cases/testcases/expectActual/lib/src/jsMain/kotlin/Actuals.kt

@ -0,0 +1,4 @@
import androidx.compose.runtime.Composable
actual val Abc.composableIntVal: Int
@Composable get () = 100

4
compose/integrations/composable-test-cases/testcases/expectActual/lib/src/nativeMain/kotlin/Actuals.kt

@ -0,0 +1,4 @@
import androidx.compose.runtime.Composable
actual val Abc.composableIntVal: Int
@Composable get () = 100

21
compose/integrations/composable-test-cases/testcases/expectActual/main/build.gradle.kts

@ -0,0 +1,21 @@
plugins {
kotlin("multiplatform")
id("org.jetbrains.compose")
}
kotlin {
configureTargets()
sourceSets {
val commonMain by getting {
dependencies {
implementation(compose.runtime)
implementation(getCommonLib())
implementation(getLibDependencyForMain())
}
}
val commonTest by getting {
configureCommonTestDependencies()
}
}
}

32
compose/integrations/composable-test-cases/testcases/expectActual/main/src/commonTest/kotlin/Tests.kt

@ -0,0 +1,32 @@
import com.example.common.TextLeafNode
import com.example.common.composeText
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import kotlin.test.Test
import kotlin.test.assertEquals
@OptIn(ExperimentalCoroutinesApi::class)
class Tests {
@Test
// K/JS fails. Related: https://github.com/JetBrains/compose-multiplatform/issues/3373
fun composableExpectActualValGetter() = runTest {
val root = composeText {
val v = Abc().composableIntVal
TextLeafNode("$v")
}
assertEquals("root:{100}", root.dump())
}
@Test
fun commonComposableValGetter() = runTest {
val root = composeText {
val v = Abc().commonIntVal
TextLeafNode("$v")
}
assertEquals("root:{1000}", root.dump())
}
}

29
examples/README.md

@ -1,16 +1,15 @@
# Samples
| Sample | Description | Platforms |
| ------------- | ------------- | ------------- |
| [Imageviewer](imageviewer) | Image Viewer application | Android, iOS, Desktop |
| [Codeviewer](codeviewer) | File browser and code viewer application | Android, iOS, Desktop |
| [Chat](chat) | A simple chat | Android, iOS, Desktop |
| [Minesweeper](minesweeper) | A simple game where you need to find hidden mines | Android, iOS, Desktop |
| [Falling Balls](falling-balls) | A simple game | Android, iOS, Desktop |
| [Visual effects](visual-effects) | Visual effects | Android, iOS, Desktop |
| [Widgets Gallery](widgets-gallery) | Gallery of standard widgets | Android, iOS, Desktop |
| [Todoapp Lite](todoapp-lite) | A simplified version of [Todoapp](todoapp), fully based on Compose | Android, iOS, Desktop |
| [Todoapp](todoapp) | TODO items tracker with persistence and multiple screens, written with external navigation library | Android, iOS native, Desktop |
| [Issues tracker](issues) | GitHub issue tracker with an adaptive UI and ktor-client | Android, Desktop |
| [Notepad](notepad) | Notepad, using the Composable Window API | Desktop |
| [IDEA plugin](intellij-plugin) | Plugin for IDEA using Compose for Desktop | Desktop |
| [HTML based samples](html/README.md) | Examples written with Compose HTML Library
| Sample | Description | Platforms |
| ------------- |----------------------------------------------------------------------------------------------------| ------------- |
| [Imageviewer](imageviewer) | Image Viewer application | Android, iOS, Desktop |
| [Codeviewer](codeviewer) | File browser and code viewer application | Android, iOS, Desktop |
| [Chat](chat) | A simple chat | Android, iOS, Desktop |
| [Minesweeper](minesweeper) | A simple game where you need to find hidden mines | Android, iOS, Desktop |
| [Falling Balls](falling-balls) | A simple game | Android, iOS, Desktop |
| [Visual effects](visual-effects) | Visual effects | Android, iOS, Desktop |
| [Widgets Gallery](widgets-gallery) | Gallery of standard widgets | Android, iOS, Desktop |
| [Todoapp Lite](todoapp-lite) | A simple todo app fully based on Compose | Android, iOS, Desktop |
| [Issues tracker](issues) | GitHub issue tracker with an adaptive UI and ktor-client | Android, Desktop |
| [Notepad](notepad) | Notepad, using the Composable Window API | Desktop |
| [IDEA plugin](intellij-plugin) | Plugin for IDEA using Compose for Desktop | Desktop |
| [HTML based samples](html/README.md) | Examples written with Compose HTML Library |

4
examples/chat/gradle.properties

@ -11,6 +11,6 @@ kotlin.native.useEmbeddableCompilerJar=true
kotlin.mpp.androidSourceSetLayoutVersion=2
# Enable kotlin/native experimental memory model
kotlin.native.binary.memoryModel=experimental
kotlin.version=1.8.20
kotlin.version=1.9.0
agp.version=7.1.3
compose.version=1.4.1
compose.version=1.4.3

4
examples/codeviewer/gradle.properties

@ -11,6 +11,6 @@ kotlin.native.useEmbeddableCompilerJar=true
kotlin.mpp.androidSourceSetLayoutVersion=2
# Enable kotlin/native experimental memory model
kotlin.native.binary.memoryModel=experimental
kotlin.version=1.8.20
kotlin.version=1.9.0
agp.version=7.1.3
compose.version=1.4.1
compose.version=1.4.3

4
examples/falling-balls/gradle.properties

@ -11,6 +11,6 @@ kotlin.native.useEmbeddableCompilerJar=true
kotlin.mpp.androidSourceSetLayoutVersion=2
# Enable kotlin/native experimental memory model
kotlin.native.binary.memoryModel=experimental
kotlin.version=1.8.20
kotlin.version=1.9.0
agp.version=7.1.3
compose.version=1.4.1
compose.version=1.4.3

4
examples/html/compose-bird/gradle.properties

@ -1,3 +1,3 @@
kotlin.code.style=official
kotlin.version=1.8.20
compose.version=1.4.1
kotlin.version=1.9.0
compose.version=1.4.3

4
examples/html/compose-in-js/gradle.properties

@ -2,5 +2,5 @@ kotlin.code.style=official
kotlin.mpp.enableGranularSourceSetsMetadata=true
kotlin.native.enableDependencyPropagation=false
kotlin.js.webpack.major.version=4
kotlin.version=1.8.20
compose.version=1.4.1
kotlin.version=1.9.0
compose.version=1.4.3

4
examples/html/landing/gradle.properties

@ -1,3 +1,3 @@
kotlin.code.style=official
kotlin.version=1.8.20
compose.version=1.4.1
kotlin.version=1.9.0
compose.version=1.4.3

4
examples/html/with-react/gradle.properties

@ -1,3 +1,3 @@
kotlin.code.style=official
kotlin.version=1.8.20
compose.version=1.4.1
kotlin.version=1.9.0
compose.version=1.4.3

4
examples/intellij-plugin/gradle.properties

@ -1,3 +1,3 @@
kotlin.code.style=official
kotlin.version=1.8.20
compose.version=1.4.1
kotlin.version=1.9.0
compose.version=1.4.3

4
examples/issues/gradle.properties

@ -19,6 +19,6 @@ kotlin.code.style=official
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
kotlin.version=1.8.20
kotlin.version=1.9.0
agp.version=7.1.3
compose.version=1.4.1
compose.version=1.4.3

4
examples/minesweeper/gradle.properties

@ -11,6 +11,6 @@ kotlin.native.useEmbeddableCompilerJar=true
kotlin.mpp.androidSourceSetLayoutVersion=2
# Enable kotlin/native experimental memory model
kotlin.native.binary.memoryModel=experimental
kotlin.version=1.8.20
kotlin.version=1.9.0
agp.version=7.1.3
compose.version=1.4.1
compose.version=1.4.3

4
examples/notepad/gradle.properties

@ -1,4 +1,4 @@
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
kotlin.code.style=official
kotlin.version=1.8.20
compose.version=1.4.1
kotlin.version=1.9.0
compose.version=1.4.3

4
examples/todoapp-lite/gradle.properties

@ -11,6 +11,6 @@ kotlin.native.useEmbeddableCompilerJar=true
kotlin.mpp.androidSourceSetLayoutVersion=2
# Enable kotlin/native experimental memory model
kotlin.native.binary.memoryModel=experimental
kotlin.version=1.8.20
kotlin.version=1.9.0
agp.version=7.1.3
compose.version=1.4.1
compose.version=1.4.3

15
examples/todoapp/.gitignore vendored

@ -1,15 +0,0 @@
*.iml
.gradle
/local.properties
/.idea
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
build/
/captures
.externalNativeBuild
.cxx

23
examples/todoapp/.run/browser.run.xml

@ -1,23 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="browser" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<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=":web:jsBrowserDevelopmentRun" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2" />
</configuration>
</component>

23
examples/todoapp/.run/desktop.run.xml

@ -1,23 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="desktop" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<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=":desktop:run" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<method v="2" />
</configuration>
</component>

61
examples/todoapp/README.md

@ -1,61 +0,0 @@
An example of Kotlin Multiplatform todo app with shared Android/Desktop Compose UI and SwiftUI (not Compose) iOS.
This example supports the following targets:
- `Android` (Compose)
- `Desktop/JVM` (Compose)
- `Web/JavaScript` (Compose)
- `iOS` (SwiftUI, not Compose)
Libraries used:
- Compose Multiplatform - shared UI
- [Decompose](https://github.com/arkivanov/Decompose) - navigation and lifecycle
- [MVIKotlin](https://github.com/arkivanov/MVIKotlin) - presentation and business logic
- [Reaktive](https://github.com/badoo/Reaktive) - background processing and data transformation
- [SQLDelight](https://github.com/cashapp/sqldelight) - data storage
There are multiple modules:
- `:common:utils` - just some useful helpers
- `:common:database` - SQLDelight database definition
- `:common:main` - displays a list of todo items and a text field
- `:common:edit` - accepts an item id and allows editing
- `:common:root` - navigates between `main` and `edit` screens
- `:common:compose-ui` - Shared Compose UI for Android and Desktop
- `:android` - Android application
- `:desktop` - Desktop application
- `:web` - Web browser application + Compose HTML Library
- `ios` - iOS Xcode project
The root module is integrated into Android, Desktop and iOS (non-Compose) apps.
Features:
- 99% of the code is shared: data, business logic, presentation, navigation and UI
- View state is preserved when navigating between screens, Android configuration change, etc.
- Model-View-Intent (aka MVI) architectural pattern
- Pluggable UI - Compose UI for Android, Desktop and Web, SwiftUI (not Compose) for iOS
### Running desktop application
* To run, launch command: `./gradlew :desktop:run`
* Or choose **desktop** configuration in IDE and run it.
![desktop-run-configuration.png](screenshots/desktop-run-configuration.png)
#### Building native desktop distribution
```
./gradlew :desktop:packageDistributionForCurrentOS
# outputs are written to desktop/build/compose/binaries
```
### Running Android application
Open project in Intellij IDEA or Android Studio and run "android" configuration.
### Running Web browser application
* To run, launch command: `./gradlew :web:jsBrowserDevelopmentRun`
* Or choose **browser** configuration in IDE and run it.
![browser-run-configuration.png](screenshots/browser-run-configuration.png)
### Running iOS application
Open and build the Xcode project located in `ios` folder.
![Desktop](screenshots/todo.png)

44
examples/todoapp/android/build.gradle.kts

@ -1,44 +0,0 @@
plugins {
id("com.android.application")
kotlin("android")
id("org.jetbrains.compose")
}
android {
compileSdk = 33
defaultConfig {
minSdk = 26
targetSdk = 33
versionCode = 1
versionName = "1.0"
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
packagingOptions {
exclude("META-INF/*")
}
}
dependencies {
implementation(project(":common:database"))
implementation(project(":common:utils"))
implementation(project(":common:root"))
implementation(project(":common:compose-ui"))
implementation(compose.material)
implementation(Deps.ArkIvanov.MVIKotlin.mvikotlin)
implementation(Deps.ArkIvanov.MVIKotlin.mvikotlinMain)
implementation(Deps.ArkIvanov.MVIKotlin.mvikotlinLogging)
implementation(Deps.ArkIvanov.MVIKotlin.mvikotlinTimeTravel)
implementation(Deps.ArkIvanov.Decompose.decompose)
implementation(Deps.ArkIvanov.Decompose.extensionsCompose)
implementation(Deps.AndroidX.AppCompat.appCompat)
implementation(Deps.AndroidX.Activity.activityCompose)
// Workaround for https://github.com/JetBrains/compose-jb/issues/2340
implementation("androidx.compose.material:material:${Deps.JetpackComposeWorkaround.VERSION}")
}

28
examples/todoapp/android/src/main/AndroidManifest.xml

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="example.todo.android">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:name=".App"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
<activity
android:name="example.todo.android.MainActivity"
android:label="@string/app_name"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

13
examples/todoapp/android/src/main/java/example/todo/android/App.kt

@ -1,13 +0,0 @@
package example.todo.android
import android.app.Application
import com.arkivanov.mvikotlin.timetravel.server.TimeTravelServer
class App : Application() {
override fun onCreate() {
super.onCreate()
TimeTravelServer().start()
}
}

8
examples/todoapp/android/src/main/java/example/todo/android/Color.kt

@ -1,8 +0,0 @@
package example.todo.android
import androidx.compose.ui.graphics.Color
val purple200 = Color(0xFFBB86FC)
val purple500 = Color(0xFF6200EE)
val purple700 = Color(0xFF3700B3)
val teal200 = Color(0xFF03DAC5)

39
examples/todoapp/android/src/main/java/example/todo/android/MainActivity.kt

@ -1,39 +0,0 @@
package example.todo.android
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.defaultComponentContext
import com.arkivanov.mvikotlin.logging.store.LoggingStoreFactory
import com.arkivanov.mvikotlin.timetravel.store.TimeTravelStoreFactory
import example.todo.common.database.DefaultTodoSharedDatabase
import example.todo.common.database.TodoDatabaseDriver
import example.todo.common.root.TodoRoot
import example.todo.common.root.integration.TodoRootComponent
import example.todo.common.ui.TodoRootContent
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val root = todoRoot(defaultComponentContext())
setContent {
ComposeAppTheme {
Surface(color = MaterialTheme.colors.background) {
TodoRootContent(root)
}
}
}
}
private fun todoRoot(componentContext: ComponentContext): TodoRoot =
TodoRootComponent(
componentContext = componentContext,
storeFactory = LoggingStoreFactory(TimeTravelStoreFactory()),
database = DefaultTodoSharedDatabase(TodoDatabaseDriver(context = this))
)
}

11
examples/todoapp/android/src/main/java/example/todo/android/Shape.kt

@ -1,11 +0,0 @@
package example.todo.android
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)
)

35
examples/todoapp/android/src/main/java/example/todo/android/Theme.kt

@ -1,35 +0,0 @@
package example.todo.android
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material.MaterialTheme
import androidx.compose.material.darkColors
import androidx.compose.material.lightColors
import androidx.compose.runtime.Composable
private val DarkColorPalette = darkColors(
primary = purple200,
primaryVariant = purple700,
secondary = teal200
)
private val LightColorPalette = lightColors(
primary = purple500,
primaryVariant = purple700,
secondary = teal200
)
@Composable
fun ComposeAppTheme(darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable() () -> Unit) {
val colors = if (darkTheme) {
DarkColorPalette
} else {
LightColorPalette
}
MaterialTheme(
colors = colors,
typography = typography,
shapes = shapes,
content = content
)
}

16
examples/todoapp/android/src/main/java/example/todo/android/Type.kt

@ -1,16 +0,0 @@
package example.todo.android
import androidx.compose.material.Typography
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
// Set of Material typography styles to start with
val typography = Typography(
body1 = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 16.sp
)
)

34
examples/todoapp/android/src/main/res/drawable-v24/ic_launcher_foreground.xml

@ -1,34 +0,0 @@
<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:fillType="evenOdd"
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
android:strokeWidth="1"
android:strokeColor="#00000000">
<aapt:attr name="android:fillColor">
<gradient
android:endX="78.5885"
android:endY="90.9159"
android:startX="48.7653"
android:startY="61.0927"
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="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

170
examples/todoapp/android/src/main/res/drawable/ic_launcher_background.xml

@ -1,170 +0,0 @@
<?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="#008577"
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>

5
examples/todoapp/android/src/main/res/mipmap-anydpi-v26/ic_launcher.xml

@ -1,5 +0,0 @@
<?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>

5
examples/todoapp/android/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml

@ -1,5 +0,0 @@
<?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>

BIN
examples/todoapp/android/src/main/res/mipmap-hdpi/ic_launcher.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

BIN
examples/todoapp/android/src/main/res/mipmap-hdpi/ic_launcher_round.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

BIN
examples/todoapp/android/src/main/res/mipmap-mdpi/ic_launcher.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

BIN
examples/todoapp/android/src/main/res/mipmap-mdpi/ic_launcher_round.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

BIN
examples/todoapp/android/src/main/res/mipmap-xhdpi/ic_launcher.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

BIN
examples/todoapp/android/src/main/res/mipmap-xhdpi/ic_launcher_round.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

BIN
examples/todoapp/android/src/main/res/mipmap-xxhdpi/ic_launcher.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

BIN
examples/todoapp/android/src/main/res/mipmap-xxhdpi/ic_launcher_round.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

BIN
examples/todoapp/android/src/main/res/mipmap-xxxhdpi/ic_launcher.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

BIN
examples/todoapp/android/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

4
examples/todoapp/android/src/main/res/values/strings.xml

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Todo</string>
</resources>

19
examples/todoapp/build.gradle.kts

@ -1,19 +0,0 @@
plugins {
`kotlin-dsl`
}
allprojects {
repositories {
google()
mavenCentral()
mavenLocal()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
}
afterEvaluate {
// Workaround for https://youtrack.jetbrains.com/issue/KT-52776
rootProject.extensions.findByType<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension>()?.apply {
versions.webpackCli.version = "4.10.0"
}
}
}

24
examples/todoapp/buildSrc/build.gradle.kts

@ -1,24 +0,0 @@
plugins {
`kotlin-dsl`
}
initDeps(project)
repositories {
mavenLocal()
google()
mavenCentral()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
}
dependencies {
implementation(Deps.JetBrains.Compose.gradlePlugin)
implementation(Deps.JetBrains.Kotlin.gradlePlugin)
implementation(Deps.Android.Tools.Build.gradlePlugin)
implementation(Deps.Squareup.SQLDelight.gradlePlugin)
}
kotlin {
// Add Deps to compilation, so it will become available in main project
sourceSets.getByName("main").kotlin.srcDir("buildSrc/src/main/kotlin")
}

12
examples/todoapp/buildSrc/buildSrc/build.gradle.kts

@ -1,12 +0,0 @@
plugins {
`kotlin-dsl`
}
repositories {
mavenCentral()
}
dependencies {
//todo workaround to build iOS Arm64 simulator:
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10")
}

101
examples/todoapp/buildSrc/buildSrc/src/main/kotlin/Deps.kt

@ -1,101 +0,0 @@
// We store Kotlin and Compose versions in gradle.properties to
// be able to override them on CI.
// You probably won't need this, so you can get rid of `project` in this file.
import org.gradle.api.Project
lateinit var properties: Map<String, *>
fun initDeps(project: Project) {
properties = project.properties
}
object Deps {
object JetpackComposeWorkaround {
// Workaround for https://github.com/JetBrains/compose-jb/issues/2340
val VERSION: String = "1.4.0-rc01"
}
object JetBrains {
object Kotlin {
private val VERSION get() = properties["kotlin.version"]
val gradlePlugin get() = "org.jetbrains.kotlin:kotlin-gradle-plugin:$VERSION"
val testCommon get() = "org.jetbrains.kotlin:kotlin-test-common:$VERSION"
val testJunit get() = "org.jetbrains.kotlin:kotlin-test-junit:$VERSION"
val testJs get() = "org.jetbrains.kotlin:kotlin-test-js:$VERSION"
val testAnnotationsCommon get() = "org.jetbrains.kotlin:kotlin-test-annotations-common:$VERSION"
}
object Coroutines {
private val VERSION get() = "1.6.4"
val swing get() = "org.jetbrains.kotlinx:kotlinx-coroutines-swing:$VERSION"
}
object Compose {
private val VERSION get() = properties["compose.version"]
val gradlePlugin get() = "org.jetbrains.compose:compose-gradle-plugin:$VERSION"
}
}
object Android {
object Tools {
object Build {
const val gradlePlugin = "com.android.tools.build:gradle:7.2.0"
}
}
}
object AndroidX {
object AppCompat {
const val appCompat = "androidx.appcompat:appcompat:1.3.0"
}
object Activity {
const val activityCompose = "androidx.activity:activity-compose:1.3.0"
}
}
object ArkIvanov {
object MVIKotlin {
private const val VERSION = "3.0.0"
const val rx = "com.arkivanov.mvikotlin:rx:$VERSION"
const val mvikotlin = "com.arkivanov.mvikotlin:mvikotlin:$VERSION"
const val mvikotlinMain = "com.arkivanov.mvikotlin:mvikotlin-main:$VERSION"
const val mvikotlinLogging = "com.arkivanov.mvikotlin:mvikotlin-logging:$VERSION"
const val mvikotlinTimeTravel = "com.arkivanov.mvikotlin:mvikotlin-timetravel:$VERSION"
const val mvikotlinExtensionsReaktive = "com.arkivanov.mvikotlin:mvikotlin-extensions-reaktive:$VERSION"
}
object Decompose {
private const val VERSION = "1.0.0-alpha-05"
const val decompose = "com.arkivanov.decompose:decompose:$VERSION"
const val extensionsCompose = "com.arkivanov.decompose:extensions-compose-jetbrains:$VERSION"
}
object Essenty {
private const val VERSION = "0.6.0"
const val lifecycle = "com.arkivanov.essenty:lifecycle:$VERSION"
}
}
object Badoo {
object Reaktive {
private const val VERSION = "1.2.1"
const val reaktive = "com.badoo.reaktive:reaktive:$VERSION"
const val reaktiveTesting = "com.badoo.reaktive:reaktive-testing:$VERSION"
const val utils = "com.badoo.reaktive:utils:$VERSION"
const val coroutinesInterop = "com.badoo.reaktive:coroutines-interop:$VERSION"
}
}
object Squareup {
object SQLDelight {
private const val VERSION = "1.5.5"
const val gradlePlugin = "com.squareup.sqldelight:gradle-plugin:$VERSION"
const val androidDriver = "com.squareup.sqldelight:android-driver:$VERSION"
const val sqliteDriver = "com.squareup.sqldelight:sqlite-driver:$VERSION"
const val nativeDriver = "com.squareup.sqldelight:native-driver:$VERSION"
const val sqljsDriver = "com.squareup.sqldelight:sqljs-driver:$VERSION"
}
}
}

17
examples/todoapp/buildSrc/buildSrc/src/main/kotlin/IosWorkaroundSupportArm64Simulator.kt

@ -1,17 +0,0 @@
import org.jetbrains.kotlin.gradle.dsl.KotlinTargetContainerWithNativeShortcuts
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
fun KotlinTargetContainerWithNativeShortcuts.iosWorkaroundSupportArm64Simulator(
configure: KotlinNativeTarget.() -> Unit
) {
val isBuildToSimulator = System.getenv("SDK_NAME")?.startsWith("iphonesimulator") ?: false
val isArm64Target = System.getenv("NATIVE_ARCH") == "arm64"
if (isBuildToSimulator && isArm64Target) {
//workaround:
iosSimulatorArm64(name = "ios", configure = configure)
} else {
//default behavior:
ios(configure = configure)
}
}

3
examples/todoapp/buildSrc/gradle.properties

@ -1,3 +0,0 @@
# TODO can we get rid of duplication with root gradle.properties?
kotlin.version=1.8.20
compose.version=1.4.0

26
examples/todoapp/buildSrc/src/main/kotlin/android-setup.gradle.kts

@ -1,26 +0,0 @@
plugins {
id("com.android.library")
}
initDeps(project)
android {
compileSdk = 33
defaultConfig {
minSdk = 23
targetSdk = 33
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
sourceSets {
named("main") {
manifest.srcFile("src/androidMain/AndroidManifest.xml")
res.srcDirs("src/androidMain/res")
}
}
}

39
examples/todoapp/buildSrc/src/main/kotlin/multiplatform-compose-setup.gradle.kts

@ -1,39 +0,0 @@
plugins {
id("com.android.library")
id("kotlin-multiplatform")
id("org.jetbrains.compose")
}
initDeps(project)
kotlin {
jvm("desktop")
android()
sourceSets {
named("commonMain") {
dependencies {
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material)
}
}
named("androidMain") {
dependencies {
implementation("androidx.appcompat:appcompat:1.3.0")
implementation("androidx.core:core-ktx:1.3.1")
}
}
named("desktopMain") {
dependencies {
implementation(compose.desktop.common)
}
}
}
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions.jvmTarget = "11"
}
}

75
examples/todoapp/buildSrc/src/main/kotlin/multiplatform-setup.gradle.kts

@ -1,75 +0,0 @@
plugins {
id("com.android.library")
id("kotlin-multiplatform")
}
initDeps(project)
kotlin {
jvm("desktop")
android()
iosX64()
iosArm64()
iosSimulatorArm64()
js(IR) {
browser()
}
sourceSets {
create("iosMain") {
dependsOn(getByName("commonMain"))
}
create("iosTest") {
dependsOn(getByName("commonTest"))
}
getByName("iosX64Main") {
dependsOn(getByName("iosMain"))
}
getByName("iosX64Test") {
dependsOn(getByName("iosTest"))
}
getByName("iosArm64Main") {
dependsOn(getByName("iosMain"))
}
getByName("iosArm64Test") {
dependsOn(getByName("iosTest"))
}
getByName("iosSimulatorArm64Main") {
dependsOn(getByName("iosMain"))
}
getByName("iosSimulatorArm64Test") {
dependsOn(getByName("iosTest"))
}
named("commonTest") {
dependencies {
implementation(Deps.JetBrains.Kotlin.testCommon)
implementation(Deps.JetBrains.Kotlin.testAnnotationsCommon)
}
}
named("androidTest") {
dependencies {
implementation(Deps.JetBrains.Kotlin.testJunit)
}
}
named("desktopTest") {
dependencies {
implementation(Deps.JetBrains.Kotlin.testJunit)
}
}
named("jsTest") {
dependencies {
implementation(Deps.JetBrains.Kotlin.testJs)
}
}
}
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions.jvmTarget = "11"
}
}

25
examples/todoapp/common/compose-ui/build.gradle.kts

@ -1,25 +0,0 @@
plugins {
id("multiplatform-compose-setup")
id("android-setup")
}
kotlin {
sourceSets {
named("commonMain") {
dependencies {
implementation(project(":common:main"))
implementation(project(":common:edit"))
implementation(project(":common:root"))
implementation(Deps.ArkIvanov.Decompose.decompose)
implementation(Deps.ArkIvanov.Decompose.extensionsCompose)
}
}
named("androidMain") {
dependencies {
// Workaround for https://github.com/JetBrains/compose-jb/issues/2340
implementation("androidx.compose.foundation:foundation:${Deps.JetpackComposeWorkaround.VERSION}")
}
}
}
}

2
examples/todoapp/common/compose-ui/src/androidMain/AndroidManifest.xml

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="example.todo.common.ui"/>

26
examples/todoapp/common/compose-ui/src/androidMain/kotlin/example/todo/common/ui/Scrollbars.kt

@ -1,26 +0,0 @@
package example.todo.common.ui
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
actual val MARGIN_SCROLLBAR: Dp = 0.dp
actual interface ScrollbarAdapter
@Composable
actual fun rememberScrollbarAdapter(
scrollState: LazyListState,
itemCount: Int,
averageItemSize: Dp
): ScrollbarAdapter =
object : ScrollbarAdapter {}
@Composable
actual fun VerticalScrollbar(
modifier: Modifier,
adapter: ScrollbarAdapter
) {
}

23
examples/todoapp/common/compose-ui/src/commonMain/kotlin/example/todo/common/ui/Scrollbars.kt

@ -1,23 +0,0 @@
package example.todo.common.ui
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp
expect val MARGIN_SCROLLBAR: Dp
expect interface ScrollbarAdapter
@Composable
expect fun rememberScrollbarAdapter(
scrollState: LazyListState,
itemCount: Int,
averageItemSize: Dp
): ScrollbarAdapter
@Composable
expect fun VerticalScrollbar(
modifier: Modifier,
adapter: ScrollbarAdapter
)

15
examples/todoapp/common/compose-ui/src/commonMain/kotlin/example/todo/common/ui/ShortcutHandler.kt

@ -1,15 +0,0 @@
package example.todo.common.ui
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.KeyEvent
import androidx.compose.ui.input.key.key
fun onKeyUp(key: Key, onEvent: () -> Unit): (KeyEvent) -> Boolean =
{ keyEvent ->
if (keyEvent.key == key) {
onEvent()
true
} else {
false
}
}

60
examples/todoapp/common/compose-ui/src/commonMain/kotlin/example/todo/common/ui/TodoEditUi.kt

@ -1,60 +0,0 @@
package example.todo.common.ui
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material.Checkbox
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.material.TopAppBar
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.arkivanov.decompose.extensions.compose.jetbrains.subscribeAsState
import example.todo.common.edit.TodoEdit
@Composable
fun TodoEditContent(component: TodoEdit) {
val model by component.models.subscribeAsState()
Column(horizontalAlignment = Alignment.CenterHorizontally) {
TopAppBar(
title = { Text("Edit todo") },
navigationIcon = {
IconButton(onClick = component::onCloseClicked) {
Icon(
imageVector = Icons.Default.ArrowBack,
contentDescription = null
)
}
}
)
TextField(
value = model.text,
modifier = Modifier.weight(1F).fillMaxWidth().padding(8.dp),
label = { Text("Todo text") },
onValueChange = component::onTextChanged
)
Row(modifier = Modifier.padding(8.dp), verticalAlignment = Alignment.CenterVertically) {
Text(text = "Completed")
Spacer(modifier = Modifier.width(8.dp))
Checkbox(
checked = model.isDone,
onCheckedChange = component::onDoneChanged
)
}
}
}

158
examples/todoapp/common/compose-ui/src/commonMain/kotlin/example/todo/common/ui/TodoMainUi.kt

@ -1,158 +0,0 @@
package example.todo.common.ui
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.Checkbox
import androidx.compose.material.Divider
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.OutlinedTextField
import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Delete
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.onKeyEvent
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import com.arkivanov.decompose.extensions.compose.jetbrains.subscribeAsState
import example.todo.common.main.TodoItem
import example.todo.common.main.TodoMain
@Composable
fun TodoMainContent(component: TodoMain) {
val model by component.models.subscribeAsState()
Column {
TopAppBar(title = { Text(text = "Todo List") })
Box(Modifier.weight(1F)) {
TodoList(
items = model.items,
onItemClicked = component::onItemClicked,
onDoneChanged = component::onItemDoneChanged,
onDeleteItemClicked = component::onItemDeleteClicked
)
}
TodoInput(
text = model.text,
onAddClicked = component::onAddItemClicked,
onTextChanged = component::onInputTextChanged
)
}
}
@Composable
private fun TodoList(
items: List<TodoItem>,
onItemClicked: (id: Long) -> Unit,
onDoneChanged: (id: Long, isDone: Boolean) -> Unit,
onDeleteItemClicked: (id: Long) -> Unit
) {
Box {
val listState = rememberLazyListState()
LazyColumn(state = listState) {
items(items) {
Item(
item = it,
onItemClicked = onItemClicked,
onDoneChanged = onDoneChanged,
onDeleteItemClicked = onDeleteItemClicked
)
Divider()
}
}
VerticalScrollbar(
modifier = Modifier.align(Alignment.CenterEnd).fillMaxHeight(),
adapter = rememberScrollbarAdapter(
scrollState = listState,
itemCount = items.size,
averageItemSize = 37.dp
)
)
}
}
@Composable
private fun Item(
item: TodoItem,
onItemClicked: (id: Long) -> Unit,
onDoneChanged: (id: Long, isDone: Boolean) -> Unit,
onDeleteItemClicked: (id: Long) -> Unit
) {
Row(modifier = Modifier.clickable(onClick = { onItemClicked(item.id) })) {
Spacer(modifier = Modifier.width(8.dp))
Checkbox(
checked = item.isDone,
modifier = Modifier.align(Alignment.CenterVertically),
onCheckedChange = { onDoneChanged(item.id, it) }
)
Spacer(modifier = Modifier.width(8.dp))
Text(
text = AnnotatedString(item.text),
modifier = Modifier.weight(1F).align(Alignment.CenterVertically),
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
Spacer(modifier = Modifier.width(8.dp))
IconButton(onClick = { onDeleteItemClicked(item.id) }) {
Icon(
imageVector = Icons.Default.Delete,
contentDescription = null
)
}
Spacer(modifier = Modifier.width(MARGIN_SCROLLBAR))
}
}
@OptIn(ExperimentalComposeUiApi::class)
@Composable
private fun TodoInput(
text: String,
onTextChanged: (String) -> Unit,
onAddClicked: () -> Unit
) {
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(8.dp)) {
OutlinedTextField(
value = text,
modifier = Modifier.weight(weight = 1F).onKeyEvent(onKeyUp(Key.Enter, onAddClicked)),
onValueChange = onTextChanged,
label = { Text(text = "Add a todo") }
)
Spacer(modifier = Modifier.width(8.dp))
IconButton(onClick = onAddClicked) {
Icon(
imageVector = Icons.Default.Add,
contentDescription = null
)
}
}
}

25
examples/todoapp/common/compose-ui/src/commonMain/kotlin/example/todo/common/ui/TodoRootUi.kt

@ -1,25 +0,0 @@
@file:Suppress("EXPERIMENTAL_API_USAGE")
package example.todo.common.ui
import androidx.compose.runtime.Composable
import com.arkivanov.decompose.extensions.compose.jetbrains.stack.Children
import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.fade
import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.plus
import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.scale
import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.stackAnimation
import example.todo.common.root.TodoRoot
import example.todo.common.root.TodoRoot.Child
@Composable
fun TodoRootContent(component: TodoRoot) {
Children(
stack = component.childStack,
animation = stackAnimation(fade() + scale()),
) {
when (val child = it.instance) {
is Child.Main -> TodoMainContent(child.component)
is Child.Edit -> TodoEditContent(child.component)
}
}
}

34
examples/todoapp/common/compose-ui/src/desktopMain/kotlin/example/todo/common/ui/Scrollbars.kt

@ -1,34 +0,0 @@
package example.todo.common.ui
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
actual val MARGIN_SCROLLBAR: Dp = 8.dp
actual typealias ScrollbarAdapter = androidx.compose.foundation.v2.ScrollbarAdapter
@OptIn(ExperimentalFoundationApi::class)
@Composable
actual fun rememberScrollbarAdapter(
scrollState: LazyListState,
itemCount: Int,
averageItemSize: Dp
): ScrollbarAdapter =
androidx.compose.foundation.rememberScrollbarAdapter(
scrollState = scrollState
)
@Composable
actual fun VerticalScrollbar(
modifier: Modifier,
adapter: ScrollbarAdapter
) {
androidx.compose.foundation.VerticalScrollbar(
modifier = modifier,
adapter = adapter
)
}

28
examples/todoapp/common/compose-ui/src/desktopMain/kotlin/example/todo/common/ui/TodoEditPreview.kt

@ -1,28 +0,0 @@
package example.todo.common.ui
import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.runtime.Composable
import com.arkivanov.decompose.value.MutableValue
import com.arkivanov.decompose.value.Value
import example.todo.common.edit.TodoEdit
import example.todo.common.edit.TodoEdit.Model
@Composable
@Preview
fun TodoEditContentPreview() {
TodoEditContent(TodoEditPreview())
}
class TodoEditPreview : TodoEdit {
override val models: Value<Model> =
MutableValue(
Model(
text = "Some text",
isDone = true
)
)
override fun onTextChanged(text: String) {}
override fun onDoneChanged(isDone: Boolean) {}
override fun onCloseClicked() {}
}

37
examples/todoapp/common/compose-ui/src/desktopMain/kotlin/example/todo/common/ui/TodoMainPreview.kt

@ -1,37 +0,0 @@
package example.todo.common.ui
import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.runtime.Composable
import com.arkivanov.decompose.value.MutableValue
import com.arkivanov.decompose.value.Value
import example.todo.common.main.TodoItem
import example.todo.common.main.TodoMain
import example.todo.common.main.TodoMain.Model
@Preview
@Composable
fun TodoMainContentPreview() {
TodoMainContent(TodoMainPreview())
}
class TodoMainPreview : TodoMain {
override val models: Value<Model> =
MutableValue(
Model(
items = List(5) { index ->
TodoItem(
id = index.toLong(),
text = "Item $index",
isDone = index % 2 == 0
)
},
text = "Some text"
)
)
override fun onItemClicked(id: Long) {}
override fun onItemDoneChanged(id: Long, isDone: Boolean) {}
override fun onItemDeleteClicked(id: Long) {}
override fun onInputTextChanged(text: String) {}
override fun onAddItemClicked() {}
}

46
examples/todoapp/common/database/build.gradle.kts

@ -1,46 +0,0 @@
plugins {
id("multiplatform-setup")
id("android-setup")
id("com.squareup.sqldelight")
}
sqldelight {
database("TodoDatabase") {
packageName = "example.todo.database"
}
}
kotlin {
sourceSets {
commonMain {
dependencies {
implementation(Deps.Badoo.Reaktive.reaktive)
}
}
androidMain {
dependencies {
implementation(Deps.Squareup.SQLDelight.androidDriver)
implementation(Deps.Squareup.SQLDelight.sqliteDriver)
}
}
desktopMain {
dependencies {
implementation(Deps.Squareup.SQLDelight.sqliteDriver)
}
}
iosMain {
dependencies {
implementation(Deps.Squareup.SQLDelight.nativeDriver)
}
}
jsMain {
dependencies {
implementation(Deps.Squareup.SQLDelight.sqljsDriver)
}
}
}
}

2
examples/todoapp/common/database/src/androidMain/AndroidManifest.xml

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="example.todo.common.database"/>

14
examples/todoapp/common/database/src/androidMain/kotlin/example/todo/common/database/TodoDatabaseDriverFactory.kt

@ -1,14 +0,0 @@
package example.todo.common.database
import android.content.Context
import com.squareup.sqldelight.android.AndroidSqliteDriver
import com.squareup.sqldelight.db.SqlDriver
import example.todo.database.TodoDatabase
@Suppress("FunctionName") // FactoryFunction
fun TodoDatabaseDriver(context: Context): SqlDriver =
AndroidSqliteDriver(
schema = TodoDatabase.Schema,
context = context,
name = "TodoDatabase.db"
)

91
examples/todoapp/common/database/src/commonMain/kotlin/example/todo/common/database/DefaultTodoSharedDatabase.kt

@ -1,91 +0,0 @@
package example.todo.common.database
import com.badoo.reaktive.base.setCancellable
import com.badoo.reaktive.completable.Completable
import com.badoo.reaktive.maybe.Maybe
import com.badoo.reaktive.observable.Observable
import com.badoo.reaktive.observable.autoConnect
import com.badoo.reaktive.observable.firstOrError
import com.badoo.reaktive.observable.map
import com.badoo.reaktive.observable.observable
import com.badoo.reaktive.observable.observeOn
import com.badoo.reaktive.observable.replay
import com.badoo.reaktive.scheduler.ioScheduler
import com.badoo.reaktive.single.Single
import com.badoo.reaktive.single.asCompletable
import com.badoo.reaktive.single.asObservable
import com.badoo.reaktive.single.doOnBeforeSuccess
import com.badoo.reaktive.single.flatMapObservable
import com.badoo.reaktive.single.map
import com.badoo.reaktive.single.mapNotNull
import com.badoo.reaktive.single.observeOn
import com.badoo.reaktive.single.singleOf
import com.squareup.sqldelight.Query
import com.squareup.sqldelight.db.SqlDriver
import example.todo.database.TodoDatabase
class DefaultTodoSharedDatabase(driver: Single<SqlDriver>) : TodoSharedDatabase {
constructor(driver: SqlDriver) : this(singleOf(driver))
private val queries: Single<TodoDatabaseQueries> =
driver
.map { TodoDatabase(it).todoDatabaseQueries }
.asObservable()
.replay()
.autoConnect()
.firstOrError()
override fun observeAll(): Observable<List<TodoItemEntity>> =
query(TodoDatabaseQueries::selectAll)
.observe { it.executeAsList() }
override fun select(id: Long): Maybe<TodoItemEntity> =
query { it.select(id = id) }
.mapNotNull { it.executeAsOneOrNull() }
override fun add(text: String): Completable =
execute { it.add(text = text) }
override fun setText(id: Long, text: String): Completable =
execute { it.setText(id = id, text = text) }
override fun setDone(id: Long, isDone: Boolean): Completable =
execute { it.setDone(id = id, isDone = isDone) }
override fun delete(id: Long): Completable =
execute { it.delete(id = id) }
override fun clear(): Completable =
execute { it.clear() }
private fun <T : Any> query(query: (TodoDatabaseQueries) -> Query<T>): Single<Query<T>> =
queries
.observeOn(ioScheduler)
.map(query)
private fun execute(query: (TodoDatabaseQueries) -> Unit): Completable =
queries
.observeOn(ioScheduler)
.doOnBeforeSuccess(query)
.asCompletable()
private fun <T : Any, R> Single<Query<T>>.observe(get: (Query<T>) -> R): Observable<R> =
flatMapObservable { it.observed() }
.observeOn(ioScheduler)
.map(get)
private fun <T : Any> Query<T>.observed(): Observable<Query<T>> =
observable { emitter ->
val listener =
object : Query.Listener {
override fun queryResultsChanged() {
emitter.onNext(this@observed)
}
}
emitter.onNext(this@observed)
addListener(listener)
emitter.setCancellable { removeListener(listener) }
}
}

105
examples/todoapp/common/database/src/commonMain/kotlin/example/todo/common/database/TestTodoSharedDatabase.kt

@ -1,105 +0,0 @@
package example.todo.common.database
import com.badoo.reaktive.base.invoke
import com.badoo.reaktive.completable.Completable
import com.badoo.reaktive.completable.completableFromFunction
import com.badoo.reaktive.completable.observeOn
import com.badoo.reaktive.maybe.Maybe
import com.badoo.reaktive.maybe.observeOn
import com.badoo.reaktive.observable.Observable
import com.badoo.reaktive.observable.map
import com.badoo.reaktive.observable.observeOn
import com.badoo.reaktive.scheduler.Scheduler
import com.badoo.reaktive.single.notNull
import com.badoo.reaktive.single.singleFromFunction
import com.badoo.reaktive.subject.behavior.BehaviorSubject
// There were problems when using real database in JS tests, hence the in-memory test implementation
class TestTodoSharedDatabase(
private val scheduler: Scheduler
) : TodoSharedDatabase {
private val itemsSubject = BehaviorSubject<Map<Long, TodoItemEntity>>(emptyMap())
private val itemsObservable = itemsSubject.observeOn(scheduler)
val testing: Testing = Testing()
override fun observeAll(): Observable<List<TodoItemEntity>> =
itemsObservable.map { it.values.toList() }
override fun select(id: Long): Maybe<TodoItemEntity> =
singleFromFunction { testing.select(id = id) }
.notNull()
.observeOn(scheduler)
override fun add(text: String): Completable =
execute { testing.add(text = text) }
override fun setText(id: Long, text: String): Completable =
execute { testing.setText(id = id, text = text) }
override fun setDone(id: Long, isDone: Boolean): Completable =
execute { testing.setDone(id = id, isDone = isDone) }
override fun delete(id: Long): Completable =
execute { testing.delete(id = id) }
override fun clear(): Completable =
execute { testing.clear() }
private fun execute(block: () -> Unit): Completable =
completableFromFunction(block)
.observeOn(scheduler)
inner class Testing {
fun select(id: Long): TodoItemEntity? =
itemsSubject.value[id]
fun selectRequired(id: Long): TodoItemEntity =
requireNotNull(select(id = id))
fun add(text: String) {
updateItems { items ->
val nextId = items.keys.maxOrNull()?.plus(1L) ?: 1L
val item =
TodoItemEntity(
id = nextId,
orderNum = items.size.toLong(),
text = text,
isDone = false
)
items + (nextId to item)
}
}
fun setText(id: Long, text: String) {
updateItem(id = id) { it.copy(text = text) }
}
fun setDone(id: Long, isDone: Boolean) {
updateItem(id = id) { it.copy(isDone = isDone) }
}
fun delete(id: Long) {
updateItems { it - id }
}
fun clear() {
updateItems { emptyMap() }
}
fun getLastInsertId(): Long? =
itemsSubject.value.values.lastOrNull()?.id
private fun updateItems(func: (Map<Long, TodoItemEntity>) -> Map<Long, TodoItemEntity>) {
itemsSubject(func(itemsSubject.value))
}
private fun updateItem(id: Long, func: (TodoItemEntity) -> TodoItemEntity) {
updateItems {
it + (id to it.getValue(id).let(func))
}
}
}
}

22
examples/todoapp/common/database/src/commonMain/kotlin/example/todo/common/database/TodoSharedDatabase.kt

@ -1,22 +0,0 @@
package example.todo.common.database
import com.badoo.reaktive.completable.Completable
import com.badoo.reaktive.maybe.Maybe
import com.badoo.reaktive.observable.Observable
interface TodoSharedDatabase {
fun observeAll(): Observable<List<TodoItemEntity>>
fun select(id: Long): Maybe<TodoItemEntity>
fun add(text: String): Completable
fun setText(id: Long, text: String): Completable
fun setDone(id: Long, isDone: Boolean): Completable
fun delete(id: Long): Completable
fun clear(): Completable
}

39
examples/todoapp/common/database/src/commonMain/sqldelight/example/todo/common/database/TodoDatabase.sq

@ -1,39 +0,0 @@
CREATE TABLE IF NOT EXISTS TodoItemEntity (
id INTEGER PRIMARY KEY AUTOINCREMENT,
orderNum INTEGER NOT NULL,
text TEXT NOT NULL,
isDone INTEGER AS Boolean NOT NULL DEFAULT 0
);
selectAll:
SELECT *
FROM TodoItemEntity;
select:
SELECT *
FROM TodoItemEntity
WHERE id = :id;
add:
INSERT INTO TodoItemEntity (orderNum, text)
VALUES ((CASE (SELECT COUNT(*) FROM TodoItemEntity) WHEN 0 THEN 1 ELSE (SELECT MAX(orderNum)+1 FROM TodoItemEntity) END), :text);
setText:
UPDATE TodoItemEntity
SET text = :text
WHERE id = :id;
setDone:
UPDATE TodoItemEntity
SET isDone = :isDone
WHERE id = :id;
delete:
DELETE FROM TodoItemEntity
WHERE id = :id;
getLastInsertId:
SELECT last_insert_rowid();
clear:
DELETE FROM TodoItemEntity;

15
examples/todoapp/common/database/src/desktopMain/kotlin/example/todo/common/database/TodoDatabaseDriverFactory.kt

@ -1,15 +0,0 @@
package example.todo.common.database
import com.squareup.sqldelight.db.SqlDriver
import com.squareup.sqldelight.sqlite.driver.JdbcSqliteDriver
import example.todo.database.TodoDatabase
import java.io.File
@Suppress("FunctionName") // FactoryFunction
fun TodoDatabaseDriver(): SqlDriver {
val databasePath = File(System.getProperty("java.io.tmpdir"), "ComposeTodoDatabase.db")
val driver = JdbcSqliteDriver(url = "jdbc:sqlite:${databasePath.absolutePath}")
TodoDatabase.Schema.create(driver)
return driver
}

9
examples/todoapp/common/database/src/iosMain/kotlin/example/todo/common/database/TodoDatabaseDriverFactory.kt

@ -1,9 +0,0 @@
package example.todo.common.database
import com.squareup.sqldelight.db.SqlDriver
import com.squareup.sqldelight.drivers.native.NativeSqliteDriver
import example.todo.database.TodoDatabase
@Suppress("FunctionName") // Factory function
fun TodoDatabaseDriver(): SqlDriver =
NativeSqliteDriver(TodoDatabase.Schema, "TodoDatabase.db")

10
examples/todoapp/common/database/src/jsMain/kotlin/example/todo/common/database/TodoDatabaseDriverFactory.kt

@ -1,10 +0,0 @@
package example.todo.common.database
import com.badoo.reaktive.promise.asSingle
import com.badoo.reaktive.single.Single
import com.squareup.sqldelight.db.SqlDriver
import com.squareup.sqldelight.drivers.sqljs.initSqlDriver
import example.todo.database.TodoDatabase
fun todoDatabaseDriver(): Single<SqlDriver> =
initSqlDriver(TodoDatabase.Schema).asSingle()

19
examples/todoapp/common/edit/build.gradle.kts

@ -1,19 +0,0 @@
plugins {
id("multiplatform-setup")
id("android-setup")
}
kotlin {
sourceSets {
named("commonMain") {
dependencies {
implementation(project(":common:utils"))
implementation(project(":common:database"))
implementation(Deps.ArkIvanov.MVIKotlin.mvikotlin)
implementation(Deps.ArkIvanov.MVIKotlin.mvikotlinExtensionsReaktive)
implementation(Deps.ArkIvanov.Decompose.decompose)
implementation(Deps.Badoo.Reaktive.reaktive)
}
}
}
}

2
examples/todoapp/common/edit/src/androidMain/AndroidManifest.xml

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="example.todo.common.edit"/>

23
examples/todoapp/common/edit/src/commonMain/kotlin/example/todo/common/edit/TodoEdit.kt

@ -1,23 +0,0 @@
package example.todo.common.edit
import com.arkivanov.decompose.value.Value
interface TodoEdit {
val models: Value<Model>
fun onTextChanged(text: String)
fun onDoneChanged(isDone: Boolean)
fun onCloseClicked()
data class Model(
val text: String,
val isDone: Boolean
)
sealed class Output {
object Finished : Output()
}
}

6
examples/todoapp/common/edit/src/commonMain/kotlin/example/todo/common/edit/TodoItem.kt

@ -1,6 +0,0 @@
package example.todo.common.edit
internal data class TodoItem(
val text: String,
val isDone: Boolean
)

12
examples/todoapp/common/edit/src/commonMain/kotlin/example/todo/common/edit/integration/Mappers.kt

@ -1,12 +0,0 @@
package example.todo.common.edit.integration
import example.todo.common.edit.TodoEdit.Model
import example.todo.common.edit.store.TodoEditStore.State
internal val stateToModel: (State) -> Model =
{
Model(
text = it.text,
isDone = it.isDone
)
}

48
examples/todoapp/common/edit/src/commonMain/kotlin/example/todo/common/edit/integration/TodoEditComponent.kt

@ -1,48 +0,0 @@
package example.todo.common.edit.integration
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.value.Value
import com.arkivanov.decompose.value.operator.map
import com.arkivanov.mvikotlin.core.store.StoreFactory
import com.badoo.reaktive.base.Consumer
import com.badoo.reaktive.base.invoke
import example.todo.common.database.TodoSharedDatabase
import example.todo.common.edit.TodoEdit
import example.todo.common.edit.TodoEdit.Model
import example.todo.common.edit.TodoEdit.Output
import example.todo.common.edit.store.TodoEditStore.Intent
import example.todo.common.edit.store.TodoEditStoreProvider
import example.todo.common.utils.asValue
import example.todo.common.utils.getStore
class TodoEditComponent(
componentContext: ComponentContext,
storeFactory: StoreFactory,
database: TodoSharedDatabase,
itemId: Long,
private val output: Consumer<Output>
) : TodoEdit, ComponentContext by componentContext {
private val store =
instanceKeeper.getStore {
TodoEditStoreProvider(
storeFactory = storeFactory,
database = TodoEditStoreDatabase(database = database),
id = itemId
).provide()
}
override val models: Value<Model> = store.asValue().map(stateToModel)
override fun onTextChanged(text: String) {
store.accept(Intent.SetText(text = text))
}
override fun onDoneChanged(isDone: Boolean) {
store.accept(Intent.SetDone(isDone = isDone))
}
override fun onCloseClicked() {
output(Output.Finished)
}
}

31
examples/todoapp/common/edit/src/commonMain/kotlin/example/todo/common/edit/integration/TodoEditStoreDatabase.kt

@ -1,31 +0,0 @@
package example.todo.common.edit.integration
import com.badoo.reaktive.completable.Completable
import com.badoo.reaktive.maybe.Maybe
import com.badoo.reaktive.maybe.map
import example.todo.common.database.TodoItemEntity
import example.todo.common.database.TodoSharedDatabase
import example.todo.common.edit.TodoItem
import example.todo.common.edit.store.TodoEditStoreProvider.Database
internal class TodoEditStoreDatabase(
private val database: TodoSharedDatabase
) : Database {
override fun load(id: Long): Maybe<TodoItem> =
database
.select(id = id)
.map { it.toItem() }
private fun TodoItemEntity.toItem(): TodoItem =
TodoItem(
text = text,
isDone = isDone
)
override fun setText(id: Long, text: String): Completable =
database.setText(id = id, text = text)
override fun setDone(id: Long, isDone: Boolean): Completable =
database.setDone(id = id, isDone = isDone)
}

24
examples/todoapp/common/edit/src/commonMain/kotlin/example/todo/common/edit/store/TodoEditStore.kt

@ -1,24 +0,0 @@
package example.todo.common.edit.store
import com.arkivanov.mvikotlin.core.store.Store
import example.todo.common.edit.TodoItem
import example.todo.common.edit.store.TodoEditStore.Intent
import example.todo.common.edit.store.TodoEditStore.Label
import example.todo.common.edit.store.TodoEditStore.State
internal interface TodoEditStore : Store<Intent, State, Label> {
sealed class Intent {
data class SetText(val text: String) : Intent()
data class SetDone(val isDone: Boolean) : Intent()
}
data class State(
val text: String = "",
val isDone: Boolean = false
)
sealed class Label {
data class Changed(val item: TodoItem) : Label()
}
}

83
examples/todoapp/common/edit/src/commonMain/kotlin/example/todo/common/edit/store/TodoEditStoreProvider.kt

@ -1,83 +0,0 @@
package example.todo.common.edit.store
import com.arkivanov.mvikotlin.core.store.Reducer
import com.arkivanov.mvikotlin.core.store.SimpleBootstrapper
import com.arkivanov.mvikotlin.core.store.Store
import com.arkivanov.mvikotlin.core.store.StoreFactory
import com.arkivanov.mvikotlin.extensions.reaktive.ReaktiveExecutor
import com.badoo.reaktive.completable.Completable
import com.badoo.reaktive.maybe.Maybe
import com.badoo.reaktive.maybe.map
import com.badoo.reaktive.maybe.observeOn
import com.badoo.reaktive.scheduler.mainScheduler
import example.todo.common.edit.TodoItem
import example.todo.common.edit.store.TodoEditStore.Intent
import example.todo.common.edit.store.TodoEditStore.Label
import example.todo.common.edit.store.TodoEditStore.State
internal class TodoEditStoreProvider(
private val storeFactory: StoreFactory,
private val database: Database,
private val id: Long
) {
fun provide(): TodoEditStore =
object : TodoEditStore, Store<Intent, State, Label> by storeFactory.create(
name = "EditStore",
initialState = State(),
bootstrapper = SimpleBootstrapper(Unit),
executorFactory = ::ExecutorImpl,
reducer = ReducerImpl
) {}
private sealed class Msg {
data class Loaded(val item: TodoItem) : Msg()
data class TextChanged(val text: String) : Msg()
data class DoneChanged(val isDone: Boolean) : Msg()
}
private inner class ExecutorImpl : ReaktiveExecutor<Intent, Unit, State, Msg, Label>() {
override fun executeAction(action: Unit, getState: () -> State) {
database
.load(id = id)
.map(Msg::Loaded)
.observeOn(mainScheduler)
.subscribeScoped(onSuccess = ::dispatch)
}
override fun executeIntent(intent: Intent, getState: () -> State) =
when (intent) {
is Intent.SetText -> setText(text = intent.text, state = getState())
is Intent.SetDone -> setDone(isDone = intent.isDone, state = getState())
}
private fun setText(text: String, state: State) {
dispatch(Msg.TextChanged(text = text))
publish(Label.Changed(TodoItem(text = text, isDone = state.isDone)))
database.setText(id = id, text = text).subscribeScoped()
}
private fun setDone(isDone: Boolean, state: State) {
dispatch(Msg.DoneChanged(isDone = isDone))
publish(Label.Changed(TodoItem(text = state.text, isDone = isDone)))
database.setDone(id = id, isDone = isDone).subscribeScoped()
}
}
private object ReducerImpl : Reducer<State, Msg> {
override fun State.reduce(msg: Msg): State =
when (msg) {
is Msg.Loaded -> copy(text = msg.item.text, isDone = msg.item.isDone)
is Msg.TextChanged -> copy(text = msg.text)
is Msg.DoneChanged -> copy(isDone = msg.isDone)
}
}
interface Database {
fun load(id: Long): Maybe<TodoItem>
fun setText(id: Long, text: String): Completable
fun setDone(id: Long, isDone: Boolean): Completable
}
}

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

Loading…
Cancel
Save