1/*
2 * Copyright (C) 2016 The Android Open Source Project
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
17package com.android.car.radio;
18
19import android.annotation.Nullable;
20import android.hardware.radio.ProgramSelector;
21import android.support.v7.widget.RecyclerView;
22import android.util.Log;
23import android.view.LayoutInflater;
24import android.view.View;
25import android.view.ViewGroup;
26
27import androidx.car.widget.PagedListView;
28
29import com.android.car.broadcastradio.support.Program;
30
31import java.util.List;
32import java.util.Objects;
33
34/**
35 * Adapter that will display a list of radio stations that represent the user's presets.
36 */
37public class PresetsAdapter extends RecyclerView.Adapter<PresetsViewHolder>
38        implements PagedListView.ItemCap {
39    private static final String TAG = "Em.PresetsAdapter";
40
41    // Only one type of view in this adapter.
42    private static final int PRESETS_VIEW_TYPE = 0;
43
44    private Program mActiveProgram;
45
46    private List<Program> mPresets;
47    private OnPresetItemClickListener mPresetClickListener;
48    private OnPresetItemFavoriteListener mPresetFavoriteListener;
49
50    /**
51     * Interface for a listener that will be notified when an item in the presets list has been
52     * clicked.
53     */
54    public interface OnPresetItemClickListener {
55        /**
56         * Method called when an item in the preset list has been clicked.
57         *
58         * @param selector The {@link ProgramSelector} corresponding to the clicked preset.
59         */
60        void onPresetItemClicked(ProgramSelector selector);
61    }
62
63    /**
64     * Interface for a listener that will be notified when a favorite in the presets list has been
65     * toggled.
66     */
67    public interface OnPresetItemFavoriteListener {
68
69        /**
70         * Method called when an item's favorite status has been toggled
71         *
72         * @param program The {@link Program} corresponding to the clicked preset.
73         * @param saveAsFavorite Whether the program should be saved or removed as a favorite.
74         */
75        void onPresetItemFavoriteChanged(Program program, boolean saveAsFavorite);
76    }
77
78    /**
79     * Set a listener to be notified whenever a preset card is pressed.
80     */
81    public void setOnPresetItemClickListener(@Nullable OnPresetItemClickListener listener) {
82        mPresetClickListener = Objects.requireNonNull(listener);
83    }
84
85    /**
86     * Set a listener to be notified whenever a preset favorite is changed.
87     */
88    public void setOnPresetItemFavoriteListener(@Nullable OnPresetItemFavoriteListener listener) {
89        mPresetFavoriteListener = listener;
90    }
91
92    /**
93     * Sets the given list as the list of presets to display.
94     */
95    public void setPresets(List<Program> presets) {
96        mPresets = presets;
97        notifyDataSetChanged();
98    }
99
100    /**
101     * Indicates which radio station is the active one inside the list of presets that are set on
102     * this adapter. This will cause that station to be highlighted in the list. If the station
103     * passed to this method does not match any of the presets, then none will be highlighted.
104     */
105    public void setActiveProgram(Program program) {
106        mActiveProgram = program;
107        notifyDataSetChanged();
108    }
109
110    @Override
111    public PresetsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
112        View view = LayoutInflater.from(parent.getContext())
113                .inflate(R.layout.radio_preset_stream_card, parent, false);
114
115        return new PresetsViewHolder(
116                view, this::handlePresetClicked, this::handlePresetFavoriteChanged);
117    }
118
119    @Override
120    public void onBindViewHolder(PresetsViewHolder holder, int position) {
121        if (getPresetCount() == 0) {
122            holder.bindPreset(mActiveProgram, true, getItemCount(), false);
123            return;
124        }
125        Program station = mPresets.get(position);
126        boolean isActiveStation = station.getSelector().equals(mActiveProgram.getSelector());
127        holder.bindPreset(station, isActiveStation, getItemCount(), true);
128    }
129
130    @Override
131    public int getItemViewType(int position) {
132        return PRESETS_VIEW_TYPE;
133    }
134
135    @Override
136    public int getItemCount() {
137        int numPresets = getPresetCount();
138        return (numPresets == 0) ? 1 : numPresets;
139    }
140
141    private int getPresetCount() {
142        return (mPresets == null) ? 0 : mPresets.size();
143    }
144
145    @Override
146    public void setMaxItems(int max) {
147        // No-op. A PagedListView needs the ItemCap interface to be implemented. However, the
148        // list of presets should not be limited.
149    }
150
151    private void handlePresetClicked(int position) {
152        if (Log.isLoggable(TAG, Log.VERBOSE)) {
153            Log.v(TAG, String.format("onPresetClicked(); item count: %d; position: %d",
154                    getItemCount(), position));
155        }
156        if (mPresetClickListener != null && getItemCount() > position) {
157            if (getPresetCount() == 0) {
158                mPresetClickListener.onPresetItemClicked(mActiveProgram.getSelector());
159                return;
160            }
161            mPresetClickListener.onPresetItemClicked(mPresets.get(position).getSelector());
162        }
163    }
164
165    private void handlePresetFavoriteChanged (int position, boolean saveAsFavorite) {
166        if (mPresetFavoriteListener != null && getItemCount() > position) {
167            if (getPresetCount() == 0) {
168                mPresetFavoriteListener.onPresetItemFavoriteChanged(mActiveProgram, saveAsFavorite);
169                return;
170            }
171            mPresetFavoriteListener.onPresetItemFavoriteChanged(
172                    mPresets.get(position), saveAsFavorite);
173        }
174    }
175}
176