package org.sugr.gearshift.ui.settings;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.LoaderManager;
import android.support.v4.app.NavUtils;
import android.support.v4.content.Loader;
import android.support.v4.widget.SlidingPaneLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import org.sugr.gearshift.G;
import org.sugr.gearshift.R;
import org.sugr.gearshift.core.TransmissionProfile;
import org.sugr.gearshift.ui.SelectableRecyclerViewAdapter;
import org.sugr.gearshift.ui.TorrentListActivity;
import org.sugr.gearshift.ui.loader.TransmissionProfileSupportLoader;
import org.sugr.gearshift.ui.util.Colorizer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class SettingsActivity extends AppCompatActivity {
enum Type {
PROFILE_HEADER, PREFERENCES, PROFILE, PROFILE_DIRECTORIES
}
private SlidingPaneLayout slidingPane;
private ProfileAdapter profileAdapter;
private static final int PREFERENCE_GROUP_COUNT = 3;
private static final String PREFERENCE_FRAGMENT_TAG = "preference-fragment";
private static final String DIRECTORIES_FRAGMENT_TAG = "directories-fragment";
private SharedPreferences.OnSharedPreferenceChangeListener defaultPrefListener
= (sharedPreferences, key) -> {
if (key.equals(G.PREF_PROFILES)) {
Loader loader = getSupportLoaderManager().getLoader(G.PROFILES_LOADER_ID);
if (loader != null) {
loader.onContentChanged();
}
}
};
private SharedPreferences.OnSharedPreferenceChangeListener profilesPrefListener
= (sharedPreferences, key) -> {
Loader loader = getSupportLoaderManager().getLoader(G.PROFILES_LOADER_ID);
if (loader != null) {
loader.onContentChanged();
}
};
private LoaderManager.LoaderCallbacks<TransmissionProfile[]> profileLoaderCallbacks = new LoaderManager.LoaderCallbacks<TransmissionProfile[]>() {
@Override
public android.support.v4.content.Loader<TransmissionProfile[]> onCreateLoader(
int id, Bundle args) {
return new TransmissionProfileSupportLoader(SettingsActivity.this, true);
}
@Override
public void onLoadFinished(
android.support.v4.content.Loader<TransmissionProfile[]> loader,
TransmissionProfile[] profiles) {
List<ProfileItem> items = new ArrayList<>(profiles.length);
for (TransmissionProfile profile : profiles) {
items.add(createProfileItem(profile));
}
if (items.size() == 0 && profileAdapter.itemData.size() > PREFERENCE_GROUP_COUNT) {
Iterator<ProfileItem> iter = profileAdapter.itemData.iterator();
int count = 0;
while (iter.hasNext()) {
ProfileItem item = iter.next();
if (item.getType() == Type.PROFILE_HEADER || item.getType() == Type.PROFILE) {
iter.remove();
count++;
}
}
profileAdapter.notifyItemRangeRemoved(PREFERENCE_GROUP_COUNT, count);
} else if (items.size() > 0 && profileAdapter.itemData.size() == PREFERENCE_GROUP_COUNT) {
ProfileItem header = new ProfileItem("profile-header", Type.PROFILE_HEADER,
getString(R.string.header_label_profiles), null);
profileAdapter.itemData.add(header);
profileAdapter.notifyItemInserted(PREFERENCE_GROUP_COUNT);
}
Iterator<ProfileItem> iter = profileAdapter.itemData.iterator();
int index = 0;
while (iter.hasNext()) {
ProfileItem item = iter.next();
if (item.getType() == Type.PROFILE) {
int idx = items.indexOf(item);
if (idx != -1) {
if (items.get(idx).differs(item)) {
profileAdapter.itemData.set(index, items.get(idx));
profileAdapter.notifyItemChanged(index);
}
items.remove(item);
} else {
iter.remove();
profileAdapter.notifyItemRemoved(index--);
}
}
index++;
}
if (items.size() > 0) {
int start = profileAdapter.itemData.size();
for (ProfileItem item : items) {
profileAdapter.itemData.add(item);
}
profileAdapter.notifyItemRangeInserted(start, items.size());
}
G.requestBackup(SettingsActivity.this);
}
@Override
public void onLoaderReset(
android.support.v4.content.Loader<TransmissionProfile[]> loader) {
Iterator<ProfileItem> iter = profileAdapter.itemData.iterator();
int count = 0;
while (iter.hasNext()) {
ProfileItem item = iter.next();
if (item.getType() == Type.PROFILE_HEADER || item.getType() == Type.PROFILE) {
iter.remove();
count++;
}
}
profileAdapter.notifyItemRangeRemoved(PREFERENCE_GROUP_COUNT, count);
}
};
public boolean isPreferencesOpen() {
Fragment f = getFragmentManager().findFragmentById(R.id.preference_panel);
return f != null && f.isAdded();
}
public boolean isProfileOpen() {
Fragment f = getFragmentManager().findFragmentById(R.id.preference_panel);
return f != null && f.isAdded() && (
f instanceof TransmissionProfileSettingsFragment
|| f instanceof TransmissionProfileDirectoriesSettingsFragment
);
}
public boolean isPreferencesAlwaysVisible() {
return !slidingPane.isSlideable();
}
public void closePreferences() {
if (!isPreferencesOpen()) {
return;
}
profileAdapter.clearSelections();
resetPreferencePane();
if (!isPreferencesAlwaysVisible()) {
slidingPane.openPane();
}
}
@Override public void onBackPressed() {
Fragment f = getFragmentManager().findFragmentById(R.id.preference_panel);
if (isPreferencesOpen()) {
if (f instanceof TransmissionProfileDirectoriesSettingsFragment) {
String id = f.getArguments().getString(G.ARG_PROFILE_ID);
if (id == null) {
id = "new-profile";
}
addFragment(id, Type.PROFILE, null);
} else {
closePreferences();
}
return;
}
NavUtils.navigateUpTo(this, new Intent(this, TorrentListActivity.class));
overridePendingTransition(android.R.anim.fade_in, R.anim.slide_out_top);
}
public void addFragment(String id, Type type, Bundle args) {
Fragment fragment = null;
switch (id) {
case "general-preferences":
fragment = new GeneralSettingsFragment();
break;
case "filter-preferences":
fragment = new FiltersSettingsFragment();
break;
case "sort-preferences":
fragment = new SortSettingsFragment();
break;
case "new-profile":
fragment = new TransmissionProfileSettingsFragment();
if (args == null) {
args = new Bundle();
}
break;
default:
switch (type) {
case PROFILE:
fragment = new TransmissionProfileSettingsFragment();
if (args == null) {
args = new Bundle();
}
args.putString(G.ARG_PROFILE_ID, id);
Intent intent = getIntent();
if (intent.hasExtra(G.ARG_PROFILE_ID)
&& id.equals(intent.getStringExtra(G.ARG_PROFILE_ID))) {
args.putStringArrayList(G.ARG_DIRECTORIES,
intent.getStringArrayListExtra(G.ARG_DIRECTORIES));
}
break;
case PROFILE_DIRECTORIES:
fragment = new TransmissionProfileDirectoriesSettingsFragment();
if (args == null) {
args = new Bundle();
}
break;
}
}
if (fragment != null) {
if (args != null) {
fragment.setArguments(args);
}
}
if (fragment == null) {
return;
}
String tag = type == Type.PROFILE_DIRECTORIES
? DIRECTORIES_FRAGMENT_TAG : PREFERENCE_FRAGMENT_TAG;
findViewById(R.id.watermark).setVisibility(View.GONE);
FragmentManager fm = getFragmentManager();
Fragment previous = fm.findFragmentById(R.id.preference_panel);
FragmentTransaction tx = fm.beginTransaction();
if (previous != null) {
tx.remove(previous);
}
tx.replace(R.id.preference_panel, fragment, tag).addToBackStack(null).commit();
fm.executePendingTransactions();
}
@Override protected void onCreate(Bundle state) {
super.onCreate(state);
setContentView(R.layout.activity_settings);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
if (toolbar != null) {
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
slidingPane = (SlidingPaneLayout) findViewById(R.id.sliding_pane);
slidingPane.setSliderFadeColor(getResources().getColor(R.color.preference_background));
slidingPane.setShadowResourceLeft(R.drawable.pane_shadow);
slidingPane.setPanelSlideListener(new SlidingPaneLayout.SimplePanelSlideListener() {
@Override
public void onPanelOpened(View panel) {
if (isPreferencesOpen()) {
resetPreferencePane();
}
}
});
slidingPane.openPane();
profileAdapter = new ProfileAdapter(this);
RecyclerView profileList = (RecyclerView) findViewById(R.id.profile_list);
profileList.setLayoutManager(new LinearLayoutManager(this));
profileList.setAdapter(profileAdapter);
fillPreferences();
getSupportLoaderManager().initLoader(G.PROFILES_LOADER_ID, null, profileLoaderCallbacks);
boolean showNewProfile = getIntent().getBooleanExtra(G.ARG_NEW_PROFILE, false);
if (state == null) {
TransmissionProfile.cleanTemporaryPreferences();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
prefs.registerOnSharedPreferenceChangeListener(defaultPrefListener);
prefs = getSharedPreferences(TransmissionProfile.getPreferencesName(),
Activity.MODE_PRIVATE);
prefs.registerOnSharedPreferenceChangeListener(profilesPrefListener);
} else {
showNewProfile = false;
}
if (showNewProfile) {
addFragment("new-profile", Type.PROFILE, null);
slidingPane.closePane();
}
}
@Override protected void onResume() {
super.onResume();
FragmentManager fm = getFragmentManager();
View watermark = findViewById(R.id.watermark);
watermark.setVisibility(fm.findFragmentById(R.id.preference_panel) == null
? View.VISIBLE : View.GONE);
}
@Override public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.add_profile_option, menu);
return super.onCreateOptionsMenu(menu);
}
@Override public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
if (isProfileOpen()) {
Fragment f = getFragmentManager().findFragmentById(R.id.preference_panel);
if (f instanceof TransmissionProfileDirectoriesSettingsFragment) {
String id = f.getArguments().getString(G.ARG_PROFILE_ID);
if (id != null) {
addFragment(id, Type.PROFILE, null);
return true;
}
} else {
return false;
}
}
if (isPreferencesOpen()) {
closePreferences();
return true;
}
NavUtils.navigateUpTo(this, new Intent(this, TorrentListActivity.class));
overridePendingTransition(android.R.anim.fade_in, R.anim.slide_out_top);
return true;
case R.id.add_profile:
addFragment("new-profile", Type.PROFILE, null);
slidingPane.closePane();
return true;
}
return super.onOptionsItemSelected(item);
}
private void setSelectedItem(ProfileItem item) {
if (item.getType() == Type.PROFILE_HEADER) {
return;
}
addFragment(item.getId(), item.getType(), null);
slidingPane.closePane();
}
private void fillPreferences() {
ProfileItem item = new ProfileItem("general-preferences", Type.PREFERENCES,
getString(R.string.header_label_general_preferences), null);
profileAdapter.itemData.add(0, item);
item = new ProfileItem("filter-preferences", Type.PREFERENCES,
getString(R.string.header_label_filters), null);
profileAdapter.itemData.add(1, item);
item = new ProfileItem("sort-preferences", Type.PREFERENCES,
getString(R.string.header_label_sort), null);
profileAdapter.itemData.add(2, item);
profileAdapter.notifyItemRangeInserted(0, profileAdapter.itemData.size());
}
private ProfileItem createProfileItem(TransmissionProfile profile) {
String sublabel = (profile.getUsername().length() > 0 ? profile.getUsername() + "@" : "")
+ profile.getHost() + ":" + profile.getPort();
ProfileItem item = new ProfileItem(profile.getId(), Type.PROFILE,
profile.getName(), sublabel);
item.setColor(profile.getColor());
return item;
}
private void resetPreferencePane() {
findViewById(R.id.watermark).setVisibility(View.VISIBLE);
FragmentManager fm = getFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
transaction.remove(fm.findFragmentById(R.id.preference_panel));
transaction.commit();
fm.executePendingTransactions();
}
private static class ProfileAdapter extends SelectableRecyclerViewAdapter<ProfileAdapter.ViewHolder, ProfileItem> {
private SettingsActivity context;
public ProfileAdapter(SettingsActivity context) {
super();
this.context = context;
}
@Override public boolean isItemSelectable(int position) {
if (itemData.size() <= position) {
return false;
}
ProfileItem item = itemData.get(position);
return item.getType() != Type.PROFILE_HEADER;
}
@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 void onBindViewHolder(ViewHolder holder, final int position) {
super.onBindViewHolder(holder, position);
final ProfileItem item = itemData.get(position);
holder.itemView.setOnClickListener(v -> {
clearSelections();
setItemSelected(position, true);
context.setSelectedItem(item);
});
holder.label.setText(item.getLabel());
/* Enable the marquee animation */
holder.label.setSelected(true);
if (holder.sublabel != null) {
holder.sublabel.setText(item.getSublabel());
holder.sublabel.setSelected(true);
}
if (holder.color != null) {
Colorizer.colorizeView(holder.color, item.getColor() == null ?
Colorizer.defaultColor(context) :
item.getColor(),
GradientDrawable.OVAL
);
}
}
@Override public long getItemId(int position) {
return this.itemData.get(position).hashCode();
}
@Override public int getItemViewType(int position) {
ProfileItem item = itemData.get(position);
switch (item.getType()) {
case PROFILE_HEADER:
return R.layout.settings_profile_header;
case PREFERENCES:
return R.layout.settings_preference_item;
default:
return R.layout.settings_profile_item;
}
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView label;
public TextView sublabel;
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);
color = (ImageView) itemView.findViewById(R.id.profile_color);
}
}
}
private class ProfileItem {
private String id;
private Type type;
private String label;
private String sublabel;
private Integer color = null;
private ProfileItem(String id, Type type, String label, String sublabel) {
this.id = id;
this.type = type;
this.label = label;
this.sublabel = sublabel;
}
public String getId() {
return id;
}
public Type getType() {
return type;
}
public String getLabel() {
return label;
}
public String getSublabel() {
return sublabel;
}
public Integer getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
}
public boolean differs(ProfileItem o) {
if (!this.equals(o)) {
return false;
}
if (!label.equals(o.label) || !sublabel.equals(o.sublabel) || color != o.color) {
return true;
}
return false;
}
@Override public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ProfileItem that = (ProfileItem) o;
if (!id.equals(that.id)) return false;
if (type != that.type) return false;
return true;
}
@Override public int hashCode() {
int result = id.hashCode();
result = 31 * result + type.hashCode();
result = 31 * result + label.hashCode();
result = 31 * result + (sublabel != null ? sublabel.hashCode() : 0);
return result;
}
}
}