├── .buildscript └── deploy_website.sh ├── .github └── workflows │ ├── build.yml │ └── deploy-website.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── RELEASING.md ├── build.gradle.kts ├── buildSrc ├── build.gradle.kts ├── settings.gradle.kts └── src │ └── main │ └── kotlin │ └── reactivecircus │ └── flowbinding │ ├── AdditionalCompilerArgs.kt │ ├── AndroidSdk.kt │ ├── ApiCheckConfigs.kt │ ├── DetektConfigs.kt │ ├── DokkaConfigs.kt │ ├── Environment.kt │ ├── FlowBindingExtension.kt │ ├── FlowBindingPlugin.kt │ ├── ProjectConfigurations.kt │ ├── Publishing.kt │ └── SlimTests.kt ├── detekt.yml ├── docs └── images │ └── reactive_circus_logo.png ├── flowbinding-activity ├── README.md ├── api │ └── flowbinding-activity.api ├── build.gradle.kts ├── fixtures │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── reactivecircus │ │ │ └── flowbinding │ │ │ └── activity │ │ │ └── fixtures │ │ │ └── ActivityFragment.kt │ │ └── res │ │ └── layout │ │ └── fragment_activity.xml ├── gradle.properties └── src │ ├── androidTest │ └── java │ │ └── reactivecircus │ │ └── flowbinding │ │ └── activity │ │ └── OnBackPressedDispatcherBackPressedFlowTest.kt │ └── main │ ├── AndroidManifest.xml │ └── java │ └── reactivecircus │ └── flowbinding │ └── activity │ └── OnBackPressedDispatcherBackPressedFlow.kt ├── flowbinding-android ├── README.md ├── api │ └── flowbinding-android.api ├── build.gradle.kts ├── fixtures │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── reactivecircus │ │ │ └── flowbinding │ │ │ └── android │ │ │ └── fixtures │ │ │ ├── view │ │ │ └── AndroidViewFragment.kt │ │ │ └── widget │ │ │ ├── AbsListFragment.kt │ │ │ ├── AndroidWidgetFragment.kt │ │ │ ├── AutoCompleteViewFragment.kt │ │ │ └── ListFragment.kt │ │ └── res │ │ └── layout │ │ ├── fragment_abs_list.xml │ │ ├── fragment_android_view.xml │ │ ├── fragment_android_widget.xml │ │ ├── fragment_auto_complete_view.xml │ │ └── fragment_list.xml ├── gradle.properties └── src │ ├── androidTest │ └── java │ │ └── reactivecircus │ │ └── flowbinding │ │ └── android │ │ ├── testutil │ │ └── TestMenuItem.kt │ │ ├── view │ │ ├── MenuItemActionViewEventFlowTest.kt │ │ ├── MenuItemClickedFlowTest.kt │ │ ├── ViewAttachEventFlowTest.kt │ │ ├── ViewClickedFlowTest.kt │ │ ├── ViewDragFlowTest.kt │ │ ├── ViewDrawFlowTest.kt │ │ ├── ViewFocusChangedFlowTest.kt │ │ ├── ViewGlobalLayoutFlowTest.kt │ │ ├── ViewGroupHierarchyChangeEventFlowTest.kt │ │ ├── ViewHoverFlowTest.kt │ │ ├── ViewKeyEventFlowTest.kt │ │ ├── ViewLayoutChangeEventFlowTest.kt │ │ ├── ViewLayoutChangeFlowTest.kt │ │ ├── ViewLongClickedFlowTest.kt │ │ ├── ViewPreDrawFlowTest.kt │ │ ├── ViewScrollChangeEventFlowTest.kt │ │ ├── ViewSystemUiVisibilityChangeFlowTest.kt │ │ └── ViewTouchFlowTest.kt │ │ └── widget │ │ ├── AbsListViewScrollEventFlowTest.kt │ │ ├── AdapterDataChangeFlowTest.kt │ │ ├── AdapterViewItemClickEventFlowTest.kt │ │ ├── AdapterViewItemClickFlowTest.kt │ │ ├── AdapterViewItemLongClickEventFlowTest.kt │ │ ├── AdapterViewItemLongClickFlowTest.kt │ │ ├── AdapterViewItemSelectionFlowTest.kt │ │ ├── AdapterViewSelectionEventFlowTest.kt │ │ ├── AutoCompleteTextViewDismissFlowTest.kt │ │ ├── AutoCompleteTextViewItemClickEventFlowTest.kt │ │ ├── CompoundButtonCheckedChangedFlowTest.kt │ │ ├── PopupMenuDismissFlowTest.kt │ │ ├── PopupMenuItemClickFlowTest.kt │ │ ├── RadioGroupCheckedChangedFlowTest.kt │ │ ├── RatingBarRatingChangeEventFlowTest.kt │ │ ├── RatingBarRatingChangeFlowTest.kt │ │ ├── SearchViewQueryTextChangeFlowTest.kt │ │ ├── SearchViewQueryTextEventFlowTest.kt │ │ ├── SeekBarChangeEventFlowTest.kt │ │ ├── SeekBarProgressChangeFlowTest.kt │ │ ├── TextViewAfterTextChangeEventFlowTest.kt │ │ ├── TextViewBeforeTextChangeEventFlowTest.kt │ │ ├── TextViewEditorActionEventFlowTest.kt │ │ ├── TextViewTextChangeEventFlowTest.kt │ │ └── TextViewTextChangeFlowTest.kt │ └── main │ ├── AndroidManifest.xml │ └── java │ └── reactivecircus │ └── flowbinding │ └── android │ ├── view │ ├── MenuItemActionViewEventFlow.kt │ ├── MenuItemClickedFlow.kt │ ├── ViewAttachEventFlow.kt │ ├── ViewClickedFlow.kt │ ├── ViewDragFlow.kt │ ├── ViewDrawFlow.kt │ ├── ViewFocusChangedFlow.kt │ ├── ViewGlobalLayoutFlow.kt │ ├── ViewGroupHierarchyChangeEventFlow.kt │ ├── ViewHoverFlow.kt │ ├── ViewKeyEventFlow.kt │ ├── ViewLayoutChangeEventFlow.kt │ ├── ViewLayoutChangeFlow.kt │ ├── ViewLongClickedFlow.kt │ ├── ViewPreDrawFlow.kt │ ├── ViewScrollChangeEventFlow.kt │ ├── ViewSystemUiVisibilityChangeFlow.kt │ └── ViewTouchFlow.kt │ └── widget │ ├── AbsListViewScrollEventFlow.kt │ ├── AdapterDataChangeFlow.kt │ ├── AdapterViewItemClickEventFlow.kt │ ├── AdapterViewItemClickFlow.kt │ ├── AdapterViewItemLongClickEventFlow.kt │ ├── AdapterViewItemLongClickFlow.kt │ ├── AdapterViewItemSelectionFlow.kt │ ├── AdapterViewSelectionEventFlow.kt │ ├── AutoCompleteTextViewDismissFlow.kt │ ├── AutoCompleteTextViewItemClickEventFlow.kt │ ├── CompoundButtonCheckedChangedFlow.kt │ ├── PopupMenuDismissFlow.kt │ ├── PopupMenuItemClickFlow.kt │ ├── RadioGroupCheckedChangedFlow.kt │ ├── RatingBarRatingChangeEventFlow.kt │ ├── RatingBarRatingChangeFlow.kt │ ├── SearchViewQueryTextChangeFlow.kt │ ├── SearchViewQueryTextEventFlow.kt │ ├── SeekBarChangeEventFlow.kt │ ├── SeekBarProgressChangeFlow.kt │ ├── TextViewAfterTextChangeEventFlow.kt │ ├── TextViewBeforeTextChangeEventFlow.kt │ ├── TextViewEditorActionEventFlow.kt │ ├── TextViewTextChangeEventFlow.kt │ └── TextViewTextChangeFlow.kt ├── flowbinding-appcompat ├── README.md ├── api │ └── flowbinding-appcompat.api ├── build.gradle.kts ├── fixtures │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── reactivecircus │ │ │ └── flowbinding │ │ │ └── appcompat │ │ │ └── fixtures │ │ │ └── AppCompatFragment.kt │ │ └── res │ │ └── layout │ │ └── fragment_appcompat.xml ├── gradle.properties └── src │ ├── androidTest │ └── java │ │ └── reactivecircus │ │ └── flowbinding │ │ └── appcompat │ │ ├── ActionMenuViewItemClickFlowTest.kt │ │ ├── PopupMenuDismissFlowTest.kt │ │ ├── PopupMenuItemClickFlowTest.kt │ │ ├── SearchViewQueryTextChangeFlowTest.kt │ │ ├── SearchViewQueryTextEventFlowTest.kt │ │ ├── ToolbarItemClickFlowTest.kt │ │ └── ToolbarNavigationClickFlowTest.kt │ └── main │ ├── AndroidManifest.xml │ └── java │ └── reactivecircus │ └── flowbinding │ └── appcompat │ ├── ActionMenuViewItemClickFlow.kt │ ├── PopupMenuDismissFlow.kt │ ├── PopupMenuItemClickFlow.kt │ ├── SearchViewQueryTextChangeFlow.kt │ ├── SearchViewQueryTextEventFlow.kt │ ├── ToolbarItemClickFlow.kt │ └── ToolbarNavigationClickFlow.kt ├── flowbinding-common ├── README.md ├── api │ └── flowbinding-common.api ├── build.gradle.kts ├── gradle.properties └── src │ ├── androidTest │ └── java │ │ └── reactivecircus │ │ └── flowbinding │ │ └── common │ │ └── CheckMainThreadTest.kt │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── reactivecircus │ │ └── flowbinding │ │ └── common │ │ ├── CheckMainThread.kt │ │ └── InitialValueFlow.kt │ └── test │ └── java │ └── reactivecircus │ └── flowbinding │ └── common │ └── InitialValueFlowTest.kt ├── flowbinding-core ├── README.md ├── api │ └── flowbinding-core.api ├── build.gradle.kts ├── fixtures │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── reactivecircus │ │ │ └── flowbinding │ │ │ └── core │ │ │ └── fixtures │ │ │ └── CoreFragment.kt │ │ └── res │ │ └── layout │ │ └── fragment_core.xml ├── gradle.properties └── src │ ├── androidTest │ └── java │ │ └── reactivecircus │ │ └── flowbinding │ │ └── core │ │ └── NestedScrollViewScrollChangeEventFlowTest.kt │ └── main │ ├── AndroidManifest.xml │ └── java │ └── reactivecircus │ └── flowbinding │ └── core │ └── NestedScrollViewScrollChangeEventFlow.kt ├── flowbinding-drawerlayout ├── README.md ├── api │ └── flowbinding-drawerlayout.api ├── build.gradle.kts ├── fixtures │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── reactivecircus │ │ │ └── flowbinding │ │ │ └── drawerlayout │ │ │ └── fixtures │ │ │ └── DrawerLayoutFragment.kt │ │ └── res │ │ └── layout │ │ └── fragment_drawer_layout.xml ├── gradle.properties └── src │ ├── androidTest │ └── java │ │ └── reactivecircus │ │ └── flowbinding │ │ └── drawerlayout │ │ └── DrawerLayoutDrawerStateChangedFlowTest.kt │ └── main │ ├── AndroidManifest.xml │ └── java │ └── reactivecircus │ └── flowbinding │ └── drawerlayout │ └── DrawerLayoutDrawerStateChangedFlow.kt ├── flowbinding-lifecycle ├── README.md ├── api │ └── flowbinding-lifecycle.api ├── build.gradle.kts ├── fixtures │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── reactivecircus │ │ │ └── flowbinding │ │ │ └── lifecycle │ │ │ └── fixtures │ │ │ └── LifecycleFragment.kt │ │ └── res │ │ └── layout │ │ └── fragment_lifecycle.xml ├── gradle.properties └── src │ ├── androidTest │ └── java │ │ └── reactivecircus │ │ └── flowbinding │ │ └── lifecycle │ │ └── LifecycleEventFlowTest.kt │ └── main │ ├── AndroidManifest.xml │ └── java │ └── reactivecircus │ └── flowbinding │ └── lifecycle │ └── LifecycleEventFlow.kt ├── flowbinding-material ├── README.md ├── api │ └── flowbinding-material.api ├── build.gradle.kts ├── fixtures │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── reactivecircus │ │ │ └── flowbinding │ │ │ └── material │ │ │ └── fixtures │ │ │ ├── MaterialFragment1.kt │ │ │ └── MaterialFragment2.kt │ │ └── res │ │ ├── layout │ │ ├── fragment_material_1.xml │ │ └── fragment_material_2.xml │ │ └── menu │ │ ├── bottom_navigation.xml │ │ └── side_navigation.xml ├── gradle.properties └── src │ ├── androidTest │ └── java │ │ └── reactivecircus │ │ └── flowbinding │ │ └── material │ │ ├── AppBarLayoutOffsetChangedFlowTest.kt │ │ ├── BottomSheetBehaviorSlidedFlowTest.kt │ │ ├── BottomSheetBehaviorStateChangedFlowTest.kt │ │ ├── ChipCloseIconClickedFlowTest.kt │ │ ├── ChipGroupCheckedChangedFlowTest.kt │ │ ├── MaterialButtonCheckedChangedFlowTest.kt │ │ ├── MaterialButtonToggleGroupCheckedChangedFlowTest.kt │ │ ├── MaterialCardViewCheckedChangedFlowTest.kt │ │ ├── MaterialDatePickerCancelFlowTest.kt │ │ ├── MaterialDatePickerDismissFlowTest.kt │ │ ├── MaterialDatePickerNegativeButtonClickFlowTest.kt │ │ ├── MaterialDatePickerPositiveButtonClickFlowTest.kt │ │ ├── MaterialTimePickerCancelFlowTest.kt │ │ ├── MaterialTimePickerDismissFlowTest.kt │ │ ├── MaterialTimePickerNegativeButtonClickFlowTest.kt │ │ ├── MaterialTimePickerPositiveButtonClickFlowTest.kt │ │ ├── NavigationBarViewItemReselectedFlowTest.kt │ │ ├── NavigationBarViewItemSelectedFlowTest.kt │ │ ├── NavigationViewItemSelectedFlowTest.kt │ │ ├── RangeSliderChangeEventFlowTest.kt │ │ ├── RangeSliderTouchEventFlowTest.kt │ │ ├── RangeSliderValuesChangeFlowTest.kt │ │ ├── SliderChangeEventFlowTest.kt │ │ ├── SliderTouchEventFlowTest.kt │ │ ├── SliderValueChangeFlowTest.kt │ │ ├── SnackbarDismissedFlowTest.kt │ │ ├── SnackbarShownFlowTest.kt │ │ ├── SwipeDismissBehaviorDismissedFlowTest.kt │ │ ├── SwipeDismissBehaviorDragStateChangedFlowTest.kt │ │ ├── TabLayoutTabSelectionEventFlowTest.kt │ │ ├── TextInputLayoutIconClickedFlowTest.kt │ │ └── TextInputLayoutIconLongClickedFlowTest.kt │ └── main │ ├── AndroidManifest.xml │ └── java │ └── reactivecircus │ └── flowbinding │ └── material │ ├── AppBarLayoutOffsetChangedFlow.kt │ ├── BottomNavigationViewItemReselectedFlow.kt │ ├── BottomNavigationViewItemSelectedFlow.kt │ ├── BottomSheetBehaviorSlidedFlow.kt │ ├── BottomSheetBehaviorStateChangedFlow.kt │ ├── ChipCloseIconClickedFlow.kt │ ├── ChipGroupCheckedChangedFlow.kt │ ├── MaterialButtonCheckedChangedFlow.kt │ ├── MaterialButtonToggleGroupCheckedChangedFlow.kt │ ├── MaterialCardViewCheckedChangedFlow.kt │ ├── MaterialDatePickerCancelFlow.kt │ ├── MaterialDatePickerDismissFlow.kt │ ├── MaterialDatePickerNegativeButtonClickFlow.kt │ ├── MaterialDatePickerPositiveButtonClickFlow.kt │ ├── MaterialTimePickerCancelFlow.kt │ ├── MaterialTimePickerDismissFlow.kt │ ├── MaterialTimePickerNegativeButtonClickFlow.kt │ ├── MaterialTimePickerPositiveButtonClickFlow.kt │ ├── NavigationBarViewItemReselectedFlow.kt │ ├── NavigationBarViewItemSelectedFlow.kt │ ├── NavigationViewItemSelectedFlow.kt │ ├── RangeSliderChangeEventFlow.kt │ ├── RangeSliderTouchEventFlow.kt │ ├── RangeSliderValuesChangeFlow.kt │ ├── SliderChangeEventFlow.kt │ ├── SliderTouchEventFlow.kt │ ├── SliderValueChangeFlow.kt │ ├── SnackbarDismissedFlow.kt │ ├── SnackbarShownFlow.kt │ ├── SwipeDismissBehaviorDismissedFlow.kt │ ├── SwipeDismissBehaviorDragStateChangedFlow.kt │ ├── TabLayoutTabSelectionEventFlow.kt │ ├── TextInputLayoutIconClickedFlow.kt │ └── TextInputLayoutIconLongClickedFlow.kt ├── flowbinding-navigation ├── README.md ├── api │ └── flowbinding-navigation.api ├── build.gradle.kts ├── fixtures │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── reactivecircus │ │ │ └── flowbinding │ │ │ └── navigation │ │ │ └── fixtures │ │ │ └── NavigationFragment.kt │ │ └── res │ │ ├── layout │ │ ├── fragment_a.xml │ │ ├── fragment_b.xml │ │ ├── fragment_c.xml │ │ └── fragment_navigation.xml │ │ └── navigation │ │ └── navigation.xml ├── gradle.properties └── src │ ├── androidTest │ └── java │ │ └── reactivecircus │ │ └── flowbinding │ │ └── navigation │ │ └── NavControllerDestinationChangeEventFlowTest.kt │ └── main │ ├── AndroidManifest.xml │ └── java │ └── reactivecircus │ └── flowbinding │ └── navigation │ └── NavControllerDestinationChangeEventFlow.kt ├── flowbinding-preference ├── README.md ├── api │ └── flowbinding-preference.api ├── build.gradle.kts ├── fixtures │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── reactivecircus │ │ │ └── flowbinding │ │ │ └── preference │ │ │ └── fixtures │ │ │ └── SettingsFragment.kt │ │ └── res │ │ ├── layout │ │ └── fragment_preference.xml │ │ └── xml │ │ └── preferences.xml ├── gradle.properties └── src │ ├── androidTest │ └── java │ │ └── reactivecircus │ │ └── flowbinding │ │ └── preference │ │ ├── EditTextPreferenceBindEventFlowTest.kt │ │ ├── PreferenceChangedFlowTest.kt │ │ └── PreferenceClickedFlowTest.kt │ └── main │ ├── AndroidManifest.xml │ └── java │ └── reactivecircus │ └── flowbinding │ └── preference │ ├── EditTextPreferenceBindEventFlow.kt │ ├── PreferenceChangedFlow.kt │ └── PreferenceClickedFlow.kt ├── flowbinding-recyclerview ├── README.md ├── api │ └── flowbinding-recyclerview.api ├── build.gradle.kts ├── fixtures │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── reactivecircus │ │ │ └── flowbinding │ │ │ └── recyclerview │ │ │ └── fixtures │ │ │ └── RecyclerViewFragment.kt │ │ └── res │ │ └── layout │ │ └── fragment_recycler_view.xml ├── gradle.properties └── src │ ├── androidTest │ └── java │ │ └── reactivecircus │ │ └── flowbinding │ │ └── recyclerview │ │ ├── RecyclerViewAdapterDataChangeFlowTest.kt │ │ ├── RecyclerViewChildAttachStateChangeEventFlowTest.kt │ │ ├── RecyclerViewFlingEventFlowTest.kt │ │ ├── RecyclerViewScrollEventFlowTest.kt │ │ ├── RecyclerViewScrollStateChangedFlowTest.kt │ │ └── TestAdapter.kt │ └── main │ ├── AndroidManifest.xml │ └── java │ └── reactivecircus │ └── flowbinding │ └── recyclerview │ ├── RecyclerViewAdapterDataChangeFlow.kt │ ├── RecyclerViewChildAttachStateChangeEventFlow.kt │ ├── RecyclerViewFlingEventFlow.kt │ ├── RecyclerViewScrollEventFlow.kt │ └── RecyclerViewScrollStateChangedFlow.kt ├── flowbinding-swiperefreshlayout ├── README.md ├── api │ └── flowbinding-swiperefreshlayout.api ├── build.gradle.kts ├── fixtures │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── reactivecircus │ │ │ └── flowbinding │ │ │ └── swiperefreshlayout │ │ │ └── fixtures │ │ │ └── SwipeRefreshLayoutFragment.kt │ │ └── res │ │ └── layout │ │ └── fragment_swipe_refresh_layout.xml ├── gradle.properties └── src │ ├── androidTest │ └── java │ │ └── reactivecircus │ │ └── flowbinding │ │ └── swiperefreshlayout │ │ └── SwipeRefreshLayoutRefreshFlowTest.kt │ └── main │ ├── AndroidManifest.xml │ └── java │ └── reactivecircus │ └── flowbinding │ └── swiperefreshlayout │ └── SwipeRefreshLayoutRefreshFlow.kt ├── flowbinding-viewpager ├── README.md ├── api │ └── flowbinding-viewpager.api ├── build.gradle.kts ├── fixtures │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── reactivecircus │ │ │ └── flowbinding │ │ │ └── viewpager │ │ │ └── fixtures │ │ │ └── ViewPagerFragment.kt │ │ └── res │ │ └── layout │ │ ├── fragment_page_item.xml │ │ └── fragment_viewpager.xml ├── gradle.properties └── src │ ├── androidTest │ └── java │ │ └── reactivecircus │ │ └── flowbinding │ │ └── viewpager │ │ ├── ViewPagerPageScrollStateChangedFlowTest.kt │ │ ├── ViewPagerPageScrolledFlowTest.kt │ │ └── ViewPagerPageSelectedFlowTest.kt │ └── main │ ├── AndroidManifest.xml │ └── java │ └── reactivecircus │ └── flowbinding │ └── viewpager │ ├── ViewPagerPageScrollStateChangedFlow.kt │ ├── ViewPagerPageScrolledFlow.kt │ └── ViewPagerPageSelectedFlow.kt ├── flowbinding-viewpager2 ├── README.md ├── api │ └── flowbinding-viewpager2.api ├── build.gradle.kts ├── fixtures │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── reactivecircus │ │ │ └── flowbinding │ │ │ └── viewpager2 │ │ │ └── fixtures │ │ │ └── ViewPager2Fragment.kt │ │ └── res │ │ └── layout │ │ ├── fragment_viewpager2.xml │ │ └── item_viewpager.xml ├── gradle.properties └── src │ ├── androidTest │ └── java │ │ └── reactivecircus │ │ └── flowbinding │ │ └── viewpager2 │ │ ├── ViewPager2PageScrollStateChangedFlowTest.kt │ │ ├── ViewPager2PageScrolledFlowTest.kt │ │ └── ViewPager2PageSelectedFlowTest.kt │ └── main │ ├── AndroidManifest.xml │ └── java │ └── reactivecircus │ └── flowbinding │ └── viewpager2 │ ├── ViewPager2PageScrollStateChangedFlow.kt │ ├── ViewPager2PageScrolledFlow.kt │ └── ViewPager2PageSelectedFlow.kt ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── lint-rules ├── .gitignore ├── build.gradle.kts └── src │ ├── main │ ├── java │ │ └── reactivecircus │ │ │ └── flowbinding │ │ │ └── lint │ │ │ ├── FlowBindingIssueRegistry.kt │ │ │ └── MissingListenerRemovalDetector.kt │ └── resources │ │ └── META-INF │ │ └── services │ │ └── com.android.tools.lint.client.api.IssueRegistry │ └── test │ └── java │ └── reactivecircus │ └── flowbinding │ └── lint │ └── MissingListenerRemovalDetectorTest.kt ├── mkdocs.yml ├── renovate.json ├── settings.gradle.kts └── testing-infra ├── build.gradle.kts └── src └── main ├── AndroidManifest.xml └── java └── reactivecircus └── flowbinding └── testing ├── CustomRobotActions.kt ├── FlowRecorder.kt ├── MotionEventUtil.kt └── TestLauncher.kt /.github/workflows/deploy-website.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Website 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - '**.md' 9 | - 'mkdocs.yml' 10 | - '.github/workflows/**' 11 | 12 | jobs: 13 | deploy-website: 14 | name: Generate API docs and deploy website 15 | runs-on: macos-latest 16 | steps: 17 | - uses: actions/checkout@v3 18 | - uses: gradle/wrapper-validation-action@v1 19 | - uses: actions/setup-java@v3 20 | with: 21 | distribution: 'zulu' 22 | java-version: '18' 23 | - uses: gradle/gradle-build-action@v2 24 | - uses: actions/setup-python@v4 25 | with: 26 | python-version: '3.10' 27 | - run: | 28 | pip install mkdocs-material mkdocs-minify-plugin 29 | .buildscript/deploy_website.sh 30 | env: 31 | CI: true 32 | JAVA_TOOL_OPTIONS: -Xmx4g -XX:+UseParallelGC 33 | GRADLE_OPTS: -Dkotlin.incremental.useClasspathSnapshot=false -Dorg.gradle.jvmargs="-Xmx4g -XX:+HeapDumpOnOutOfMemoryError" 34 | DEPLOY_TOKEN: ${{ secrets.GH_DEPLOY_TOKEN }} 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Files for the ART/Dalvik VM 2 | *.dex 3 | 4 | # Java class files 5 | *.class 6 | 7 | # Generated files 8 | bin/ 9 | gen/ 10 | out/ 11 | 12 | # Gradle files 13 | .gradle/ 14 | build/ 15 | reports/ 16 | 17 | # Local configuration file (sdk path, etc) 18 | local.properties 19 | 20 | # Log Files 21 | *.log 22 | 23 | # Android Studio captures folder 24 | captures/ 25 | 26 | # Intellij 27 | *.iml 28 | .idea/ 29 | 30 | # External native build folder generated in Android Studio 2.2 and later 31 | .externalNativeBuild 32 | 33 | # Docs 34 | site 35 | docs/api 36 | -------------------------------------------------------------------------------- /RELEASING.md: -------------------------------------------------------------------------------- 1 | # Releasing 2 | 3 | 1. Change the version in top-level `gradle.properties` to a non-SNAPSHOT version. 4 | 2. Update the `CHANGELOG.md` for the impending release. 5 | 3. Update the `README.md` with the new version. 6 | 4. `git commit -am "Prepare for release X.Y.Z."` (where X.Y.Z is the new version). 7 | 5. `./gradlew clean publish` 8 | 6. Visit [Sonatype Nexus](https://s01.oss.sonatype.org/) and promote the artifact. 9 | 7. `git tag -a X.Y.X -m "X.Y.Z"` (where X.Y.Z is the new version) 10 | 8. Update the top-level `gradle.properties` to the next SNAPSHOT version. 11 | 9. `git commit -am "Prepare next development version."` 12 | 10. `git push && git push --tags` 13 | 14 | If step 5 or 6 fails, drop the Sonatype repo, fix the problem, commit, and start again at step 5. 15 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `flowbinding-plugin` 3 | } 4 | -------------------------------------------------------------------------------- /buildSrc/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `kotlin-dsl` 3 | } 4 | 5 | dependencies { 6 | // TODO: remove once https://github.com/gradle/gradle/issues/15383#issuecomment-779893192 is fixed 7 | implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location)) 8 | implementation(libs.plugin.kotlin) 9 | implementation(libs.plugin.dokka) 10 | implementation(libs.plugin.agp) 11 | implementation(libs.plugin.detekt) 12 | implementation(libs.plugin.binaryCompatibilityValidator) 13 | implementation(libs.plugin.mavenPublish) 14 | } 15 | 16 | gradlePlugin { 17 | plugins { 18 | register("flowbinding") { 19 | id = "flowbinding-plugin" 20 | implementationClass = "reactivecircus.flowbinding.FlowBindingPlugin" 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /buildSrc/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | @Suppress("UnstableApiUsage") 2 | dependencyResolutionManagement { 3 | repositories { 4 | mavenCentral() 5 | google() 6 | gradlePluginPortal() 7 | } 8 | 9 | versionCatalogs { 10 | create("libs") { 11 | from(files("../gradle/libs.versions.toml")) 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/reactivecircus/flowbinding/AdditionalCompilerArgs.kt: -------------------------------------------------------------------------------- 1 | package reactivecircus.flowbinding 2 | 3 | val additionalCompilerArgs = listOf( 4 | "-progressive", 5 | "-Xjvm-default=all", 6 | "-opt-in=kotlin.Experimental" 7 | ) 8 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/reactivecircus/flowbinding/AndroidSdk.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("ClassName") 2 | 3 | package reactivecircus.flowbinding 4 | 5 | object androidSdk { 6 | const val minSdk = 14 7 | const val testMinSdk = 21 8 | const val targetSdk = 33 9 | const val compileSdk = 33 10 | const val buildTools = "33.0.0" 11 | } 12 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/reactivecircus/flowbinding/ApiCheckConfigs.kt: -------------------------------------------------------------------------------- 1 | package reactivecircus.flowbinding 2 | 3 | import org.gradle.api.Project 4 | import org.gradle.kotlin.dsl.configure 5 | import org.gradle.kotlin.dsl.withType 6 | import kotlinx.validation.ApiValidationExtension 7 | import kotlinx.validation.BinaryCompatibilityValidatorPlugin 8 | 9 | /** 10 | * Apply and configure the [BinaryCompatibilityValidatorPlugin] for the [Project]. 11 | */ 12 | internal fun Project.configureBinaryCompatibilityValidation() { 13 | pluginManager.apply(BinaryCompatibilityValidatorPlugin::class.java) 14 | plugins.withType { 15 | extensions.configure { 16 | ignoredProjects.addAll(IGNORED_PROJECTS) 17 | } 18 | } 19 | } 20 | 21 | private val IGNORED_PROJECTS = listOf( 22 | "flowbinding-activity-fixtures", 23 | "flowbinding-android-fixtures", 24 | "flowbinding-appcompat-fixtures", 25 | "flowbinding-core-fixtures", 26 | "flowbinding-drawerlayout-fixtures", 27 | "flowbinding-lifecycle-fixtures", 28 | "flowbinding-material-fixtures", 29 | "flowbinding-navigation-fixtures", 30 | "flowbinding-preference-fixtures", 31 | "flowbinding-recyclerview-fixtures", 32 | "flowbinding-swiperefreshlayout-fixtures", 33 | "flowbinding-viewpager-fixtures", 34 | "flowbinding-viewpager2-fixtures", 35 | "testing-infra", 36 | "lint-rules" 37 | ) 38 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/reactivecircus/flowbinding/DetektConfigs.kt: -------------------------------------------------------------------------------- 1 | package reactivecircus.flowbinding 2 | 3 | import io.gitlab.arturbosch.detekt.Detekt 4 | import io.gitlab.arturbosch.detekt.DetektPlugin 5 | import io.gitlab.arturbosch.detekt.extensions.DetektExtension 6 | import org.gradle.accessors.dm.LibrariesForLibs 7 | import org.gradle.api.Project 8 | import org.gradle.kotlin.dsl.configure 9 | import org.gradle.kotlin.dsl.the 10 | import org.gradle.kotlin.dsl.withType 11 | 12 | /** 13 | * Apply detekt configs to the [Project]. 14 | */ 15 | internal fun Project.configureDetektPlugin() { 16 | // apply detekt plugin 17 | pluginManager.apply(DetektPlugin::class.java) 18 | 19 | // enable Ktlint formatting 20 | val detektVersion = the().versions.detekt.get() 21 | dependencies.add("detektPlugins", "io.gitlab.arturbosch.detekt:detekt-formatting:$detektVersion") 22 | 23 | plugins.withType { 24 | extensions.configure { 25 | source = files("src/") 26 | config = files("${project.rootDir}/detekt.yml") 27 | buildUponDefaultConfig = true 28 | allRules = true 29 | } 30 | tasks.withType().configureEach { 31 | reports { 32 | html.outputLocation.set(file("build/reports/detekt/${project.name}.html")) 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/reactivecircus/flowbinding/DokkaConfigs.kt: -------------------------------------------------------------------------------- 1 | package reactivecircus.flowbinding 2 | 3 | import org.gradle.api.Project 4 | import org.gradle.kotlin.dsl.withType 5 | import org.jetbrains.dokka.gradle.DokkaMultiModuleTask 6 | import org.jetbrains.dokka.gradle.DokkaPlugin 7 | 8 | /** 9 | * Apply and configure the [DokkaPlugin] for the [Project]. 10 | */ 11 | internal fun Project.configureDokka() { 12 | pluginManager.apply(DokkaPlugin::class.java) 13 | tasks.withType().configureEach { 14 | val apiDir = rootDir.resolve("docs/api") 15 | outputDirectory.set(apiDir) 16 | doLast { 17 | apiDir.resolve("-modules.html").renameTo(apiDir.resolve("index.html")) 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/reactivecircus/flowbinding/Environment.kt: -------------------------------------------------------------------------------- 1 | package reactivecircus.flowbinding 2 | 3 | import org.gradle.api.Project 4 | 5 | val Project.isCiBuild: Boolean 6 | get() = providers.environmentVariable("CI").orNull == "true" 7 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/reactivecircus/flowbinding/FlowBindingExtension.kt: -------------------------------------------------------------------------------- 1 | package reactivecircus.flowbinding 2 | 3 | import org.gradle.api.model.ObjectFactory 4 | import org.gradle.api.provider.Property 5 | import org.gradle.kotlin.dsl.property 6 | 7 | /** 8 | * Extension for [FlowBindingPlugin]. 9 | */ 10 | @Suppress("UnstableApiUsage", "unused") 11 | open class FlowBindingExtension internal constructor(objects: ObjectFactory) { 12 | 13 | /** 14 | * Whether to enable strict explicit API mode for the project. 15 | * 16 | * Default is `false`. 17 | */ 18 | val enableExplicitApi: Property = objects.property().convention(false) 19 | } 20 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/reactivecircus/flowbinding/Publishing.kt: -------------------------------------------------------------------------------- 1 | package reactivecircus.flowbinding 2 | 3 | import com.vanniktech.maven.publish.MavenPublishBaseExtension 4 | import com.vanniktech.maven.publish.MavenPublishBasePlugin 5 | import com.vanniktech.maven.publish.MavenPublishPlugin 6 | import com.vanniktech.maven.publish.SonatypeHost 7 | import org.gradle.api.Project 8 | import org.gradle.kotlin.dsl.configure 9 | import org.gradle.kotlin.dsl.withType 10 | 11 | /** 12 | * Configure the [MavenPublishPlugin] if applied. 13 | */ 14 | internal fun Project.configureMavenPublishing() { 15 | plugins.withType { 16 | extensions.configure { 17 | publishToMavenCentral(SonatypeHost.S01, automaticRelease = true) 18 | signAllPublications() 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/reactivecircus/flowbinding/SlimTests.kt: -------------------------------------------------------------------------------- 1 | package reactivecircus.flowbinding 2 | 3 | import com.android.build.api.variant.ApplicationAndroidComponentsExtension 4 | import com.android.build.api.variant.LibraryAndroidComponentsExtension 5 | import org.gradle.api.Project 6 | import org.gradle.kotlin.dsl.findByType 7 | import org.gradle.language.nativeplatform.internal.BuildType 8 | 9 | /** 10 | * When the "slimTests" project property is provided, disable the unit test tasks 11 | * on `release` build type to avoid running the same tests repeatedly 12 | * in different build variants. 13 | * 14 | * Examples: 15 | * `./gradlew test -PslimTests` will run unit tests for `debug` build variants 16 | * in Android App and Library projects, and all tests in JVM projects. 17 | */ 18 | internal fun Project.configureSlimTests() { 19 | if (providers.gradleProperty(SLIM_TESTS_PROPERTY).isPresent) { 20 | // disable unit test tasks on the release build type for Android Library projects 21 | extensions.findByType()?.run { 22 | beforeVariants(selector().withBuildType(BuildType.RELEASE.name)) { 23 | it.enableUnitTest = false 24 | } 25 | } 26 | 27 | // disable unit test tasks on the release build type for Android Application projects. 28 | extensions.findByType()?.run { 29 | beforeVariants(selector().withBuildType(BuildType.RELEASE.name)) { 30 | it.enableUnitTest = false 31 | } 32 | } 33 | } 34 | } 35 | 36 | private const val SLIM_TESTS_PROPERTY = "slimTests" 37 | -------------------------------------------------------------------------------- /detekt.yml: -------------------------------------------------------------------------------- 1 | formatting: 2 | android: true 3 | MaximumLineLength: 4 | maxLineLength: 120 5 | excludes: ["**/test/**","**/androidTest/**"] 6 | 7 | style: 8 | MaxLineLength: 9 | maxLineLength: 120 10 | excludes: ["**/test/**","**/androidTest/**"] 11 | -------------------------------------------------------------------------------- /docs/images/reactive_circus_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ReactiveCircus/FlowBinding/25e5b9723211d37c3cb36daae8649cc1d603691a/docs/images/reactive_circus_logo.png -------------------------------------------------------------------------------- /flowbinding-activity/README.md: -------------------------------------------------------------------------------- 1 | # FlowBinding Activity 2 | 3 | This module provides bindings for the **AndroidX Activity** library. 4 | 5 | ## Transitive Dependency 6 | 7 | `androidx.activity:activity-ktx` 8 | 9 | ## Download 10 | 11 | ```groovy 12 | implementation "io.github.reactivecircus.flowbinding:flowbinding-activity:${flowbinding_version}" 13 | ``` 14 | 15 | ## Available Bindings 16 | 17 | ```kotlin 18 | fun OnBackPressedDispatcher.backPresses(enabled: Boolean): Flow 19 | ``` 20 | -------------------------------------------------------------------------------- /flowbinding-activity/api/flowbinding-activity.api: -------------------------------------------------------------------------------- 1 | public final class reactivecircus/flowbinding/activity/OnBackPressedDispatcherBackPressedFlowKt { 2 | public static final fun backPresses (Landroidx/activity/OnBackPressedDispatcher;Landroidx/lifecycle/LifecycleOwner;)Lkotlinx/coroutines/flow/Flow; 3 | } 4 | 5 | -------------------------------------------------------------------------------- /flowbinding-activity/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `flowbinding-plugin` 3 | id("com.android.library") 4 | kotlin("android") 5 | id("com.vanniktech.maven.publish") 6 | id("org.jetbrains.dokka") 7 | } 8 | 9 | flowBinding { 10 | enableExplicitApi.set(true) 11 | } 12 | 13 | android { 14 | namespace = "reactivecircus.flowbinding.activity" 15 | defaultConfig { 16 | testApplicationId = "reactivecircus.flowbinding.activity.test" 17 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 18 | } 19 | } 20 | 21 | dependencies { 22 | api(project(":flowbinding-common")) 23 | 24 | implementation(libs.androidx.activity) 25 | implementation(libs.kotlinx.coroutines.android) 26 | 27 | lintChecks(project(":lint-rules")) 28 | 29 | androidTestImplementation(project(":testing-infra")) 30 | androidTestImplementation(project(":flowbinding-activity-fixtures")) 31 | } 32 | -------------------------------------------------------------------------------- /flowbinding-activity/fixtures/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `flowbinding-plugin` 3 | id("com.android.library") 4 | kotlin("android") 5 | } 6 | 7 | android { 8 | namespace = "reactivecircus.flowbinding.activity.fixtures" 9 | buildFeatures { 10 | viewBinding = true 11 | androidResources = true 12 | } 13 | } 14 | 15 | dependencies { 16 | implementation(libs.androidx.activity) 17 | implementation(libs.androidx.fragment.ktx) 18 | } 19 | -------------------------------------------------------------------------------- /flowbinding-activity/fixtures/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /flowbinding-activity/fixtures/src/main/java/reactivecircus/flowbinding/activity/fixtures/ActivityFragment.kt: -------------------------------------------------------------------------------- 1 | package reactivecircus.flowbinding.activity.fixtures 2 | 3 | import androidx.fragment.app.Fragment 4 | 5 | class ActivityFragment : Fragment(R.layout.fragment_activity) 6 | -------------------------------------------------------------------------------- /flowbinding-activity/fixtures/src/main/res/layout/fragment_activity.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | -------------------------------------------------------------------------------- /flowbinding-activity/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=flowbinding-activity 2 | POM_NAME=FlowBinding Activity 3 | POM_DESCRIPTION=Kotlin Flow binding APIs for AndroidX Activity 4 | POM_PACKAGING=aar 5 | -------------------------------------------------------------------------------- /flowbinding-activity/src/androidTest/java/reactivecircus/flowbinding/activity/OnBackPressedDispatcherBackPressedFlowTest.kt: -------------------------------------------------------------------------------- 1 | package reactivecircus.flowbinding.activity 2 | 3 | import androidx.test.filters.LargeTest 4 | import com.google.common.truth.Truth.assertThat 5 | import org.junit.Test 6 | import reactivecircus.blueprint.testing.action.pressBack 7 | import reactivecircus.flowbinding.activity.fixtures.ActivityFragment 8 | import reactivecircus.flowbinding.testing.FlowRecorder 9 | import reactivecircus.flowbinding.testing.launchTest 10 | import reactivecircus.flowbinding.testing.recordWith 11 | 12 | @LargeTest 13 | class OnBackPressedDispatcherBackPressedFlowTest { 14 | 15 | @Test 16 | fun onBackPressedDispatcherBackPresses() { 17 | launchTest { 18 | val recorder = FlowRecorder(testScope) 19 | fragment.requireActivity().onBackPressedDispatcher.backPresses(owner = fragment).recordWith(recorder) 20 | 21 | pressBack() 22 | assertThat(recorder.takeValue()) 23 | .isEqualTo(Unit) 24 | recorder.assertNoMoreValues() 25 | 26 | cancelTestScope() 27 | 28 | pressBack() 29 | recorder.assertNoMoreValues() 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /flowbinding-activity/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /flowbinding-activity/src/main/java/reactivecircus/flowbinding/activity/OnBackPressedDispatcherBackPressedFlow.kt: -------------------------------------------------------------------------------- 1 | package reactivecircus.flowbinding.activity 2 | 3 | import androidx.activity.OnBackPressedCallback 4 | import androidx.activity.OnBackPressedDispatcher 5 | import androidx.annotation.CheckResult 6 | import androidx.lifecycle.LifecycleOwner 7 | import kotlinx.coroutines.ExperimentalCoroutinesApi 8 | import kotlinx.coroutines.channels.awaitClose 9 | import kotlinx.coroutines.flow.Flow 10 | import kotlinx.coroutines.flow.callbackFlow 11 | import kotlinx.coroutines.flow.conflate 12 | import reactivecircus.flowbinding.common.checkMainThread 13 | 14 | /** 15 | * Create a [Flow] of on back pressed events on the [OnBackPressedDispatcher] instance. 16 | * 17 | * @param owner the LifecycleOwner which controls when the callback should be invoked. 18 | * 19 | * Note: Created flow keeps a strong reference to the [OnBackPressedDispatcher] instance 20 | * until the coroutine that launched the flow collector is cancelled. 21 | * 22 | * Example of usage: 23 | * 24 | * ``` 25 | * onBackPressedDispatcher.backPresses(lifecycleOwner) 26 | * .onEach { 27 | * // handle back pressed 28 | * } 29 | * .launchIn(uiScope) 30 | * ``` 31 | */ 32 | @CheckResult 33 | @OptIn(ExperimentalCoroutinesApi::class) 34 | public fun OnBackPressedDispatcher.backPresses(owner: LifecycleOwner): Flow = 35 | callbackFlow { 36 | checkMainThread() 37 | val callback = object : OnBackPressedCallback(true) { 38 | override fun handleOnBackPressed() { 39 | trySend(Unit) 40 | } 41 | } 42 | addCallback(owner, callback) 43 | awaitClose { callback.remove() } 44 | }.conflate() 45 | -------------------------------------------------------------------------------- /flowbinding-android/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `flowbinding-plugin` 3 | id("com.android.library") 4 | kotlin("android") 5 | id("com.vanniktech.maven.publish") 6 | id("org.jetbrains.dokka") 7 | } 8 | 9 | flowBinding { 10 | enableExplicitApi.set(true) 11 | } 12 | 13 | android { 14 | namespace = "reactivecircus.flowbinding.android" 15 | defaultConfig { 16 | testApplicationId = "reactivecircus.flowbinding.android.test" 17 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 18 | } 19 | } 20 | 21 | dependencies { 22 | api(project(":flowbinding-common")) 23 | 24 | implementation(libs.kotlinx.coroutines.android) 25 | 26 | lintChecks(project(":lint-rules")) 27 | 28 | androidTestImplementation(project(":testing-infra")) 29 | androidTestImplementation(project(":flowbinding-android-fixtures")) 30 | } 31 | -------------------------------------------------------------------------------- /flowbinding-android/fixtures/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `flowbinding-plugin` 3 | id("com.android.library") 4 | kotlin("android") 5 | } 6 | 7 | android { 8 | namespace = "reactivecircus.flowbinding.android.fixtures" 9 | buildFeatures { 10 | viewBinding = true 11 | androidResources = true 12 | } 13 | } 14 | 15 | dependencies { 16 | implementation(libs.androidx.fragment.ktx) 17 | } 18 | -------------------------------------------------------------------------------- /flowbinding-android/fixtures/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /flowbinding-android/fixtures/src/main/java/reactivecircus/flowbinding/android/fixtures/view/AndroidViewFragment.kt: -------------------------------------------------------------------------------- 1 | package reactivecircus.flowbinding.android.fixtures.view 2 | 3 | import android.content.ClipData 4 | import android.os.Build 5 | import android.os.Bundle 6 | import android.view.View 7 | import androidx.fragment.app.Fragment 8 | import reactivecircus.flowbinding.android.fixtures.R 9 | import reactivecircus.flowbinding.android.fixtures.databinding.FragmentAndroidViewBinding 10 | 11 | class AndroidViewFragment : Fragment(R.layout.fragment_android_view) { 12 | 13 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 14 | super.onViewCreated(view, savedInstanceState) 15 | val binding = FragmentAndroidViewBinding.bind(view) 16 | binding.draggableView.setOnLongClickListener { 17 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 18 | binding.draggableView.startDragAndDrop( 19 | ClipData.newPlainText("", ""), 20 | View.DragShadowBuilder(binding.draggableView), 21 | true, 22 | 0 23 | ) 24 | } else { 25 | @Suppress("deprecation") 26 | binding.draggableView.startDrag( 27 | ClipData.newPlainText("", ""), 28 | View.DragShadowBuilder(binding.draggableView), 29 | true, 30 | 0 31 | ) 32 | } 33 | true 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /flowbinding-android/fixtures/src/main/java/reactivecircus/flowbinding/android/fixtures/widget/AbsListFragment.kt: -------------------------------------------------------------------------------- 1 | package reactivecircus.flowbinding.android.fixtures.widget 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import android.widget.ArrayAdapter 6 | import androidx.fragment.app.Fragment 7 | import reactivecircus.flowbinding.android.fixtures.R 8 | import reactivecircus.flowbinding.android.fixtures.databinding.FragmentAbsListBinding 9 | 10 | class AbsListFragment : Fragment(R.layout.fragment_abs_list) { 11 | 12 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 13 | super.onViewCreated(view, savedInstanceState) 14 | val binding = FragmentAbsListBinding.bind(view) 15 | 16 | @Suppress("MagicNumber") 17 | val values = IntArray(50) { it + 1 }.toTypedArray() 18 | val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_list_item_1, values) 19 | binding.absListView.adapter = adapter 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /flowbinding-android/fixtures/src/main/java/reactivecircus/flowbinding/android/fixtures/widget/AndroidWidgetFragment.kt: -------------------------------------------------------------------------------- 1 | package reactivecircus.flowbinding.android.fixtures.widget 2 | 3 | import androidx.fragment.app.Fragment 4 | import reactivecircus.flowbinding.android.fixtures.R 5 | 6 | class AndroidWidgetFragment : Fragment(R.layout.fragment_android_widget) 7 | -------------------------------------------------------------------------------- /flowbinding-android/fixtures/src/main/java/reactivecircus/flowbinding/android/fixtures/widget/AutoCompleteViewFragment.kt: -------------------------------------------------------------------------------- 1 | package reactivecircus.flowbinding.android.fixtures.widget 2 | 3 | import androidx.fragment.app.Fragment 4 | import reactivecircus.flowbinding.android.fixtures.R 5 | 6 | class AutoCompleteViewFragment : Fragment(R.layout.fragment_auto_complete_view) 7 | -------------------------------------------------------------------------------- /flowbinding-android/fixtures/src/main/java/reactivecircus/flowbinding/android/fixtures/widget/ListFragment.kt: -------------------------------------------------------------------------------- 1 | package reactivecircus.flowbinding.android.fixtures.widget 2 | 3 | import android.os.Bundle 4 | import android.view.View 5 | import android.widget.ArrayAdapter 6 | import androidx.fragment.app.Fragment 7 | import reactivecircus.flowbinding.android.fixtures.R 8 | import reactivecircus.flowbinding.android.fixtures.databinding.FragmentListBinding 9 | 10 | class ListFragment : Fragment(R.layout.fragment_list) { 11 | 12 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 13 | super.onViewCreated(view, savedInstanceState) 14 | val binding = FragmentListBinding.bind(view) 15 | 16 | val values = arrayOf("One", "Two", "Three") 17 | val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_list_item_1, values) 18 | binding.listView.adapter = adapter 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /flowbinding-android/fixtures/src/main/res/layout/fragment_abs_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | -------------------------------------------------------------------------------- /flowbinding-android/fixtures/src/main/res/layout/fragment_android_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 |