/* * Artcodes recognises a different marker scheme that allows the * creation of aesthetically pleasing, even beautiful, codes. * Copyright (C) 2013-2016 The University of Nottingham * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package uk.ac.horizon.artcodes.adapter; import android.content.Context; import android.databinding.ViewDataBinding; import android.util.SparseArray; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import uk.ac.horizon.artcodes.R; import uk.ac.horizon.artcodes.activity.ArtcodeActivity; import uk.ac.horizon.artcodes.activity.ExperienceActivity; import uk.ac.horizon.artcodes.databinding.ExperienceCardBinding; import uk.ac.horizon.artcodes.databinding.GroupHeaderBinding; import uk.ac.horizon.artcodes.model.Experience; import uk.ac.horizon.artcodes.server.ArtcodeServer; import uk.ac.horizon.artcodes.server.LoadCallback; public class ExperienceGroupAdapter extends GridAdapter { public class Group { private String name; private View.OnClickListener clickListener; private final SparseArray<Experience> experiences = new SparseArray<>(); private List<String> ids = new ArrayList<>(); public void setClickListener(View.OnClickListener clickListener) { this.clickListener = clickListener; } private void add(int index, Experience experience) { if (isEmpty()) { experiences.append(index, experience); adapter.notifyItemRangeInserted(indexOf(name), 2); } else { final Experience existing = experiences.get(index); if (existing == null) { experiences.append(index, experience); adapter.notifyItemInserted(indexOf(experience)); } else { experiences.append(index, experience); adapter.notifyItemChanged(indexOf(experience)); } } } public boolean isEmpty() { return experiences.size() == 0; } public void setIds(List<String> ids) { this.ids = ids; update(); } public boolean showMore() { return clickListener != null && ids.size() > layoutManager.getSpanCount(); } private void update() { int index = 0; List<String> idList = ids; if(showMore()) { idList = ids.subList(0, layoutManager.getSpanCount()); } for (final String uri : idList) { if(experiences.get(index) == null) { final int experienceIndex = index; loadStarted(); server.loadExperience(uri, new LoadCallback<Experience>() { @Override public void loaded(final Experience experience) { loadFinished(); add(experienceIndex, experience); } @Override public void error(Throwable e) { showError(context.getString(R.string.connection_error)); loadFinished(); } }); } index++; } } } private static final int EXPERIENCE_VIEW = 3; public static final int GROUP_VIEW = 9; private final String[] ordering = {"recent", "starred", "nearby", "featured", "new", "popular"}; private final Map<String, Group> groups = new HashMap<>(); private final ArtcodeServer server; public ExperienceGroupAdapter(Context context, ArtcodeServer server) { super(context); this.server = server; } @Override protected void columnsChanged() { for(Group group: groups.values()) { if(group.clickListener != null) { group.update(); } } } @Override public ViewDataBinding createBinding(final ViewGroup parent, final int viewType) { if (viewType == EXPERIENCE_VIEW) { return ExperienceCardBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); } return GroupHeaderBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); } @Override public void bind(final int position, final ViewDataBinding binding) { Object item = getItemAt(position); if (binding instanceof ExperienceCardBinding && item instanceof Experience) { final Experience experience = (Experience) item; final ExperienceCardBinding experienceCardBinding = (ExperienceCardBinding) binding; experienceCardBinding.setExperience((Experience) item); experienceCardBinding.getRoot().setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ExperienceActivity.start(context, experience); } }); experienceCardBinding.scanButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ArtcodeActivity.start(context, experience); } }); } else if (binding instanceof GroupHeaderBinding && item instanceof Group) { Group group = ((Group) item); ((GroupHeaderBinding) binding).title.setText(getStringResourceByName(context, group.name)); if (group.showMore()) { binding.getRoot().setOnClickListener(group.clickListener); ((GroupHeaderBinding) binding).moreButton.setOnClickListener(group.clickListener); ((GroupHeaderBinding) binding).moreButton.setVisibility(View.VISIBLE); } else { binding.getRoot().setOnClickListener(null); ((GroupHeaderBinding) binding).moreButton.setVisibility(View.INVISIBLE); } } } @Override protected int getSpan(final int position) { int viewType = adapter.getItemViewType(position); if (viewType == EXPERIENCE_VIEW) { return 1; } else { return layoutManager.getSpanCount(); } } @Override public int getViewCount() { int size = 0; for (String groupName : ordering) { Group group = groups.get(groupName); if (group != null && !group.isEmpty()) { size += 1; size += group.experiences.size(); } } return size; } public Object getItemAt(int position) { int currentPosition = position; for (String groupName : ordering) { Group group = groups.get(groupName); if (group != null && !group.isEmpty()) { if (currentPosition == 0) { return group; } currentPosition -= 1; if (currentPosition < group.experiences.size()) { return group.experiences.get(group.experiences.keyAt(currentPosition)); } currentPosition -= group.experiences.size(); } } return null; } @Override public int getViewType(int position) { Object item = getItemAt(position); if (item instanceof Experience) { return EXPERIENCE_VIEW; } return GROUP_VIEW; } public Group getGroup(String name) { Group group = groups.get(name); if (group == null) { group = new Group(); group.name = name; groups.put(name, group); } return group; } private int indexOf(String groupName) { int index = 0; for (String aGroup : ordering) { if (aGroup.equals(groupName)) { return index; } Group group = groups.get(aGroup); if (group != null && !group.isEmpty()) { index += 1; index += group.experiences.size(); } } return -1; } private int indexOf(Experience experience) { int index = 0; for (String groupName : ordering) { Group group = groups.get(groupName); if (group != null && !group.isEmpty()) { index += 1; int experienceIndex = group.experiences.indexOfValue(experience); if (experienceIndex > -1) { return index + experienceIndex; } index += group.experiences.size(); } } return -1; } public LoadCallback<List<String>> getCallback(final String name, final View.OnClickListener clickListener) { return new LoadCallback<List<String>>() { @Override public void loaded(List<String> item) { Group group = getGroup(name); group.setClickListener(clickListener); group.setIds(item); loadFinished(); } @Override public void error(Throwable e) { showError(context.getString(R.string.connection_error)); loadFinished(); } }; } public LoadCallback<Map<String, List<String>>> getCallback() { return new LoadCallback<Map<String, List<String>>>() { @Override public void loaded(Map<String, List<String>> item) { for (String name : item.keySet()) { Group group = getGroup(name); group.setIds(item.get(name)); } loadFinished(); } @Override public void error(Throwable e) { showError(context.getString(R.string.connection_error)); loadFinished(); } }; } private String getStringResourceByName(Context context, String aString) { String packageName = context.getPackageName(); int resId = context.getResources().getIdentifier(aString, "string", packageName); if (resId == 0) { return aString.substring(0, 1).toUpperCase() + aString.substring(1); } return context.getString(resId); } }