Giter Site home page Giter Site logo

reactivecircus / flowbinding Goto Github PK

View Code? Open in Web Editor NEW
900.0 23.0 43.0 15.96 MB

Kotlin Coroutines Flow binding APIs for Android's platform and unbundled UI widgets, inspired by RxBinding.

Home Page: https://reactivecircus.github.io/FlowBinding/

License: Apache License 2.0

Shell 0.46% Kotlin 99.54%
android kotlin kotlin-coroutines kotlin-flow androidx material-components

flowbinding's Introduction

FlowBinding

CI Maven Central Android API License

Kotlin Flow binding APIs for Android's platform and unbundled UI widgets, inspired by RxBinding.

Flow is (conceptually) a reactive streams implementation provided by the kotlinx-coroutines-core artifact.

FlowBinding offers an extensive set of extension functions that turn traditional callbacks / listeners on Android UI widgets into the Flow type.

Article

Download

Dependencies are hosted on Maven Central.

Latest version:

def flowbinding_version = "1.2.0"

Platform Bindings

implementation "io.github.reactivecircus.flowbinding:flowbinding-android:${flowbinding_version}"

AndroidX Bindings

implementation "io.github.reactivecircus.flowbinding:flowbinding-activity:${flowbinding_version}"
implementation "io.github.reactivecircus.flowbinding:flowbinding-appcompat:${flowbinding_version}"
implementation "io.github.reactivecircus.flowbinding:flowbinding-core:${flowbinding_version}"
implementation "io.github.reactivecircus.flowbinding:flowbinding-drawerlayout:${flowbinding_version}"
implementation "io.github.reactivecircus.flowbinding:flowbinding-lifecycle:${flowbinding_version}"
implementation "io.github.reactivecircus.flowbinding:flowbinding-navigation:${flowbinding_version}"
implementation "io.github.reactivecircus.flowbinding:flowbinding-preference:${flowbinding_version}"
implementation "io.github.reactivecircus.flowbinding:flowbinding-recyclerview:${flowbinding_version}"
implementation "io.github.reactivecircus.flowbinding:flowbinding-swiperefreshlayout:${flowbinding_version}"
implementation "io.github.reactivecircus.flowbinding:flowbinding-viewpager:${flowbinding_version}"
implementation "io.github.reactivecircus.flowbinding:flowbinding-viewpager2:${flowbinding_version}"

Material Components Bindings

implementation "io.github.reactivecircus.flowbinding:flowbinding-material:${flowbinding_version}"

Snapshots of the development version are available in Sonatype's snapshots repository.

Usage

Binding UI Events

To observe click events on an Android View:

findViewById<Button>(R.id.button)
    .clicks() // binding API available in flowbinding-android
    .onEach {
        // handle button clicked
    }
    .launchIn(uiScope)

Binding Scope

launchIn(scope) is a shorthand for scope.launch { flow.collect() } provided by the kotlinx-coroutines-core library.

This uiScope in the example above is a CoroutineScope that defines the lifecycle of this Flow. The binding implementation will respect this scope by unregistering the callback / listener automatically when the scope is cancelled.

In the context of Android lifecycle this means the uiScope passed in here should be a scope that's bound to the Lifecycle of the view the widget lives in.

androidx.lifecycle:lifecycle-runtime-ktx:2.2.0 introduced an extension property LifecycleOwner.lifecycleScope: LifecycleCoroutineScope which will be cancelled when the Lifecycle is destroyed.

In an Activity it might look something like this:

class ExampleActivity : AppCompatActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_example)

        findViewById<ViewPager2>(R.id.viewPager)
            .pageSelections() // binding API available in flowbinding-viewpager2
            .onEach { pagePosition ->
                // handle pagePosition
            }
            .launchIn(lifecycleScope) // provided by lifecycle-runtime-ktx
    }
}

In a Fragment:

class ExampleFragment : Fragment(R.layout.example_fragment_layout) {
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        val binding = ExampleFragmentLayoutBinding.bind(view)
        binding.viewPager
            .pageSelections() // binding API available in flowbinding-viewpager2
            .onEach { pagePosition ->
                // handle pagePosition
            }
            .launchIn(viewLifecycleOwner.lifecycleScope) // provided by lifecycle-runtime-ktx
    }
}

