├── .circleci └── config.yml ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ └── question.md └── workflows │ └── run-tests.yml ├── .gitignore ├── LICENSE.md ├── README.md ├── build.gradle ├── example-databinding ├── .gitignore ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── xwray │ │ └── groupie │ │ └── example │ │ └── databinding │ │ ├── CarouselGroup.java │ │ ├── ColumnGroup.java │ │ ├── ExpandableHeaderItem.java │ │ ├── HeaderItemDecoration.java │ │ ├── InsetItemDecoration.java │ │ ├── MainActivity.java │ │ └── item │ │ ├── CardItem.java │ │ ├── CarouselCardItem.java │ │ ├── CarouselItem.java │ │ ├── ColumnItem.java │ │ ├── DraggableItem.java │ │ ├── FullBleedCardItem.java │ │ ├── HeaderItem.java │ │ ├── HeartCardItem.java │ │ ├── SmallCardItem.java │ │ ├── SwipeToDeleteItem.java │ │ └── UpdatableItem.java │ └── res │ └── layout │ ├── activity_main.xml │ ├── item_card.xml │ ├── item_carousel.xml │ ├── item_expandable_header.xml │ ├── item_header.xml │ ├── item_heart_card.xml │ └── item_square_card.xml ├── example-shared ├── .gitignore ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── xwray │ │ └── groupie │ │ └── example │ │ └── core │ │ ├── InfiniteScrollListener.java │ │ ├── Prefs.java │ │ ├── SettingsActivity.java │ │ ├── decoration │ │ ├── CarouselItemDecoration.java │ │ ├── DebugItemDecoration.java │ │ ├── HeaderItemDecoration.java │ │ ├── InsetItemDecoration.java │ │ └── SwipeTouchCallback.java │ │ └── widget │ │ └── CheckableImageView.java │ └── res │ ├── animator │ ├── opacity_pulse.xml │ ├── rotation_collapse_to_expand.xml │ └── rotation_expand_to_collapse.xml │ ├── drawable-v21 │ └── ripple_circular.xml │ ├── drawable │ ├── avd_favorite_progress.xml │ ├── clear.xml │ ├── collapse.xml │ ├── collapse_animated.xml │ ├── expand.xml │ ├── expand_animated.xml │ ├── favorite.xml │ ├── favorite_border.xml │ ├── favorite_pressed.xml │ ├── favorite_state_list.xml │ ├── ic_keyboard_arrow_right_black_24dp.xml │ ├── palette.xml │ ├── ripple_circular.xml │ ├── shuffle.xml │ └── wrench.xml │ ├── layout │ ├── activity_settings.xml │ └── switch_pref.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-v21 │ └── styles.xml │ ├── values-w480dp │ └── bools.xml │ ├── values-w640dp │ └── dimens.xml │ ├── values-w720dp │ └── bools.xml │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── bools.xml │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── example-viewbinding ├── .gitignore ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── xwray │ │ └── groupie │ │ └── example │ │ └── viewbinding │ │ ├── CarouselGroup.kt │ │ ├── ColumnGroup.kt │ │ ├── ExpandableHeaderItem.kt │ │ ├── HeaderItemDecoration.kt │ │ ├── InsetItemDecoration.kt │ │ ├── MainActivity.kt │ │ └── item │ │ ├── CardItem.kt │ │ ├── CarouselCardItem.kt │ │ ├── CarouselItem.kt │ │ ├── ColumnItem.kt │ │ ├── FullBleedCardItem.kt │ │ ├── HeaderItem.kt │ │ ├── HeartCardItem.kt │ │ ├── SmallCardItem.kt │ │ ├── SwipeToDeleteItem.kt │ │ └── UpdatableItem.kt │ └── res │ └── layout │ ├── activity_main.xml │ ├── item_card.xml │ ├── item_carousel.xml │ ├── item_expandable_header.xml │ ├── item_header.xml │ ├── item_heart_card.xml │ └── item_square_card.xml ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── jcenter ├── bintray.gradle └── maven-install.gradle ├── library-databinding ├── .gitignore ├── build.gradle ├── gradle.properties └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── xwray │ └── groupie │ └── databinding │ ├── BindableItem.java │ └── GroupieViewHolder.java ├── library-viewbinding ├── .gitignore ├── build.gradle ├── gradle.properties └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── xwray │ └── groupie │ └── viewbinding │ ├── BindableItem.java │ └── GroupieViewHolder.java ├── library ├── .gitignore ├── build.gradle ├── gradle.properties └── src │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── xwray │ │ └── groupie │ │ ├── AsyncDiffUtil.java │ │ ├── DiffCallback.java │ │ ├── DiffTask.java │ │ ├── ExpandableGroup.java │ │ ├── ExpandableItem.java │ │ ├── Group.java │ │ ├── GroupAdapter.java │ │ ├── GroupDataObserver.java │ │ ├── GroupUtils.java │ │ ├── GroupieAdapter.java │ │ ├── GroupieViewHolder.java │ │ ├── Item.java │ │ ├── NestedGroup.java │ │ ├── OnAsyncUpdateListener.java │ │ ├── OnItemClickListener.java │ │ ├── OnItemLongClickListener.java │ │ ├── Section.java │ │ ├── SpanSizeProvider.java │ │ ├── TouchCallback.java │ │ └── UpdatingGroup.java │ └── test │ └── java │ └── com │ └── xwray │ └── groupie │ ├── AlwaysUpdatingItem.java │ ├── ContentUpdatingItem.java │ ├── DummyGroup.java │ ├── DummyItem.java │ ├── ExpandableGroupTest.java │ ├── GroupAdapterTest.java │ ├── GroupUtilsTest.java │ ├── ItemTest.java │ ├── SectionTest.java │ ├── UpdatingGroupTest.java │ └── ViewTypeTest.java ├── release-bintray.gradle └── settings.gradle.kts /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | working_directory: ~/code 5 | docker: 6 | - image: circleci/android:api-29 7 | environment: 8 | JVM_OPTS: -Xmx3200m 9 | steps: 10 | - checkout 11 | - restore_cache: 12 | key: jars-{{ checksum "build.gradle" }} 13 | - run: 14 | name: Run Lint 15 | command: ./gradlew lint --console plain 16 | - run: 17 | name: Run Unit Tests 18 | command: ./gradlew test --console plain 19 | - store_artifacts: 20 | path: build/lint-reports 21 | destination: reports 22 | - store_test_results: 23 | path: library/build/test-results 24 | - save_cache: 25 | paths: 26 | - ~/.gradle 27 | key: jars-{{ checksum "build.gradle" }} 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug, waiting for response 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 16 | **Expected behavior** 17 | A clear and concise description of what you expected to happen. 18 | 19 | **Library version** 20 | [e.g. 2.4.0] 21 | 22 | **Additional context** 23 | Add any other context about the problem here. 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement, waiting for response 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe** 11 | A clear and concise description of what the problem is. 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Additional context** 17 | Add any other context about the problem here. 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: General question 3 | about: Ask a question about Groupie 4 | title: '' 5 | labels: question, waiting for response 6 | assignees: '' 7 | 8 | --- 9 | -------------------------------------------------------------------------------- /.github/workflows/run-tests.yml: -------------------------------------------------------------------------------- 1 | name: Run Tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Set up JDK 13 | uses: actions/setup-java@v3 14 | with: 15 | java-version: '17' 16 | distribution: 'temurin' 17 | 18 | - name: Checkout Submodules 19 | uses: actions/checkout@v3 20 | 21 | - name: Validate Gradle Wrapper 22 | uses: gradle/wrapper-validation-action@v1 23 | 24 | - name: Run Lint 25 | run: ./gradlew lint --console plain 26 | 27 | - name: Run Unit Tests 28 | run: ./gradlew test --console plain 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | *.jks 3 | .DS_Store 4 | .externalNativeBuild 5 | .gradle 6 | .idea/* 7 | /.idea/libraries 8 | /.idea/workspace.xml 9 | /build 10 | /captures 11 | /local.properties 12 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | def lintReportsDir = file("${rootProject.buildDir}/lint-reports") 4 | def testReportsDir = "${rootProject.buildDir}/test-reports" 5 | def testResultsDir = "${rootProject.buildDir}/test-results" 6 | 7 | buildscript { 8 | ext.kotlin_version = '1.6.21' 9 | ext.android_plugin_version = '7.0.4' 10 | ext.sdkVersion = 31 11 | ext.minimumSdkVersion = 14 12 | ext.databinding_version = '7.1.3' 13 | ext.viewbinding_version = '7.1.3' 14 | 15 | ext.junit_version = '4.13.2' 16 | ext.mockito_version = '3.3.3' 17 | 18 | repositories { 19 | google() 20 | mavenCentral() 21 | maven { url "https://jitpack.io" } 22 | } 23 | dependencies { 24 | classpath "com.android.tools.build:gradle:$android_plugin_version" 25 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 26 | classpath "org.jetbrains.dokka:dokka-android-gradle-plugin:0.9.18" 27 | // NOTE: Do not place your application dependencies here; they belong 28 | // in the individual module build.gradle files 29 | } 30 | } 31 | 32 | allprojects { project -> 33 | repositories { 34 | google() 35 | mavenCentral() 36 | jcenter() 37 | maven { url "https://jitpack.io" } 38 | } 39 | 40 | afterEvaluate { 41 | if (project.hasProperty('android')) { 42 | android { 43 | // use a custom location for the Lint reports so that it's easy to archive them in Circle CI 44 | lintOptions { 45 | htmlOutput file("$lintReportsDir/${project.name}/lint-report.html") 46 | } 47 | // it would be nice to do the same with test results/reports 48 | // but it doesn't work: https://issuetracker.google.com/issues/37132023 49 | testOptions { 50 | reportDir "$testReportsDir/${project.name}" 51 | resultsDir "$testResultsDir/${project.name}" 52 | } 53 | } 54 | } 55 | } 56 | } 57 | 58 | task clean(type: Delete) { 59 | delete rootProject.buildDir 60 | } 61 | -------------------------------------------------------------------------------- /example-databinding/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /example-databinding/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion rootProject.sdkVersion 5 | 6 | defaultConfig { 7 | applicationId "com.xwray.groupie.example.databinding" 8 | minSdkVersion rootProject.minimumSdkVersion 9 | targetSdkVersion rootProject.sdkVersion 10 | versionCode 1 11 | versionName "1.0" 12 | vectorDrawables.useSupportLibrary true 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | } 18 | } 19 | 20 | buildFeatures { 21 | dataBinding true 22 | viewBinding false 23 | } 24 | 25 | lintOptions { 26 | abortOnError false 27 | } 28 | } 29 | 30 | dependencies { 31 | implementation project(':library-databinding') 32 | implementation project(':example-shared') 33 | implementation "androidx.appcompat:appcompat:1.4.1" 34 | implementation "com.google.android.material:material:1.4.0" 35 | implementation "androidx.cardview:cardview:1.0.0" 36 | implementation "androidx.vectordrawable:vectordrawable:1.1.0" 37 | implementation "androidx.vectordrawable:vectordrawable-animated:1.1.0" 38 | } 39 | -------------------------------------------------------------------------------- /example-databinding/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /example-databinding/src/main/java/com/xwray/groupie/example/databinding/CarouselGroup.java: -------------------------------------------------------------------------------- 1 | package com.xwray.groupie.example.databinding; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.recyclerview.widget.RecyclerView; 5 | 6 | import com.xwray.groupie.Group; 7 | import com.xwray.groupie.GroupDataObserver; 8 | import com.xwray.groupie.GroupieAdapter; 9 | import com.xwray.groupie.GroupieViewHolder; 10 | import com.xwray.groupie.Item; 11 | import com.xwray.groupie.example.databinding.item.CarouselItem; 12 | 13 | /** 14 | * A group that contains a single carousel item and is empty when the carousel is empty 15 | **/ 16 | public class CarouselGroup implements Group { 17 | 18 | private boolean isEmpty = true; 19 | private final RecyclerView.Adapter adapter; 20 | private GroupDataObserver groupDataObserver; 21 | private final CarouselItem carouselItem; 22 | 23 | private RecyclerView.AdapterDataObserver adapterDataObserver = new RecyclerView.AdapterDataObserver() { 24 | 25 | @Override 26 | public void onItemRangeRemoved(int positionStart, int itemCount) { 27 | boolean empty = adapter.getItemCount() == 0; 28 | if (empty && !isEmpty) { 29 | isEmpty = empty; 30 | groupDataObserver.onItemRemoved(carouselItem, 0); 31 | } 32 | } 33 | 34 | @Override 35 | public void onItemRangeInserted(int positionStart, int itemCount) { 36 | boolean empty = adapter.getItemCount() == 0; 37 | if (isEmpty && !empty) { 38 | isEmpty = empty; 39 | groupDataObserver.onItemInserted(carouselItem, 0); 40 | } 41 | } 42 | }; 43 | 44 | public CarouselGroup(RecyclerView.ItemDecoration itemDecoration, GroupieAdapter adapter) { 45 | this.adapter = adapter; 46 | carouselItem = new CarouselItem(itemDecoration, adapter); 47 | isEmpty = adapter.getItemCount() == 0; 48 | adapter.registerAdapterDataObserver(adapterDataObserver); 49 | } 50 | 51 | @Override 52 | public int getItemCount() { 53 | return isEmpty ? 0 : 1; 54 | } 55 | 56 | @NonNull 57 | @Override 58 | public Item getItem(int position) { 59 | if (position == 0 && !isEmpty) return carouselItem; 60 | else throw new IndexOutOfBoundsException(); 61 | } 62 | 63 | @Override 64 | public int getPosition(@NonNull Item item) { 65 | return item == carouselItem && !isEmpty ? 0 : -1; 66 | } 67 | 68 | @Override 69 | public void registerGroupDataObserver(@NonNull GroupDataObserver groupDataObserver) { 70 | this.groupDataObserver = groupDataObserver; 71 | } 72 | 73 | @Override 74 | public void unregisterGroupDataObserver(@NonNull GroupDataObserver groupDataObserver) { 75 | this.groupDataObserver = null; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /example-databinding/src/main/java/com/xwray/groupie/example/databinding/ColumnGroup.java: -------------------------------------------------------------------------------- 1 | package com.xwray.groupie.example.databinding; 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import com.xwray.groupie.Group; 6 | import com.xwray.groupie.GroupDataObserver; 7 | import com.xwray.groupie.Item; 8 | import com.xwray.groupie.databinding.BindableItem; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | /** 14 | * A simple, non-editable, non-nested group of Items which displays a list as vertical columns. 15 | */ 16 | public class ColumnGroup implements Group { 17 | 18 | private List> items = new ArrayList<>(); 19 | 20 | public ColumnGroup(List> items) { 21 | for (int i = 0; i < items.size(); i++) { 22 | // Rearrange items so that the adapter appears to arrange them in vertical columns 23 | int index; 24 | if (i % 2 == 0) { 25 | index = i / 2; 26 | } else { 27 | index = (i - 1) / 2 + (int) (items.size() / 2f); 28 | // If columns are uneven, we'll put an extra one at the end of the first column, 29 | // meaning the second column's indices will all be increased by 1 30 | if (items.size() % 2 == 1) index++; 31 | } 32 | BindableItem trackItem = items.get(index); 33 | this.items.add(trackItem); 34 | } 35 | } 36 | 37 | @Override 38 | public void registerGroupDataObserver(@NonNull GroupDataObserver groupDataObserver) { 39 | // no real need to do anything here 40 | } 41 | 42 | @Override 43 | public void unregisterGroupDataObserver(@NonNull GroupDataObserver groupDataObserver) { 44 | // no real need to do anything here 45 | } 46 | 47 | @NonNull 48 | @Override 49 | public BindableItem getItem(int position) { 50 | return items.get(position); 51 | } 52 | 53 | @Override 54 | public int getPosition(@NonNull Item item) { 55 | return items.indexOf(item); 56 | } 57 | 58 | @Override public int getItemCount() { 59 | return items.size(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /example-databinding/src/main/java/com/xwray/groupie/example/databinding/ExpandableHeaderItem.java: -------------------------------------------------------------------------------- 1 | package com.xwray.groupie.example.databinding; 2 | 3 | import android.graphics.drawable.Animatable; 4 | import androidx.annotation.NonNull; 5 | import androidx.annotation.StringRes; 6 | import android.view.View; 7 | 8 | import com.xwray.groupie.ExpandableGroup; 9 | import com.xwray.groupie.ExpandableItem; 10 | import com.xwray.groupie.example.databinding.databinding.ItemHeaderBinding; 11 | import com.xwray.groupie.example.databinding.item.HeaderItem; 12 | 13 | public class ExpandableHeaderItem extends HeaderItem implements ExpandableItem { 14 | 15 | private ExpandableGroup expandableGroup; 16 | 17 | public ExpandableHeaderItem(@StringRes int titleStringResId, @StringRes int subtitleResId) { 18 | super(titleStringResId, subtitleResId); 19 | } 20 | 21 | @Override public void bind(@NonNull final ItemHeaderBinding viewBinding, int position) { 22 | super.bind(viewBinding, position); 23 | 24 | // Initial icon state -- not animated. 25 | viewBinding.icon.setVisibility(View.VISIBLE); 26 | viewBinding.icon.setImageResource(expandableGroup.isExpanded() ? R.drawable.collapse : R.drawable.expand); 27 | viewBinding.icon.setOnClickListener(new View.OnClickListener() { 28 | @Override public void onClick(View view) { 29 | expandableGroup.onToggleExpanded(); 30 | bindIcon(viewBinding); 31 | } 32 | }); 33 | } 34 | 35 | private void bindIcon(ItemHeaderBinding viewBinding) { 36 | viewBinding.icon.setVisibility(View.VISIBLE); 37 | viewBinding.icon.setImageResource(expandableGroup.isExpanded() ? R.drawable.collapse_animated : R.drawable.expand_animated); 38 | Animatable drawable = (Animatable) viewBinding.icon.getDrawable(); 39 | drawable.start(); 40 | } 41 | 42 | @Override public void setExpandableGroup(@NonNull ExpandableGroup onToggleListener) { 43 | this.expandableGroup = onToggleListener; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /example-databinding/src/main/java/com/xwray/groupie/example/databinding/HeaderItemDecoration.java: -------------------------------------------------------------------------------- 1 | package com.xwray.groupie.example.databinding; 2 | 3 | import androidx.annotation.ColorInt; 4 | import androidx.annotation.LayoutRes; 5 | 6 | public class HeaderItemDecoration extends com.xwray.groupie.example.core.decoration.HeaderItemDecoration { 7 | public HeaderItemDecoration(@ColorInt int background, int sidePaddingPixels) { 8 | super(background, sidePaddingPixels, R.layout.item_header); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /example-databinding/src/main/java/com/xwray/groupie/example/databinding/InsetItemDecoration.java: -------------------------------------------------------------------------------- 1 | package com.xwray.groupie.example.databinding; 2 | 3 | import androidx.annotation.ColorInt; 4 | import androidx.annotation.Dimension; 5 | 6 | public class InsetItemDecoration extends com.xwray.groupie.example.core.decoration.InsetItemDecoration { 7 | public InsetItemDecoration(@ColorInt int backgroundColor, @Dimension int padding) { 8 | super(backgroundColor, padding, MainActivity.INSET_TYPE_KEY, MainActivity.INSET); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /example-databinding/src/main/java/com/xwray/groupie/example/databinding/item/CardItem.java: -------------------------------------------------------------------------------- 1 | package com.xwray.groupie.example.databinding.item; 2 | 3 | import androidx.annotation.ColorInt; 4 | import androidx.annotation.NonNull; 5 | 6 | import com.xwray.groupie.databinding.BindableItem; 7 | import com.xwray.groupie.example.databinding.R; 8 | import com.xwray.groupie.example.databinding.databinding.ItemCardBinding; 9 | 10 | import static com.xwray.groupie.example.databinding.MainActivity.INSET; 11 | import static com.xwray.groupie.example.databinding.MainActivity.INSET_TYPE_KEY; 12 | 13 | public class CardItem extends BindableItem { 14 | 15 | private CharSequence text; 16 | 17 | public CardItem() { 18 | this(""); 19 | } 20 | 21 | public CardItem(CharSequence text) { 22 | this.text = text; 23 | getExtras().put(INSET_TYPE_KEY, INSET); 24 | } 25 | 26 | @Override public int getLayout() { 27 | return R.layout.item_card; 28 | } 29 | 30 | @Override public void bind(@NonNull ItemCardBinding viewBinding, int position) { 31 | viewBinding.text.setText(text); 32 | } 33 | 34 | public final CharSequence getText() { 35 | return text; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /example-databinding/src/main/java/com/xwray/groupie/example/databinding/item/CarouselCardItem.java: -------------------------------------------------------------------------------- 1 | package com.xwray.groupie.example.databinding.item; 2 | 3 | import androidx.annotation.ColorInt; 4 | import androidx.annotation.NonNull; 5 | 6 | import com.xwray.groupie.databinding.BindableItem; 7 | import com.xwray.groupie.example.databinding.R; 8 | import com.xwray.groupie.example.databinding.databinding.ItemSquareCardBinding; 9 | 10 | /** 11 | * A card item with a fixed width so it can be used with a horizontal layout manager. 12 | */ 13 | public class CarouselCardItem extends BindableItem { 14 | 15 | @ColorInt private int colorInt; 16 | 17 | public CarouselCardItem(@ColorInt int colorInt) { 18 | this.colorInt = colorInt; 19 | } 20 | 21 | @Override public int getLayout() { 22 | return R.layout.item_square_card; 23 | } 24 | 25 | @Override public void bind(@NonNull ItemSquareCardBinding viewBinding, int position) { 26 | viewBinding.getRoot().setBackgroundColor(colorInt); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /example-databinding/src/main/java/com/xwray/groupie/example/databinding/item/CarouselItem.java: -------------------------------------------------------------------------------- 1 | package com.xwray.groupie.example.databinding.item; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.recyclerview.widget.LinearLayoutManager; 5 | import androidx.recyclerview.widget.RecyclerView; 6 | import android.view.View; 7 | 8 | import com.xwray.groupie.GroupieAdapter; 9 | import com.xwray.groupie.Item; 10 | import com.xwray.groupie.OnItemClickListener; 11 | import com.xwray.groupie.databinding.BindableItem; 12 | import com.xwray.groupie.databinding.GroupieViewHolder; 13 | import com.xwray.groupie.example.databinding.R; 14 | import com.xwray.groupie.example.databinding.databinding.ItemCarouselBinding; 15 | 16 | /** 17 | * A horizontally scrolling RecyclerView, for use in a vertically scrolling RecyclerView. 18 | */ 19 | public class CarouselItem extends BindableItem implements OnItemClickListener { 20 | 21 | private final GroupieAdapter adapter; 22 | private final RecyclerView.ItemDecoration carouselDecoration; 23 | 24 | public CarouselItem(RecyclerView.ItemDecoration itemDecoration, GroupieAdapter adapter) { 25 | this.carouselDecoration = itemDecoration; 26 | this.adapter = adapter; 27 | adapter.setOnItemClickListener(this); 28 | } 29 | 30 | @NonNull 31 | @Override 32 | public GroupieViewHolder createViewHolder(@NonNull View itemView) { 33 | GroupieViewHolder viewHolder = super.createViewHolder(itemView); 34 | RecyclerView recyclerView = viewHolder.binding.recyclerView; 35 | recyclerView.addItemDecoration(carouselDecoration); 36 | recyclerView.setLayoutManager(new LinearLayoutManager(recyclerView.getContext(), LinearLayoutManager.HORIZONTAL, false)); 37 | return viewHolder; 38 | } 39 | 40 | @Override public void bind(@NonNull ItemCarouselBinding viewBinding, int position) { 41 | viewBinding.recyclerView.setAdapter(adapter); 42 | } 43 | 44 | @Override public int getLayout() { 45 | return R.layout.item_carousel; 46 | } 47 | 48 | @Override 49 | public void onItemClick(@NonNull Item item, @NonNull View view) { 50 | adapter.remove(item); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /example-databinding/src/main/java/com/xwray/groupie/example/databinding/item/ColumnItem.java: -------------------------------------------------------------------------------- 1 | package com.xwray.groupie.example.databinding.item; 2 | 3 | import com.xwray.groupie.example.databinding.MainActivity; 4 | 5 | public class ColumnItem extends CardItem { 6 | 7 | public ColumnItem(int index) { 8 | super(String.valueOf(index)); 9 | getExtras().put(MainActivity.INSET_TYPE_KEY, MainActivity.INSET); 10 | } 11 | 12 | @Override public int getSpanSize(int spanCount, int position) { 13 | return spanCount / 2; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /example-databinding/src/main/java/com/xwray/groupie/example/databinding/item/DraggableItem.java: -------------------------------------------------------------------------------- 1 | package com.xwray.groupie.example.databinding.item; 2 | 3 | import androidx.annotation.ColorInt; 4 | import androidx.recyclerview.widget.ItemTouchHelper; 5 | 6 | public class DraggableItem extends CardItem { 7 | public DraggableItem(@ColorInt int colorRes) { 8 | super(); 9 | } 10 | 11 | @Override public int getDragDirs() { 12 | return ItemTouchHelper.DOWN | ItemTouchHelper.UP; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /example-databinding/src/main/java/com/xwray/groupie/example/databinding/item/FullBleedCardItem.java: -------------------------------------------------------------------------------- 1 | package com.xwray.groupie.example.databinding.item; 2 | 3 | import com.xwray.groupie.example.databinding.MainActivity; 4 | 5 | public class FullBleedCardItem extends CardItem { 6 | 7 | public FullBleedCardItem() { 8 | super(); 9 | getExtras().remove(MainActivity.INSET_TYPE_KEY); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /example-databinding/src/main/java/com/xwray/groupie/example/databinding/item/HeaderItem.java: -------------------------------------------------------------------------------- 1 | package com.xwray.groupie.example.databinding.item; 2 | 3 | import androidx.annotation.DrawableRes; 4 | import androidx.annotation.NonNull; 5 | import androidx.annotation.StringRes; 6 | import android.view.View; 7 | 8 | import com.xwray.groupie.databinding.BindableItem; 9 | import com.xwray.groupie.example.databinding.R; 10 | import com.xwray.groupie.example.databinding.databinding.ItemHeaderBinding; 11 | 12 | public class HeaderItem extends BindableItem { 13 | 14 | @StringRes private final int titleStringResId; 15 | @StringRes private final int subtitleResId; 16 | @DrawableRes private final int iconResId; 17 | private final View.OnClickListener onIconClickListener; 18 | 19 | public HeaderItem(@StringRes int titleStringResId) { 20 | this(titleStringResId, 0); 21 | } 22 | 23 | public HeaderItem(@StringRes int titleStringResId, @StringRes int subtitleResId) { 24 | this(titleStringResId, subtitleResId, 0, null); 25 | } 26 | 27 | public HeaderItem(@StringRes int titleStringResId, @StringRes int subtitleResId, @DrawableRes int iconResId, View.OnClickListener onIconClickListener) { 28 | this.titleStringResId = titleStringResId; 29 | this.subtitleResId = subtitleResId; 30 | this.iconResId = iconResId; 31 | this.onIconClickListener = onIconClickListener; 32 | } 33 | 34 | @Override public int getLayout() { 35 | return R.layout.item_header; 36 | } 37 | 38 | @Override public void bind(@NonNull ItemHeaderBinding viewBinding, int position) { 39 | viewBinding.title.setText(titleStringResId); 40 | if (subtitleResId != 0) { 41 | viewBinding.subtitle.setText(subtitleResId); 42 | } 43 | viewBinding.subtitle.setVisibility(subtitleResId != 0 ? View.VISIBLE : View.GONE); 44 | 45 | if (iconResId != 0) { 46 | viewBinding.icon.setImageResource(iconResId); 47 | viewBinding.icon.setOnClickListener(onIconClickListener); 48 | } 49 | viewBinding.icon.setVisibility(iconResId != 0 ? View.VISIBLE : View.GONE); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /example-databinding/src/main/java/com/xwray/groupie/example/databinding/item/HeartCardItem.java: -------------------------------------------------------------------------------- 1 | package com.xwray.groupie.example.databinding.item; 2 | 3 | import android.graphics.drawable.Animatable; 4 | import androidx.annotation.ColorInt; 5 | import androidx.annotation.NonNull; 6 | import android.view.View; 7 | 8 | import com.xwray.groupie.databinding.BindableItem; 9 | import com.xwray.groupie.example.databinding.MainActivity; 10 | import com.xwray.groupie.example.databinding.R; 11 | import com.xwray.groupie.example.databinding.databinding.ItemHeartCardBinding; 12 | 13 | import java.util.List; 14 | 15 | public class HeartCardItem extends BindableItem { 16 | 17 | public static final String FAVORITE = "FAVORITE"; 18 | 19 | private final OnFavoriteListener onFavoriteListener; 20 | private boolean checked = false; 21 | private boolean inProgress = false; 22 | 23 | public HeartCardItem(long id, OnFavoriteListener onFavoriteListener) { 24 | super(id); 25 | this.onFavoriteListener = onFavoriteListener; 26 | getExtras().put(MainActivity.INSET_TYPE_KEY, MainActivity.INSET); 27 | } 28 | 29 | @Override 30 | public int getLayout() { 31 | return R.layout.item_heart_card; 32 | } 33 | 34 | @Override 35 | public void bind(@NonNull final ItemHeartCardBinding binding, int position) { 36 | //binding.getRoot().setBackgroundColor(colorRes); 37 | bindHeart(binding); 38 | binding.text.setText(String.valueOf(getId() + 1)); 39 | 40 | binding.favorite.setOnClickListener(new View.OnClickListener() { 41 | @Override 42 | public void onClick(View v) { 43 | inProgress = true; 44 | animateProgress(binding); 45 | 46 | onFavoriteListener.onFavorite(HeartCardItem.this, !checked); 47 | } 48 | }); 49 | } 50 | 51 | private void bindHeart(ItemHeartCardBinding binding) { 52 | if (inProgress) { 53 | animateProgress(binding); 54 | } else { 55 | binding.favorite.setImageResource(R.drawable.favorite_state_list); 56 | } 57 | binding.favorite.setChecked(checked); 58 | } 59 | 60 | private void animateProgress(ItemHeartCardBinding binding) { 61 | binding.favorite.setImageResource(R.drawable.avd_favorite_progress); 62 | ((Animatable) binding.favorite.getDrawable()).start(); 63 | } 64 | 65 | public void setFavorite(boolean favorite) { 66 | inProgress = false; 67 | checked = favorite; 68 | } 69 | 70 | @Override 71 | public void bind(@NonNull ItemHeartCardBinding binding, int position, @NonNull List payloads) { 72 | if (payloads.contains(FAVORITE)) { 73 | bindHeart(binding); 74 | } else { 75 | bind(binding, position); 76 | } 77 | } 78 | 79 | @Override 80 | public boolean isClickable() { 81 | return false; 82 | } 83 | 84 | public interface OnFavoriteListener { 85 | void onFavorite(HeartCardItem item, boolean favorite); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /example-databinding/src/main/java/com/xwray/groupie/example/databinding/item/SmallCardItem.java: -------------------------------------------------------------------------------- 1 | package com.xwray.groupie.example.databinding.item; 2 | 3 | public class SmallCardItem extends CardItem { 4 | 5 | public SmallCardItem() { 6 | super(); 7 | } 8 | 9 | public SmallCardItem(CharSequence text) { 10 | super(text); 11 | } 12 | 13 | @Override public int getSpanSize(int spanCount, int position) { 14 | return spanCount / 3; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /example-databinding/src/main/java/com/xwray/groupie/example/databinding/item/SwipeToDeleteItem.java: -------------------------------------------------------------------------------- 1 | package com.xwray.groupie.example.databinding.item; 2 | 3 | import androidx.annotation.ColorInt; 4 | import androidx.recyclerview.widget.ItemTouchHelper; 5 | 6 | public class SwipeToDeleteItem extends CardItem { 7 | public SwipeToDeleteItem(@ColorInt int colorRes) { 8 | super(); 9 | } 10 | 11 | @Override public int getSwipeDirs() { 12 | return ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /example-databinding/src/main/java/com/xwray/groupie/example/databinding/item/UpdatableItem.java: -------------------------------------------------------------------------------- 1 | package com.xwray.groupie.example.databinding.item; 2 | 3 | public class UpdatableItem extends SmallCardItem { 4 | 5 | private final int index; 6 | 7 | public UpdatableItem(int index) { 8 | super(String.valueOf(index)); 9 | this.index = index; 10 | } 11 | 12 | @Override 13 | public long getId() { 14 | return index; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /example-databinding/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 12 | 13 | 14 | 15 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /example-databinding/src/main/res/layout/item_card.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /example-databinding/src/main/res/layout/item_carousel.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example-databinding/src/main/res/layout/item_expandable_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 13 | 14 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /example-databinding/src/main/res/layout/item_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | 23 | 24 | 32 | 33 | 41 | 42 | 43 | 44 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /example-databinding/src/main/res/layout/item_heart_card.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 13 | 24 | 25 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /example-databinding/src/main/res/layout/item_square_card.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /example-shared/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /example-shared/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion rootProject.sdkVersion 5 | 6 | defaultConfig { 7 | minSdkVersion rootProject.minimumSdkVersion 8 | targetSdkVersion rootProject.sdkVersion 9 | versionCode 1 10 | versionName "1.0" 11 | vectorDrawables.useSupportLibrary true 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | } 17 | } 18 | lintOptions { 19 | abortOnError false 20 | } 21 | } 22 | 23 | dependencies { 24 | api project (':library') 25 | api "androidx.recyclerview:recyclerview:1.2.1" 26 | api "androidx.appcompat:appcompat:1.4.1" 27 | api "com.google.android.material:material:1.4.0" 28 | api "androidx.cardview:cardview:1.0.0" 29 | api "androidx.preference:preference:1.2.0" 30 | api "androidx.vectordrawable:vectordrawable:1.1.0" 31 | api "androidx.vectordrawable:vectordrawable-animated:1.1.0" 32 | } 33 | -------------------------------------------------------------------------------- /example-shared/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /example-shared/src/main/java/com/xwray/groupie/example/core/InfiniteScrollListener.java: -------------------------------------------------------------------------------- 1 | package com.xwray.groupie.example.core; 2 | 3 | import androidx.recyclerview.widget.LinearLayoutManager; 4 | import androidx.recyclerview.widget.RecyclerView; 5 | 6 | public abstract class InfiniteScrollListener extends RecyclerView.OnScrollListener { 7 | 8 | private int previousTotal = 0; // The total number of items in the dataset after the last load 9 | private boolean loading = true; // True if we are still waiting for the last set of data to load. 10 | private final int visibleThreshold = 5; // The minimum amount of items to have below your current scroll position before loading more. 11 | private int firstVisibleItem, visibleItemCount, totalItemCount; 12 | private int currentPage = 0; 13 | private LinearLayoutManager linearLayoutManager; 14 | private Runnable loadMore = new Runnable() { 15 | @Override 16 | public void run() { 17 | onLoadMore(currentPage); 18 | } 19 | }; 20 | 21 | public InfiniteScrollListener(LinearLayoutManager linearLayoutManager) { 22 | this.linearLayoutManager = linearLayoutManager; 23 | } 24 | 25 | public void setLinearLayoutManager(LinearLayoutManager linearLayoutManager) { 26 | this.linearLayoutManager = linearLayoutManager; 27 | } 28 | 29 | @Override 30 | public void onScrolled(final RecyclerView recyclerView, int dx, int dy) { 31 | super.onScrolled(recyclerView, dx, dy); 32 | visibleItemCount = recyclerView.getChildCount(); 33 | totalItemCount = linearLayoutManager.getItemCount(); 34 | firstVisibleItem = linearLayoutManager.findFirstVisibleItemPosition(); 35 | 36 | if (loading) { 37 | if (totalItemCount > previousTotal || totalItemCount == 0) { 38 | loading = false; 39 | previousTotal = totalItemCount; 40 | } 41 | } 42 | 43 | // End has been reached 44 | if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)) { 45 | currentPage++; 46 | recyclerView.post(loadMore); 47 | loading = true; 48 | } 49 | } 50 | 51 | public abstract void onLoadMore(int current_page); 52 | } 53 | -------------------------------------------------------------------------------- /example-shared/src/main/java/com/xwray/groupie/example/core/Prefs.java: -------------------------------------------------------------------------------- 1 | package com.xwray.groupie.example.core; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | 6 | import androidx.preference.PreferenceManager; 7 | 8 | public class Prefs { 9 | 10 | private static final String KEY_COLOR = "KEY_COLOR"; 11 | private static final String KEY_BOUNDS = "KEY_BOUNDS"; 12 | private static final String KEY_ASYNC = "KEY_ASYNC"; 13 | private static final String KEY_OFFSETS = "KEY_OFFSETS"; 14 | 15 | private static volatile Prefs singleton; 16 | private final SharedPreferences prefs; 17 | 18 | private boolean showColor; 19 | private boolean showBounds; 20 | private boolean useAsync; 21 | private boolean showOffsets; 22 | 23 | private Prefs(Context context) { 24 | prefs = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext()); 25 | showColor = prefs.getBoolean(KEY_COLOR, false); 26 | showBounds = prefs.getBoolean(KEY_BOUNDS, false); 27 | useAsync = prefs.getBoolean(KEY_ASYNC, false); 28 | showOffsets = prefs.getBoolean(KEY_OFFSETS, false); 29 | } 30 | 31 | public static Prefs get(Context context) { 32 | if (singleton == null) { 33 | synchronized (Prefs.class) { 34 | singleton = new Prefs(context); 35 | } 36 | } 37 | return singleton; 38 | } 39 | 40 | public void registerListener(SharedPreferences.OnSharedPreferenceChangeListener listener) { 41 | prefs.registerOnSharedPreferenceChangeListener(listener); 42 | } 43 | 44 | public void unregisterListener(SharedPreferences.OnSharedPreferenceChangeListener listener) { 45 | prefs.unregisterOnSharedPreferenceChangeListener(listener); 46 | } 47 | 48 | public boolean getShowBounds() { 49 | return showBounds; 50 | } 51 | 52 | public boolean getUseAsync() { 53 | return useAsync; 54 | } 55 | 56 | public boolean getShowOffsets() { 57 | return showOffsets; 58 | } 59 | 60 | public boolean getShowColor() { 61 | return showColor; 62 | } 63 | 64 | public void setShowColor(boolean showColor) { 65 | this.showColor = showColor; 66 | prefs.edit().putBoolean(KEY_COLOR, showColor).apply(); 67 | } 68 | 69 | void setShowOffsets(boolean showOffsets) { 70 | this.showOffsets = showOffsets; 71 | prefs.edit().putBoolean(KEY_OFFSETS, showOffsets).apply(); 72 | } 73 | 74 | void setShowBounds(boolean showBounds) { 75 | this.showBounds = showBounds; 76 | prefs.edit().putBoolean(KEY_BOUNDS, showBounds).apply(); 77 | } 78 | 79 | void setUseAsync(boolean useAsync) { 80 | this.useAsync = useAsync; 81 | prefs.edit().putBoolean(KEY_ASYNC, useAsync).apply(); 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /example-shared/src/main/java/com/xwray/groupie/example/core/SettingsActivity.java: -------------------------------------------------------------------------------- 1 | package com.xwray.groupie.example.core; 2 | 3 | import android.os.Bundle; 4 | import androidx.appcompat.app.AppCompatActivity; 5 | import androidx.appcompat.widget.SwitchCompat; 6 | import android.view.ViewGroup; 7 | import android.widget.CompoundButton; 8 | import android.widget.TextView; 9 | 10 | public class SettingsActivity extends AppCompatActivity { 11 | 12 | @Override 13 | protected void onCreate(Bundle savedInstanceState) { 14 | super.onCreate(savedInstanceState); 15 | setContentView(R.layout.activity_settings); 16 | final Prefs prefs = Prefs.get(this); 17 | 18 | ViewGroup useAsyncContainer = findViewById(R.id.use_async); 19 | SwitchCompat useAsyncSwitch = useAsyncContainer.findViewById(R.id.the_switch); 20 | TextView useAsyncText = useAsyncContainer.findViewById(R.id.text); 21 | 22 | ViewGroup showBoundsContainer = findViewById(R.id.show_bounds); 23 | SwitchCompat showBoundsSwitch = showBoundsContainer.findViewById(R.id.the_switch); 24 | TextView showBoundsText = showBoundsContainer.findViewById(R.id.text); 25 | 26 | ViewGroup showOffsetsContainer = findViewById(R.id.show_offsets); 27 | SwitchCompat showOffsetsSwitch = showOffsetsContainer.findViewById(R.id.the_switch); 28 | TextView showOffsetsText = showOffsetsContainer.findViewById(R.id.text); 29 | 30 | useAsyncText.setText(R.string.use_async); 31 | useAsyncSwitch.setChecked(prefs.getUseAsync()); 32 | 33 | showBoundsText.setText(R.string.show_bounds); 34 | showBoundsSwitch.setChecked(prefs.getShowBounds()); 35 | 36 | showOffsetsText.setText(R.string.show_offsets); 37 | showOffsetsSwitch.setChecked(prefs.getShowOffsets()); 38 | 39 | showBoundsSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 40 | @Override 41 | public void onCheckedChanged(CompoundButton compoundButton, boolean showBounds) { 42 | prefs.setShowBounds(showBounds); 43 | } 44 | }); 45 | 46 | useAsyncSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 47 | @Override 48 | public void onCheckedChanged(CompoundButton compoundButton, boolean useAsync) { 49 | prefs.setUseAsync(useAsync); 50 | } 51 | }); 52 | 53 | showOffsetsSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 54 | @Override 55 | public void onCheckedChanged(CompoundButton compoundButton, boolean showOffsets) { 56 | prefs.setShowOffsets(showOffsets); 57 | } 58 | }); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /example-shared/src/main/java/com/xwray/groupie/example/core/decoration/CarouselItemDecoration.java: -------------------------------------------------------------------------------- 1 | package com.xwray.groupie.example.core.decoration; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Paint; 5 | import android.graphics.Rect; 6 | import androidx.annotation.ColorInt; 7 | import androidx.annotation.NonNull; 8 | import androidx.recyclerview.widget.RecyclerView; 9 | import android.view.View; 10 | 11 | public class CarouselItemDecoration extends RecyclerView.ItemDecoration { 12 | 13 | private final Paint grayBackgroundPaint; 14 | private final int padding; 15 | 16 | public CarouselItemDecoration(@ColorInt int backgroundColor, int paddingPixelSize) { 17 | grayBackgroundPaint = new Paint(); 18 | grayBackgroundPaint.setColor(backgroundColor); 19 | padding = paddingPixelSize; 20 | } 21 | 22 | @Override public void getItemOffsets(Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { 23 | outRect.right = padding; 24 | } 25 | 26 | @Override public void onDraw(@NonNull Canvas c, RecyclerView parent, @NonNull RecyclerView.State state) { 27 | int childCount = parent.getChildCount(); 28 | RecyclerView.LayoutManager lm = parent.getLayoutManager(); 29 | for (int i = 0; i < childCount; i++) { 30 | View child = parent.getChildAt(i); 31 | 32 | int right = (int) (lm.getDecoratedRight(child) + child.getTranslationX()); 33 | if (i == childCount - 1) { 34 | // Last item 35 | right = Math.max(right, parent.getWidth()); 36 | } 37 | 38 | // Right border 39 | c.drawRect(child.getRight() + child.getTranslationX(), 0, right, parent.getHeight(), grayBackgroundPaint); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /example-shared/src/main/java/com/xwray/groupie/example/core/decoration/DebugItemDecoration.java: -------------------------------------------------------------------------------- 1 | package com.xwray.groupie.example.core.decoration; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Paint; 7 | 8 | import androidx.annotation.NonNull; 9 | import androidx.core.content.ContextCompat; 10 | import androidx.recyclerview.widget.RecyclerView; 11 | import android.view.View; 12 | 13 | import com.xwray.groupie.example.core.Prefs; 14 | import com.xwray.groupie.example.core.R; 15 | 16 | public class DebugItemDecoration extends RecyclerView.ItemDecoration { 17 | 18 | private int decoratedLeft, decoratedTop, decoratedRight, decoratedBottom; 19 | private int left, top, right, bottom; 20 | private Paint paint = new Paint(); 21 | private Prefs prefs; 22 | private int leftColor, topColor, rightColor, bottomColor; 23 | 24 | public DebugItemDecoration(Context context) { 25 | prefs = Prefs.get(context); 26 | leftColor = ContextCompat.getColor(context, R.color.red_200); 27 | topColor = ContextCompat.getColor(context, R.color.pink_200); 28 | rightColor = ContextCompat.getColor(context, R.color.purple_200); 29 | bottomColor = ContextCompat.getColor(context, R.color.indigo_200); 30 | } 31 | 32 | @Override public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { 33 | if (!(prefs.getShowBounds() || prefs.getShowOffsets())) return; 34 | 35 | int childCount = parent.getChildCount(); 36 | for (int i = 0; i < childCount; i++) { 37 | View child = parent.getChildAt(i); 38 | 39 | RecyclerView.LayoutManager lm = parent.getLayoutManager(); 40 | decoratedLeft = lm.getDecoratedLeft(child) + (int) child.getTranslationX(); 41 | decoratedTop = lm.getDecoratedTop(child) + (int) child.getTranslationY(); 42 | decoratedRight = lm.getDecoratedRight(child) + (int) child.getTranslationX(); 43 | decoratedBottom = lm.getDecoratedBottom(child) + (int) child.getTranslationY(); 44 | 45 | left = child.getLeft() + (int) child.getTranslationX(); 46 | top = child.getTop() + (int) child.getTranslationY(); 47 | right = child.getRight() + (int) child.getTranslationX(); 48 | bottom = child.getBottom() + (int) child.getTranslationY(); 49 | 50 | if (prefs.getShowBounds()) { 51 | paint.setColor(Color.RED); 52 | paint.setStyle(Paint.Style.STROKE); 53 | paint.setStrokeWidth(1); 54 | c.drawRect(decoratedLeft, decoratedTop, decoratedRight, decoratedBottom, paint); 55 | } 56 | 57 | if (prefs.getShowOffsets()) { 58 | paint.setStyle(Paint.Style.FILL); 59 | 60 | paint.setColor(leftColor); 61 | c.drawRect(decoratedLeft, decoratedTop, left, decoratedBottom, paint); 62 | 63 | paint.setColor(topColor); 64 | c.drawRect(decoratedLeft, decoratedTop, decoratedRight, top, paint); 65 | 66 | paint.setColor(rightColor); 67 | c.drawRect(right, decoratedTop, decoratedRight, decoratedBottom, paint); 68 | 69 | paint.setColor(bottomColor); 70 | c.drawRect(decoratedLeft, bottom, decoratedRight, decoratedBottom, paint); 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /example-shared/src/main/java/com/xwray/groupie/example/core/decoration/HeaderItemDecoration.java: -------------------------------------------------------------------------------- 1 | package com.xwray.groupie.example.core.decoration; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Paint; 5 | import android.graphics.Rect; 6 | import androidx.annotation.ColorInt; 7 | import androidx.annotation.LayoutRes; 8 | import androidx.annotation.NonNull; 9 | import androidx.recyclerview.widget.RecyclerView; 10 | import android.view.View; 11 | 12 | public class HeaderItemDecoration extends RecyclerView.ItemDecoration { 13 | 14 | private final Paint paint; 15 | private final int sidePaddingPixels; 16 | private final int headerViewType; 17 | 18 | public HeaderItemDecoration(@ColorInt int background, int sidePaddingPixels, @LayoutRes int headerViewType) { 19 | this.sidePaddingPixels = sidePaddingPixels; 20 | this.headerViewType = headerViewType; 21 | paint = new Paint(); 22 | paint.setColor(background); 23 | } 24 | 25 | @SuppressWarnings("BooleanMethodIsAlwaysInverted") 26 | public boolean isHeader(View child, RecyclerView parent) { 27 | int viewType = parent.getLayoutManager().getItemViewType(child); 28 | return viewType == headerViewType; 29 | } 30 | 31 | @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { 32 | if (!isHeader(view, parent)) return; 33 | 34 | outRect.left = sidePaddingPixels; 35 | outRect.right = sidePaddingPixels; 36 | } 37 | 38 | @Override public void onDraw(@NonNull Canvas c, RecyclerView parent, @NonNull RecyclerView.State state) { 39 | for (int i = 0; i < parent.getChildCount(); i++) { 40 | View child = parent.getChildAt(i); 41 | if (!isHeader(child, parent)) continue; 42 | 43 | RecyclerView.LayoutManager lm = parent.getLayoutManager(); 44 | 45 | float top = lm.getDecoratedTop(child) + child.getTranslationY(); 46 | float bottom = lm.getDecoratedBottom(child) + child.getTranslationY(); 47 | if (i == parent.getChildCount() - 1) { 48 | // Draw to bottom if last item 49 | bottom = Math.max(parent.getHeight(), bottom); 50 | } 51 | float right = lm.getDecoratedRight(child) + child.getTranslationX(); 52 | float left = lm.getDecoratedLeft(child) + child.getTranslationX(); 53 | c.drawRect(left, top, right, bottom, paint); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /example-shared/src/main/java/com/xwray/groupie/example/core/decoration/InsetItemDecoration.java: -------------------------------------------------------------------------------- 1 | package com.xwray.groupie.example.core.decoration; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Paint; 5 | import android.graphics.Rect; 6 | import androidx.annotation.ColorInt; 7 | import androidx.annotation.Dimension; 8 | import androidx.recyclerview.widget.GridLayoutManager; 9 | import androidx.recyclerview.widget.RecyclerView; 10 | import android.view.View; 11 | 12 | import com.xwray.groupie.GroupieViewHolder; 13 | 14 | /** 15 | * An ItemDecoration which applies an even visual padding on the left and right edges of a grid and 16 | * between each item, while also applying an even amount of inset to each item. This ensures that 17 | * all items remain the same size. 18 | * 19 | * It assumes all items in a row have the same span size, and it assumes it's the only item 20 | * decorator. 21 | */ 22 | public class InsetItemDecoration extends RecyclerView.ItemDecoration { 23 | 24 | private final Paint paint; 25 | private final int padding; 26 | private final String key; 27 | private final String value; 28 | 29 | public InsetItemDecoration(@ColorInt int backgroundColor, @Dimension int padding, String key, String value) { 30 | this.key = key; 31 | this.value = value; 32 | paint = new Paint(); 33 | paint.setColor(backgroundColor); 34 | this.padding = padding; 35 | } 36 | 37 | private boolean isInset(View view, RecyclerView parent) { 38 | GroupieViewHolder viewHolder = (GroupieViewHolder) parent.getChildViewHolder(view); 39 | if (viewHolder.getExtras().containsKey(key)) { 40 | return viewHolder.getExtras().get(key).equals(value); 41 | } else { 42 | return false; 43 | } 44 | } 45 | 46 | @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { 47 | if (!isInset(view, parent)) return; 48 | 49 | GridLayoutManager.LayoutParams layoutParams = (GridLayoutManager.LayoutParams) view.getLayoutParams(); 50 | GridLayoutManager gridLayoutManager = (GridLayoutManager) parent.getLayoutManager(); 51 | float spanSize = layoutParams.getSpanSize(); 52 | float totalSpanSize = gridLayoutManager.getSpanCount(); 53 | 54 | float n = totalSpanSize / spanSize; // num columns 55 | float c = layoutParams.getSpanIndex() / spanSize; // column index 56 | 57 | float leftPadding = padding * ((n - c) / n); 58 | float rightPadding = padding * ((c + 1) / n); 59 | 60 | outRect.left = (int) leftPadding; 61 | outRect.right = (int) rightPadding; 62 | outRect.bottom = padding; 63 | } 64 | 65 | @Override public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { 66 | RecyclerView.LayoutManager lm = parent.getLayoutManager(); 67 | 68 | int childCount = parent.getChildCount(); 69 | for (int i = 0; i < childCount; i++) { 70 | View child = parent.getChildAt(i); 71 | if (!isInset(child, parent)) continue; 72 | 73 | // 74 | if (child.getTranslationX() != 0 || child.getTranslationY() != 0) { 75 | c.drawRect( 76 | lm.getDecoratedLeft(child), 77 | lm.getDecoratedTop(child), 78 | lm.getDecoratedRight(child), 79 | lm.getDecoratedBottom(child), 80 | paint 81 | ); 82 | continue; 83 | } 84 | 85 | boolean isLast = i == childCount - 1; 86 | float top = child.getTop() + child.getTranslationY(); 87 | float bottom = child.getBottom() + child.getTranslationY(); 88 | 89 | // Left border 90 | c.drawRect( 91 | lm.getDecoratedLeft(child) + child.getTranslationX(), 92 | top, 93 | child.getLeft() + child.getTranslationX(), 94 | bottom, 95 | paint); 96 | 97 | float right = lm.getDecoratedRight(child) + child.getTranslationX(); 98 | if (isLast) { 99 | right = Math.max(right, parent.getWidth()); 100 | } 101 | 102 | // Right border 103 | c.drawRect( 104 | child.getRight() + child.getTranslationX(), 105 | top, 106 | right, 107 | bottom, 108 | paint); 109 | 110 | // Bottom border 111 | c.drawRect( 112 | lm.getDecoratedLeft(child) + child.getTranslationY(), 113 | bottom, 114 | right, 115 | lm.getDecoratedBottom(child) + child.getTranslationY(), 116 | paint); 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /example-shared/src/main/java/com/xwray/groupie/example/core/decoration/SwipeTouchCallback.java: -------------------------------------------------------------------------------- 1 | package com.xwray.groupie.example.core.decoration; 2 | 3 | import android.graphics.Canvas; 4 | 5 | import androidx.annotation.NonNull; 6 | import androidx.recyclerview.widget.RecyclerView; 7 | import androidx.recyclerview.widget.ItemTouchHelper; 8 | import android.view.View; 9 | 10 | import com.xwray.groupie.TouchCallback; 11 | 12 | public abstract class SwipeTouchCallback extends TouchCallback { 13 | public SwipeTouchCallback() { 14 | super(); 15 | } 16 | 17 | @Override public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { 18 | return false; 19 | } 20 | 21 | @Override public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { 22 | if (ItemTouchHelper.ACTION_STATE_SWIPE == actionState) { 23 | View child = viewHolder.itemView; 24 | RecyclerView.LayoutManager lm = recyclerView.getLayoutManager(); 25 | 26 | // Fade out the item 27 | child.setAlpha(1 - (Math.abs(dX) / (float) child.getWidth())); 28 | } 29 | 30 | super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /example-shared/src/main/java/com/xwray/groupie/example/core/widget/CheckableImageView.java: -------------------------------------------------------------------------------- 1 | package com.xwray.groupie.example.core.widget; 2 | 3 | import android.content.Context; 4 | import androidx.appcompat.widget.AppCompatImageView; 5 | import android.util.AttributeSet; 6 | import android.widget.Checkable; 7 | 8 | public class CheckableImageView extends AppCompatImageView implements Checkable { 9 | 10 | public CheckableImageView(Context context) { 11 | super(context); 12 | } 13 | 14 | public CheckableImageView(Context context, AttributeSet attrs) { 15 | super(context, attrs); 16 | } 17 | 18 | private static final int[] CheckedStateSet = {android.R.attr.state_checked}; 19 | 20 | private boolean checked = false; 21 | 22 | public boolean isChecked() { 23 | return checked; 24 | } 25 | 26 | public void setChecked(boolean b) { 27 | if (b != checked) { 28 | checked = b; 29 | refreshDrawableState(); 30 | } 31 | } 32 | 33 | public void toggle() { 34 | setChecked(!checked); 35 | } 36 | 37 | @Override 38 | public int[] onCreateDrawableState(int extraSpace) { 39 | final int[] drawableState = super.onCreateDrawableState(extraSpace + 1); 40 | if (isChecked()) { 41 | mergeDrawableStates(drawableState, CheckedStateSet); 42 | } 43 | return drawableState; 44 | } 45 | 46 | @Override 47 | protected void drawableStateChanged() { 48 | super.drawableStateChanged(); 49 | invalidate(); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /example-shared/src/main/res/animator/opacity_pulse.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 12 | 20 | 21 | -------------------------------------------------------------------------------- /example-shared/src/main/res/animator/rotation_collapse_to_expand.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /example-shared/src/main/res/animator/rotation_expand_to_collapse.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /example-shared/src/main/res/drawable-v21/ripple_circular.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /example-shared/src/main/res/drawable/avd_favorite_progress.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /example-shared/src/main/res/drawable/clear.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /example-shared/src/main/res/drawable/collapse.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /example-shared/src/main/res/drawable/collapse_animated.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /example-shared/src/main/res/drawable/expand.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /example-shared/src/main/res/drawable/expand_animated.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /example-shared/src/main/res/drawable/favorite.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /example-shared/src/main/res/drawable/favorite_border.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /example-shared/src/main/res/drawable/favorite_pressed.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | 11 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /example-shared/src/main/res/drawable/favorite_state_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /example-shared/src/main/res/drawable/ic_keyboard_arrow_right_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /example-shared/src/main/res/drawable/palette.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example-shared/src/main/res/drawable/ripple_circular.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /example-shared/src/main/res/drawable/shuffle.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example-shared/src/main/res/drawable/wrench.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example-shared/src/main/res/layout/activity_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 12 | 13 | 16 | 17 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /example-shared/src/main/res/layout/switch_pref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 15 | 16 | 23 | 24 | -------------------------------------------------------------------------------- /example-shared/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lisawray/groupie/85889f23b7176cc0f4ecdc657335ebcc93cc036f/example-shared/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example-shared/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lisawray/groupie/85889f23b7176cc0f4ecdc657335ebcc93cc036f/example-shared/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example-shared/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lisawray/groupie/85889f23b7176cc0f4ecdc657335ebcc93cc036f/example-shared/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example-shared/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lisawray/groupie/85889f23b7176cc0f4ecdc657335ebcc93cc036f/example-shared/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example-shared/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lisawray/groupie/85889f23b7176cc0f4ecdc657335ebcc93cc036f/example-shared/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example-shared/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /example-shared/src/main/res/values-w480dp/bools.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /example-shared/src/main/res/values-w640dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 3 4 | 5 | -------------------------------------------------------------------------------- /example-shared/src/main/res/values-w720dp/bools.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /example-shared/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 4 7 | 8 | -------------------------------------------------------------------------------- /example-shared/src/main/res/values/bools.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | false 4 | false 5 | 6 | -------------------------------------------------------------------------------- /example-shared/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFF444 4 | #DDD333 5 | #fff 6 | #eee 7 | #fff 8 | #ef9a9a 9 | #F48FB1 10 | #CE93D8 11 | #B39DDB 12 | #9FA8DA 13 | #90CAF9 14 | #81D4FA 15 | #80DEEA 16 | #80CBC4 17 | #A5D6A7 18 | #C5E1A5 19 | #E6EE9C 20 | #FFF59D 21 | #FFE082 22 | #FFCC80 23 | #FFAB91 24 | 25 | 26 | @color/red_200 27 | @color/pink_200 28 | @color/purple_200 29 | @color/deep_purple_200 30 | @color/indigo_200 31 | @color/blue_200 32 | @color/light_blue_200 33 | @color/cyan_200 34 | @color/teal_200 35 | @color/green_200 36 | @color/light_green_200 37 | @color/lime_200 38 | @color/yellow_200 39 | @color/amber_200 40 | @color/orange_200 41 | @color/deep_orange_200 42 | 43 | 44 | 45 | @color/red_500 46 | @color/pink_500 47 | @color/purple_500 48 | @color/deep_purple_500 49 | @color/indigo_500 50 | @color/blue_500 51 | @color/light_blue_500 52 | @color/cyan_500 53 | @color/teal_500 54 | @color/green_500 55 | @color/light_green_500 56 | @color/lime_500 57 | @color/yellow_500 58 | @color/amber_500 59 | @color/orange_500 60 | @color/deep_orange_500 61 | 62 | 63 | 64 | #eeeeeeee 65 | #00000000 66 | 67 | #f44336 68 | #E91E63 69 | #9C27B0 70 | #673AB7 71 | #3F51B5 72 | #2196F3 73 | #03A9F4 74 | #00BCD4 75 | #009688 76 | #4CAF50 77 | #8BC34A 78 | #CDDC39 79 | #FFEB3B 80 | #FFC107 81 | #FF9800 82 | #FF5722 83 | 84 | -------------------------------------------------------------------------------- /example-shared/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 4dp 6 | 8dp 7 | 16dp 8 | 2 9 | 16dp 10 | 11 | -------------------------------------------------------------------------------- /example-shared/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Groupie 3 | Expanding group 4 | Carousel 5 | Vertical columns 6 | A full bleed item 7 | Multiple columns with even spacing 8 | Infinite loading 9 | Tap on the header to expand or contract the group. 10 | Swipe this section horizontally to scroll its items. 11 | Swipe to delete 12 | Drag to reorder 13 | Updating group 14 | Click the shuffle icon to update the list with a random set of changes. 15 | SettingsActivity 16 | Use async adapter 17 | Show bounds 18 | Show offsets 19 | Update with payload 20 | These items demonstrate robust, efficient partial asynchronous updates 21 | Reorderable Section 22 | Tap to Reorder 23 | Tapping on the title sends this group to the bottom of the section 24 | 25 | -------------------------------------------------------------------------------- /example-shared/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 15 | 16 |