package com.seafile.seadroid2.ui.adapter;
import android.util.SparseBooleanArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.google.common.collect.Lists;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
import com.seafile.seadroid2.R;
import com.seafile.seadroid2.SeadroidApplication;
import com.seafile.seadroid2.data.DataManager;
import com.seafile.seadroid2.data.SeafCachedFile;
import com.seafile.seadroid2.data.SeafDirent;
import com.seafile.seadroid2.data.SeafGroup;
import com.seafile.seadroid2.data.SeafItem;
import com.seafile.seadroid2.data.SeafRepo;
import com.seafile.seadroid2.transfer.DownloadTaskInfo;
import com.seafile.seadroid2.ui.AnimateFirstDisplayListener;
import com.seafile.seadroid2.ui.NavContext;
import com.seafile.seadroid2.ui.WidgetUtils;
import com.seafile.seadroid2.ui.activity.BrowserActivity;
import com.seafile.seadroid2.util.Utils;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class SeafItemAdapter extends BaseAdapter {
private ArrayList<SeafItem> items;
private BrowserActivity mActivity;
private boolean repoIsEncrypted;
private boolean actionModeOn;
private SparseBooleanArray mSelectedItemsIds;
private List<Integer> mSelectedItemsPositions = Lists.newArrayList();
private List<SeafDirent> mSelectedItemsValues = Lists.newArrayList();
/** DownloadTask instance container **/
private List<DownloadTaskInfo> mDownloadTaskInfos;
public SeafItemAdapter(BrowserActivity activity) {
mActivity = activity;
items = Lists.newArrayList();
mSelectedItemsIds = new SparseBooleanArray();
}
/** sort files type */
public static final int SORT_BY_NAME = 9;
/** sort files type */
public static final int SORT_BY_LAST_MODIFIED_TIME = 10;
/** sort files order */
public static final int SORT_ORDER_ASCENDING = 11;
/** sort files order */
public static final int SORT_ORDER_DESCENDING = 12;
@Override
public int getCount() {
return items.size();
}
@Override
public boolean isEmpty() {
return items.isEmpty();
}
/**
* To refresh downloading status of {@link com.seafile.seadroid2.ui.fragment.ReposFragment#mListView},
* use this method to update data set.
* <p>
* This method should be called after the "Download folder" menu was clicked.
*
* @param newList
*/
public void setDownloadTaskList(List<DownloadTaskInfo> newList) {
if (!equalLists(newList, mDownloadTaskInfos)) {
this.mDownloadTaskInfos = newList;
// redraw the list
notifyDataSetChanged();
}
}
/**
* Compare two lists
*
* @param newList
* @param oldList
* @return true if the two lists are equal,
* false, otherwise.
*/
private boolean equalLists(List<DownloadTaskInfo> newList, List<DownloadTaskInfo> oldList) {
if (newList == null && oldList == null)
return true;
if ((newList == null && oldList != null)
|| newList != null && oldList == null
|| newList.size() != oldList.size())
return false;
return newList.equals(oldList);
}
public void addEntry(SeafItem entry) {
items.add(entry);
// Collections.sort(items);
notifyDataSetChanged();
}
public void add(SeafItem entry) {
items.add(entry);
}
public void notifyChanged() {
notifyDataSetChanged();
}
@Override
public SeafItem getItem(int position) {
return items.get(position);
}
public void setItems(List<SeafDirent> dirents) {
items.clear();
items.addAll(dirents);
this.mSelectedItemsIds.clear();
this.mSelectedItemsPositions.clear();
this.mSelectedItemsValues.clear();
}
public void deselectAllItems() {
mSelectedItemsIds.clear();
mSelectedItemsPositions.clear();
mSelectedItemsValues.clear();
notifyDataSetChanged();
}
public void selectAllItems() {
mSelectedItemsIds.clear();
mSelectedItemsPositions.clear();
mSelectedItemsValues.clear();
for (int i = 0; i < items.size(); i++) {
mSelectedItemsIds.put(i, true);
mSelectedItemsPositions.add(i);
mSelectedItemsValues.add((SeafDirent) items.get(i));
}
notifyDataSetChanged();
}
@Override
public long getItemId(int position) {
return position;
}
public void clear() {
items.clear();
}
public boolean areAllItemsSelectable() {
return false;
}
public boolean isEnable(int position) {
SeafItem item = items.get(position);
return !(item instanceof SeafGroup);
}
public boolean isClickable(int position) {
SeafItem item = items.get(position);
return !(item instanceof SeafGroup);
}
public int getViewTypeCount() {
return 2;
}
public int getItemViewType(int position) {
SeafItem item = items.get(position);
if (item instanceof SeafGroup)
return 0;
else
return 1;
}
private View getRepoView(final SeafRepo repo, View convertView, ViewGroup parent) {
View view = convertView;
Viewholder viewHolder;
if (convertView == null) {
view = LayoutInflater.from(mActivity).inflate(R.layout.list_item_entry, null);
TextView title = (TextView) view.findViewById(R.id.list_item_title);
TextView subtitle = (TextView) view.findViewById(R.id.list_item_subtitle);
ImageView multiSelect = (ImageView) view.findViewById(R.id.list_item_multi_select_btn);
ImageView icon = (ImageView) view.findViewById(R.id.list_item_icon);
RelativeLayout action = (RelativeLayout) view.findViewById(R.id.expandable_toggle_button);
ImageView downloadStatusIcon = (ImageView) view.findViewById(R.id.list_item_download_status_icon);
ProgressBar progressBar = (ProgressBar) view.findViewById(R.id.list_item_download_status_progressbar);
viewHolder = new Viewholder(title, subtitle, multiSelect, icon, action, downloadStatusIcon, progressBar);
view.setTag(viewHolder);
} else {
viewHolder = (Viewholder) convertView.getTag();
}
viewHolder.action.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mActivity.showRepoBottomSheet(repo);
}
});
viewHolder.multiSelect.setVisibility(View.GONE);
viewHolder.downloadStatusIcon.setVisibility(View.GONE);
viewHolder.progressBar.setVisibility(View.GONE);
viewHolder.title.setText(repo.getTitle());
viewHolder.subtitle.setText(repo.getSubtitle());
ImageLoader.getInstance().displayImage("drawable://" + repo.getIcon(), viewHolder.icon, WidgetUtils.iconOptions);
if (repo.hasWritePermission()) {
viewHolder.action.setVisibility(View.VISIBLE);
}else {
viewHolder.action.setVisibility(View.INVISIBLE);
}
return view;
}
private View getGroupView(SeafGroup group) {
View view = LayoutInflater.from(mActivity).inflate(R.layout.group_item, null);
TextView tv = (TextView) view.findViewById(R.id.textview_groupname);
String groupTitle = group.getTitle();
if ("Organization".equals(groupTitle)) {
groupTitle = mActivity.getString(R.string.shared_with_all);
}
tv.setText(groupTitle);
return view;
}
private View getDirentView(final SeafDirent dirent, View convertView, ViewGroup parent, final int position) {
View view = convertView;
final Viewholder viewHolder;
if (convertView == null) {
view = LayoutInflater.from(mActivity).inflate(R.layout.list_item_entry, null);
TextView title = (TextView) view.findViewById(R.id.list_item_title);
TextView subtitle = (TextView) view.findViewById(R.id.list_item_subtitle);
ImageView icon = (ImageView) view.findViewById(R.id.list_item_icon);
ImageView multiSelect = (ImageView) view.findViewById(R.id.list_item_multi_select_btn);
RelativeLayout action = (RelativeLayout) view.findViewById(R.id.expandable_toggle_button);
ImageView downloadStatusIcon = (ImageView) view.findViewById(R.id.list_item_download_status_icon);
ProgressBar progressBar = (ProgressBar) view.findViewById(R.id.list_item_download_status_progressbar);
viewHolder = new Viewholder(title, subtitle, multiSelect, icon, action, downloadStatusIcon, progressBar);
view.setTag(viewHolder);
} else {
viewHolder = (Viewholder) convertView.getTag();
}
viewHolder.action.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (dirent.isDir())
mActivity.showDirBottomSheet(dirent.getTitle(), (SeafDirent) getItem(position));
else
mActivity.showFileBottomSheet(dirent.getTitle(), (SeafDirent) getItem(position));
}
});
if (actionModeOn) {
viewHolder.multiSelect.setVisibility(View.VISIBLE);
if (mSelectedItemsIds.get(position)) {
viewHolder.multiSelect.setImageResource(R.drawable.multi_select_item_checked);
} else
viewHolder.multiSelect.setImageResource(R.drawable.multi_select_item_unchecked);
viewHolder.multiSelect.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!mSelectedItemsIds.get(position)) {
viewHolder.multiSelect.setImageResource(R.drawable.multi_select_item_checked);
mSelectedItemsIds.put(position, true);
mSelectedItemsPositions.add(position);
mSelectedItemsValues.add(dirent);
} else {
viewHolder.multiSelect.setImageResource(R.drawable.multi_select_item_unchecked);
mSelectedItemsIds.delete(position);
mSelectedItemsPositions.remove(Integer.valueOf(position));
mSelectedItemsValues.remove(dirent);
}
mActivity.onItemSelected();
}
});
} else
viewHolder.multiSelect.setVisibility(View.GONE);
viewHolder.title.setText(dirent.getTitle());
if (dirent.isDir()) {
viewHolder.downloadStatusIcon.setVisibility(View.GONE);
viewHolder.progressBar.setVisibility(View.GONE);
viewHolder.subtitle.setText(dirent.getSubtitle());
if (repoIsEncrypted) {
viewHolder.action.setVisibility(View.GONE);
} else
viewHolder.action.setVisibility(View.VISIBLE);
viewHolder.icon.setImageResource(dirent.getIcon());
} else {
viewHolder.downloadStatusIcon.setVisibility(View.GONE);
viewHolder.progressBar.setVisibility(View.GONE);
viewHolder.action.setVisibility(View.VISIBLE);
setFileView(dirent, viewHolder, position);
}
return view;
}
/**
* use to refresh view of {@link com.seafile.seadroid2.ui.fragment.ReposFragment #mPullRefreshListView}
* <p>
* <h5>when to show download status icons</h5>
* if the dirent is a file and already cached, show cached icon.</br>
* if the dirent is a file and waiting to download, show downloading icon.</br>
* if the dirent is a file and is downloading, show indeterminate progressbar.</br>
* ignore directories and repos.</br>
*
* @param dirent
* @param viewHolder
* @param position
*/
private void setFileView(SeafDirent dirent, Viewholder viewHolder, int position) {
NavContext nav = mActivity.getNavContext();
DataManager dataManager = mActivity.getDataManager();
String repoName = nav.getRepoName();
String repoID = nav.getRepoID();
String filePath = Utils.pathJoin(nav.getDirPath(), dirent.name);
if (repoName == null || repoID == null)
return;
File file = dataManager.getLocalRepoFile(repoName, repoID, filePath);
boolean cacheExists = false;
if (file.exists()) {
SeafCachedFile cf = dataManager.getCachedFile(repoName, repoID, filePath);
String subtitle = null;
subtitle = dirent.getSubtitle();
if (cf != null) {
cacheExists = true;
}
// show file download finished
viewHolder.downloadStatusIcon.setVisibility(View.VISIBLE);
viewHolder.downloadStatusIcon.setImageResource(R.drawable.list_item_download_finished);
viewHolder.subtitle.setText(subtitle);
viewHolder.progressBar.setVisibility(View.GONE);
} else {
int downloadStatusIcon = R.drawable.list_item_download_waiting;
if (mDownloadTaskInfos != null) {
for (DownloadTaskInfo downloadTaskInfo : mDownloadTaskInfos) {
// use repoID and path to identify the task
if (downloadTaskInfo.repoID.equals(repoID)
&& downloadTaskInfo.pathInRepo.equals(filePath)) {
switch (downloadTaskInfo.state) {
case INIT:
case FAILED:
downloadStatusIcon = R.drawable.list_item_download_waiting;
viewHolder.downloadStatusIcon.setVisibility(View.VISIBLE);
viewHolder.progressBar.setVisibility(View.GONE);
break;
case CANCELLED:
viewHolder.downloadStatusIcon.setVisibility(View.GONE);
viewHolder.progressBar.setVisibility(View.GONE);
break;
case TRANSFERRING:
viewHolder.downloadStatusIcon.setVisibility(View.GONE);
viewHolder.progressBar.setVisibility(View.VISIBLE);
break;
case FINISHED:
downloadStatusIcon = R.drawable.list_item_download_finished;
viewHolder.downloadStatusIcon.setVisibility(View.VISIBLE);
viewHolder.progressBar.setVisibility(View.GONE);
break;
default:
downloadStatusIcon = R.drawable.list_item_download_waiting;
break;
}
}
}
} else {
viewHolder.downloadStatusIcon.setVisibility(View.GONE);
viewHolder.progressBar.setVisibility(View.GONE);
}
viewHolder.downloadStatusIcon.setImageResource(downloadStatusIcon);
viewHolder.subtitle.setText(dirent.getSubtitle());
}
if (Utils.isViewableImage(file.getName())) {
DisplayImageOptions options = new DisplayImageOptions.Builder()
.extraForDownloader(dataManager.getAccount())
.delayBeforeLoading(500)
.resetViewBeforeLoading(true)
.showImageOnLoading(R.drawable.file_image)
.showImageForEmptyUri(R.drawable.file_image)
.showImageOnFail(R.drawable.file_image)
.cacheInMemory(true)
.cacheOnDisk(true)
.considerExifParams(true)
.build();
ImageLoadingListener animateFirstListener = new AnimateFirstDisplayListener();
String url = dataManager.getThumbnailLink(repoName, repoID, filePath, getThumbnailWidth());
if (url == null) {
ImageLoader.getInstance().displayImage("drawable://" + dirent.getIcon(), viewHolder.icon, WidgetUtils.iconOptions);
} else
ImageLoader.getInstance().displayImage(url, viewHolder.icon, options, animateFirstListener);
} else {
ImageLoader.getInstance().displayImage("drawable://" + dirent.getIcon(), viewHolder.icon, WidgetUtils.iconOptions);
}
}
private View getCacheView(SeafCachedFile item, View convertView, ViewGroup parent) {
View view = convertView;
Viewholder viewHolder;
if (convertView == null) {
view = LayoutInflater.from(mActivity).inflate(R.layout.list_item_entry, null);
TextView title = (TextView) view.findViewById(R.id.list_item_title);
TextView subtitle = (TextView) view.findViewById(R.id.list_item_subtitle);
ImageView multiSelect = (ImageView) view.findViewById(R.id.list_item_multi_select_btn);
ImageView icon = (ImageView) view.findViewById(R.id.list_item_icon);
RelativeLayout action = (RelativeLayout) view.findViewById(R.id.expandable_toggle_button);
ImageView downloadStatusIcon = (ImageView) view.findViewById(R.id.list_item_download_status_icon);
ProgressBar progressBar = (ProgressBar) view.findViewById(R.id.list_item_download_status_progressbar);
viewHolder = new Viewholder(title, subtitle, multiSelect, icon, action, downloadStatusIcon, progressBar);
view.setTag(viewHolder);
} else {
viewHolder = (Viewholder) convertView.getTag();
}
viewHolder.downloadStatusIcon.setVisibility(View.VISIBLE);
viewHolder.downloadStatusIcon.setImageResource(R.drawable.list_item_download_finished);
viewHolder.progressBar.setVisibility(View.GONE);
viewHolder.title.setText(item.getTitle());
viewHolder.subtitle.setText(item.getSubtitle());
ImageLoader.getInstance().displayImage("drawable://" + item.getIcon(), viewHolder.icon, WidgetUtils.iconOptions);
viewHolder.action.setVisibility(View.INVISIBLE);
return view;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
SeafItem item = items.get(position);
if (item instanceof SeafRepo) {
return getRepoView((SeafRepo) item, convertView, parent);
} else if (item instanceof SeafGroup) {
return getGroupView((SeafGroup) item);
} else if (item instanceof SeafCachedFile) {
return getCacheView((SeafCachedFile) item, convertView, parent);
} else {
return getDirentView((SeafDirent) item, convertView, parent, position);
}
}
public void setActionModeOn(boolean actionModeOn) {
this.actionModeOn = actionModeOn;
}
public void toggleSelection(int position) {
if (mSelectedItemsIds.get(position)) {
// unselected
mSelectedItemsIds.delete(position);
mSelectedItemsPositions.remove(Integer.valueOf(position));
mSelectedItemsValues.remove(items.get(position));
} else {
mSelectedItemsIds.put(position, true);
mSelectedItemsPositions.add(position);
mSelectedItemsValues.add((SeafDirent) items.get(position));
}
mActivity.onItemSelected();
notifyDataSetChanged();
}
public int getCheckedItemCount() {
return mSelectedItemsIds.size();
}
public List<SeafDirent> getSelectedItemsValues() {
return mSelectedItemsValues;
}
private class Viewholder {
TextView title, subtitle;
ImageView icon, multiSelect, downloadStatusIcon; // downloadStatusIcon used to show file downloading status, it is invisible by default
ProgressBar progressBar;
RelativeLayout action;
public Viewholder(TextView title,
TextView subtitle,
ImageView multiSelect,
ImageView icon,
RelativeLayout action,
ImageView downloadStatusIcon,
ProgressBar progressBar
) {
super();
this.icon = icon;
this.multiSelect = multiSelect;
this.action = action;
this.title = title;
this.subtitle = subtitle;
this.downloadStatusIcon = downloadStatusIcon;
this.progressBar = progressBar;
}
}
private int getThumbnailWidth() {
return (int) SeadroidApplication.getAppContext().getResources().getDimension(R.dimen.lv_icon_width);
}
public void setEncryptedRepo(boolean encrypted) {
repoIsEncrypted = encrypted;
}
/**
* Sorts the given list by type of {@link #SORT_BY_NAME} or {@link #SORT_BY_LAST_MODIFIED_TIME},
* and by order of {@link #SORT_ORDER_ASCENDING} or {@link #SORT_ORDER_DESCENDING}
*/
public void sortFiles(int type, int order) {
List<SeafGroup> groups = Lists.newArrayList();
List<SeafCachedFile> cachedFiles = Lists.newArrayList();
List<SeafDirent> folders = Lists.newArrayList();
List<SeafDirent> files = Lists.newArrayList();
SeafGroup group = null;
for (SeafItem item : items) {
if (item instanceof SeafGroup) {
group = (SeafGroup) item;
groups.add(group);
} else if (item instanceof SeafRepo) {
if (group == null)
continue;
group.addIfAbsent((SeafRepo) item);
} else if (item instanceof SeafCachedFile) {
cachedFiles.add(((SeafCachedFile) item));
} else {
if (((SeafDirent) item).isDir())
folders.add(((SeafDirent) item));
else
files.add(((SeafDirent) item));
}
}
items.clear();
// sort SeafGroups and SeafRepos
for (SeafGroup sg : groups) {
sg.sortByType(type, order);
items.add(sg);
items.addAll(sg.getRepos());
}
// sort SeafDirents
if (type == SORT_BY_NAME) {
// sort by name, in ascending order
Collections.sort(folders, new SeafDirent.DirentNameComparator());
Collections.sort(files, new SeafDirent.DirentNameComparator());
if (order == SORT_ORDER_DESCENDING) {
Collections.reverse(folders);
Collections.reverse(files);
}
} else if (type == SORT_BY_LAST_MODIFIED_TIME) {
// sort by last modified time, in ascending order
Collections.sort(folders, new SeafDirent.DirentLastMTimeComparator());
Collections.sort(files, new SeafDirent.DirentLastMTimeComparator());
if (order == SORT_ORDER_DESCENDING) {
Collections.reverse(folders);
Collections.reverse(files);
}
}
// Adds the objects in the specified collection to this ArrayList
items.addAll(cachedFiles);
items.addAll(folders);
items.addAll(files);
}
}