Note that with FlowBinding you no longer need to unregister / remove listeners or callbacks in onDestroy() as this is done automatically for you.

Binding UI Events with Additional Information

Some UI widgets might hold a state internally which you might want to observe with a Flow.

For example with a TabLayout you might want to observe and react to the Tab selection events. In this case the binding API returns a Flow of custom TabLayoutSelectionEvent type which contains the currently selected Tab:

tabLayout.tabSelectionEvents()
    .filterIsInstance<TabLayoutSelectionEvent.TabSelected>() // only care about TabSelected events
    .onEach { event ->
        // sync selected tab title to some other UI element
        selectedTabTitle.text = event.tab.text
    }
    .launchIn(uiScope)

Skipping Initial Value

Bindings which emit a stream of state changes return the InitialValueFlow.

An InitialValueFlow emits the current value (state) of the widget immediately upon collection of the Flow.

In some cases you might want to skip the initial emission of the current value. This can be done by calling the skipInitialValue() on the InitialValueFlow:

slider.valueChanges()
    .skipInitialValue()
    .onEach { value ->
        // handle value
    }
    .launchIn(uiScope) // current value won't be emitted immediately

Additional Samples

All binding APIs are documented with Example of usage.

All bindings are covered by instrumented tests which you may want to refer to.

Roadmap

Our goal is to provide most of the bindings provided by RxBinding, while shifting our focus to supporting more modern AndroidX APIs such as ViewPager2 and the new components in Material Components as they become available.

List of all bindings available:

Please feel free to create an issue if you think a useful binding is missing or you want a new binding added to the library.

Credits

This library is inspired by RxBinding which provides RxJava binding APIs for Android's UI widgets.

Many thanks to RxBinding's author Jake Wharton and its contributors.

License

Copyright 2019 Yang Chen

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.

flowbinding's People

Contributors

adambl4 avatar flowmo7 avatar hoc081098 avatar pavlospt avatar renovate[bot] avatar ychescale9 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

flowbinding's Issues

Question: Handling clicks in RecyclerView Adapter

Hello,

I was wondering How can I handle clicks from a view inside a RecyclerView Adapter and later collect them outside this adapter for instance in a Fragment/Activity? I'm probably looking for something like PublishSubject in RxJava

For instance

  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DiscoverHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.section_title, parent, false)
        view.clicks().collect() //How can I somehow propagate those clicks to a property?
        ..............
    }

I used to do this with callbacks but I want to achieve a similar thing using this library.

Suggestion: support Lifecycle events

Thanks for this useful library ๐Ÿ‘

I suggest adding a new artifact flowbinding-lifecycle which supports Flow of Lifecycle events. Here's a proposal of how this could look like:

import androidx.lifecycle.Lifecycle
import androidx.lifecycle.Lifecycle.Event
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.OnLifecycleEvent
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map

fun Lifecycle.events(): Flow<Event> = callbackFlow {
    val observer = object : LifecycleObserver {
        @OnLifecycleEvent(Event.ON_ANY)
        fun onEvent(owner: LifecycleOwner, event: Event) {
            offer(event)
        }
    }
    addObserver(observer)
    awaitClose { removeObserver(observer) }
}

fun Lifecycle.onCreate(): Flow<Unit> =
    events()
        .filter { it == Event.ON_CREATE }
        .map { Unit }

Thank you!

Data classes for event wrappers

What do you think about converting "event wrapper" classes to data classes?
(TextChangeEvent, ScrollEvent, EditorActionEvent, etc)

I see at least two improvements:

  • distinctUntilChanged will work correctly with overloaded equals
  • ability to use destructuring declaration in collect lambdas, for example:
// w/o data class
textView.textChangeEvents().collect {
    doSmth(it.view, it.text)
}

// with data class
textView.textChangeEvents().collect { (view, text, _, _, _) ->
    doSmth(view, text)
}

Issue with conflate() operator in bindings

I use the events() binding in my application. More precisely I use it to listen for view lifecycle events in a Fragment like viewLifecycleOwner.lifecycle.events().

