package info.knacki.pass.settings.ui;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;
import android.preference.SwitchPreference;
import android.support.v4.app.NavUtils;
import android.support.v7.app.ActionBar;
import android.util.SparseArray;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
import java.io.File;
import java.util.List;
import java.util.logging.Logger;
import info.knacki.pass.R;
import info.knacki.pass.git.GitInterface;
import info.knacki.pass.git.GitInterfaceFactory;
import info.knacki.pass.git.entities.GitRef;
import info.knacki.pass.io.FileUtils;
import info.knacki.pass.io.PathUtils;
import info.knacki.pass.settings.SettingsManager;
import info.knacki.pass.ui.GitPullActivity;
import info.knacki.pass.ui.alertPrompt.AlertPrompt;
import info.knacki.pass.ui.alertPrompt.views.TextView;
/**
* A {@link PreferenceActivity} that presents a set of application settings. On
* handset devices, settings are presented as a single list. On tablets,
* settings are split by category, with category headers shown to the left of
* the list of settings.
*
* See
* Android Design: Settings for design guidelines and the Settings
* API Guide for more information on developing a Settings UI.
*/
public class SettingsActivity extends AppCompatPreferenceActivity {
private static final Logger log = Logger.getLogger(SettingsActivity.class.getName());
/**
* Helper method to determine if the device has an extra-large screen. For
* example, 10" tablets are extra-large.
*/
private static boolean isXLargeTablet(Context context) {
return (context.getResources().getConfiguration().screenLayout
& Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setupActionBar();
}
/**
* Set up the {@link android.app.ActionBar}, if the API is available.
*/
private void setupActionBar() {
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
// Show the Up button in the action bar.
actionBar.setDisplayHomeAsUpEnabled(true);
}
}
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
if (!super.onMenuItemSelected(featureId, item)) {
NavUtils.navigateUpFromSameTask(this);
}
return true;
}
return super.onMenuItemSelected(featureId, item);
}
/**
* {@inheritDoc}
*/
@Override
public boolean onIsMultiPane() {
return isXLargeTablet(this);
}
/**
* {@inheritDoc}
*/
@Override
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void onBuildHeaders(List target) {
loadHeadersFromResource(R.xml.pref_headers, target);
}
/**
* This method stops fragment injection in malicious applications.
* Make sure to deny any unknown fragments here.
*/
protected boolean isValidFragment(String fragmentName) {
return PreferenceFragment.class.getName().equals(fragmentName)
|| GeneralPreferenceFragment.class.getName().equals(fragmentName)
|| EncryptionPreferenceFragment.class.getName().equals(fragmentName)
|| VCSPreferenceFragment.class.getName().equals(fragmentName)
|| GPGPreferenceFragment.class.getName().equals(fragmentName);
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class GeneralPreferenceFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_general);
setHasOptionsMenu(true);
findPreference(getResources().getString(R.string.id_softSettings)).setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
//FIXME
return true;
}
});
findPreference(getResources().getString(R.string.id_removeall)).setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
new AlertPrompt(getActivity())
.setTitle(R.string.are_you_sure)
.setView(new TextView(getActivity())
.SetText(R.string.about_to_rm_root_star))
.setPositiveButton(R.string.ok, new AlertPrompt.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, View view) {
new File(PathUtils.GetGitFile(getActivity())).delete();
File f = new File(PathUtils.GetPassDir(getActivity()));
FileUtils.rmdir(f);
f.mkdir();
}
})
.setNegativeButton(R.string.cancel, new AlertPrompt.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, View view) {
}
})
.show();
return true;
}
});
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
startActivity(new Intent(getActivity(), SettingsActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class EncryptionPreferenceFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_encryption);
setHasOptionsMenu(true);
ListPreference encTypePref = (ListPreference) findPreference(getResources().getString(R.string.id_enctype));
final int encTypeIndex = SettingsManager.GetDefaultEncryptionType(getActivity()).IntValue();
encTypePref.setSummary(encTypePref.getEntries()[encTypeIndex]);
encTypePref.setValueIndex(encTypeIndex);
encTypePref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object o) {
int value = Integer.parseInt(o.toString());
preference.setSummary(((ListPreference) preference).getEntries()[value]);
SettingsManager.SetDefaultEncryptionType(getActivity(), SettingsManager.EncryptionType.FromInt(value));
return true;
}
});
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
startActivity(new Intent(getActivity(), SettingsActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class VCSPreferenceFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_vcs);
setHasOptionsMenu(true);
abstract class PrefListener implements Preference.OnPreferenceChangeListener {
@Override
public boolean onPreferenceChange(Preference preference, Object o) {
savePref(preference, o);
VCSPreferenceFragment.this.reload();
return true;
}
abstract void savePref(Preference preference, Object o);
}
findPreference(getResources().getString(R.string.id_vcs_enable)).setOnPreferenceChangeListener(new PrefListener() {
@Override
void savePref(Preference preference, Object o) {
if ((Boolean) o)
SettingsManager.SetVCS(getActivity(), new SettingsManager.Git());
else
SettingsManager.SetVCS(getActivity(), null);
}
});
findPreference(getResources().getString(R.string.id_vcs_list)).setOnPreferenceChangeListener(new PrefListener() {
@Override
void savePref(Preference preference, Object o) {
SettingsManager.VCS vcs = SettingsManager.GetVCS(getActivity());
SettingsManager.VCS newVcs;
switch (Integer.parseInt((String) o)) {
case 0:
newVcs = new SettingsManager.Git();
break;
default:
return;
}
if (!vcs.GetName().equals(newVcs.GetName())) {
SettingsManager.SetVCS(getActivity(), newVcs);
}
}
});
findPreference(getResources().getString(R.string.id_vcs_git_url)).setOnPreferenceChangeListener(new PrefListener() {
@Override
void savePref(Preference preference, Object o) {
SettingsManager.Git git = (SettingsManager.Git) SettingsManager.GetVCS(getActivity());
git.SetUrl(((String) o).trim());
SettingsManager.SetVCS(getActivity(), git);
}
});
findPreference(getResources().getString(R.string.id_vcs_git_user)).setOnPreferenceChangeListener(new PrefListener() {
@Override
void savePref(Preference preference, Object o) {
SettingsManager.Git git = (SettingsManager.Git) SettingsManager.GetVCS(getActivity());
git.SetUser(((String) o).trim());
SettingsManager.SetVCS(getActivity(), git);
}
});
findPreference(getResources().getString(R.string.id_vcs_git_pass)).setOnPreferenceChangeListener(new PrefListener() {
@Override
void savePref(Preference preference, Object o) {
SettingsManager.Git git = (SettingsManager.Git) SettingsManager.GetVCS(getActivity());
git.SetPassword(((String) o).trim());
SettingsManager.SetVCS(getActivity(), git);
}
});
findPreference(getResources().getString(R.string.id_vcs_git_ci_username)).setOnPreferenceChangeListener(new PrefListener() {
@Override
void savePref(Preference preference, Object o) {
SettingsManager.Git git = (SettingsManager.Git) SettingsManager.GetVCS(getActivity());
git.SetUsername(((String) o).trim());
SettingsManager.SetVCS(getActivity(), git);
}
});
findPreference(getResources().getString(R.string.id_vcs_git_ci_useremail)).setOnPreferenceChangeListener(new PrefListener() {
@Override
void savePref(Preference preference, Object o) {
SettingsManager.Git git = (SettingsManager.Git) SettingsManager.GetVCS(getActivity());
git.SetUserEmail(((String) o).trim());
SettingsManager.SetVCS(getActivity(), git);
}
});
findPreference(getResources().getString(R.string.id_vcs_git_branches)).setOnPreferenceChangeListener(new PrefListener() {
@Override
void savePref(Preference preference, Object o) {
SettingsManager.Git git = (SettingsManager.Git) SettingsManager.GetVCS(getActivity());
git.SetBranch(((String) o).trim());
SettingsManager.SetVCS(getActivity(), git);
}
});
findPreference(getResources().getString(R.string.id_vcs_git_pull)).setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
startActivity(new Intent(getActivity(), GitPullActivity.class));
return true;
}
});
reload();
}
final SparseArray hiddenPreferences = new SparseArray<>();
private void RemovePrefs(int... prefIds) {
for (int id: prefIds) {
Preference pref = findPreference(getResources().getString(id));
if (pref != null) {
getPreferenceScreen().removePreference(pref);
hiddenPreferences.put(id, pref);
}
}
}
private Preference FindPreference(int prefId) {
Preference p = findPreference(getResources().getString(prefId));
if (p != null)
return p;
p = hiddenPreferences.get(prefId);
hiddenPreferences.remove(prefId);
if (p != null)
getPreferenceScreen().addPreference(p);
return p;
}
protected void reload() {
final SettingsManager.VCS versioning = SettingsManager.GetVCS(getActivity());
if (versioning != null) {
((SwitchPreference) findPreference(getResources().getString(R.string.id_vcs_enable))).setChecked(true);
ListPreference vcsType = (ListPreference) FindPreference(R.string.id_vcs_list);
vcsType.setEnabled(true);
if (versioning instanceof SettingsManager.Git) {
vcsType.setValueIndex(0);
vcsType.setSummary(vcsType.getEntries()[0]);
EditTextPreference gitUrl = (EditTextPreference) FindPreference(R.string.id_vcs_git_url);
gitUrl.setSummary(((SettingsManager.Git) versioning).GetUrl());
gitUrl.setText(((SettingsManager.Git) versioning).GetUrl());
FindPreference(R.string.id_vcs_git_authcategory);
EditTextPreference gitUser = (EditTextPreference) FindPreference(R.string.id_vcs_git_user);
gitUser.setSummary(((SettingsManager.Git) versioning).GetUser());
gitUser.setText(((SettingsManager.Git) versioning).GetUser());
EditTextPreference gitPass = (EditTextPreference) FindPreference(R.string.id_vcs_git_pass);
gitPass.setSummary(((SettingsManager.Git) versioning).GetPassword().length() == 0 ? "" : "******");
gitPass.setText(((SettingsManager.Git) versioning).GetPassword());
FindPreference(R.string.id_vcs_git_commitinfocategory);
ListPreference gitBranches = (ListPreference) FindPreference(R.string.id_vcs_git_branches);
populateBranches(gitBranches, (SettingsManager.Git) versioning);
FindPreference(R.string.id_vcs_git_pull);
EditTextPreference gitUsername = (EditTextPreference) FindPreference(R.string.id_vcs_git_ci_username);
gitUsername.setSummary(((SettingsManager.Git) versioning).GetUsername());
gitUsername.setDefaultValue(((SettingsManager.Git) versioning).GetUsername());
EditTextPreference gitUserEmail = (EditTextPreference) FindPreference(R.string.id_vcs_git_ci_useremail);
gitUserEmail.setSummary(((SettingsManager.Git) versioning).GetUserEmail());
gitUserEmail.setDefaultValue(((SettingsManager.Git) versioning).GetUserEmail());
} else {
RemovePrefs(R.string.id_vcs_git_url,
R.string.id_vcs_git_user,
R.string.id_vcs_git_pass,
R.string.id_vcs_git_branches,
R.string.id_vcs_git_pull,
R.string.id_vcs_git_ci_username,
R.string.id_vcs_git_ci_useremail,
R.string.id_vcs_git_commitinfocategory,
R.string.id_vcs_git_authcategory);
}
} else {
((SwitchPreference) findPreference(getResources().getString(R.string.id_vcs_enable))).setChecked(false);
ListPreference vcsType = (ListPreference) findPreference(getResources().getString(R.string.id_vcs_list));
vcsType.setEnabled(false);
vcsType.setSummary("");
RemovePrefs(R.string.id_vcs_git_url,
R.string.id_vcs_git_user,
R.string.id_vcs_git_pass,
R.string.id_vcs_git_branches,
R.string.id_vcs_git_pull,
R.string.id_vcs_git_ci_username,
R.string.id_vcs_git_ci_useremail,
R.string.id_vcs_git_commitinfocategory,
R.string.id_vcs_git_authcategory);
}
}
protected void populateBranches(final ListPreference gitBranches, final SettingsManager.Git versioning) {
gitBranches.setEnabled(false);
GitInterface gitInterface = GitInterfaceFactory.factory(getActivity(), versioning);
if (gitInterface != null) {
gitInterface.GetRefs(new GitInterface.OnResponseListener() {
@Override
public void onResponse(final GitRef[] result) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
CharSequence[] refNames = new CharSequence[result.length];
CharSequence[] refs = new CharSequence[result.length];
int selected = -1;
for (int i = 0; i < result.length; ++i) {
refNames[i] = result[i].GetBranchName();
refs[i] = result[i].GetBranch();
if (result[i].GetBranch().equals(versioning.GetBranch()))
selected = i;
}
gitBranches.setEntries(refNames);
gitBranches.setEntryValues(refs);
gitBranches.setEnabled(true);
if (selected >= 0) {
gitBranches.setSummary(refNames[selected]);
gitBranches.setValueIndex(selected);
}
}
});
}
@Override
public void onError(final String msg, final Throwable e) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getActivity(), msg, Toast.LENGTH_LONG).show();
}
});
}
});
} else {
gitBranches.setEntryValues(new CharSequence[]{});
gitBranches.setEntries(new CharSequence[]{});
gitBranches.setEnabled(false);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
startActivity(new Intent(getActivity(), SettingsActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
}
public final static int ACTIVITY_REQUEST_CODE_BROWSEGPG = 1;
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class GPGPreferenceFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_gpg);
setHasOptionsMenu(true);
findPreference(getResources().getString(R.string.id_gpg_keyfile)).setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.setType("file/*");
GPGPreferenceFragment.this.startActivityForResult(i, ACTIVITY_REQUEST_CODE_BROWSEGPG);
return true;
}
});
updateGpgFileLabel();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == ACTIVITY_REQUEST_CODE_BROWSEGPG) {
if (resultCode == RESULT_OK) {
Uri uriData = data.getData();
if (null != uriData) {
String path = uriData.getPath();
SettingsManager.SetGPGKeyFile(getActivity(), path);
updateGpgFileLabel();
}
}
}
}
protected void updateGpgFileLabel() {
String gpgFileName = SettingsManager.GetGPGKeyFile(getActivity());
File gpgFile = gpgFileName == null ? null : new File(gpgFileName);
if (gpgFile != null && gpgFile.exists()) {
findPreference(getResources().getString(R.string.id_gpg_keyfile)).setSummary(gpgFile.getName());
} else {
findPreference(getResources().getString(R.string.id_gpg_keyfile)).setSummary(R.string.pref_summary_gpg_keyfile);
}
}
}
}