├── .gitignore
├── README.md
├── build.gradle
├── compoundadapter-sample
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── negusoft
│ │ └── compoundadapter
│ │ └── ApplicationTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── negusoft
│ │ │ └── compoundadapter
│ │ │ ├── MainActivity.java
│ │ │ ├── SampleActivity.java
│ │ │ ├── adapter
│ │ │ ├── DynamicDataAdapter.java
│ │ │ ├── StaticDataAdapter.java
│ │ │ └── TreeNodeAdapter.java
│ │ │ ├── data
│ │ │ └── Samples.java
│ │ │ └── fragment
│ │ │ ├── AdapterGroupTreeFragment.java
│ │ │ ├── AdapterGroupWithChangingData.java
│ │ │ ├── AdapterGroupWithHeaderFragment.java
│ │ │ ├── AdapterGroupWithStableIds.java
│ │ │ └── MainListFragment.java
│ └── res
│ │ ├── drawable-xxhdpi
│ │ └── ic_github.png
│ │ ├── drawable
│ │ └── selectable_item.xml
│ │ ├── layout
│ │ ├── item_content.xml
│ │ ├── item_sample_list_title.xml
│ │ ├── main_content.xml
│ │ ├── main_layout.xml
│ │ ├── recyclerview.xml
│ │ ├── sample_layout.xml
│ │ └── tree_fragment.xml
│ │ ├── menu
│ │ └── adaptergroup_with_header.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-w820dp
│ │ └── dimens.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── negusoft
│ └── compoundadapter
│ └── ExampleUnitTest.java
├── compoundadapter
├── .gitignore
├── bintray-upload.gradle
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── negusoft
│ │ └── compountadapter
│ │ └── ApplicationTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ └── java
│ │ └── com
│ │ └── negusoft
│ │ └── compountadapter
│ │ └── recyclerview
│ │ ├── AdapterGroup.java
│ │ ├── AdapterPosition.java
│ │ └── SingleAdapter.java
│ └── test
│ └── java
│ └── com
│ └── negusoft
│ └── compountadapter
│ └── ExampleUnitTest.java
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | # built application files
2 | *.apk
3 | *.ap_
4 |
5 | # files for the dex VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # generated files
12 | bin/
13 | gen/
14 |
15 | # Local configuration file (sdk path, etc)
16 | local.properties
17 |
18 | # Eclipse project files
19 | .classpath
20 | .project
21 |
22 | # Proguard folder generated by Eclipse
23 | proguard/
24 |
25 | # Intellij project files
26 | *.iml
27 | *.ipr
28 | *.iws
29 | .idea/
30 | *.prefs
31 |
32 | # Gradle
33 | build/
34 | .gradle
35 |
36 | # Mac files
37 | .DS_Store
38 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | - Project: CompoundAdapter
2 | - Developer: Borja Lopez Urkidi
3 | - Organization: Negusoft
4 | - Web: http://www.negusoft.com
5 |
6 |
7 | Description
8 | ===========
9 |
10 | Android library that provides a way to define a RecyclerView.Adapter out of subadapters (AdapterGroup).
11 |
12 |
13 | Features
14 | ========
15 | - AdapterGroup: Adapter containing inner addapters.
16 | - Nesting: AdapterGroups can have other AdapterGroups
17 | - Performance: Child adapters of the same type can recycle ViewHolders (as expected)
18 | - Edit the adapter structure while the AdapterGroup is attached to the RecyclerView
19 |
20 |
21 | Basic Setup
22 | ===========
23 |
24 | You can add CompoundAdapter to your project using the following gradle dependency:
25 |
26 | or Gradle:
27 | ```groovy
28 | compile 'com.negusoft.compoundadapter:compoundadapter:0.8.0'
29 | ```
30 |
31 | You can then use the AdapterGroup class to combine RecyclerView.Adapters. For example the following code will display the content of two adapters in the same RecyclerView:
32 |
33 | ``` java
34 | RecyclerView recyclerView = (RecyclerView)findViewById(R.id.recyclerview);
35 |
36 | AdapterGroup adapterGroup = new AdapterGroup();
37 | adapterGroup.addAdapter(new FirstAdapter());
38 | adapterGroup.addAdapter(new SecondAdapter());
39 |
40 | recyclerView.setAdapter(adapterGroup);
41 | ```
42 |
43 |
44 | Relative Item Positions
45 | =======================
46 |
47 | Keep in mind that if you are using the ViewHolders position (getAdapterPosition(), getLayoutPosition()), the reported values are relative to the origin. That is, in the previous example, the onClick() implemented in the first item of the SecondAdapter will not report a position 0.
48 |
49 |
50 | Adapter Types and Performance
51 | =============================
52 |
53 | A good thing about RecyclerViews is that they reuse ViewHolder to optimize performance. In order not to loose this optimizations, AdapterGroup groups RecyclerView.Adapters by type, such a way that they can reuse each others ViewHolders. This way, if you add two instances of MyBookAdapter, for example, the second instance might bind a ViewHolder that was instantiated by the first one.
54 |
55 | By default, adapters are grouped by their java class. If you want more control on this, you may add them to the AdapterGroup by using addAdapter(adapter, type). This way, you can make adapters of different type share ViewHolders. Or the oposite, avoid that two adapters share ViewHolders.
56 |
57 |
58 | Updateing Data
59 | ==============
60 |
61 | You can update the data with the usual methods: notifyDataSetChanged(), notifyItemInserted()... You can use this methods on the AdapterGroup directly or call the child Adapters.
62 |
63 | Just make sure that the positions passed to the notifyItemXxx() method are relative to that specific adapter. That is, to remove the fist item in the Second adapter might be done like this:
64 |
65 | ``` java
66 | // Remove the first item of secondAdapter
67 | secondAdapter.notifyItemRangeRemoved(0);
68 |
69 | // Same operation, given that firstAdapter has 5 items
70 | adapterGroup.notifyItemRangeRemoved(5);
71 | ```
72 |
73 |
74 | License
75 | =======
76 |
77 | Copyright 2016 Negusoft
78 |
79 | Licensed under the Apache License, Version 2.0 (the "License");
80 | you may not use this file except in compliance with the License.
81 | You may obtain a copy of the License at
82 |
83 | http://www.apache.org/licenses/LICENSE-2.0
84 |
85 | Unless required by applicable law or agreed to in writing, software
86 | distributed under the License is distributed on an "AS IS" BASIS,
87 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
88 | See the License for the specific language governing permissions and
89 | limitations under the License.
90 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.1.2'
9 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.4'
10 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3'
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | jcenter()
17 | }
18 | }
19 |
20 | task clean(type: Delete) {
21 | delete rootProject.buildDir
22 | }
23 |
--------------------------------------------------------------------------------
/compoundadapter-sample/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/compoundadapter-sample/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "24.0.0"
6 |
7 | defaultConfig {
8 | applicationId "com.negusoft.compoundadapter"
9 | minSdkVersion 17
10 | targetSdkVersion 23
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile project(":compoundadapter")
24 |
25 | compile 'com.android.support:appcompat-v7:23.4.0'
26 | compile 'com.android.support:design:23.4.0'
27 |
28 | testCompile 'junit:junit:4.12'
29 | }
30 |
--------------------------------------------------------------------------------
/compoundadapter-sample/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 /Users/blurkidi/dev/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 |
--------------------------------------------------------------------------------
/compoundadapter-sample/src/androidTest/java/com/negusoft/compoundadapter/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.negusoft.compoundadapter;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/compoundadapter-sample/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
11 |
12 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/compoundadapter-sample/src/main/java/com/negusoft/compoundadapter/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.negusoft.compoundadapter;
2 |
3 | import android.content.Intent;
4 | import android.net.Uri;
5 | import android.os.Bundle;
6 | import android.support.design.widget.FloatingActionButton;
7 | import android.support.design.widget.Snackbar;
8 | import android.support.v7.app.AppCompatActivity;
9 | import android.support.v7.widget.Toolbar;
10 | import android.view.View;
11 |
12 | public class MainActivity extends AppCompatActivity {
13 |
14 | private static final String REPO_URL = "https://github.com/negusoft/CompoundAdapter-android";
15 |
16 | @Override
17 | protected void onCreate(Bundle savedInstanceState) {
18 | super.onCreate(savedInstanceState);
19 | setContentView(R.layout.main_layout);
20 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
21 | setSupportActionBar(toolbar);
22 |
23 | FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
24 | fab.setOnClickListener(new View.OnClickListener() {
25 | @Override
26 | public void onClick(View view) {
27 | Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(REPO_URL));
28 | startActivity(intent);
29 | }
30 | });
31 |
32 | findViewById(R.id.adapterGroupWithHeader).setOnClickListener(new View.OnClickListener() {
33 | @Override
34 | public void onClick(View v) {
35 | Intent intent = SampleActivity.makeIntent(MainActivity.this, SampleActivity.SampleType.ADAPTER_GROUP_WITH_HEADER);
36 | startActivity(intent);
37 | }
38 | });
39 | findViewById(R.id.adapterGroupWithChangingData).setOnClickListener(new View.OnClickListener() {
40 | @Override
41 | public void onClick(View v) {
42 | Intent intent = SampleActivity.makeIntent(MainActivity.this, SampleActivity.SampleType.ADAPTER_GROUP_WITH_CHANGING_DATA);
43 | startActivity(intent);
44 | }
45 | });
46 | findViewById(R.id.adapterGroupWithStableIds).setOnClickListener(new View.OnClickListener() {
47 | @Override
48 | public void onClick(View v) {
49 | Intent intent = SampleActivity.makeIntent(MainActivity.this, SampleActivity.SampleType.ADAPTER_GROUP_WITH_STABLE_IDS);
50 | startActivity(intent);
51 | }
52 | });
53 | findViewById(R.id.adapterGroupTree).setOnClickListener(new View.OnClickListener() {
54 | @Override
55 | public void onClick(View v) {
56 | Intent intent = SampleActivity.makeIntent(MainActivity.this, SampleActivity.SampleType.ADAPTER_GROUP_TREE);
57 | startActivity(intent);
58 | }
59 | });
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/compoundadapter-sample/src/main/java/com/negusoft/compoundadapter/SampleActivity.java:
--------------------------------------------------------------------------------
1 | package com.negusoft.compoundadapter;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.support.design.widget.FloatingActionButton;
7 | import android.support.design.widget.Snackbar;
8 | import android.support.v4.app.Fragment;
9 | import android.support.v7.app.AppCompatActivity;
10 | import android.support.v7.widget.Toolbar;
11 | import android.view.MenuItem;
12 | import android.view.View;
13 |
14 | import com.negusoft.compoundadapter.fragment.AdapterGroupTreeFragment;
15 | import com.negusoft.compoundadapter.fragment.AdapterGroupWithChangingData;
16 | import com.negusoft.compoundadapter.fragment.AdapterGroupWithHeaderFragment;
17 | import com.negusoft.compoundadapter.fragment.AdapterGroupWithStableIds;
18 | import com.negusoft.compoundadapter.fragment.MainListFragment;
19 |
20 | public class SampleActivity extends AppCompatActivity {
21 |
22 | private static String EXTRA_SAMPLE_TYPE = "EXTRA_SAMPLE_TYPE";
23 |
24 | public enum SampleType {
25 | ADAPTER_GROUP_WITH_HEADER,
26 | ADAPTER_GROUP_WITH_CHANGING_DATA,
27 | ADAPTER_GROUP_WITH_STABLE_IDS,
28 | ADAPTER_GROUP_TREE
29 | }
30 |
31 | public static Intent makeIntent(Context c, SampleType sampleType) {
32 | Intent result = new Intent(c, SampleActivity.class)
33 | .putExtra(EXTRA_SAMPLE_TYPE, sampleType.name());
34 | return result;
35 | }
36 |
37 | @Override
38 | protected void onCreate(Bundle savedInstanceState) {
39 | super.onCreate(savedInstanceState);
40 | setContentView(R.layout.sample_layout);
41 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
42 | setSupportActionBar(toolbar);
43 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
44 |
45 | if (savedInstanceState == null) {
46 | String typeName = getIntent().getStringExtra(EXTRA_SAMPLE_TYPE);
47 | SampleType type = SampleType.valueOf(typeName);
48 | addFragment(type);
49 | }
50 | }
51 |
52 | @Override
53 | public boolean onOptionsItemSelected(MenuItem item) {
54 | switch (item.getItemId()) {
55 | case android.R.id.home:
56 | finish();
57 | return true;
58 | default:
59 | return super.onOptionsItemSelected(item);
60 | }
61 | }
62 |
63 | private void addFragment(SampleType type) {
64 | switch (type) {
65 | case ADAPTER_GROUP_WITH_HEADER:
66 | addFragment(AdapterGroupWithHeaderFragment.newInstance());
67 | break;
68 | case ADAPTER_GROUP_WITH_CHANGING_DATA:
69 | addFragment(AdapterGroupWithChangingData.newInstance());
70 | break;
71 | case ADAPTER_GROUP_WITH_STABLE_IDS:
72 | addFragment(AdapterGroupWithStableIds.newInstance());
73 | break;
74 | case ADAPTER_GROUP_TREE:
75 | addFragment(AdapterGroupTreeFragment.newInstance());
76 | break;
77 | }
78 | }
79 |
80 | private void addFragment(Fragment fragment) {
81 | getSupportFragmentManager()
82 | .beginTransaction()
83 | .add(R.id.content, fragment)
84 | .commit();
85 | }
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/compoundadapter-sample/src/main/java/com/negusoft/compoundadapter/adapter/DynamicDataAdapter.java:
--------------------------------------------------------------------------------
1 | package com.negusoft.compoundadapter.adapter;
2 |
3 | import android.support.v7.widget.RecyclerView;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.TextView;
8 | import android.widget.Toast;
9 |
10 | import com.negusoft.compoundadapter.R;
11 |
12 | import java.util.ArrayList;
13 | import java.util.List;
14 |
15 | /**
16 | * RecyclerView adapter displaying a static list of items
17 | */
18 | public class DynamicDataAdapter extends RecyclerView.Adapter {
19 |
20 | public interface ItemSelectedListener {
21 | void onItemSelected(Item item);
22 | }
23 |
24 | public static class Item {
25 | public final String value;
26 | public Item(String value) {
27 | this.value = value;
28 | }
29 | }
30 |
31 | static final class ViewHolder extends RecyclerView.ViewHolder {
32 |
33 | TextView textView;
34 | Item item;
35 |
36 | ViewHolder(View itemView) {
37 | super(itemView);
38 | textView = (TextView)itemView.findViewById(android.R.id.text1);
39 | }
40 |
41 | void setOntItemSelectedListener(final ItemSelectedListener listener) {
42 | if (listener == null) {
43 | textView.setOnClickListener(null);
44 | } else {
45 | textView.setOnClickListener(new View.OnClickListener() {
46 | @Override
47 | public void onClick(View v) {
48 | listener.onItemSelected(item);
49 | }
50 | });
51 | }
52 | }
53 |
54 | void setItem(Item item) {
55 | this.item = item;
56 | textView.setText(item.value);
57 | }
58 |
59 | String getText() {
60 | return textView.getText().toString();
61 | }
62 | }
63 |
64 | private final List- mItems;
65 | private ItemSelectedListener mItemSelectedListener;
66 |
67 | public DynamicDataAdapter() {
68 | mItems = new ArrayList<>(10);
69 | }
70 |
71 | public DynamicDataAdapter(List values) {
72 | mItems = new ArrayList<>(values.size());
73 | for (String value : values) {
74 | mItems.add(new Item(value));
75 | }
76 | }
77 |
78 | public Item addItem(String value) {
79 | return addItem(value, true);
80 | }
81 |
82 | public Item addItem(String value, boolean notify) {
83 | Item item = new Item(value);
84 | mItems.add(item);
85 | if (notify) {
86 | notifyItemInserted(mItems.size() - 1);
87 | }
88 |
89 | return item;
90 | }
91 |
92 | public void removeItem(Item item) {
93 | removeItem(item, true);
94 | }
95 |
96 | public void removeItem(Item item, boolean notify) {
97 | int index = mItems.indexOf(item);
98 | if (index >= 0) {
99 | mItems.remove(index);
100 | if (notify) {
101 | notifyItemRemoved(index);
102 | }
103 | }
104 | }
105 |
106 | public void setItemSelectedListener(ItemSelectedListener listener) {
107 | mItemSelectedListener = listener;
108 | }
109 |
110 | @Override
111 | public DynamicDataAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
112 | LayoutInflater inflater = LayoutInflater.from(parent.getContext());
113 | View view = inflater.inflate(R.layout.item_content, parent, false);
114 | return new DynamicDataAdapter.ViewHolder(view);
115 | }
116 |
117 | @Override
118 | public void onBindViewHolder(final DynamicDataAdapter.ViewHolder holder, int position) {
119 | holder.setItem(mItems.get(position));
120 | holder.setOntItemSelectedListener(mItemSelectedListener);
121 | }
122 |
123 | @Override
124 | public int getItemCount() {
125 | return mItems.size();
126 | }
127 |
128 | @Override
129 | public long getItemId(int position) {
130 | return mItems.get(position).hashCode();
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/compoundadapter-sample/src/main/java/com/negusoft/compoundadapter/adapter/StaticDataAdapter.java:
--------------------------------------------------------------------------------
1 | package com.negusoft.compoundadapter.adapter;
2 |
3 | import android.support.v7.widget.RecyclerView;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.TextView;
8 | import android.widget.Toast;
9 |
10 | import com.negusoft.compoundadapter.R;
11 | import com.negusoft.compoundadapter.data.Samples;
12 |
13 | import java.util.ArrayList;
14 | import java.util.List;
15 |
16 | /**
17 | * RecyclerView adapter displaying a static list of items
18 | */
19 | public class StaticDataAdapter extends RecyclerView.Adapter {
20 |
21 | public interface ItemSelectedListener {
22 | public void onItemSelected(String value);
23 | }
24 |
25 | static final class ViewHolder extends RecyclerView.ViewHolder {
26 |
27 | TextView textView;
28 |
29 | ViewHolder(View itemView) {
30 | super(itemView);
31 | textView = (TextView)itemView.findViewById(android.R.id.text1);
32 | itemView.setOnClickListener(new View.OnClickListener() {
33 | @Override
34 | public void onClick(View v) {
35 | Toast.makeText(v.getContext(), textView.getText(), Toast.LENGTH_SHORT).show();
36 | }
37 | });
38 | }
39 |
40 | void setText(String text) {
41 | textView.setText(text);
42 | }
43 |
44 | String getText() {
45 | return textView.getText().toString();
46 | }
47 | }
48 |
49 | private ItemSelectedListener mItemSelectedListener;
50 |
51 | public void setItemSelectedListener(ItemSelectedListener listener) {
52 | mItemSelectedListener = listener;
53 | }
54 |
55 | @Override
56 | public StaticDataAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
57 | LayoutInflater inflater = LayoutInflater.from(parent.getContext());
58 | View view = inflater.inflate(R.layout.item_content, parent, false);
59 | return new StaticDataAdapter.ViewHolder(view);
60 | }
61 |
62 | @Override
63 | public void onBindViewHolder(final StaticDataAdapter.ViewHolder holder, int position) {
64 | holder.setText(Samples.VALUES[position]);
65 | holder.textView.setOnClickListener(new View.OnClickListener() {
66 | @Override
67 | public void onClick(View v) {
68 | if (mItemSelectedListener != null)
69 | mItemSelectedListener.onItemSelected(holder.getText());
70 | }
71 | });
72 | }
73 |
74 | @Override
75 | public int getItemCount() {
76 | return Samples.VALUES.length;
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/compoundadapter-sample/src/main/java/com/negusoft/compoundadapter/adapter/TreeNodeAdapter.java:
--------------------------------------------------------------------------------
1 | package com.negusoft.compoundadapter.adapter;
2 |
3 | import android.content.Context;
4 | import android.content.res.Resources;
5 | import android.graphics.drawable.ColorDrawable;
6 | import android.graphics.drawable.Drawable;
7 | import android.support.v7.widget.RecyclerView;
8 | import android.util.Log;
9 | import android.util.TypedValue;
10 | import android.view.LayoutInflater;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 | import android.widget.TextView;
14 | import android.widget.Toast;
15 |
16 | import com.negusoft.compoundadapter.R;
17 | import com.negusoft.compountadapter.recyclerview.AdapterGroup;
18 | import com.negusoft.compountadapter.recyclerview.AdapterPosition;
19 |
20 | import java.util.Random;
21 |
22 | /** Adapter representing a node in a tree and allows adding/removing child nodes. */
23 | public class TreeNodeAdapter extends AdapterGroup {
24 |
25 | // The depth of the node, it will determine the indentation
26 | private final int mDepth;
27 |
28 | // Text to be displayed for the node
29 | private final String mName;
30 |
31 | private NodeItemAdapter mNodeItemAdapter;
32 | private TreeNodeAdapter mParentNode;
33 |
34 | private ItemClickListener mListener;
35 |
36 | private boolean mSelected = false;
37 |
38 | public TreeNodeAdapter(String name, ItemClickListener listener) {
39 | this(0, name, listener);
40 | }
41 |
42 | TreeNodeAdapter(int depth, String name, ItemClickListener listener) {
43 | super();
44 | mDepth = depth;
45 | mName = name;
46 | mListener = listener;
47 | mNodeItemAdapter = new NodeItemAdapter();
48 | addAdapter(mNodeItemAdapter);
49 | }
50 |
51 | public TreeNodeAdapter addNode(String name) {
52 | TreeNodeAdapter node = new TreeNodeAdapter(mDepth + 1, name, mListener);
53 | addAdapter(node);
54 |
55 | node.mParentNode = this;
56 |
57 | return node;
58 | }
59 |
60 | public void addSibling(String name) {
61 | if (mParentNode == null)
62 | return;
63 | mParentNode.addNode(name);
64 | }
65 |
66 | public void setSelected(boolean selected) {
67 | mSelected = selected;
68 | mNodeItemAdapter.notifyItemChanged(0);
69 | }
70 |
71 | public void delete() {
72 | if (mParentNode == null)
73 | return;
74 | mParentNode.removeAdapter(this);
75 | }
76 |
77 | public TreeNodeAdapter getParentNode() {
78 | return mParentNode;
79 | }
80 |
81 | public interface ItemClickListener {
82 | void onNodeSelected(TreeNodeAdapter node, TreeNodeAdapter parentNode, int index);
83 | }
84 |
85 | private static class ViewHolder extends RecyclerView.ViewHolder {
86 |
87 | View selectableView;
88 | TextView textView;
89 |
90 | public ViewHolder(View itemView) {
91 | super(itemView);
92 | selectableView = itemView.findViewById(R.id.selectable);
93 | textView = (TextView) itemView.findViewById(android.R.id.text1);
94 | }
95 |
96 | public void setDepth(int depth) {
97 | Resources r = textView.getContext().getResources();
98 | float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 14, r.getDisplayMetrics());
99 | textView.setPaddingRelative((int)(px * (depth + 1)), 0, 0, 0);
100 | }
101 |
102 | public void setText(String text) {
103 | textView.setText(text);
104 | }
105 |
106 | public void setClickListener(View.OnClickListener listener) {
107 | textView.setOnClickListener(listener);
108 | }
109 | }
110 |
111 | private class NodeItemAdapter extends RecyclerView.Adapter {
112 | @Override
113 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
114 | LayoutInflater inflater = LayoutInflater.from(parent.getContext());
115 | View view = inflater.inflate(R.layout.item_content, parent, false);
116 |
117 | return new ViewHolder(view);
118 | }
119 |
120 | @Override
121 | public void onBindViewHolder(final ViewHolder holder, final int position) {
122 | Context c = holder.textView.getContext();
123 |
124 | holder.setDepth(mDepth);
125 | holder.setText(mName);
126 | holder.setClickListener(new View.OnClickListener() {
127 | @Override
128 | public void onClick(View v) {
129 | mListener.onNodeSelected(TreeNodeAdapter.this, getParentNode(), position);
130 | }
131 | });
132 | holder.selectableView.setSelected(mSelected);
133 | }
134 |
135 | @Override
136 | public int getItemCount() {
137 | return 1;
138 | }
139 | }
140 |
141 | }
142 |
--------------------------------------------------------------------------------
/compoundadapter-sample/src/main/java/com/negusoft/compoundadapter/data/Samples.java:
--------------------------------------------------------------------------------
1 | package com.negusoft.compoundadapter.data;
2 |
3 | import java.util.Random;
4 |
5 | /**
6 | * Some sample dummy data.
7 | */
8 | public class Samples {
9 |
10 | public static final String[] VALUES = new String[] {
11 | "ONE",
12 | "TWO",
13 | "THREE",
14 | "FOUR",
15 | "FIVE",
16 | "SIX",
17 | "SEVEN",
18 | "EIGHT",
19 | "NINE"
20 | };
21 |
22 | public static String getRandomSample() {
23 | return VALUES[new Random().nextInt(VALUES.length)];
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/compoundadapter-sample/src/main/java/com/negusoft/compoundadapter/fragment/AdapterGroupTreeFragment.java:
--------------------------------------------------------------------------------
1 | package com.negusoft.compoundadapter.fragment;
2 |
3 | import android.content.Context;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 | import android.support.v4.app.Fragment;
7 | import android.support.v7.widget.LinearLayoutManager;
8 | import android.support.v7.widget.RecyclerView;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.widget.Toast;
13 |
14 | import com.negusoft.compoundadapter.R;
15 | import com.negusoft.compoundadapter.adapter.TreeNodeAdapter;
16 | import com.negusoft.compountadapter.recyclerview.AdapterGroup;
17 | import com.negusoft.compountadapter.recyclerview.AdapterPosition;
18 |
19 | import java.util.Random;
20 |
21 | public class AdapterGroupTreeFragment extends Fragment {
22 |
23 | private static final int INITIAL_NODE_COUNT = 2;
24 | private static final int INITIAL_NODE_CHILDREN_COUNT = 3;
25 |
26 | public static AdapterGroupTreeFragment newInstance() {
27 | return new AdapterGroupTreeFragment();
28 | }
29 |
30 | private RecyclerView mRecyclerView;
31 | private AdapterGroup mAdapterGroup;
32 | private TreeNodeAdapter mTreeNodeAdapter;
33 |
34 | private TreeNodeAdapter mSelectedNode;
35 |
36 | @Nullable
37 | @Override
38 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
39 | View result = inflater.inflate(R.layout.tree_fragment, container, false);
40 |
41 | Context c = getActivity().getApplicationContext();
42 | mRecyclerView = ((RecyclerView)result.findViewById(R.id.recyclerview));
43 | mRecyclerView.setLayoutManager(new LinearLayoutManager(c));
44 | getActivity().setTitle(R.string.sample_adapter_group_tree);
45 |
46 | // Listeners
47 | result.findViewById(R.id.delete).setOnClickListener(new View.OnClickListener() {
48 | @Override
49 | public void onClick(View v) {
50 | if (mSelectedNode == null)
51 | return;
52 | mSelectedNode.delete();
53 | mSelectedNode = null;
54 | }
55 | });
56 | result.findViewById(R.id.newChild).setOnClickListener(new View.OnClickListener() {
57 | @Override
58 | public void onClick(View v) {
59 | if (mSelectedNode == null)
60 | return;
61 | mSelectedNode.addNode(getRandomNodeName());
62 | }
63 | });
64 | result.findViewById(R.id.newSibling).setOnClickListener(new View.OnClickListener() {
65 | @Override
66 | public void onClick(View v) {
67 | if (mSelectedNode == null)
68 | return;
69 | mSelectedNode.addSibling(getRandomNodeName());
70 | }
71 | });
72 |
73 | // Initialize the adapter
74 | mTreeNodeAdapter = new TreeNodeAdapter(getString(R.string.sample_list_title), mListener);
75 |
76 | for (int i=0; i
2 |
5 |
-
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/compoundadapter-sample/src/main/res/layout/item_content.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
15 |
16 |
27 |
28 |
--------------------------------------------------------------------------------
/compoundadapter-sample/src/main/res/layout/item_sample_list_title.xml:
--------------------------------------------------------------------------------
1 |
2 |
15 |
--------------------------------------------------------------------------------
/compoundadapter-sample/src/main/res/layout/main_content.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
16 |
17 |
26 |
27 |
36 |
37 |
46 |
47 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/compoundadapter-sample/src/main/res/layout/main_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
21 |
22 |
23 |
24 |
25 |
26 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/compoundadapter-sample/src/main/res/layout/recyclerview.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/compoundadapter-sample/src/main/res/layout/sample_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
21 |
22 |
23 |
24 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/compoundadapter-sample/src/main/res/layout/tree_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
19 |
20 |
27 |
28 |
35 |
36 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/compoundadapter-sample/src/main/res/menu/adaptergroup_with_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/compoundadapter-sample/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/negusoft/CompoundAdapter-android/55b4c745a38547fb0151eeef61fadc6a0dd2f523/compoundadapter-sample/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/compoundadapter-sample/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/negusoft/CompoundAdapter-android/55b4c745a38547fb0151eeef61fadc6a0dd2f523/compoundadapter-sample/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/compoundadapter-sample/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/negusoft/CompoundAdapter-android/55b4c745a38547fb0151eeef61fadc6a0dd2f523/compoundadapter-sample/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/compoundadapter-sample/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/negusoft/CompoundAdapter-android/55b4c745a38547fb0151eeef61fadc6a0dd2f523/compoundadapter-sample/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/compoundadapter-sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/negusoft/CompoundAdapter-android/55b4c745a38547fb0151eeef61fadc6a0dd2f523/compoundadapter-sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/compoundadapter-sample/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
--------------------------------------------------------------------------------
/compoundadapter-sample/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/compoundadapter-sample/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #009688
4 | #00796B
5 | #FF5722
6 |
7 |
--------------------------------------------------------------------------------
/compoundadapter-sample/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 16dp
6 |
7 |
--------------------------------------------------------------------------------
/compoundadapter-sample/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | CompoundAdapter
3 | AdapterGroup Samples
4 |
5 |
6 | Add
7 |
8 |
9 | Data with header
10 | Changing data
11 | Changing with stable IDs
12 | AdapterGroup tree
13 |
14 |
--------------------------------------------------------------------------------
/compoundadapter-sample/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/compoundadapter-sample/src/test/java/com/negusoft/compoundadapter/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.negusoft.compoundadapter;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/compoundadapter/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/compoundadapter/bintray-upload.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.github.dcendents.android-maven'
2 | apply plugin: 'com.jfrog.bintray'
3 |
4 | ext {
5 | versionName = android.defaultConfig.versionName
6 |
7 | projectName = 'CompoundAdapter-android'
8 | projectDescription = 'Android library that provides a way to define a RecyclerView.Adapter out of subadapters (AdapterGroup).'
9 |
10 | siteUrl = 'https://github.com/negusoft/CompoundAdapter-android'
11 | gitUrl = 'https://github.com/negusoft/CompoundAdapter-android.git'
12 | issuesUrl = 'https://github.com/negusoft/CompoundAdapter-android/issues'
13 | }
14 |
15 | version = versionName
16 | group = 'com.negusoft.compoundadapter'
17 |
18 | bintray {
19 | user = System.getenv('BINTRAY_USERNAME') ?: BINTRAY_USERNAME
20 | key = System.getenv('BINTRAY_API_KEY') ?: BINTRAY_API_KEY
21 |
22 | configurations = ['archives'] //When uploading configuration files
23 | pkg {
24 | repo = 'maven'
25 | userOrg = 'negusoft'
26 | name = projectName
27 | desc = projectDescription
28 | websiteUrl = siteUrl
29 | issueTrackerUrl = issuesUrl
30 | vcsUrl = gitUrl
31 | licenses = ['Apache-2.0']
32 | labels = ['android', 'RecyclerView', 'adapter', 'compound', 'AdapterGroup']
33 | publicDownloadNumbers = true
34 | version {
35 | name = versionName
36 | desc = 'v' + versionName
37 | }
38 | }
39 | }
40 |
41 | install {
42 | repositories.mavenInstaller {
43 | // This generates POM.xml with proper parameters
44 | pom {
45 | project {
46 | packaging 'aar'
47 |
48 | // Add your description here
49 | name projectName
50 | url siteUrl
51 |
52 | // Set your license
53 | licenses {
54 | license {
55 | name 'The Apache Software License, Version 2.0'
56 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
57 | }
58 | }
59 | developers {
60 | developer {
61 | id 'blurkidi'
62 | name 'Borja Lopez Urkidi'
63 | email 'blurkidi@negusoft.com'
64 | }
65 | }
66 | scm {
67 | connection gitUrl
68 | developerConnection gitUrl
69 | url siteUrl
70 | }
71 | }
72 | }
73 | }
74 | }
75 |
76 | task sourcesJar(type: Jar) {
77 | from android.sourceSets.main.java.srcDirs
78 | classifier = 'sources'
79 | }
80 |
81 | task javadoc(type: Javadoc) {
82 | source = android.sourceSets.main.java.srcDirs
83 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
84 | }
85 |
86 | task javadocJar(type: Jar, dependsOn: javadoc) {
87 | classifier = 'javadoc'
88 | from javadoc.destinationDir
89 | }
90 |
91 | artifacts {
92 | archives javadocJar
93 | archives sourcesJar
94 | }
--------------------------------------------------------------------------------
/compoundadapter/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "23.0.3"
6 |
7 | defaultConfig {
8 | minSdkVersion 9
9 | targetSdkVersion 23
10 | versionCode 1
11 | versionName "0.8.0"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | ext {
22 | supportLibraryVersion = '23.+'
23 | }
24 |
25 | dependencies {
26 | compile "com.android.support:appcompat-v7:$supportLibraryVersion"
27 | compile "com.android.support:recyclerview-v7:$supportLibraryVersion"
28 | testCompile 'junit:junit:4.12'
29 | }
30 |
31 | apply from: 'bintray-upload.gradle'
--------------------------------------------------------------------------------
/compoundadapter/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 /Users/blurkidi/dev/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 |
--------------------------------------------------------------------------------
/compoundadapter/src/androidTest/java/com/negusoft/compountadapter/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.negusoft.compountadapter;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/compoundadapter/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/compoundadapter/src/main/java/com/negusoft/compountadapter/recyclerview/AdapterGroup.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright 2016 Negusoft
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | ******************************************************************************/
16 | package com.negusoft.compountadapter.recyclerview;
17 |
18 | import android.support.annotation.Nullable;
19 | import android.support.v7.widget.RecyclerView;
20 | import android.util.SparseArray;
21 | import android.util.SparseIntArray;
22 | import android.view.ViewGroup;
23 |
24 | import java.security.InvalidParameterException;
25 | import java.util.ArrayList;
26 | import java.util.Collections;
27 | import java.util.HashMap;
28 | import java.util.List;
29 | import java.util.Map;
30 | import java.util.NavigableMap;
31 | import java.util.Set;
32 | import java.util.TreeMap;
33 | import java.util.WeakHashMap;
34 |
35 | /**
36 | * An adapter made out of adapters.
37 | */
38 | public class AdapterGroup extends RecyclerView.Adapter {
39 |
40 | /**
41 | * Can be implemented by RecyclerView.Adapters to let the AdapterGroup know about its adapter type identifier.
42 | */
43 | public interface AdapterTypeProvider {
44 | String getAdapterType();
45 | }
46 |
47 | // A list with the adapter holder and a map for quick access by adapter
48 | private final List mAdapterHolderList = new ArrayList<>(3);
49 | private final Map mAdapterHolderMap = new HashMap<>(3);
50 | private final NavigableMap mAdapterHoldersByPosition = new TreeMap<>();
51 |
52 | private final Map mAdapterTypes = new HashMap<>();
53 | private final SparseArray mAdapterTypesByViewType = new SparseArray<>();
54 |
55 | private int mTotalCount = 0;
56 | private boolean mRecyclerViewAttached = false;
57 |
58 | private ViewTypeGenerator mViewTypeGenerator = new ViewTypeGenerator(1);
59 |
60 | /**
61 | * Add the given adapter at the end.
62 | */
63 | public void addAdapter(RecyclerView.Adapter adapter) {
64 | addAdapter(mAdapterHolderList.size(), adapter, null);
65 | }
66 |
67 | /**
68 | * Add the given adapter.
69 | * @param location The index where the adapter will be inserted.
70 | */
71 | public void addAdapter(int location, RecyclerView.Adapter adapter) {
72 | addAdapter(location, adapter, null);
73 | }
74 |
75 | /**
76 | * Add the given adapter at the end.
77 | * @param adapterType Adapters of the same type reuse each others ViewHolders. By default,
78 | * adapters are grouped by class.
79 | */
80 | public void addAdapter(RecyclerView.Adapter adapter, @Nullable String adapterType) {
81 | addAdapter(mAdapterHolderList.size(), adapter, adapterType);
82 | }
83 |
84 | /**
85 | * Add the given adapter.
86 | * @param location The index where the adapter will be inserted.
87 | * @param adapterType Adapters of the same type reuse each others ViewHolders. By default,
88 | * adapters are grouped by class. If it is null and the adapter implements
89 | * AdapterTypeProvider, the getAdapterType() value is used.
90 | */
91 | public void addAdapter(int location, RecyclerView.Adapter adapter, @Nullable String adapterType) {
92 | if (adapterType == null) {
93 | adapterType = getDefaultAdapterType(adapter);
94 | }
95 |
96 | AdapterHolder holder = new AdapterHolder(adapter, adapterType);
97 | if (mAdapterHolderMap.containsKey(adapter))
98 | throw new InvalidParameterException("The adapter is already present in the CompoundAdapter");
99 |
100 | mAdapterHolderList.add(location, holder);
101 | mAdapterHolderMap.put(adapter, holder);
102 |
103 | // Set the parent reference if the adapter is a AdapterGroup
104 | if (adapter instanceof AdapterGroup) {
105 | ((AdapterGroup)adapter).mRecyclerViewAttached = mRecyclerViewAttached;
106 | }
107 |
108 | // Register the data observer if we are already attached to the RecyclerView
109 | if (mRecyclerViewAttached) {
110 | updateIndexing();
111 | holder.registerDataObserver();
112 |
113 | notifyItemRangeInserted(holder.startPosition, holder.count);
114 | }
115 | }
116 |
117 | /** Take the adapter type from AdapterTypeProvider or use the default */
118 | private String getDefaultAdapterType(RecyclerView.Adapter adapter) {
119 | if (adapter instanceof AdapterTypeProvider) {
120 | String result = ((AdapterTypeProvider)adapter).getAdapterType();
121 | if (result != null)
122 | return result;
123 | }
124 | return adapter.getClass().toString();
125 | }
126 |
127 | /**
128 | * Remove the given adapter.
129 | */
130 | public void removeAdapter(RecyclerView.Adapter adapter) {
131 | AdapterHolder removedHolder = mAdapterHolderMap.remove(adapter);
132 | if (removedHolder == null)
133 | return;
134 |
135 | mAdapterHolderList.remove(removedHolder);
136 |
137 | if (mRecyclerViewAttached) {
138 | removedHolder.unregisterDataObserver();
139 | notifyItemRangeRemoved(removedHolder.startPosition, removedHolder.count);
140 | }
141 | }
142 |
143 | /**
144 | * Returns the adapter at the given index.
145 | */
146 | public RecyclerView.Adapter getAdapter(int location) {
147 | return mAdapterHolderList.get(location).adapter;
148 | }
149 |
150 | /**
151 | * Returns a list of all the adapters that compose the AdapterGroup.
152 | */
153 | public List getAdapters() {
154 | List result = new ArrayList<>();
155 | for (AdapterHolder holder : mAdapterHolderList) {
156 | result.add(holder.adapter);
157 | }
158 | return result;
159 | }
160 |
161 | /**
162 | * @return True if the adapter is part of this adapter group. False otherwise.
163 | */
164 | public boolean containsAdapter(RecyclerView.Adapter adapter) {
165 | return mAdapterHolderMap.containsKey(adapter);
166 | }
167 |
168 | /**
169 | * @return The index of the given adapter or -1 if it was not found.
170 | */
171 | public int indexOfAdapter(RecyclerView.Adapter adapter) {
172 | AdapterHolder holder = mAdapterHolderMap.get(adapter);
173 | if (holder == null)
174 | return -1;
175 |
176 | return mAdapterHolderList.indexOf(holder);
177 | }
178 |
179 | /**
180 | * Returns the adapter at the given position along with the mapped position
181 | */
182 | public AdapterPosition getAdapterAtItemPosition(int position) {
183 | updateIndexing();
184 |
185 | AdapterHolder holder = getAdapterHolderForIndex(position);
186 | int index = holder.mapPosition(position);
187 |
188 | return new AdapterPosition(holder.adapter, index);
189 | }
190 |
191 | @Override
192 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
193 | AdaptersByType adaptersByType = mAdapterTypesByViewType.get(viewType);
194 | int innerViewType = adaptersByType.getInnerViewType(viewType);
195 | RecyclerView.Adapter adapter = adaptersByType.adapters.iterator().next();
196 |
197 | return adapter.onCreateViewHolder(parent, innerViewType);
198 | }
199 |
200 | @Override
201 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
202 | AdapterHolder adapterHolder = getAdapterHolderForIndex(position);
203 | int innerPosition = adapterHolder.mapPosition(position);
204 | adapterHolder.adapter.onBindViewHolder(holder, innerPosition);
205 | }
206 |
207 | @Override
208 | public int getItemCount() {
209 | // TODO update index only if required
210 | updateIndexing();
211 | return mTotalCount;
212 | }
213 |
214 | @Override
215 | public int getItemViewType(int position) {
216 | return getItemViewType(position, mAdapterTypes, mAdapterTypesByViewType, mViewTypeGenerator);
217 | }
218 |
219 | private int getItemViewType(int position, Map adapterTypes, SparseArray adapterTypesByViewType, ViewTypeGenerator viewTypeGenerator) {
220 | AdapterHolder adapterHolder = getAdapterHolderForIndex(position);
221 | int innerPosition = adapterHolder.mapPosition(position);
222 |
223 | // IF the adapter is AdapterGroup -> dive into the sub-adapters
224 | if (adapterHolder.adapter instanceof AdapterGroup) {
225 | return ((AdapterGroup)adapterHolder.adapter).getItemViewType(innerPosition, adapterTypes, adapterTypesByViewType, viewTypeGenerator);
226 | }
227 |
228 | // Add the view type mapping in the corresponding adapter type group
229 | int innerViewType = adapterHolder.adapter.getItemViewType(innerPosition);
230 | AdaptersByType adapterGroupsByType = adapterTypes.get(adapterHolder.adapterType);
231 | if (adapterGroupsByType == null) {
232 | adapterGroupsByType = new AdaptersByType(viewTypeGenerator);
233 | adapterTypes.put(adapterHolder.adapterType, adapterGroupsByType);
234 | }
235 | if (!adapterGroupsByType.adapters.contains(adapterHolder.adapter)) {
236 | adapterGroupsByType.adapters.add(adapterHolder.adapter);
237 | }
238 |
239 | int outerViewType = adapterGroupsByType.getOuterViewType(innerViewType);
240 | adapterTypesByViewType.put(outerViewType, adapterGroupsByType);
241 |
242 | return outerViewType;
243 | }
244 |
245 | @Override
246 | public long getItemId(int position) {
247 | AdapterHolder adapterHolder = getAdapterHolderForIndex(position);
248 | int innerPosition = adapterHolder.mapPosition(position);
249 | return adapterHolder.adapter.getItemId(innerPosition);
250 | }
251 |
252 | @Override
253 | public void onAttachedToRecyclerView(RecyclerView recyclerView) {
254 | super.onAttachedToRecyclerView(recyclerView);
255 | setRecyclerViewAttached(this, true);
256 | registerAdapterDataObserver(mAdapterDataObserver);
257 | }
258 |
259 | @Override
260 | public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
261 | super.onDetachedFromRecyclerView(recyclerView);
262 | setRecyclerViewAttached(this, false);
263 | unregisterAdapterDataObserver(mAdapterDataObserver);
264 | }
265 |
266 | /** Recursive method to set the attached flags through the AdapterGroup hierarchy. */
267 | private void setRecyclerViewAttached(AdapterGroup adapterGroup, boolean attached) {
268 | adapterGroup.mRecyclerViewAttached = attached;
269 | for (AdapterHolder holder : adapterGroup.mAdapterHolderList) {
270 | // Register/Unregister observers
271 | if (attached) {
272 | holder.registerDataObserver();
273 | } else {
274 | holder.unregisterDataObserver();
275 | }
276 |
277 | // Dive deeper if for each child AdapterGroup
278 | if (holder.adapter instanceof AdapterGroup) {
279 | setRecyclerViewAttached((AdapterGroup)holder.adapter, attached);
280 | }
281 | }
282 | }
283 |
284 | private void updateIndexing() {
285 | mAdapterHoldersByPosition.clear();
286 | int counter = 0;
287 | for (AdapterHolder holder : mAdapterHolderList) {
288 | mAdapterHoldersByPosition.put(counter, holder);
289 | counter += holder.updateIndex(counter);
290 | }
291 | mTotalCount = counter;
292 | }
293 |
294 | private RecyclerView.AdapterDataObserver mAdapterDataObserver = new RecyclerView.AdapterDataObserver() {
295 | @Override
296 | public void onChanged() {
297 | updateIndexing();
298 | }
299 |
300 | @Override
301 | public void onItemRangeChanged(int positionStart, int itemCount) {
302 | updateIndexing();
303 | }
304 |
305 | @Override
306 | public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
307 | updateIndexing();
308 | }
309 |
310 | @Override
311 | public void onItemRangeInserted(int positionStart, int itemCount) {
312 | updateIndexing();
313 | }
314 |
315 | @Override
316 | public void onItemRangeRemoved(int positionStart, int itemCount) {
317 | updateIndexing();
318 | }
319 |
320 | @Override
321 | public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
322 | updateIndexing();
323 | }
324 | };
325 |
326 | private AdapterHolder getAdapterHolderForIndex(int index) {
327 | return mAdapterHoldersByPosition.floorEntry(index).getValue();
328 | }
329 |
330 | /** Represents an inner Adapter along info related to it. */
331 | class AdapterHolder {
332 | final RecyclerView.Adapter adapter;
333 | final String adapterType;
334 |
335 | AdapterHolderDataObserver dataObserver;
336 | int startPosition = -1;
337 | int count = -1;
338 |
339 | AdapterHolder(RecyclerView.Adapter adapter, String adapterType) {
340 | this.adapter = adapter;
341 | this.adapterType = adapterType;
342 | }
343 |
344 | int updateIndex(int position) {
345 | startPosition = position;
346 | count = adapter.getItemCount();
347 | return count;
348 | }
349 |
350 | /** Map position: AdapterGroup -> child adapter */
351 | int mapPosition(int position) {
352 | return position - startPosition;
353 | }
354 |
355 | /** Map position: child adapter -> AdapterGroup */
356 | int mapPositionInverse(int position) {
357 | return position + startPosition;
358 | }
359 |
360 | void registerDataObserver() {
361 | if (dataObserver != null)
362 | return;
363 | dataObserver = new AdapterHolderDataObserver(this);
364 | adapter.registerAdapterDataObserver(dataObserver);
365 |
366 | // Register child adapters data observers
367 | if (adapter instanceof AdapterGroup) {
368 | for (AdapterHolder holder : ((AdapterGroup)adapter).mAdapterHolderList) {
369 | holder.registerDataObserver();
370 | }
371 | }
372 | }
373 |
374 | void unregisterDataObserver() {
375 | if (dataObserver == null)
376 | return;
377 | adapter.unregisterAdapterDataObserver(dataObserver);
378 | dataObserver = null;
379 |
380 | // Unregister child adapters data observers
381 | if (adapter instanceof AdapterGroup) {
382 | for (AdapterHolder holder : ((AdapterGroup)adapter).mAdapterHolderList) {
383 | holder.unregisterDataObserver();
384 | }
385 | }
386 | }
387 | }
388 |
389 | /** Maps from outer to inner view types and vice versa. */
390 | class ViewTypeMapping {
391 | private SparseIntArray in2outMapping = new SparseIntArray();
392 | private SparseIntArray out2inMapping = new SparseIntArray();
393 | }
394 |
395 | /** A set of AdapterGroups of the same type, which share the view type mapping. */
396 | class AdaptersByType {
397 | // Use weak references for the set of adapters.
398 | final Set adapters = Collections.newSetFromMap(new WeakHashMap(2));;
399 | final ViewTypeMapping viewTypeMapping = new ViewTypeMapping();
400 | final ViewTypeGenerator viewTypeGenerator;
401 |
402 | AdaptersByType(ViewTypeGenerator viewTypeGenerator) {
403 | this.viewTypeGenerator = viewTypeGenerator;
404 | }
405 |
406 | int getOuterViewType(int innerViewType) {
407 | int outerViewType = viewTypeMapping.in2outMapping.get(innerViewType, 0);
408 | if (outerViewType != 0)
409 | return outerViewType;
410 |
411 | // The view type is not mapped -> generate a outer view type
412 | outerViewType = viewTypeGenerator.getNext();
413 | viewTypeMapping.in2outMapping.put(innerViewType, outerViewType);
414 | viewTypeMapping.out2inMapping.put(outerViewType, innerViewType);
415 |
416 | return outerViewType;
417 | }
418 |
419 | int getInnerViewType(int outerViewType) {
420 | return viewTypeMapping.out2inMapping.get(outerViewType);
421 | }
422 | }
423 |
424 | /** AdapterDataObserver for each of the Adapters in order to forward changes to the parent. */
425 | class AdapterHolderDataObserver extends RecyclerView.AdapterDataObserver {
426 |
427 | final AdapterHolder holder;
428 |
429 | AdapterHolderDataObserver(AdapterHolder holder) {
430 | this.holder = holder;
431 | }
432 |
433 | @Override
434 | public void onChanged() {
435 | updateIndexing();
436 | notifyDataSetChanged();
437 | }
438 |
439 | @Override
440 | public void onItemRangeChanged(int positionStart, int itemCount) {
441 | updateIndexing();
442 | int innerPositionStart = holder.mapPositionInverse(positionStart);
443 | notifyItemRangeChanged(innerPositionStart, itemCount);
444 | }
445 |
446 | @Override
447 | public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
448 | updateIndexing();
449 | int innerPositionStart = holder.mapPositionInverse(positionStart);
450 | notifyItemRangeChanged(innerPositionStart, itemCount, payload);
451 | }
452 |
453 | @Override
454 | public void onItemRangeInserted(int positionStart, int itemCount) {
455 | updateIndexing();
456 | int innerPositionStart = holder.mapPositionInverse(positionStart);
457 | notifyItemRangeInserted(innerPositionStart, itemCount);
458 | }
459 |
460 | @Override
461 | public void onItemRangeRemoved(int positionStart, int itemCount) {
462 | updateIndexing();
463 | int innerPositionStart = holder.mapPositionInverse(positionStart);
464 | notifyItemRangeRemoved(innerPositionStart, itemCount);
465 | }
466 |
467 | @Override
468 | public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
469 | updateIndexing();
470 | int innerPositionStart = holder.mapPositionInverse(fromPosition);
471 | // There is no notifyItemRangeMoved method at the moment so send individual events
472 | for (int i=0; i
28 | extends RecyclerView.Adapter
29 | implements AdapterGroup.AdapterTypeProvider {
30 |
31 | /** Delegate interfaces, composed of the creator and binder roles. */
32 | public interface Delegate
33 | extends Creator, Binder {
34 | }
35 | public interface Creator {
36 | T createViewHolder(ViewGroup parent);
37 | }
38 | public interface Binder {
39 | void bindViewHolder(T viewHolder);
40 | }
41 |
42 | public static SingleAdapter create(final @LayoutRes View view) {
43 | return new SingleAdapter(new Creator() {
44 | @Override
45 | public ViewHolder createViewHolder(ViewGroup parent) {
46 | return new ViewHolder(view);
47 | }
48 | }, null);
49 | }
50 |
51 | public static SingleAdapter create(final @LayoutRes int layout) {
52 | return create(layout, null);
53 | }
54 |
55 | public static SingleAdapter create(final @LayoutRes int layout, final Binder binder) {
56 | return new SingleAdapter<>(new Delegate() {
57 | @Override
58 | public ViewHolder createViewHolder(ViewGroup parent) {
59 | LayoutInflater inflater = LayoutInflater.from(parent.getContext());
60 | View view = inflater.inflate(layout, parent, false);
61 | return new ViewHolder(view);
62 | }
63 | @Override
64 | public void bindViewHolder(ViewHolder viewHolder) {
65 | if (binder != null) {
66 | binder.bindViewHolder(viewHolder);
67 | }
68 | }
69 | });
70 | }
71 |
72 | // Delegate roles
73 | private final Creator mCreator;
74 | private final Binder mBinder;
75 |
76 | private long mItemId;
77 |
78 | /**
79 | * New instance with a delegate that creates and binds the ViewHolder
80 | */
81 | public SingleAdapter(Delegate delegate) {
82 | mCreator = delegate;
83 | mBinder = delegate;
84 | mItemId = RecyclerView.NO_ID;
85 | }
86 |
87 | /**
88 | * New instance with a creator and the binder to manage the ViewHolder
89 | */
90 | public SingleAdapter(Creator creator, Binder binder) {
91 | mCreator = creator;
92 | mBinder = binder;
93 | mItemId = RecyclerView.NO_ID;
94 | }
95 |
96 | /** Get the item ID used for RecyclerView.Adapter.getItemId() */
97 | public long getItemId() {
98 | return mItemId;
99 | }
100 |
101 | /** Set the item ID used for RecyclerView.Adapter.getItemId() */
102 | public void setItemId(long itemId) {
103 | mItemId = itemId;
104 | }
105 |
106 | @Override
107 | public T onCreateViewHolder(ViewGroup parent, int viewType) {
108 | return mCreator.createViewHolder(parent);
109 | }
110 |
111 | @Override
112 | public void onBindViewHolder(T holder, int position) {
113 | if (mBinder == null)
114 | return;
115 | mBinder.bindViewHolder(holder);
116 | }
117 |
118 | @Override
119 | public int getItemCount() {
120 | return 1;
121 | }
122 |
123 | @Override
124 | public long getItemId(int position) {
125 | return mItemId;
126 | }
127 |
128 | @Override
129 | public String getAdapterType() {
130 | return mCreator.getClass().toString();
131 | }
132 |
133 | static class ViewHolder extends RecyclerView.ViewHolder {
134 | public ViewHolder(View itemView) {
135 | super(itemView);
136 | }
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/compoundadapter/src/test/java/com/negusoft/compountadapter/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.negusoft.compountadapter;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/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
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/negusoft/CompoundAdapter-android/55b4c745a38547fb0151eeef61fadc6a0dd2f523/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 28 10:00:20 PST 2015
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':compoundadapter-sample', ':compoundadapter'
2 |
--------------------------------------------------------------------------------