/*
* Copyright (C) 2016 Simon Vig Therkildsen
*
* 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 net.simonvt.cathode.ui.search;
import android.graphics.drawable.Animatable;
import android.support.graphics.drawable.VectorDrawableCompat;
import android.support.v7.util.DiffUtil;
import android.support.v7.widget.AppCompatImageView;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import butterknife.BindView;
import butterknife.ButterKnife;
import java.util.List;
import net.simonvt.cathode.R;
import net.simonvt.cathode.api.enumeration.ItemType;
import net.simonvt.cathode.images.ImageType;
import net.simonvt.cathode.images.ImageUri;
import net.simonvt.cathode.search.Result;
import net.simonvt.cathode.widget.CircularProgressIndicator;
import net.simonvt.cathode.widget.RemoteImageView;
public class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.ViewHolder> {
public interface OnResultClickListener {
void onShowClicked(long showId, String title, String overview);
void onMovieClicked(long movieId, String title, String overview);
void onQueryClicked(String query);
}
private static final int TYPE_RECENT = 0;
private static final int TYPE_RESULT = 1;
private static final int TYPE_SEARCH = 2;
private static final int TYPE_SEARCHING = 3;
private static final int TYPE_NO_RESULTS = 4;
private OnResultClickListener listener;
private List<String> recentQueries;
private boolean displaySearching;
private List<Result> results;
public SearchAdapter(OnResultClickListener listener) {
this.listener = listener;
}
public void setRecentQueries(List<String> recentQueries) {
List<String> oldQueries = this.recentQueries;
this.recentQueries = recentQueries;
final boolean hadItems = oldQueries != null && oldQueries.size() > 0;
final boolean hasItems = recentQueries.size() > 0;
if (hasItems) {
if (!hadItems) {
notifyItemInserted(0);
} else {
notifyItemChanged(0);
}
} else {
if (hadItems) {
notifyItemRemoved(0);
} else {
notifyItemChanged(0);
}
}
}
private boolean hasRecentQueries() {
return recentQueries != null && recentQueries.size() > 0;
}
public void setSearching(boolean displaySearching) {
if (displaySearching != this.displaySearching) {
this.displaySearching = displaySearching;
final boolean hasRecentQueries = hasRecentQueries();
final int offset = hasRecentQueries ? 1 : 0;
if (displaySearching) {
if (results != null && results.size() > 0) {
notifyItemRangeRemoved(offset, results.size());
} else {
notifyItemRemoved(offset);
}
notifyItemInserted(offset);
} else {
notifyItemRemoved(offset);
if (results != null && results.size() > 0) {
notifyItemRangeInserted(offset, results.size());
} else {
notifyItemInserted(offset);
}
}
}
}
public void setResults(final List<Result> results) {
final List<Result> oldResults = this.results;
this.results = results;
final boolean hasRecentQueries = hasRecentQueries();
final int offset = hasRecentQueries ? 1 : 0;
if (!displaySearching) {
if (oldResults == null) {
if (results != null) {
notifyItemRemoved(offset);
if (results.size() == 0) {
notifyItemInserted(offset);
} else {
notifyItemRangeInserted(offset, results.size());
}
}
} else if (oldResults.size() == 0) {
if (results == null) {
notifyItemRemoved(offset);
notifyItemInserted(offset);
} else if (results.size() > 0) {
notifyItemRemoved(offset);
notifyItemRangeInserted(offset, results.size());
}
} else {
if (results == null || results.size() == 0) {
notifyItemRangeRemoved(offset, oldResults.size());
notifyItemInserted(offset);
} else {
diffLists(oldResults, results);
}
}
}
}
private void diffLists(final List<Result> oldResults, final List<Result> newResults) {
final boolean hasRecentQueries = hasRecentQueries();
final int offset = hasRecentQueries ? 1 : 0;
DiffUtil.calculateDiff(new DiffUtil.Callback() {
@Override public int getOldListSize() {
int size = 0;
if (hasRecentQueries) {
size += 1;
}
if (oldResults != null) {
size += oldResults.size();
}
return size;
}
@Override public int getNewListSize() {
int size = 0;
if (hasRecentQueries) {
size += 1;
}
if (newResults != null) {
size += newResults.size();
}
return size;
}
@Override public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
if (hasRecentQueries) {
if (oldItemPosition == 0 || newItemPosition == 0) {
return oldItemPosition == newItemPosition;
}
}
final Result oldItem = oldResults.get(oldItemPosition - offset);
final Result newItem = newResults.get(newItemPosition - offset);
return newItem.getItemType() == oldItem.getItemType()
&& newItem.getItemId() == oldItem.getItemId();
}
@Override public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
if (hasRecentQueries && oldItemPosition == 0 && newItemPosition == 0) {
return true;
}
final Result oldItem = oldResults.get(oldItemPosition - offset);
final Result newItem = newResults.get(newItemPosition - offset);
return newItem.equals(oldItem);
}
}).dispatchUpdatesTo(this);
}
@Override public int getItemCount() {
int size = 0;
if (recentQueries != null && recentQueries.size() > 0) {
size += 1;
}
if (!displaySearching && results != null && results.size() > 0) {
size += results.size();
} else {
size += 1;
}
return size;
}
@Override public int getItemViewType(int position) {
if (position == 0 && hasRecentQueries()) {
return TYPE_RECENT;
}
if (displaySearching) {
return TYPE_SEARCHING;
}
if (results == null) {
return TYPE_SEARCH;
}
if (results.size() == 0) {
return TYPE_NO_RESULTS;
}
return TYPE_RESULT;
}
@Override public void onViewAttachedToWindow(ViewHolder holder) {
super.onViewAttachedToWindow(holder);
if (holder.getItemViewType() == TYPE_SEARCHING) {
((SearchingHolder) holder).drawable.start();
}
}
@Override public void onViewDetachedFromWindow(ViewHolder holder) {
super.onViewDetachedFromWindow(holder);
if (holder.getItemViewType() == TYPE_SEARCHING) {
((SearchingHolder) holder).drawable.stop();
}
}
@Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_SEARCHING) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.search_searching, parent, false);
return new SearchingHolder(view);
} else if (viewType == TYPE_SEARCH) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.search_something, parent, false);
return new ViewHolder(view);
} else if (viewType == TYPE_NO_RESULTS) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.search_no_results, parent, false);
return new ViewHolder(view);
} else if (viewType == TYPE_RECENT) {
View view =
LayoutInflater.from(parent.getContext()).inflate(R.layout.search_recents, parent, false);
final RecentsViewHolder holder = new RecentsViewHolder(view);
VectorDrawableCompat icon = VectorDrawableCompat.create(parent.getContext().getResources(),
R.drawable.ic_search_history_24dp, null);
holder.query1.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
holder.query2.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
holder.query3.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
holder.query1.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View view) {
listener.onQueryClicked(holder.queryOneQuery);
}
});
holder.query2.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View view) {
listener.onQueryClicked(holder.queryTwoQuery);
}
});
holder.query3.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View view) {
listener.onQueryClicked(holder.queryThreeQuery);
}
});
return holder;
} else {
View view =
LayoutInflater.from(parent.getContext()).inflate(R.layout.search_result, parent, false);
final ViewHolder holder = new ResultViewHolder(view);
view.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View view) {
final int position = holder.getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
final boolean hasRecentQueries = hasRecentQueries();
final int offset = hasRecentQueries ? 1 : 0;
Result result = results.get(position - offset);
if (result.getItemType() == ItemType.SHOW) {
listener.onShowClicked(result.getItemId(), result.getTitle(), result.getOverview());
} else {
listener.onMovieClicked(result.getItemId(), result.getTitle(), result.getOverview());
}
}
}
});
return holder;
}
}
@Override public void onBindViewHolder(ViewHolder holder, int position) {
if (holder.getItemViewType() == TYPE_RECENT) {
RecentsViewHolder recentsHolder = (RecentsViewHolder) holder;
final int recentQueryCount = recentQueries.size();
recentsHolder.queryOneQuery = recentQueries.get(0);
recentsHolder.query1.setText(recentsHolder.queryOneQuery);
if (recentQueryCount >= 2) {
recentsHolder.queryTwoQuery = recentQueries.get(1);
recentsHolder.query2.setText(recentsHolder.queryTwoQuery);
recentsHolder.query2.setVisibility(View.VISIBLE);
} else {
recentsHolder.query2.setVisibility(View.GONE);
}
if (recentQueryCount >= 3) {
recentsHolder.queryThreeQuery = recentQueries.get(2);
recentsHolder.query3.setText(recentsHolder.queryThreeQuery);
recentsHolder.query3.setVisibility(View.VISIBLE);
} else {
recentsHolder.query3.setVisibility(View.GONE);
}
} else if (holder.getItemViewType() == TYPE_RESULT) {
final int offset = hasRecentQueries() ? 1 : 0;
ResultViewHolder resultHolder = (ResultViewHolder) holder;
Result result = results.get(position - offset);
String poster;
if (result.getItemType() == ItemType.SHOW) {
poster = ImageUri.create(ImageUri.ITEM_SHOW, ImageType.POSTER, result.getItemId());
} else {
poster = ImageUri.create(ImageUri.ITEM_MOVIE, ImageType.POSTER, result.getItemId());
}
resultHolder.poster.setImage(poster);
resultHolder.title.setText(result.getTitle());
resultHolder.overview.setText(result.getOverview());
resultHolder.rating.setValue(result.getRating());
}
}
static class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
static class SearchingHolder extends ViewHolder {
@BindView(R.id.searching) AppCompatImageView searching;
Animatable drawable;
public SearchingHolder(View itemView) {
super(itemView);
drawable = (Animatable) searching.getDrawable();
}
}
static class RecentsViewHolder extends ViewHolder {
@BindView(R.id.queries) ViewGroup queries;
@BindView(R.id.query1) TextView query1;
@BindView(R.id.query2) TextView query2;
@BindView(R.id.query3) TextView query3;
String queryOneQuery;
String queryTwoQuery;
String queryThreeQuery;
public RecentsViewHolder(View itemView) {
super(itemView);
}
}
static class ResultViewHolder extends ViewHolder {
@BindView(R.id.poster) RemoteImageView poster;
@BindView(R.id.title) TextView title;
@BindView(R.id.overview) TextView overview;
@BindView(R.id.rating) CircularProgressIndicator rating;
public ResultViewHolder(View itemView) {
super(itemView);
}
}
}