summaryrefslogtreecommitdiff
path: root/android/support/car/drawer/CarDrawerAdapter.java
blob: b0fd965deefe9bb0c6ac4bb1b538830696068029 (plain)
1
2
3
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.support.car.drawer;

import android.content.Context;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.car.R;
import android.support.car.widget.PagedListView;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * Base adapter for displaying items in the car navigation drawer, which uses a
 * {@link PagedListView}.
 *
 * <p>Subclasses must set the title that will be displayed when displaying the contents of the
 * drawer via {@link #setTitle(CharSequence)}. The title can be updated at any point later on. The
 * title of the root adapter will also be the main title showed in the toolbar when the drawer is
 * closed. See {@link CarDrawerController#setRootAdapter(CarDrawerAdapter)} for more information.
 *
 * <p>This class also takes care of implementing the PageListView.ItemCamp contract and subclasses
 * should implement {@link #getActualItemCount()}.
 */
public abstract class CarDrawerAdapter extends RecyclerView.Adapter<DrawerItemViewHolder>
        implements PagedListView.ItemCap, DrawerItemClickListener {
    private final boolean mShowDisabledListOnEmpty;
    private final Drawable mEmptyListDrawable;
    private int mMaxItems = PagedListView.ItemCap.UNLIMITED;
    private CharSequence mTitle;
    private TitleChangeListener mTitleChangeListener;

    /**
     * Interface for a class that will be notified a new title has been set on this adapter.
     */
    interface TitleChangeListener {
        /**
         * Called when {@link #setTitle(CharSequence)} has been called and the title has been
         * changed.
         */
        void onTitleChanged(CharSequence newTitle);
    }

    protected CarDrawerAdapter(Context context, boolean showDisabledListOnEmpty) {
        mShowDisabledListOnEmpty = showDisabledListOnEmpty;

        mEmptyListDrawable = context.getDrawable(R.drawable.ic_list_view_disable);
        mEmptyListDrawable.setColorFilter(context.getColor(R.color.car_tint),
                PorterDuff.Mode.SRC_IN);
    }

    /** Returns the title set via {@link #setTitle(CharSequence)}. */
    CharSequence getTitle() {
        return mTitle;
    }

    /** Updates the title to display in the toolbar for this Adapter. */
    public final void setTitle(@NonNull CharSequence title) {
        if (title == null) {
            throw new IllegalArgumentException("setTitle() cannot be passed a null title!");
        }

        mTitle = title;

        if (mTitleChangeListener != null) {
            mTitleChangeListener.onTitleChanged(mTitle);
        }
    }

    /** Sets a listener to be notified whenever the title of this adapter has been changed. */
    void setTitleChangeListener(@Nullable TitleChangeListener listener) {
        mTitleChangeListener = listener;
    }

    @Override
    public final void setMaxItems(int maxItems) {
        mMaxItems = maxItems;
    }

    @Override
    public final int getItemCount() {
        if (shouldShowDisabledListItem()) {
            return 1;
        }
        return mMaxItems >= 0 ? Math.min(mMaxItems, getActualItemCount()) : getActualItemCount();
    }

    /**
     * Returns the absolute number of items that can be displayed in the list.
     *
     * <p>A class should implement this method to supply the number of items to be displayed.
     * Returning 0 from this method will cause an empty list icon to be displayed in the drawer.
     *
     * <p>A class should override this method rather than {@link #getItemCount()} because that
     * method is handling the logic of when to display the empty list icon. It will return 1 when
     * {@link #getActualItemCount()} returns 0.
     *
     * @return The number of items to be displayed in the list.
     */
    protected abstract int getActualItemCount();

    @Override
    public final int getItemViewType(int position) {
        if (shouldShowDisabledListItem()) {
            return R.layout.car_drawer_list_item_empty;
        }

        return usesSmallLayout(position)
                ? R.layout.car_drawer_list_item_small
                : R.layout.car_drawer_list_item_normal;
    }

    /**
     * Used to indicate the layout used for the Drawer item at given position. Subclasses can
     * override this to use normal layout which includes text element below title.
     *
     * <p>A small layout is presented by the layout {@code R.layout.car_drawer_list_item_small}.
     * Otherwise, the layout {@code R.layout.car_drawer_list_item_normal} will be used.
     *
     * @param position Adapter position of item.
     * @return Whether the item at this position will use a small layout (default) or normal layout.
     */
    protected boolean usesSmallLayout(int position) {
        return true;
    }

    @Override
    public final DrawerItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
        return new DrawerItemViewHolder(view);
    }

    @Override
    public final void onBindViewHolder(DrawerItemViewHolder holder, int position) {
        if (shouldShowDisabledListItem()) {
            holder.getTitle().setText(null);
            holder.getIcon().setImageDrawable(mEmptyListDrawable);
            holder.setItemClickListener(null);
        } else {
            holder.setItemClickListener(this);
            populateViewHolder(holder, position);
        }
    }

    /**
     * Whether or not this adapter should be displaying an empty list icon. The icon is shown if it
     * has been configured to show and there are no items to be displayed.
     */
    private boolean shouldShowDisabledListItem() {
        return mShowDisabledListOnEmpty && getActualItemCount() == 0;
    }

    /**
     * Subclasses should set all elements in {@code holder} to populate the drawer-item. If some
     * element is not used, it should be nulled out since these ViewHolder/View's are recycled.
     */
    protected abstract void populateViewHolder(DrawerItemViewHolder holder, int position);

    /**
     * Called when this adapter has been popped off the stack and is no longer needed. Subclasses
     * can override to do any necessary cleanup.
     */
    public void cleanup() {}
}