However the ON_START event is swallowed for some reason. For example I do receive ON_CREATE and ON_RESUME but not ON_START. It seems like this is a race conditions as ON_START does occur depending of where/when I listen for these events.

I noticed that you apply a conflate() on the Flow. I copied the code of events() and just removed conflate(). With my version I receive ON_START all the time. So I wonder why do you apply conflate()? It seems you add this to all bindings? Is there a specific reason?

AutoCompleteTextView.textChanges() includes changes on completion

AutoCompleteTextView.textChanges() includes text change events caused by item clicks. Clicking an item fills in the TextView causing a text change event, which is not always desired. Maybe something similar to the following could be added?

fun AutoCompleteTextView.textChangesBeforeCompletion(
    emitImmediately: Boolean = false
): Flow<CharSequence> =
    callbackFlow<CharSequence> {
        checkMainThread()
        val listener = object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) =
                Unit

            override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
                if (isPerformingCompletion) {
                    return
                }

                safeOffer(s)
            }

            override fun afterTextChanged(s: Editable) = Unit
        }

        addTextChangedListener(listener)
        awaitClose { removeTextChangedListener(listener) }
    }
        .startWithCurrentValue(emitImmediately) { text }
        .conflate()

Emit immediately by default

I don't agree with the current false default value for emitImmediately. I would argue most idiomatic reactive code using FlowBinding will want the initial value. In addition, RxBinding emits the initial value by default, and FlowBinding clearly advertises itself as its direct counterpart.

Obviously this is a behavior breaking change, but an important one to get right early.

AS 4.0 Canary 6, Kotlin 1.3.61: e: java.lang.IllegalStateException: Backend Internal error: Exception during code generation

Has anyone seen this error with AS 4.0 Canary 6 and Kotlin 1.3.61?
As soon as I try using any of the FlowBindings stuff, it fails with this error.

Commented out everything except this:
timeAllowed.clicks().onEach { tableTimeViewModel.onTimeClicked() }.launchIn(lifecycleScope)
and it causes the compiler to fail. Commenting it out lets me build the project again.

This is the full gradle error if that helps:

