implements CheckableViewHolder {
12 |
13 | private SparseBooleanArray mMap = new SparseBooleanArray();
14 | private RecyclerAdapter mAdapter;
15 | private boolean isLockable = false;
16 | private int mSelectedMax = -1;
17 |
18 | public CheckableAdapterDecorator(RecyclerAdapter adapter) {
19 | mAdapter = adapter;
20 | }
21 |
22 | @Override public boolean isCheckable(Object item) {
23 | return isChecked(item) || mMap.indexOfValue(true) < 0 || !isLockable && isLock();
24 | }
25 |
26 | @Override public void onBindViewHolder(RecyclerViewHolder holder, int position) {
27 | ((CheckableRecyclerViewHolder)holder).setChecked(isChecked(mAdapter.getItem(position)));
28 | ((CheckableRecyclerViewHolder)holder).setCheckable(isCheckable(mAdapter.getItem(position)));
29 | ((CheckableRecyclerViewHolder)holder).setDecorator(this);
30 | super.onBindViewHolder(holder, position);
31 | }
32 |
33 |
34 | public void setSelectedMax(int selectedMax) {
35 | mSelectedMax = selectedMax;
36 | }
37 |
38 | public void setLockable(boolean lockable) {
39 | isLockable = lockable;
40 | }
41 |
42 | @Override public boolean isChecked(Object item) {
43 | return mMap.get(getHashCode(item));
44 | }
45 |
46 | @Override public void selectedItem(Object item) {
47 | if (mSelectedMax == 1) {
48 | mMap.clear();
49 | }
50 | put(getHashCode(item), true);
51 | }
52 |
53 | @Override public void unselectedItem(Object item) {
54 | put(getHashCode(item), false);
55 | }
56 |
57 | @SuppressWarnings("unchecked")
58 | private int getHashCode(Object o) {
59 | if (mAdapter.indexOf(o) > -1) {
60 | return mAdapter.getItem(mAdapter.indexOf(o)).hashCode();
61 | }
62 | return -1;
63 | }
64 |
65 | private boolean isLock() {
66 | int count = 0;
67 | for (int i = 0; i < mMap.size(); i++) {
68 | if (mMap.valueAt(i)){
69 | count++;
70 | }
71 | }
72 | return mSelectedMax <= 1 || (mSelectedMax > 0 && mSelectedMax < count);
73 | }
74 |
75 | private void put(int hashCode, boolean value) {
76 | if (hashCode > 0) {
77 | mMap.put(hashCode, value);
78 | }
79 | }
80 | }
--------------------------------------------------------------------------------
/adapter/src/main/java/com/android/jmaxime/adapters/EasyPagerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.android.jmaxime.adapters;
2 |
3 | import android.support.annotation.NonNull;
4 | import android.support.v4.view.PagerAdapter;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 |
8 | import com.android.jmaxime.factory.ViewHolderFactory;
9 | import com.android.jmaxime.interfaces.IBaseCommunication;
10 | import com.android.jmaxime.interfaces.InitViewHolderDecorator;
11 | import com.android.jmaxime.interfaces.ShowPictureDecorator;
12 | import com.android.jmaxime.viewholder.RecyclerViewHolder;
13 |
14 | import java.util.ArrayList;
15 | import java.util.List;
16 |
17 | /**
18 | * @author Maxime Jallu
19 | * @since 26/09/2017
20 | *
21 | * Use this Class for :
22 | * {DOCUMENTATION}
23 | */
24 | public class EasyPagerAdapter extends PagerAdapter {
25 |
26 | private final List mItems;
27 | private final ViewHolderFactory mFactory;
28 |
29 | public EasyPagerAdapter(Class extends RecyclerViewHolder> viewHolder) {
30 | this(new ArrayList<>(), viewHolder);
31 | }
32 |
33 | public EasyPagerAdapter(List items, Class extends RecyclerViewHolder> viewHolder) {
34 | this(items, viewHolder, null);
35 | }
36 |
37 | public EasyPagerAdapter(List items, Class extends RecyclerViewHolder> viewHolder, IBaseCommunication callback) {
38 | mItems = items;
39 | mFactory = new ViewHolderFactory.Builder<>(viewHolder).append(callback).build();
40 | }
41 |
42 | @Override public Object instantiateItem(@NonNull ViewGroup container, int position) {
43 | RecyclerViewHolder vh = mFactory.createViewHolder(container);
44 | vh.bind(mItems.get(position));
45 | container.addView(vh.itemView);
46 | return vh.itemView;
47 | }
48 |
49 | @Override
50 | public int getItemPosition(Object object){
51 | /*for force notifyDataSetChange*/
52 | return PagerAdapter.POSITION_NONE;
53 | }
54 |
55 | @Override
56 | public boolean isViewFromObject(View view, Object object) {
57 | return view == object;
58 | }
59 |
60 | @Override public int getCount() {
61 | return mItems.size();
62 | }
63 |
64 | public void attachInitHolderDecorator(InitViewHolderDecorator holderDecorator) {
65 | mFactory.setHolderDecorator(holderDecorator);
66 | }
67 |
68 | public void attachShowPictureDecorator(ShowPictureDecorator pictureDecorator) {
69 | mFactory.setPictureDecorator(pictureDecorator);
70 | }
71 |
72 | @Override
73 | public void destroyItem(ViewGroup container, int position, Object object) {
74 | container.removeView((View) object);
75 | }
76 |
77 | public void addAll(List medias) {
78 | mItems.addAll(medias);
79 | notifyDataSetChanged();
80 | }
81 |
82 | public void addAll(int index, List medias) {
83 | mItems.addAll(index, medias);
84 | notifyDataSetChanged();
85 | }
86 | }
--------------------------------------------------------------------------------
/code_quality_tools/checkstyle.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/adapter/src/main/java/com/android/jmaxime/utils/RecyclerItemClickListener.java:
--------------------------------------------------------------------------------
1 | package com.android.jmaxime.utils;
2 |
3 |
4 | import android.support.v7.widget.RecyclerView;
5 | import android.support.v7.widget.RecyclerView.OnChildAttachStateChangeListener;
6 | import android.view.View;
7 | import android.view.View.OnClickListener;
8 |
9 | public class RecyclerItemClickListener implements OnChildAttachStateChangeListener {
10 | private final RecyclerView mRecycler;
11 | private final OnClickItemListener mClickListener;
12 | private final OnLongClickItemListener mLongClickListener;
13 |
14 | public RecyclerItemClickListener(RecyclerView recycler, OnClickItemListener clickListener, OnLongClickItemListener longClickListener) {
15 | mRecycler = recycler;
16 | mClickListener = clickListener;
17 | mLongClickListener = longClickListener;
18 | }
19 |
20 | public static void affectOnClick(RecyclerView recyclerView, OnClickItemListener listener, OnLongClickItemListener longClickListener) {
21 | recyclerView.addOnChildAttachStateChangeListener(new RecyclerItemClickListener(recyclerView, listener, longClickListener));
22 | }
23 |
24 | public static void affectOnClick(RecyclerView recyclerView, OnClickItemListener listener) {
25 | recyclerView.addOnChildAttachStateChangeListener(new RecyclerItemClickListener(recyclerView, listener, null));
26 | }
27 |
28 | public static void affectOnLongClick(RecyclerView recyclerView, OnLongClickItemListener listener) {
29 | recyclerView.addOnChildAttachStateChangeListener(new RecyclerItemClickListener(recyclerView, null, listener));
30 | }
31 |
32 | public void onChildViewAttachedToWindow(View view) {
33 | if (mClickListener != null) {
34 | view.setOnClickListener(new OnClickListener() {
35 | public void onClick(View v) {
36 | RecyclerItemClickListener.this.setOnChildAttachedToWindow(v);
37 | }
38 | });
39 | }
40 |
41 | if (mLongClickListener != null) {
42 | view.setOnLongClickListener(new View.OnLongClickListener() {
43 | @Override
44 | public boolean onLongClick(View view) {
45 | return setOnLongClickChildAttachedToWindow(view);
46 | }
47 | });
48 | }
49 | }
50 |
51 | private void setOnChildAttachedToWindow(View v) {
52 | if (v != null && this.mClickListener != null) {
53 | int position = this.mRecycler.getChildLayoutPosition(v);
54 | if (position >= 0) {
55 | this.mClickListener.onItemClick(position, v);
56 | }
57 | }
58 | }
59 |
60 | private boolean setOnLongClickChildAttachedToWindow(View v) {
61 | if (v != null && this.mLongClickListener != null) {
62 | int position = this.mRecycler.getChildLayoutPosition(v);
63 | if (position >= 0) {
64 | return this.mLongClickListener.onItemLongClick(position, v);
65 | }
66 | }
67 | return false;
68 | }
69 |
70 | public void onChildViewDetachedFromWindow(View view) {
71 | if (view != null) {
72 | view.setOnClickListener(null);
73 | }
74 | }
75 |
76 | public interface OnClickItemListener {
77 | void onItemClick(int position, View view);
78 | }
79 |
80 | /**
81 | * @see Documentation Android
82 | */
83 | public interface OnLongClickItemListener {
84 | /**
85 | * Called when a view has been clicked and held.
86 | *
87 | * @param position position view in adapter
88 | * @param view viewHolder that was clicked and held.
89 | * @return true if the callback consumed the long click, false otherwise.
90 | */
91 | boolean onItemLongClick(int position, View view);
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/adapter/maven.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Chris Banes
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 |
17 | apply plugin: 'maven'
18 | apply plugin: 'signing'
19 |
20 | def MAVEN_GROUP = hasProperty('GROUP') ? GROUP : ""
21 | def MAVEN_POM_ARTIFACT_ID = hasProperty('POM_ARTIFACT_ID') ? POM_ARTIFACT_ID : ""
22 | def MAVEN_POM_NAME = hasProperty('POM_NAME') ? POM_NAME : ""
23 | def MAVEN_POM_PACKAGING = hasProperty('POM_PACKAGING') ? POM_PACKAGING : ""
24 | def MAVEN_POM_DESCRIPTION = hasProperty('POM_DESCRIPTION') ? POM_DESCRIPTION : ""
25 | def MAVEN_POM_URL = hasProperty('POM_URL') ? POM_URL : ""
26 | def MAVEN_POM_SCM_URL = hasProperty('POM_SCM_URL') ? POM_SCM_URL : ""
27 | def MAVEN_POM_SCM_CONNECTION = hasProperty('POM_SCM_CONNECTION') ? POM_SCM_CONNECTION : ""
28 | def MAVEN_POM_SCM_DEV_CONNECTION = hasProperty('POM_SCM_DEV_CONNECTION') ? POM_SCM_DEV_CONNECTION : ""
29 | def MAVEN_POM_LICENCE_NAME = hasProperty('POM_LICENCE_NAME') ? POM_LICENCE_NAME : ""
30 | def MAVEN_POM_LICENCE_URL = hasProperty('POM_LICENCE_URL') ? POM_LICENCE_URL : ""
31 | def MAVEN_POM_LICENCE_DIST = hasProperty('POM_LICENCE_DIST') ? POM_LICENCE_DIST : ""
32 | def MAVEN_POM_DEVELOPER_ID = hasProperty('POM_DEVELOPER_ID') ? POM_DEVELOPER_ID : ""
33 | def MAVEN_POM_DEVELOPER_NAME = hasProperty('POM_DEVELOPER_NAME') ? POM_DEVELOPER_NAME : ""
34 |
35 | def isReleaseBuild() {
36 | return rootProject.ext.versionName.contains("SNAPSHOT") == false
37 | }
38 |
39 | def getReleaseRepositoryUrl() {
40 | return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL
41 | : "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
42 | }
43 |
44 | def getSnapshotRepositoryUrl() {
45 | return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL
46 | : "https://oss.sonatype.org/content/repositories/snapshots/"
47 | }
48 |
49 | def getRepositoryUsername() {
50 | return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : ""
51 | }
52 |
53 | def getRepositoryPassword() {
54 | return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : ""
55 | }
56 |
57 | afterEvaluate { project ->
58 | uploadArchives {
59 | repositories {
60 | mavenDeployer {
61 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
62 |
63 | pom.groupId = MAVEN_GROUP
64 | pom.artifactId = MAVEN_POM_ARTIFACT_ID
65 | pom.version = rootProject.ext.versionName
66 |
67 | repository(url: getReleaseRepositoryUrl()) {
68 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
69 | }
70 | snapshotRepository(url: getSnapshotRepositoryUrl()) {
71 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
72 | }
73 |
74 | pom.project {
75 | name MAVEN_POM_NAME
76 | packaging MAVEN_POM_PACKAGING
77 | description MAVEN_POM_DESCRIPTION
78 | url MAVEN_POM_URL
79 |
80 | scm {
81 | url MAVEN_POM_SCM_URL
82 | connection MAVEN_POM_SCM_CONNECTION
83 | developerConnection MAVEN_POM_SCM_DEV_CONNECTION
84 | }
85 |
86 | licenses {
87 | license {
88 | name MAVEN_POM_LICENCE_NAME
89 | url MAVEN_POM_LICENCE_URL
90 | distribution MAVEN_POM_LICENCE_DIST
91 | }
92 | }
93 |
94 | developers {
95 | developer {
96 | id MAVEN_POM_DEVELOPER_ID
97 | name MAVEN_POM_DEVELOPER_NAME
98 | }
99 | }
100 | }
101 | }
102 | }
103 | }
104 | signing {
105 | required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") }
106 | sign configurations.archives
107 | }
108 |
109 | //task androidJavadocs(type: Javadoc) {
110 | //source = android.sourceSets.main.allJava
111 | //}
112 |
113 | //task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
114 | //classifier = 'javadoc'
115 | //from androidJavadocs.destinationDir
116 | //}
117 |
118 | task androidSourcesJar(type: Jar) {
119 | classifier = 'sources'
120 | from android.sourceSets.main.java.sourceFiles
121 | }
122 |
123 | artifacts {
124 | archives androidSourcesJar
125 | }
126 | }
--------------------------------------------------------------------------------
/adapter/src/main/java/com/android/jmaxime/viewholder/RecyclerViewHolder.java:
--------------------------------------------------------------------------------
1 | package com.android.jmaxime.viewholder;
2 |
3 |
4 | import android.content.Context;
5 | import android.graphics.drawable.Drawable;
6 | import android.support.annotation.ColorRes;
7 | import android.support.annotation.DrawableRes;
8 | import android.support.annotation.NonNull;
9 | import android.support.annotation.PluralsRes;
10 | import android.support.annotation.StringRes;
11 | import android.support.annotation.UiThread;
12 | import android.support.v4.content.ContextCompat;
13 | import android.support.v4.graphics.drawable.DrawableCompat;
14 | import android.support.v7.widget.RecyclerView;
15 | import android.util.Log;
16 | import android.view.View;
17 | import android.widget.ImageView;
18 |
19 | import com.android.jmaxime.interfaces.IBaseCommunication;
20 | import com.android.jmaxime.interfaces.InitViewHolderDecorator;
21 | import com.android.jmaxime.interfaces.ShowPictureDecorator;
22 |
23 | /**
24 | * @author Maxime Jallu
25 | * @link ArrayRecyclerAdapter
26 | *
27 | * Tools this class:
28 | *
29 | * getContext()
30 | * getColor(@ColorRes res)
31 | * getDrawable(@DrawableRes res)
32 | * @since 30/06/2016
33 | *
34 | * Create for CubeInStore - Android (Decathlon)
35 | *
36 | * Use this Class for :
37 | * make it easier ViewHolder adapter recyclerView, define T type of item
38 | * Must to use in ArrayRecyclerAdapter
39 | */
40 | public abstract class RecyclerViewHolder extends RecyclerView.ViewHolder {
41 |
42 | private T mItem;
43 | private boolean isBound;
44 | private InitViewHolderDecorator mDecorator;
45 | private ShowPictureDecorator mPictureDecorator;
46 | private IBaseCommunication mCommunication;
47 |
48 | public RecyclerViewHolder(@NonNull View itemView) {
49 | super(itemView);
50 | }
51 |
52 | public void initBinding() {
53 | if (mDecorator != null) {
54 | mDecorator.initBinding(this, itemView);
55 | }
56 | }
57 |
58 | public final void bindingSmart(final T item){
59 | /*change state : binding in progress*/
60 | setBound(false);
61 | /*set viewModel*/
62 | setItem(item);
63 | /*update view*/
64 | if (this instanceof EmptyRecyclerViewHolder) {
65 | ((EmptyRecyclerViewHolder) this).bind();
66 | } else {
67 | bind(item);
68 | }
69 | /*change state : binding finish*/
70 | setBound(true);
71 | }
72 |
73 | @UiThread
74 | public abstract void bind(final T item);
75 |
76 | protected final Context getContext() {
77 | return itemView.getContext();
78 | }
79 |
80 | protected final String getString(@StringRes int stringRes) {
81 | return getContext().getString(stringRes);
82 | }
83 |
84 | protected final String getString(@StringRes int stringRes, String string) {
85 | return getContext().getResources().getString(stringRes, string);
86 | }
87 |
88 | protected final String getQuantityString(@PluralsRes int pluralRes, int quantity) {
89 | return getContext().getResources().getQuantityString(pluralRes, quantity, quantity);
90 | }
91 |
92 | protected final String getQuantityStringFormat(@PluralsRes int pluralRes, int quantity) {
93 | return getContext().getResources().getQuantityString(pluralRes, quantity, quantity);
94 | }
95 |
96 | protected final int getColor(@ColorRes int colorResId) {
97 | return ContextCompat.getColor(getContext(), colorResId);
98 | }
99 |
100 | protected final Drawable getDrawable(@DrawableRes int drawableResId) {
101 | return ContextCompat.getDrawable(getContext(), drawableResId);
102 | }
103 |
104 | protected final Drawable getDrawable(@DrawableRes int drawableId, @ColorRes int colorId){
105 | Drawable drawable = getDrawable(drawableId);
106 | DrawableCompat.setTint(drawable.mutate(), getColor(colorId));
107 | return drawable;
108 | }
109 |
110 | @UiThread
111 | protected final void showPicture(ImageView picture, String url) {
112 | if (mPictureDecorator != null) {
113 | mPictureDecorator.showPicture(picture, url);
114 | }
115 | }
116 |
117 | protected final boolean isBound() {
118 | return isBound;
119 | }
120 |
121 | private void setBound(boolean bound) {
122 | isBound = bound;
123 | }
124 |
125 | public final void setInitViewDecorator(InitViewHolderDecorator decorator) {
126 | mDecorator = decorator;
127 | }
128 |
129 | public final void setPictureDecorator(ShowPictureDecorator pictureDecorator) {
130 | mPictureDecorator = pictureDecorator;
131 | }
132 |
133 | public final T getItem() {
134 | return mItem;
135 | }
136 |
137 | public final void setItem(T item) {
138 | mItem = item;
139 | }
140 |
141 | protected final I getDispatcher() {
142 | I i = null;
143 | try {
144 | //noinspection unchecked
145 | i = (I) mCommunication;
146 | } catch (ClassCastException e) {
147 | Log.e("ViewHolderFactory", "getInterfaceCallback: ", e);
148 | }
149 | return i;
150 | }
151 |
152 | public final void setCommunication(IBaseCommunication interfaceCallback) {
153 | mCommunication = interfaceCallback;
154 | }
155 | }
156 |
157 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Status
2 |
3 |  [](https://android-arsenal.com/api?level=16)
4 |
5 |
6 | [](https://maven-badges.herokuapp.com/maven-central/com.github.maximejallu/adapters)
7 |
8 | [](https://android-arsenal.com/details/1/6400)
9 |
10 | # Generic-Adapter:
11 |
12 | This tool allows you to no longer worry about adapters. Now you will only create your ViewHolder.
13 | Communication management between your Views and your ViewHolders is possible.
14 | Creating sections is now very easily.
15 | Enjoy.
16 |
17 | # Download [](https://maven-badges.herokuapp.com/maven-central/com.github.maximejallu/adapters)
18 | buildtool used is 27
19 | use {exclude group: 'com.android.support'} only if you have problems
20 | ```groovy
21 | dependencies {
22 | ...
23 | implementation ('com.github.maximejallu:adapters:{version}')
24 | ...
25 | }
26 | ```
27 |
28 | # Decorators for : [ButterKnife][1] - [Picasso][2] - [Glide][3] ...
29 | ```java
30 | public class SampleApplication extends Application {
31 |
32 | @Override
33 | public void onCreate() {
34 | super.onCreate();
35 |
36 | RecyclerAdapter.Helper()
37 | .append(new InitViewHolderDecorator() {
38 | @Override
39 | public void initBinding(Object target, View view) {
40 | ButterKnife.bind(target, view);
41 | }
42 | })
43 | .append(new ShowPictureDecorator() {
44 | @Override
45 | public void showPicture(ImageView picture, String url) {
46 | //use Picasso, Glide... Other
47 | }
48 | })
49 | .init();
50 | }
51 | }
52 | ```
53 |
54 | # RecyclerAdapter (Easy sample method)
55 | CustomerViewHolder.class :
56 | ```java
57 | @BindLayoutRes(R.layout.{name_of_your_layout})
58 | public class CustomerViewHolder extends RecyclerViewHolder {
59 | TextView mText;
60 | CustomerViewHolder(View view){
61 | super(view);
62 | mText = view.findViewById(R.id.text1);
63 | }
64 |
65 | void onBind(Customer item){
66 | //todo implements
67 | }
68 | }
69 | ```
70 |
71 | MainFragment.class
72 | ```java
73 | public class MainFragment extends Fragment {
74 | ...
75 | private RecyclerAdapter mAdapter;
76 |
77 | void onCreate(...){
78 | mAdapter = new RecyclerAdapter(customerList, CustomerViewHolder.class);
79 | }
80 | ...
81 | }
82 | ```
83 | # RecyclerAdapter (Multi cell method)
84 | - create your necessary ViewHolder (here only one example)
85 | ```java
86 | @BindLayoutRes(R.layout.{name_of_your_layout1})
87 | public class CustomerViewHolder1 extends RecyclerViewHolder {
88 | CustomerViewHolder1(View view){
89 | super(view);
90 | }
91 |
92 | void onBind(Customer item){
93 | //todo implements
94 | }
95 | }
96 |
97 | //# Solution 1 : the object determines are own item view type
98 | public class Customer implements IViewType {
99 | public static final int TYPE_ON_LINE = 0; /*default*/
100 | public static final int TYPE_STORE = 1;
101 | public static final int TYPE_OTHER = 2;
102 | private int mType;
103 |
104 | @Override
105 | public int getItemViewType() {
106 | return mType;
107 | }
108 | }
109 |
110 | public class MyFragment extends Fragment {
111 |
112 | public void onCreateView(){
113 | private RecyclerAdapter mAdapter;
114 |
115 | mAdapter = new RecyclerAdapter(customerList, CustomerViewHolder1.class/*type par default*/);
116 | mAdapter.putViewType(Customer.TYPE_STORE, CustomerViewHolder2.class, null /*callback*/);
117 | mAdapter.putViewType(Customer.TYPE_OTHER, CustomerViewHolder3.class, true /*add default callback*/);
118 |
119 | //# Solution 2 : We give the strategy of the IViewType to our adapt it
120 | mAdapter.setItemViewType(item -> {
121 | //todo stategy type of item
122 | return 0;
123 | });
124 | mRecyclerView.setAdapter(adapter);
125 | }
126 |
127 | }
128 | ```
129 | # SectionDecorator (Recycler with LinearLayout or GridLayout)
130 | precondition : create your RecyclerViewHolder
131 | Sample :
132 | ```java
133 | mRecylerView.setLayoutManager(...);
134 | /*create Adapter*/
135 | RecyclerAdapter baseAdapter = new RecyclerAdapter<>(...);
136 | /*create sectioned adapter. the Adapter type can be RecyclerView.Adapter*/
137 | SectionedAdapter adapter = new SectionedAdapter<>(SectionViewHolder.class, baseAdapter);
138 | /*add your sections*/
139 | sectionAdapter.addSection(0/*position*/, "Title Section 1");
140 | /*attach Adapter to RecyclerView*/
141 | mRecylerView.setAdapter(sectionAdapter);
142 | ```
143 |
144 | # ItemDecoration
145 | ```java
146 | mRecyclerView.addItemDecoration(new FooterDecoration(getContext(), this, R.layout.item_space_80));
147 | ```
148 |
149 | [1]: https://github.com/JakeWharton/butterknife
150 | [2]: https://github.com/square/picasso
151 | [3]: https://github.com/bumptech/glide
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/android/jmaxime/sample/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.android.jmaxime.sample;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.NonNull;
5 | import android.support.design.widget.BottomNavigationView;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.support.v7.widget.LinearLayoutManager;
8 | import android.support.v7.widget.RecyclerView;
9 | import android.view.MenuItem;
10 |
11 | import com.android.jmaxime.adapters.RecyclerAdapter;
12 | import com.android.jmaxime.adapters.decorators.SectionedAdapter;
13 | import com.android.jmaxime.sample.models.A;
14 | import com.android.jmaxime.sample.models.B;
15 | import com.android.jmaxime.sample.models.Customer;
16 | import com.android.jmaxime.sample.viewholders.A_Bis_ViewHolder;
17 | import com.android.jmaxime.sample.viewholders.A_ViewHolder;
18 | import com.android.jmaxime.sample.viewholders.B_ViewHolder;
19 | import com.android.jmaxime.sample.viewholders.EmptyViewHolder;
20 | import com.android.jmaxime.sample.viewholders.customers.Customer2ViewHolder;
21 | import com.android.jmaxime.sample.viewholders.customers.CustomerViewHolder;
22 | import com.android.jmaxime.viewholder.Container;
23 |
24 | import java.util.ArrayList;
25 | import java.util.List;
26 |
27 | public class MainActivity extends AppCompatActivity {
28 |
29 | private RecyclerView mRecycler;
30 |
31 | private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
32 | = new BottomNavigationView.OnNavigationItemSelectedListener() {
33 |
34 | @Override
35 | public boolean onNavigationItemSelected(@NonNull MenuItem item) {
36 | switch (item.getItemId()) {
37 | case R.id.navigation_home:
38 | setMultiAdapter();
39 | return true;
40 | case R.id.navigation_dashboard:
41 | setSimpleMultiAdapter();
42 | return true;
43 | case R.id.navigation_notifications:
44 | setSectionAdapter();
45 | return true;
46 | }
47 | return false;
48 | }
49 | };
50 |
51 | @Override
52 | protected void onCreate(Bundle savedInstanceState) {
53 | super.onCreate(savedInstanceState);
54 | setContentView(R.layout.activity_main);
55 |
56 | mRecycler = findViewById(R.id.recycler);
57 | mRecycler.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
58 |
59 | BottomNavigationView navigation = findViewById(R.id.navigation);
60 | navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
61 |
62 |
63 | List customers = new ArrayList<>();
64 | customers.add(new Customer("Alice"));
65 | customers.add(new Customer("Béatrice"));
66 | customers.add(new Customer("Mathilde"));
67 |
68 | RecyclerAdapter adapter = new RecyclerAdapter<>(customers, CustomerViewHolder.class);
69 | adapter.putViewType(1, Customer2ViewHolder.class, false);
70 | adapter.setViewTypeStrategy(item -> {
71 | if (item.getName().startsWith("A")){
72 | return 1;
73 | }
74 | return 0;
75 | });
76 | mRecycler.setAdapter(adapter);
77 | }
78 |
79 | private void setMultiAdapter() {
80 | List containers = new ArrayList<>();
81 | containers.add(new Container(new A("Je suis ONE")));
82 | containers.add(new Container());
83 | containers.add(new Container(new A("Je suis ONE+")));
84 | containers.add(new Container(new B("je suis TWO")));
85 | containers.add(new Container(new A("Je suis ONE++")));
86 | containers.add(new Container(new B("je suis TWO+")));
87 | containers.add(new Container(new B("je suis TWO++")));
88 | containers.add(new Container(new A("Je suis ONE3+")));
89 | containers.add(new Container(new A("Je suis ONE4+")));
90 | containers.add(new Container(new B("je suis TWO3+")));
91 | containers.add(new Container(new B("je suis TWO4+")));
92 | containers.add(new Container());
93 | containers.add(new Container());
94 | containers.add(new Container(new B("je suis TWO5+")));
95 | containers.add(new Container());
96 |
97 | RecyclerAdapter multiTypeAdapter = new RecyclerAdapter<>(containers, A_ViewHolder.class);
98 | multiTypeAdapter.putViewType(2, B_ViewHolder.class, true);
99 | multiTypeAdapter.putViewType(3, EmptyViewHolder.class, true);
100 | multiTypeAdapter.setViewTypeStrategy(item -> {
101 | if (item.getValue() == null) {
102 | return 3;
103 | }
104 | return (item.getValue() instanceof A) ? 1 : 2;
105 | });
106 | mRecycler.setAdapter(multiTypeAdapter);
107 | }
108 |
109 | private void setSimpleMultiAdapter() {
110 | List list = new ArrayList<>();
111 | list.add(new A("Alibaba"));
112 | list.add(new A("Allouette "));
113 |
114 | RecyclerAdapter adapter = new RecyclerAdapter<>(list, A_ViewHolder.class);
115 | adapter.putViewType(1, A_Bis_ViewHolder.class, true);
116 | adapter.setViewTypeStrategy(item -> {
117 | if (item.getName().length() > 7) {
118 | return 1;
119 | }
120 | return 0;
121 | });
122 | mRecycler.setAdapter(adapter);
123 | }
124 |
125 |
126 | private void setSectionAdapter(){
127 | mRecycler.getAdapter().notifyDataSetChanged();
128 | List list = new ArrayList<>();
129 | list.add(new A("Alibaba"));
130 | list.add(new A("Allouette "));
131 |
132 | RecyclerAdapter adapter = new RecyclerAdapter<>(list, A_ViewHolder.class);
133 | SectionedAdapter sectionedAdapter = new SectionedAdapter<>(A_Bis_ViewHolder.class, adapter);
134 | sectionedAdapter.addSection(0, new A("SECTION ONE"));
135 | sectionedAdapter.addSection(1, new A("SECTION TWO"));
136 | // mRecycler.setAdapter(sectionedAdapter);
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/sample/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
11 |
16 |
21 |
26 |
31 |
36 |
41 |
46 |
51 |
56 |
61 |
66 |
71 |
76 |
81 |
86 |
91 |
96 |
101 |
106 |
111 |
116 |
121 |
126 |
131 |
136 |
141 |
146 |
151 |
156 |
161 |
166 |
171 |
172 |
--------------------------------------------------------------------------------
/adapter/src/main/java/com/android/jmaxime/factory/ViewHolderFactory.java:
--------------------------------------------------------------------------------
1 | package com.android.jmaxime.factory;
2 |
3 | import android.support.annotation.LayoutRes;
4 | import android.support.annotation.NonNull;
5 | import android.support.annotation.Nullable;
6 | import android.util.Log;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 |
11 | import com.android.jmaxime.annotations.BindLayoutRes;
12 | import com.android.jmaxime.interfaces.IBaseCommunication;
13 | import com.android.jmaxime.interfaces.InitViewHolderDecorator;
14 | import com.android.jmaxime.interfaces.ShowPictureDecorator;
15 | import com.android.jmaxime.viewholder.RecyclerViewHolder;
16 |
17 | import java.lang.reflect.InvocationTargetException;
18 |
19 | public class ViewHolderFactory {
20 |
21 | private static final String TAG = ViewHolderFactory.class.getName();
22 |
23 | private Class extends RecyclerViewHolder> mViewHolderType;
24 | private @LayoutRes int mLayoutResId;
25 | private IBaseCommunication mCallback;
26 | private InitViewHolderDecorator mHolderDecorator;
27 | private ShowPictureDecorator mPictureDecorator;
28 |
29 | ViewHolderFactory(Class extends RecyclerViewHolder> viewHolderType,
30 | @Nullable IBaseCommunication callback,
31 | @Nullable InitViewHolderDecorator holderDecorator,
32 | @Nullable ShowPictureDecorator pictureDecorator) {
33 | update(viewHolderType, callback);
34 | mHolderDecorator = holderDecorator;
35 | mPictureDecorator = pictureDecorator;
36 | }
37 |
38 | public final RecyclerViewHolder createViewHolder(@NonNull ViewGroup view) {
39 | RecyclerViewHolder viewHolder = getInstance(LayoutInflater.from(view.getContext())
40 | .inflate(mLayoutResId, view, false));
41 | if (viewHolder != null) {
42 | viewHolder.setCommunication(mCallback);
43 | viewHolder.setInitViewDecorator(mHolderDecorator);
44 | viewHolder.setPictureDecorator(mPictureDecorator);
45 | }
46 | return viewHolder;
47 | }
48 |
49 | @SuppressWarnings("TryWithIdenticalCatches")
50 | private RecyclerViewHolder getInstance(@NonNull View view) {
51 | RecyclerViewHolder viewHolder = null;
52 | try {
53 | /*HACK : prévention...*/
54 | mViewHolderType.getConstructor(View.class).setAccessible(true);
55 | viewHolder = mViewHolderType.getConstructor(View.class).newInstance(view);
56 | } catch (InstantiationException e) {
57 | Log.i(TAG, "getInstance: ");
58 | } catch (IllegalAccessException e) {
59 | Log.i(TAG, "getInstance: ", e);
60 | } catch (InvocationTargetException e) {
61 | Log.i(TAG, "getInstance: ", e);
62 | } catch (NoSuchMethodException e) {
63 | Log.i(TAG, "not found constructor. La class suivante doit être en static ou ne pas être en inner class : " +
64 | mViewHolderType.getName(), e);
65 | }
66 | return viewHolder;
67 | }
68 |
69 | @Nullable
70 | protected I getInterfaceCallback() {
71 | I communication = null;
72 | try {
73 | //noinspection unchecked
74 | communication = (I) mCallback;
75 | } catch (ClassCastException e) {
76 | Log.e(TAG, "getInterfaceCallback: ", e);
77 | }
78 | return communication;
79 | }
80 |
81 | @Nullable
82 | public InitViewHolderDecorator getHolderDecorator() {
83 | return mHolderDecorator;
84 | }
85 |
86 | public void setHolderDecorator(InitViewHolderDecorator holderDecorator) {
87 | mHolderDecorator = holderDecorator;
88 | }
89 |
90 | @Nullable
91 | public ShowPictureDecorator getPictureDecorator() {
92 | return mPictureDecorator;
93 | }
94 |
95 | public void setPictureDecorator(ShowPictureDecorator pictureDecorator) {
96 | mPictureDecorator = pictureDecorator;
97 | }
98 |
99 | public IBaseCommunication getCommunication() {
100 | return mCallback;
101 | }
102 |
103 | public void setCallback(IBaseCommunication callback) {
104 | mCallback = callback;
105 | }
106 |
107 | void update(Class extends RecyclerViewHolder> viewHolderType, IBaseCommunication callback) {
108 | mViewHolderType = viewHolderType;
109 | /*optimisation reflexion*/
110 | mLayoutResId = getLayoutResId(viewHolderType);
111 | mCallback = callback;
112 | }
113 |
114 | private int getLayoutResId(Class extends RecyclerViewHolder> aClass) {
115 | checkViewType(aClass);
116 | return aClass.getAnnotation(BindLayoutRes.class).value();
117 | }
118 |
119 | private void checkViewType(Class extends RecyclerViewHolder> viewHolder) {
120 | if (!viewHolder.isAnnotationPresent(BindLayoutRes.class)) {
121 | throw new IllegalArgumentException(viewHolder.getSimpleName()
122 | + "is not annoted by " + BindLayoutRes.class.getSimpleName());
123 | }
124 | }
125 |
126 | public static class Builder {
127 | private Class extends RecyclerViewHolder> mViewHolderType;
128 | private IBaseCommunication mCallback;
129 | private InitViewHolderDecorator mHolderDecorator;
130 | private ShowPictureDecorator mPictureDecorator;
131 |
132 | public Builder(@NonNull Class extends RecyclerViewHolder> viewHolderType) {
133 | mViewHolderType = viewHolderType;
134 | }
135 |
136 | public Builder append(IBaseCommunication communication) {
137 | this.mCallback = communication;
138 | return this;
139 | }
140 |
141 | public Builder append(InitViewHolderDecorator holderDecorator) {
142 | this.mHolderDecorator = holderDecorator;
143 | return this;
144 | }
145 |
146 | public Builder append(ShowPictureDecorator pictureDecorator) {
147 | this.mPictureDecorator = pictureDecorator;
148 | return this;
149 | }
150 |
151 | public ViewHolderFactory build() {
152 | return new ViewHolderFactory<>(mViewHolderType, mCallback, mHolderDecorator, mPictureDecorator);
153 | }
154 |
155 | public RecyclerViewHolder createView(ViewGroup parent){
156 | return build().createViewHolder(parent);
157 | }
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/gradle/gradle-mvn-push.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Chris Banes
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 |
17 | apply plugin: 'maven'
18 | apply plugin: 'signing'
19 |
20 | def isReleaseBuild() {
21 | return VERSION_NAME.contains("SNAPSHOT") == false
22 | }
23 |
24 | def getRepositoryUsername() {
25 | return hasProperty('SONATYPE_NEXUS_USERNAME') ? SONATYPE_NEXUS_USERNAME : System.env.SONATYPE_NEXUS_USERNAME
26 | }
27 |
28 | def getRepositoryPassword() {
29 | return hasProperty('SONATYPE_NEXUS_PASSWORD') ? SONATYPE_NEXUS_PASSWORD : System.env.SONATYPE_NEXUS_PASSWORD
30 | }
31 |
32 | afterEvaluate { project ->
33 | uploadArchives {
34 | repositories {
35 | mavenDeployer {
36 | beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
37 |
38 | pom.groupId = GROUP
39 | pom.artifactId = POM_ARTIFACT_ID
40 | pom.version = VERSION_NAME
41 |
42 | repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
43 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
44 | }
45 | snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") {
46 | authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
47 | }
48 |
49 | pom.project {
50 | name POM_NAME
51 | packaging POM_PACKAGING
52 | description POM_DESCRIPTION
53 | url POM_URL
54 |
55 | scm {
56 | url POM_SCM_URL
57 | connection POM_SCM_CONNECTION
58 | developerConnection POM_SCM_DEV_CONNECTION
59 | }
60 |
61 | licenses {
62 | license {
63 | name POM_LICENCE_NAME
64 | url POM_LICENCE_URL
65 | distribution POM_LICENCE_DIST
66 | }
67 | }
68 |
69 | developers {
70 | developer {
71 | id POM_DEVELOPER_ID
72 | name POM_DEVELOPER_NAME
73 | }
74 | }
75 | }
76 | }
77 | }
78 | }
79 |
80 | signing {
81 | required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") }
82 | sign configurations.archives
83 | }
84 |
85 | if (project.getPlugins().hasPlugin('com.android.application') ||
86 | project.getPlugins().hasPlugin('com.android.library')) {
87 | task install(type: Upload, dependsOn: assemble) {
88 | repositories.mavenInstaller {
89 | configuration = configurations.archives
90 |
91 | pom.groupId = GROUP
92 | pom.artifactId = POM_ARTIFACT_ID
93 | pom.version = VERSION_NAME
94 |
95 | pom.project {
96 | name POM_NAME
97 | packaging POM_PACKAGING
98 | description POM_DESCRIPTION
99 | url POM_URL
100 |
101 | scm {
102 | url POM_SCM_URL
103 | connection POM_SCM_CONNECTION
104 | developerConnection POM_SCM_DEV_CONNECTION
105 | }
106 |
107 | licenses {
108 | license {
109 | name POM_LICENCE_NAME
110 | url POM_LICENCE_URL
111 | distribution POM_LICENCE_DIST
112 | }
113 | }
114 |
115 | developers {
116 | developer {
117 | id POM_DEVELOPER_ID
118 | name POM_DEVELOPER_NAME
119 | }
120 | }
121 | }
122 | }
123 | }
124 |
125 | task androidJavadocs(type: Javadoc) {
126 | source = android.sourceSets.main.java.source
127 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
128 | }
129 |
130 | task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
131 | classifier = 'javadoc'
132 | from androidJavadocs.destinationDir
133 | }
134 |
135 | task androidSourcesJar(type: Jar) {
136 | classifier = 'sources'
137 | from android.sourceSets.main.java.source
138 | }
139 | } else {
140 | install {
141 | repositories.mavenInstaller {
142 | pom.groupId = GROUP
143 | pom.artifactId = POM_ARTIFACT_ID
144 | pom.version = VERSION_NAME
145 |
146 | pom.project {
147 | name POM_NAME
148 | packaging POM_PACKAGING
149 | description POM_DESCRIPTION
150 | url POM_URL
151 |
152 | scm {
153 | url POM_SCM_URL
154 | connection POM_SCM_CONNECTION
155 | developerConnection POM_SCM_DEV_CONNECTION
156 | }
157 |
158 | licenses {
159 | license {
160 | name POM_LICENCE_NAME
161 | url POM_LICENCE_URL
162 | distribution POM_LICENCE_DIST
163 | }
164 | }
165 |
166 | developers {
167 | developer {
168 | id POM_DEVELOPER_ID
169 | name POM_DEVELOPER_NAME
170 | }
171 | }
172 | }
173 | }
174 | }
175 |
176 | task sourcesJar(type: Jar, dependsOn:classes) {
177 | classifier = 'sources'
178 | from sourceSets.main.allSource
179 | }
180 |
181 | task javadocJar(type: Jar, dependsOn:javadoc) {
182 | classifier = 'javadoc'
183 | from javadoc.destinationDir
184 | }
185 | }
186 |
187 | if (JavaVersion.current().isJava8Compatible()) {
188 | allprojects {
189 | tasks.withType(Javadoc) {
190 | options.addStringOption('Xdoclint:none', '-quiet')
191 | }
192 | }
193 | }
194 |
195 | artifacts {
196 | if (project.getPlugins().hasPlugin('com.android.application') ||
197 | project.getPlugins().hasPlugin('com.android.library')) {
198 | archives androidSourcesJar
199 | archives androidJavadocsJar
200 | } else {
201 | archives sourcesJar
202 | archives javadocJar
203 | }
204 | }
205 | }
206 |
--------------------------------------------------------------------------------
/adapter/src/main/java/com/android/jmaxime/adapters/itemdecorator/DividerItemDecoration.java:
--------------------------------------------------------------------------------
1 | package com.android.jmaxime.adapters.itemdecorator;
2 |
3 |
4 | import android.content.Context;
5 | import android.content.res.TypedArray;
6 | import android.graphics.Canvas;
7 | import android.graphics.Rect;
8 | import android.graphics.drawable.Drawable;
9 | import android.support.v7.widget.LinearLayoutManager;
10 | import android.support.v7.widget.RecyclerView;
11 | import android.view.View;
12 |
13 | @SuppressWarnings("WeakerAccess")
14 | public class DividerItemDecoration extends RecyclerView.ItemDecoration {
15 |
16 | private static final String INVALID = "invalid orientation";
17 | private static final int[] ATTRS = new int[]{
18 | android.R.attr.listDivider
19 | };
20 |
21 | public static final int LIST_HORIZONTAL = LinearLayoutManager.HORIZONTAL;
22 | public static final int LIST_VERTICAL = LinearLayoutManager.VERTICAL;
23 | public static final int GRID_STROKE = 3;
24 | public static final int GRID_FILL = 4;
25 | private static Drawable mDivider;
26 | private int mOrientation;
27 |
28 | /**
29 | * Custom constructor
30 | *
31 | * @param context
32 | * @param orientation
33 | */
34 | public DividerItemDecoration(final Context context, final int orientation) {
35 | final TypedArray a = context.obtainStyledAttributes(ATTRS);
36 | if (mDivider == null){
37 | mDivider = a.getDrawable(0);
38 | }
39 | a.recycle();
40 | setOrientation(orientation);
41 | }
42 |
43 | /**
44 | * Set the orientation of the underlying grid / list
45 | *
46 | * @param orientation must be
47 | * {@link DividerItemDecoration#LIST_HORIZONTAL}
48 | * {@link DividerItemDecoration#LIST_VERTICAL}
49 | * {@link DividerItemDecoration#GRID_STROKE}
50 | * {@link DividerItemDecoration#GRID_FILL}
51 | */
52 | public void setOrientation(final int orientation) {
53 | if (orientation != LIST_HORIZONTAL &&
54 | orientation != LIST_VERTICAL &&
55 | orientation != GRID_STROKE &&
56 | orientation != GRID_FILL) {
57 | throw new IllegalArgumentException(INVALID);
58 | }
59 | mOrientation = orientation;
60 | }
61 |
62 | @Override
63 | public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
64 | super.onDraw(c, parent, state);
65 | if (mDivider != null) {
66 | switch (mOrientation) {
67 | case LIST_VERTICAL:
68 | drawVertical(c, parent);
69 | break;
70 | case LIST_HORIZONTAL:
71 | drawHorizontal(c, parent);
72 | break;
73 | case GRID_FILL:
74 | drawGridFill(c, parent);
75 | break;
76 | case GRID_STROKE:
77 | drawGridStroke(c, parent);
78 | break;
79 | default:
80 | throw new IllegalArgumentException(INVALID);
81 | }
82 | }
83 | }
84 |
85 | /**
86 | * Draw vertical divider in parent
87 | *
88 | * @param c canvas
89 | * @param parent recycler view
90 | */
91 | public void drawVertical(final Canvas c, final RecyclerView parent) {
92 | final int left = parent.getPaddingLeft();
93 | final int right = parent.getWidth() - parent.getPaddingRight();
94 |
95 | final int childCount = parent.getChildCount();
96 | for (int i = 0; i < childCount; i++) {
97 | final View child = parent.getChildAt(i);
98 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
99 | .getLayoutParams();
100 | final int top = child.getBottom() + params.bottomMargin;
101 | final int bottom = top + mDivider.getIntrinsicHeight();
102 | mDivider.setBounds(left, top, right, bottom);
103 | mDivider.draw(c);
104 | }
105 | }
106 |
107 | /**
108 | * Draw horizontal divider in parent
109 | *
110 | * @param c Canvas
111 | * @param parent Recycler view
112 | */
113 | public void drawHorizontal(final Canvas c, final RecyclerView parent) {
114 | final int top = parent.getPaddingTop();
115 | final int bottom = parent.getHeight() - parent.getPaddingBottom();
116 |
117 | final int childCount = parent.getChildCount();
118 | for (int i = 0; i < childCount; i++) {
119 | final View child = parent.getChildAt(i);
120 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
121 | .getLayoutParams();
122 | final int left = child.getRight() + params.rightMargin;
123 | final int right = left + mDivider.getIntrinsicHeight();
124 | mDivider.setBounds(left, top, right, bottom);
125 | mDivider.draw(c);
126 | }
127 | }
128 |
129 | /**
130 | * Remove both horizontal and vertical divider in parent
131 | *
132 | * @param c Canvas
133 | * @param parent Recycler view
134 | */
135 | public void drawGridStroke(final Canvas c, final RecyclerView parent) {
136 | final int childCount = parent.getChildCount();
137 | for (int i = 0; i < childCount; i++) {
138 | final View child = parent.getChildAt(i);
139 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
140 | .getLayoutParams();
141 | final int left = child.getLeft() - params.leftMargin;
142 | final int right = child.getRight() + params.rightMargin;
143 | final int top = child.getTop() - params.topMargin;
144 | final int bottom = child.getBottom() + params.bottomMargin;
145 | mDivider.setBounds(left, top, left + mDivider.getIntrinsicHeight(), bottom);
146 | mDivider.draw(c);
147 | mDivider.setBounds(right - mDivider.getIntrinsicHeight(), top, right, bottom);
148 | mDivider.draw(c);
149 | mDivider.setBounds(left, top, right, top + mDivider.getIntrinsicHeight());
150 | mDivider.draw(c);
151 | mDivider.setBounds(left, bottom - mDivider.getIntrinsicHeight(), right, bottom);
152 | mDivider.draw(c);
153 | mDivider.draw(c);
154 | }
155 | }
156 |
157 | /**
158 | * Draw both horizontal and vertical divider in parent
159 | *
160 | * @param c Canvas
161 | * @param parent Recler view
162 | */
163 | public void drawGridFill(final Canvas c, final RecyclerView parent) {
164 | final int childCount = parent.getChildCount();
165 | for (int i = 0; i < childCount; i++) {
166 | final View child = parent.getChildAt(i);
167 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
168 | .getLayoutParams();
169 | final int left = child.getLeft() - params.leftMargin;
170 | final int right = child.getRight() + params.rightMargin;
171 | final int top = child.getTop() - params.topMargin;
172 | final int bottom = child.getBottom() + params.bottomMargin;
173 | mDivider.setBounds(left, top, right, bottom);
174 | mDivider.draw(c);
175 | }
176 | }
177 |
178 | @Override
179 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
180 | super.getItemOffsets(outRect, view, parent, state);
181 | if (mDivider != null) {
182 | switch (mOrientation) {
183 | case LIST_VERTICAL:
184 | outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
185 | break;
186 | case LIST_HORIZONTAL:
187 | outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
188 | break;
189 | case GRID_FILL:
190 | outRect.set(mDivider.getIntrinsicWidth(), mDivider.getIntrinsicWidth(), mDivider.getIntrinsicWidth(), mDivider.getIntrinsicWidth());
191 | break;
192 | case GRID_STROKE:
193 | outRect.set(0, 0, 0, 0);
194 | break;
195 | default:
196 | throw new IllegalArgumentException(INVALID);
197 | }
198 | }
199 | }
200 | }
201 |
202 |
--------------------------------------------------------------------------------
/adapter/src/main/java/com/android/jmaxime/adapters/decorators/SectionedAdapter.java:
--------------------------------------------------------------------------------
1 | package com.android.jmaxime.adapters.decorators;
2 |
3 | import android.support.annotation.NonNull;
4 | import android.support.annotation.Nullable;
5 | import android.support.v7.widget.GridLayoutManager;
6 | import android.support.v7.widget.RecyclerView;
7 | import android.util.SparseArray;
8 | import android.view.ViewGroup;
9 |
10 | import com.android.jmaxime.factory.ViewHolderFactory;
11 | import com.android.jmaxime.viewholder.RecyclerViewHolder;
12 |
13 | import java.util.ArrayList;
14 | import java.util.Collections;
15 | import java.util.List;
16 |
17 | /**
18 | *
19 | * @param Section Type
20 | * @param RecyclerAdapter base Type
21 | */
22 | @SuppressWarnings("WeakerAccess") public class SectionedAdapter extends RecyclerView.Adapter {
23 |
24 | private static final int DEFAULT_SECTION_TYPE = 0;
25 | private static final int SECTION_TYPE = 2312;
26 | private SparseArray> mSectionHolderFactoryList;
27 | private SparseArray> mSectionItems = new SparseArray<>();
28 | @NonNull private A mBaseAdapter;
29 | private boolean mValid = true;
30 |
31 | public SectionedAdapter(@NonNull Class extends RecyclerViewHolder> viewHolder, @NonNull A a) {
32 | mSectionHolderFactoryList = new SparseArray<>();
33 | mSectionHolderFactoryList.append(DEFAULT_SECTION_TYPE, new ViewHolderFactory.Builder<>(viewHolder).build());
34 | mBaseAdapter = a;
35 | }
36 |
37 | @Override
38 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
39 | if (viewType == SECTION_TYPE) {
40 | return mSectionHolderFactoryList.get(DEFAULT_SECTION_TYPE).createViewHolder(parent);
41 | } else {
42 | return mBaseAdapter.onCreateViewHolder(parent, viewType - 1);
43 | }
44 | }
45 |
46 | @Override
47 | public void onBindViewHolder(RecyclerView.ViewHolder sectionViewHolder, int position) {
48 | if (isSectionHeaderPosition(position)) {
49 | //noinspection unchecked
50 | ((RecyclerViewHolder) sectionViewHolder).bind(mSectionItems.get(position).getT());
51 | } else {
52 | //noinspection unchecked
53 | mBaseAdapter.onBindViewHolder(sectionViewHolder, sectionedPositionToPosition(position));
54 | }
55 | }
56 |
57 | @Override
58 | public int getItemViewType(int position) {
59 | return isSectionHeaderPosition(position)
60 | ? SECTION_TYPE
61 | : mBaseAdapter.getItemViewType(sectionedPositionToPosition(position)) + 1;
62 | }
63 |
64 | @Override
65 | public long getItemId(int position) {
66 | return isSectionHeaderPosition(position)
67 | ? Integer.MAX_VALUE - mSectionItems.indexOfKey(position)
68 | : mBaseAdapter.getItemId(sectionedPositionToPosition(position));
69 | }
70 |
71 | @Override
72 | public int getItemCount() {
73 | return (mValid ? mBaseAdapter.getItemCount() + mSectionItems.size() : 0);
74 | }
75 |
76 | @Override
77 | public void onAttachedToRecyclerView(RecyclerView recyclerView) {
78 | super.onAttachedToRecyclerView(recyclerView);
79 | init(recyclerView);
80 | }
81 |
82 | public A getBaseAdapter() {
83 | return mBaseAdapter;
84 | }
85 |
86 | public void addSection(int position, S item) {
87 | addSection(new SectionAdapter<>(position, item));
88 | }
89 |
90 | public int positionToSectionedPosition(int position) {
91 | int offset = 0;
92 | for (int i = 0; i < mSectionItems.size(); i++) {
93 | if (mSectionItems.valueAt(i).getFirstPosition() > position) {
94 | break;
95 | }
96 | ++offset;
97 | }
98 | return position + offset;
99 | }
100 |
101 | /**
102 | * Get the real position of base adapter
103 | *
104 | * @param sectionedPosition position this adapter
105 | * @return position baseAdapter
106 | */
107 | private int sectionedPositionToPosition(int sectionedPosition) {
108 | if (isSectionHeaderPosition(sectionedPosition)) {
109 | return RecyclerView.NO_POSITION;
110 | }
111 |
112 | int offset = 0;
113 | for (int i = 0; i < mSectionItems.size(); i++) {
114 | if (mSectionItems.valueAt(i).getSectionedPosition() > sectionedPosition) {
115 | break;
116 | }
117 | --offset;
118 | }
119 | return sectionedPosition + offset;
120 | }
121 |
122 | public boolean isSectionHeaderPosition(int position) {
123 | return mSectionItems.get(position) != null;
124 | }
125 |
126 |
127 | private void addSection(SectionAdapter section) {
128 | mSectionItems.append(section.getFirstPosition(), section);
129 | List> s = new ArrayList<>();
130 | for (int i = 0; i < mSectionItems.size(); i++) {
131 | s.add(mSectionItems.valueAt(i));
132 | }
133 |
134 | setSections(s);
135 | }
136 |
137 | private void setSections(List> sections) {
138 | mSectionItems.clear();
139 |
140 | int offset = 0; // offset positions for the headers we're adding
141 | for (SectionAdapter section : sortSections(sections)) {
142 | section.setSectionedPosition(section.getFirstPosition() + offset);
143 | mSectionItems.append(section.getSectionedPosition(), section);
144 | ++offset;
145 | }
146 |
147 | notifyDataSetChanged();
148 | }
149 |
150 | private List> sortSections(List> sections) {
151 | Collections.sort(sections, (o, o1) -> (o.getFirstPosition() == o1.getFirstPosition())
152 | ? 0
153 | : ((o.getFirstPosition() < o1.getFirstPosition()) ? -1 : 1));
154 | return sections;
155 | }
156 |
157 | private void init(@Nullable RecyclerView r) {
158 | mBaseAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
159 | @Override
160 | public void onChanged() {
161 | mValid = mBaseAdapter.getItemCount() > 0;
162 | notifyDataSetChanged();
163 | }
164 |
165 | @Override
166 | public void onItemRangeChanged(int positionStart, int itemCount) {
167 | mValid = mBaseAdapter.getItemCount() > 0;
168 | notifyItemRangeChanged(positionStart, itemCount);
169 | }
170 |
171 | @Override
172 | public void onItemRangeInserted(int positionStart, int itemCount) {
173 | mValid = mBaseAdapter.getItemCount() > 0;
174 | notifyItemRangeInserted(positionStart, itemCount);
175 | }
176 |
177 | @Override
178 | public void onItemRangeRemoved(int positionStart, int itemCount) {
179 | mValid = mBaseAdapter.getItemCount() > 0;
180 | notifyItemRangeRemoved(positionStart, itemCount);
181 | }
182 | });
183 |
184 | if (r != null) {
185 | RecyclerView.LayoutManager layoutManager = r.getLayoutManager();
186 | if (layoutManager instanceof GridLayoutManager) {
187 | ((GridLayoutManager) layoutManager)
188 | .setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
189 | @Override
190 | public int getSpanSize(int position) {
191 | return (isSectionHeaderPosition(position)) ? ((GridLayoutManager) layoutManager)
192 | .getSpanCount() : 1;
193 | }
194 | });
195 | }
196 | }
197 | }
198 |
199 | private class SectionAdapter {
200 | private T mT;
201 | private int firstPosition;
202 | private int sectionedPosition;
203 |
204 | public SectionAdapter(int firstPosition, T t) {
205 | mT = t;
206 | this.firstPosition = firstPosition;
207 | }
208 |
209 | public T getT() {
210 | return mT;
211 | }
212 |
213 | public int getFirstPosition() {
214 | return firstPosition;
215 | }
216 |
217 | public int getSectionedPosition() {
218 | return sectionedPosition;
219 | }
220 |
221 | public void setSectionedPosition(int sectionedPosition) {
222 | this.sectionedPosition = sectionedPosition;
223 | }
224 | }
225 | }
226 |
--------------------------------------------------------------------------------
/adapter/src/main/java/com/android/jmaxime/adapters/RecyclerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.android.jmaxime.adapters;
2 |
3 | import android.support.annotation.IntRange;
4 | import android.support.annotation.NonNull;
5 | import android.support.annotation.Nullable;
6 | import android.support.v7.widget.RecyclerView;
7 | import android.util.Log;
8 | import android.util.SparseArray;
9 | import android.view.ViewGroup;
10 |
11 | import com.android.jmaxime.factory.ViewHolderFactory;
12 | import com.android.jmaxime.interfaces.IAdapterChanged;
13 | import com.android.jmaxime.interfaces.IBaseCommunication;
14 | import com.android.jmaxime.interfaces.IViewType;
15 | import com.android.jmaxime.interfaces.InitViewHolderDecorator;
16 | import com.android.jmaxime.interfaces.ItemViewTypeStrategy;
17 | import com.android.jmaxime.interfaces.ShowPictureDecorator;
18 | import com.android.jmaxime.viewholder.Container;
19 | import com.android.jmaxime.viewholder.RecyclerViewHolder;
20 |
21 | import java.security.AccessControlException;
22 | import java.util.ArrayList;
23 | import java.util.List;
24 |
25 | @SuppressWarnings("unchecked")
26 | public class RecyclerAdapter extends RecyclerView.Adapter {
27 |
28 | private static final int DEFAULT_VIEW_TYPE = 0;
29 | private static InitViewHolderDecorator sHolderDecorator;
30 | private static ShowPictureDecorator sPictureDecorator;
31 | private final String TAG = this.getClass().getSimpleName();
32 | private List mTList;
33 | private SparseArray mViewHolderFactory;
34 | private ItemViewTypeStrategy mViewTypeStrategy;
35 | private IAdapterChanged mAdapterChanged;
36 |
37 | public RecyclerAdapter() {
38 | mTList = new ArrayList<>();
39 | }
40 |
41 | public RecyclerAdapter(ViewHolderFactory factory) {
42 | this(new ArrayList<>(), factory);
43 | }
44 |
45 | public RecyclerAdapter(Class extends RecyclerViewHolder> viewHolderType) {
46 | this(new ArrayList<>(), viewHolderType, null);
47 | }
48 |
49 | public RecyclerAdapter(Class extends RecyclerViewHolder> viewHolderType, @Nullable IBaseCommunication callback) {
50 | this(new ArrayList<>(), viewHolderType, callback);
51 | }
52 |
53 | public RecyclerAdapter(List TList, Class extends RecyclerViewHolder> viewHolderType) {
54 | this(TList, viewHolderType, null);
55 | }
56 |
57 | public RecyclerAdapter(List TList, Class extends RecyclerViewHolder> viewHolderType, @Nullable IBaseCommunication callback) {
58 | this(TList, new ViewHolderFactory.Builder(viewHolderType).append(callback).build());
59 | }
60 |
61 | public RecyclerAdapter(List TList, ViewHolderFactory factory) {
62 | mTList = TList;
63 | mViewHolderFactory = new SparseArray<>();
64 | factory.setHolderDecorator(sHolderDecorator);
65 | factory.setPictureDecorator(sPictureDecorator);
66 | mViewHolderFactory.append(DEFAULT_VIEW_TYPE, factory);
67 | }
68 |
69 | private static void setHolderDecorator(InitViewHolderDecorator holderDecorator) {
70 | sHolderDecorator = holderDecorator;
71 | }
72 |
73 | private static void setPictureDecorator(ShowPictureDecorator pictureDecorator) {
74 | sPictureDecorator = pictureDecorator;
75 | }
76 |
77 | public static Helper Helper() {
78 | return new Helper();
79 | }
80 |
81 | @Override
82 | public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
83 | if (mViewHolderFactory == null || mViewHolderFactory.size() == 0) {
84 | throw new AccessControlException("mViewHolderFactory is not instancied. thanks use setDefaultFactory() method.");
85 | }
86 |
87 | RecyclerViewHolder vh = getViewHolderFactory(viewType).createViewHolder(parent);
88 | /*used for decorator. Sample ButterKnife*/
89 | vh.initBinding();
90 | return vh;
91 | }
92 |
93 | @Override
94 | public void onBindViewHolder(RecyclerViewHolder holder, int position) {
95 | /*recupération de notre viewModel*/
96 | Object viewModel = getItem(position);
97 | if (viewModel instanceof Container) {
98 | viewModel = ((Container) viewModel).getValue();
99 | }
100 | holder.bindingSmart(viewModel);
101 | }
102 |
103 | @Override
104 | public int getItemCount() {
105 | return mTList != null ? mTList.size() : 0;
106 | }
107 |
108 | @Override
109 | public int getItemViewType(int position) {
110 | if (mViewTypeStrategy != null) {
111 | return mViewTypeStrategy.getItemViewType(getItem(position));
112 | } else if (getItem(position) != null && getItem(position) instanceof IViewType) {
113 | return ((IViewType) getItem(position)).getItemViewType();
114 | }
115 | if (mViewHolderFactory.size() > 1) {
116 | Log.w(TAG, "----------------------------GENERIC--ADAPTER--WARNING----------------------------------");
117 | Log.w(TAG, "in getItemViewType: It looks like you forgot to call the method \"setViewTypeStrategy\"");
118 | }
119 | return super.getItemViewType(position);
120 | }
121 |
122 | /**
123 | * Get Item
124 | *
125 | * @param position position founded
126 | * @return instance to position
127 | */
128 | public T getItem(int position) {
129 | return mTList.get(position);
130 | }
131 |
132 | public void setDefaultFactory(ViewHolderFactory factory) {
133 | mViewHolderFactory.append(DEFAULT_VIEW_TYPE, factory);
134 | }
135 |
136 | /**
137 | * Set the strategy for multi item type
138 | * This strategy its priority on IViewType
139 | *
140 | * @param viewTypeStrategy strategy for multi view type holder
141 | */
142 | public void setViewTypeStrategy(ItemViewTypeStrategy viewTypeStrategy) {
143 | mViewTypeStrategy = viewTypeStrategy;
144 | }
145 |
146 | /**
147 | * @param viewType register type
148 | * @param viewHolder attache ViewHolder at to viewType
149 | * @param useDefaultConfiguration add IBaseCommunication, HeaderDecorator and PictureDecorator of Default
150 | */
151 | public void putViewType(@IntRange(from = 1) int viewType, @NonNull Class extends RecyclerViewHolder> viewHolder, boolean useDefaultConfiguration) {
152 | if (useDefaultConfiguration) {
153 | putViewType(viewType, viewHolder,
154 | mViewHolderFactory.get(DEFAULT_VIEW_TYPE).getCommunication(),
155 | mViewHolderFactory.get(DEFAULT_VIEW_TYPE).getHolderDecorator(),
156 | mViewHolderFactory.get(DEFAULT_VIEW_TYPE).getPictureDecorator());
157 | } else {
158 | putViewType(viewType, viewHolder, null, null, null);
159 | }
160 | }
161 |
162 | public void putViewType(@IntRange(from = 1) int viewType, @NonNull Class extends RecyclerViewHolder> viewHolder, @Nullable IBaseCommunication communicationCallback) {
163 | putViewType(viewType, viewHolder, communicationCallback, null, null);
164 | }
165 |
166 | public void putViewType(@IntRange(from = 1) int viewType, @NonNull Class extends RecyclerViewHolder> viewHolder,
167 | @Nullable IBaseCommunication communicationCallback,
168 | @Nullable InitViewHolderDecorator holderDecorator,
169 | @Nullable ShowPictureDecorator pictureDecorator) {
170 | if (viewType == 0) {
171 | throw new IllegalArgumentException("viewType must be greater than 0. Because 0 is reserved for viewHolder by default");
172 | }
173 | mViewHolderFactory.append(viewType,
174 | new ViewHolderFactory.Builder(viewHolder)
175 | .append(communicationCallback)
176 | .append(holderDecorator)
177 | .append(pictureDecorator)
178 | .build());
179 | }
180 |
181 | public boolean contains(final T obj) {
182 | return mTList.contains(obj);
183 | }
184 |
185 | protected void callChangedListener() {
186 | if (mAdapterChanged != null) {
187 | mAdapterChanged.onItemCountChange(getItemCount());
188 | }
189 | }
190 |
191 | public void setOnAdapterChangedListener(IAdapterChanged adapterChanged) {
192 | mAdapterChanged = adapterChanged;
193 | }
194 |
195 | public void setCommunication(@Nullable IBaseCommunication communication) {
196 | mViewHolderFactory.get(DEFAULT_VIEW_TYPE).setCallback(communication);
197 | notifyDataSetChanged();
198 | }
199 |
200 | public void attachInitHolderDecorator(@Nullable InitViewHolderDecorator holderDecorator) {
201 | mViewHolderFactory.get(DEFAULT_VIEW_TYPE).setHolderDecorator(holderDecorator);
202 | }
203 |
204 | public void attachShowPictureDecorator(@Nullable ShowPictureDecorator pictureDecorator) {
205 | mViewHolderFactory.get(DEFAULT_VIEW_TYPE).setPictureDecorator(pictureDecorator);
206 | }
207 |
208 | /**
209 | * Inserts the specified element at the specified position in this list (optional operation).
210 | * Shifts the element currently at that position (if any) and any subsequent elements to the right (adds one to their indices).
211 | *
212 | * @param item element to be inserted
213 | */
214 | public void addItem(@NonNull T item) {
215 | if (mTList != null) {
216 | mTList.add(item);
217 | notifyItemInserted(mTList.size());
218 | }
219 | }
220 |
221 | /**
222 | * Inserts the specified element at the specified position in this list (optional operation).
223 | * Shifts the element currently at that position (if any) and any subsequent elements to the right (adds one to their indices).
224 | *
225 | * @param item element to be inserted
226 | * @param position index at which the specified element is to be inserted
227 | */
228 | public void addItem(@NonNull T item, @IntRange(from = 0) int position) {
229 | if (mTList != null) {
230 | position = Math.min(position, mTList.size());
231 | mTList.add(position, item);
232 | notifyItemInserted(position);
233 | }
234 | }
235 |
236 | /**
237 | * Inserts the specified element at the specified position in this list (optional operation).
238 | * Shifts the element currently at that position (if any) and any subsequent elements to the right (adds one to their indices).
239 | *
240 | * @param collection elements to be inserted
241 | */
242 | public void addAll(List collection) {
243 | if (mTList != null) {
244 | mTList.addAll(collection);
245 | int start = Math.max(0, (mTList.size() - collection.size()) - 1);
246 | notifyItemRangeInserted(start, collection.size());
247 | }
248 | }
249 |
250 | /**
251 | * Inserts the specified element at the specified position in this list (optional operation).
252 | * Shifts the element currently at that position (if any) and any subsequent elements to the right (adds one to their indices).
253 | *
254 | * @param item the element to be removed
255 | */
256 | public void removeItem(@NonNull T item) {
257 | removeItem(getTList().indexOf(item));
258 | }
259 |
260 | /**
261 | * Inserts the specified element at the specified position in this list (optional operation).
262 | * Shifts the element currently at that position (if any) and any subsequent elements to the right (adds one to their indices).
263 | *
264 | * @param position the index of the element to be removed
265 | */
266 | public void removeItem(@IntRange(from = 0) int position) {
267 | if (mTList != null && position > -1 && position < mTList.size()) {
268 | mTList.remove(position);
269 | notifyItemRemoved(position);
270 | }
271 | }
272 |
273 | /**
274 | * Set new list items and notifyDataSetChanged()
275 | *
276 | * @param list new instance items list for bind views
277 | * @link notifyDataSetChanged
278 | */
279 | public void updateItems(@NonNull List list) {
280 | mTList = list;
281 | notifyDataSetChanged();
282 | }
283 |
284 | /**
285 | * @param item find item
286 | * @return
287 | * @see List#indexOf
288 | */
289 | public int indexOf(T item) {
290 | return getTList() != null ? getTList().indexOf(item) : -1;
291 | }
292 |
293 | /**
294 | * @return instance items list
295 | */
296 | public List getTList() {
297 | return mTList;
298 | }
299 |
300 | public boolean isEmpty() {
301 | return mTList == null || mTList.isEmpty();
302 | }
303 |
304 | private boolean containsViewType(int viewType) {
305 | return mViewHolderFactory.indexOfKey(viewType) >= 0;
306 | }
307 |
308 | private ViewHolderFactory getViewHolderFactory(int viewType) {
309 | return mViewHolderFactory.get(containsViewType(viewType) ? viewType : DEFAULT_VIEW_TYPE);
310 | }
311 |
312 | public static class Helper {
313 |
314 | private InitViewHolderDecorator mInitDecorator;
315 | private ShowPictureDecorator mPictureDecorator;
316 |
317 | Helper() {
318 | }
319 |
320 | public Helper append(InitViewHolderDecorator decorator) {
321 | mInitDecorator = decorator;
322 | return this;
323 | }
324 |
325 | public Helper append(ShowPictureDecorator decorator) {
326 | mPictureDecorator = decorator;
327 | return this;
328 | }
329 |
330 | public void init() {
331 | RecyclerAdapter.setHolderDecorator(mInitDecorator);
332 | RecyclerAdapter.setPictureDecorator(mPictureDecorator);
333 | }
334 | }
335 | }
336 |
--------------------------------------------------------------------------------