/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with context work for additional information
* regarding copyright ownership. The ASF licenses context file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use context file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.doplgangr.secrecy.Views;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.app.ActionBarActivity;
import android.text.InputType;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.ViewAnimator;
import com.doplgangr.secrecy.FileSystem.Vault;
import com.doplgangr.secrecy.FileSystem.storage;
import com.doplgangr.secrecy.R;
import com.doplgangr.secrecy.Settings.Prefs_;
import com.doplgangr.secrecy.Settings.SettingsFragment_;
import com.doplgangr.secrecy.Util;
import com.nineoldandroids.view.ViewHelper;
import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.EFragment;
import org.androidannotations.annotations.OptionsItem;
import org.androidannotations.annotations.OptionsMenu;
import org.androidannotations.annotations.UiThread;
import org.androidannotations.annotations.ViewById;
import org.androidannotations.annotations.res.DrawableRes;
import org.androidannotations.annotations.sharedpreferences.Pref;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import de.greenrobot.event.EventBus;
@EFragment(R.layout.activity_list_vault)
@OptionsMenu(R.menu.list_vault)
public class VaultsListFragment extends Fragment {
@ViewById(R.id.list)
LinearLayout mLinearView;
@ViewById(R.id.actionBarTitle)
TextView mActionBarTitle;
@ViewById(R.id.scrollView)
ScrollView mScrollView;
@ViewById(R.id.header)
View mHeader;
@ViewById(R.id.nothing)
View nothing;
@DrawableRes(R.drawable.file_selector)
Drawable selector;
@Pref
Prefs_ Pref;
ActionBarActivity context;
VaultsAdapter adapter;
OnVaultSelectedListener mOnVaultSelected;
OnFragmentFinishListener mFinishListener;
private boolean isPaused = false;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mOnVaultSelected = (OnVaultSelectedListener) activity;
mFinishListener = (OnFragmentFinishListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement Listener");
}
}
@AfterViews
void oncreate() {
if (!EventBus.getDefault().isRegistered(this))
EventBus.getDefault().register(this);
context = (ActionBarActivity) getActivity();
if (mLinearView != null)
mLinearView.removeAllViews();
context.getSupportActionBar().setTitle("");
mActionBarTitle.setText(R.string.App__name);
java.io.File root = storage.getRoot();
if (!Util.canWrite(root)) {
Util.alert(context,
context.getString(R.string.Error__root_IOException),
context.getString(R.string.Error__root_IOException_message),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
mFinishListener.onNew(null, new SettingsFragment_());
}
},
null
);
return;
}
adapter = new VaultsAdapter(context, null);
ArrayList<File> files = storage.getDirectories(root);
for (int i = 0; i < files.size(); i++) {
adapter.add(files.get(i).getName());
final View mView = adapter.getView(i, mLinearView); //inject vaults into list
mLinearView.addView(mView, i);
setClickListener(mView, i);
}
if (adapter.getCount() == 0) {
nothing.setVisibility(View.VISIBLE);
mLinearView.setVisibility(View.GONE);
} else {
nothing.setVisibility(View.GONE);
mLinearView.setVisibility(View.VISIBLE);
}
mScrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
@Override
public void onScrollChanged() {
int scrollY = mScrollView.getScrollY(); //for verticalScrollViewint scrollY = getScrollY();
//sticky actionbar
int mHeaderTextHeight = context.getResources().getDimensionPixelSize(R.dimen.header_text_height);
int mActionBarHeight = context.getResources().getDimensionPixelSize(R.dimen.action_bar_height);
int translationY = Math.max(-scrollY, -mHeaderTextHeight);
ViewHelper.setTranslationY(mHeader, translationY);
ViewGroup.LayoutParams params = mActionBarTitle.getLayoutParams();
params.height = scrollY > mActionBarHeight ? mActionBarHeight : mHeaderTextHeight;
mActionBarTitle.setLayoutParams(params);
}
});
showTutorial();
}
public void onEventMainThread(FilesActivity.shouldRefresh ignored) {
oncreate();
}
public void setClickListener(final View mView, final int i) {
mView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
open(adapter.getItem(i), mView, i);
}
});
mView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
switchView(mView, R.id.vault_rename_layout);
((EditText) mView.findViewById(R.id.rename_name)).setText(adapter.getItem(i));
mView.findViewById(R.id.rename_ok)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View ignored) {
final String newName = ((EditText) mView.findViewById(R.id.rename_name))
.getText().toString();
switchView(mView, R.id.vault_decrypt_layout);
mView.findViewById(R.id.open_ok)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View ignored) {
String password = ((EditText) mView.findViewById(R.id.open_password))
.getText().toString();
rename(i, newName, password);
switchView(mView, R.id.vault_decrypt_layout);
}
});
mView.findViewById(R.id.open_cancel)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View ignored) {
switchView(mView, R.id.vault_name_layout);
}
});
}
});
mView.findViewById(R.id.rename_cancel)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
switchView(mView, R.id.vault_name_layout);
}
});
return true;
}
});
}
@OptionsItem(R.id.action_add_vault)
void add() {
final View dialogView = View.inflate(context, R.layout.new_credentials, null);
final EditText password = new EditText(context);
password.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
new AlertDialog.Builder(context)
.setTitle(getString(R.string.Vault__new))
.setView(dialogView)
.setPositiveButton(getString(R.string.OK), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
String name = ((EditText) dialogView.findViewById(R.id.newName)).getText().toString();
String password = ((EditText) dialogView.findViewById(R.id.stealth_keycode)).getText().toString();
String Confirmpassword = ((EditText) dialogView.findViewById(R.id.confirmPassword)).getText().toString();
File directory = new File(storage.getRoot().getAbsolutePath() + "/" + name);
if (!password.equals(Confirmpassword) || "".equals(password))
passwordWrong();
else if (directory.mkdirs()) {
try {
File file = new File(storage.getTempFolder(), ".nomedia");
file.delete();
file.createNewFile();
FileOutputStream outputStream = new FileOutputStream(file);
outputStream.write(name.getBytes());
outputStream.close();
Uri nomediaURI = Uri.fromFile(file);
Vault newVault = new Vault(name, password, true);
newVault.addFile(context, nomediaURI);
file.delete();
oncreate();
} catch (IOException e) {
e.printStackTrace();
}
} else
failedtocreate();
}
}).setNegativeButton(getString(R.string.CANCEL), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
// Do nothing.
}
}).show();
}
void passwordWrong() {
new AlertDialog.Builder(context)
.setTitle(getString(R.string.Error__wrong_password_confirmation))
.setMessage(getString(R.string.Error__wrong_password_confirmation_message))
.setPositiveButton(getString(R.string.OK), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
}
}).show();
}
void failedtocreate() {
new AlertDialog.Builder(context)
.setTitle(getString(R.string.Error__cannot_create_vault))
.setMessage(getString(R.string.Error__cannot_create_vault_message))
.setPositiveButton(getString(R.string.OK), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
}
}).show();
}
void open(final String vault, final View mView, final int i) {
// vault name
// View of lisitem
// position of listitem in list
switchView(mView, R.id.vault_decrypt_layout);
mView.findViewById(R.id.open_ok)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String value = ((EditText) mView.findViewById(R.id.open_password))
.getText().toString();
mOnVaultSelected.onVaultSelected(vault, value);
}
});
mView.findViewById(R.id.open_cancel)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
switchView(mView, R.id.vault_name_layout);
}
});
}
void rename(final int position, final String newName, final String password) {
Vault newVault = new Vault(adapter.getItem(position), password).rename(newName);
if (newVault == null)
Util.alert(context,
getString(R.string.Error__rename_password_incorrect),
getString(R.string.Error__rename_password_incorrect_message),
Util.emptyClickListener,
null
);
oncreate();
}
@UiThread
void switchView(final View parentView, int showView) {
EditText passwordView = (EditText) parentView.findViewById(R.id.open_password);
View renameView = parentView.findViewById(R.id.rename_name);
ViewAnimator viewAnimator = (ViewAnimator) parentView.findViewById(R.id.viewAnimator);
viewAnimator.setInAnimation(context, R.anim.slide_down);
int viewIndex = 0;
switch (showView) {
case R.id.vault_name_layout:
viewIndex = 0;
break;
case R.id.vault_decrypt_layout:
viewIndex = 1;
if (passwordView != null) {
passwordView.requestFocus();
passwordView.setText(""); //Reset password field everytime
}
break;
case R.id.vault_delete_layout:
viewIndex = 2;
break;
case R.id.vault_rename_layout:
viewIndex = 3;
if (renameView != null)
renameView.requestFocus();
break;
}
viewAnimator.setDisplayedChild(viewIndex);
}
void finish() {
mFinishListener.onFinish(this);
}
void showTutorial() {
if ((adapter.getCount() > 0) && (Pref.showVaultLongPressRenameTutorial().get())) {
final View mView =
context.getLayoutInflater().inflate(R.layout.vault_item_tutorial, mLinearView, false);
TextView mInstructions = (TextView) mView.findViewById(R.id.Tutorial__instruction);
if (mInstructions != null)
mInstructions.setText(R.string.Tutorial__long_click_to_rename);
mLinearView.addView(mView, 0);
mView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
mLinearView.removeView(mView);
Pref.edit()
.showVaultLongPressRenameTutorial()
.put(false)
.apply();
return true;
}
});
return; //Show only one tutorial at a time. Don't overload users!!
}
}
public interface OnVaultSelectedListener {
public void onVaultSelected(String vault, String password);
}
public interface OnFragmentFinishListener {
public void onFinish(Fragment fragment);
public void onNew(Bundle bundle, Fragment fragment);
}
public interface onPanic {
void onPanic();
}
}