e: java.lang.IllegalStateException: Backend Internal error: Exception during code generation
Element is unknownThe root cause java.lang.AssertionError was thrown at: org.jetbrains.kotlin.backend.jvm.lower.AddContinuationLowering.addCreate(AddContinuationLowering.kt:250)
	at org.jetbrains.kotlin.codegen.CompilationErrorHandler.lambda$static$0(CompilationErrorHandler.java:35)
	at org.jetbrains.kotlin.backend.jvm.JvmBackendFacade.doGenerateFilesInternal$backend_jvm(JvmBackendFacade.kt:93)
	at org.jetbrains.kotlin.backend.jvm.JvmBackendFacade.doGenerateFilesInternal$backend_jvm$default(JvmBackendFacade.kt:64)
	at org.jetbrains.kotlin.backend.jvm.JvmBackendFacade.doGenerateFilesInternal$backend_jvm(JvmBackendFacade.kt:52)
	at org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory.generateModule(JvmIrCodegenFactory.kt:36)
	at org.jetbrains.kotlin.codegen.KotlinCodegenFacade.doGenerateFiles(KotlinCodegenFacade.java:47)
	at org.jetbrains.kotlin.codegen.KotlinCodegenFacade.compileCorrectFiles(KotlinCodegenFacade.java:39)
	at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.generate(KotlinToJVMBytecodeCompiler.kt:638)
	at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules$cli(KotlinToJVMBytecodeCompiler.kt:198)
	at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:172)
	at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:56)
	at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:85)
	at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:43)
	at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:104)
	at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:349)
	at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:105)
	at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileIncrementally(IncrementalCompilerRunner.kt:237)
	at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:88)
	at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execIncrementalCompiler(CompileServiceImpl.kt:606)
	at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:99)
	at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1645)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:357)
	at sun.rmi.transport.Transport$1.run(Transport.java:200)
	at sun.rmi.transport.Transport$1.run(Transport.java:197)
	at java.security.AccessController.doPrivileged(Native Method)
	at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
	at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:573)
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:834)
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:688)
	at java.security.AccessController.doPrivileged(Native Method)
	at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:687)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.AssertionError: Assertion failed
	at org.jetbrains.kotlin.backend.jvm.lower.AddContinuationLowering.addCreate(AddContinuationLowering.kt:250)
	at org.jetbrains.kotlin.backend.jvm.lower.AddContinuationLowering.generateContinuationClassForLambda(AddContinuationLowering.kt:137)
	at org.jetbrains.kotlin.backend.jvm.lower.AddContinuationLowering.lower(AddContinuationLowering.kt:72)
	at org.jetbrains.kotlin.backend.common.phaser.PhaseBuildersKt$makeIrFilePhase$1.invoke(PhaseBuilders.kt:206)
	at org.jetbrains.kotlin.backend.common.phaser.PhaseBuildersKt$makeIrFilePhase$1.invoke(PhaseBuilders.kt:204)
	at org.jetbrains.kotlin.backend.common.phaser.AbstractNamedPhaseWrapper$runBody$1.invoke(CompilerPhase.kt:128)
	at org.jetbrains.kotlin.backend.common.phaser.CompilerPhaseKt.downlevel(CompilerPhase.kt:24)
	at org.jetbrains.kotlin.backend.common.phaser.AbstractNamedPhaseWrapper.runBody(CompilerPhase.kt:127)
	at org.jetbrains.kotlin.backend.common.phaser.AbstractNamedPhaseWrapper.invoke(CompilerPhase.kt:105)
	at org.jetbrains.kotlin.backend.common.phaser.CompositePhase.invoke(PhaseBuilders.kt:29)
	at org.jetbrains.kotlin.backend.common.phaser.PhaseBuildersKt$performByIrFile$1.invoke(PhaseBuilders.kt:177)
	at org.jetbrains.kotlin.backend.common.phaser.PhaseBuildersKt$performByIrFile$1.invoke(PhaseBuilders.kt:169)
	at org.jetbrains.kotlin.backend.common.phaser.AbstractNamedPhaseWrapper$runBody$1.invoke(CompilerPhase.kt:128)
	at org.jetbrains.kotlin.backend.common.phaser.CompilerPhaseKt.downlevel(CompilerPhase.kt:24)
	at org.jetbrains.kotlin.backend.common.phaser.AbstractNamedPhaseWrapper.runBody(CompilerPhase.kt:127)
	at org.jetbrains.kotlin.backend.common.phaser.AbstractNamedPhaseWrapper.invoke(CompilerPhase.kt:105)
	at org.jetbrains.kotlin.backend.common.phaser.CompositePhase.invoke(PhaseBuilders.kt:29)
	at org.jetbrains.kotlin.backend.common.phaser.AbstractNamedPhaseWrapper$runBody$1.invoke(CompilerPhase.kt:128)
	at org.jetbrains.kotlin.backend.common.phaser.CompilerPhaseKt.downlevel(CompilerPhase.kt:24)
	at org.jetbrains.kotlin.backend.common.phaser.AbstractNamedPhaseWrapper.runBody(CompilerPhase.kt:127)
	at org.jetbrains.kotlin.backend.common.phaser.AbstractNamedPhaseWrapper.invoke(CompilerPhase.kt:105)
	at org.jetbrains.kotlin.backend.common.phaser.CompositePhase.invoke(PhaseBuilders.kt:29)
	at org.jetbrains.kotlin.backend.common.phaser.CompilerPhaseKt.invokeToplevel(CompilerPhase.kt:42)
	at org.jetbrains.kotlin.backend.jvm.JvmLower.lower(JvmLower.kt:288)
	at org.jetbrains.kotlin.backend.jvm.JvmBackendFacade.doGenerateFilesInternal$backend_jvm(JvmBackendFacade.kt:91)
	... 36 more


FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:compileDebugKotlin'.
> Internal compiler error. See log for more details

Need to manually depend on flowbinding-common since 1.0.0-alpha01

Since 1.0.0-alpha01 I need to manually add a dependency to flowbinding-common, otherwise I get the following error:

Cannot access class 'reactivecircus.flowbinding.common.InitialValueFlow'. Check your module classpath for missing or conflicting dependencies

Activity Result API

I wonder if it would be possible to add bindings for the new Activity Result API? It would be nice to have if there's a clean way to do it.

