diff --git a/.github/workflows/compilation-check.yml b/.github/workflows/compilation-check.yml
index 0352a1b1..5c4a9c54 100644
--- a/.github/workflows/compilation-check.yml
+++ b/.github/workflows/compilation-check.yml
@@ -23,4 +23,4 @@ jobs:
- name: Cocoapods install
run: (cd sample/ios-app && pod install)
- name: Build pods-dependent and publish local
- run: ./gradlew -PlibraryPublish :widgets-flat:publishToMavenLocal :widgets-bottomsheet:publishToMavenLocal :widgets-sms:publishToMavenLocal
\ No newline at end of file
+ run: ./gradlew -PlibraryPublish :widgets-flat:publishToMavenLocal :widgets-bottomsheet:publishToMavenLocal :widgets-sms:publishToMavenLocal :widgets-datetime-picker:publishToMavenLocal :widgets-collection:publishToMavenLocal
\ No newline at end of file
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index bd45f705..007056cf 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -21,4 +21,4 @@ jobs:
- name: Cocoapods install
run: (cd sample/ios-app && pod install)
- name: Build pods-dependent and publish local
- run: ./gradlew -PlibraryPublish :widgets-flat:publishAllPublicationsToBintrayRepository :widgets-bottomsheet:publishAllPublicationsToBintrayRepository :widgets-sms:publishAllPublicationsToBintrayRepository -DBINTRAY_USER=${{ secrets.BINTRAY_USER }} -DBINTRAY_KEY=${{ secrets.BINTRAY_KEY }}
\ No newline at end of file
+ run: ./gradlew -PlibraryPublish :widgets-flat:publishAllPublicationsToBintrayRepository :widgets-bottomsheet:publishAllPublicationsToBintrayRepository :widgets-sms:publishAllPublicationsToBintrayRepository :widgets-datetime-picker:publishAllPublicationsToBintrayRepository :widgets-collection:publishAllPublicationsToBintrayRepository -DBINTRAY_USER=${{ secrets.BINTRAY_USER }} -DBINTRAY_KEY=${{ secrets.BINTRAY_KEY }}
\ No newline at end of file
diff --git a/README.md b/README.md
index e64f210d..5f69d91d 100755
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ This is a Kotlin MultiPlatform library that provides declarative UI and applicat
in common code. You can implement full application for Android and iOS only from common code with it.
## Current status
-Current version - `0.1.0-dev-14`. Dev version is not tested in production tasks yet, API can be changed and
+Current version - `0.1.0-dev-15`. Dev version is not tested in production tasks yet, API can be changed and
bugs may be found. But dev version is chance to test limits of API and concepts to feedback and improve lib.
We open for any feedback and ideas (go to issues or #moko at [kotlinlang.slack.com](https://kotlinlang.slack.com))!
@@ -222,6 +222,7 @@ val loginScreen = Theme(baseTheme) {
- 0.1.0-dev-12
- 0.1.0-dev-13
- 0.1.0-dev-14
+ - 0.1.0-dev-15
## Installation
root build.gradle
@@ -236,7 +237,7 @@ allprojects {
project build.gradle
```groovy
dependencies {
- commonMainApi("dev.icerock.moko:widgets:0.1.0-dev-14")
+ commonMainApi("dev.icerock.moko:widgets:0.1.0-dev-15")
}
```
@@ -254,7 +255,7 @@ buildscript {
}
dependencies {
- classpath "dev.icerock.moko.widgets:gradle-plugin:0.1.0-dev-14"
+ classpath "dev.icerock.moko.widgets:gradle-plugin:0.1.0-dev-15"
}
}
@@ -370,19 +371,18 @@ Please see more examples in the [sample directory](sample).
- The [widgets directory](widgets) contains the `widgets` library;
- The [widgets-bottomsheet directory](widgets-bottomsheet) contains the `widgets-bottomsheet` library;
- The [widgets-sms directory](widgets-sms) contains the `widgets-sms` library;
+- The [widgets-datetime-picker directory](widgets-datetime-picker) contains the `datetime-picker` library;
+- The [widgets-collection directory](widgets-collection) contains the `collection` library;
- The [gradle-plugin directory](gradle-plugin) contains the gradle-plugin which apply compiler plugins for Native and JVM;
- The [kotlin-plugin directory](kotlin-plugin) contains the JVM compiler plugin with code-generation from @WidgetDef annotation;
- The [kotlin-native-plugin directory](kotlin-native-plugin) contains the Native compiler plugin with code-generation from @WidgetDef annotation;
- The [kotlin-common-plugin directory](kotlin-common-plugin) contains the common code of JVM and Native compiler plugins;
- The [sample directory](sample) contains sample apps for Android and iOS; plus the mpp-library connected to the apps;
- For local testing a library use:
- - `./gradlew -PpluginPublish publishPluginPublicationToMavenLocal`
- - `./gradlew -PlibraryPublish :widgets:publishToMavenLocal`
- - `cd sample/ios-app && pod install`
- - `./gradlew -PlibraryPublish :widgets-flat:publishToMavenLocal :widgets-bottomsheet:publishToMavenLocal :widgets-sms:publishToMavenLocal`
+ - `./publishToMavenLocal.sh`
+ - `cd sample/ios-app`
+ - `pod install`
- sample apps priority use the locally published version
- - `./gradlew :sample:mpp-library:syncMultiPlatformLibraryDebugFrameworkIosX64` - compile sample shared code for iOS
- - `cd sample/ios-app && pod install` - install pods with compiled shared code
- run android from `Android Studio` - module `android-app`, run iOS from xcode workspace `sample/ios-app/ios-app.xcworkspace`
## Contributing
diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts
index 1d00a8cc..e80c75b1 100644
--- a/buildSrc/build.gradle.kts
+++ b/buildSrc/build.gradle.kts
@@ -14,7 +14,7 @@ repositories {
}
dependencies {
- implementation("dev.icerock:mobile-multiplatform:0.5.2")
+ implementation("dev.icerock:mobile-multiplatform:0.5.3")
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.61")
implementation("com.android.tools.build:gradle:3.5.2")
}
diff --git a/buildSrc/src/main/kotlin/Deps.kt b/buildSrc/src/main/kotlin/Deps.kt
index 67b13fc1..eb6b5395 100755
--- a/buildSrc/src/main/kotlin/Deps.kt
+++ b/buildSrc/src/main/kotlin/Deps.kt
@@ -73,6 +73,16 @@ object Deps {
iosX64 = "dev.icerock.moko:widgets-bottomsheet-iosx64:${Versions.Libs.MultiPlatform.mokoWidgets}",
iosArm64 = "dev.icerock.moko:widgets-bottomsheet-iosarm64:${Versions.Libs.MultiPlatform.mokoWidgets}"
)
+ val mokoWidgetsCollection = MultiPlatformLibrary(
+ common = "dev.icerock.moko:widgets-collection:${Versions.Libs.MultiPlatform.mokoWidgets}",
+ iosX64 = "dev.icerock.moko:widgets-collection-iosx64:${Versions.Libs.MultiPlatform.mokoWidgets}",
+ iosArm64 = "dev.icerock.moko:widgets-collection-iosarm64:${Versions.Libs.MultiPlatform.mokoWidgets}"
+ )
+ val mokoWidgetsDateTimePicker = MultiPlatformLibrary(
+ common = "dev.icerock.moko:widgets-datetime-picker:${Versions.Libs.MultiPlatform.mokoWidgets}",
+ iosX64 = "dev.icerock.moko:widgets-datetime-picker-iosx64:${Versions.Libs.MultiPlatform.mokoWidgets}",
+ iosArm64 = "dev.icerock.moko:widgets-datetime-picker-iosarm64:${Versions.Libs.MultiPlatform.mokoWidgets}"
+ )
val mokoResources = MultiPlatformLibrary(
common = "dev.icerock.moko:resources:${Versions.Libs.MultiPlatform.mokoResources}",
iosX64 = "dev.icerock.moko:resources-iosx64:${Versions.Libs.MultiPlatform.mokoResources}",
diff --git a/moko-widgets-collection.podspec b/moko-widgets-collection.podspec
new file mode 100644
index 00000000..40a89b27
--- /dev/null
+++ b/moko-widgets-collection.podspec
@@ -0,0 +1,20 @@
+Pod::Spec.new do |spec|
+ spec.name = 'moko-widgets-collection'
+ spec.version = '0.1.0'
+ spec.homepage = 'https://github.com/icerockdev/moko-widgets'
+ spec.source = { :git => "https://github.com/icerockdev/moko-widgets.git", :tag => "release/#{spec.version}" }
+ spec.authors = 'IceRock Development'
+ spec.license = { :type => 'Apache 2', :file => 'LICENSE.md' }
+ spec.summary = 'Swift additions to moko-widgets Kotlin/Native library'
+ spec.module_name = "mokoWidgetsCollection"
+
+ spec.source_files = "widgets-collection/src/iosMain/swift/**/*.{h,m,swift}"
+ spec.resources = "widgets-collection/src/iosMain/bundle/**/*"
+
+ spec.ios.deployment_target = '11.0'
+ spec.swift_version = '5.0'
+
+ spec.pod_target_xcconfig = {
+ 'VALID_ARCHS' => '$(ARCHS_STANDARD_64_BIT)'
+ }
+end
diff --git a/publishToMavenLocal.sh b/publishToMavenLocal.sh
index 13637d78..efd4b26f 100755
--- a/publishToMavenLocal.sh
+++ b/publishToMavenLocal.sh
@@ -1,3 +1,4 @@
./gradlew -PpluginPublish publishPluginPublicationToMavenLocal
./gradlew -PlibraryPublish :widgets:publishToMavenLocal
-./gradlew -PlibraryPublish :widgets-flat:publishToMavenLocal :widgets-bottomsheet:publishToMavenLocal :widgets-sms:publishToMavenLocal
\ No newline at end of file
+(cd sample/ios-app && pod install)
+./gradlew -PlibraryPublish :widgets-flat:publishToMavenLocal :widgets-bottomsheet:publishToMavenLocal :widgets-sms:publishToMavenLocal :widgets-datetime-picker:publishToMavenLocal :widgets-collection:publishToMavenLocal
\ No newline at end of file
diff --git a/sample/ios-app/Podfile b/sample/ios-app/Podfile
index fb086090..00932cb9 100644
--- a/sample/ios-app/Podfile
+++ b/sample/ios-app/Podfile
@@ -17,6 +17,5 @@ target 'TestProj' do
pod 'mppLibraryIos', :path => '../mpp-library'
pod 'moko-widgets-flat', :path => '../../'
pod 'moko-widgets-bottomsheet', :path => '../../'
-
- pod 'MultiPlatformLibraryMvvm', :git => 'https://github.com/icerockdev/moko-mvvm.git', :tag => 'release/0.4.0-dev-2'
+ pod 'moko-widgets-collection', :path => '../../'
end
diff --git a/sample/ios-app/Podfile.lock b/sample/ios-app/Podfile.lock
index 49c62bfa..88f00f85 100644
--- a/sample/ios-app/Podfile.lock
+++ b/sample/ios-app/Podfile.lock
@@ -1,76 +1,48 @@
PODS:
- - Alamofire (4.9.1)
- - AlamofireImage (3.6.0):
- - Alamofire (~> 4.9)
- FloatingPanel (1.7.2)
- InputMask (5.0.0)
- moko-widgets-bottomsheet (0.1.0):
- FloatingPanel
+ - moko-widgets-collection (0.1.0)
- moko-widgets-flat (0.1.0):
- InputMask (~> 5.0.0)
- mppLibraryIos (0.1.0)
- MultiPlatformLibrary (0.1.0)
- - MultiPlatformLibraryMvvm (0.3.0):
- - MultiPlatformLibrary
- - MultiPlatformLibraryMvvm/AlamofireImage (= 0.3.0)
- - MultiPlatformLibraryMvvm/Core (= 0.3.0)
- - MultiPlatformLibraryMvvm/SkyFloatingLabelTextField (= 0.3.0)
- - MultiPlatformLibraryMvvm/AlamofireImage (0.3.0):
- - AlamofireImage
- - MultiPlatformLibrary
- - MultiPlatformLibraryMvvm/Core (0.3.0):
- - MultiPlatformLibrary
- - MultiPlatformLibraryMvvm/SkyFloatingLabelTextField (0.3.0):
- - MultiPlatformLibrary
- - SkyFloatingLabelTextField
- - SkyFloatingLabelTextField (3.7.0)
DEPENDENCIES:
- moko-widgets-bottomsheet (from `../../`)
+ - moko-widgets-collection (from `../../`)
- moko-widgets-flat (from `../../`)
- mppLibraryIos (from `../mpp-library`)
- MultiPlatformLibrary (from `../mpp-library`)
- - MultiPlatformLibraryMvvm (from `https://github.com/icerockdev/moko-mvvm.git`, tag `release/0.4.0-dev-2`)
SPEC REPOS:
https://github.com/CocoaPods/Specs.git:
- - Alamofire
- - AlamofireImage
- InputMask
- - SkyFloatingLabelTextField
trunk:
- FloatingPanel
EXTERNAL SOURCES:
moko-widgets-bottomsheet:
:path: "../../"
+ moko-widgets-collection:
+ :path: "../../"
moko-widgets-flat:
:path: "../../"
mppLibraryIos:
:path: "../mpp-library"
MultiPlatformLibrary:
:path: "../mpp-library"
- MultiPlatformLibraryMvvm:
- :git: https://github.com/icerockdev/moko-mvvm.git
- :tag: release/0.4.0-dev-2
-
-CHECKOUT OPTIONS:
- MultiPlatformLibraryMvvm:
- :git: https://github.com/icerockdev/moko-mvvm.git
- :tag: release/0.4.0-dev-2
SPEC CHECKSUMS:
- Alamofire: 85e8a02c69d6020a0d734f6054870d7ecb75cf18
- AlamofireImage: be9963c6582d68b39e89191f64c82a7d7bf40fdd
FloatingPanel: b275a35d0a09be4bd37025e710a6a1d063bfc161
InputMask: 8a10dbc8ac3f94f0a5b4c380424bbe6795c69b16
moko-widgets-bottomsheet: 68e942940b15bf0c6605675140d907fdb79db31d
+ moko-widgets-collection: 722c6fca0b0dcab0b54fdb674b4638d4f715434c
moko-widgets-flat: 3d68acddc0469a1288ede5b5b63b6588de5aa5e1
mppLibraryIos: 72c3984fbaa53978d678e62096fd613e67839f0c
MultiPlatformLibrary: 176fb8ade516666cd47e93de1b71ba0441a541bb
- MultiPlatformLibraryMvvm: 999ac3896d8214fd65e0e0a376a2e553bf4515b3
- SkyFloatingLabelTextField: 4b46db0ab1ccde0919cded29c656e6b4805eda04
-PODFILE CHECKSUM: 4b3a5440fa9c919597e5ebac2ced886871ffb124
+PODFILE CHECKSUM: d67011d3954d166daed6874ad60b67569d84c8b3
-COCOAPODS: 1.8.4
+COCOAPODS: 1.9.0
diff --git a/sample/ios-app/src/Info.plist b/sample/ios-app/src/Info.plist
index 52507931..5df5f5c2 100755
--- a/sample/ios-app/src/Info.plist
+++ b/sample/ios-app/src/Info.plist
@@ -48,6 +48,8 @@
UISupportedInterfaceOrientations
UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
UISupportedInterfaceOrientations~ipad
diff --git a/sample/mpp-library/build.gradle.kts b/sample/mpp-library/build.gradle.kts
index b46e2182..582fe510 100644
--- a/sample/mpp-library/build.gradle.kts
+++ b/sample/mpp-library/build.gradle.kts
@@ -31,12 +31,11 @@ val deps = listOf(
Deps.Libs.MultiPlatform.mokoGraphics,
Deps.Libs.MultiPlatform.mokoWidgets,
Deps.Libs.MultiPlatform.mokoWidgetsFlat,
- Deps.Libs.MultiPlatform.mokoWidgetsBottomSheet
+ Deps.Libs.MultiPlatform.mokoWidgetsBottomSheet,
+ Deps.Libs.MultiPlatform.mokoWidgetsCollection
)
-setupFramework(
- exports = deps
-)
+setupFramework(exports = emptyList())
dependencies {
mppLibrary(Deps.Libs.MultiPlatform.kotlinStdLib)
@@ -58,5 +57,6 @@ cocoaPods {
pod("moko-widgets-flat", "mokoWidgetsFlat", onlyLink = true)
pod("moko-widgets-bottomsheet", "mokoWidgetsBottomSheet", onlyLink = true)
+ pod("moko-widgets-collection", "mokoWidgetsCollection", onlyLink = true)
pod("mppLibraryIos")
}
diff --git a/sample/mpp-library/src/commonMain/kotlin/App.kt b/sample/mpp-library/src/commonMain/kotlin/App.kt
index aef8e01c..3cffae26 100644
--- a/sample/mpp-library/src/commonMain/kotlin/App.kt
+++ b/sample/mpp-library/src/commonMain/kotlin/App.kt
@@ -5,6 +5,8 @@
import com.icerockdev.library.AppTheme
import com.icerockdev.library.MR
import com.icerockdev.library.SharedFactory
+import com.icerockdev.library.sample.PostsScreen
+import com.icerockdev.library.sample.PostsViewModel
import com.icerockdev.library.universal.CartScreen
import com.icerockdev.library.universal.InfoWebViewScreen
import com.icerockdev.library.universal.LoginScreen
@@ -24,6 +26,8 @@ import dev.icerock.moko.widgets.ImageWidget
import dev.icerock.moko.widgets.InputWidget
import dev.icerock.moko.widgets.TabsWidget
import dev.icerock.moko.widgets.button
+import dev.icerock.moko.widgets.collection.CollectionWidget
+import dev.icerock.moko.widgets.collection.SimpleCollectionViewFactory
import dev.icerock.moko.widgets.container
import dev.icerock.moko.widgets.core.Theme
import dev.icerock.moko.widgets.core.Value
@@ -36,6 +40,8 @@ import dev.icerock.moko.widgets.factory.SystemInputViewFactory
import dev.icerock.moko.widgets.factory.SystemTabsViewFactory
import dev.icerock.moko.widgets.factory.SystemTextViewFactory
import dev.icerock.moko.widgets.flat.FlatInputViewFactory
+import dev.icerock.moko.widgets.sample.CollectionImageUnitItem
+import dev.icerock.moko.widgets.sample.CollectionScreen
import dev.icerock.moko.widgets.sample.InputWidgetGalleryScreen
import dev.icerock.moko.widgets.sample.ProductsSearchScreen
import dev.icerock.moko.widgets.sample.ScrollContentScreen
@@ -45,6 +51,7 @@ import dev.icerock.moko.widgets.screen.Args
import dev.icerock.moko.widgets.screen.BaseApplication
import dev.icerock.moko.widgets.screen.Screen
import dev.icerock.moko.widgets.screen.ScreenDesc
+import dev.icerock.moko.widgets.screen.TemplateScreen
import dev.icerock.moko.widgets.screen.TypedScreenDesc
import dev.icerock.moko.widgets.screen.WidgetScreen
import dev.icerock.moko.widgets.screen.navigation.BottomNavigationItem
@@ -60,6 +67,7 @@ import dev.icerock.moko.widgets.screen.navigation.createRouter
import dev.icerock.moko.widgets.screen.navigation.route
import dev.icerock.moko.widgets.style.background.Background
import dev.icerock.moko.widgets.style.background.Fill
+import dev.icerock.moko.widgets.style.background.Orientation
import dev.icerock.moko.widgets.style.state.PressableState
import dev.icerock.moko.widgets.style.state.SelectableState
import dev.icerock.moko.widgets.style.view.MarginValues
@@ -108,6 +116,8 @@ class App() : BaseApplication() {
buildInputGalleryRouteInfo(theme, router),
buildSearchRouteInfo(theme, router),
buildTabsRouteInfo(theme, router),
+ buildCollectionRouteInfo(theme, router),
+ buildPostsRouteInfo(theme, router),
SelectGalleryScreen.RouteInfo(
name = "Old Demo".desc(),
route = router.createPushRoute(oldDemo(router))
@@ -177,6 +187,53 @@ class App() : BaseApplication() {
)
}
+ private fun buildCollectionRouteInfo(
+ theme: Theme,
+ router: NavigationScreen.Router
+ ): SelectGalleryScreen.RouteInfo {
+ val collectionTheme = Theme(theme) {
+ factory[CollectionWidget.DefaultCategory] = SimpleCollectionViewFactory(
+ orientation = Orientation.HORIZONTAL,
+ margins = MarginValues(top = 16f, bottom = 16f)
+ )
+ factory[CollectionImageUnitItem.Id.Image] = SystemImageViewFactory(
+ cornerRadius = 8f,
+ margins = MarginValues(start = 4f, end = 4f)
+ )
+ }
+ val collectionScreen = registerScreen(CollectionScreen::class) {
+ CollectionScreen(collectionTheme)
+ }
+
+ return SelectGalleryScreen.RouteInfo(
+ name = "Collection in list".desc(),
+ route = router.createPushRoute(collectionScreen)
+ )
+ }
+
+ private fun buildPostsRouteInfo(
+ theme: Theme,
+ router: NavigationScreen.Router
+ ): SelectGalleryScreen.RouteInfo {
+ val postsTheme = Theme(theme) {
+ factory[PostsScreen.Id.Collection] = SimpleCollectionViewFactory(
+ padding = PaddingValues(4f)
+ )
+ }
+
+ val postsScreen = registerScreen(PostsScreen::class) {
+ PostsScreen(
+ postsTheme,
+ PostsViewModel()
+ )
+ }
+
+ return SelectGalleryScreen.RouteInfo(
+ name = "Posts Collection".desc(),
+ route = router.createPushRoute(postsScreen)
+ )
+ }
+
private fun oldDemo(
router: NavigationScreen.Router
): TypedScreenDesc {
@@ -230,6 +287,10 @@ class App() : BaseApplication() {
val mainScreen = registerScreen(MainBottomNavigationScreen::class) {
val bottomRouter = createRouter()
+ val templateScreen = registerScreen(TemplateScreen::class) {
+ TemplateScreen(navTitle = "Template".desc(), labelText = "Template Screen".desc(), theme = theme)
+ }
+
val cartNavigation = registerScreen(CartNavigationScreen::class) {
val navigationRouter = createRouter()
val profileScreen = registerScreen(PlatformProfileScreen::class) {
@@ -306,6 +367,11 @@ class App() : BaseApplication() {
title = "Logout".desc(),
screenDesc = logoutScreen
)
+ tab(
+ id = 5,
+ title = "Empty".desc(),
+ screenDesc = templateScreen
+ )
}
}
diff --git a/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/AppTheme.kt b/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/AppTheme.kt
index d8b76d4b..b6927e4d 100644
--- a/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/AppTheme.kt
+++ b/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/AppTheme.kt
@@ -9,16 +9,16 @@ import com.icerockdev.library.sample.UsersScreen
import com.icerockdev.library.universal.LoginScreen
import dev.icerock.moko.graphics.Color
import dev.icerock.moko.widgets.ButtonWidget
-import dev.icerock.moko.widgets.CollectionWidget
import dev.icerock.moko.widgets.ConstraintWidget
import dev.icerock.moko.widgets.InputWidget
import dev.icerock.moko.widgets.StatefulWidget
+import dev.icerock.moko.widgets.collection.CollectionWidget
+import dev.icerock.moko.widgets.collection.SimpleCollectionViewFactory
import dev.icerock.moko.widgets.core.Theme
import dev.icerock.moko.widgets.factory.ConstraintViewFactory
import dev.icerock.moko.widgets.factory.FloatingLabelInputViewFactory
import dev.icerock.moko.widgets.factory.StatefulViewFactory
import dev.icerock.moko.widgets.factory.SystemButtonViewFactory
-import dev.icerock.moko.widgets.factory.SystemCollectionViewFactory
import dev.icerock.moko.widgets.factory.SystemListViewFactory
import dev.icerock.moko.widgets.factory.SystemTextViewFactory
import dev.icerock.moko.widgets.style.background.Background
@@ -110,7 +110,7 @@ object AppTheme {
)
)
- factory[PostsCollection] = SystemCollectionViewFactory(
+ factory[PostsCollection] = SimpleCollectionViewFactory(
padding = PaddingValues(4f)
)
}
diff --git a/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/sample/PostsSample.kt b/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/sample/PostsSample.kt
index ee393b56..c7d7bbaf 100644
--- a/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/sample/PostsSample.kt
+++ b/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/sample/PostsSample.kt
@@ -12,24 +12,26 @@ import dev.icerock.moko.mvvm.viewmodel.ViewModel
import dev.icerock.moko.resources.desc.StringDesc
import dev.icerock.moko.resources.desc.desc
import dev.icerock.moko.units.CollectionUnitItem
-import dev.icerock.moko.widgets.CollectionWidget
-import dev.icerock.moko.widgets.collection
+import dev.icerock.moko.widgets.collection.CollectionWidget
+import dev.icerock.moko.widgets.collection.collection
import dev.icerock.moko.widgets.core.Theme
import dev.icerock.moko.widgets.core.Widget
+import dev.icerock.moko.widgets.screen.Args.Empty
+import dev.icerock.moko.widgets.screen.WidgetScreen
+import dev.icerock.moko.widgets.screen.navigation.NavigationBar
+import dev.icerock.moko.widgets.screen.navigation.NavigationItem
import dev.icerock.moko.widgets.style.view.SizeSpec
import dev.icerock.moko.widgets.style.view.WidgetSize
class PostsScreen(
private val theme: Theme,
- private val viewModel: PostsViewModelContract,
- private val collectionCategory: CollectionWidget.Category
-) {
+ private val viewModel: PostsViewModelContract
+) : WidgetScreen(), NavigationItem {
fun createWidget(): Widget> {
return with(theme) {
collection(
size = WidgetSize.AsParent,
id = Id.Collection,
- category = collectionCategory,
items = viewModel.posts.map { posts ->
posts.map { post ->
PostCollectionUnitItem(
@@ -46,8 +48,16 @@ class PostsScreen(
object Id {
object Collection : CollectionWidget.Id
}
+
+ override val navigationBar: NavigationBar
+ get() = NavigationBar.Normal("Posts".desc())
+
+ override fun createContentWidget(): Widget> {
+ return createWidget()
+ }
}
+
interface PostsViewModelContract {
val posts: LiveData>
diff --git a/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/sample/UsersSample.kt b/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/sample/UsersSample.kt
index 249f6670..ae160f5f 100644
--- a/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/sample/UsersSample.kt
+++ b/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/sample/UsersSample.kt
@@ -11,10 +11,9 @@ import dev.icerock.moko.mvvm.livedata.mergeWith
import dev.icerock.moko.mvvm.viewmodel.ViewModel
import dev.icerock.moko.units.CollectionUnitItem
import dev.icerock.moko.units.TableUnitItem
-import dev.icerock.moko.widgets.CollectionWidget
import dev.icerock.moko.widgets.ListWidget
-import dev.icerock.moko.widgets.TabsWidget
-import dev.icerock.moko.widgets.collection
+import dev.icerock.moko.widgets.collection.CollectionWidget
+import dev.icerock.moko.widgets.collection.collection
import dev.icerock.moko.widgets.core.Theme
import dev.icerock.moko.widgets.core.Widget
import dev.icerock.moko.widgets.list
diff --git a/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/units/LoadingUnitWidget.kt b/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/units/LoadingUnitWidget.kt
index 381df3a3..65751a4b 100644
--- a/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/units/LoadingUnitWidget.kt
+++ b/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/units/LoadingUnitWidget.kt
@@ -64,8 +64,8 @@ class LoadingUnitWidget(
override val reuseId: String = "LoadingUnitItem"
- override fun createWidget(data: LiveData): UnitItemRoot {
- return unitWidget.createWidget(data).let { UnitItemRoot.from(it) }
+ override fun createWidget(data: LiveData): Widget {
+ return unitWidget.createWidget(data)
}
}
}
diff --git a/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/units/PostCollectionUnitItem.kt b/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/units/PostCollectionUnitItem.kt
index 52d5f560..2294cade 100644
--- a/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/units/PostCollectionUnitItem.kt
+++ b/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/units/PostCollectionUnitItem.kt
@@ -7,6 +7,7 @@ package com.icerockdev.library.units
import com.icerockdev.library.sample.PostsViewModelContract
import dev.icerock.moko.mvvm.livedata.LiveData
import dev.icerock.moko.mvvm.livedata.map
+import dev.icerock.moko.widgets.ImageWidget
import dev.icerock.moko.widgets.clickable
import dev.icerock.moko.widgets.container
import dev.icerock.moko.widgets.core.Image
@@ -27,49 +28,19 @@ class PostCollectionUnitItem(
) : WidgetsCollectionUnitItem(itemId, data) {
override val reuseId: String = "PostUnitItem"
- override fun createWidget(data: LiveData): UnitItemRoot {
- return with(theme) {
- UnitItemRoot.from(createBody(data))
- }
+ override fun createWidget(data: LiveData): Widget {
+ return theme.createBody(data)
}
private fun Theme.createBody(data: LiveData) =
clickable(
- child = container(
-// factory = DefaultContainerWidgetViewFactory(
-// DefaultContainerWidgetViewFactoryBase.Style(
-// background = Background(
-// fill = Fill.Solid(Color(0x66, 0x66, 0x66, 0xFF))
-// ),
-// margins = MarginValues(4f)
-// )
-// ),
- size = WidgetSize.AspectByWidth(
- width = SizeSpec.AsParent,
- aspectRatio = 0.73f
- )
- ) {
- center {
- image(
- size = WidgetSize.Const(
- width = SizeSpec.AsParent,
- height = SizeSpec.AsParent
- ),
-// factory = DefaultImageWidgetViewFactory(
-// DefaultImageWidgetViewFactoryBase.Style(
-// scaleType = DefaultImageWidgetViewFactoryBase.ScaleType.FILL
-// )
-// ),
- image = data.map { Image.network(it.imageUrl) }
- )
- }
- top {
- createHeader(data)
- }
- bottom {
- createFooter(data)
- }
- },
+ child = image(size = WidgetSize.AspectByWidth(
+ width = SizeSpec.AsParent,
+ aspectRatio = 1.5f
+ ),
+ scaleType = ImageWidget.ScaleType.FILL,
+ image = data.map { Image.network(it.imageUrl) }
+ ),
onClick = {
println("item $data pressed!")
}
@@ -91,7 +62,7 @@ class PostCollectionUnitItem(
// padding = PaddingValues(bottom = 8f)
// )
// ),
- size = WidgetSize.Const(SizeSpec.AsParent, SizeSpec.WrapContent)
+ size = WidgetSize.Const(SizeSpec.MatchConstraint, SizeSpec.MatchConstraint)
) {
center {
text(
@@ -115,7 +86,7 @@ class PostCollectionUnitItem(
): Widget {
val regularItems = listOf>(
text(
- size = WidgetSize.Const(SizeSpec.AsParent, SizeSpec.WrapContent),
+ size = WidgetSize.Const(SizeSpec.MatchConstraint, SizeSpec.WrapContent),
// factory = DefaultTextWidgetViewFactory(
// DefaultTextWidgetViewFactoryBase.Style(
// textStyle = TextStyle(
diff --git a/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/units/UserUnitWidget.kt b/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/units/UserUnitWidget.kt
index 91487d84..b997c4ec 100644
--- a/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/units/UserUnitWidget.kt
+++ b/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/units/UserUnitWidget.kt
@@ -11,6 +11,7 @@ import dev.icerock.moko.resources.desc.desc
import dev.icerock.moko.widgets.clickable
import dev.icerock.moko.widgets.core.Image
import dev.icerock.moko.widgets.core.Theme
+import dev.icerock.moko.widgets.core.Widget
import dev.icerock.moko.widgets.image
import dev.icerock.moko.widgets.linear
import dev.icerock.moko.widgets.style.background.Orientation
@@ -109,8 +110,8 @@ class UserUnitWidget(
override val reuseId: String = "UserUnitItem"
- override fun createWidget(data: LiveData): UnitItemRoot {
- return unitWidget.createWidget(data).let { UnitItemRoot.from(it) }
+ override fun createWidget(data: LiveData): Widget {
+ return unitWidget.createWidget(data)
}
}
}
diff --git a/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/universal/WidgetsScreen.kt b/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/universal/WidgetsScreen.kt
index db16113c..b140a7fd 100644
--- a/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/universal/WidgetsScreen.kt
+++ b/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/universal/WidgetsScreen.kt
@@ -17,7 +17,7 @@ import com.icerockdev.library.sample.StateScreen
import com.icerockdev.library.sample.StateViewModel
import com.icerockdev.library.sample.UsersScreen
import com.icerockdev.library.sample.UsersViewModel
-import dev.icerock.moko.widgets.CollectionWidget
+import dev.icerock.moko.widgets.collection.CollectionWidget
import dev.icerock.moko.widgets.constraint
import dev.icerock.moko.widgets.core.Theme
import dev.icerock.moko.widgets.core.Widget
@@ -81,8 +81,7 @@ class WidgetsScreen(
title = const("P"),
body = PostsScreen(
theme = theme,
- viewModel = PostsViewModel(),
- collectionCategory = postsCollectionCategory
+ viewModel = PostsViewModel()
).createWidget()
)
tab(
diff --git a/sample/mpp-library/src/commonMain/kotlin/dev/icerock/moko/widgets/sample/CollectionScreen.kt b/sample/mpp-library/src/commonMain/kotlin/dev/icerock/moko/widgets/sample/CollectionScreen.kt
new file mode 100644
index 00000000..997c2524
--- /dev/null
+++ b/sample/mpp-library/src/commonMain/kotlin/dev/icerock/moko/widgets/sample/CollectionScreen.kt
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package dev.icerock.moko.widgets.sample
+
+import dev.icerock.moko.mvvm.livedata.LiveData
+import dev.icerock.moko.mvvm.livedata.MutableLiveData
+import dev.icerock.moko.mvvm.livedata.map
+import dev.icerock.moko.resources.desc.desc
+import dev.icerock.moko.units.CollectionUnitItem
+import dev.icerock.moko.units.TableUnitItem
+import dev.icerock.moko.widgets.ImageWidget
+import dev.icerock.moko.widgets.ListWidget
+import dev.icerock.moko.widgets.collection.CollectionWidget
+import dev.icerock.moko.widgets.collection.collection
+import dev.icerock.moko.widgets.constraint
+import dev.icerock.moko.widgets.core.Image
+import dev.icerock.moko.widgets.core.Theme
+import dev.icerock.moko.widgets.core.Widget
+import dev.icerock.moko.widgets.image
+import dev.icerock.moko.widgets.list
+import dev.icerock.moko.widgets.screen.Args
+import dev.icerock.moko.widgets.screen.WidgetScreen
+import dev.icerock.moko.widgets.screen.navigation.NavigationBar
+import dev.icerock.moko.widgets.screen.navigation.NavigationItem
+import dev.icerock.moko.widgets.style.view.SizeSpec
+import dev.icerock.moko.widgets.style.view.WidgetSize
+import dev.icerock.moko.widgets.units.UnitItemRoot
+import dev.icerock.moko.widgets.units.WidgetsCollectionUnitItem
+import dev.icerock.moko.widgets.units.WidgetsTableUnitItem
+
+class CollectionScreen(
+ private val theme: Theme
+) : WidgetScreen(), NavigationItem {
+
+ override val navigationBar: NavigationBar = NavigationBar.Normal(title = "Collection in list".desc())
+
+ override fun createContentWidget(): Widget> {
+ return with(theme) {
+ constraint(size = WidgetSize.AsParent) {
+
+ val content = +content()
+
+ constraints {
+ content topToTop root.safeArea
+ content leftRightToLeftRight root
+ content bottomToBottom root.safeArea
+ }
+ }
+ }
+ }
+
+ private fun Theme.content() = list(
+ size = WidgetSize.Const(
+ width = SizeSpec.AsParent,
+ height = SizeSpec.MatchConstraint
+ ),
+ id = Ids.List,
+ items = listItems()
+ )
+
+ private fun Theme.listItems() = List>(10) {
+ listOf(
+ "https://cdn.pixabay.com/photo/2015/04/23/22/00/tree-736885__340.jpg",
+ "https://cdn.pixabay.com/photo/2015/02/24/15/41/dog-647528__340.jpg",
+ "https://images.pexels.com/photos/814499/pexels-photo-814499.jpeg?auto=compress&cs=tinysrgb&dpr=1&w=500",
+ "https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2016/03/1458289957powerful-images3.jpg"
+ )
+ }.mapIndexed { index, urls ->
+ ImageSliderUnit(
+ itemId = index.toLong(),
+ data = urls.map { Image.network(it) },
+ theme = this
+ ) as TableUnitItem
+ }.let { MutableLiveData(it) }
+
+ object Ids {
+ object List : ListWidget.Id
+ }
+}
+
+class ImageSliderUnit(
+ itemId: Long,
+ data: List,
+ private val theme: Theme
+) : WidgetsTableUnitItem>(itemId, data) {
+ override val reuseId: String = "ImageSliderUnit"
+
+ override fun createWidget(data: LiveData>): UnitItemRoot {
+ return UnitItemRoot.from(theme.createUnitWidget(data))
+ }
+
+ private fun Theme.createUnitWidget(data: LiveData>) = collection(
+ size = WidgetSize.Const(SizeSpec.AsParent, SizeSpec.Exact(182f)),
+ id = Id.Collection,
+ items = data.map {
+ it.mapIndexed { index, image ->
+ CollectionImageUnitItem(
+ itemId = index.toLong(),
+ data = image,
+ theme = theme
+ ) as CollectionUnitItem
+ }
+ }
+ )
+
+ object Id {
+ object Collection : CollectionWidget.Id
+ }
+}
+
+class CollectionImageUnitItem(
+ itemId: Long,
+ data: Image,
+ private val theme: Theme
+) : WidgetsCollectionUnitItem(itemId, data) {
+ override val reuseId: String = "CollectionImageUnitItem"
+
+ override fun createWidget(data: LiveData): Widget {
+ return with(theme) {
+ image(
+ size = WidgetSize.Const(SizeSpec.Exact(312f), SizeSpec.Exact(182f)),
+ id = Id.Image,
+ scaleType = ImageWidget.ScaleType.FILL,
+ image = data
+ )
+ }
+ }
+
+ object Id {
+ object Image : ImageWidget.Id
+ }
+}
diff --git a/sample/mpp-library/src/commonMain/resources/MR/base/strings.xml b/sample/mpp-library/src/commonMain/resources/MR/base/strings.xml
index cffafd71..c569894f 100644
--- a/sample/mpp-library/src/commonMain/resources/MR/base/strings.xml
+++ b/sample/mpp-library/src/commonMain/resources/MR/base/strings.xml
@@ -1,6 +1,6 @@
- test
+ test string
test 2
test 3
Test Project
diff --git a/sample/mpp-library/src/commonMain/resources/MR/ru/strings.xml b/sample/mpp-library/src/commonMain/resources/MR/ru/strings.xml
index ac2042f7..fbd3376d 100644
--- a/sample/mpp-library/src/commonMain/resources/MR/ru/strings.xml
+++ b/sample/mpp-library/src/commonMain/resources/MR/ru/strings.xml
@@ -1,6 +1,6 @@
- тест
+ тестовая строка
тест 2
тест 3
Тестовый проект
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 754cd9a8..8366666a 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -42,6 +42,8 @@ if (!pluginPublish) {
include(":widgets-flat")
include(":widgets-sms")
include(":widgets-bottomsheet")
+ include(":widgets-collection")
+ include(":widgets-datetime-picker")
if (!libraryPublish) {
include(":sample:android-app")
diff --git a/widgets-bottomsheet/src/androidMain/kotlin/dev/icerock/moko/widgets/bottomsheet/BottomSheet.kt b/widgets-bottomsheet/src/androidMain/kotlin/dev/icerock/moko/widgets/bottomsheet/BottomSheet.kt
index f459e596..f8841513 100644
--- a/widgets-bottomsheet/src/androidMain/kotlin/dev/icerock/moko/widgets/bottomsheet/BottomSheet.kt
+++ b/widgets-bottomsheet/src/androidMain/kotlin/dev/icerock/moko/widgets/bottomsheet/BottomSheet.kt
@@ -4,6 +4,7 @@
package dev.icerock.moko.widgets.bottomsheet
+import android.content.Context
import com.google.android.material.bottomsheet.BottomSheetDialog
import dev.icerock.moko.widgets.core.ViewFactoryContext
import dev.icerock.moko.widgets.core.Widget
@@ -13,10 +14,10 @@ import dev.icerock.moko.widgets.style.view.WidgetSize
actual fun Screen<*>.showBottomSheet(
content: Widget>,
- onDismiss: () -> Unit
-) {
- val context = context ?: return
- val dialog = BottomSheetDialog(context)
+ onDismiss: (isSelfDismissed: Boolean) -> Unit
+): SelfDismisser? {
+ val context = context ?: return null
+ val dialog = DismissedBottomSheetDialog(context, onDismiss)
dialog.setContentView(
content.buildView(
ViewFactoryContext(
@@ -26,6 +27,14 @@ actual fun Screen<*>.showBottomSheet(
)
).view
)
- dialog.setOnCancelListener { onDismiss() }
+ dialog.setOnCancelListener { onDismiss(false) }
dialog.show()
+ return dialog
}
+
+private class DismissedBottomSheetDialog(context: Context, val onDismiss: (Boolean) -> Unit): BottomSheetDialog(context), SelfDismisser {
+ override fun dismissSelf() {
+ this.dismiss()
+ onDismiss(true)
+ }
+}
\ No newline at end of file
diff --git a/widgets-bottomsheet/src/commonMain/kotlin/dev/icerock/moko/widgets/bottomsheet/BottomSheet.kt b/widgets-bottomsheet/src/commonMain/kotlin/dev/icerock/moko/widgets/bottomsheet/BottomSheet.kt
index 3532025e..28032164 100644
--- a/widgets-bottomsheet/src/commonMain/kotlin/dev/icerock/moko/widgets/bottomsheet/BottomSheet.kt
+++ b/widgets-bottomsheet/src/commonMain/kotlin/dev/icerock/moko/widgets/bottomsheet/BottomSheet.kt
@@ -11,5 +11,9 @@ import dev.icerock.moko.widgets.style.view.WidgetSize
expect fun Screen<*>.showBottomSheet(
content: Widget>,
- onDismiss: () -> Unit
-)
+ onDismiss: (isSelfDismissed: Boolean) -> Unit
+): SelfDismisser?
+
+interface SelfDismisser {
+ fun dismissSelf()
+}
\ No newline at end of file
diff --git a/widgets-bottomsheet/src/iosMain/kotlin/dev/icerock/moko/widgets/bottomSheet/BottomSheet.kt b/widgets-bottomsheet/src/iosMain/kotlin/dev/icerock/moko/widgets/bottomSheet/BottomSheet.kt
index d907fb3d..43638ab4 100644
--- a/widgets-bottomsheet/src/iosMain/kotlin/dev/icerock/moko/widgets/bottomSheet/BottomSheet.kt
+++ b/widgets-bottomsheet/src/iosMain/kotlin/dev/icerock/moko/widgets/bottomSheet/BottomSheet.kt
@@ -12,12 +12,22 @@ import dev.icerock.moko.widgets.style.view.WidgetSize
actual fun Screen<*>.showBottomSheet(
content: Widget>,
- onDismiss: () -> Unit
-) {
+ onDismiss: (isSelfDismissed: Boolean) -> Unit
+): SelfDismisser? {
val view = content.buildView(viewController).view
- BottomSheetController().showOnViewController(
+ val holder = BottomSheetHolder()
+ holder.bottomSheet.showOnViewController(
vc = this.viewController,
withContent = view,
onDismiss = onDismiss
)
+ return holder
}
+
+private class BottomSheetHolder: SelfDismisser {
+ val bottomSheet = BottomSheetController()
+
+ override fun dismissSelf() {
+ bottomSheet.dismiss()
+ }
+}
\ No newline at end of file
diff --git a/widgets-bottomsheet/src/iosMain/swift/BottomSheetController.swift b/widgets-bottomsheet/src/iosMain/swift/BottomSheetController.swift
index 8b32554b..bf0ffa1f 100644
--- a/widgets-bottomsheet/src/iosMain/swift/BottomSheetController.swift
+++ b/widgets-bottomsheet/src/iosMain/swift/BottomSheetController.swift
@@ -9,17 +9,20 @@ private var AssociatedDelegateHandle: UInt8 = 0
@objc public class BottomSheetController: NSObject, FloatingPanelControllerDelegate {
+ private weak var controller: FloatingPanelController?
+ private var onDismiss: ((Bool) -> Void)?
+
@objc public func show(
onViewController vc: UIViewController,
withContent view: UIView,
- onDismiss: @escaping () -> Void
+ onDismiss: @escaping (Bool) -> Void
) {
view.updateConstraints()
view.layoutSubviews()
-
+
let maxSize = CGSize(width: UIScreen.main.bounds.width, height: UIView.layoutFittingCompressedSize.height)
view.frame = UIScreen.main.bounds
-
+
let floatLayout = BottomSheetLayout(
preferredHeight: view.systemLayoutSizeFitting(
UIView.layoutFittingCompressedSize,
@@ -40,17 +43,29 @@ private var AssociatedDelegateHandle: UInt8 = 0
fpc.backdropView.backgroundColor = UIColor.black
fpc.isRemovalInteractionEnabled = true
+ view.superview?.layer.maskedCorners = [CACornerMask.layerMinXMinYCorner, CACornerMask.layerMaxXMinYCorner]
+ view.superview?.layer.masksToBounds = true
+ view.superview?.layer.cornerRadius = 14
+
+ controller = fpc
+ self.onDismiss = onDismiss
+
objc_setAssociatedObject(fpc, &AssociatedDelegateHandle, delegate, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
vc.present(fpc, animated: true, completion: nil)
}
+
+ @objc public func dismiss() {
+ controller?.dismiss(animated: true, completion: nil)
+ self.onDismiss?(true)
+ }
}
class FloatingDelegate: FloatingPanelControllerDelegate {
private let floatingLayout: FloatingPanelLayout
- private let onDismiss: () -> Void
+ private let onDismiss: (Bool) -> Void
- init(floatingLayout: FloatingPanelLayout, onDismiss: @escaping () -> Void) {
+ init(floatingLayout: FloatingPanelLayout, onDismiss: @escaping (Bool) -> Void) {
self.floatingLayout = floatingLayout
self.onDismiss = onDismiss
}
@@ -59,8 +74,16 @@ class FloatingDelegate: FloatingPanelControllerDelegate {
return floatingLayout
}
+ func floatingPanelDidEndDecelerating(_ vc: FloatingPanelController) {
+ if vc.position == .hidden {
+ vc.removePanelFromParent(animated: true)
+ vc.dismiss(animated: false, completion: nil)
+ onDismiss(false)
+ }
+ }
+
func floatingPanelDidEndRemove(_ vc: FloatingPanelController) {
- onDismiss()
+ onDismiss(false)
}
}
@@ -78,11 +101,11 @@ class BottomSheetLayout: FloatingPanelLayout {
case .half: return preferredHeight
case .full: return 0
case .tip: return 0
- case .hidden: return nil
+ case .hidden: return 0
}
}
- var supportedPositions: Set = [.half, .tip]
+ var supportedPositions: Set = [.half, .hidden]
func backdropAlphaFor(position: FloatingPanelPosition) -> CGFloat {
return 0.3
diff --git a/widgets-collection/build.gradle.kts b/widgets-collection/build.gradle.kts
new file mode 100644
index 00000000..7890dc08
--- /dev/null
+++ b/widgets-collection/build.gradle.kts
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+plugins {
+ id("com.android.library")
+ id("org.jetbrains.kotlin.multiplatform")
+ id("dev.icerock.mobile.multiplatform")
+ id("maven-publish")
+ id("dev.icerock.mobile.multiplatform-widgets-generator")
+}
+
+group = "dev.icerock.moko"
+version = Versions.Libs.MultiPlatform.mokoWidgets
+
+android {
+ compileSdkVersion(Versions.Android.compileSdk)
+
+ defaultConfig {
+ minSdkVersion(Versions.Android.minSdk)
+ targetSdkVersion(Versions.Android.targetSdk)
+ }
+}
+
+dependencies {
+ mppLibrary(Deps.Libs.MultiPlatform.kotlinStdLib)
+ mppLibrary(Deps.Libs.MultiPlatform.coroutines)
+
+ mppLibrary(Deps.Libs.MultiPlatform.mokoMvvm)
+ mppLibrary(Deps.Libs.MultiPlatform.mokoResources)
+ mppLibrary(Deps.Libs.MultiPlatform.mokoFields)
+ mppLibrary(Deps.Libs.MultiPlatform.mokoWidgets)
+ mppLibrary(Deps.Libs.MultiPlatform.mokoUnits)
+
+ androidLibrary(Deps.Libs.Android.lifecycle)
+ androidLibrary(Deps.Libs.Android.recyclerView)
+ androidLibrary(Deps.Libs.Android.swipeRefreshLayout)
+}
+
+publishing {
+ repositories.maven("https://api.bintray.com/maven/icerockdev/moko/moko-widgets/;publish=1") {
+ name = "bintray"
+
+ credentials {
+ username = System.getProperty("BINTRAY_USER")
+ password = System.getProperty("BINTRAY_KEY")
+ }
+ }
+}
+
+cocoaPods {
+ podsProject = file("../sample/ios-app/Pods/Pods.xcodeproj")
+
+ pod(scheme = "moko-widgets-collection", module = "mokoWidgetsCollection")
+}
diff --git a/widgets-collection/src/androidMain/AndroidManifest.xml b/widgets-collection/src/androidMain/AndroidManifest.xml
new file mode 100644
index 00000000..d9349e2d
--- /dev/null
+++ b/widgets-collection/src/androidMain/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/factory/SystemCollectionViewFactory.kt b/widgets-collection/src/androidMain/kotlin/dev/icerock/moko/widgets/collection/SimpleCollectionViewFactory.kt
similarity index 68%
rename from widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/factory/SystemCollectionViewFactory.kt
rename to widgets-collection/src/androidMain/kotlin/dev/icerock/moko/widgets/collection/SimpleCollectionViewFactory.kt
index 8b7718b7..1d085312 100644
--- a/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/factory/SystemCollectionViewFactory.kt
+++ b/widgets-collection/src/androidMain/kotlin/dev/icerock/moko/widgets/collection/SimpleCollectionViewFactory.kt
@@ -1,14 +1,16 @@
/*
- * Copyright 2019 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/
-package dev.icerock.moko.widgets.factory
+package dev.icerock.moko.widgets.collection
+import android.view.ViewGroup
+import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.StaggeredGridLayoutManager
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
+import dev.icerock.moko.units.UnitItem
import dev.icerock.moko.units.adapter.UnitsRecyclerViewAdapter
-import dev.icerock.moko.widgets.CollectionWidget
import dev.icerock.moko.widgets.core.View
import dev.icerock.moko.widgets.core.ViewBundle
import dev.icerock.moko.widgets.core.ViewFactory
@@ -18,17 +20,14 @@ import dev.icerock.moko.widgets.style.applyPaddingIfNeeded
import dev.icerock.moko.widgets.style.background.Background
import dev.icerock.moko.widgets.style.background.Fill
import dev.icerock.moko.widgets.style.background.Orientation
-import dev.icerock.moko.widgets.style.ext.toStaggeredGridLayoutManager
import dev.icerock.moko.widgets.style.view.MarginValues
import dev.icerock.moko.widgets.style.view.PaddingValues
import dev.icerock.moko.widgets.style.view.WidgetSize
import dev.icerock.moko.widgets.utils.androidId
import dev.icerock.moko.widgets.utils.bind
-import dev.icerock.moko.widgets.view.UnitItemDecorator
-actual class SystemCollectionViewFactory actual constructor(
+actual class SimpleCollectionViewFactory actual constructor(
private val orientation: Orientation,
- private val spanCount: Int,
private val padding: PaddingValues?,
private val margins: MarginValues?,
private val background: Background?
@@ -48,7 +47,7 @@ actual class SystemCollectionViewFactory actual constructor(
val recyclerView = RecyclerView(context).apply {
clipToPadding = false
layoutManager = StaggeredGridLayoutManager(
- spanCount,
+ 1, // in columned collection will be changed
orientation.toStaggeredGridLayoutManager()
)
adapter = unitsAdapter
@@ -56,7 +55,7 @@ actual class SystemCollectionViewFactory actual constructor(
id = widget.id.androidId
applyPaddingIfNeeded(padding)
- applyBackgroundIfNeeded(this@SystemCollectionViewFactory.background)
+ applyBackgroundIfNeeded(this@SimpleCollectionViewFactory.background)
}
val resultView: View = if (haveSwipeRefreshListener) {
@@ -79,11 +78,12 @@ actual class SystemCollectionViewFactory actual constructor(
widget.items.bind(lifecycleOwner) { units ->
val list = units.orEmpty()
+ val onReachEnd = widget.onReachEnd
unitsAdapter.units = when {
- widget.onReachEnd == null -> list
+ onReachEnd == null -> list
list.isEmpty() -> list
else -> list.subList(0, list.lastIndex) + UnitItemDecorator(list.last()) {
- widget.onReachEnd.invoke()
+ onReachEnd.invoke()
}
}
}
@@ -94,4 +94,28 @@ actual class SystemCollectionViewFactory actual constructor(
margins = margins
)
}
+
+ private fun Orientation.toStaggeredGridLayoutManager(): Int = when (this) {
+ Orientation.VERTICAL -> StaggeredGridLayoutManager.VERTICAL
+ Orientation.HORIZONTAL -> StaggeredGridLayoutManager.HORIZONTAL
+ }
+
+ private class UnitItemDecorator(
+ private val decorated: UnitItem,
+ val onBind: () -> Unit
+ ) : UnitItem {
+
+ override val itemId: Long get() = decorated.itemId
+
+ override val viewType: Int get() = decorated.viewType
+
+ override fun bindViewHolder(viewHolder: RecyclerView.ViewHolder) {
+ decorated.bindViewHolder(viewHolder)
+ onBind()
+ }
+
+ override fun createViewHolder(parent: ViewGroup, lifecycleOwner: LifecycleOwner): RecyclerView.ViewHolder {
+ return decorated.createViewHolder(parent, lifecycleOwner)
+ }
+ }
}
diff --git a/widgets/src/commonMain/kotlin/dev/icerock/moko/widgets/CollectionWidget.kt b/widgets-collection/src/commonMain/kotlin/dev/icerock/moko/widgets/collection/CollectionWidget.kt
similarity index 89%
rename from widgets/src/commonMain/kotlin/dev/icerock/moko/widgets/CollectionWidget.kt
rename to widgets-collection/src/commonMain/kotlin/dev/icerock/moko/widgets/collection/CollectionWidget.kt
index 3be42476..7bfff137 100644
--- a/widgets/src/commonMain/kotlin/dev/icerock/moko/widgets/CollectionWidget.kt
+++ b/widgets-collection/src/commonMain/kotlin/dev/icerock/moko/widgets/collection/CollectionWidget.kt
@@ -2,7 +2,7 @@
* Copyright 2019 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/
-package dev.icerock.moko.widgets
+package dev.icerock.moko.widgets.collection
import dev.icerock.moko.mvvm.livedata.LiveData
import dev.icerock.moko.units.CollectionUnitItem
@@ -13,10 +13,9 @@ import dev.icerock.moko.widgets.core.ViewFactory
import dev.icerock.moko.widgets.core.ViewFactoryContext
import dev.icerock.moko.widgets.core.Widget
import dev.icerock.moko.widgets.core.WidgetDef
-import dev.icerock.moko.widgets.factory.SystemCollectionViewFactory
import dev.icerock.moko.widgets.style.view.WidgetSize
-@WidgetDef(SystemCollectionViewFactory::class)
+@WidgetDef(SimpleCollectionViewFactory::class)
class CollectionWidget(
private val factory: ViewFactory>,
override val size: WS,
diff --git a/widgets/src/commonMain/kotlin/dev/icerock/moko/widgets/factory/SystemCollectionViewFactory.kt b/widgets-collection/src/commonMain/kotlin/dev/icerock/moko/widgets/collection/SimpleCollectionViewFactory.kt
similarity index 74%
rename from widgets/src/commonMain/kotlin/dev/icerock/moko/widgets/factory/SystemCollectionViewFactory.kt
rename to widgets-collection/src/commonMain/kotlin/dev/icerock/moko/widgets/collection/SimpleCollectionViewFactory.kt
index 1f7595ab..a9dc4aef 100644
--- a/widgets/src/commonMain/kotlin/dev/icerock/moko/widgets/factory/SystemCollectionViewFactory.kt
+++ b/widgets-collection/src/commonMain/kotlin/dev/icerock/moko/widgets/collection/SimpleCollectionViewFactory.kt
@@ -1,10 +1,9 @@
/*
- * Copyright 2019 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
+ * Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/
-package dev.icerock.moko.widgets.factory
+package dev.icerock.moko.widgets.collection
-import dev.icerock.moko.widgets.CollectionWidget
import dev.icerock.moko.widgets.core.ViewFactory
import dev.icerock.moko.widgets.style.background.Background
import dev.icerock.moko.widgets.style.background.Fill
@@ -13,9 +12,8 @@ import dev.icerock.moko.widgets.style.view.MarginValues
import dev.icerock.moko.widgets.style.view.PaddingValues
import dev.icerock.moko.widgets.style.view.WidgetSize
-expect class SystemCollectionViewFactory(
+expect class SimpleCollectionViewFactory(
orientation: Orientation = Orientation.VERTICAL,
- spanCount: Int = 2,
padding: PaddingValues? = null,
margins: MarginValues? = null,
background: Background? = null
diff --git a/widgets-collection/src/iosArm64Main b/widgets-collection/src/iosArm64Main
new file mode 120000
index 00000000..93d7d747
--- /dev/null
+++ b/widgets-collection/src/iosArm64Main
@@ -0,0 +1 @@
+iosMain
\ No newline at end of file
diff --git a/widgets-collection/src/iosMain/kotlin/dev/icerock/moko/widgets/collection/SimpleCollectionViewFactory.kt b/widgets-collection/src/iosMain/kotlin/dev/icerock/moko/widgets/collection/SimpleCollectionViewFactory.kt
new file mode 100644
index 00000000..3f1d7042
--- /dev/null
+++ b/widgets-collection/src/iosMain/kotlin/dev/icerock/moko/widgets/collection/SimpleCollectionViewFactory.kt
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package dev.icerock.moko.widgets.collection
+
+import cocoapods.mokoWidgetsCollection.ALCollectionFlowLayout
+import dev.icerock.moko.units.UnitCollectionViewDataSource
+import dev.icerock.moko.widgets.core.ViewBundle
+import dev.icerock.moko.widgets.core.ViewFactory
+import dev.icerock.moko.widgets.core.ViewFactoryContext
+import dev.icerock.moko.widgets.style.background.Background
+import dev.icerock.moko.widgets.style.background.Fill
+import dev.icerock.moko.widgets.style.background.Orientation
+import dev.icerock.moko.widgets.style.view.MarginValues
+import dev.icerock.moko.widgets.style.view.PaddingValues
+import dev.icerock.moko.widgets.style.view.WidgetSize
+import dev.icerock.moko.widgets.utils.Edges
+import dev.icerock.moko.widgets.utils.applyBackgroundIfNeeded
+import dev.icerock.moko.widgets.utils.bind
+import dev.icerock.moko.widgets.utils.toEdgeInsets
+import kotlinx.cinterop.readValue
+import kotlinx.cinterop.useContents
+import platform.CoreGraphics.CGRectZero
+import platform.UIKit.UICollectionView
+import platform.UIKit.UICollectionViewScrollDirection
+import platform.UIKit.UIColor
+import platform.UIKit.UIEdgeInsetsMake
+import platform.UIKit.UIEdgeInsetsZero
+import platform.UIKit.backgroundColor
+import platform.UIKit.translatesAutoresizingMaskIntoConstraints
+
+actual class SimpleCollectionViewFactory actual constructor(
+ private val orientation: Orientation,
+ private val padding: PaddingValues?,
+ private val margins: MarginValues?,
+ private val background: Background?
+) : ViewFactory> {
+
+ override fun build(
+ widget: CollectionWidget,
+ size: WS,
+ viewFactoryContext: ViewFactoryContext
+ ): ViewBundle {
+ val layoutAndDelegate = ALCollectionFlowLayout().apply {
+ sectionInset = UIEdgeInsetsZero.readValue()
+ minimumInteritemSpacing = 0.0
+ minimumLineSpacing = 0.0
+ scrollDirection = when (orientation) {
+ Orientation.HORIZONTAL -> UICollectionViewScrollDirection.UICollectionViewScrollDirectionHorizontal
+ Orientation.VERTICAL -> UICollectionViewScrollDirection.UICollectionViewScrollDirectionVertical
+ }
+ }
+
+ val collectionView = UICollectionView(
+ frame = CGRectZero.readValue(),
+ collectionViewLayout = layoutAndDelegate
+ ).apply {
+ backgroundColor = UIColor.clearColor
+
+ applyBackgroundIfNeeded(background)
+
+ when (orientation) {
+ Orientation.VERTICAL -> {
+ this.setAlwaysBounceHorizontal(false)
+ this.setShowsHorizontalScrollIndicator(false)
+ }
+ Orientation.HORIZONTAL -> {
+ this.setAlwaysBounceVertical(false)
+ this.setShowsVerticalScrollIndicator(false)
+ }
+ }
+
+ padding?.toEdgeInsets()?.also { insetsValue ->
+ val insets = insetsValue.useContents {
+ Edges(
+ top = this.top,
+ leading = this.left,
+ trailing = this.right,
+ bottom = this.bottom
+ )
+ }
+ contentInset = UIEdgeInsetsMake(
+ top = insets.top,
+ bottom = insets.bottom,
+ left = insets.leading,
+ right = insets.trailing
+ )
+ }
+ }
+ val unitDataSource = UnitCollectionViewDataSource(collectionView)
+
+ with(collectionView) {
+ translatesAutoresizingMaskIntoConstraints = false
+ dataSource = unitDataSource
+ }
+
+ widget.items.bind { unitDataSource.unitItems = it }
+
+ return ViewBundle(
+ view = collectionView,
+ size = size,
+ margins = margins
+ )
+ }
+
+// @Suppress(
+// "CONFLICTING_OVERLOADS",
+// "RETURN_TYPE_MISMATCH_ON_INHERITANCE",
+// "MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED",
+// "DIFFERENT_NAMES_FOR_THE_SAME_PARAMETER_IN_SUPERTYPES"
+// )
+// private class SpanCollectionViewLayout(
+// private val spanCount: Int,
+// private val orientation: Orientation
+// ) : UICollectionViewFlowLayout(), UICollectionViewDelegateFlowLayoutProtocol {
+// private val reusableStubs = mutableMapOf()
+// var dataSource: UnitCollectionViewDataSource? = null
+//
+// override fun collectionView(
+// collectionView: UICollectionView,
+// layout: UICollectionViewLayout,
+// sizeForItemAtIndexPath: NSIndexPath
+// ): CValue {
+//
+// println("Request cell for indexPath: ${sizeForItemAtIndexPath.debugDescription() ?: "unknown"}")
+//
+// val fixedItemSize = getFixedCellDimension(collectionView, spanCount, orientation)
+//
+// val position = sizeForItemAtIndexPath.item.toInt()
+//
+// val unit = dataSource!!.unitItems!![position]
+//
+// println("Request stub")
+//
+// val stub = getStub(collectionView, unit, sizeForItemAtIndexPath)
+// objc_sync_enter(stub)
+// stub.setTranslatesAutoresizingMaskIntoConstraints(false)
+// unit.bind(stub)
+//
+// with(stub.contentView) {
+// translatesAutoresizingMaskIntoConstraints = false
+// println("Bind unit to stub")
+//
+//
+// when (orientation) {
+// Orientation.VERTICAL -> {
+// val constraint = widthAnchor.constraintEqualToConstant(fixedItemSize)
+// constraint.setActive(true)
+// updateConstraints()
+// layoutSubviews()
+// val result = CGSizeMake(fixedItemSize, wrapContentHeight(fixedItemSize))
+// removeConstraint(constraint)
+// return result
+// }
+//
+// Orientation.HORIZONTAL -> {
+// //TODO: Copy logic from vertical
+// return CGSizeMake(wrapContentWidth(fixedItemSize), fixedItemSize)
+// }
+// }
+// }
+//
+// objc_sync_exit(stub)
+// }
+//
+// private fun getStub(
+// collectionView: UICollectionView,
+// unit: CollectionUnitItem,
+// indexPath: NSIndexPath
+// ): UICollectionViewCell {
+// println("Dequeue cell - ${unit.reusableIdentifier}")
+// val exist = reusableStubs[unit.reusableIdentifier]
+// return if (exist != null) {
+// println("Already stubbed, return")
+// exist
+// } else {
+// println("Dequeue stub")
+//
+// val stub = collectionView.dequeueReusableCellWithReuseIdentifier(
+// unit.reusableIdentifier,
+// indexPath
+// )
+// reusableStubs[unit.reusableIdentifier] = stub
+// stub
+// }
+// }
+// }
+}
+//
+//internal fun getFixedCellDimension(
+// forCollectionView: UICollectionView,
+// spanCount: Int,
+// andOrientation: Orientation
+//): CGFloat {
+// val collectionViewSize = forCollectionView.bounds.useContents { size }
+//
+// val sizeExtract: (CGSize) -> CGFloat
+// val padExtract: (UIEdgeInsets) -> CGFloat
+//
+// when (andOrientation) {
+// Orientation.VERTICAL -> {
+// sizeExtract = { it.width }
+// padExtract = { it.left + it.right }
+// }
+// Orientation.HORIZONTAL -> {
+// sizeExtract = { it.height }
+// padExtract = { it.top + it.bottom }
+// }
+// }
+// return (sizeExtract(collectionViewSize)
+// - forCollectionView.contentInset.useContents(padExtract)) / spanCount
+//}
\ No newline at end of file
diff --git a/widgets-collection/src/iosMain/swift/ALCollectionFlowLayout.swift b/widgets-collection/src/iosMain/swift/ALCollectionFlowLayout.swift
new file mode 100644
index 00000000..a6ccdf30
--- /dev/null
+++ b/widgets-collection/src/iosMain/swift/ALCollectionFlowLayout.swift
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+import UIKit
+
+@objc public class ALCollectionFlowLayout: UICollectionViewFlowLayout {
+ func widestCellWidth(bounds: CGRect) -> CGFloat {
+ guard let collectionView = collectionView else {
+ return 0
+ }
+
+ let insets = collectionView.contentInset
+ let width = bounds.width - insets.left - insets.right
+
+ if width < 0 { return 0 }
+ else { return width }
+ }
+
+ func updateEstimatedItemSize(bounds: CGRect, insets: UIEdgeInsets) {
+ let width: CGFloat
+ let height: CGFloat
+
+ if scrollDirection == .horizontal {
+ width = 200
+ height = bounds.height - insets.top - insets.bottom
+ } else {
+ width = bounds.width - insets.left - insets.right
+ height = 200
+ }
+
+ estimatedItemSize = CGSize(width: width, height: height)
+ }
+
+ override public func prepare() {
+ super.prepare()
+
+ guard let cv = collectionView else { return }
+
+ updateEstimatedItemSize(bounds: cv.bounds, insets: cv.adjustedContentInset)
+ }
+
+ override public func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
+ guard let cv = collectionView else { return false }
+
+ let oldSize = cv.bounds.size
+ guard oldSize != newBounds.size else { return false }
+
+ updateEstimatedItemSize(bounds: newBounds, insets: cv.adjustedContentInset)
+ return true
+ }
+}
diff --git a/widgets-collection/src/iosX64Main b/widgets-collection/src/iosX64Main
new file mode 120000
index 00000000..93d7d747
--- /dev/null
+++ b/widgets-collection/src/iosX64Main
@@ -0,0 +1 @@
+iosMain
\ No newline at end of file
diff --git a/widgets-datetime-picker/build.gradle.kts b/widgets-datetime-picker/build.gradle.kts
new file mode 100644
index 00000000..efbeadad
--- /dev/null
+++ b/widgets-datetime-picker/build.gradle.kts
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+plugins {
+ id("com.android.library")
+ id("org.jetbrains.kotlin.multiplatform")
+ id("dev.icerock.mobile.multiplatform")
+ id("kotlin-android-extensions")
+ id("maven-publish")
+}
+
+group = "dev.icerock.moko"
+version = Versions.Libs.MultiPlatform.mokoWidgets
+
+android {
+ compileSdkVersion(Versions.Android.compileSdk)
+
+ defaultConfig {
+ minSdkVersion(Versions.Android.minSdk)
+ targetSdkVersion(Versions.Android.targetSdk)
+ }
+}
+
+dependencies {
+ mppLibrary(Deps.Libs.MultiPlatform.kotlinStdLib)
+ mppLibrary(Deps.Libs.MultiPlatform.coroutines)
+
+ mppLibrary(Deps.Libs.MultiPlatform.mokoMvvm)
+ mppLibrary(Deps.Libs.MultiPlatform.mokoResources)
+ mppLibrary(Deps.Libs.MultiPlatform.mokoWidgets)
+ mppLibrary(Deps.Libs.MultiPlatform.klock)
+
+ androidLibrary(Deps.Libs.Android.appCompat)
+ androidLibrary(Deps.Libs.Android.lifecycle)
+}
+
+publishing {
+ repositories.maven("https://api.bintray.com/maven/icerockdev/moko/moko-widgets/;publish=1") {
+ name = "bintray"
+
+ credentials {
+ username = System.getProperty("BINTRAY_USER")
+ password = System.getProperty("BINTRAY_KEY")
+ }
+ }
+}
diff --git a/widgets-datetime-picker/src/androidMain/AndroidManifest.xml b/widgets-datetime-picker/src/androidMain/AndroidManifest.xml
new file mode 100644
index 00000000..e30bbf93
--- /dev/null
+++ b/widgets-datetime-picker/src/androidMain/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/screen/DatePickerDialogHandler.kt b/widgets-datetime-picker/src/androidMain/kotlin/dev/icerock/moko/widgets/datetimepicker/DatePickerDialogHandler.kt
similarity index 97%
rename from widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/screen/DatePickerDialogHandler.kt
rename to widgets-datetime-picker/src/androidMain/kotlin/dev/icerock/moko/widgets/datetimepicker/DatePickerDialogHandler.kt
index dfe849b6..996e40b2 100644
--- a/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/screen/DatePickerDialogHandler.kt
+++ b/widgets-datetime-picker/src/androidMain/kotlin/dev/icerock/moko/widgets/datetimepicker/DatePickerDialogHandler.kt
@@ -2,7 +2,7 @@
* Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/
-package dev.icerock.moko.widgets.screen
+package dev.icerock.moko.widgets.datetimepicker
import android.app.DatePickerDialog
import android.app.Dialog
@@ -13,6 +13,7 @@ import androidx.fragment.app.FragmentManager
import com.soywiz.klock.DateTime
import dev.icerock.moko.graphics.Color
import dev.icerock.moko.parcelize.Parcelize
+import dev.icerock.moko.widgets.screen.Screen
import java.util.*
import kotlin.properties.ReadOnlyProperty
diff --git a/widgets-datetime-picker/src/androidMain/kotlin/dev/icerock/moko/widgets/datetimepicker/TimePickerDialogExt.kt b/widgets-datetime-picker/src/androidMain/kotlin/dev/icerock/moko/widgets/datetimepicker/TimePickerDialogExt.kt
new file mode 100644
index 00000000..6551e0ba
--- /dev/null
+++ b/widgets-datetime-picker/src/androidMain/kotlin/dev/icerock/moko/widgets/datetimepicker/TimePickerDialogExt.kt
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package dev.icerock.moko.widgets.datetimepicker
+
+import android.app.Dialog
+import android.app.TimePickerDialog
+import android.os.Bundle
+import android.os.Parcelable
+import androidx.fragment.app.DialogFragment
+import androidx.fragment.app.FragmentManager
+import dev.icerock.moko.graphics.Color
+import dev.icerock.moko.widgets.screen.Screen
+import kotlinx.android.parcel.Parcelize
+import kotlin.properties.ReadOnlyProperty
+
+actual class TimePickerDialogHandler
+
+actual fun Screen<*>.registerTimePickerDialogHandler(
+ positive: ((dialogId: Int, hour: Int, minute: Int) -> Unit)?,
+ negative: ((dialogId: Int) -> Unit)?
+): ReadOnlyProperty, TimePickerDialogHandler> =
+ registerAttachFragmentHook(TimePickerDialogHandler()) { fragment ->
+ if (fragment !is TimePickerDialogFragment) return@registerAttachFragmentHook
+
+ fragment.positiveAction = positive
+ fragment.negativeAction = negative
+ }
+
+actual fun Screen<*>.showTimePickerDialog(
+ dialogId: Int,
+ handler: TimePickerDialogHandler,
+ factory: TimePickerDialogBuilder.() -> Unit
+) {
+ TimePickerDialogBuilder(dialogId, childFragmentManager).apply {
+ factory(this)
+ show()
+ }
+}
+
+actual class TimePickerDialogBuilder(
+ private val dialogId: Int,
+ private val fragmentManager: FragmentManager
+) {
+ private var initialHour = 12
+ private var initialMinute = 5
+ private var is24HoursFormat = true
+
+ /**
+ * Don't work for Android, it takes accent color from Theme.
+ */
+ actual fun setAccentColor(color: Color) {}
+
+ actual fun setInitialHour(hour: Int) {
+ initialHour = validateHours(hour)
+ }
+
+ actual fun setInitialMinutes(minute: Int) {
+ initialMinute = validateMinutes(minute)
+ }
+
+ actual fun is24HoursFormat(flag: Boolean) {
+ is24HoursFormat = flag
+ }
+
+ internal fun show() {
+ TimePickerDialogFragment(
+ TimePickerDialogFragment.Args(dialogId, initialHour, initialMinute, is24HoursFormat)
+ ).show(fragmentManager, null)
+ }
+}
+
+class TimePickerDialogFragment : DialogFragment() {
+ var positiveAction: ((dialogId: Int, hour: Int, minute: Int) -> Unit)? = null
+ var negativeAction: ((dialogId: Int) -> Unit)? = null
+
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ val args = arguments?.getParcelable(ARG_KEY)
+ requireNotNull(args) { "Can't be created without arguments." }
+
+ val dialogId = args.dialogId
+ val dialog = TimePickerDialog(
+ context,
+ TimePickerDialog.OnTimeSetListener { _, hour, minute ->
+ positiveAction?.invoke(dialogId, hour, minute)
+ },
+ args.initialHour,
+ args.initialMinute,
+ args.is24HoursFormat
+ )
+
+ dialog.setOnCancelListener { negativeAction?.invoke(dialogId) }
+ return dialog
+ }
+
+ @Parcelize
+ data class Args(
+ val dialogId: Int,
+ val initialHour: Int,
+ val initialMinute: Int,
+ val is24HoursFormat: Boolean
+ ) : Parcelable
+
+ companion object {
+ private const val ARG_KEY = "arg_bundle"
+
+ operator fun invoke(args: Args) = TimePickerDialogFragment().apply {
+ arguments = Bundle().apply {
+ putParcelable(ARG_KEY, args)
+ }
+ }
+
+ }
+}
diff --git a/widgets/src/commonMain/kotlin/dev/icerock/moko/widgets/screen/ShowDatePickerExt.kt b/widgets-datetime-picker/src/commonMain/kotlin/dev/icerock/moko/widgets/datetimepicker/ShowDatePickerExt.kt
similarity index 89%
rename from widgets/src/commonMain/kotlin/dev/icerock/moko/widgets/screen/ShowDatePickerExt.kt
rename to widgets-datetime-picker/src/commonMain/kotlin/dev/icerock/moko/widgets/datetimepicker/ShowDatePickerExt.kt
index fd4f6fd7..da34a945 100644
--- a/widgets/src/commonMain/kotlin/dev/icerock/moko/widgets/screen/ShowDatePickerExt.kt
+++ b/widgets-datetime-picker/src/commonMain/kotlin/dev/icerock/moko/widgets/datetimepicker/ShowDatePickerExt.kt
@@ -2,10 +2,11 @@
* Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/
-package dev.icerock.moko.widgets.screen
+package dev.icerock.moko.widgets.datetimepicker
import com.soywiz.klock.DateTime
import dev.icerock.moko.graphics.Color
+import dev.icerock.moko.widgets.screen.Screen
import kotlin.properties.ReadOnlyProperty
expect class DatePickerDialogHandler
diff --git a/widgets-datetime-picker/src/commonMain/kotlin/dev/icerock/moko/widgets/datetimepicker/TimePickerDialog.kt b/widgets-datetime-picker/src/commonMain/kotlin/dev/icerock/moko/widgets/datetimepicker/TimePickerDialog.kt
new file mode 100644
index 00000000..c7fa701f
--- /dev/null
+++ b/widgets-datetime-picker/src/commonMain/kotlin/dev/icerock/moko/widgets/datetimepicker/TimePickerDialog.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package dev.icerock.moko.widgets.datetimepicker
+
+import dev.icerock.moko.graphics.Color
+import dev.icerock.moko.widgets.screen.Screen
+import kotlin.properties.ReadOnlyProperty
+
+expect class TimePickerDialogHandler
+
+expect fun Screen<*>.registerTimePickerDialogHandler(
+ positive: ((dialogId: Int, hour: Int, minute: Int) -> Unit)?,
+ negative: ((dialogId: Int) -> Unit)? = null
+): ReadOnlyProperty, TimePickerDialogHandler>
+
+expect class TimePickerDialogBuilder {
+ fun setAccentColor(color: Color)
+ fun setInitialHour(hour: Int)
+ fun setInitialMinutes(minute: Int)
+ fun is24HoursFormat(flag: Boolean)
+}
+
+expect fun Screen<*>.showTimePickerDialog(
+ dialogId: Int,
+ handler: TimePickerDialogHandler,
+ factory: TimePickerDialogBuilder.() -> Unit
+)
+
+internal fun validateHours(hour: Int) = when {
+ hour < 0 -> 0
+ hour > 23 -> 23
+ else -> hour
+}
+
+internal fun validateMinutes(minute: Int) = when {
+ minute < 0 -> 0
+ minute > 59 -> 59
+ else -> minute
+}
diff --git a/widgets-datetime-picker/src/iosArm64Main b/widgets-datetime-picker/src/iosArm64Main
new file mode 120000
index 00000000..93d7d747
--- /dev/null
+++ b/widgets-datetime-picker/src/iosArm64Main
@@ -0,0 +1 @@
+iosMain
\ No newline at end of file
diff --git a/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/screen/ShowDatePickerExt.kt b/widgets-datetime-picker/src/iosMain/kotlin/dev/icerock/moko/widgets/datetimepicker/ShowDatePickerExt.kt
similarity index 98%
rename from widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/screen/ShowDatePickerExt.kt
rename to widgets-datetime-picker/src/iosMain/kotlin/dev/icerock/moko/widgets/datetimepicker/ShowDatePickerExt.kt
index 9c7b6edc..2ad73e68 100644
--- a/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/screen/ShowDatePickerExt.kt
+++ b/widgets-datetime-picker/src/iosMain/kotlin/dev/icerock/moko/widgets/datetimepicker/ShowDatePickerExt.kt
@@ -1,11 +1,12 @@
/*
* Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/
-package dev.icerock.moko.widgets.screen
+package dev.icerock.moko.widgets.datetimepicker
import com.soywiz.klock.DateTime
import dev.icerock.moko.graphics.Color
import dev.icerock.moko.graphics.toUIColor
+import dev.icerock.moko.widgets.screen.Screen
import dev.icerock.moko.widgets.utils.setEventHandler
import kotlin.properties.ReadOnlyProperty
import platform.UIKit.UIModalPresentationOverCurrentContext
diff --git a/widgets-datetime-picker/src/iosMain/kotlin/dev/icerock/moko/widgets/datetimepicker/TimePickerDialogExt.kt b/widgets-datetime-picker/src/iosMain/kotlin/dev/icerock/moko/widgets/datetimepicker/TimePickerDialogExt.kt
new file mode 100644
index 00000000..c9c700ae
--- /dev/null
+++ b/widgets-datetime-picker/src/iosMain/kotlin/dev/icerock/moko/widgets/datetimepicker/TimePickerDialogExt.kt
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package dev.icerock.moko.widgets.datetimepicker
+
+import dev.icerock.moko.graphics.Color
+import dev.icerock.moko.graphics.toUIColor
+import dev.icerock.moko.widgets.screen.Screen
+import dev.icerock.moko.widgets.utils.setEventHandler
+import platform.Foundation.NSBundle
+import platform.Foundation.NSCalendar
+import platform.Foundation.NSCalendarUnitHour
+import platform.Foundation.NSCalendarUnitMinute
+import platform.Foundation.NSDate
+import platform.UIKit.UIApplication
+import platform.UIKit.UIButton
+import platform.UIKit.UIColor
+import platform.UIKit.UIControlEventTouchUpInside
+import platform.UIKit.UIControlStateNormal
+import platform.UIKit.UIDatePicker
+import platform.UIKit.UIDatePickerMode
+import platform.UIKit.UIModalPresentationOverCurrentContext
+import platform.UIKit.UIView
+import platform.UIKit.UIViewController
+import platform.UIKit.addSubview
+import platform.UIKit.backgroundColor
+import platform.UIKit.bottomAnchor
+import platform.UIKit.heightAnchor
+import platform.UIKit.leadingAnchor
+import platform.UIKit.safeAreaLayoutGuide
+import platform.UIKit.topAnchor
+import platform.UIKit.trailingAnchor
+import platform.UIKit.translatesAutoresizingMaskIntoConstraints
+import kotlin.properties.ReadOnlyProperty
+
+actual class TimePickerDialogHandler(
+ val positive: ((dialogId: Int, hour: Int, minute: Int) -> Unit)?,
+ val negative: ((dialogId: Int) -> Unit)?
+)
+
+actual fun Screen<*>.registerTimePickerDialogHandler(
+ positive: ((dialogId: Int, hour: Int, minute: Int) -> Unit)?,
+ negative: ((dialogId: Int) -> Unit)?
+): ReadOnlyProperty, TimePickerDialogHandler> {
+ return createConstReadOnlyProperty(TimePickerDialogHandler(positive, negative))
+}
+
+actual fun Screen<*>.showTimePickerDialog(
+ dialogId: Int,
+ handler: TimePickerDialogHandler,
+ factory: TimePickerDialogBuilder.() -> Unit
+) {
+ TimePickerDialogBuilder().apply {
+ factory(this)
+ val controller = createViewController(handler, dialogId)
+ controller.modalPresentationStyle = UIModalPresentationOverCurrentContext
+ this@showTimePickerDialog.viewController.presentViewController(
+ controller,
+ animated = true,
+ completion = null
+ )
+ }
+}
+
+actual class TimePickerDialogBuilder {
+ private var initialHour = 12
+ private var initialMinute = 5
+ private var accentColor: Color? = null
+
+ actual fun setAccentColor(color: Color) {
+ accentColor = color
+ }
+
+ actual fun setInitialHour(hour: Int) {
+ initialHour = validateHours(hour)
+ }
+
+ actual fun setInitialMinutes(minute: Int) {
+ initialMinute = validateMinutes(minute)
+ }
+
+ /**
+ * Don't work for iOS, it takes format from user local settings in setting.app.
+ */
+ actual fun is24HoursFormat(flag: Boolean) {}
+
+ internal fun createViewController(
+ handler: TimePickerDialogHandler,
+ dialogId: Int
+ ) = TimePickerController(accentColor, initialHour, initialMinute, handler, dialogId)
+}
+
+class TimePickerController(
+ private val accentColor: Color?,
+ private val initialHour: Int,
+ private val initialMinute: Int,
+ private val handler: TimePickerDialogHandler,
+ private val dialogId: Int
+) : UIViewController(nibName = null, bundle = null) {
+
+ override fun viewDidLoad() {
+ super.viewDidLoad()
+
+ view.backgroundColor = UIColor.blackColor.colorWithAlphaComponent(0.7)
+
+ val pickerBackground = UIView()
+ view.addSubview(pickerBackground)
+ pickerBackground.translatesAutoresizingMaskIntoConstraints = false
+ pickerBackground.backgroundColor = UIColor.whiteColor
+ pickerBackground.leadingAnchor.constraintEqualToAnchor(
+ anchor = view.leadingAnchor
+ ).active = true
+ pickerBackground.trailingAnchor.constraintEqualToAnchor(
+ anchor = view.trailingAnchor
+ ).active = true
+ pickerBackground.bottomAnchor.constraintEqualToAnchor(
+ anchor = view.bottomAnchor
+ ).active = true
+
+ val datePicker = UIDatePicker()
+ datePicker.translatesAutoresizingMaskIntoConstraints = false
+ datePicker.datePickerMode = UIDatePickerMode.UIDatePickerModeTime
+ view.addSubview(datePicker)
+ datePicker.leadingAnchor.constraintEqualToAnchor(
+ anchor = view.leadingAnchor
+ ).active = true
+ datePicker.trailingAnchor.constraintEqualToAnchor(
+ anchor = view.trailingAnchor
+ ).active = true
+ datePicker.bottomAnchor.constraintEqualToAnchor(
+ anchor = view.safeAreaLayoutGuide.bottomAnchor
+ ).active = true
+ datePicker.heightAnchor.constraintEqualToConstant(232.0)
+
+ pickerBackground.topAnchor.constraintEqualToAnchor(
+ anchor = datePicker.topAnchor
+ ).active = true
+
+ val controlPanel = UIView()
+ controlPanel.translatesAutoresizingMaskIntoConstraints = false
+ controlPanel.backgroundColor = UIColor(red = 0.97, green = 0.97, blue = 0.97, alpha = 1.0)
+ view.addSubview(controlPanel)
+ controlPanel.leadingAnchor.constraintEqualToAnchor(
+ anchor = view.leadingAnchor
+ ).active = true
+ controlPanel.trailingAnchor.constraintEqualToAnchor(
+ anchor = view.trailingAnchor
+ ).active = true
+ controlPanel.bottomAnchor.constraintEqualToAnchor(
+ anchor = datePicker.topAnchor
+ ).active = true
+ controlPanel.heightAnchor.constraintEqualToConstant(44.0)
+
+ val bundle = NSBundle.bundleForClass(UIApplication)
+ val doneButton = UIButton()
+ doneButton.translatesAutoresizingMaskIntoConstraints = false
+ doneButton.setTitle(
+ title = bundle.localizedStringForKey(
+ key = "Done",
+ value = "Done",
+ table = null
+ ) ?: "Done",
+ forState = UIControlStateNormal
+ )
+ if (accentColor != null) {
+ doneButton.setTitleColor(accentColor.toUIColor(), UIControlStateNormal)
+ }
+ controlPanel.addSubview(doneButton)
+ doneButton.trailingAnchor.constraintEqualToAnchor(
+ anchor = controlPanel.trailingAnchor,
+ constant = -16.0
+ ).active = true
+ doneButton.bottomAnchor.constraintEqualToAnchor(
+ anchor = controlPanel.bottomAnchor
+ ).active = true
+ doneButton.topAnchor.constraintEqualToAnchor(
+ anchor = controlPanel.topAnchor
+ ).active = true
+
+ val cancelButton = UIButton()
+ cancelButton.translatesAutoresizingMaskIntoConstraints = false
+ cancelButton.setTitle(
+ title = bundle.localizedStringForKey(
+ key = "Cancel",
+ value = "Cancel",
+ table = null
+ ) ?: "Cancel",
+ forState = UIControlStateNormal
+ )
+ if (accentColor != null) {
+ cancelButton.setTitleColor(accentColor.toUIColor(), UIControlStateNormal)
+ }
+ controlPanel.addSubview(cancelButton)
+ cancelButton.leadingAnchor.constraintEqualToAnchor(
+ anchor = controlPanel.leadingAnchor,
+ constant = 16.0
+ ).active = true
+ cancelButton.bottomAnchor.constraintEqualToAnchor(
+ anchor = controlPanel.bottomAnchor
+ ).active = true
+ cancelButton.topAnchor.constraintEqualToAnchor(
+ anchor = controlPanel.topAnchor
+ ).active = true
+
+ val initialComponents = NSCalendar.currentCalendar.components(
+ NSCalendarUnitHour or NSCalendarUnitMinute,
+ NSDate()
+ ).apply {
+ setHour(initialHour.toLong())
+ setMinute(initialMinute.toLong())
+ }
+ NSCalendar.currentCalendar.dateFromComponents(initialComponents)?.let {
+ datePicker.setDate(it)
+ }
+
+ doneButton.setEventHandler(UIControlEventTouchUpInside) {
+ this.dismissViewControllerAnimated(flag = true, completion = null)
+ val hour =
+ NSCalendar.currentCalendar.components(NSCalendarUnitHour, datePicker.date).hour
+ val minute =
+ NSCalendar.currentCalendar.components(NSCalendarUnitMinute, datePicker.date).minute
+ handler.positive?.invoke(dialogId, hour.toInt(), minute.toInt())
+ }
+ cancelButton.setEventHandler(UIControlEventTouchUpInside) {
+ this.dismissViewControllerAnimated(flag = true, completion = null)
+ handler.negative?.invoke(dialogId)
+ }
+ }
+
+}
diff --git a/widgets-datetime-picker/src/iosX64Main b/widgets-datetime-picker/src/iosX64Main
new file mode 120000
index 00000000..93d7d747
--- /dev/null
+++ b/widgets-datetime-picker/src/iosX64Main
@@ -0,0 +1 @@
+iosMain
\ No newline at end of file
diff --git a/widgets/build.gradle.kts b/widgets/build.gradle.kts
index b7e13595..7fbea83f 100644
--- a/widgets/build.gradle.kts
+++ b/widgets/build.gradle.kts
@@ -36,7 +36,6 @@ dependencies {
mppLibrary(Deps.Libs.MultiPlatform.mokoMedia)
mppLibrary(Deps.Libs.MultiPlatform.mokoGraphics)
mppLibrary(Deps.Libs.MultiPlatform.mokoParcelize)
- mppLibrary(Deps.Libs.MultiPlatform.klock)
androidLibrary(Deps.Libs.Android.appCompat)
androidLibrary(Deps.Libs.Android.fragment)
diff --git a/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/factory/ButtonWithIconViewFactory.kt b/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/factory/ButtonWithIconViewFactory.kt
index 6db144c4..874535c4 100644
--- a/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/factory/ButtonWithIconViewFactory.kt
+++ b/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/factory/ButtonWithIconViewFactory.kt
@@ -86,6 +86,7 @@ actual class ButtonWithIconViewFactory actual constructor(
button.applyStateBackgroundIfNeeded(background)
button.supportBackgroundTintList = null
button.supportBackgroundTintMode = null
+ button.iconTint = null
button.applyPaddingIfNeeded(padding)
if (androidElevationEnabled == false && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
diff --git a/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/factory/FloatingLabelInputViewFactory.kt b/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/factory/FloatingLabelInputViewFactory.kt
index 36d37550..4c62c6bc 100644
--- a/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/factory/FloatingLabelInputViewFactory.kt
+++ b/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/factory/FloatingLabelInputViewFactory.kt
@@ -139,6 +139,7 @@ actual class FloatingLabelInputViewFactory actual constructor(
collapsingTextHelper.collapsedTypeface = when (it.fontStyle) {
FontStyle.BOLD -> Typeface.DEFAULT_BOLD
FontStyle.MEDIUM -> Typeface.DEFAULT
+ FontStyle.ITALIC -> Typeface.create(Typeface.DEFAULT, Typeface.ITALIC)
}
collapsingTextHelper.expandedTypeface = collapsingTextHelper.collapsedTypeface
}
diff --git a/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/factory/SystemImageViewFactory.kt b/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/factory/SystemImageViewFactory.kt
index f7a55bb4..f2a7a14d 100644
--- a/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/factory/SystemImageViewFactory.kt
+++ b/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/factory/SystemImageViewFactory.kt
@@ -11,6 +11,7 @@ import dev.icerock.moko.widgets.core.ViewBundle
import dev.icerock.moko.widgets.core.ViewFactory
import dev.icerock.moko.widgets.core.ViewFactoryContext
import dev.icerock.moko.widgets.style.view.MarginValues
+import dev.icerock.moko.widgets.style.view.SizeSpec
import dev.icerock.moko.widgets.style.view.WidgetSize
import dev.icerock.moko.widgets.utils.bind
import dev.icerock.moko.widgets.utils.dp
@@ -35,6 +36,13 @@ actual class SystemImageViewFactory actual constructor(
ImageWidget.ScaleType.FILL -> imageView.scaleType = ImageView.ScaleType.CENTER_CROP
ImageWidget.ScaleType.FIT -> imageView.scaleType = ImageView.ScaleType.CENTER_INSIDE
}
+ if ((size is WidgetSize.Const<*, *> &&
+ (size.width is SizeSpec.WrapContent || size.height is SizeSpec.WrapContent)) ||
+ (size is WidgetSize.AspectByWidth<*> && size.width is SizeSpec.WrapContent) ||
+ (size is WidgetSize.AspectByHeight<*> && size.height is SizeSpec.WrapContent)
+ ) {
+ imageView.adjustViewBounds = true
+ }
widget.image.bind(lifecycleOwner) { image ->
if (image == null) {
diff --git a/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/factory/SystemTextViewFactory.kt b/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/factory/SystemTextViewFactory.kt
index 0ee1c487..a5f01663 100644
--- a/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/factory/SystemTextViewFactory.kt
+++ b/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/factory/SystemTextViewFactory.kt
@@ -6,9 +6,9 @@ package dev.icerock.moko.widgets.factory
import android.annotation.SuppressLint
import android.text.Html
+import android.text.TextUtils
import android.text.method.LinkMovementMethod
import android.view.Gravity
-import android.widget.TextView
import androidx.appcompat.widget.AppCompatTextView
import dev.icerock.moko.graphics.Color
import dev.icerock.moko.widgets.TextWidget
@@ -65,7 +65,13 @@ actual class SystemTextViewFactory actual constructor(
}
}
}
- widget.text.bind(lifecycleOwner) { textView.text = it?.toString(context)?.run(strProcessing) }
+ widget.maxLines?.bind(lifecycleOwner) {
+ textView.maxLines = (it ?: Int.MAX_VALUE)
+ textView.ellipsize = TextUtils.TruncateAt.END
+ }
+ widget.text.bind(lifecycleOwner) {
+ textView.text = it?.toString(context)?.run(strProcessing)
+ }
if (isHtmlConverted) {
textView.movementMethod = LinkMovementMethod.getInstance()
diff --git a/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/screen/Screen.kt b/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/screen/Screen.kt
index 15cd758c..d8bce85b 100644
--- a/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/screen/Screen.kt
+++ b/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/screen/Screen.kt
@@ -51,6 +51,10 @@ actual abstract class Screen : Fragment() {
return EventsDispatcher(mainExecutor)
}
+ actual open fun onViewCreated() {
+
+ }
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -59,6 +63,7 @@ actual abstract class Screen : Fragment() {
resultCode = getIntNullable(RESULT_CODE_KEY)
screenId = getIntNullable(SCREEN_ID_KEY)
}
+ onViewCreated()
}
override fun onResume() {
diff --git a/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/style/NavigationBarNormal.kt b/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/style/NavigationBarNormal.kt
index af6c340f..e3a0ba0d 100644
--- a/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/style/NavigationBarNormal.kt
+++ b/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/style/NavigationBarNormal.kt
@@ -46,6 +46,7 @@ fun NavigationBar.Normal.apply(
val style = when (fontStyle) {
FontStyle.BOLD -> Typeface.BOLD
FontStyle.MEDIUM -> Typeface.NORMAL
+ FontStyle.ITALIC -> Typeface.ITALIC
}
val styleSpan = StyleSpan(style)
setSpan(styleSpan, 0, title.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
diff --git a/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/style/NavigationBarSearch.kt b/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/style/NavigationBarSearch.kt
index 0a53f4f1..d4c59c2c 100644
--- a/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/style/NavigationBarSearch.kt
+++ b/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/style/NavigationBarSearch.kt
@@ -48,6 +48,7 @@ fun NavigationBar.Search.apply(
val style = when (fontStyle) {
FontStyle.BOLD -> Typeface.BOLD
FontStyle.MEDIUM -> Typeface.NORMAL
+ FontStyle.ITALIC -> Typeface.ITALIC
}
val styleSpan = StyleSpan(style)
setSpan(styleSpan, 0, title.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
diff --git a/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/style/ext/OrientationExt.kt b/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/style/ext/OrientationExt.kt
index 16ff46bb..18825d3f 100644
--- a/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/style/ext/OrientationExt.kt
+++ b/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/style/ext/OrientationExt.kt
@@ -31,8 +31,3 @@ internal fun Orientation.toRecyclerView(): Int = when (this) {
Orientation.VERTICAL -> RecyclerView.VERTICAL
Orientation.HORIZONTAL -> RecyclerView.HORIZONTAL
}
-
-internal fun Orientation.toStaggeredGridLayoutManager(): Int = when (this) {
- Orientation.VERTICAL -> StaggeredGridLayoutManager.VERTICAL
- Orientation.HORIZONTAL -> StaggeredGridLayoutManager.HORIZONTAL
-}
diff --git a/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/style/fontStyle.kt b/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/style/fontStyle.kt
index 5567a232..5dd87c23 100644
--- a/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/style/fontStyle.kt
+++ b/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/style/fontStyle.kt
@@ -12,5 +12,6 @@ fun TextView.applyFontStyle(fontStyle: FontStyle) {
when (fontStyle) {
FontStyle.BOLD -> setTypeface(typeface, Typeface.BOLD)
FontStyle.MEDIUM -> setTypeface(typeface, Typeface.NORMAL)
+ FontStyle.ITALIC -> setTypeface(typeface, Typeface.ITALIC)
}
}
diff --git a/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/units/WidgetsCollectionUnitItem.kt b/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/units/WidgetsCollectionUnitItem.kt
index efb94a6d..37d603b6 100644
--- a/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/units/WidgetsCollectionUnitItem.kt
+++ b/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/units/WidgetsCollectionUnitItem.kt
@@ -4,4 +4,127 @@
package dev.icerock.moko.widgets.units
-actual typealias WidgetsCollectionUnitItem = WidgetsTableUnitItem
+import android.content.Context
+import android.util.DisplayMetrics
+import android.view.View
+import android.view.ViewGroup
+import androidx.lifecycle.LifecycleOwner
+import androidx.recyclerview.widget.RecyclerView
+import dev.icerock.moko.mvvm.livedata.LiveData
+import dev.icerock.moko.mvvm.livedata.MutableLiveData
+import dev.icerock.moko.units.UnitItem
+import dev.icerock.moko.widgets.core.ViewFactoryContext
+import dev.icerock.moko.widgets.core.Widget
+import dev.icerock.moko.widgets.style.ext.applyMargin
+import dev.icerock.moko.widgets.style.ext.toPlatformSize
+import dev.icerock.moko.widgets.style.view.SizeSpec
+import dev.icerock.moko.widgets.style.view.WidgetSize
+import dev.icerock.moko.widgets.view.AspectRatioFrameLayout
+
+actual abstract class WidgetsCollectionUnitItem actual constructor(
+ override val itemId: Long,
+ val data: T
+) : UnitItem {
+ actual abstract val reuseId: String
+ actual abstract fun createWidget(data: LiveData): Widget
+
+ override val viewType: Int by lazy { reuseId.hashCode() }
+
+ override fun createViewHolder(
+ parent: ViewGroup,
+ lifecycleOwner: LifecycleOwner
+ ): RecyclerView.ViewHolder {
+ val mutableData: MutableLiveData = MutableLiveData(initialValue = data)
+ val widget: Widget = createWidget(mutableData)
+ val context: Context = parent.context
+ val view: View = createView(widget, context, lifecycleOwner, parent)
+ return ViewHolder(mutableData, view)
+ }
+
+ override fun bindViewHolder(viewHolder: RecyclerView.ViewHolder) {
+ val widgetViewHolder = viewHolder as ViewHolder
+ widgetViewHolder.mutableData.value = data
+ }
+
+ private fun createView(
+ widget: Widget,
+ context: Context,
+ lifecycleOwner: LifecycleOwner,
+ parent: ViewGroup
+ ): View {
+ val viewBundle = widget.buildView(
+ ViewFactoryContext(
+ context = context,
+ lifecycleOwner = lifecycleOwner,
+ parent = parent
+ )
+ )
+
+ val dm = context.resources.displayMetrics
+ val (lp, view) = (viewBundle.size to viewBundle.view)
+ .toRecyclerViewLayoutParams(dm)
+
+ viewBundle.margins?.let { lp.applyMargin(dm, it) }
+
+ return view.apply {
+ layoutParams = lp
+ }
+ }
+
+ fun Pair.toRecyclerViewLayoutParams(
+ dm: DisplayMetrics
+ ): Pair {
+ val widgetSize = this.first
+ val view = this.second
+ return when (widgetSize) {
+ is WidgetSize.Const -> {
+ RecyclerView.LayoutParams(
+ widgetSize.width.toPlatformSize(dm),
+ widgetSize.height.toPlatformSize(dm)
+ ) to view
+ }
+ is WidgetSize.AspectByWidth -> {
+ val lp = RecyclerView.LayoutParams(
+ widgetSize.width.toPlatformSize(dm),
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+
+ lp to AspectRatioFrameLayout(
+ context = view.context,
+ aspectRatio = widgetSize.aspectRatio,
+ aspectByWidth = true
+ ).apply {
+ addView(
+ view,
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT
+ )
+ }
+ }
+ is WidgetSize.AspectByHeight -> {
+ val lp = RecyclerView.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ widgetSize.height.toPlatformSize(dm)
+ )
+
+ lp to AspectRatioFrameLayout(
+ context = view.context,
+ aspectRatio = widgetSize.aspectRatio,
+ aspectByWidth = false
+ ).apply {
+ addView(
+ view,
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT
+ )
+ }
+ }
+ }
+ }
+
+ private class ViewHolder(
+ val mutableData: MutableLiveData,
+ view: View
+ ) : RecyclerView.ViewHolder(view)
+}
+
diff --git a/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/units/WidgetsTableUnitItem.kt b/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/units/WidgetsTableUnitItem.kt
index 7c20cd8b..a0c70fa8 100644
--- a/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/units/WidgetsTableUnitItem.kt
+++ b/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/units/WidgetsTableUnitItem.kt
@@ -4,126 +4,40 @@
package dev.icerock.moko.widgets.units
-import android.content.Context
-import android.util.DisplayMetrics
-import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.RecyclerView
import dev.icerock.moko.mvvm.livedata.LiveData
-import dev.icerock.moko.mvvm.livedata.MutableLiveData
-import dev.icerock.moko.units.UnitItem
-import dev.icerock.moko.widgets.core.ViewFactoryContext
+import dev.icerock.moko.units.TableUnitItem
import dev.icerock.moko.widgets.core.Widget
-import dev.icerock.moko.widgets.style.ext.applyMargin
-import dev.icerock.moko.widgets.style.ext.toPlatformSize
-import dev.icerock.moko.widgets.style.view.SizeSpec
import dev.icerock.moko.widgets.style.view.WidgetSize
-import dev.icerock.moko.widgets.view.AspectRatioFrameLayout
actual abstract class WidgetsTableUnitItem actual constructor(
- override val itemId: Long,
- val data: T
-) : UnitItem {
+ itemId: Long,
+ data: T
+) : TableUnitItem {
+ private val wrapped = object : WidgetsCollectionUnitItem(
+ itemId = itemId,
+ data = data
+ ) {
+ override val reuseId: String get() = this@WidgetsTableUnitItem.reuseId
+
+ override fun createWidget(data: LiveData): Widget {
+ return this@WidgetsTableUnitItem.createWidget(data).widget
+ }
+ }
+
actual abstract val reuseId: String
actual abstract fun createWidget(data: LiveData): UnitItemRoot
- override val viewType: Int by lazy { reuseId.hashCode() }
-
- override fun createViewHolder(
- parent: ViewGroup,
- lifecycleOwner: LifecycleOwner
- ): RecyclerView.ViewHolder {
- val mutableData: MutableLiveData = MutableLiveData(initialValue = data)
- val widget: Widget = createWidget(mutableData).widget
- val context: Context = parent.context
- val view: View = createView(widget, context, lifecycleOwner, parent)
- return ViewHolder(mutableData, view)
- }
+ override val itemId: Long get() = wrapped.itemId
+ override val viewType: Int get() = wrapped.viewType
override fun bindViewHolder(viewHolder: RecyclerView.ViewHolder) {
- val widgetViewHolder = viewHolder as ViewHolder
- widgetViewHolder.mutableData.value = data
+ wrapped.bindViewHolder(viewHolder)
}
- private fun createView(
- widget: Widget,
- context: Context,
- lifecycleOwner: LifecycleOwner,
- parent: ViewGroup
- ): View {
- val viewBundle = widget.buildView(
- ViewFactoryContext(
- context = context,
- lifecycleOwner = lifecycleOwner,
- parent = parent
- )
- )
-
- val dm = context.resources.displayMetrics
- val (lp, view) = (viewBundle.size to viewBundle.view)
- .toRecyclerViewLayoutParams(dm)
-
- viewBundle.margins?.let { lp.applyMargin(dm, it) }
-
- return view.apply {
- layoutParams = lp
- }
+ override fun createViewHolder(parent: ViewGroup, lifecycleOwner: LifecycleOwner): RecyclerView.ViewHolder {
+ return wrapped.createViewHolder(parent, lifecycleOwner)
}
-
- fun Pair.toRecyclerViewLayoutParams(
- dm: DisplayMetrics
- ): Pair {
- val widgetSize = this.first
- val view = this.second
- return when (widgetSize) {
- is WidgetSize.Const -> {
- RecyclerView.LayoutParams(
- widgetSize.width.toPlatformSize(dm),
- widgetSize.height.toPlatformSize(dm)
- ) to view
- }
- is WidgetSize.AspectByWidth -> {
- val lp = RecyclerView.LayoutParams(
- widgetSize.width.toPlatformSize(dm),
- ViewGroup.LayoutParams.WRAP_CONTENT
- )
-
- lp to AspectRatioFrameLayout(
- context = view.context,
- aspectRatio = widgetSize.aspectRatio,
- aspectByWidth = true
- ).apply {
- addView(
- view,
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT
- )
- }
- }
- is WidgetSize.AspectByHeight -> {
- val lp = RecyclerView.LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT,
- widgetSize.height.toPlatformSize(dm)
- )
-
- lp to AspectRatioFrameLayout(
- context = view.context,
- aspectRatio = widgetSize.aspectRatio,
- aspectByWidth = false
- ).apply {
- addView(
- view,
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT
- )
- }
- }
- }
- }
-
- private class ViewHolder(
- val mutableData: MutableLiveData,
- view: View
- ) : RecyclerView.ViewHolder(view)
}
diff --git a/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/utils/IdExt.kt b/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/utils/IdExt.kt
index feebf60e..dde04a2b 100644
--- a/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/utils/IdExt.kt
+++ b/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/utils/IdExt.kt
@@ -4,13 +4,50 @@
package dev.icerock.moko.widgets.utils
-import androidx.core.view.ViewCompat
+import dev.icerock.moko.widgets.BuildConfig
import dev.icerock.moko.widgets.core.Theme
import dev.icerock.moko.widgets.core.Widget
import dev.icerock.moko.widgets.style.view.WidgetSize
+import kotlin.math.abs
+
+private val classIdMap: MutableMap, Int> = mutableMapOf()
val > Theme.Id.androidId: Int
get() {
- // #61 here should be constant and unique id for every Id object. Or android SaveInstanceState will not work :(
- return ViewCompat.generateViewId() // this::class.java.hashCode()
+ val cachedId = classIdMap[this]
+ if(cachedId != null) return cachedId
+
+ val idString = this.javaClass.name
+ val hashCode = abs(idString.hashCode())
+ val id = hashCode % 0x9000
+ // 0x7F - application resources package
+ // 0x08 - id resource
+ // 0x1000 - ids is libraries reserved
+ val fullId = 0x7f081000 + id
+
+ if (BuildConfig.DEBUG) {
+ println(String.format("id %s transformed to 0x%X", idString, fullId))
+ }
+
+ if (classIdMap.containsValue(fullId)) {
+ val conflictName: String = classIdMap
+ .filter { it.value == fullId }
+ .keys.toList()
+ .first()
+ .javaClass.name
+
+ val msg = String.format(
+ "id 0x%X already used by %s, it conflict with %s",
+ fullId,
+ conflictName,
+ idString
+ )
+ throw AndroidIdConflictException(msg)
+ }
+
+ classIdMap[this] = fullId
+
+ return fullId
}
+
+private class AndroidIdConflictException(message: String) : RuntimeException(message)
diff --git a/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/view/UnitItemDecorator.kt b/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/view/UnitItemDecorator.kt
index eb273ca7..d7989671 100644
--- a/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/view/UnitItemDecorator.kt
+++ b/widgets/src/androidMain/kotlin/dev/icerock/moko/widgets/view/UnitItemDecorator.kt
@@ -14,10 +14,6 @@ internal class UnitItemDecorator(
val onBind: () -> Unit
) : UnitItem {
-// init {
-// layoutParams = decorated.layoutParams
-// }
-
override val itemId: Long get() = decorated.itemId
override val viewType: Int get() = decorated.viewType
diff --git a/widgets/src/commonMain/kotlin/dev/icerock/moko/widgets/TextWidget.kt b/widgets/src/commonMain/kotlin/dev/icerock/moko/widgets/TextWidget.kt
index 45c9ff71..caa29c70 100644
--- a/widgets/src/commonMain/kotlin/dev/icerock/moko/widgets/TextWidget.kt
+++ b/widgets/src/commonMain/kotlin/dev/icerock/moko/widgets/TextWidget.kt
@@ -21,7 +21,8 @@ class TextWidget(
private val factory: ViewFactory>,
override val size: WS,
override val id: Id?,
- val text: LiveData
+ val text: LiveData,
+ val maxLines: LiveData? = null
) : Widget(), OptionalId {
override fun buildView(viewFactoryContext: ViewFactoryContext): ViewBundle {
diff --git a/widgets/src/commonMain/kotlin/dev/icerock/moko/widgets/screen/Screen.kt b/widgets/src/commonMain/kotlin/dev/icerock/moko/widgets/screen/Screen.kt
index d7c79d6b..ccc6b919 100644
--- a/widgets/src/commonMain/kotlin/dev/icerock/moko/widgets/screen/Screen.kt
+++ b/widgets/src/commonMain/kotlin/dev/icerock/moko/widgets/screen/Screen.kt
@@ -14,6 +14,8 @@ expect abstract class Screen() {
fun createEventsDispatcher(): EventsDispatcher
+ open fun onViewCreated()
+
open val androidStatusBarColor: Color?
open val isLightStatusBar: Boolean?
}
diff --git a/widgets/src/commonMain/kotlin/dev/icerock/moko/widgets/screen/TemplateScreen.kt b/widgets/src/commonMain/kotlin/dev/icerock/moko/widgets/screen/TemplateScreen.kt
new file mode 100644
index 00000000..1c783909
--- /dev/null
+++ b/widgets/src/commonMain/kotlin/dev/icerock/moko/widgets/screen/TemplateScreen.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package dev.icerock.moko.widgets.screen
+
+import dev.icerock.moko.resources.desc.StringDesc
+import dev.icerock.moko.resources.desc.desc
+import dev.icerock.moko.widgets.constraint
+import dev.icerock.moko.widgets.core.Theme
+import dev.icerock.moko.widgets.core.Widget
+import dev.icerock.moko.widgets.screen.navigation.NavigationBar
+import dev.icerock.moko.widgets.screen.navigation.NavigationItem
+import dev.icerock.moko.widgets.style.view.SizeSpec
+import dev.icerock.moko.widgets.style.view.WidgetSize
+import dev.icerock.moko.widgets.text
+
+class TemplateScreen (
+ private val navTitle: StringDesc,
+ private val labelText: StringDesc,
+ private val theme: Theme
+) : WidgetScreen(), NavigationItem {
+ override val navigationBar = NavigationBar.Normal(title = navTitle)
+
+ override fun createContentWidget() : Widget> = with(theme) {
+ constraint(size = WidgetSize.AsParent) {
+ val label = +text(
+ size = WidgetSize.WrapContent,
+ text = const(labelText)
+ )
+
+ constraints {
+ label centerXToCenterX root
+ label centerYToCenterY root
+ }
+ }
+ }
+}
diff --git a/widgets/src/commonMain/kotlin/dev/icerock/moko/widgets/style/view/FontStyle.kt b/widgets/src/commonMain/kotlin/dev/icerock/moko/widgets/style/view/FontStyle.kt
index 078de8c2..7cbb33b7 100644
--- a/widgets/src/commonMain/kotlin/dev/icerock/moko/widgets/style/view/FontStyle.kt
+++ b/widgets/src/commonMain/kotlin/dev/icerock/moko/widgets/style/view/FontStyle.kt
@@ -5,5 +5,5 @@
package dev.icerock.moko.widgets.style.view
enum class FontStyle {
- BOLD, MEDIUM
+ BOLD, MEDIUM, ITALIC
}
diff --git a/widgets/src/commonMain/kotlin/dev/icerock/moko/widgets/units/WidgetsCollectionUnitItem.kt b/widgets/src/commonMain/kotlin/dev/icerock/moko/widgets/units/WidgetsCollectionUnitItem.kt
index 923342a5..cb9b5ccd 100644
--- a/widgets/src/commonMain/kotlin/dev/icerock/moko/widgets/units/WidgetsCollectionUnitItem.kt
+++ b/widgets/src/commonMain/kotlin/dev/icerock/moko/widgets/units/WidgetsCollectionUnitItem.kt
@@ -6,6 +6,8 @@ package dev.icerock.moko.widgets.units
import dev.icerock.moko.mvvm.livedata.LiveData
import dev.icerock.moko.units.CollectionUnitItem
+import dev.icerock.moko.widgets.core.Widget
+import dev.icerock.moko.widgets.style.view.WidgetSize
expect abstract class WidgetsCollectionUnitItem(
itemId: Long,
@@ -13,5 +15,5 @@ expect abstract class WidgetsCollectionUnitItem(
) : CollectionUnitItem {
abstract val reuseId: String
- abstract fun createWidget(data: LiveData): UnitItemRoot
+ abstract fun createWidget(data: LiveData): Widget
}
diff --git a/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/factory/ButtonWithIconViewFactory.kt b/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/factory/ButtonWithIconViewFactory.kt
index db16ef79..7c9d0118 100644
--- a/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/factory/ButtonWithIconViewFactory.kt
+++ b/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/factory/ButtonWithIconViewFactory.kt
@@ -26,7 +26,7 @@ import dev.icerock.moko.widgets.utils.setEventHandler
import kotlinx.cinterop.useContents
import platform.CoreGraphics.CGFloat
import platform.UIKit.UIButton
-import platform.UIKit.UIButtonTypeSystem
+import platform.UIKit.UIButtonTypeCustom
import platform.UIKit.UIControlContentHorizontalAlignment
import platform.UIKit.UIControlContentHorizontalAlignmentCenter
import platform.UIKit.UIControlContentHorizontalAlignmentLeft
@@ -59,7 +59,7 @@ actual class ButtonWithIconViewFactory actual constructor(
viewFactoryContext: ViewFactoryContext
): ViewBundle {
val button = UIButton.buttonWithType(
- buttonType = UIButtonTypeSystem
+ buttonType = UIButtonTypeCustom
).apply {
translatesAutoresizingMaskIntoConstraints = false
diff --git a/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/factory/SystemCollectionViewFactory.kt b/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/factory/SystemCollectionViewFactory.kt
deleted file mode 100644
index c51e1fae..00000000
--- a/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/factory/SystemCollectionViewFactory.kt
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright 2019 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
- */
-
-package dev.icerock.moko.widgets.factory
-
-import dev.icerock.moko.units.CollectionUnitItem
-import dev.icerock.moko.units.UnitCollectionViewDataSource
-import dev.icerock.moko.widgets.CollectionWidget
-import dev.icerock.moko.widgets.core.ViewBundle
-import dev.icerock.moko.widgets.core.ViewFactory
-import dev.icerock.moko.widgets.core.ViewFactoryContext
-import dev.icerock.moko.widgets.style.background.Background
-import dev.icerock.moko.widgets.style.background.Fill
-import dev.icerock.moko.widgets.style.background.Orientation
-import dev.icerock.moko.widgets.style.view.MarginValues
-import dev.icerock.moko.widgets.style.view.PaddingValues
-import dev.icerock.moko.widgets.style.view.WidgetSize
-import dev.icerock.moko.widgets.utils.Edges
-import dev.icerock.moko.widgets.utils.applyBackgroundIfNeeded
-import dev.icerock.moko.widgets.utils.bind
-import dev.icerock.moko.widgets.utils.toEdgeInsets
-import kotlinx.cinterop.CValue
-import kotlinx.cinterop.readValue
-import kotlinx.cinterop.useContents
-import platform.CoreGraphics.CGRectZero
-import platform.CoreGraphics.CGSize
-import platform.CoreGraphics.CGSizeMake
-import platform.Foundation.NSIndexPath
-import platform.UIKit.UICollectionView
-import platform.UIKit.UICollectionViewCell
-import platform.UIKit.UICollectionViewDelegateFlowLayoutProtocol
-import platform.UIKit.UICollectionViewFlowLayout
-import platform.UIKit.UICollectionViewLayout
-import platform.UIKit.UIColor
-import platform.UIKit.UIEdgeInsetsMake
-import platform.UIKit.UIEdgeInsetsZero
-import platform.UIKit.UILayoutPriorityDefaultLow
-import platform.UIKit.UILayoutPriorityRequired
-import platform.UIKit.backgroundColor
-import platform.UIKit.layoutIfNeeded
-import platform.UIKit.row
-import platform.UIKit.setNeedsLayout
-import platform.UIKit.systemLayoutSizeFittingSize
-import platform.UIKit.translatesAutoresizingMaskIntoConstraints
-
-actual class SystemCollectionViewFactory actual constructor(
- private val orientation: Orientation,
- private val spanCount: Int,
- private val padding: PaddingValues?,
- private val margins: MarginValues?,
- private val background: Background?
-) : ViewFactory> {
-
- override fun build(
- widget: CollectionWidget,
- size: WS,
- viewFactoryContext: ViewFactoryContext
- ): ViewBundle {
- val layoutAndDelegate = SpanCollectionViewLayout(spanCount).apply {
- sectionInset = UIEdgeInsetsZero.readValue()
- minimumInteritemSpacing = 0.0
- minimumLineSpacing = 0.0
- }
- val collectionView = UICollectionView(
- frame = CGRectZero.readValue(),
- collectionViewLayout = layoutAndDelegate
- ).apply {
- backgroundColor = UIColor.clearColor
- delegate = layoutAndDelegate
-
- applyBackgroundIfNeeded(background)
-
- padding?.toEdgeInsets()?.also { insetsValue ->
- val insets = insetsValue.useContents {
- Edges(
- top = this.top,
- leading = this.left,
- trailing = this.right,
- bottom = this.bottom
- )
- }
- contentInset = UIEdgeInsetsMake(
- top = insets.top,
- bottom = insets.bottom,
- left = insets.leading,
- right = insets.trailing
- )
-// val margins = UIEdgeInsetsMake(
-// top = 0.0,
-// bottom = 0.0,
-// left = insets.leading,
-// right = insets.trailing
-// )
-// layoutMargins = margins
- }
-
- // TODO add orientation support
- }
- val unitDataSource = UnitCollectionViewDataSource(collectionView)
- layoutAndDelegate.dataSource = unitDataSource
-
- with(collectionView) {
- translatesAutoresizingMaskIntoConstraints = false
- dataSource = unitDataSource
- }
-
- widget.items.bind { unitDataSource.unitItems = it }
-
- return ViewBundle(
- view = collectionView,
- size = size,
- margins = margins
- )
- }
-
- @Suppress(
- "CONFLICTING_OVERLOADS",
- "RETURN_TYPE_MISMATCH_ON_INHERITANCE",
- "MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED",
- "DIFFERENT_NAMES_FOR_THE_SAME_PARAMETER_IN_SUPERTYPES"
- )
- private class SpanCollectionViewLayout(
- private val spanCount: Int
- ) : UICollectionViewFlowLayout(), UICollectionViewDelegateFlowLayoutProtocol {
- private val reusableStubs = mutableMapOf()
- var dataSource: UnitCollectionViewDataSource? = null
-
- override fun collectionView(
- collectionView: UICollectionView,
- layout: UICollectionViewLayout,
- sizeForItemAtIndexPath: NSIndexPath
- ): CValue {
-// println("size: $sizeForItemAtIndexPath")
- val collectionViewSize = collectionView.bounds.useContents { size }
- val width = (collectionViewSize.width - collectionView.contentInset.useContents {
- this.left + this.right
- }) / spanCount
- val position = sizeForItemAtIndexPath.row.toInt()
-
-// println("width: $width")
-
- val unit = dataSource!!.unitItems!![position]
- // TODO create correct cell from unit
- val stub = UICollectionViewCell()//getStub(collectionView, unit, sizeForItemAtIndexPath)
-
- val size = with(stub.contentView) {
- translatesAutoresizingMaskIntoConstraints = false
- unit.bind(stub)
-
- setNeedsLayout()
- layoutIfNeeded()
-
- systemLayoutSizeFittingSize(
- CGSizeMake(width, 0.0),
- UILayoutPriorityRequired,
- UILayoutPriorityDefaultLow
- )
- }
-
- val (rw, rh) = size.useContents { width to height }
-
-// println("sized: $rw $rh")
-
- return CGSizeMake(rw, rh)
- }
-
- private fun getStub(
- collectionView: UICollectionView,
- unit: CollectionUnitItem,
- indexPath: NSIndexPath
- ): UICollectionViewCell {
- val exist = reusableStubs[unit.reusableIdentifier]
- return if (exist != null) exist
- else {
- val stub = collectionView.dequeueReusableCellWithReuseIdentifier(
- unit.reusableIdentifier,
- indexPath
- )
- reusableStubs[unit.reusableIdentifier] = stub
- stub
- }
- }
- }
-}
diff --git a/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/factory/SystemTextViewFactory.kt b/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/factory/SystemTextViewFactory.kt
index ff45622e..59aa650c 100644
--- a/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/factory/SystemTextViewFactory.kt
+++ b/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/factory/SystemTextViewFactory.kt
@@ -98,6 +98,10 @@ actual class SystemTextViewFactory actual constructor(
widget.text.bind { label.text = it.localized() }
}
+ widget.maxLines?.bind {
+ label.numberOfLines = (it ?: 0).toLong()
+ }
+
return ViewBundle(
view = label,
size = size,
diff --git a/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/screen/Screen.kt b/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/screen/Screen.kt
index 08ddbe98..b22aba17 100644
--- a/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/screen/Screen.kt
+++ b/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/screen/Screen.kt
@@ -34,6 +34,10 @@ actual abstract class Screen {
return created
}
+ actual open fun onViewCreated() {
+
+ }
+
actual fun createEventsDispatcher(): EventsDispatcher {
return EventsDispatcher()
}
@@ -49,6 +53,7 @@ actual abstract class Screen {
val vc = createViewController(isLightStatusBar).also {
setAssociatedObject(it, this)
}
+ onViewCreated()
_viewController = WeakReference(vc)
return vc
}
diff --git a/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/units/UnitItemExt.kt b/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/units/UnitItemExt.kt
index 24235a8c..99d92a33 100644
--- a/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/units/UnitItemExt.kt
+++ b/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/units/UnitItemExt.kt
@@ -17,9 +17,13 @@ import platform.UIKit.bottomAnchor
import platform.UIKit.layoutMargins
import platform.UIKit.layoutMarginsGuide
import platform.UIKit.leadingAnchor
+import platform.UIKit.setTranslatesAutoresizingMaskIntoConstraints
import platform.UIKit.topAnchor
import platform.UIKit.trailingAnchor
import platform.UIKit.translatesAutoresizingMaskIntoConstraints
+import dev.icerock.moko.widgets.core.Widget
+import dev.icerock.moko.widgets.style.view.WidgetSize
+import platform.UIKit.UILayoutPriorityDefaultHigh
private fun UIView.getWidgetLiveData(): MutableLiveData? {
return getAssociatedObject(this) as? MutableLiveData
@@ -31,7 +35,7 @@ private fun UIView.setWidgetLiveData(liveData: MutableLiveData) {
internal fun UIView.setupWidgetContent(
data: T,
- factory: (liveData: LiveData) -> UnitItemRoot
+ factory: (liveData: LiveData) -> Widget
) {
val liveData = this.getWidgetLiveData()
if (liveData != null) {
@@ -40,7 +44,7 @@ internal fun UIView.setupWidgetContent(
// TODO get correct viewcontroller for widgets
val viewController = UIApplication.sharedApplication.keyWindow?.rootViewController!!
val mutableLiveData = MutableLiveData(initialValue = data)
- val widget = factory(mutableLiveData).widget
+ val widget = factory(mutableLiveData)
val viewBundle = widget.buildView(viewFactoryContext = viewController)
val view = viewBundle.view.apply {
translatesAutoresizingMaskIntoConstraints = false
@@ -54,30 +58,38 @@ internal fun UIView.setupWidgetContent(
val childMargins = viewBundle.margins
val edges = dev.icerock.moko.widgets.utils.Edges(
- top = childMargins?.top?.toDouble() ?: 0.0,
- leading = childMargins?.start?.toDouble() ?: 0.0 + margin_left,
- bottom = childMargins?.bottom?.toDouble() ?: 0.0,
- trailing = childMargins?.end?.toDouble() ?: 0.0 + margin_right
+ top = childMargins?.top?.toDouble() ?: 0.0, //TODO: Support this
+ leading = childMargins?.start?.toDouble() ?: 0.0, // + margin_left,
+ bottom = childMargins?.bottom?.toDouble() ?: 0.0, //TODO: Support this
+ trailing = childMargins?.end?.toDouble() ?: 0.0 //+ margin_right
)
-
view.applySize(childSize, this, edges)
view.topAnchor.constraintEqualToAnchor(
anchor = topAnchor,
constant = edges.top
).active = true
+
view.leadingAnchor.constraintEqualToAnchor(
anchor = leadingAnchor,
constant = edges.leading
).active = true
- view.trailingAnchor.constraintEqualToAnchor(
- anchor = trailingAnchor,
- constant = -edges.trailing
- ).active = true
+
+ trailingAnchor.constraintEqualToAnchor(
+ anchor = view.trailingAnchor,
+ constant = edges.trailing
+ ).apply {
+ active = true
+ priority = UILayoutPriorityDefaultHigh
+ }
+
bottomAnchor.constraintEqualToAnchor(
anchor = view.bottomAnchor,
constant = edges.bottom
- ).active = true
+ ).apply {
+ active = true
+ priority = UILayoutPriorityDefaultHigh
+ }
this.setWidgetLiveData(mutableLiveData)
}
diff --git a/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/units/WidgetsCollectionUnitItem.kt b/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/units/WidgetsCollectionUnitItem.kt
index b8828e15..14bd8d2c 100644
--- a/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/units/WidgetsCollectionUnitItem.kt
+++ b/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/units/WidgetsCollectionUnitItem.kt
@@ -8,13 +8,16 @@ import dev.icerock.moko.mvvm.livedata.LiveData
import dev.icerock.moko.units.CollectionUnitItem
import platform.UIKit.UICollectionView
import platform.UIKit.UICollectionViewCell
+import platform.UIKit.translatesAutoresizingMaskIntoConstraints
+import dev.icerock.moko.widgets.core.Widget
+import dev.icerock.moko.widgets.style.view.WidgetSize
actual abstract class WidgetsCollectionUnitItem actual constructor(
override val itemId: Long,
private val data: T
) : CollectionUnitItem {
actual abstract val reuseId: String
- actual abstract fun createWidget(data: LiveData): UnitItemRoot
+ actual abstract fun createWidget(data: LiveData): Widget
override val reusableIdentifier: String get() = reuseId
@@ -25,7 +28,7 @@ actual abstract class WidgetsCollectionUnitItem actual constructor(
)
}
- override fun bind(cell: UICollectionViewCell) {
- cell.contentView.setupWidgetContent(data, ::createWidget)
+ override fun bind(collectionViewCell: UICollectionViewCell) {
+ collectionViewCell.contentView.setupWidgetContent(data, ::createWidget)
}
}
diff --git a/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/units/WidgetsTableUnitItem.kt b/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/units/WidgetsTableUnitItem.kt
index 9db12b11..86592cde 100644
--- a/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/units/WidgetsTableUnitItem.kt
+++ b/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/units/WidgetsTableUnitItem.kt
@@ -11,6 +11,8 @@ import platform.UIKit.UITableView
import platform.UIKit.UITableViewCell
import platform.UIKit.UIView
import platform.UIKit.subviews
+import dev.icerock.moko.widgets.core.Widget
+import dev.icerock.moko.widgets.style.view.WidgetSize
actual abstract class WidgetsTableUnitItem actual constructor(
override val itemId: Long,
@@ -29,7 +31,7 @@ actual abstract class WidgetsTableUnitItem actual constructor(
}
override fun bind(cell: UITableViewCell) {
- cell.contentView.setupWidgetContent(data, ::createWidget)
+ cell.contentView.setupWidgetContent(data) { createWidget(it).widget }
findAnimated(cell.contentView).forEach { it.startAnimating() }
}
diff --git a/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/utils/TextStyleExt.kt b/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/utils/TextStyleExt.kt
index cf53dc2c..5af9821b 100644
--- a/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/utils/TextStyleExt.kt
+++ b/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/utils/TextStyleExt.kt
@@ -22,17 +22,20 @@ import platform.UIKit.UIFont
import platform.UIKit.UIFontWeightMedium
import platform.UIKit.UILabel
import platform.UIKit.UITextField
-import platform.UIKit.systemFontSize
import platform.UIKit.UITextView
-fun TextStyle<*>.toUIFont(defaultFontSize: Double = 17.0): UIFont? { // If this is ok, can be applied to other methods
+fun TextStyle<*>.toUIFont(defaultFontSize: Double = 17.0): UIFont? {
val styleSize = size?.toDouble()
val fontStyle = fontStyle
if (fontStyle != null || styleSize != null) {
val fontSize = styleSize ?: defaultFontSize
return when (fontStyle) {
FontStyle.BOLD -> UIFont.boldSystemFontOfSize(fontSize = fontSize)
- FontStyle.MEDIUM -> UIFont.systemFontOfSize(fontSize = fontSize, weight = UIFontWeightMedium)
+ FontStyle.MEDIUM -> UIFont.systemFontOfSize(
+ fontSize = fontSize,
+ weight = UIFontWeightMedium
+ )
+ FontStyle.ITALIC -> UIFont.italicSystemFontOfSize(fontSize = fontSize)
else -> UIFont.systemFontOfSize(fontSize = fontSize)
}
}
@@ -42,16 +45,8 @@ fun TextStyle<*>.toUIFont(defaultFontSize: Double = 17.0): UIFont? { // If this
fun UIButton.applyTextStyleIfNeeded(textStyle: TextStyle>?) {
if (textStyle == null) return
- val currentFontSize = titleLabel?.font?.pointSize ?: 14.0
- val styleSize = textStyle.size?.toDouble()
- val styleStyle = textStyle.fontStyle
- if (styleStyle != null || styleSize != null) {
- val fontSize = styleSize ?: currentFontSize
- titleLabel?.font = when (styleStyle) {
- FontStyle.BOLD -> UIFont.boldSystemFontOfSize(fontSize = fontSize)
- else -> UIFont.systemFontOfSize(fontSize = fontSize)
- }
- }
+ val textFont = textStyle.toUIFont(14.0)
+ if (textFont != null) titleLabel?.font = textFont
textStyle.color?.also {
setTitleColor(color = it.normal.toUIColor(), forState = UIControlStateNormal)
@@ -63,32 +58,14 @@ fun UIButton.applyTextStyleIfNeeded(textStyle: TextStyle>?
fun UILabel.applyTextStyleIfNeeded(textStyle: TextStyle?) {
if (textStyle == null) return
- val currentFontSize = font.pointSize
- val styleSize = textStyle.size?.toDouble()
- val fontStyle = textStyle.fontStyle
- if (fontStyle != null || styleSize != null) {
- val fontSize = styleSize ?: currentFontSize
- font = when (fontStyle) {
- FontStyle.BOLD -> UIFont.boldSystemFontOfSize(fontSize = fontSize)
- else -> UIFont.systemFontOfSize(fontSize = fontSize)
- }
- }
+ font = textStyle.toUIFont() ?: font
textStyle.color?.also { textColor = it.toUIColor() }
}
fun UITextField.applyTextStyleIfNeeded(textStyle: TextStyle?) {
if (textStyle == null) return
- val currentFontSize = font?.pointSize ?: UIFont.systemFontSize
- val styleSize = textStyle.size?.toDouble()
- val fontStyle = textStyle.fontStyle
- if (fontStyle != null || styleSize != null) {
- val fontSize = styleSize ?: currentFontSize
- font = when (fontStyle) {
- FontStyle.BOLD -> UIFont.boldSystemFontOfSize(fontSize = fontSize)
- else -> UIFont.systemFontOfSize(fontSize = fontSize)
- }
- }
+ font = textStyle.toUIFont() ?: font
textStyle.color?.also { textColor = it.toUIColor() }
}
@@ -122,15 +99,6 @@ fun CATextLayer.applyTextStyleIfNeeded(textStyle: TextStyle?) {
fun UITextView.applyTextStyleIfNeeded(textStyle: TextStyle?) {
if (textStyle == null) return
- val currentFontSize = font?.pointSize ?: UIFont.systemFontSize
- val styleSize = textStyle.size?.toDouble()
- val fontStyle = textStyle.fontStyle
- if (fontStyle != null || styleSize != null) {
- val fontSize = styleSize ?: currentFontSize
- font = when (fontStyle) {
- FontStyle.BOLD -> UIFont.boldSystemFontOfSize(fontSize = fontSize)
- else -> UIFont.systemFontOfSize(fontSize = fontSize)
- }
- }
+ font = textStyle.toUIFont() ?: font
textStyle.color?.also { textColor = it.toUIColor() }
}
diff --git a/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/utils/UIViewExt.kt b/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/utils/UIViewExt.kt
index c1476657..8f46dbbc 100644
--- a/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/utils/UIViewExt.kt
+++ b/widgets/src/iosMain/kotlin/dev/icerock/moko/widgets/utils/UIViewExt.kt
@@ -12,7 +12,9 @@ import kotlinx.cinterop.CValue
import kotlinx.cinterop.readValue
import kotlinx.cinterop.useContents
import platform.CoreGraphics.CGFloat
+import platform.CoreGraphics.CGSize
import platform.CoreGraphics.CGRectMake
+import platform.CoreGraphics.CGSizeMake
import platform.UIKit.NSLayoutDimension
import platform.UIKit.UIEdgeInsets
import platform.UIKit.UIEdgeInsetsMake
@@ -165,21 +167,39 @@ fun PaddingValues.toEdgeInsets(): CValue {
}
fun UIView.wrapContentHeight(width: CGFloat? = null): CGFloat {
- val oldFrame = frame()
+ var fittingSize = CGSizeMake(width ?: 2000.0, UILayoutFittingCompressedSize.height)
+
+ println("Trying to calculate height by content width: ${fittingSize.useContents { width }}")
+
+ updateConstraints()
+ layoutSubviews()
+
+ val resultSize = systemLayoutSizeFittingSize(
+ fittingSize,
+ withHorizontalFittingPriority = UILayoutPriorityRequired,
+ verticalFittingPriority = UILayoutPriorityDefaultLow
+ ).useContents{ this }
+ println("Calculate wrap content size: W: ${resultSize.width} H: ${resultSize.height}")
+ return resultSize.height
+}
+
+fun UIView.wrapContentWidth(height: CGFloat? = null): CGFloat {
val expandedFrame = CGRectMake(
0.0,
0.0,
- width ?: UIScreen.mainScreen.bounds.useContents { this.size.width },
- UIScreen.mainScreen.bounds.useContents { this.size.height }
+ UIScreen.mainScreen.bounds.useContents { size.width },
+ height ?: UIScreen.mainScreen.bounds.useContents { size.height }
)
- setFrame(expandedFrame)
+ println("== Trying to calculate height with from initial size: W: ${expandedFrame.useContents { size }.width} H: ${expandedFrame.useContents { size }.height} ==")
+ height?.let {
+ heightAnchor.constraintEqualToConstant(it).setActive(true)
+ }
updateConstraints()
layoutSubviews()
- val result = systemLayoutSizeFittingSize(
- UILayoutFittingCompressedSize.readValue(),
- withHorizontalFittingPriority = UILayoutPriorityRequired,
- verticalFittingPriority = UILayoutPriorityDefaultLow
- ).useContents { this.height }
- setFrame(oldFrame)
- return result
+ val resultSize = systemLayoutSizeFittingSize(
+ expandedFrame.useContents { size }.readValue(),
+ withHorizontalFittingPriority = UILayoutPriorityDefaultLow,
+ verticalFittingPriority = UILayoutPriorityRequired).useContents { this }
+ println("== Calculate wrap content size: W: ${resultSize.width} H: ${resultSize.height} ==")
+ return resultSize.width
}
\ No newline at end of file