├── app ├── .gitignore ├── src │ └── main │ │ ├── res │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ ├── drawable-hdpi │ │ │ ├── ic_action_x.png │ │ │ └── ic_action_check.png │ │ ├── drawable-mdpi │ │ │ ├── ic_action_x.png │ │ │ └── ic_action_check.png │ │ ├── drawable-xhdpi │ │ │ ├── ic_action_x.png │ │ │ └── ic_action_check.png │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ ├── drawable-xxhdpi │ │ │ ├── ic_action_x.png │ │ │ └── ic_action_check.png │ │ ├── values │ │ │ ├── dimens.xml │ │ │ ├── styles.xml │ │ │ └── strings.xml │ │ ├── values-w820dp │ │ │ └── dimens.xml │ │ ├── menu │ │ │ ├── menu_main.xml │ │ │ └── menu_drawer.xml │ │ └── layout │ │ │ ├── item_header_footer.xml │ │ │ ├── item_dropdown.xml │ │ │ ├── paged_recycler_view.xml │ │ │ ├── item.xml │ │ │ ├── item_page.xml │ │ │ ├── item_immutable.xml │ │ │ ├── activity_main.xml │ │ │ ├── list_view.xml │ │ │ ├── diff_recycler_view.xml │ │ │ ├── viewpager2_view.xml │ │ │ ├── recycler_view.xml │ │ │ ├── viewpager_view.xml │ │ │ └── spinner_view.xml │ │ ├── java │ │ └── me │ │ │ └── tatarka │ │ │ └── bindingcollectionadapter │ │ │ └── sample │ │ │ ├── ImmutableItem.kt │ │ │ ├── Listeners.kt │ │ │ ├── ImmutableListeners.kt │ │ │ ├── ListExt.kt │ │ │ ├── MutableItem.kt │ │ │ ├── FragmentDiffRecyclerView.kt │ │ │ ├── FragmentPagedRecyclerView.kt │ │ │ ├── FragmentRecyclerView.kt │ │ │ ├── FragmentListView.kt │ │ │ ├── FragmentSpinnerView.kt │ │ │ ├── LoggingRecyclerViewAdapter.kt │ │ │ ├── FragmentViewPager2View.kt │ │ │ ├── FragmentViewPagerView.kt │ │ │ ├── MainActivity.kt │ │ │ ├── MutableViewModel.kt │ │ │ └── ImmutableViewModel.kt │ │ └── AndroidManifest.xml ├── proguard-rules.pro └── build.gradle ├── bindingcollectionadapter ├── .gitignore ├── src │ ├── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── me │ │ │ └── tatarka │ │ │ └── bindingcollectionadapter2 │ │ │ ├── itembindings │ │ │ ├── ItemBindingModel.java │ │ │ ├── OnItemBindModel.java │ │ │ └── OnItemBindClass.java │ │ │ ├── OnItemBind.java │ │ │ ├── AdapterReferenceCollector.java │ │ │ ├── Utils.java │ │ │ ├── BindingCollectionAdapter.java │ │ │ ├── BindingCollectionAdapters.java │ │ │ ├── ItemBinding.java │ │ │ └── BindingViewPagerAdapter.java │ ├── androidTest │ │ ├── java │ │ │ └── me │ │ │ │ └── tatarka │ │ │ │ └── bindingcollectionadapter2 │ │ │ │ ├── EmptyActivity.java │ │ │ │ ├── OnItemBindClassAndroidTest.java │ │ │ │ ├── ViewPagerInflationTest.java │ │ │ │ ├── DynamicItemViewTest.java │ │ │ │ ├── TestHelpers.java │ │ │ │ └── ListViewInflationTest.java │ │ ├── AndroidManifest.xml │ │ └── res │ │ │ └── layout │ │ │ ├── item.xml │ │ │ ├── item2.xml │ │ │ ├── list_view.xml │ │ │ ├── list_view_selector.xml │ │ │ ├── view_pager.xml │ │ │ ├── list_view_id.xml │ │ │ ├── list_view_is_enabled.xml │ │ │ ├── list_view_adapter.xml │ │ │ ├── view_pager_adapter.xml │ │ │ └── list_view_adapter_id.xml │ └── test │ │ └── java │ │ └── me │ │ └── tatarka │ │ └── bindingcollectionadapter2 │ │ ├── AdapterReferenceCollectorTest.java │ │ ├── OnItemBindModelTest.java │ │ ├── OnItemBindClassTest.java │ │ └── MergeObservableTest.java ├── proguard-rules.pro └── build.gradle ├── bindingcollectionadapter-ktx ├── .gitignore ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── me │ │ └── tatarka │ │ └── bindingcollectionadapter2 │ │ ├── ItemBinding.kt │ │ └── OnItemBindingClass.kt ├── proguard-rules.pro └── build.gradle ├── bindingcollectionadapter-paging ├── .gitignore ├── src │ ├── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── me │ │ │ └── tatarka │ │ │ └── bindingcollectionadapter2 │ │ │ ├── PagedBindingRecyclerViewAdapters.java │ │ │ └── collections │ │ │ └── AsyncDiffPagedObservableList.java │ └── test │ │ └── java │ │ └── me │ │ └── tatarka │ │ └── bindingcollectionadapter2 │ │ └── DiffObservableListTest.java └── build.gradle ├── bindingcollectionadapter-viewpager2 ├── .gitignore ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── me │ │ └── tatarka │ │ └── bindingcollectionadapter2 │ │ └── BindingViewPager2Adapters.java └── build.gradle ├── bindingcollectionadapter-recyclerview ├── .gitignore ├── src │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── res │ │ │ └── values │ │ │ │ └── ids.xml │ │ └── java │ │ │ └── me │ │ │ └── tatarka │ │ │ └── bindingcollectionadapter2 │ │ │ ├── BindingRecyclerViewAdapters.java │ │ │ └── collections │ │ │ └── AsyncDiffObservableList.java │ ├── androidTest │ │ ├── java │ │ │ └── me │ │ │ │ └── tatarka │ │ │ │ └── bindingcollectionadapter2 │ │ │ │ └── recyclerview │ │ │ │ ├── EmptyActivity.java │ │ │ │ ├── RecyclerViewInflationTest.java │ │ │ │ ├── TestHelpers.java │ │ │ │ └── DynamicItemViewTest.java │ │ ├── AndroidManifest.xml │ │ └── res │ │ │ └── layout │ │ │ ├── item.xml │ │ │ ├── item2.xml │ │ │ ├── recycler_view.xml │ │ │ ├── recycler_view_diff.xml │ │ │ └── recycler_view_adapter.xml │ └── test │ │ └── java │ │ └── me │ │ └── tatarka │ │ └── bindingcollectionadapter2 │ │ └── DiffObservableListTest.java └── build.gradle ├── .gitignore ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── settings.gradle ├── ISSUE_TEMPLATE.md ├── gradle.properties ├── .circleci └── config.yml ├── publish.gradle ├── gradlew.bat └── gradlew /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /bindingcollectionadapter/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /bindingcollectionadapter-ktx/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /bindingcollectionadapter-paging/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /bindingcollectionadapter-viewpager2/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /bindingcollectionadapter-recyclerview/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | .idea/ 4 | *.iml 5 | .DS_Store 6 | /build 7 | /captures 8 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evant/binding-collection-adapter/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evant/binding-collection-adapter/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evant/binding-collection-adapter/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evant/binding-collection-adapter/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /bindingcollectionadapter/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evant/binding-collection-adapter/HEAD/app/src/main/res/drawable-hdpi/ic_action_x.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_action_x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evant/binding-collection-adapter/HEAD/app/src/main/res/drawable-mdpi/ic_action_x.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_action_x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evant/binding-collection-adapter/HEAD/app/src/main/res/drawable-xhdpi/ic_action_x.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evant/binding-collection-adapter/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /bindingcollectionadapter-ktx/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evant/binding-collection-adapter/HEAD/app/src/main/res/drawable-hdpi/ic_action_check.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_action_check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evant/binding-collection-adapter/HEAD/app/src/main/res/drawable-mdpi/ic_action_check.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_action_x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evant/binding-collection-adapter/HEAD/app/src/main/res/drawable-xxhdpi/ic_action_x.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_action_check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evant/binding-collection-adapter/HEAD/app/src/main/res/drawable-xhdpi/ic_action_check.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_action_check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/evant/binding-collection-adapter/HEAD/app/src/main/res/drawable-xxhdpi/ic_action_check.png -------------------------------------------------------------------------------- /bindingcollectionadapter-paging/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /bindingcollectionadapter-viewpager2/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /bindingcollectionadapter-recyclerview/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /bindingcollectionadapter-recyclerview/src/main/res/values/ids.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/java/me/tatarka/bindingcollectionadapter/sample/ImmutableItem.kt: -------------------------------------------------------------------------------- 1 | package me.tatarka.bindingcollectionadapter.sample 2 | 3 | data class ImmutableItem(val index: Int, val checked: Boolean) 4 | -------------------------------------------------------------------------------- /app/src/main/java/me/tatarka/bindingcollectionadapter/sample/Listeners.kt: -------------------------------------------------------------------------------- 1 | package me.tatarka.bindingcollectionadapter.sample 2 | 3 | interface Listeners { 4 | fun onAddItem() 5 | 6 | fun onRemoveItem() 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/java/me/tatarka/bindingcollectionadapter/sample/ImmutableListeners.kt: -------------------------------------------------------------------------------- 1 | package me.tatarka.bindingcollectionadapter.sample 2 | 3 | interface ImmutableListeners : Listeners { 4 | fun onToggleChecked(index: Int): Boolean 5 | } 6 | -------------------------------------------------------------------------------- /bindingcollectionadapter/src/androidTest/java/me/tatarka/bindingcollectionadapter2/EmptyActivity.java: -------------------------------------------------------------------------------- 1 | package me.tatarka.bindingcollectionadapter2; 2 | 3 | import android.app.Activity; 4 | 5 | public class EmptyActivity extends Activity { 6 | } 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', 2 | ':bindingcollectionadapter', 3 | ':bindingcollectionadapter-ktx', 4 | ':bindingcollectionadapter-recyclerview', 5 | ':bindingcollectionadapter-paging', 6 | ':bindingcollectionadapter-viewpager2' 7 | -------------------------------------------------------------------------------- /bindingcollectionadapter-recyclerview/src/androidTest/java/me/tatarka/bindingcollectionadapter2/recyclerview/EmptyActivity.java: -------------------------------------------------------------------------------- 1 | package me.tatarka.bindingcollectionadapter2.recyclerview; 2 | 3 | import android.app.Activity; 4 | 5 | public class EmptyActivity extends Activity { 6 | } 7 | -------------------------------------------------------------------------------- /app/src/main/java/me/tatarka/bindingcollectionadapter/sample/ListExt.kt: -------------------------------------------------------------------------------- 1 | package me.tatarka.bindingcollectionadapter.sample 2 | 3 | fun List.replaceAt(index: Int, replace: (T) -> T): List = ArrayList(this).apply { 4 | val item = this[index] 5 | this[index] = replace(item) 6 | } 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /bindingcollectionadapter/src/androidTest/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | BindingCollectionAdapter 3 | MainActivity 4 | 5 | Hello world! 6 | Settings 7 | Open Drawer 8 | Close Drawer 9 | 10 | -------------------------------------------------------------------------------- /bindingcollectionadapter-recyclerview/src/androidTest/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /bindingcollectionadapter/src/androidTest/res/layout/item.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 15 | -------------------------------------------------------------------------------- /bindingcollectionadapter/src/androidTest/res/layout/item2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 15 | -------------------------------------------------------------------------------- /bindingcollectionadapter-recyclerview/src/androidTest/res/layout/item.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 15 | -------------------------------------------------------------------------------- /bindingcollectionadapter-recyclerview/src/androidTest/res/layout/item2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 15 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Is this a general databinding issue or question? You are more likely to get a 2 | response from somewhere like 3 | [StackOverflow](https://stackoverflow.com/questions/tagged/android-databinding). 4 | 5 | ## Issue 6 | Please be as detailed as possible and include a (formatted) stacktrace if 7 | relevant. A sample project that reproduce the problem goes a long way! 8 | 9 | ## Feature Request 10 | Please give an example use-case on why the feature is useful. Keep in mind the 11 | scope of this project is to bind data to RecyclerView/ListView/ViewPager etc, 12 | not to add additional features to those views. 13 | -------------------------------------------------------------------------------- /bindingcollectionadapter/src/androidTest/res/layout/list_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 16 | -------------------------------------------------------------------------------- /bindingcollectionadapter/src/androidTest/res/layout/list_view_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 16 | -------------------------------------------------------------------------------- /bindingcollectionadapter/src/main/java/me/tatarka/bindingcollectionadapter2/itembindings/ItemBindingModel.java: -------------------------------------------------------------------------------- 1 | package me.tatarka.bindingcollectionadapter2.itembindings; 2 | 3 | import androidx.annotation.NonNull; 4 | import me.tatarka.bindingcollectionadapter2.ItemBinding; 5 | 6 | /** 7 | * Implement this interface on yor items to use with {@link OnItemBindModel}. 8 | */ 9 | public interface ItemBindingModel { 10 | /** 11 | * Set the binding variable and layout of the given view. 12 | *
{@code
13 |      * onItemBind.set(BR.item, R.layout.item);
14 |      * }
15 | */ 16 | void onItemBind(@NonNull ItemBinding itemBinding); 17 | } 18 | -------------------------------------------------------------------------------- /bindingcollectionadapter/src/androidTest/res/layout/view_pager.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 16 | -------------------------------------------------------------------------------- /bindingcollectionadapter/src/main/java/me/tatarka/bindingcollectionadapter2/OnItemBind.java: -------------------------------------------------------------------------------- 1 | package me.tatarka.bindingcollectionadapter2; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | /** 6 | * Callback for setting up a {@link ItemBinding} for an item in the collection. 7 | * 8 | * @param the item type 9 | */ 10 | public interface OnItemBind { 11 | /** 12 | * Called on each item in the collection, allowing you to modify the given {@link ItemBinding}. 13 | * Note that you should not do complex processing in this method as it's called many times. 14 | */ 15 | void onItemBind(@NonNull ItemBinding itemBinding, int position, T item); 16 | } 17 | -------------------------------------------------------------------------------- /bindingcollectionadapter/src/androidTest/res/layout/list_view_id.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 17 | -------------------------------------------------------------------------------- /bindingcollectionadapter/src/androidTest/res/layout/list_view_is_enabled.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 17 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /opt/android-sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /bindingcollectionadapter/src/main/java/me/tatarka/bindingcollectionadapter2/itembindings/OnItemBindModel.java: -------------------------------------------------------------------------------- 1 | package me.tatarka.bindingcollectionadapter2.itembindings; 2 | 3 | import androidx.annotation.NonNull; 4 | import me.tatarka.bindingcollectionadapter2.ItemBinding; 5 | import me.tatarka.bindingcollectionadapter2.OnItemBind; 6 | 7 | /** 8 | * An {@link OnItemBind} that selects item views by delegating to each item. Items must implement 9 | * {@link ItemBindingModel}. 10 | */ 11 | public class OnItemBindModel implements OnItemBind { 12 | 13 | @Override 14 | public void onItemBind(@NonNull ItemBinding itemBinding, int position, T item) { 15 | item.onItemBind(itemBinding); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /bindingcollectionadapter-recyclerview/src/androidTest/res/layout/recycler_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 18 | -------------------------------------------------------------------------------- /bindingcollectionadapter/src/androidTest/res/layout/list_view_adapter.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 14 | 20 | -------------------------------------------------------------------------------- /bindingcollectionadapter-recyclerview/src/androidTest/res/layout/recycler_view_diff.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 19 | 20 | -------------------------------------------------------------------------------- /bindingcollectionadapter/src/androidTest/res/layout/view_pager_adapter.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 14 | 20 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /bindingcollectionadapter/src/androidTest/res/layout/list_view_adapter_id.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 14 | 21 | -------------------------------------------------------------------------------- /bindingcollectionadapter-recyclerview/src/androidTest/res/layout/recycler_view_adapter.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 19 | -------------------------------------------------------------------------------- /app/src/main/java/me/tatarka/bindingcollectionadapter/sample/MutableItem.kt: -------------------------------------------------------------------------------- 1 | package me.tatarka.bindingcollectionadapter.sample 2 | 3 | import androidx.annotation.MainThread 4 | import androidx.lifecycle.LiveData 5 | import androidx.lifecycle.MutableLiveData 6 | 7 | class MutableItem(val index: Int, var checkable: Boolean = false) { 8 | private val mutChecked = MutableLiveData().apply { value = false } 9 | val checked: LiveData = mutChecked 10 | 11 | fun setChecked(value: Boolean) { 12 | if (!checkable) { 13 | return 14 | } 15 | mutChecked.value = value 16 | } 17 | 18 | @MainThread 19 | fun onToggleChecked(): Boolean { 20 | if (!checkable) { 21 | return false 22 | } 23 | mutChecked.value = !(mutChecked.value)!! 24 | return true 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /bindingcollectionadapter/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /opt/android-sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # accessed with reflection 20 | -keepclassmembers androidx.databinding.ViewDataBinding { private mLifecycleOwner; } 21 | -------------------------------------------------------------------------------- /bindingcollectionadapter-ktx/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /opt/android-sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # accessed with reflection 20 | -keepclassmembers androidx.databinding.ViewDataBinding { private mLifecycleOwner; } 21 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_header_footer.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 16 | 17 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_drawer.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 11 | 12 | 15 | 16 | 19 | 20 | 23 | 24 | 27 | 28 | 31 | -------------------------------------------------------------------------------- /app/src/main/java/me/tatarka/bindingcollectionadapter/sample/FragmentDiffRecyclerView.kt: -------------------------------------------------------------------------------- 1 | package me.tatarka.bindingcollectionadapter.sample 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.fragment.app.Fragment 8 | import androidx.fragment.app.viewModels 9 | import me.tatarka.bindingcollectionadapter.sample.databinding.DiffRecyclerViewBinding 10 | 11 | class FragmentDiffRecyclerView : Fragment() { 12 | private val viewModel: ImmutableViewModel by viewModels() 13 | 14 | override fun onCreateView( 15 | inflater: LayoutInflater, 16 | container: ViewGroup?, 17 | savedInstanceState: Bundle? 18 | ): View { 19 | return DiffRecyclerViewBinding.inflate(inflater, container, false).also { 20 | it.lifecycleOwner = this 21 | it.viewModel = viewModel 22 | it.listeners = viewModel 23 | it.executePendingBindings() 24 | }.root 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/me/tatarka/bindingcollectionadapter/sample/FragmentPagedRecyclerView.kt: -------------------------------------------------------------------------------- 1 | package me.tatarka.bindingcollectionadapter.sample 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.fragment.app.Fragment 8 | import androidx.fragment.app.viewModels 9 | import me.tatarka.bindingcollectionadapter.sample.databinding.PagedRecyclerViewBinding 10 | 11 | class FragmentPagedRecyclerView : Fragment() { 12 | private val viewModel: ImmutableViewModel by viewModels() 13 | 14 | override fun onCreateView( 15 | inflater: LayoutInflater, 16 | container: ViewGroup?, 17 | savedInstanceState: Bundle? 18 | ): View { 19 | return PagedRecyclerViewBinding.inflate(inflater, container, false).also { 20 | it.lifecycleOwner = this 21 | it.viewModel = viewModel 22 | it.listeners = viewModel 23 | it.executePendingBindings() 24 | }.root 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | group=me.tatarka.bindingcollectionadapter2 21 | version=4.0.1 22 | android.useAndroidX=true 23 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_dropdown.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 19 | 20 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /bindingcollectionadapter-ktx/src/main/java/me/tatarka/bindingcollectionadapter2/ItemBinding.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("NOTHING_TO_INLINE") 2 | 3 | package me.tatarka.bindingcollectionadapter2 4 | 5 | import androidx.annotation.LayoutRes 6 | 7 | /** 8 | * Creates an `ItemBinding` with the given id and layout. 9 | * 10 | * @see ItemBinding.of 11 | */ 12 | inline fun itemBindingOf(variableId: Int, @LayoutRes layoutRes: Int): ItemBinding = 13 | ItemBinding.of(variableId, layoutRes) 14 | 15 | /** 16 | * Creates an `ItemBinding` with the given callback. 17 | * 18 | * @see ItemBinding.of 19 | */ 20 | inline fun itemBindingOf( 21 | noinline onItemBind: ( 22 | @ParameterName("itemBinding") ItemBinding, 23 | @ParameterName("position") Int, 24 | @ParameterName("item") T 25 | ) -> Unit 26 | ): ItemBinding = ItemBinding.of(onItemBind) 27 | 28 | /** 29 | * Converts an `OnItemBind` to a `ItemBinding`. 30 | * 31 | * @see ItemBinding.of 32 | */ 33 | inline fun OnItemBind.toItemBinding(): ItemBinding = 34 | ItemBinding.of(this) 35 | 36 | -------------------------------------------------------------------------------- /bindingcollectionadapter-ktx/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'kotlin-android' 3 | 4 | android { 5 | compileSdkVersion 30 6 | 7 | defaultConfig { 8 | minSdkVersion 14 9 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 10 | } 11 | buildTypes { 12 | release { 13 | minifyEnabled false 14 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 15 | } 16 | } 17 | compileOptions { 18 | sourceCompatibility JavaVersion.VERSION_1_7 19 | targetCompatibility JavaVersion.VERSION_1_7 20 | } 21 | sourceSets { 22 | androidTest { 23 | res { 24 | srcDirs = ['src/androidTest/res'] 25 | } 26 | } 27 | } 28 | buildFeatures { 29 | dataBinding = true 30 | } 31 | } 32 | 33 | dependencies { 34 | api project(':bindingcollectionadapter') 35 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" 36 | } 37 | 38 | apply from: '../publish.gradle' 39 | 40 | -------------------------------------------------------------------------------- /bindingcollectionadapter-ktx/src/main/java/me/tatarka/bindingcollectionadapter2/OnItemBindingClass.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("NOTHING_TO_INLINE") 2 | 3 | package me.tatarka.bindingcollectionadapter2 4 | 5 | import androidx.annotation.LayoutRes 6 | import me.tatarka.bindingcollectionadapter2.itembindings.OnItemBindClass 7 | 8 | /** 9 | * Maps the given type to the given id and layout. 10 | * 11 | * @see OnItemBindClass.map 12 | */ 13 | inline fun OnItemBindClass.map(variableId: Int, @LayoutRes layoutRes: Int) { 14 | map(T::class.java, variableId, layoutRes) 15 | } 16 | 17 | /** 18 | * Maps the given type to the given callback. 19 | * 20 | * @see OnItemBindClass.map 21 | */ 22 | inline fun OnItemBindClass.map( 23 | noinline onItemBind: ( 24 | @ParameterName("itemBinding") ItemBinding, 25 | @ParameterName("position") Int, 26 | @ParameterName("item") T 27 | ) -> Unit 28 | ) { 29 | map(T::class.java) { itemBinding, position, item -> 30 | onItemBind( 31 | itemBinding as ItemBinding, 32 | position, 33 | item 34 | ) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/me/tatarka/bindingcollectionadapter/sample/FragmentRecyclerView.kt: -------------------------------------------------------------------------------- 1 | package me.tatarka.bindingcollectionadapter.sample 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.fragment.app.Fragment 8 | import androidx.fragment.app.viewModels 9 | import me.tatarka.bindingcollectionadapter.sample.databinding.RecyclerViewBinding 10 | 11 | class FragmentRecyclerView : Fragment() { 12 | private val viewModel: MutableViewModel by viewModels() 13 | 14 | override fun onCreate(savedInstanceState: Bundle?) { 15 | super.onCreate(savedInstanceState) 16 | viewModel.setCheckable(true) 17 | } 18 | 19 | override fun onCreateView( 20 | inflater: LayoutInflater, 21 | container: ViewGroup?, 22 | savedInstanceState: Bundle? 23 | ): View { 24 | return RecyclerViewBinding.inflate(inflater, container, false).also { 25 | it.lifecycleOwner = this 26 | it.viewModel = viewModel 27 | it.listeners = viewModel 28 | it.executePendingBindings() 29 | }.root 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/me/tatarka/bindingcollectionadapter/sample/FragmentListView.kt: -------------------------------------------------------------------------------- 1 | package me.tatarka.bindingcollectionadapter.sample 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.fragment.app.Fragment 8 | import androidx.fragment.app.viewModels 9 | import androidx.lifecycle.ViewModelProvider 10 | import me.tatarka.bindingcollectionadapter.sample.databinding.ListViewBinding 11 | 12 | class FragmentListView : Fragment() { 13 | private val viewModel: MutableViewModel by viewModels() 14 | 15 | override fun onCreate(savedInstanceState: Bundle?) { 16 | super.onCreate(savedInstanceState) 17 | viewModel.setCheckable(true) 18 | } 19 | 20 | override fun onCreateView( 21 | inflater: LayoutInflater, 22 | container: ViewGroup?, 23 | savedInstanceState: Bundle? 24 | ): View { 25 | return ListViewBinding.inflate(inflater, container, false).also { 26 | it.lifecycleOwner = this 27 | it.viewModel = viewModel 28 | it.listeners = viewModel 29 | it.executePendingBindings() 30 | }.root 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /bindingcollectionadapter/src/test/java/me/tatarka/bindingcollectionadapter2/AdapterReferenceCollectorTest.java: -------------------------------------------------------------------------------- 1 | package me.tatarka.bindingcollectionadapter2; 2 | 3 | import androidx.databinding.ObservableList; 4 | 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | import org.junit.runners.JUnit4; 8 | 9 | import java.lang.ref.WeakReference; 10 | 11 | import static org.mockito.Mockito.mock; 12 | import static org.mockito.Mockito.verify; 13 | 14 | @RunWith(JUnit4.class) 15 | public class AdapterReferenceCollectorTest { 16 | 17 | @Test 18 | public void removesCallbackWhenAdapterIsCollected() throws Exception { 19 | BindingCollectionAdapter adapter = mock(BindingCollectionAdapter.class); 20 | ObservableList items = mock(ObservableList.class); 21 | ObservableList.OnListChangedCallback callback = mock(ObservableList.OnListChangedCallback.class); 22 | WeakReference ref = AdapterReferenceCollector.createRef(adapter, items, callback); 23 | adapter = null; 24 | System.gc(); 25 | do { 26 | Thread.sleep(50); 27 | } while (ref.get() != null); 28 | verify(items).removeOnListChangedCallback(callback); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/me/tatarka/bindingcollectionadapter/sample/FragmentSpinnerView.kt: -------------------------------------------------------------------------------- 1 | package me.tatarka.bindingcollectionadapter.sample 2 | 3 | import android.os.Bundle 4 | import androidx.fragment.app.Fragment 5 | import android.view.LayoutInflater 6 | import android.view.View 7 | import android.view.ViewGroup 8 | import androidx.fragment.app.viewModels 9 | import androidx.lifecycle.ViewModelProvider 10 | 11 | import me.tatarka.bindingcollectionadapter.sample.databinding.SpinnerViewBinding 12 | 13 | class FragmentSpinnerView : Fragment() { 14 | private val viewModel: MutableViewModel by viewModels() 15 | 16 | override fun onCreate(savedInstanceState: Bundle?) { 17 | super.onCreate(savedInstanceState) 18 | viewModel.setCheckable(false) 19 | } 20 | 21 | override fun onCreateView( 22 | inflater: LayoutInflater, 23 | container: ViewGroup?, 24 | savedInstanceState: Bundle? 25 | ): View { 26 | return SpinnerViewBinding.inflate(inflater, container, false).also { 27 | it.lifecycleOwner = this 28 | it.viewModel = viewModel 29 | it.listeners = viewModel 30 | it.executePendingBindings() 31 | }.root 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/me/tatarka/bindingcollectionadapter/sample/LoggingRecyclerViewAdapter.kt: -------------------------------------------------------------------------------- 1 | package me.tatarka.bindingcollectionadapter.sample 2 | 3 | import android.util.Log 4 | import android.view.LayoutInflater 5 | import android.view.ViewGroup 6 | import androidx.annotation.LayoutRes 7 | import androidx.databinding.ViewDataBinding 8 | import me.tatarka.bindingcollectionadapter2.BindingRecyclerViewAdapter 9 | 10 | private const val TAG = "RecyclerView" 11 | 12 | class LoggingRecyclerViewAdapter : BindingRecyclerViewAdapter() { 13 | 14 | override fun onCreateBinding( 15 | inflater: LayoutInflater, @LayoutRes layoutId: Int, 16 | viewGroup: ViewGroup 17 | ): ViewDataBinding { 18 | return super.onCreateBinding(inflater, layoutId, viewGroup).apply { 19 | Log.d(TAG, "created binding: $this") 20 | } 21 | } 22 | 23 | override fun onBindBinding( 24 | binding: ViewDataBinding, 25 | variableId: Int, @LayoutRes layoutRes: Int, 26 | position: Int, 27 | item: T 28 | ) { 29 | super.onBindBinding(binding, variableId, layoutRes, position, item) 30 | Log.d(TAG, "bound binding: $binding at position: $position") 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/res/layout/paged_recycler_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 16 | 17 | 18 | 22 | 23 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 21 | 22 | 30 | 31 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_page.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 20 | 21 | 28 | 29 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /bindingcollectionadapter-recyclerview/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 30 5 | 6 | defaultConfig { 7 | minSdkVersion 14 8 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 9 | } 10 | buildTypes { 11 | release { 12 | minifyEnabled false 13 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 14 | } 15 | } 16 | compileOptions { 17 | sourceCompatibility JavaVersion.VERSION_1_7 18 | targetCompatibility JavaVersion.VERSION_1_7 19 | } 20 | sourceSets { 21 | androidTest { 22 | res { 23 | srcDirs = ['src/androidTest/res'] 24 | } 25 | } 26 | } 27 | buildFeatures { 28 | dataBinding = true 29 | } 30 | } 31 | 32 | dependencies { 33 | api project(':bindingcollectionadapter') 34 | api 'androidx.recyclerview:recyclerview:1.0.0' 35 | 36 | testImplementation 'junit:junit:4.13.2' 37 | testImplementation 'org.assertj:assertj-core:3.6.2' 38 | testImplementation 'org.mockito:mockito-core:3.3.0' 39 | 40 | androidTestImplementation 'androidx.test:runner:1.3.0' 41 | androidTestImplementation 'androidx.test:rules:1.3.0' 42 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' 43 | androidTestImplementation 'com.squareup.assertj:assertj-android:1.1.0' 44 | } 45 | 46 | apply from: '../publish.gradle' 47 | -------------------------------------------------------------------------------- /bindingcollectionadapter/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 30 5 | 6 | defaultConfig { 7 | minSdkVersion 14 8 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 9 | } 10 | buildTypes { 11 | release { 12 | minifyEnabled false 13 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 14 | } 15 | } 16 | compileOptions { 17 | sourceCompatibility JavaVersion.VERSION_1_7 18 | targetCompatibility JavaVersion.VERSION_1_7 19 | } 20 | sourceSets { 21 | androidTest { 22 | res { 23 | srcDirs = ['src/androidTest/res'] 24 | } 25 | } 26 | } 27 | buildFeatures { 28 | dataBinding = true 29 | } 30 | } 31 | 32 | dependencies { 33 | implementation 'androidx.core:core:1.0.0' 34 | implementation 'androidx.legacy:legacy-support-core-ui:1.0.0' 35 | 36 | testImplementation 'junit:junit:4.13.2' 37 | testImplementation 'org.assertj:assertj-core:3.6.2' 38 | testImplementation 'org.mockito:mockito-core:3.3.0' 39 | 40 | androidTestImplementation 'androidx.test:runner:1.3.0' 41 | androidTestImplementation 'androidx.test:rules:1.3.0' 42 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' 43 | androidTestImplementation 'com.squareup.assertj:assertj-android:1.1.0' 44 | } 45 | 46 | apply from: '../publish.gradle' 47 | 48 | -------------------------------------------------------------------------------- /bindingcollectionadapter-paging/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'signing' 3 | 4 | android { 5 | compileSdkVersion 30 6 | 7 | defaultConfig { 8 | minSdkVersion 14 9 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 10 | } 11 | buildTypes { 12 | release { 13 | minifyEnabled false 14 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 15 | } 16 | } 17 | compileOptions { 18 | sourceCompatibility JavaVersion.VERSION_1_7 19 | targetCompatibility JavaVersion.VERSION_1_7 20 | } 21 | sourceSets { 22 | androidTest { 23 | res { 24 | srcDirs = ['src/androidTest/res'] 25 | } 26 | } 27 | } 28 | buildFeatures { 29 | dataBinding = true 30 | } 31 | } 32 | 33 | dependencies { 34 | implementation project(':bindingcollectionadapter-recyclerview') 35 | implementation 'androidx.paging:paging-runtime:2.0.0' 36 | 37 | testImplementation 'junit:junit:4.13.2' 38 | testImplementation 'org.assertj:assertj-core:3.6.2' 39 | testImplementation 'org.mockito:mockito-core:3.3.0' 40 | 41 | androidTestImplementation 'androidx.test:runner:1.3.0' 42 | androidTestImplementation 'androidx.test:rules:1.3.0' 43 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' 44 | androidTestImplementation 'com.squareup.assertj:assertj-android:1.1.0' 45 | } 46 | 47 | apply from: '../publish.gradle' 48 | -------------------------------------------------------------------------------- /bindingcollectionadapter-viewpager2/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 30 5 | 6 | defaultConfig { 7 | minSdkVersion 14 8 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 9 | } 10 | buildTypes { 11 | release { 12 | minifyEnabled false 13 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 14 | } 15 | } 16 | compileOptions { 17 | sourceCompatibility JavaVersion.VERSION_1_7 18 | targetCompatibility JavaVersion.VERSION_1_7 19 | } 20 | sourceSets { 21 | androidTest { 22 | res { 23 | srcDirs = ['src/androidTest/res'] 24 | } 25 | } 26 | } 27 | buildFeatures { 28 | dataBinding = true 29 | } 30 | } 31 | 32 | dependencies { 33 | api project(':bindingcollectionadapter') 34 | api project(':bindingcollectionadapter-recyclerview') 35 | api 'androidx.viewpager2:viewpager2:1.0.0' 36 | 37 | testImplementation 'junit:junit:4.13.2' 38 | testImplementation 'org.assertj:assertj-core:3.6.2' 39 | testImplementation 'org.mockito:mockito-core:3.3.0' 40 | 41 | androidTestImplementation 'androidx.test:runner:1.3.0' 42 | androidTestImplementation 'androidx.test:rules:1.3.0' 43 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' 44 | androidTestImplementation 'com.squareup.assertj:assertj-android:1.1.0' 45 | } 46 | 47 | apply from: '../publish.gradle' 48 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_immutable.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 24 | 25 | 33 | 34 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 9 | 13 | 14 | 18 | 19 | 23 | 24 | 25 | 29 | 30 | 31 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | working_directory: ~/code 5 | docker: 6 | - image: circleci/android:api-30 7 | environment: 8 | JVM_OPTS: -Xmx3200m 9 | steps: 10 | - checkout 11 | - restore_cache: 12 | key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }} 13 | # - run: 14 | # name: Chmod permissions #if permission for Gradlew Dependencies fail, use this. 15 | # command: sudo chmod +x ./gradlew 16 | - run: 17 | name: Download Dependencies 18 | command: ./gradlew androidDependencies 19 | - save_cache: 20 | paths: 21 | - ~/.gradle 22 | key: jars-{{ checksum "build.gradle" }}-{{ checksum "app/build.gradle" }} 23 | - run: 24 | name: Run Tests 25 | command: ./gradlew test 26 | - store_artifacts: # for display in Artifacts: https://circleci.com/docs/2.0/artifacts/ 27 | path: app/build/reports 28 | destination: reports 29 | - store_test_results: # for display in Test Summary: https://circleci.com/docs/2.0/collect-test-data/ 30 | path: app/build/test-results 31 | - deploy: 32 | command: | 33 | if [ "${CIRCLE_BRANCH}" == "main" ]; then 34 | echo "$MAVEN_CENTRAL_SEC_RING" | base64 -d > $HOME/secring.gpg 35 | gpg --import --batch $HOME/secring.gpg 36 | ./gradlew publish -Psonatype.username="$SONATYPE_USERNAME" -Psonatype.password="$SONATYPE_PASSWORD" -Psigning.keyId=34BCD878 -Psigning.password="$MAVEN_CENTRAL_KEY_PASSPHRASE" -Psigning.secretKeyRingFile=$HOME/secring.gpg -Porg.gradle.parallel=false 37 | fi 38 | workflows: 39 | version: 2 40 | build: 41 | jobs: 42 | - build: 43 | context: opensource-maven 44 | -------------------------------------------------------------------------------- /bindingcollectionadapter/src/test/java/me/tatarka/bindingcollectionadapter2/OnItemBindModelTest.java: -------------------------------------------------------------------------------- 1 | package me.tatarka.bindingcollectionadapter2; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.junit.runners.JUnit4; 6 | 7 | import java.util.Arrays; 8 | import java.util.List; 9 | 10 | import androidx.annotation.NonNull; 11 | import me.tatarka.bindingcollectionadapter2.itembindings.ItemBindingModel; 12 | import me.tatarka.bindingcollectionadapter2.itembindings.OnItemBindModel; 13 | 14 | import static org.assertj.core.api.Assertions.assertThat; 15 | 16 | @RunWith(JUnit4.class) 17 | public class OnItemBindModelTest { 18 | 19 | @Test 20 | public void selectsBasedOnItem() { 21 | OnItemBindModel onItemBind = new OnItemBindModel<>(); 22 | ItemBinding itemBinding = ItemBinding.of(onItemBind); 23 | List list = Arrays.asList(new ItemBindingModelOne(), new ItemBindingModelTwo()); 24 | itemBinding.onItemBind(0, list.get(0)); 25 | 26 | assertThat(itemBinding.variableId()).isEqualTo(0); 27 | assertThat(itemBinding.layoutRes()).isEqualTo(1); 28 | 29 | itemBinding.onItemBind(1, list.get(1)); 30 | assertThat(itemBinding.variableId()).isEqualTo(2); 31 | assertThat(itemBinding.layoutRes()).isEqualTo(3); 32 | } 33 | 34 | public static class ItemBindingModelOne implements ItemBindingModel { 35 | @Override 36 | public void onItemBind(@NonNull ItemBinding itemBinding) { 37 | itemBinding.set(0, 1); 38 | } 39 | } 40 | 41 | public static class ItemBindingModelTwo implements ItemBindingModel { 42 | @Override 43 | public void onItemBind(@NonNull ItemBinding itemBinding) { 44 | itemBinding.set(2, 3); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/me/tatarka/bindingcollectionadapter/sample/FragmentViewPager2View.kt: -------------------------------------------------------------------------------- 1 | package me.tatarka.bindingcollectionadapter.sample 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import androidx.fragment.app.Fragment 8 | import androidx.fragment.app.viewModels 9 | import androidx.lifecycle.ViewModelProvider 10 | import com.google.android.material.tabs.TabLayoutMediator 11 | import me.tatarka.bindingcollectionadapter.sample.databinding.Viewpager2ViewBinding 12 | 13 | class FragmentViewPager2View : Fragment() { 14 | private val viewModel: MutableViewModel by viewModels() 15 | 16 | override fun onCreate(savedInstanceState: Bundle?) { 17 | super.onCreate(savedInstanceState) 18 | viewModel.setCheckable(true) 19 | } 20 | 21 | override fun onCreateView( 22 | inflater: LayoutInflater, 23 | container: ViewGroup?, 24 | savedInstanceState: Bundle? 25 | ): View { 26 | return Viewpager2ViewBinding.inflate(inflater, container, false).also { 27 | it.lifecycleOwner = this 28 | it.viewModel = viewModel 29 | it.listeners = PagerListeners(viewModel) 30 | it.executePendingBindings() 31 | 32 | TabLayoutMediator(it.tabs, it.pager) { tab, position -> 33 | val item = viewModel.items[position] 34 | tab.text = viewModel.pageTitles.getPageTitle(position, item) 35 | }.attach() 36 | }.root 37 | } 38 | 39 | private class PagerListeners( 40 | private val delegate: Listeners 41 | ) : Listeners { 42 | 43 | override fun onAddItem() { 44 | delegate.onAddItem() 45 | } 46 | 47 | override fun onRemoveItem() { 48 | delegate.onRemoveItem() 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/res/layout/list_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 14 | 15 | 16 | 20 | 21 | 30 | 31 | 35 | 36 |