I made a quick attempt, but it doesn't work because registerForActivityResult must be called before STARTED and there doesn't seem to be any way to add callbacks after registering.

fun <I, O> ActivityResultCaller.activityResults(contract: ActivityResultContract<I, O>) = callbackFlow {
        val launcher = registerForActivityResult(contract) { result ->
            safeOffer(result)
        }
        awaitClose { launcher.unregister() }
    }

fun <I, O> ActivityResultCaller.launchForActivityResults(contract: ActivityResultContract<I, O>, input: I) =
    registerForActivityResult(contract) {}.launch(input)

LifecycleOwner is attempting to register while current state is RESUMED. LifecycleOwners must call register before they are STARTED

Nice work on the 1.0 release!

LeakCanary shows leaks on standard usage

Hi,

LeakCanary just showed me this:
image

It seems like the root of the leak is the lifecycle registry:
image

Do you an idea why this is happening?

The code that caused that is:

binding.goBtn.clicks()
        .onEach { navigateToAnotherFragment() }
        .launchIn(lifecycleScope)

Unresolved reference with 1.0.0-alpha03 in Kotlin 1.4

After update to 1.0.0-alpha03 and Kotlin 1.4 I received red error in imports of extensions functions like beforeTextChanges and etc and of course this function unavailable in code.

I think it related with explicit API mode.

InitialValueFlow

Following the discussion in #94, we've decided to emit the current value immediately upon collection for the bindings which emit states to align with the default behavior of RxBinding.

Instead of changing emitImmediately: Boolean = true, let's add a new InitialValueFlow type with a function for skipping the initial emission, for better type safety:

class InitialValueFlow<T>(private val flow: Flow<T>) : Flow<T> by flow {
    fun skipInitialValue(): Flow<T> = flow.drop(1)
}

This will be a breaking change.

Don't depend on unstable AndroidX libs

flowbinding-recyclerview 0.11.1 currently depends on androidx.recyclerview:1.2.0-alpha02.

I think this is a mistake, as it transitively pulls in unstable libs the consumer may not want.

I propose a policy of never depending on unstable AndroidX library versions.

If this is a required use case, separate unstable artifacts could be published.

Why doesn't clicks() return the Flow<View>

I want to merge multiple click events, but Flow prevents me from distinguishing the source of the events
merge(binding.actionWechat.clicks(), binding.actionFacebook.clicks(), binding.actionTwitter.clicks(), binding.actionWhatapp.clicks()) .onEach { }

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Rate-Limited

These updates are currently rate-limited. Click on a checkbox below to force their creation now.

  • Update dependency gradle to v8.0.1
  • Update dependency androidx.constraintlayout:constraintlayout to v2.1.4
  • Update dependency androidx.coordinatorlayout:coordinatorlayout to v1.2.0
  • Update dependency androidx.preference:preference-ktx to v1.2.0
  • Update dependency androidx.test:monitor to v1.6.1
  • Update dependency androidx.test:rules to v1.5.0
  • Update dependency androidx.test:runner to v1.5.2
  • Update dependency com.google.android.material:material to v1.8.0
  • Update dependency com.vanniktech:gradle-maven-publish-plugin to v0.24.0
  • Update dependency org.jetbrains.kotlinx:binary-compatibility-validator to v0.13.0
  • Update actions/cache action to v3
  • ๐Ÿ” Create all rate-limited PRs at once ๐Ÿ”

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

github-actions
.github/workflows/build.yml
  • actions/checkout v3
  • gradle/wrapper-validation-action v1
  • actions/setup-java v3
  • gradle/gradle-build-action v2
  • actions/checkout v3
  • gradle/wrapper-validation-action v1
  • actions/setup-java v3
  • gradle/gradle-build-action v2
  • actions/checkout v3
  • gradle/wrapper-validation-action v1
  • actions/setup-java v3
  • actions/cache v2
  • reactivecircus/android-emulator-runner v2
  • reactivecircus/android-emulator-runner v2
  • actions/checkout v3
  • gradle/wrapper-validation-action v1
  • actions/setup-java v3
  • gradle/gradle-build-action v2
