/*
This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Subsonic. If not, see .
Copyright 2015 (C) Scott Jackson
*/
package github.daneren2005.dsub.adapter;
import android.content.Context;
import android.content.res.Resources;
import android.os.Build;
import android.support.v7.widget.PopupMenu;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.util.TypedValue;
import android.view.ActionMode;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import github.daneren2005.dsub.R;
import github.daneren2005.dsub.activity.SubsonicFragmentActivity;
import github.daneren2005.dsub.view.BasicHeaderView;
import github.daneren2005.dsub.view.UpdateView;
import github.daneren2005.dsub.view.UpdateView.UpdateViewHolder;
public abstract class SectionAdapter extends RecyclerView.Adapter> {
private static String TAG = SectionAdapter.class.getSimpleName();
public static int VIEW_TYPE_HEADER = 0;
protected Context context;
protected List headers;
protected List> sections;
protected boolean singleSectionHeader;
protected OnItemClickedListener onItemClickedListener;
protected List selected = new ArrayList<>();
protected List selectedViews = new ArrayList<>();
protected ActionMode currentActionMode;
protected boolean checkable = false;
protected SectionAdapter() {}
public SectionAdapter(Context context, List section) {
this(context, section, false);
}
public SectionAdapter(Context context, List section, boolean singleSectionHeader) {
this.context = context;
this.headers = Arrays.asList("Section");
this.sections = new ArrayList<>();
this.sections.add(section);
this.singleSectionHeader = singleSectionHeader;
}
public SectionAdapter(Context context, List headers, List> sections) {
this(context, headers, sections, true);
}
public SectionAdapter(Context context, List headers, List> sections, boolean singleSectionHeader){
this.context = context;
this.headers = headers;
this.sections = sections;
this.singleSectionHeader = singleSectionHeader;
}
public void replaceExistingData(List section) {
this.sections = new ArrayList<>();
this.sections.add(section);
notifyDataSetChanged();
}
public void replaceExistingData(List headers, List> sections) {
this.headers = headers;
this.sections = sections;
notifyDataSetChanged();
}
@Override
public UpdateViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if(viewType == VIEW_TYPE_HEADER) {
return onCreateHeaderHolder(parent);
} else {
final UpdateViewHolder holder = onCreateSectionViewHolder(parent, viewType);
final UpdateView updateView = holder.getUpdateView();
if(updateView != null) {
updateView.getChildAt(0).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
T item = holder.getItem();
updateView.onClick();
if (currentActionMode != null) {
if(updateView.isCheckable()) {
if (selected.contains(item)) {
selected.remove(item);
selectedViews.remove(updateView);
setChecked(updateView, false);
} else {
selected.add(item);
selectedViews.add(updateView);
setChecked(updateView, true);
}
if (selected.isEmpty()) {
currentActionMode.finish();
} else {
currentActionMode.setTitle(context.getResources().getString(R.string.select_album_n_selected, selected.size()));
}
}
} else if (onItemClickedListener != null) {
onItemClickedListener.onItemClicked(item);
}
}
});
View moreButton = updateView.findViewById(R.id.more_button);
if(moreButton == null) {
moreButton = updateView.findViewById(R.id.item_more);
}
if (moreButton != null) {
moreButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final T item = holder.getItem();
if(onItemClickedListener != null) {
PopupMenu popup = new PopupMenu(context, v);
onItemClickedListener.onCreateContextMenu(popup.getMenu(), popup.getMenuInflater(), updateView, item);
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem menuItem) {
return onItemClickedListener.onContextItemSelected(menuItem, updateView, item);
}
});
popup.show();
}
}
});
if(checkable) {
updateView.getChildAt(0).setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if(currentActionMode == null) {
startActionMode(holder);
} else {
updateView.getChildAt(0).performClick();
}
return true;
}
});
}
}
}
return holder;
}
}
@Override
public void onBindViewHolder(UpdateViewHolder holder, int position) {
UpdateView updateView = holder.getUpdateView();
if(sections.size() == 1 && !singleSectionHeader) {
T item = sections.get(0).get(position);
onBindViewHolder(holder, item, getItemViewType(position));
if(updateView.isCheckable()) {
setChecked(updateView, selected.contains(item));
}
holder.setItem(item);
return;
}
int subPosition = 0;
int subHeader = 0;
for(List section: sections) {
boolean validHeader = headers.get(subHeader) != null;
if(position == subPosition && validHeader) {
onBindHeaderHolder(holder, headers.get(subHeader));
return;
}
int headerOffset = validHeader ? 1 : 0;
if(position < (subPosition + section.size() + headerOffset)) {
T item = section.get(position - subPosition - headerOffset);
onBindViewHolder(holder, item, getItemViewType(item));
if(updateView.isCheckable()) {
setChecked(updateView, selected.contains(item));
}
holder.setItem(item);
return;
}
subPosition += section.size();
if(validHeader) {
subPosition += 1;
}
subHeader++;
}
}
@Override
public int getItemCount() {
if(sections.size() == 1 && !singleSectionHeader) {
return sections.get(0).size();
}
int count = 0;
for(String header: headers) {
if(header != null) {
count++;
}
}
for(List section: sections) {
count += section.size();
}
return count;
}
@Override
public int getItemViewType(int position) {
if(sections.size() == 1 && !singleSectionHeader) {
return getItemViewType(sections.get(0).get(position));
}
int subPosition = 0;
int subHeader = 0;
for(List section: sections) {
boolean validHeader = headers.get(subHeader) != null;
if(position == subPosition && validHeader) {
return VIEW_TYPE_HEADER;
}
int headerOffset = validHeader ? 1 : 0;
if(position < (subPosition + section.size() + headerOffset)) {
return getItemViewType(section.get(position - subPosition - headerOffset));
}
subPosition += section.size();
if(validHeader) {
subPosition += 1;
}
subHeader++;
}
return -1;
}
public UpdateViewHolder onCreateHeaderHolder(ViewGroup parent) {
return new UpdateViewHolder(new BasicHeaderView(context));
}
public void onBindHeaderHolder(UpdateViewHolder holder, String header) {
UpdateView view = holder.getUpdateView();
if(view != null) {
view.setObject(header);
}
}
public T getItemForPosition(int position) {
if(sections.size() == 1 && !singleSectionHeader) {
return sections.get(0).get(position);
}
int subPosition = 0;
for(List section: sections) {
if(position == subPosition) {
return null;
}
if(position <= (subPosition + section.size())) {
return section.get(position - subPosition - 1);
}
subPosition += section.size() + 1;
}
return null;
}
public int getItemPosition(T item) {
if(sections.size() == 1 && !singleSectionHeader) {
return sections.get(0).indexOf(item);
}
int subPosition = 0;
for(List section: sections) {
subPosition += section.size() + 1;
int position = section.indexOf(item);
if(position != -1) {
return position + subPosition;
}
}
return -1;
}
public void setOnItemClickedListener(OnItemClickedListener onItemClickedListener) {
this.onItemClickedListener = onItemClickedListener;
}
public void addSelected(T item) {
selected.add(item);
}
public List getSelected() {
List selected = new ArrayList<>();
selected.addAll(this.selected);
return selected;
}
public void clearSelected() {
// TODO: This needs to work with multiple sections
for(T item: selected) {
int index = sections.get(0).indexOf(item);
if(singleSectionHeader) {
index++;
}
}
selected.clear();
for(UpdateView updateView: selectedViews) {
updateView.setChecked(false);
}
}
public void removeItem(T item) {
int subPosition = 0;
for(List section: sections) {
if(sections.size() > 1 || singleSectionHeader) {
subPosition++;
}
int index = section.indexOf(item);
if (index != -1) {
section.remove(item);
notifyItemRemoved(subPosition + index);
break;
}
subPosition += section.size();
}
}
public abstract UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType);
public abstract void onBindViewHolder(UpdateViewHolder holder, T item, int viewType);
public abstract int getItemViewType(T item);
public void setCheckable(boolean checkable) {
this.checkable = checkable;
}
public void setChecked(UpdateView updateView, boolean checked) {
updateView.setChecked(checked);
}
private void startActionMode(final UpdateView.UpdateViewHolder holder) {
final UpdateView updateView = holder.getUpdateView();
if (context instanceof SubsonicFragmentActivity && currentActionMode == null) {
final SubsonicFragmentActivity fragmentActivity = (SubsonicFragmentActivity) context;
Toolbar toolbar = fragmentActivity.getActiveToolbar();
toolbar.startActionMode(new ActionMode.Callback() {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
currentActionMode = mode;
fragmentActivity.onCreateOptionsMenu(menu);
T item = holder.getItem();
selected.add(item);
selectedViews.add(updateView);
setChecked(updateView, true);
mode.setTitle(context.getResources().getString(R.string.select_album_n_selected, selected.size()));
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
TypedValue typedValue = new TypedValue();
Resources.Theme theme = context.getTheme();
theme.resolveAttribute(R.attr.colorPrimaryDark, typedValue, true);
int colorPrimaryDark = typedValue.data;
Window window = ((SubsonicFragmentActivity) context).getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.setStatusBarColor(colorPrimaryDark);
}
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
if (fragmentActivity.onOptionsItemSelected(item)) {
currentActionMode.finish();
return true;
} else {
return false;
}
}
@Override
public void onDestroyActionMode(ActionMode mode) {
currentActionMode = null;
selected.clear();
for(UpdateView updateView: selectedViews) {
updateView.setChecked(false);
}
selectedViews.clear();
Window window = ((SubsonicFragmentActivity) context).getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
});
}
}
public interface OnItemClickedListener {
void onItemClicked(T item);
void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView updateView, T item);
boolean onContextItemSelected(MenuItem menuItem, UpdateView updateView, T item);
}
}