diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 00000000..8fd47e85
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,25 @@
+name: Build
+
+on:
+ pull_request:
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ - name: Setup JDK
+ uses: actions/setup-java@v3
+ with:
+ distribution: 'zulu'
+ java-version: 17
+
+ - name: Setup Gradle
+ uses: gradle/gradle-build-action@v2
+
+ - name: Build the sample app to verify it works
+ run: ./gradlew sample:assemble
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
new file mode 100644
index 00000000..58e56004
--- /dev/null
+++ b/.github/workflows/publish.yml
@@ -0,0 +1,39 @@
+name: Publish
+
+on:
+ push:
+ branches:
+ - master
+ tags:
+ - v*
+
+jobs:
+ deploy:
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ - name: Setup JDK
+ uses: actions/setup-java@v3
+ with:
+ distribution: 'zulu'
+ java-version: 17
+
+ - name: Setup Gradle
+ uses: gradle/gradle-build-action@v2
+
+ - name: Build the sample app to verify it works
+ run: ./gradlew sample:assemble
+
+ - name: Deploy to Sonatype
+ if: github.event_name == 'push' && github.ref == 'refs/heads/master'
+ run: ./gradlew publish --no-parallel
+ env:
+ ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.MAVEN_CENTRAL_USERNAME }}
+ ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.MAVEN_CENTRAL_PASSWORD }}
+ ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.GPG_KEY }}
+ ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.GPG_KEY_ID }}
+ ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.GPG_KEY_PASSWORD }}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 480991b7..d74a2876 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,26 @@
-
# ChangeLog
+## Version 1.7.0
+
+* New: Bindings list:
+ * Google "material" library bindings:
+ * `corbind-material`:
+ * `HideBottomViewOnScrollBehavior`:
+ * `bottomViewScrollStateChanges`
+ * `SearchBar`:
+ * `navigationClicks`
+ * `SearchView`:
+ * `transitionStateChanges`
+ * `transitionStateChangeEvents`
+ * `SideSheetBehavior`:
+ * `sideSheetSlides`
+ * `sideSheetStateChanges`
+* Update: Kotlin modules dependency to v1.8.0.
+* Update: Material components dependency to v1.8.0.
+* Update: Minor update of other libraries.
+
+
## Version 1.6.0
* New: Fragment module
@@ -222,7 +241,7 @@ single selection flag.
* `Snackbar`:
* `shown`
* `SwipeDismissBehavior`:
- * 'dragStateChanges`
+ * `dragStateChanges`
* Fix: Fixed sources jars generation (#6).
diff --git a/LICENSE b/LICENSE
index 6ca9be21..d6456956 100755
--- a/LICENSE
+++ b/LICENSE
@@ -1,3 +1,4 @@
+
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
@@ -186,7 +187,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
- Copyright [2019] [Vladimir Raupov]
+ Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/README.md b/README.md
index eb0bc72f..bf11e5c4 100644
--- a/README.md
+++ b/README.md
@@ -1,63 +1,69 @@
[![Corbind](logo.svg)](https://ldralighieri.github.io/Corbind)
[![Maven Central](https://img.shields.io/maven-central/v/ru.ldralighieri.corbind/corbind.svg)](https://search.maven.org/search?q=g:ru.ldralighieri.corbind)
-[![Kotlin Version](https://img.shields.io/badge/Kotlin-v1.7.20-blue.svg)](https://kotlinlang.org)
+[![Kotlin Version](https://img.shields.io/badge/Kotlin-v1.8.0-blue.svg?logo=kotlin)](https://kotlinlang.org)
[![Kotlin Coroutines Version](https://img.shields.io/badge/Coroutines-v1.6.4-blue.svg)](https://kotlinlang.org/docs/reference/coroutines-overview.html)
[![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg?style=flat)](https://www.apache.org/licenses/LICENSE-2.0)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/a1c9a1b1d1ce4ca7a201ab93492bf6e0)](https://app.codacy.com/gh/LDRAlighieri/Corbind)
[![API](https://img.shields.io/badge/API-14%2B-brightgreen.svg?style=flat)](https://android-arsenal.com/api?level=14)
-[![Google Dev Library](https://img.shields.io/badge/Featured%20in%20devlibrary.withgoogle.com-Corbind-blue)](https://devlibrary.withgoogle.com/products/android/repos/LDRAlighieri-Corbind)
+[![Google Dev Library](https://img.shields.io/badge/Google_DevLibrary-Corbind-blue)](https://devlibrary.withgoogle.com/products/android/repos/LDRAlighieri-Corbind)
[![Android Weekly](https://androidweekly.net/issues/issue-377/badge)](https://androidweekly.net/issues/issue-377)
-Kotlin Coroutines binding APIs for Android UI widgets from the platform and support libraries. **Supports Flow, ReceiveChannel and Actor**.
+⚡ Kotlin Coroutines binding APIs for Android UI widgets from the platform and support libraries. **Supports Flow, ReceiveChannel and Actor**.
## Description
-This library is for Android applications only. Help you to transform Android UI events into cold [Flow][flow], hot [ReceiveChannel][channel] or just perform an action through an [Actor][actor].
+This library is for Android applications only. Help you to transform Android UI events into cold [Flow][flow], hot [ReceiveChannel][channel] or just perform an action through an [Actor][actor]. Please consider giving this repository a star ⭐ if you like the project.
-## Download
+## Using in your projects
Platform bindings:
-```groovy
-implementation 'ru.ldralighieri.corbind:corbind:1.6.0'
+```kotlin
+dependencies {
+ implementation("ru.ldralighieri.corbind:corbind:1.7.0")
+}
```
AndroidX library bindings:
-```groovy
-implementation 'ru.ldralighieri.corbind:corbind-activity:1.6.0'
-implementation 'ru.ldralighieri.corbind:corbind-appcompat:1.6.0'
-implementation 'ru.ldralighieri.corbind:corbind-core:1.6.0'
-implementation 'ru.ldralighieri.corbind:corbind-drawerlayout:1.6.0'
-implementation 'ru.ldralighieri.corbind:corbind-fragment:1.6.0'
-implementation 'ru.ldralighieri.corbind:corbind-leanback:1.6.0'
-implementation 'ru.ldralighieri.corbind:corbind-lifecycle:1.6.0'
-implementation 'ru.ldralighieri.corbind:corbind-navigation:1.6.0'
-implementation 'ru.ldralighieri.corbind:corbind-recyclerview:1.6.0'
-implementation 'ru.ldralighieri.corbind:corbind-slidingpanelayout:1.6.0'
-implementation 'ru.ldralighieri.corbind:corbind-swiperefreshlayout:1.6.0'
-implementation 'ru.ldralighieri.corbind:corbind-viewpager:1.6.0'
-implementation 'ru.ldralighieri.corbind:corbind-viewpager2:1.6.0'
+```kotlin
+dependencies {
+ implementation("ru.ldralighieri.corbind:corbind-activity:1.7.0")
+ implementation("ru.ldralighieri.corbind:corbind-appcompat:1.7.0")
+ implementation("ru.ldralighieri.corbind:corbind-core:1.7.0")
+ implementation("ru.ldralighieri.corbind:corbind-drawerlayout:1.7.0")
+ implementation("ru.ldralighieri.corbind:corbind-fragment:1.7.0")
+ implementation("ru.ldralighieri.corbind:corbind-leanback:1.7.0")
+ implementation("ru.ldralighieri.corbind:corbind-lifecycle:1.7.0")
+ implementation("ru.ldralighieri.corbind:corbind-navigation:1.7.0")
+ implementation("ru.ldralighieri.corbind:corbind-recyclerview:1.7.0")
+ implementation("ru.ldralighieri.corbind:corbind-slidingpanelayout:1.7.0")
+ implementation("ru.ldralighieri.corbind:corbind-swiperefreshlayout:1.7.0")
+ implementation("ru.ldralighieri.corbind:corbind-viewpager:1.7.0")
+ implementation("ru.ldralighieri.corbind:corbind-viewpager2:1.7.0")
+}
```
Google 'material' library bindings:
-```groovy
-implementation 'ru.ldralighieri.corbind:corbind-material:1.6.0'
+```kotlin
+dependencies {
+ implementation("ru.ldralighieri.corbind:corbind-material:1.7.0")
+}
```
Snapshot build:
-```groovy
+```kotlin
repositories {
- maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
+ maven("https://oss.sonatype.org/content/repositories/snapshots/")
}
dependencies {
- implementation 'ru.ldralighieri.corbind:{module}:1.6.1-SNAPSHOT'
+ implementation("ru.ldralighieri.corbind:{module}:1.8.0-SNAPSHOT")
}
```
@@ -65,21 +71,21 @@ dependencies {
## List of extensions
You can find a list of extensions in the description of each module:
-[corbind]
-[corbind-activity]
-[corbind-appcompat]
-[corbind-core]
-[corbind-drawerlayout]
-[corbind-fragment]
-[corbind-leanback]
-[corbind-lifecycle]
-[corbind-material]
-[corbind-navigation]
-[corbind-recyclerview]
-[corbind-slidingpanelayout]
-[corbind-swiperefreshlayout]
-[corbind-viewpager]
-[corbind-viewpager2]
+* [corbind]
+* [corbind-activity]
+* [corbind-appcompat]
+* [corbind-core]
+* [corbind-drawerlayout]
+* [corbind-fragment]
+* [corbind-leanback]
+* [corbind-lifecycle]
+* [corbind-material]
+* [corbind-navigation]
+* [corbind-recyclerview]
+* [corbind-slidingpanelayout]
+* [corbind-swiperefreshlayout]
+* [corbind-viewpager]
+* [corbind-viewpager2]
## How to use it?
@@ -146,7 +152,7 @@ If I forgot something or you have any ideas what can be added or corrected, plea
## License
```
-Copyright 2019-2022 Vladimir Raupov
+Copyright 2019-2023 Vladimir Raupov
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/build-logic/convention/build.gradle.kts b/build-logic/convention/build.gradle.kts
index 827cebb7..f35e67ca 100644
--- a/build-logic/convention/build.gradle.kts
+++ b/build-logic/convention/build.gradle.kts
@@ -21,8 +21,8 @@ plugins {
group = "ru.ldralighieri.corbind.buildlogic"
java {
- sourceCompatibility = JavaVersion.VERSION_11
- targetCompatibility = JavaVersion.VERSION_11
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
}
dependencies {
diff --git a/build-logic/convention/src/main/kotlin/DokkaConventionPlugin.kt b/build-logic/convention/src/main/kotlin/DokkaConventionPlugin.kt
index 3cf2812c..286d602a 100644
--- a/build-logic/convention/src/main/kotlin/DokkaConventionPlugin.kt
+++ b/build-logic/convention/src/main/kotlin/DokkaConventionPlugin.kt
@@ -29,7 +29,7 @@ class DokkaConventionPlugin : Plugin {
tasks.withType().configureEach {
dokkaSourceSets.named("main") {
- jdkVersion.set(JavaVersion.VERSION_11.majorVersion.toInt())
+ jdkVersion.set(JavaVersion.VERSION_17.majorVersion.toInt())
skipDeprecated.set(false)
reportUndocumented.set(false)
diff --git a/build-logic/convention/src/main/kotlin/SpotlessConventionPlugin.kt b/build-logic/convention/src/main/kotlin/SpotlessConventionPlugin.kt
index eb9e368a..6aa7ab38 100644
--- a/build-logic/convention/src/main/kotlin/SpotlessConventionPlugin.kt
+++ b/build-logic/convention/src/main/kotlin/SpotlessConventionPlugin.kt
@@ -32,7 +32,10 @@ class SpotlessConventionPlugin : Plugin {
kotlin {
target("**/*.kt")
targetExclude("**/build/**/*.kt")
+
ktlint(libs.findVersion("ktlint").get().toString())
+ .editorConfigOverride(mapOf("disabled_rules" to "filename"))
+
licenseHeaderFile(rootProject.file("spotless/copyright.kt"))
}
}
diff --git a/build-logic/convention/src/main/kotlin/ru/ldralighieri/corbind/Project+configureKotlinAndroid.kt b/build-logic/convention/src/main/kotlin/ru/ldralighieri/corbind/Project+configureKotlinAndroid.kt
index b5c61ab3..233aad71 100644
--- a/build-logic/convention/src/main/kotlin/ru/ldralighieri/corbind/Project+configureKotlinAndroid.kt
+++ b/build-logic/convention/src/main/kotlin/ru/ldralighieri/corbind/Project+configureKotlinAndroid.kt
@@ -39,12 +39,12 @@ internal fun Project.configureKotlinAndroid(
}
compileOptions {
- sourceCompatibility = JavaVersion.VERSION_11
- targetCompatibility = JavaVersion.VERSION_11
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
- jvmTarget = JavaVersion.VERSION_11.toString()
+ jvmTarget = JavaVersion.VERSION_17.toString()
// Treat all Kotlin warnings as errors
allWarningsAsErrors = true
diff --git a/build-logic/gradle.properties b/build-logic/gradle.properties
new file mode 100644
index 00000000..510f596d
--- /dev/null
+++ b/build-logic/gradle.properties
@@ -0,0 +1,4 @@
+# Gradle
+org.gradle.parallel=true
+org.gradle.caching=true
+org.gradle.configureondemand=true
diff --git a/build-logic/gradle/wrapper/gradle-wrapper.jar b/build-logic/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..f6b961fd
Binary files /dev/null and b/build-logic/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/build-logic/gradle/wrapper/gradle-wrapper.properties b/build-logic/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..ae03e316
--- /dev/null
+++ b/build-logic/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Dec 04 14:00:15 VLAT 2019
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
diff --git a/build-logic/settings.gradle.kts b/build-logic/settings.gradle.kts
index 641ddefd..5140168e 100644
--- a/build-logic/settings.gradle.kts
+++ b/build-logic/settings.gradle.kts
@@ -30,4 +30,5 @@ dependencyResolutionManagement {
}
}
+rootProject.name = "build-logic"
include(":convention")
diff --git a/build.gradle.kts b/build.gradle.kts
index 8f8794b7..1b2437e0 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -17,13 +17,12 @@
import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask
import io.gitlab.arturbosch.detekt.Detekt
-buildscript {
- dependencies {
- classpath(libs.bundles.plugins)
- }
-}
-
plugins {
+ alias(libs.plugins.android.application) apply false
+ alias(libs.plugins.android.library) apply false
+ alias(libs.plugins.kotlin.android) apply false
+ alias(libs.plugins.spotless) apply false
+ alias(libs.plugins.maven.publish) apply false
alias(libs.plugins.detekt)
alias(libs.plugins.gver)
}
@@ -55,7 +54,7 @@ detekt {
}
tasks.withType().configureEach {
- jvmTarget = JavaVersion.VERSION_11.toString()
+ jvmTarget = JavaVersion.VERSION_17.toString()
reports {
html.required.set(true)
xml.required.set(false)
@@ -66,7 +65,7 @@ tasks.withType().configureEach {
// Dependency updates
fun isNonStable(version: String): Boolean {
- val stableKeyword = listOf("RELEASE", "FINAL").any { version.toUpperCase().contains(it) }
+ val stableKeyword = listOf("RELEASE", "FINAL").any { version.contains(it) }
val regex = "^[0-9,.v-]+(-r)?$".toRegex()
val isStable = stableKeyword || regex.matches(version)
return isStable.not()
diff --git a/corbind-activity/README.md b/corbind-activity/README.md
index 13ff9f28..a0829eed 100644
--- a/corbind-activity/README.md
+++ b/corbind-activity/README.md
@@ -3,8 +3,10 @@
To add androidx activity bindings, import `corbind-activity` module:
-```groovy
-implementation 'ru.ldralighieri.corbind:corbind-activity:1.6.0'
+```kotlin
+dependencies {
+ implementation("ru.ldralighieri.corbind:corbind-activity:1.7.0")
+}
```
## List of extensions
@@ -17,7 +19,7 @@ Component | Extension | Description
## Simple examples
```kotlin
-onBackPressedDispatcher.backPresses(lifecycleOwner = this)
+onBackPressedDispatcher.backPresses(lifecycleOwner = this) // Flow
.onEach { /* handle onBackPressed event */ }
.flowWithLifecycle(lifecycle)
.launchIn(lifecycleScope) // lifecycle-runtime-ktx
diff --git a/corbind-appcompat/README.md b/corbind-appcompat/README.md
index b0ac9c6d..7a3e03d9 100644
--- a/corbind-appcompat/README.md
+++ b/corbind-appcompat/README.md
@@ -3,8 +3,10 @@
To add androidx appcompat bindings, import `corbind-appcompat` module:
-```groovy
-implementation 'ru.ldralighieri.corbind:corbind-appcompat:1.6.0'
+```kotlin
+dependencies {
+ implementation("ru.ldralighieri.corbind:corbind-appcompat:1.7.0")
+}
```
## List of extensions
diff --git a/corbind-core/README.md b/corbind-core/README.md
index adf4ec6a..edf80145 100644
--- a/corbind-core/README.md
+++ b/corbind-core/README.md
@@ -3,8 +3,10 @@
To add androidx core bindings, import `corbind-core` module:
-```groovy
-implementation 'ru.ldralighieri.corbind:corbind-core:1.6.0'
+```kotlin
+dependencies {
+ implementation("ru.ldralighieri.corbind:corbind-core:1.7.0")
+}
```
## List of extensions
diff --git a/corbind-drawerlayout/README.md b/corbind-drawerlayout/README.md
index 349a25e6..540eeba2 100644
--- a/corbind-drawerlayout/README.md
+++ b/corbind-drawerlayout/README.md
@@ -3,8 +3,10 @@
To add androidx drawerlayout bindings, import `corbind-drawerlayout` module:
-```groovy
-implementation 'ru.ldralighieri.corbind:corbind-drawerlayout:1.6.0'
+```kotlin
+dependencies {
+ implementation("ru.ldralighieri.corbind:corbind-drawerlayout:1.7.0")
+}
```
## List of extensions
diff --git a/corbind-fragment/README.md b/corbind-fragment/README.md
index 0f386da3..68a9068b 100644
--- a/corbind-fragment/README.md
+++ b/corbind-fragment/README.md
@@ -3,8 +3,10 @@
To add androidx fragment bindings, import `corbind-fragment` module:
-```groovy
-implementation 'ru.ldralighieri.corbind:corbind-fragment:1.6.0'
+```kotlin
+dependencies {
+ implementation("ru.ldralighieri.corbind:corbind-fragment:1.7.0")
+}
```
## List of extensions
@@ -21,7 +23,7 @@ lifecycleScope.launchWhenStarted {
parentFragmentManager.resultEvents(
requestKey = FRAGMENT_REQUEST_KEY,
lifecycleOwner = this@CurrentFragment
- )
+ ) // Flow
.onEach { event -> /* handle result event */ }
.launchIn(this@launchWhenStarted) // lifecycle-runtime-ktx
}
diff --git a/corbind-leanback/README.md b/corbind-leanback/README.md
index b82a5723..8709c732 100644
--- a/corbind-leanback/README.md
+++ b/corbind-leanback/README.md
@@ -3,8 +3,10 @@
To add androidx leanback bindings, import `corbind-leanback` module:
-```groovy
-implementation 'ru.ldralighieri.corbind:corbind-leanback:1.6.0'
+```kotlin
+dependencies {
+ implementation("ru.ldralighieri.corbind:corbind-leanback:1.7.0")
+}
```
## List of extensions
diff --git a/corbind-lifecycle/README.md b/corbind-lifecycle/README.md
index dc226fde..a8015184 100644
--- a/corbind-lifecycle/README.md
+++ b/corbind-lifecycle/README.md
@@ -3,8 +3,10 @@
To add androidx lifecycle bindings, import `corbind-lifecycle` module:
-```groovy
-implementation 'ru.ldralighieri.corbind:corbind-lifecycle:1.6.0'
+```kotlin
+dependencies {
+ implementation("ru.ldralighieri.corbind:corbind-lifecycle:1.7.0")
+}
```
## List of extensions
@@ -17,7 +19,7 @@ Component | Extension | Description
## Simple examples
```kotlin
-lifecycle.events()
+lifecycle.events() // Flow
.filter { it == Lifecycle.Event.ON_RESUME }
.onEach { /* handle lifecycle onResume event */ }
.flowWithLifecycle(lifecycle)
diff --git a/corbind-material/README.md b/corbind-material/README.md
index 354dda15..e4361840 100644
--- a/corbind-material/README.md
+++ b/corbind-material/README.md
@@ -3,8 +3,10 @@
To add material bindings, import `corbind-material` module:
-```groovy
-implementation 'ru.ldralighieri.corbind:corbind-material:1.6.0'
+```kotlin
+dependencies {
+ implementation("ru.ldralighieri.corbind:corbind-material:1.7.0")
+}
```
## List of extensions
@@ -16,6 +18,7 @@ Component | Extension | Description
| `stateChanges` | Called when the bottom sheet changes its state.
**Chip** | `closeIconClicks` | Called when the chip’s close icon is clicked.
**ChipGroup** | `checkedChanges` | Called when the checked chips are changed.
+**View**
(HideBottomViewOnScrollBehavior) | `bottomViewScrollStateChanges` | Called when the bottom view changes its scrolled state.
**MaterialButton** | `checkedChanges` | Called when the checked state of a MaterialButton has changed.
**MaterialButtonToggleGroup** | `buttonCheckedChangeEvents` | Called when a `MaterialButton` in this group is checked or unchecked (only *not* in single selection mode).
| `buttonCheckedChanges` | Called when a `MaterialButton` in this group is checked (only in single selection mode).
@@ -34,6 +37,11 @@ Component | Extension | Description
**RangeSlider** | `touches` | Called when a range slider's touch event is being started/stopped.
| `valuesChanges` | Called a range slider's value is changed. This is called for all existing values to check all the current values use.
| `valuesChangeEvents` | A more advanced version of the `valuesChanges`.
+**SearchBar** | `navigationClicks` | Called whenever the user clicks the navigation button at the start of the searchbar.
+**SearchView** | `transitionStateChanges` | Called when the given `SearchView's` transition state has changed.
+ | `transitionStateChangeEvents` | A more advanced version of the `transitionStateChanges`.
+**View**
(SideSheetBehavior) | `sideSheetSlides` | Called when the side sheet is being dragged.
+ | `sideSheetStateChanges` | Called when the side sheet changes its state.
**Slider** | `touches` | Called when a slider's touch event is being started/stopped.
| `valueChanges` | Called a slider's value is changed.
| `valueChangeEvents` | A more advanced version of the `valueChanges`.
diff --git a/corbind-material/src/main/kotlin/ru/ldralighieri/corbind/material/BottomSheetBehaviorSlides.kt b/corbind-material/src/main/kotlin/ru/ldralighieri/corbind/material/BottomSheetBehaviorSlides.kt
index 7ad7465a..b6ad9fe6 100644
--- a/corbind-material/src/main/kotlin/ru/ldralighieri/corbind/material/BottomSheetBehaviorSlides.kt
+++ b/corbind-material/src/main/kotlin/ru/ldralighieri/corbind/material/BottomSheetBehaviorSlides.kt
@@ -18,7 +18,6 @@ package ru.ldralighieri.corbind.material
import android.view.View
import androidx.annotation.CheckResult
-import androidx.coordinatorlayout.widget.CoordinatorLayout
import com.google.android.material.bottomsheet.BottomSheetBehavior
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -48,7 +47,7 @@ fun View.slides(
for (offset in channel) action(offset)
}
- val behavior = getBehavior(this@slides)
+ val behavior = getBottomSheetBehavior()
val callback = callback(scope, events::trySend)
behavior.addBottomSheetCallback(callback)
events.invokeOnClose { behavior.removeBottomSheetCallback(callback) }
@@ -88,7 +87,7 @@ fun View.slides(
scope: CoroutineScope,
capacity: Int = Channel.RENDEZVOUS
): ReceiveChannel = corbindReceiveChannel(capacity) {
- val behavior = getBehavior(this@slides)
+ val behavior = getBottomSheetBehavior()
val callback = callback(scope, ::trySend)
behavior.addBottomSheetCallback(callback)
invokeOnClose { behavior.removeBottomSheetCallback(callback) }
@@ -106,21 +105,14 @@ fun View.slides(
* .launchIn(lifecycleScope) // lifecycle-runtime-ktx
* ```
*/
+@CheckResult
fun View.slides(): Flow = channelFlow {
- val behavior = getBehavior(this@slides)
+ val behavior = getBottomSheetBehavior()
val callback = callback(this, ::trySend)
behavior.addBottomSheetCallback(callback)
awaitClose { behavior.removeBottomSheetCallback(callback) }
}
-@CheckResult
-private fun getBehavior(view: View): BottomSheetBehavior<*> {
- val params = view.layoutParams as? CoordinatorLayout.LayoutParams
- ?: throw IllegalArgumentException("The view is not in a Coordinator Layout.")
- return params.behavior as BottomSheetBehavior<*>?
- ?: throw IllegalStateException("There's no behavior set on this view.")
-}
-
@CheckResult
private fun callback(
scope: CoroutineScope,
diff --git a/corbind-material/src/main/kotlin/ru/ldralighieri/corbind/material/BottomSheetBehaviorStateChanges.kt b/corbind-material/src/main/kotlin/ru/ldralighieri/corbind/material/BottomSheetBehaviorStateChanges.kt
index 101484da..3d103195 100644
--- a/corbind-material/src/main/kotlin/ru/ldralighieri/corbind/material/BottomSheetBehaviorStateChanges.kt
+++ b/corbind-material/src/main/kotlin/ru/ldralighieri/corbind/material/BottomSheetBehaviorStateChanges.kt
@@ -49,7 +49,7 @@ fun View.stateChanges(
for (state in channel) action(state)
}
- val behavior = getBehavior(this@stateChanges)
+ val behavior = getBottomSheetBehavior()
events.trySend(behavior.state)
val callback = callback(scope, events::trySend)
behavior.addBottomSheetCallback(callback)
@@ -92,7 +92,7 @@ fun View.stateChanges(
scope: CoroutineScope,
capacity: Int = Channel.RENDEZVOUS
): ReceiveChannel = corbindReceiveChannel(capacity) {
- val behavior = getBehavior(this@stateChanges)
+ val behavior = getBottomSheetBehavior()
trySend(behavior.state)
val callback = callback(scope, ::trySend)
behavior.addBottomSheetCallback(callback)
@@ -121,19 +121,19 @@ fun View.stateChanges(
* .launchIn(lifecycleScope) // lifecycle-runtime-ktx
* ```
*/
+@CheckResult
fun View.stateChanges(): InitialValueFlow = channelFlow {
- val behavior = getBehavior(this@stateChanges)
+ val behavior = getBottomSheetBehavior()
val callback = callback(this, ::trySend)
behavior.addBottomSheetCallback(callback)
awaitClose { behavior.removeBottomSheetCallback(callback) }
-}.asInitialValueFlow(getBehavior(this@stateChanges).state)
+}.asInitialValueFlow(getBottomSheetBehavior().state)
-@CheckResult
-private fun getBehavior(view: View): BottomSheetBehavior<*> {
- val params = view.layoutParams as? CoordinatorLayout.LayoutParams
+internal fun View.getBottomSheetBehavior(): BottomSheetBehavior<*> {
+ val params = layoutParams as? CoordinatorLayout.LayoutParams
?: throw IllegalArgumentException("The view is not in a Coordinator Layout.")
return params.behavior as BottomSheetBehavior<*>?
- ?: throw IllegalStateException("There's no behavior set on this view.")
+ ?: throw IllegalStateException("There's no BottomSheetBehavior set on this view.")
}
@CheckResult
@@ -142,9 +142,9 @@ private fun callback(
emitter: (Int) -> Unit
) = object : BottomSheetBehavior.BottomSheetCallback() {
- override fun onSlide(bottomSheet: View, slideOffset: Float) = Unit
-
override fun onStateChanged(bottomSheet: View, newState: Int) {
if (scope.isActive) { emitter(newState) }
}
+
+ override fun onSlide(bottomSheet: View, slideOffset: Float) = Unit
}
diff --git a/corbind-material/src/main/kotlin/ru/ldralighieri/corbind/material/HideBottomViewOnScrollBehaviorScrollStateChanges.kt b/corbind-material/src/main/kotlin/ru/ldralighieri/corbind/material/HideBottomViewOnScrollBehaviorScrollStateChanges.kt
new file mode 100644
index 00000000..6babd45a
--- /dev/null
+++ b/corbind-material/src/main/kotlin/ru/ldralighieri/corbind/material/HideBottomViewOnScrollBehaviorScrollStateChanges.kt
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2022 Vladimir Raupov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ru.ldralighieri.corbind.material
+
+import android.view.View
+import androidx.annotation.CheckResult
+import androidx.coordinatorlayout.widget.CoordinatorLayout
+import com.google.android.material.behavior.HideBottomViewOnScrollBehavior
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.channels.ReceiveChannel
+import kotlinx.coroutines.channels.actor
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.channelFlow
+import kotlinx.coroutines.isActive
+import ru.ldralighieri.corbind.internal.corbindReceiveChannel
+
+/**
+ * Perform an action on the bottom view scroll state change events from [View] on
+ * [HideBottomViewOnScrollBehavior].
+ *
+ * @param scope Root coroutine scope
+ * @param capacity Capacity of the channel's buffer (no buffer by default)
+ * @param action An action to perform
+ */
+fun View.bottomViewScrollStateChanges(
+ scope: CoroutineScope,
+ capacity: Int = Channel.RENDEZVOUS,
+ action: suspend (Int) -> Unit
+) {
+ val events = scope.actor(Dispatchers.Main.immediate, capacity) {
+ for (state in channel) action(state)
+ }
+
+ val behavior = getBehavior()
+ val listener = listener(scope, events::trySend)
+ behavior.addOnScrollStateChangedListener(listener)
+ events.invokeOnClose { behavior.removeOnScrollStateChangedListener(listener) }
+}
+
+/**
+ * Perform an action on the bottom view scroll state change events from [View] on
+ * [HideBottomViewOnScrollBehavior], inside new [CoroutineScope].
+ *
+ * @param capacity Capacity of the channel's buffer (no buffer by default)
+ * @param action An action to perform
+ */
+suspend fun View.bottomViewScrollStateChanges(
+ capacity: Int = Channel.RENDEZVOUS,
+ action: suspend (Int) -> Unit
+) = coroutineScope {
+ bottomViewScrollStateChanges(this, capacity, action)
+}
+
+/**
+ * Create a channel which emits the bottom view scroll state change events from [View] on
+ * [HideBottomViewOnScrollBehavior].
+ *
+ * *Note:* A value will be emitted immediately.
+ *
+ * Examples:
+ *
+ * ```
+ * launch {
+ * bottomView.bottomViewScrollStateChanges(scope)
+ * .consumeEach { /* handle bottom view scroll state change */ }
+ * }
+ * ```
+ *
+ * @param scope Root coroutine scope
+ * @param capacity Capacity of the channel's buffer (no buffer by default)
+ */
+@CheckResult
+fun View.bottomViewScrollStateChanges(
+ scope: CoroutineScope,
+ capacity: Int = Channel.RENDEZVOUS
+): ReceiveChannel = corbindReceiveChannel(capacity) {
+ val behavior = getBehavior()
+ val listener = listener(scope, ::trySend)
+ behavior.addOnScrollStateChangedListener(listener)
+ invokeOnClose { behavior.removeOnScrollStateChangedListener(listener) }
+}
+
+/**
+ * Create a flow which emits the bottom view scroll state change events from [View] on
+ * [HideBottomViewOnScrollBehavior].
+ *
+ * *Note:* A value will be emitted immediately.
+ *
+ * Examples:
+ *
+ * ```
+ * bottomView.bottomViewScrollStateChanges()
+ * .onEach { /* handle bottom view scroll state change */ }
+ * .flowWithLifecycle(lifecycle)
+ * .launchIn(lifecycleScope) // lifecycle-runtime-ktx
+ * ```
+ */
+@CheckResult
+fun View.bottomViewScrollStateChanges(): Flow = channelFlow {
+ val behavior = getBehavior()
+ val listener = listener(this, ::trySend)
+ behavior.addOnScrollStateChangedListener(listener)
+ awaitClose { behavior.removeOnScrollStateChangedListener(listener) }
+}
+
+private fun View.getBehavior(): HideBottomViewOnScrollBehavior<*> {
+ val params = layoutParams as? CoordinatorLayout.LayoutParams
+ ?: throw IllegalArgumentException("The view is not in a Coordinator Layout.")
+ return params.behavior as HideBottomViewOnScrollBehavior<*>?
+ ?: throw IllegalStateException("There's no HideBottomViewOnScrollBehavior set on this view.")
+}
+
+@CheckResult
+private fun listener(
+ scope: CoroutineScope,
+ emitter: (Int) -> Unit
+) = HideBottomViewOnScrollBehavior.OnScrollStateChangedListener { _, newState ->
+ if (scope.isActive) { emitter(newState) }
+}
diff --git a/corbind-material/src/main/kotlin/ru/ldralighieri/corbind/material/SearchBarNavigationClicks.kt b/corbind-material/src/main/kotlin/ru/ldralighieri/corbind/material/SearchBarNavigationClicks.kt
new file mode 100644
index 00000000..05b15148
--- /dev/null
+++ b/corbind-material/src/main/kotlin/ru/ldralighieri/corbind/material/SearchBarNavigationClicks.kt
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2023 Vladimir Raupov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ru.ldralighieri.corbind.material
+
+import android.os.Build
+import android.view.View
+import androidx.annotation.CheckResult
+import androidx.annotation.RequiresApi
+import com.google.android.material.search.SearchBar
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.channels.ReceiveChannel
+import kotlinx.coroutines.channels.actor
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.channelFlow
+import kotlinx.coroutines.isActive
+import ru.ldralighieri.corbind.internal.corbindReceiveChannel
+
+/**
+ * Perform an action on [SearchBar] navigation click events.
+ *
+ * *Warning:* The created actor uses [SearchBar.setNavigationOnClickListener]. Only one actor can
+ * be used at a time.
+ *
+ * @param scope Root coroutine scope
+ * @param capacity Capacity of the channel's buffer (no buffer by default)
+ * @param action An action to perform
+ */
+@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
+fun SearchBar.navigationClicks(
+ scope: CoroutineScope,
+ capacity: Int = Channel.RENDEZVOUS,
+ action: suspend () -> Unit
+) {
+ val events = scope.actor(Dispatchers.Main.immediate, capacity) {
+ for (ignored in channel) action()
+ }
+
+ setNavigationOnClickListener(listener(scope, events::trySend))
+ events.invokeOnClose { setNavigationOnClickListener(null) }
+}
+
+/**
+ * Perform an action on [SearchBar] navigation click events, inside new [CoroutineScope].
+ *
+ * *Warning:* The created actor uses [SearchBar.setNavigationOnClickListener]. Only one actor can
+ * be used at a time.
+ *
+ * @param capacity Capacity of the channel's buffer (no buffer by default)
+ * @param action An action to perform
+ */
+@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
+suspend fun SearchBar.navigationClicks(
+ capacity: Int = Channel.RENDEZVOUS,
+ action: suspend () -> Unit
+) = coroutineScope {
+ navigationClicks(this, capacity, action)
+}
+
+/**
+ * Create a channel which emits on [SearchBar] navigation click events.
+ *
+ * *Warning:* The created channel uses [SearchBar.setNavigationOnClickListener]. Only one channel
+ * can be used at a time.
+ *
+ * Example:
+ *
+ * ```
+ * launch {
+ * searchbar.navigationClicks(scope)
+ * .consumeEach { /* handle navigation click */ }
+ * }
+ * ```
+ *
+ * @param scope Root coroutine scope
+ * @param capacity Capacity of the channel's buffer (no buffer by default)
+ */
+@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
+@CheckResult
+fun SearchBar.navigationClicks(
+ scope: CoroutineScope,
+ capacity: Int = Channel.RENDEZVOUS
+): ReceiveChannel = corbindReceiveChannel(capacity) {
+ setNavigationOnClickListener(listener(scope, ::trySend))
+ invokeOnClose { setNavigationOnClickListener(null) }
+}
+
+/**
+ * Create a flow which emits on [SearchBar] navigation click events.
+ *
+ * *Warning:* The created flow uses [SearchBar.setNavigationOnClickListener]. Only one flow can be
+ * used at a time.
+ *
+ * Example:
+ *
+ * ```
+ * searchbar.navigationClicks()
+ * .onEach { /* handle navigation click */ }
+ * .flowWithLifecycle(lifecycle)
+ * .launchIn(lifecycleScope) // lifecycle-runtime-ktx
+ * ```
+ */
+@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
+@CheckResult
+fun SearchBar.navigationClicks(): Flow = channelFlow {
+ setNavigationOnClickListener(listener(this, ::trySend))
+ awaitClose { setNavigationOnClickListener(null) }
+}
+
+@CheckResult
+private fun listener(
+ scope: CoroutineScope,
+ emitter: (Unit) -> Unit
+) = View.OnClickListener {
+ if (scope.isActive) { emitter(Unit) }
+}
diff --git a/corbind-material/src/main/kotlin/ru/ldralighieri/corbind/material/SearchViewTransitionStateChangeEvents.kt b/corbind-material/src/main/kotlin/ru/ldralighieri/corbind/material/SearchViewTransitionStateChangeEvents.kt
new file mode 100644
index 00000000..43db0012
--- /dev/null
+++ b/corbind-material/src/main/kotlin/ru/ldralighieri/corbind/material/SearchViewTransitionStateChangeEvents.kt
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2022 Vladimir Raupov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ru.ldralighieri.corbind.material
+
+import androidx.annotation.CheckResult
+import com.google.android.material.search.SearchView
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.channels.ReceiveChannel
+import kotlinx.coroutines.channels.actor
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.channelFlow
+import kotlinx.coroutines.isActive
+import ru.ldralighieri.corbind.internal.corbindReceiveChannel
+
+data class SearchViewTransitionStateChangeEvent(
+ val view: SearchView,
+ val previousState: SearchView.TransitionState,
+ val newState: SearchView.TransitionState
+)
+
+/**
+ * Perform an action on the
+ * [transition state change event][SearchViewTransitionStateChangeEvent] on [SearchView].
+ *
+ * @param scope Root coroutine scope
+ * @param capacity Capacity of the channel's buffer (no buffer by default)
+ * @param action An action to perform
+ */
+fun SearchView.transitionStateChangeEvents(
+ scope: CoroutineScope,
+ capacity: Int = Channel.RENDEZVOUS,
+ action: suspend (SearchViewTransitionStateChangeEvent) -> Unit
+) {
+ val events = scope.actor(Dispatchers.Main.immediate, capacity) {
+ for (event in channel) action(event)
+ }
+
+ val listener = listener(scope, events::trySend)
+ addTransitionListener(listener)
+ events.invokeOnClose { removeTransitionListener(listener) }
+}
+
+/**
+ * Perform an action on the
+ * [transition state change event][SearchViewTransitionStateChangeEvent] on [SearchView], inside new
+ * [CoroutineScope].
+ *
+ * @param capacity Capacity of the channel's buffer (no buffer by default)
+ * @param action An action to perform
+ */
+suspend fun SearchView.transitionStateChangeEvents(
+ capacity: Int = Channel.RENDEZVOUS,
+ action: suspend (SearchViewTransitionStateChangeEvent) -> Unit
+) = coroutineScope {
+ transitionStateChangeEvents(this, capacity, action)
+}
+
+/**
+ * Create a channel which emits the
+ * [transition state change event][SearchViewTransitionStateChangeEvent] on [SearchView].
+ *
+ * Example:
+ *
+ * ```
+ * launch {
+ * searchView.transitionStateChangeEvents(scope)
+ * .consumeEach { /* handle transition state change even */ }
+ * }
+ * ```
+ *
+ * @param scope Root coroutine scope
+ * @param capacity Capacity of the channel's buffer (no buffer by default)
+ */
+@CheckResult
+fun SearchView.transitionStateChangeEvents(
+ scope: CoroutineScope,
+ capacity: Int = Channel.RENDEZVOUS
+): ReceiveChannel = corbindReceiveChannel(capacity) {
+ val listener = listener(scope, ::trySend)
+ addTransitionListener(listener)
+ invokeOnClose { removeTransitionListener(listener) }
+}
+
+/**
+ * Create a flow which emits the
+ * [transition state change event][SearchViewTransitionStateChangeEvent] on [SearchView].
+ *
+ * Example:
+ *
+ * ```
+ * searchView.transitionStateChangeEvents()
+ * .onEach { /* handle transition state change event */ }
+ * .flowWithLifecycle(lifecycle)
+ * .launchIn(lifecycleScope) // lifecycle-runtime-ktx
+ * ```
+ */
+@CheckResult
+fun SearchView.transitionStateChangeEvents(): Flow =
+ channelFlow {
+ val listener = listener(this, ::trySend)
+ addTransitionListener(listener)
+ awaitClose { removeTransitionListener(listener) }
+ }
+
+@CheckResult
+private fun listener(
+ scope: CoroutineScope,
+ emitter: (SearchViewTransitionStateChangeEvent) -> Unit
+) = SearchView.TransitionListener { searchView, previousState, newState ->
+ if (scope.isActive) {
+ emitter(SearchViewTransitionStateChangeEvent(searchView, previousState, newState))
+ }
+}
diff --git a/corbind-material/src/main/kotlin/ru/ldralighieri/corbind/material/SearchViewTransitionStateChanges.kt b/corbind-material/src/main/kotlin/ru/ldralighieri/corbind/material/SearchViewTransitionStateChanges.kt
new file mode 100644
index 00000000..c1ac958c
--- /dev/null
+++ b/corbind-material/src/main/kotlin/ru/ldralighieri/corbind/material/SearchViewTransitionStateChanges.kt
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2022 Vladimir Raupov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ru.ldralighieri.corbind.material
+
+import androidx.annotation.CheckResult
+import com.google.android.material.search.SearchView
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.channels.ReceiveChannel
+import kotlinx.coroutines.channels.actor
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.channelFlow
+import kotlinx.coroutines.isActive
+import ru.ldralighieri.corbind.internal.corbindReceiveChannel
+
+/**
+ * Perform an action on the transition state change events on [SearchView].
+ *
+ * @param scope Root coroutine scope
+ * @param capacity Capacity of the channel's buffer (no buffer by default)
+ * @param action An action to perform
+ */
+fun SearchView.transitionStateChanges(
+ scope: CoroutineScope,
+ capacity: Int = Channel.RENDEZVOUS,
+ action: suspend (SearchView.TransitionState) -> Unit
+) {
+ val events = scope.actor(Dispatchers.Main.immediate, capacity) {
+ for (state in channel) action(state)
+ }
+
+ val listener = listener(scope, events::trySend)
+ addTransitionListener(listener)
+ events.invokeOnClose { removeTransitionListener(listener) }
+}
+
+/**
+ * Perform an action on the transition state change events on [SearchView], inside new
+ * [CoroutineScope].
+ *
+ * @param capacity Capacity of the channel's buffer (no buffer by default)
+ * @param action An action to perform
+ */
+suspend fun SearchView.transitionStateChanges(
+ capacity: Int = Channel.RENDEZVOUS,
+ action: suspend (SearchView.TransitionState) -> Unit
+) = coroutineScope {
+ transitionStateChanges(this, capacity, action)
+}
+
+/**
+ * Create a channel which emits the transition state change events on [SearchView].
+ *
+ * Example:
+ *
+ * ```
+ * launch {
+ * searchView.transitionStateChanges(scope)
+ * .consumeEach { /* handle transition state change even */ }
+ * }
+ * ```
+ *
+ * @param scope Root coroutine scope
+ * @param capacity Capacity of the channel's buffer (no buffer by default)
+ */
+@CheckResult
+fun SearchView.transitionStateChanges(
+ scope: CoroutineScope,
+ capacity: Int = Channel.RENDEZVOUS
+): ReceiveChannel = corbindReceiveChannel(capacity) {
+ val listener = listener(scope, ::trySend)
+ addTransitionListener(listener)
+ invokeOnClose { removeTransitionListener(listener) }
+}
+
+/**
+ * Create a flow which emits the transition state change events on [SearchView].
+ *
+ * Example:
+ *
+ * ```
+ * searchView.transitionStateChanges()
+ * .onEach { /* handle transition state change event */ }
+ * .flowWithLifecycle(lifecycle)
+ * .launchIn(lifecycleScope) // lifecycle-runtime-ktx
+ * ```
+ */
+@CheckResult
+fun SearchView.transitionStateChanges(): Flow = channelFlow {
+ val listener = listener(this, ::trySend)
+ addTransitionListener(listener)
+ awaitClose { removeTransitionListener(listener) }
+}
+
+@CheckResult
+private fun listener(
+ scope: CoroutineScope,
+ emitter: (SearchView.TransitionState) -> Unit
+) = SearchView.TransitionListener { _, _, newState ->
+ if (scope.isActive) { emitter(newState) }
+}
diff --git a/corbind-material/src/main/kotlin/ru/ldralighieri/corbind/material/SideSheetBehaviorSlides.kt b/corbind-material/src/main/kotlin/ru/ldralighieri/corbind/material/SideSheetBehaviorSlides.kt
new file mode 100644
index 00000000..8fc5b9b4
--- /dev/null
+++ b/corbind-material/src/main/kotlin/ru/ldralighieri/corbind/material/SideSheetBehaviorSlides.kt
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2022 Vladimir Raupov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ru.ldralighieri.corbind.material
+
+import android.view.View
+import androidx.annotation.CheckResult
+import com.google.android.material.sidesheet.SideSheetBehavior
+import com.google.android.material.sidesheet.SideSheetCallback
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.channels.ReceiveChannel
+import kotlinx.coroutines.channels.actor
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.channelFlow
+import kotlinx.coroutines.isActive
+import ru.ldralighieri.corbind.internal.corbindReceiveChannel
+
+/**
+ * Perform an action on the slide offset events from [View] on [SideSheetBehavior].
+ *
+ * @param scope Root coroutine scope
+ * @param capacity Capacity of the channel's buffer (no buffer by default)
+ * @param action An action to perform
+ */
+fun View.sideSheetSlides(
+ scope: CoroutineScope,
+ capacity: Int = Channel.RENDEZVOUS,
+ action: suspend (Float) -> Unit
+) {
+ val events = scope.actor(Dispatchers.Main.immediate, capacity) {
+ for (offset in channel) action(offset)
+ }
+
+ val behavior = getSideSheetBehavior()
+ val callback = callback(scope, events::trySend)
+ behavior.addCallback(callback)
+ events.invokeOnClose { behavior.removeCallback(callback) }
+}
+
+/**
+ * Perform an action on the slide offset events from [View] on [SideSheetBehavior], inside new
+ * [CoroutineScope].
+ *
+ * @param capacity Capacity of the channel's buffer (no buffer by default)
+ * @param action An action to perform
+ */
+suspend fun View.sideSheetSlides(
+ capacity: Int = Channel.RENDEZVOUS,
+ action: suspend (Float) -> Unit
+) = coroutineScope {
+ sideSheetSlides(this, capacity, action)
+}
+
+/**
+ * Create a channel which emits the slide offset events from [View] on [SideSheetBehavior].
+ *
+ * Example:
+ *
+ * ```
+ * launch {
+ * sideSheetBehavior.sideSheetSlides(scope)
+ * .consumeEach { /* handle slide offset */ }
+ * }
+ * ```
+ *
+ * @param scope Root coroutine scope
+ * @param capacity Capacity of the channel's buffer (no buffer by default)
+ */
+@CheckResult
+fun View.sideSheetSlides(
+ scope: CoroutineScope,
+ capacity: Int = Channel.RENDEZVOUS
+): ReceiveChannel = corbindReceiveChannel(capacity) {
+ val behavior = getSideSheetBehavior()
+ val callback = callback(scope, ::trySend)
+ behavior.addCallback(callback)
+ invokeOnClose { behavior.removeCallback(callback) }
+}
+
+/**
+ * Create a flow which emits the slide offset events from [View] on [SideSheetBehavior].
+ *
+ * Example:
+ *
+ * ```
+ * sideSheetBehavior.sideSheetSlides()
+ * .onEach { /* handle slide offset */ }
+ * .flowWithLifecycle(lifecycle)
+ * .launchIn(lifecycleScope) // lifecycle-runtime-ktx
+ * ```
+ */
+@CheckResult
+fun View.sideSheetSlides(): Flow = channelFlow {
+ val behavior = getSideSheetBehavior()
+ val callback = callback(this, ::trySend)
+ behavior.addCallback(callback)
+ awaitClose { behavior.removeCallback(callback) }
+}
+
+@CheckResult
+private fun callback(
+ scope: CoroutineScope,
+ emitter: (Float) -> Unit
+) = object : SideSheetCallback() {
+
+ override fun onSlide(sheet: View, slideOffset: Float) {
+ if (scope.isActive) { emitter(slideOffset) }
+ }
+
+ override fun onStateChanged(sheet: View, newState: Int) = Unit
+}
diff --git a/corbind-material/src/main/kotlin/ru/ldralighieri/corbind/material/SideSheetBehaviorStateChanges.kt b/corbind-material/src/main/kotlin/ru/ldralighieri/corbind/material/SideSheetBehaviorStateChanges.kt
new file mode 100644
index 00000000..2fd18084
--- /dev/null
+++ b/corbind-material/src/main/kotlin/ru/ldralighieri/corbind/material/SideSheetBehaviorStateChanges.kt
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2022 Vladimir Raupov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ru.ldralighieri.corbind.material
+
+import android.view.View
+import androidx.annotation.CheckResult
+import androidx.coordinatorlayout.widget.CoordinatorLayout
+import com.google.android.material.sidesheet.SideSheetBehavior
+import com.google.android.material.sidesheet.SideSheetCallback
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.channels.ReceiveChannel
+import kotlinx.coroutines.channels.actor
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.flow.channelFlow
+import kotlinx.coroutines.isActive
+import ru.ldralighieri.corbind.internal.InitialValueFlow
+import ru.ldralighieri.corbind.internal.asInitialValueFlow
+import ru.ldralighieri.corbind.internal.corbindReceiveChannel
+
+/**
+ * Perform an action on the state change events from [View] on [SideSheetBehavior].
+ *
+ * @param scope Root coroutine scope
+ * @param capacity Capacity of the channel's buffer (no buffer by default)
+ * @param action An action to perform
+ */
+fun View.sideSheetStateChanges(
+ scope: CoroutineScope,
+ capacity: Int = Channel.RENDEZVOUS,
+ action: suspend (Int) -> Unit
+) {
+ val events = scope.actor(Dispatchers.Main.immediate, capacity) {
+ for (state in channel) action(state)
+ }
+
+ val behavior = getSideSheetBehavior()
+ events.trySend(behavior.state)
+ val callback = callback(scope, events::trySend)
+ behavior.addCallback(callback)
+ events.invokeOnClose { behavior.removeCallback(callback) }
+}
+
+/**
+ * Perform an action on the state change events from [View] on [SideSheetBehavior], inside new
+ * [CoroutineScope].
+ *
+ * @param capacity Capacity of the channel's buffer (no buffer by default)
+ * @param action An action to perform
+ */
+suspend fun View.sideSheetStateChanges(
+ capacity: Int = Channel.RENDEZVOUS,
+ action: suspend (Int) -> Unit
+) = coroutineScope {
+ sideSheetStateChanges(this, capacity, action)
+}
+
+/**
+ * Create a channel which emits the state change events from [View] on [SideSheetBehavior].
+ *
+ * *Note:* A value will be emitted immediately.
+ *
+ * Example:
+ *
+ * ```
+ * launch {
+ * sideSheetBehavior.sideSheetStateChanges(scope)
+ * .consumeEach { /* handle state change */ }
+ * }
+ * ```
+ *
+ * @param scope Root coroutine scope
+ * @param capacity Capacity of the channel's buffer (no buffer by default)
+ */
+@CheckResult
+fun View.sideSheetStateChanges(
+ scope: CoroutineScope,
+ capacity: Int = Channel.RENDEZVOUS
+): ReceiveChannel = corbindReceiveChannel(capacity) {
+ val behavior = getSideSheetBehavior()
+ trySend(behavior.state)
+ val callback = callback(scope, ::trySend)
+ behavior.addCallback(callback)
+ invokeOnClose { behavior.removeCallback(callback) }
+}
+
+/**
+ * Create a flow which emits the state change events from [View] on [SideSheetBehavior].
+ *
+ * *Note:* A value will be emitted immediately.
+ *
+ * Examples:
+ *
+ * ```
+ * // handle initial value
+ * sideSheetBehavior.sideSheetStateChanges()
+ * .onEach { /* handle state change */ }
+ * .flowWithLifecycle(lifecycle)
+ * .launchIn(lifecycleScope) // lifecycle-runtime-ktx
+ *
+ * // drop initial value
+ * sideSheetBehavior.sideSheetStateChanges()
+ * .dropInitialValue()
+ * .onEach { /* handle state change */ }
+ * .flowWithLifecycle(lifecycle)
+ * .launchIn(lifecycleScope) // lifecycle-runtime-ktx
+ * ```
+ */
+@CheckResult
+fun View.sideSheetStateChanges(): InitialValueFlow = channelFlow {
+ val behavior = getSideSheetBehavior()
+ val callback = callback(this, ::trySend)
+ behavior.addCallback(callback)
+ awaitClose { behavior.removeCallback(callback) }
+}.asInitialValueFlow(getSideSheetBehavior().state)
+
+internal fun View.getSideSheetBehavior(): SideSheetBehavior<*> {
+ val params = layoutParams as? CoordinatorLayout.LayoutParams
+ ?: throw IllegalArgumentException("The view is not in a Coordinator Layout.")
+ return params.behavior as SideSheetBehavior<*>?
+ ?: throw IllegalStateException("There's no SideSheetBehavior set on this view.")
+}
+
+@CheckResult
+private fun callback(
+ scope: CoroutineScope,
+ emitter: (Int) -> Unit
+) = object : SideSheetCallback() {
+
+ override fun onStateChanged(sheet: View, newState: Int) {
+ if (scope.isActive) { emitter(newState) }
+ }
+
+ override fun onSlide(sheet: View, slideOffset: Float) = Unit
+}
diff --git a/corbind-navigation/README.md b/corbind-navigation/README.md
index 667cb151..44b81d33 100644
--- a/corbind-navigation/README.md
+++ b/corbind-navigation/README.md
@@ -3,8 +3,10 @@
To add androidx navigation bindings, import `corbind-navigation` module:
-```groovy
-implementation 'ru.ldralighieri.corbind:corbind-navigation:1.6.0'
+```kotlin
+dependencies {
+ implementation("ru.ldralighieri.corbind:corbind-navigation:1.7.0")
+}
```
## List of extensions
diff --git a/corbind-recyclerview/README.md b/corbind-recyclerview/README.md
index f591e400..2e06b89f 100644
--- a/corbind-recyclerview/README.md
+++ b/corbind-recyclerview/README.md
@@ -3,8 +3,10 @@
To add androidx recyclerview bindings, import `corbind-recyclerview` module:
-```groovy
-implementation 'ru.ldralighieri.corbind:corbind-recyclerview:1.6.0'
+```kotlin
+dependencies {
+ implementation("ru.ldralighieri.corbind:corbind-recyclerview:1.7.0")
+}
```
## List of extensions
diff --git a/corbind-slidingpanelayout/README.md b/corbind-slidingpanelayout/README.md
index 3834fee5..3e21e000 100644
--- a/corbind-slidingpanelayout/README.md
+++ b/corbind-slidingpanelayout/README.md
@@ -3,8 +3,10 @@
To add androidx slidingpanelayout bindings, import `corbind-slidingpanelayout` module:
-```groovy
-implementation 'ru.ldralighieri.corbind:corbind-slidingpanelayout:1.6.0'
+```kotlin
+dependencies {
+ implementation("ru.ldralighieri.corbind:corbind-slidingpanelayout:1.7.0")
+}
```
## List of extensions
diff --git a/corbind-swiperefreshlayout/README.md b/corbind-swiperefreshlayout/README.md
index e3e51a87..9904d7b8 100644
--- a/corbind-swiperefreshlayout/README.md
+++ b/corbind-swiperefreshlayout/README.md
@@ -3,8 +3,10 @@
To add androidx swiperefreshlayout bindings, import `corbind-swiperefreshlayout` module:
-```groovy
-implementation 'ru.ldralighieri.corbind:corbind-swiperefreshlayout:1.6.0'
+```kotlin
+dependencies {
+ implementation("ru.ldralighieri.corbind:corbind-swiperefreshlayout:1.7.0")
+}
```
## List of extensions
diff --git a/corbind-viewpager/README.md b/corbind-viewpager/README.md
index 26c38e9e..d6e4e61a 100644
--- a/corbind-viewpager/README.md
+++ b/corbind-viewpager/README.md
@@ -3,8 +3,10 @@
To add androidx viewpager bindings, import `corbind-viewpager` module:
-```groovy
-implementation 'ru.ldralighieri.corbind:corbind-viewpager:1.6.0'
+```kotlin
+dependencies {
+ implementation("ru.ldralighieri.corbind:corbind-viewpager:1.7.0")
+}
```
## List of extensions
diff --git a/corbind-viewpager/src/main/kotlin/ru/ldralighieri/corbind/viewpager/ViewPagerPageScrollEvents.kt b/corbind-viewpager/src/main/kotlin/ru/ldralighieri/corbind/viewpager/ViewPagerPageScrollEvents.kt
index e9eb368f..c5aacf72 100644
--- a/corbind-viewpager/src/main/kotlin/ru/ldralighieri/corbind/viewpager/ViewPagerPageScrollEvents.kt
+++ b/corbind-viewpager/src/main/kotlin/ru/ldralighieri/corbind/viewpager/ViewPagerPageScrollEvents.kt
@@ -126,8 +126,10 @@ private fun listener(
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
if (scope.isActive) {
val event = ViewPagerPageScrollEvent(
- viewPager, position, positionOffset,
- positionOffsetPixels
+ viewPager = viewPager,
+ position = position,
+ positionOffset = positionOffset,
+ positionOffsetPixels = positionOffsetPixels
)
emitter(event)
}
diff --git a/corbind-viewpager2/README.md b/corbind-viewpager2/README.md
index dd391817..1a4f11a1 100644
--- a/corbind-viewpager2/README.md
+++ b/corbind-viewpager2/README.md
@@ -3,8 +3,10 @@
To add androidx viewpager2 bindings, import `corbind-viewpager2` module:
-```groovy
-implementation 'ru.ldralighieri.corbind:corbind-viewpager2:1.6.0'
+```kotlin
+dependencies {
+ implementation("ru.ldralighieri.corbind:corbind-viewpager2:1.7.0")
+}
```
## List of extensions
diff --git a/corbind-viewpager2/src/main/kotlin/ru/ldralighieri/corbind/viewpager2/ViewPager2PageScrollEvents.kt b/corbind-viewpager2/src/main/kotlin/ru/ldralighieri/corbind/viewpager2/ViewPager2PageScrollEvents.kt
index bb93abe4..c96b0b2b 100644
--- a/corbind-viewpager2/src/main/kotlin/ru/ldralighieri/corbind/viewpager2/ViewPager2PageScrollEvents.kt
+++ b/corbind-viewpager2/src/main/kotlin/ru/ldralighieri/corbind/viewpager2/ViewPager2PageScrollEvents.kt
@@ -126,8 +126,10 @@ private fun callback(
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
if (scope.isActive) {
val event = ViewPager2PageScrollEvent(
- viewPager, position, positionOffset,
- positionOffsetPixels
+ viewPager = viewPager,
+ position = position,
+ positionOffset = positionOffset,
+ positionOffsetPixels = positionOffsetPixels
)
emitter(event)
}
diff --git a/corbind/README.md b/corbind/README.md
index 4ac57e11..21442c01 100644
--- a/corbind/README.md
+++ b/corbind/README.md
@@ -3,8 +3,10 @@
To add platform bindings, import `corbind` module:
-```groovy
-implementation 'ru.ldralighieri.corbind:corbind:1.6.0'
+```kotlin
+dependencies {
+ implementation("ru.ldralighieri.corbind:corbind:1.7.0")
+}
```
## List of extensions
diff --git a/corbind/build.gradle.kts b/corbind/build.gradle.kts
index bb097f0c..e0d7bbd7 100644
--- a/corbind/build.gradle.kts
+++ b/corbind/build.gradle.kts
@@ -25,7 +25,6 @@ android {
}
dependencies {
- api(libs.kotlin.stdlib)
api(libs.kotlin.coroutines.android)
api(libs.androidx.annotation)
}
diff --git a/corbind/src/main/kotlin/ru/ldralighieri/corbind/widget/AbsListViewScrollEvents.kt b/corbind/src/main/kotlin/ru/ldralighieri/corbind/widget/AbsListViewScrollEvents.kt
index 818118f9..bfa463fa 100644
--- a/corbind/src/main/kotlin/ru/ldralighieri/corbind/widget/AbsListViewScrollEvents.kt
+++ b/corbind/src/main/kotlin/ru/ldralighieri/corbind/widget/AbsListViewScrollEvents.kt
@@ -138,8 +138,11 @@ private fun listener(
currentScrollState = scrollState
if (scope.isActive) {
val event = AbsListViewScrollEvent(
- absListView, scrollState,
- absListView.firstVisiblePosition, absListView.childCount, absListView.count
+ view = absListView,
+ scrollState = scrollState,
+ firstVisibleItem = absListView.firstVisiblePosition,
+ visibleItemCount = absListView.childCount,
+ totalItemCount = absListView.count
)
emitter(event)
}
@@ -153,8 +156,11 @@ private fun listener(
) {
if (scope.isActive) {
val event = AbsListViewScrollEvent(
- absListView, currentScrollState, firstVisibleItem,
- visibleItemCount, totalItemCount
+ view = absListView,
+ scrollState = currentScrollState,
+ firstVisibleItem = firstVisibleItem,
+ visibleItemCount = visibleItemCount,
+ totalItemCount = totalItemCount
)
emitter(event)
}
diff --git a/corbind/src/main/kotlin/ru/ldralighieri/corbind/widget/AdapterViewSelectionEvents.kt b/corbind/src/main/kotlin/ru/ldralighieri/corbind/widget/AdapterViewSelectionEvents.kt
index 6f99fdec..78b67adf 100644
--- a/corbind/src/main/kotlin/ru/ldralighieri/corbind/widget/AdapterViewSelectionEvents.kt
+++ b/corbind/src/main/kotlin/ru/ldralighieri/corbind/widget/AdapterViewSelectionEvents.kt
@@ -182,8 +182,10 @@ private fun initialValue(adapterView: AdapterView): AdapterView
AdapterViewNothingSelectionEvent(adapterView)
} else {
AdapterViewItemSelectionEvent(
- adapterView, adapterView.selectedView,
- adapterView.selectedItemPosition, adapterView.selectedItemId
+ view = adapterView,
+ selectedView = adapterView.selectedView,
+ position = adapterView.selectedItemPosition,
+ id = adapterView.selectedItemId
)
}
}
diff --git a/corbind/src/main/kotlin/ru/ldralighieri/corbind/widget/PopupMenuItemClicks.kt b/corbind/src/main/kotlin/ru/ldralighieri/corbind/widget/PopupMenuItemClicks.kt
index 63c98041..42434283 100644
--- a/corbind/src/main/kotlin/ru/ldralighieri/corbind/widget/PopupMenuItemClicks.kt
+++ b/corbind/src/main/kotlin/ru/ldralighieri/corbind/widget/PopupMenuItemClicks.kt
@@ -123,7 +123,6 @@ private fun listener(
scope: CoroutineScope,
emitter: (MenuItem) -> Unit
) = PopupMenu.OnMenuItemClickListener {
-
if (scope.isActive) {
emitter(it)
return@OnMenuItemClickListener true
diff --git a/gradle.properties b/gradle.properties
index 168e36b8..aedfbe09 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,20 +1,10 @@
+# Gradle
# https://github.com/Kotlin/dokka/issues/1405
org.gradle.jvmargs=-XX:MaxMetaspaceSize=3G
-
-# AndroidX
-android.useAndroidX=true
-compileSdk=33
-targetSdk=33
-minSdk=14
-
-
# Maven
-SONATYPE_HOST=DEFAULT
-RELEASE_SIGNING_ENABLED=true
-
GROUP=ru.ldralighieri.corbind
-VERSION_NAME=1.6.1-SNAPSHOT
+VERSION_NAME=1.7.0
POM_DESCRIPTION=Kotlin Coroutines binding APIs for Android UI widgets from the platform and support libraries.
@@ -30,3 +20,14 @@ POM_LICENCE_DIST=repo
POM_DEVELOPER_ID=ldralighieri
POM_DEVELOPER_NAME=Vladimir Raupov
POM_DEVELOPER_URL=https://github.com/LDRAlighieri/
+
+SONATYPE_HOST=DEFAULT
+RELEASE_SIGNING_ENABLED=true
+SONATYPE_AUTOMATIC_RELEASE=true
+
+# Android
+android.useAndroidX=true
+buildTools=33.0.1
+compileSdk=33
+targetSdk=33
+minSdk=14
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 329ca624..8c995c42 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,76 +1,77 @@
[versions]
-spotless = "6.8.0"
-gver = "0.43.0"
-detekt = "1.21.0"
+# Plugins
+agp = "7.4.0"
dokka = "1.7.20"
-maven-publish = "0.22.0"
+spotless = "6.13.0"
+mavenPublish = "0.23.2"
+detekt = "1.22.0"
+gver = "0.44.0"
-plugin-android = "7.3.1"
+# Kotlin
+kotlin = "1.8.0"
+kotlinCoroutines = "1.6.4"
-kotlin = "1.7.20"
-kotlin-coroutines = "1.6.4"
+# Androidx
+androidxCore = "1.9.0"
+androidxAnnotation = "1.5.0"
+androidxAppcompat = "1.6.0"
+androidxDrawerlayout = "1.1.1"
+androidxLeanback = "1.0.0"
+androidxNavigation = "2.5.3"
+androidxRecyclerview = "1.2.1"
+androidxSlidingpanelayout = "1.2.0"
+androidxSwiperefreshlayout = "1.1.0"
+androidxViewpager = "1.0.0"
+androidxViewpager2 = "1.0.0"
+androidxLifecycle = "2.5.1"
+androidxActivity = "1.6.1"
+androidxFragment = "1.5.5"
+androidxConstraintlayout = "2.1.4"
-androidx-core = "1.9.0"
-androidx-annotation = "1.5.0"
-androidx-appcompat = "1.5.1"
-androidx-drawerlayout = "1.1.1"
-androidx-leanback = "1.0.0"
-androidx-navigation = "2.5.2"
-androidx-recyclerview = "1.2.1"
-androidx-slidingpanelayout = "1.2.0"
-androidx-swiperefreshlayout = "1.1.0"
-androidx-viewpager = "1.0.0"
-androidx-viewpager2 = "1.0.0"
-androidx-lifecycle = "2.5.1"
-androidx-activity = "1.6.0"
-androidx-fragment = "1.5.3"
-androidx-constraintlayout = "2.1.4"
-
-material = "1.7.0"
+# Google
+material = "1.8.0"
+# Lint
ktlint = "0.46.1"
-[plugins]
-spotless = { id = "com.diffplug.spotless", version.ref = "spotless" }
-gver = { id = "com.github.ben-manes.versions", version.ref = "gver" }
-detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" }
-dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" }
+[libraries]
+# Kotlin
+kotlin-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinCoroutines" }
+# Androidx
+androidx-core = { module = "androidx.core:core", version.ref = "androidxCore" }
+androidx-annotation = { module = "androidx.annotation:annotation", version.ref = "androidxAnnotation" }
+androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidxAppcompat" }
+androidx-drawerlayout = { module = "androidx.drawerlayout:drawerlayout", version.ref = "androidxDrawerlayout" }
+androidx-leanback = { module = "androidx.leanback:leanback", version.ref = "androidxLeanback" }
+androidx-navigation = { module = "androidx.navigation:navigation-runtime", version.ref = "androidxNavigation" }
+androidx-recyclerview = { module = "androidx.recyclerview:recyclerview", version.ref = "androidxRecyclerview" }
+androidx-slidingpanelayout = { module = "androidx.slidingpanelayout:slidingpanelayout", version.ref = "androidxSlidingpanelayout" }
+androidx-swiperefreshlayout = { module = "androidx.swiperefreshlayout:swiperefreshlayout", version.ref = "androidxSwiperefreshlayout" }
+androidx-viewpager = { module = "androidx.viewpager:viewpager", version.ref = "androidxViewpager" }
+androidx-viewpager2 = { module = "androidx.viewpager2:viewpager2", version.ref = "androidxViewpager2" }
+androidx-lifecycle-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "androidxLifecycle" }
+androidx-activity = { module = "androidx.activity:activity", version.ref = "androidxActivity" }
+androidx-fragment = { module = "androidx.fragment:fragment", version.ref = "androidxFragment" }
+androidx-constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version.ref = "androidxConstraintlayout" }
-[libraries]
-android-gradlePlugin = { module = "com.android.tools.build:gradle", version.ref = "plugin-android" }
+# Google
+material = { module = "com.google.android.material:material", version.ref = "material" }
+
+
+# build-logic
+android-gradlePlugin = { module = "com.android.tools.build:gradle", version.ref = "agp" }
kotlin-gradlePlugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
dokka-gradlePlugin = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version.ref = "dokka" }
-publish-gradlePlugin = { module = "com.vanniktech:gradle-maven-publish-plugin", version.ref = "maven-publish" }
spotless-gradlePlugin = { module = "com.diffplug.spotless:spotless-plugin-gradle", version.ref = "spotless" }
-kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk8", version.ref = "kotlin" }
-kotlin-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlin-coroutines" }
-
-androidx-core = { module = "androidx.core:core", version.ref = "androidx-core" }
-androidx-annotation = { module = "androidx.annotation:annotation", version.ref = "androidx-annotation" }
-androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" }
-androidx-drawerlayout = { module = "androidx.drawerlayout:drawerlayout", version.ref = "androidx-drawerlayout" }
-androidx-leanback = { module = "androidx.leanback:leanback", version.ref = "androidx-leanback" }
-androidx-navigation = { module = "androidx.navigation:navigation-runtime", version.ref = "androidx-navigation" }
-androidx-recyclerview = { module = "androidx.recyclerview:recyclerview", version.ref = "androidx-recyclerview" }
-androidx-slidingpanelayout = { module = "androidx.slidingpanelayout:slidingpanelayout", version.ref = "androidx-slidingpanelayout" }
-androidx-swiperefreshlayout = { module = "androidx.swiperefreshlayout:swiperefreshlayout", version.ref = "androidx-swiperefreshlayout" }
-androidx-viewpager = { module = "androidx.viewpager:viewpager", version.ref = "androidx-viewpager" }
-androidx-viewpager2 = { module = "androidx.viewpager2:viewpager2", version.ref = "androidx-viewpager2" }
-androidx-lifecycle-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "androidx-lifecycle" }
-androidx-activity = { module = "androidx.activity:activity", version.ref = "androidx-activity" }
-androidx-fragment = { module = "androidx.fragment:fragment", version.ref = "androidx-fragment" }
-androidx-constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version.ref = "androidx-constraintlayout" }
-
-material = { module = "com.google.android.material:material", version.ref = "material" }
-
-[bundles]
-plugins = [
- "android-gradlePlugin",
- "kotlin-gradlePlugin",
- "dokka-gradlePlugin",
- "publish-gradlePlugin"
-]
+[plugins]
+android-application = { id = "com.android.application", version.ref = "agp" }
+android-library = { id = "com.android.library", version.ref = "agp" }
+kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
+spotless = { id = "com.diffplug.spotless", version.ref = "spotless" }
+maven-publish = { id = "com.vanniktech.maven.publish", version.ref = "mavenPublish" }
+detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" }
+gver = { id = "com.github.ben-manes.versions", version.ref = "gver" }
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index cbff8992..f1ff01ff 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -18,4 +18,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip
diff --git a/sample/build.gradle.kts b/sample/build.gradle.kts
index 44032297..07e0fbee 100644
--- a/sample/build.gradle.kts
+++ b/sample/build.gradle.kts
@@ -20,12 +20,15 @@ plugins {
}
android {
+ namespace = "ru.ldralighieri.corbind.sample"
+
+ val buildTools: String by project
val compileSdk: String by project
val minSdk: String by project
val targetSdk: String by project
@Suppress("LocalVariableName") val VERSION_NAME: String by project
- namespace = "ru.ldralighieri.corbind.sample"
+ buildToolsVersion = buildTools
this.compileSdk = compileSdk.toInt()
defaultConfig {
@@ -39,24 +42,24 @@ android {
}
buildTypes {
- debug {
+ val debug by getting {
isDebuggable = true
isMinifyEnabled = false
isShrinkResources = false
- proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
}
release {
isDebuggable = false
isMinifyEnabled = true
isShrinkResources = true
+ signingConfig = debug.signingConfig
proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
}
}
compileOptions {
- sourceCompatibility = JavaVersion.VERSION_11
- targetCompatibility = JavaVersion.VERSION_11
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
}
packagingOptions {
diff --git a/sample/src/main/res/values-v29/themes.xml b/sample/src/main/res/values-v29/themes.xml
index 808d87fb..95e3cec7 100644
--- a/sample/src/main/res/values-v29/themes.xml
+++ b/sample/src/main/res/values-v29/themes.xml
@@ -14,12 +14,12 @@
~ limitations under the License.
-->
-
+
-
+