.github/workflows/deploy-website.yml
  • actions/checkout v3
  • gradle/wrapper-validation-action v1
  • actions/setup-java v3
  • gradle/gradle-build-action v2
  • actions/setup-python v4
gradle
gradle.properties
settings.gradle.kts
build.gradle.kts
buildSrc/settings.gradle.kts
buildSrc/build.gradle.kts
flowbinding-activity/gradle.properties
flowbinding-activity/build.gradle.kts
flowbinding-activity/fixtures/build.gradle.kts
flowbinding-android/gradle.properties
flowbinding-android/build.gradle.kts
flowbinding-android/fixtures/build.gradle.kts
flowbinding-appcompat/gradle.properties
flowbinding-appcompat/build.gradle.kts
flowbinding-appcompat/fixtures/build.gradle.kts
flowbinding-common/gradle.properties
flowbinding-common/build.gradle.kts
flowbinding-core/gradle.properties
flowbinding-core/build.gradle.kts
flowbinding-core/fixtures/build.gradle.kts
flowbinding-drawerlayout/gradle.properties
flowbinding-drawerlayout/build.gradle.kts
flowbinding-drawerlayout/fixtures/build.gradle.kts
flowbinding-lifecycle/gradle.properties
flowbinding-lifecycle/build.gradle.kts
flowbinding-lifecycle/fixtures/build.gradle.kts
flowbinding-material/gradle.properties
flowbinding-material/build.gradle.kts
flowbinding-material/fixtures/build.gradle.kts
flowbinding-navigation/gradle.properties
flowbinding-navigation/build.gradle.kts
flowbinding-navigation/fixtures/build.gradle.kts
flowbinding-preference/gradle.properties
flowbinding-preference/build.gradle.kts
flowbinding-preference/fixtures/build.gradle.kts
flowbinding-recyclerview/gradle.properties
flowbinding-recyclerview/build.gradle.kts
flowbinding-recyclerview/fixtures/build.gradle.kts
flowbinding-swiperefreshlayout/gradle.properties
flowbinding-swiperefreshlayout/build.gradle.kts
flowbinding-swiperefreshlayout/fixtures/build.gradle.kts
flowbinding-viewpager/gradle.properties
flowbinding-viewpager/build.gradle.kts
flowbinding-viewpager/fixtures/build.gradle.kts
flowbinding-viewpager2/gradle.properties
flowbinding-viewpager2/build.gradle.kts
flowbinding-viewpager2/fixtures/build.gradle.kts
gradle/libs.versions.toml
  • org.jetbrains.kotlin:kotlin-gradle-plugin 1.8.10
  • org.jetbrains.dokka:dokka-gradle-plugin 1.7.20
  • com.android.tools.build:gradle 7.4.1
  • com.vanniktech:gradle-maven-publish-plugin 0.23.2
  • org.jetbrains.kotlinx:binary-compatibility-validator 0.12.1
  • io.gitlab.arturbosch.detekt:detekt-gradle-plugin 1.22.0
  • com.android.tools.lint:lint 30.4.1
  • com.android.tools.lint:lint-api 30.4.1
  • com.android.tools.lint:lint-tests 30.4.1
  • org.jetbrains.kotlinx:kotlinx-coroutines-core 1.6.4
  • org.jetbrains.kotlinx:kotlinx-coroutines-android 1.6.4
  • org.jetbrains.kotlinx:kotlinx-coroutines-test 1.6.4
  • androidx.core:core-ktx 1.9.0
  • androidx.annotation:annotation 1.5.0
  • androidx.appcompat:appcompat 1.6.1
  • androidx.activity:activity 1.6.1
  • androidx.fragment:fragment-ktx 1.5.5
  • androidx.fragment:fragment-testing 1.5.5
  • androidx.coordinatorlayout:coordinatorlayout 1.1.0
  • androidx.recyclerview:recyclerview 1.2.1
  • androidx.viewpager:viewpager 1.0.0
  • androidx.viewpager2:viewpager2 1.0.0
  • androidx.swiperefreshlayout:swiperefreshlayout 1.1.0
  • androidx.drawerlayout:drawerlayout 1.1.1
  • androidx.constraintlayout:constraintlayout 2.0.4
  • androidx.lifecycle:lifecycle-runtime-ktx 2.5.1
  • androidx.lifecycle:lifecycle-runtime-testing 2.5.1
  • androidx.lifecycle:lifecycle-common-java8 2.5.1
  • androidx.navigation:navigation-runtime-ktx 2.5.3
  • androidx.navigation:navigation-fragment-ktx 2.5.3
  • androidx.preference:preference-ktx 1.1.1
  • androidx.test:monitor 1.4.1-alpha01
  • androidx.test:rules 1.4.1-alpha01
  • androidx.test:runner 1.4.1-alpha01
  • androidx.test.ext:junit-ktx 1.1.4-alpha01
  • androidx.test.espresso:espresso-core 3.5.0-alpha01
  • androidx.test.espresso:espresso-contrib 3.5.0-alpha01
  • androidx.test.espresso:espresso-intents 3.5.0-alpha01
  • com.google.android.material:material 1.6.0
  • io.github.reactivecircus.blueprint:blueprint-testing-robot 1.18.0
  • junit:junit 4.13.2
  • com.google.truth:truth 1.1.3
