package org.sugr.gearshift.ui;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.database.Cursor;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import org.sugr.gearshift.G;
import org.sugr.gearshift.G.FilterBy;
import org.sugr.gearshift.R;
import org.sugr.gearshift.core.TransmissionProfile;
import org.sugr.gearshift.core.TransmissionSession;
import org.sugr.gearshift.service.DataService;
import org.sugr.gearshift.ui.loader.TorrentTrafficLoader;
import org.sugr.gearshift.ui.settings.SettingsActivity;
import org.sugr.gearshift.ui.util.Colorizer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.TreeSet;
public class TorrentListMenuFragment extends Fragment
implements TorrentListNotificationInterface, TransmissionProfileListNotificationInterface {
private RecyclerView filterList;
private FilterAdapter filterAdapter;
private enum Type {
PROFILE_SELECTOR, PROFILE, FILTER, DIRECTORY, TRACKER,
SESSION_DATA_HEADER
}
private static final String PROFILE_SELECTOR_KEY = "profile_selector";
private static final String FILTERS_HEADER_KEY = "filters_header";
private static final String DIRECTORIES_HEADER_KEY = "directories_header";
private static final String TRACKERS_HEADER_KEY = "trackers_header";
private TreeSet<String> directories = new TreeSet<>(G.SIMPLE_STRING_COMPARATOR);
private TreeSet<String> trackers = new TreeSet<>(G.SIMPLE_STRING_COMPARATOR);
private HashMap<String, ListItem> listItemMap = new HashMap<>();
private SharedPreferences sharedPrefs;
private BroadcastReceiver sessionReceiver;
private Handler closeHandler = new Handler();
private Runnable closeRunnable = new Runnable() {
@Override public void run() {
if (getActivity() == null) {
return;
}
DrawerLayout drawer = ((DrawerLayout) getActivity().findViewById(R.id.drawer_layout));
drawer.closeDrawer(getActivity().findViewById(R.id.sliding_menu_frame));
}
};
private boolean filtersChanged;
private boolean initialProfilesLoaded = false;
private OnSharedPreferenceChangeListener sharedPrefListener = new OnSharedPreferenceChangeListener() {
@Override public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
if (key.matches(G.PREF_FILTER_MATCH_TEST)) {
filtersChanged = true;
}
}
};
private LoaderManager.LoaderCallbacks<TorrentTrafficLoader.TorrentTrafficOutputData> torrentTrafficLoaderCallbacks
= new LoaderManager.LoaderCallbacks<TorrentTrafficLoader.TorrentTrafficOutputData>() {
@Override public Loader<TorrentTrafficLoader.TorrentTrafficOutputData> onCreateLoader(int id, Bundle bundle) {
if (id == G.TORRENT_MENU_TRAFFIC_LOADER_ID) {
TransmissionProfileInterface context = (TransmissionProfileInterface) getActivity();
if (context == null || context.getProfile() == null) {
return null;
}
boolean showStatus = sharedPrefs.getBoolean(G.PREF_SHOW_STATUS, true);
boolean directoriesEnabled = sharedPrefs.getBoolean(G.PREF_FILTER_DIRECTORIES, true);
boolean trackersEnabled = sharedPrefs.getBoolean(G.PREF_FILTER_TRACKERS, false);
return new TorrentTrafficLoader(getActivity(), context.getProfile().getId(),
!showStatus, directoriesEnabled, trackersEnabled);
}
return null;
}
@Override public void onLoadFinished(Loader<TorrentTrafficLoader.TorrentTrafficOutputData> loader, TorrentTrafficLoader.TorrentTrafficOutputData data) {
boolean updateDirectoryFilter = false;
boolean updateTrackerFilter = false;
boolean checkSelected = false;
TransmissionSessionInterface context = (TransmissionSessionInterface) getActivity();
if (context == null) {
return;
}
if (context.getSession() == null) {
G.logD("No session, removing directories and tracker filters");
int[][] insertRanges = new int[][]{new int[]{-1, 1}, new int[]{-1, 1}};
Iterator<ListItem> iter = filterAdapter.itemData.iterator();
directories.clear();
trackers.clear();
int index = 0;
while (iter.hasNext()) {
ListItem item = iter.next();
if (DIRECTORIES_HEADER_KEY.equals(item.getValueString())
|| TRACKERS_HEADER_KEY.equals(item.getValueString())
|| item.getType() == Type.DIRECTORY
|| item.getType() == Type.TRACKER) {
if (insertRanges[0][0] == -1 && DIRECTORIES_HEADER_KEY.equals(item.getValueString())) {
insertRanges[0][0] = index;
insertRanges[0][1]++;
}
if (insertRanges[1][0] == -1 && TRACKERS_HEADER_KEY.equals(item.getValueString())) {
insertRanges[1][0] = index;
insertRanges[1][1]++;
}
if (item.getType() == Type.DIRECTORY) {
insertRanges[0][1]++;
}
if (item.getType() == Type.TRACKER) {
insertRanges[1][1]++;
}
iter.remove();
}
index++;
}
if (insertRanges[0][0] != -1) {
filterAdapter.notifyItemRangeInserted(insertRanges[0][0], insertRanges[0][1]);
}
if (insertRanges[1][0] != -1) {
filterAdapter.notifyItemRangeInserted(insertRanges[1][0], insertRanges[1][1]);
}
return;
}
int[][] insertRanges = new int[][]{new int[]{-1, 0}, new int[]{-1, 0}};
if (data.directories != null) {
String dir = sharedPrefs.getString(G.PREF_LIST_DIRECTORY, "");
boolean equalDirectories = true;
List<String> normalizedDirs = new ArrayList<>();
for (String d : data.directories) {
if (d.length() == 0) {
continue;
}
while (d.charAt(d.length() - 1) == '/') {
if (d.length() == 1) {
break;
}
d = d.substring(0, d.length() - 1);
}
if (!normalizedDirs.contains(d)) {
normalizedDirs.add(d);
}
}
boolean currentDirectoryTorrents = dir.equals("") || normalizedDirs.contains(dir);
if (normalizedDirs.size() != directories.size()) {
equalDirectories = false;
} else {
for (String d : normalizedDirs) {
if (!directories.contains(d)) {
equalDirectories = false;
break;
}
}
}
if (!equalDirectories) {
directories.clear();
directories.addAll(normalizedDirs);
int[] range = removeDirectoriesFilters();
if (range[0] != -1) {
filterAdapter.notifyItemRangeRemoved(range[0], range[1]);
}
if (directories.size() > 1) {
int position = filterAdapter.itemData.indexOf(listItemMap.get(TRACKERS_HEADER_KEY));
if (position == -1) {
position = filterAdapter.itemData.size();
}
if (!listItemMap.containsKey(DIRECTORIES_HEADER_KEY)) {
new ListItem(Type.SESSION_DATA_HEADER, DIRECTORIES_HEADER_KEY, R.string.menu_directories_header);
}
ListItem header = listItemMap.get(DIRECTORIES_HEADER_KEY);
insertRanges[0][0] = position;
filterAdapter.itemData.add(position++, header);
insertRanges[0][1]++;
for (String d : directories) {
ListItem di = getDirectoryItem(d);
if (di != null) {
filterAdapter.itemData.add(position++, di);
insertRanges[0][1]++;
}
}
updateDirectoryFilter = !currentDirectoryTorrents;
} else {
updateDirectoryFilter = true;
}
checkSelected = true;
}
} else {
int[] range = removeDirectoriesFilters();
if (range[0] != -1) {
filterAdapter.notifyItemRangeRemoved(range[0], range[1]);
}
if (!sharedPrefs.getString(G.PREF_LIST_DIRECTORY, "").equals("")) {
updateDirectoryFilter = true;
}
}
if (data.trackers != null) {
String track = sharedPrefs.getString(G.PREF_LIST_TRACKER, "");
boolean equalTrackers = true;
boolean currentTrackerTorrents = track.equals("") || data.trackers.contains(track)
|| G.FILTER_UNTRACKED.equals(track);
if (data.trackers.size() != trackers.size()) {
equalTrackers = false;
} else {
for (String t : data.trackers) {
if (!trackers.contains(t)) {
equalTrackers = false;
break;
}
}
}
if (!equalTrackers) {
trackers.clear();
trackers.addAll(data.trackers);
int[] range = removeTrackersFilters();
if (range[0] != -1) {
filterAdapter.notifyItemRangeRemoved(range[0], range[1]);
}
if (trackers.size() > 0 && sharedPrefs.getBoolean(G.PREF_FILTER_UNTRACKED, false)
|| trackers.size() > 1) {
if (!listItemMap.containsKey(TRACKERS_HEADER_KEY)) {
new ListItem(Type.SESSION_DATA_HEADER, TRACKERS_HEADER_KEY, R.string.menu_trackers_header);
}
ListItem header = listItemMap.get(TRACKERS_HEADER_KEY);
insertRanges[1][0] = filterAdapter.itemData.size();
filterAdapter.itemData.add(header);
insertRanges[1][1]++;
for (String t : trackers) {
filterAdapter.itemData.add(getTrackerItem(t));
insertRanges[1][1]++;
}
if (sharedPrefs.getBoolean(G.PREF_FILTER_UNTRACKED, false)) {
ListItem untracked = new ListItem(Type.TRACKER, G.FILTER_UNTRACKED,
getString(R.string.menu_filters_untracked), G.PREF_FILTER_UNTRACKED);
filterAdapter.itemData.add(untracked);
insertRanges[1][1]++;
}
updateTrackerFilter = !currentTrackerTorrents;
} else {
updateTrackerFilter = false;
}
checkSelected = true;
}
} else {
int[] range = removeTrackersFilters();
if (range[0] != -1) {
filterAdapter.notifyItemRangeRemoved(range[0], range[1]);
}
if (!sharedPrefs.getString(G.PREF_LIST_TRACKER, "").equals("")) {
updateTrackerFilter = true;
}
}
if (updateDirectoryFilter || updateTrackerFilter) {
TorrentListFragment fragment =
((TorrentListFragment) getFragmentManager().findFragmentById(R.id.torrent_list));
if (updateDirectoryFilter) {
fragment.setListDirectoryFilter(null);
}
if (updateTrackerFilter) {
fragment.setListTrackerFilter(null);
}
closeHandler.removeCallbacks(closeRunnable);
closeHandler.post(closeRunnable);
}
if (insertRanges[0][0] != -1) {
filterAdapter.notifyItemRangeInserted(insertRanges[0][0], insertRanges[0][1]);
}
if (insertRanges[1][0] != -1) {
filterAdapter.notifyItemRangeInserted(insertRanges[1][0], insertRanges[1][1]);
}
if (checkSelected) {
checkSelectedItems();
}
}
@Override
public void onLoaderReset(Loader<TorrentTrafficLoader.TorrentTrafficOutputData> loader) {
}
};
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
sessionReceiver = new SessionReceiver();
Context context = new ContextThemeWrapper(getActivity(), android.R.style.Theme_Holo);
LayoutInflater localInflater = inflater.cloneInContext(context);
View root = localInflater.inflate(R.layout.fragment_torrent_list_menu, container, false);
filterList = (RecyclerView) root.findViewById(R.id.filter_list);
/* TODO: The list items should have a count that indicates
* how many torrents are matched by the filter */
filterAdapter = new FilterAdapter(this);
filterList.setAdapter(filterAdapter);
filterList.setLayoutManager(new LinearLayoutManager(getActivity()));
sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
sharedPrefs.registerOnSharedPreferenceChangeListener(sharedPrefListener);
setStaticClickHandlers(root);
fillMenuItems();
checkSelectedItems();
return root;
}
@Override public void onResume() {
super.onResume();
if (filtersChanged) {
filtersChanged = false;
directories.clear();
trackers.clear();
fillMenuItems();
checkSelectedItems();
}
if (((TransmissionSessionInterface) getActivity()).getSession() != null) {
updateSessionFilters(true);
}
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(
sessionReceiver, new IntentFilter(G.INTENT_SESSION_INVALIDATED));
}
@Override public void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(sessionReceiver);
}
@Override
public void notifyTorrentListChanged(Cursor cursor, int error, boolean added, boolean removed,
boolean statusChanged, boolean metadataNeeded,
boolean connected) {
getActivity().getSupportLoaderManager().restartLoader(G.TORRENT_MENU_TRAFFIC_LOADER_ID,
null, torrentTrafficLoaderCallbacks);
}
@Override
public void notifyTransmissionProfileListChanged(List<TransmissionProfile> profiles) {
int start = removeProfileSelector();
int[] range = removeProfiles();
View root = getView();
if (start != -1) {
filterAdapter.notifyItemRangeRemoved(start, range[1] + 1);
}
if (profiles.size() > 0) {
start = fillProfileSelector();
filterAdapter.notifyItemInserted(start);
if (!initialProfilesLoaded) {
filterList.scrollToPosition(0);
initialProfilesLoaded = true;
}
getActivity().getSupportLoaderManager().restartLoader(G.TORRENT_MENU_TRAFFIC_LOADER_ID,
null, torrentTrafficLoaderCallbacks);
if (root != null) {
root.findViewById(R.id.filter_list).setVisibility(View.VISIBLE);
}
} else {
if (root != null) {
root.findViewById(R.id.filter_list).setVisibility(View.GONE);
}
}
}
private void setActivatedPosition(ListItem item, int position) {
if (position == ListView.INVALID_POSITION) {
filterAdapter.clearSelections();
} else {
if (filterAdapter.itemData.size() <= position) {
return;
}
TorrentListFragment fragment =
((TorrentListFragment) getFragmentManager().findFragmentById(R.id.torrent_list));
final TorrentListActivity context = (TorrentListActivity) getActivity();
TransmissionProfile profile = context.getProfile();
boolean allFilterEnabled = sharedPrefs.getBoolean(G.PREF_FILTER_ALL, true);
ListItem selectedFilter = null;
ListItem selectedDirectory = null;
ListItem selectedTracker = null;
for (ListItem i : filterAdapter.getSelectedItems()) {
switch (i.getType()) {
case FILTER:
selectedFilter = i;
break;
case DIRECTORY:
selectedDirectory = i;
break;
case TRACKER:
selectedTracker = i;
break;
}
}
switch(item.getType()) {
case PROFILE_SELECTOR:
filterAdapter.setProfilesVisible(!filterAdapter.areProfilesVisible());
break;
case PROFILE:
if (profile != null && profile.getId().equals(item.getValueString())) {
break;
}
for (TransmissionProfile prof : context.getProfiles()) {
if (prof.getId().equals(item.getValueString())) {
TransmissionProfile.setCurrentProfile(prof,
PreferenceManager.getDefaultSharedPreferences(context));
context.setProfile(prof);
context.setRefreshing(true, DataService.Requests.GET_TORRENTS);
break;
}
}
filterAdapter.setProfilesVisible(false);
int pos = removeProfileSelector();
filterAdapter.notifyItemRemoved(pos);
pos = fillProfileSelector();
filterAdapter.notifyItemInserted(pos);
break;
case FILTER:
FilterBy value;
if (item.equals(selectedFilter)) {
if (allFilterEnabled) {
break;
}
value = FilterBy.ALL;
filterAdapter.setItemSelected(position, false);
} else {
if (selectedFilter != null) {
filterAdapter.setItemSelected(
filterAdapter.itemData.indexOf(selectedFilter), false);
}
filterAdapter.setItemSelected(position, true);
value = (FilterBy) item.getValue();
}
fragment.setListFilter(value);
break;
case DIRECTORY:
if (selectedDirectory != null) {
filterAdapter.setItemSelected(
filterAdapter.itemData.indexOf(selectedDirectory), false);
}
if (item.equals(selectedDirectory)) {
fragment.setListDirectoryFilter(null);
} else {
filterAdapter.setItemSelected(position, true);
fragment.setListDirectoryFilter(item.getValueString());
}
break;
case TRACKER:
if (selectedTracker != null) {
filterAdapter.setItemSelected(
filterAdapter.itemData.indexOf(selectedTracker), false);
}
if (item.equals(selectedTracker)) {
fragment.setListTrackerFilter(null);
} else {
filterAdapter.setItemSelected(position, true);
fragment.setListTrackerFilter(item.getValueString());
}
break;
default:
return;
}
if (item.getType() != Type.PROFILE_SELECTOR) {
closeHandler.removeCallbacks(closeRunnable);
closeHandler.post(closeRunnable);
}
}
}
private int fillProfileSelector() {
TransmissionProfileInterface context = (TransmissionProfileInterface) getActivity();
TransmissionProfile profile = context.getProfile();
if (profile == null) {
return -1;
}
ListItem item = new ListItem(Type.PROFILE_SELECTOR,
profile.getId(), profile.getName(), null);
item.setSublabel((profile.getUsername().length() > 0 ? profile.getUsername() + "@" : "")
+ profile.getHost() + ":" + profile.getPort());
item.setColor(profile.getColor());
filterAdapter.itemData.add(0, item);
listItemMap.put(PROFILE_SELECTOR_KEY, item);
return 0;
}
private int[] fillProfiles() {
TransmissionProfileInterface context = (TransmissionProfileInterface) getActivity();
TransmissionProfile currentProfile = context.getProfile();
ListItem selector = listItemMap.get(PROFILE_SELECTOR_KEY);
int index = filterAdapter.itemData.indexOf(selector);
if (currentProfile == null || index == -1) {
return new int[]{-1, 0};
}
int start = ++index;
int count = 0;
for (TransmissionProfile profile : context.getProfiles()) {
if (profile.getId().equals(currentProfile.getId())) {
continue;
}
ListItem item = new ListItem(Type.PROFILE,
profile.getId(), profile.getName(), null);
item.setSublabel((profile.getUsername().length() > 0 ? profile.getUsername() + "@" : "")
+ profile.getHost() + ":" + profile.getPort());
item.setColor(profile.getColor());
filterAdapter.itemData.add(index++, item);
count++;
}
return new int[]{start, count};
}
private int[] fillSessionItems() {
int[] range = new int[]{-1, 0};
TransmissionSessionInterface context = (TransmissionSessionInterface) getActivity();
TransmissionSession session = context.getSession();
if (session == null) {
return range;
}
ListItem header = listItemMap.get(FILTERS_HEADER_KEY);
if (header == null) {
header = new ListItem(Type.SESSION_DATA_HEADER, FILTERS_HEADER_KEY, R.string.menu_filters_header);
}
if (filterAdapter.itemData.indexOf(header) != -1) {
return range;
}
ArrayList<ListItem> list = new ArrayList<>();
for (FilterBy filter : FilterBy.values()) {
ListItem item;
if (listItemMap.containsKey(filter.name())) {
item = listItemMap.get(filter.name());
} else {
int string = -1;
String pref = null;
switch(filter) {
case ALL:
string = R.string.menu_filters_all;
pref = G.PREF_FILTER_ALL;
break;
case DOWNLOADING:
string = R.string.menu_filters_downloading;
pref = G.PREF_FILTER_DOWNLOADING;
break;
case SEEDING:
string = R.string.menu_filters_seeding;
pref = G.PREF_FILTER_SEEDING;
break;
case PAUSED:
string = R.string.menu_filters_paused;
pref = G.PREF_FILTER_PAUSED;
break;
case COMPLETE:
string = R.string.menu_filters_complete;
pref = G.PREF_FILTER_COMPLETE;
break;
case INCOMPLETE:
string = R.string.menu_filters_incomplete;
pref = G.PREF_FILTER_INCOMPLETE;
break;
case ACTIVE:
string = R.string.menu_filters_active;
pref = G.PREF_FILTER_ACTIVE;
break;
case CHECKING:
string = R.string.menu_filters_checking;
pref = G.PREF_FILTER_CHECKING;
break;
case ERRORS:
string = R.string.menu_filters_errors;
pref = G.PREF_FILTER_ERRORS;
break;
}
item = new ListItem(Type.FILTER, filter, string, pref);
}
if (sharedPrefs.getBoolean(item.getPreferenceKey(), true)) {
list.add(item);
}
}
if (sharedPrefs.getBoolean(G.PREF_FILTER_ALL, true) && list.size() > 1 || list.size() > 0) {
ListItem pivot = listItemMap.get(DIRECTORIES_HEADER_KEY);
int position = filterAdapter.itemData.indexOf(pivot);
if (position == -1) {
pivot = listItemMap.get(TRACKERS_HEADER_KEY);
position = filterAdapter.itemData.indexOf(pivot);
}
if (position == -1) {
position = filterAdapter.itemData.size();
}
range[0] = position;
filterAdapter.itemData.add(position++, header);
for (ListItem item : list) {
filterAdapter.itemData.add(position++, item);
}
range[1] = list.size() + 1;
}
list.clear();
return range;
}
private void setStaticClickHandlers(View root) {
final TorrentListActivity context = (TorrentListActivity) getActivity();
View.OnClickListener listener = view -> {
TransmissionSession session = context.getSession();
TransmissionProfile profile = context.getProfile();
boolean overrideTransition = false;
final Intent intent;
switch (view.getId()) {
case R.id.filter_list_session_settings:
if (session == null) {
return;
}
intent = new Intent(context, TransmissionSessionActivity.class);
intent.putExtra(G.ARG_PROFILE, profile);
intent.putExtra(G.ARG_SESSION, session);
overrideTransition = true;
break;
case R.id.filter_list_settings:
intent = new Intent(context, SettingsActivity.class);
if (session != null) {
ArrayList<String> directories1 = new ArrayList<>(session.getDownloadDirectories());
directories1.remove(session.getDownloadDir());
intent.putExtra(G.ARG_DIRECTORIES, directories1);
}
if (profile != null) {
intent.putExtra(G.ARG_PROFILE_ID, profile.getId());
}
overrideTransition = true;
break;
case R.id.filter_list_about:
intent = new Intent(context, AboutActivity.class);
break;
default:
return;
}
closeHandler.removeCallbacks(closeRunnable);
closeHandler.post(closeRunnable);
final boolean oT = overrideTransition;
closeHandler.postDelayed(() -> {
startActivity(intent);
if (oT) {
context.overridePendingTransition(
R.anim.slide_in_top, android.R.anim.fade_out);
}
}, getResources().getInteger(android.R.integer.config_shortAnimTime) + 100);
};
root.findViewById(R.id.filter_list_session_settings).setOnClickListener(listener);
root.findViewById(R.id.filter_list_settings).setOnClickListener(listener);
root.findViewById(R.id.filter_list_about).setOnClickListener(listener);
}
private void fillMenuItems() {
filterAdapter.itemData.clear();
fillProfileSelector();
fillSessionItems();
checkSelectedItems();
filterAdapter.notifyDataSetChanged();
filterList.scrollToPosition(0);
}
private void checkSelectedItems() {
filterAdapter.clearSelections();
FilterBy selectedFilter = FilterBy.ALL;
if (sharedPrefs.contains(G.PREF_LIST_FILTER)) {
try {
selectedFilter = FilterBy.valueOf(
sharedPrefs.getString(G.PREF_LIST_FILTER, "")
);
} catch (Exception ignored) { }
}
int position = filterAdapter.itemData.indexOf(
listItemMap.get(selectedFilter.name()));
if (position > -1) {
filterAdapter.setItemSelected(position, true);
} else if (selectedFilter != FilterBy.ALL) {
position = filterAdapter.itemData.indexOf(
listItemMap.get(selectedFilter.name()));
if (position > -1) {
filterAdapter.setItemSelected(position, true);
TorrentListFragment fragment =
((TorrentListFragment) getFragmentManager().findFragmentById(R.id.torrent_list));
fragment.setListFilter(FilterBy.ALL);
}
}
if (sharedPrefs.getBoolean(G.PREF_FILTER_DIRECTORIES, true)) {
String selectedDirectory = null;
if (sharedPrefs.contains(G.PREF_LIST_DIRECTORY)) {
selectedDirectory = sharedPrefs.getString(G.PREF_LIST_DIRECTORY, null);
}
if (selectedDirectory != null) {
position = filterAdapter.itemData.indexOf(
listItemMap.get(selectedDirectory));
filterAdapter.setItemSelected(position, true);
}
}
if (sharedPrefs.getBoolean(G.PREF_FILTER_TRACKERS, false)) {
String selectedTracker = null;
if (sharedPrefs.contains(G.PREF_LIST_TRACKER)) {
selectedTracker = sharedPrefs.getString(G.PREF_LIST_TRACKER, null);
}
if (!sharedPrefs.getBoolean(G.PREF_FILTER_UNTRACKED, false)
&& selectedFilter.equals(G.FILTER_UNTRACKED)) {
selectedTracker = null;
}
if (selectedTracker != null) {
position = filterAdapter.itemData.indexOf(
listItemMap.get(selectedTracker));
filterAdapter.setItemSelected(position, true);
}
}
}
private int removeProfileSelector() {
ListItem selector = listItemMap.get(PROFILE_SELECTOR_KEY);
int position = filterAdapter.itemData.indexOf(selector);
filterAdapter.itemData.remove(selector);
return position;
}
private int[] removeProfiles() {
Iterator<ListItem> iter = filterAdapter.itemData.iterator();
int start = -1;
int count = 0;
int index = 0;
while (iter.hasNext()) {
ListItem item = iter.next();
if (item.getType() == Type.PROFILE) {
iter.remove();
if (start == -1) {
start = index;
}
count++;
}
++index;
}
return new int[]{start, count};
}
private int[] removeSessionItems() {
Iterator<ListItem> iter = filterAdapter.itemData.iterator();
int start = -1;
int count = 0;
int index = 0;
while (iter.hasNext()) {
ListItem item = iter.next();
switch (item.getType()) {
case SESSION_DATA_HEADER:
case FILTER:
case DIRECTORY:
case TRACKER:
iter.remove();
if (start == -1) {
start = index;
}
count++;
break;
}
++index;
}
return new int[]{start, count};
}
private ListItem getDirectoryItem(String directory) {
ListItem item;
if (listItemMap.containsKey(directory)) {
item = listItemMap.get(directory);
} else {
String name = directory;
int lastSlash = name.lastIndexOf('/');
if (lastSlash > -1) {
name = name.substring(lastSlash + 1);
}
if (TextUtils.isEmpty(name)) {
return null;
}
item = new ListItem(Type.DIRECTORY, directory, name, G.PREF_FILTER_DIRECTORIES);
}
return item;
}
private int[] removeDirectoriesFilters() {
ListItem item = listItemMap.get(DIRECTORIES_HEADER_KEY);
int start = filterAdapter.itemData.indexOf(item);
int count = 1;
filterAdapter.itemData.remove(item);
Iterator<ListItem> iter = filterAdapter.itemData.iterator();
while (iter.hasNext()) {
item = iter.next();
if (item.getType() == Type.DIRECTORY) {
iter.remove();
count++;
}
}
return new int[]{start, count};
}
private ListItem getTrackerItem(String tracker) {
ListItem item;
if (listItemMap.containsKey(tracker)) {
item = listItemMap.get(tracker);
} else {
item = new ListItem(Type.TRACKER, tracker, tracker, G.PREF_FILTER_TRACKERS);
}
return item;
}
private int[] removeTrackersFilters() {
ListItem item = listItemMap.get(TRACKERS_HEADER_KEY);
int start = filterAdapter.itemData.indexOf(item);
int count = 1;
filterAdapter.itemData.remove(item);
Iterator<ListItem> iter = filterAdapter.itemData.iterator();
while (iter.hasNext()) {
item = iter.next();
if (item.getType() == Type.TRACKER) {
iter.remove();
count++;
}
}
return new int[]{start, count};
}
private void updateSessionFilters(boolean validSession) {
if (validSession) {
int[] range = fillSessionItems();
if (range[0] != -1) {
filterAdapter.notifyItemRangeInserted(range[0], range[1]);
}
getView().findViewById(R.id.filter_list_session_settings).setVisibility(View.VISIBLE);
getActivity().getSupportLoaderManager().restartLoader(G.TORRENT_MENU_TRAFFIC_LOADER_ID,
null, torrentTrafficLoaderCallbacks);
} else {
if (((TransmissionProfileInterface) getActivity()).getProfile() == null) {
getView().findViewById(R.id.filter_list_session_settings).setVisibility(View.INVISIBLE);
} else {
getView().findViewById(R.id.filter_list_session_settings).setVisibility(View.GONE);
}
int[] range = removeSessionItems();
if (range[0] != -1) {
filterAdapter.notifyItemRangeRemoved(range[0], range[1]);
}
}
}
private static class FilterAdapter extends SelectableRecyclerViewAdapter<FilterAdapter.ViewHolder, ListItem> {
private TorrentListMenuFragment context;
private boolean profilesVisible;
public FilterAdapter(TorrentListMenuFragment context) {
super();
this.context = context;
}
public boolean areProfilesVisible() {
return profilesVisible;
}
public void setProfilesVisible(boolean visible) {
this.profilesVisible = visible;
if (visible) {
int[] range = context.fillProfiles();
notifyItemRangeInserted(range[0], range[1]);
setItemSelected(range[0] - 1, true);
} else {
int[] range = context.removeProfiles();
if (range[0] != -1) {
notifyItemRangeRemoved(range[0], range[1]);
setItemSelected(range[0] - 1, false);
}
}
}
@Override public long getItemId(int position) {
return this.itemData.get(position).hashCode();
}
@Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemLayoutView = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
return new ViewHolder(itemLayoutView, viewType);
}
@Override public boolean isItemSelectable(int position) {
if (itemData.size() <= position) {
return false;
}
ListItem item = itemData.get(position);
if (item == null) {
return false;
}
switch (item.getType()) {
case SESSION_DATA_HEADER:
return false;
case PROFILE_SELECTOR:
TorrentListActivity listActivity = (TorrentListActivity) context.getActivity();
return listActivity.getProfiles().size() > 1;
}
return true;
}
@Override public void onBindViewHolder(ViewHolder holder, int position) {
super.onBindViewHolder(holder, position);
final ListItem item = itemData.get(position);
holder.itemView.setOnClickListener(v -> context.setActivatedPosition(item, itemData.indexOf(item)));
if (holder.label != null) {
holder.label.setText(item.getLabel());
}
if (holder.sublabel != null) {
holder.sublabel.setText(item.getSublabel());
}
if (holder.icon != null) {
holder.icon.setBackgroundResource(item.getIconId());
}
if (holder.color != null) {
Colorizer.colorizeView(holder.color, item.getColor() == null ?
Colorizer.defaultColor(context.getActivity()) :
item.getColor(),
GradientDrawable.OVAL
);
}
}
@Override public int getItemViewType(int position) {
ListItem item = itemData.get(position);
switch (item.getType()) {
case SESSION_DATA_HEADER:
return R.layout.filter_list_header;
case PROFILE_SELECTOR:
return R.layout.filter_list_profile_selector;
case PROFILE:
return R.layout.filter_list_profile_item;
default:
return R.layout.filter_list_item;
}
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView label;
public TextView sublabel;
public View icon;
public ImageView color;
public ViewHolder(View itemView, int type) {
super(itemView);
label = (TextView) itemView.findViewById(android.R.id.text1);
sublabel = (TextView) itemView.findViewById(android.R.id.text2);
icon = itemView.findViewById(android.R.id.icon);
color = (ImageView) itemView.findViewById(R.id.profile_color);
}
}
}
private class ListItem {
private Type type;
private Enum<?> value;
private int iconId;
private Integer color = null;
private String valueString;
private String label;
private String sublabel;
private String pref;
public ListItem(Type type, Enum<?> value, int stringId,
String pref) {
this.type = type;
this.value = value;
label = getString(stringId);
this.pref = pref;
listItemMap.put(value.name(), this);
}
public ListItem(Type type, String value, String label,
String pref) {
this.type = type;
this.label = label;
valueString = value;
this.pref = pref;
listItemMap.put(value, this);
}
public ListItem(Type type, String value, int stringId) {
this.type = type;
label = getString(stringId);
valueString = value;
listItemMap.put(value, this);
}
public ListItem(Type type, String value, int stringId, int iconId) {
this.type = type;
this.iconId = iconId;
label = getString(stringId);
valueString = value;
listItemMap.put(value, this);
}
public Type getType() {
return type;
}
public Enum<?> getValue() {
return value;
}
public String getValueString() {
return value == null ? valueString : value.name();
}
public String getLabel() {
return label;
}
public int getIconId() {
return iconId;
}
public String getSublabel() {
return sublabel;
}
public void setSublabel(String sublabel) {
this.sublabel = sublabel;
}
public String getPreferenceKey() {
return pref;
}
public Integer getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ListItem listItem = (ListItem) o;
if (iconId != listItem.iconId) return false;
if (label != null ? !label.equals(listItem.label) : listItem.label != null)
return false;
if (pref != null ? !pref.equals(listItem.pref) : listItem.pref != null) return false;
if (sublabel != null ? !sublabel.equals(listItem.sublabel) : listItem.sublabel != null)
return false;
if (type != listItem.type) return false;
if (value != null ? !value.equals(listItem.value) : listItem.value != null)
return false;
if (valueString != null ? !valueString.equals(listItem.valueString) : listItem.valueString != null)
return false;
return true;
}
@Override
public int hashCode() {
int result = type.hashCode();
result = 31 * result + (value != null ? value.hashCode() : 0);
result = 31 * result + iconId;
result = 31 * result + (valueString != null ? valueString.hashCode() : 0);
result = 31 * result + (label != null ? label.hashCode() : 0);
result = 31 * result + (sublabel != null ? sublabel.hashCode() : 0);
result = 31 * result + (pref != null ? pref.hashCode() : 0);
return result;
}
}
private class SessionReceiver extends BroadcastReceiver {
@Override public void onReceive(Context context, Intent intent) {
if (getActivity() == null) {
return;
}
updateSessionFilters(intent.getBooleanExtra(G.ARG_SESSION_VALID, false));
}
}
}