lint-rules/build.gradle.kts
testing-infra/build.gradle.kts
gradle-wrapper
gradle/wrapper/gradle-wrapper.properties
  • gradle 8.0

  • Check this box to trigger a request for Renovate to run again on this repository

Expose common dependencies (like safeOffer) as public apis

I'm using this library for all standard views, but every now and again i have to use external library that don't have support of FlowBinding. I'd love to add a new extension for it using the same method used by all FlowBinding methods. It would be pretty straightforward, but functions like safeOffer are restricted to library group. I'm not sure if you would want to make those public, since it is technically an implementation detail, but it would make my life better :)

Lint errors with 1.1.0 related to Java version

When I run Android Lint on my code, I get this error with FlowBinding 1.1.0.

It works with 1.0.0.

> Task :app:kaptStagingReleaseKotlin
/path/to/SomeFragment.java:69: error: cannot access LayoutChangeEvent
    private final void handleRecyclerViewBottomChange(reactivecircus.flowbinding.android.view.LayoutChangeEvent event) {
                                                                                             ^
  bad class file: /Users/graham/.gradle/caches/transforms-3/a5f9611dd5c277a906f0dc6820dfc2bd/transformed/jetified-flowbinding-android-1.1.0-api.jar(reactivecircus/flowbinding/android/view/LayoutChangeEvent.class
    class file has wrong version 55.0, should be 52.0
    Please remove or make sure it appears in the correct subdirectory of the classpath.
> Task :app:kaptStagingReleaseKotlin FAILED

FAILURE: Build failed with an exception.

The code appears to compile and run correctly; it's just a Lint error.

I have these build options:

    compileOptions {
        coreLibraryDesugaringEnabled true
        sourceCompatibility 1.8
        targetCompatibility 1.8
    }

    kotlinOptions {
        jvmTarget = '1.8'
    }

Suggestion: Expose `fromUser` parameter in Slider.valueChanges()

I've encountered a use-case where I need to filter out the valueChanges() events from a Slider on whether the change has been initiated by a user-input or programmatically.
The Slider.OnChangeListener provides a boolean parameter fromUser for that indication.

I would see two possible approaches for such a functionality:

1. Expose the fromUser boolean in the returned Flow

fun Slider.valueChangesWithFromUser(emitImmediately: Boolean = false): Flow<Pair<Float, Boolean>>

This would, however, introduce a second method for valuesChanged (as for the majority of uses, the fromUser parameter will not be necessary and will result in unnecessary packing / unpacking of the actual float variable), and the Pair as a return type may not be self describing.

2. Introduce an optional parameter to tell the method which events to return

fun Slider.valueChangesWithFromUser(emitImmediately: Boolean = false, fromUser: Boolean? = null): Flow<Float>

This way, the method would encapsulate the filter logic, which I would have seen as:

  • fromUser = null: all events are emitted
  • fromUser = false: only events not initiated by a user input are emitted
  • fromUser = true: only events initiated by a user input are emitted

Personally I would prefer the second solution, but I would love to hear your opinion on this, and if you like either approach and think this has a place in the library, I would be happy to create a PR for that.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.