diff --git a/app/build.gradle b/app/build.gradle index d453f775..7cfaf3de 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -18,10 +18,16 @@ android { } } } +repositories { + maven { url 'http://clinker.47deg.com/nexus/content/groups/public' } +} dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile project(':libraries:openpgp-api-lib') compile 'org.eclipse.jgit:org.eclipse.jgit:3.4.+' compile 'org.apache.commons:commons-io:1.3.2' + compile ('com.fortysevendeg.swipelistview:swipelistview:1.0-SNAPSHOT@aar') { + transitive = true + } } diff --git a/app/src/main/java/com/zeapo/pwdstore/PasswordFragment.java b/app/src/main/java/com/zeapo/pwdstore/PasswordFragment.java index db214cc5..d9346892 100644 --- a/app/src/main/java/com/zeapo/pwdstore/PasswordFragment.java +++ b/app/src/main/java/com/zeapo/pwdstore/PasswordFragment.java @@ -1,20 +1,27 @@ package com.zeapo.pwdstore; import android.app.Activity; +import android.content.Context; import android.os.Bundle; import android.app.Fragment; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.animation.Animation; +import android.view.animation.ScaleAnimation; import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ExpandableListAdapter; import android.widget.ExpandableListView; +import android.widget.LinearLayout; import android.widget.ListAdapter; import android.widget.ListView; +import com.fortysevendeg.swipelistview.BaseSwipeListViewListener; +import com.fortysevendeg.swipelistview.SwipeListView; +import com.fortysevendeg.swipelistview.SwipeListViewListener; import com.zeapo.pwdstore.utils.PasswordAdapter; import com.zeapo.pwdstore.utils.PasswordItem; import com.zeapo.pwdstore.utils.PasswordRepository; @@ -29,14 +36,14 @@ import java.util.List; * with a GridView. *

*/ -public class PasswordFragment extends Fragment implements ExpandableListView.OnGroupClickListener { +public class PasswordFragment extends Fragment implements SwipeListViewListener { private OnFragmentInteractionListener mListener; /** * The fragment's ListView/GridView. */ - private ExpandableListView mListView; + private SwipeListView mListView; /** * The Adapter which will be used to populate the ListView/GridView with @@ -64,11 +71,11 @@ public class PasswordFragment extends Fragment implements ExpandableListView.OnG View view = inflater.inflate(R.layout.fragment_password, container, false); // Set the adapter - mListView = (ExpandableListView) view.findViewById(R.id.pass_list); - mListView.setAdapter((android.widget.ExpandableListAdapter) mAdapter); - + mListView = (SwipeListView) view.findViewById(R.id.pass_list); + ((AdapterView) mListView).setAdapter(mAdapter); // Set OnItemClickListener so we can be notified on item clicks - mListView.setOnGroupClickListener(this); +// mListView.setOnItemClickListener(this); + mListView.setSwipeListViewListener(this); mListView.setSelectionFromTop(getArguments().getInt("Position"), 0); return view; @@ -98,23 +105,105 @@ public class PasswordFragment extends Fragment implements ExpandableListView.OnG } - @Override - public boolean onGroupClick(ExpandableListView expandableListView, View view, int i, long l) { - if( ((PasswordItem) mAdapter.getGroup(i)).getType() == PasswordItem.TYPE_CATEGORY ){ - if (null != mListener) { - // Notify the active callbacks interface (the activity, if the - // fragment is attached to one) that an item has been selected. - mListener.onFragmentInteraction(mAdapter.getItem(i)); - } - } else { - if (expandableListView.isGroupExpanded(i)) { - expandableListView.collapseGroup(i); - } else { - expandableListView.expandGroup(i); - } +// @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + PasswordItem item = mAdapter.getItem(position); + if (item.getType() == PasswordItem.TYPE_PASSWORD) { +// if (item.selected) { +// item.selected = false; +// } else { +// View right = view.findViewById(R.id.row_buttons); +// ScaleAnimation animation = new ScaleAnimation(view.getX(), 0, view.getY(), 0, Animation.RELATIVE_TO_SELF, (float)0.5, Animation.RELATIVE_TO_SELF, (float)0.5); +// right.setAnimation(animation); +// item.selected = true; +// } + } else if (null != mListener) { + // Notify the active callbacks interface (the activity, if the + // fragment is attached to one) that an item has been selected. + mListener.onFragmentInteraction(mAdapter.getItem(position)); } - return true; + } + + @Override + public void onOpened(int i, boolean b) { + + } + + @Override + public void onClosed(int i, boolean b) { + + } + + @Override + public void onListChanged() { + + } + + @Override + public void onMove(int i, float v) { + + } + + @Override + public void onStartOpen(int i, int i2, boolean b) { + + } + + @Override + public void onStartClose(int i, boolean b) { + + } + + @Override + public void onClickFrontView(int i) { + if (mAdapter.getItem(i).getType() == PasswordItem.TYPE_PASSWORD) { + mListView.openAnimate(i); + } else if (null != mListener) { + // Notify the active callbacks interface (the activity, if the + // fragment is attached to one) that an item has been selected. + mListener.onFragmentInteraction(mAdapter.getItem(i)); + } + } + + @Override + public void onClickBackView(int i) { + mListView.closeAnimate(i); + } + + @Override + public void onDismiss(int[] ints) { + + } + + @Override + public int onChangeSwipeMode(int i) { + return 0; + } + + @Override + public void onChoiceChanged(int i, boolean b) { + + } + + @Override + public void onChoiceStarted() { + + } + + @Override + public void onChoiceEnded() { + + } + + @Override + public void onFirstListItem() { + + } + + @Override + public void onLastListItem() { + } public interface OnFragmentInteractionListener { @@ -125,7 +214,7 @@ public class PasswordFragment extends Fragment implements ExpandableListView.OnG public void updateAdapter() { mAdapter.clear(); mAdapter.addAll(PasswordRepository.getPasswords(new File(getArguments().getString("Path")))); - mListView.setAdapter((ExpandableListAdapter) mAdapter); + mListView.setAdapter((ListAdapter) mAdapter); } } diff --git a/app/src/main/java/com/zeapo/pwdstore/PasswordStore.java b/app/src/main/java/com/zeapo/pwdstore/PasswordStore.java index 62475867..dff6721d 100644 --- a/app/src/main/java/com/zeapo/pwdstore/PasswordStore.java +++ b/app/src/main/java/com/zeapo/pwdstore/PasswordStore.java @@ -249,14 +249,6 @@ public class PasswordStore extends Activity implements ToCloneOrNot.OnFragmentI public void onFragmentInteraction(PasswordItem item) { if (item.getType() == PasswordItem.TYPE_CATEGORY) { checkLocalRepository(item.getFile()); - } else { - try { - - - } catch (Exception e) { -// TODO handle problems - e.printStackTrace(); - } } } public void decryptPassword(PasswordItem item) { diff --git a/app/src/main/java/com/zeapo/pwdstore/crypto/PgpHandler.java b/app/src/main/java/com/zeapo/pwdstore/crypto/PgpHandler.java index 68c71c4b..423b513d 100644 --- a/app/src/main/java/com/zeapo/pwdstore/crypto/PgpHandler.java +++ b/app/src/main/java/com/zeapo/pwdstore/crypto/PgpHandler.java @@ -34,6 +34,7 @@ import com.zeapo.pwdstore.utils.PasswordRepository; import org.apache.commons.io.FileUtils; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.util.StringUtils; +import org.openintents.openpgp.IOpenPgpService; import org.openintents.openpgp.OpenPgpError; import org.openintents.openpgp.OpenPgpSignatureResult; import org.openintents.openpgp.util.OpenPgpApi; @@ -48,7 +49,7 @@ import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.util.ArrayList; -public class PgpHandler extends Activity { +public class PgpHandler extends Activity implements OpenPgpServiceConnection.OnBound{ private OpenPgpServiceConnection mServiceConnection; @@ -57,6 +58,8 @@ public class PgpHandler extends Activity { SharedPreferences settings; private Activity activity; + private ProgressDialog bindingDialog; + public static final int REQUEST_CODE_SIGN = 9910; public static final int REQUEST_CODE_ENCRYPT = 9911; public static final int REQUEST_CODE_SIGN_AND_ENCRYPT = 9912; @@ -74,7 +77,7 @@ public class PgpHandler extends Activity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - activity = this; + this.activity = this; // some persistance settings = PreferenceManager.getDefaultSharedPreferences(this); @@ -91,31 +94,13 @@ public class PgpHandler extends Activity { // bind to service mServiceConnection = new OpenPgpServiceConnection( - PgpHandler.this, providerPackageName); + PgpHandler.this, providerPackageName, this ); mServiceConnection.bindToService(); - - Bundle extra = getIntent().getExtras(); - if (extra.getString("Operation").equals("DECRYPT")) { - setContentView(R.layout.decrypt_layout); - ((TextView) findViewById(R.id.crypto_password_file)).setText(extra.getString("NAME")); - String cat = new File(extra.getString("FILE_PATH").replace(PasswordRepository.getWorkTree().getAbsolutePath(), "")) - .getParentFile().getName(); - - ((TextView) findViewById(R.id.crypto_password_category)).setText(cat + "/"); - } else if (extra.getString("Operation").equals("ENCRYPT")) { - setContentView(R.layout.encrypt_layout); - String cat = extra.getString("FILE_PATH"); - cat = cat.replace(PasswordRepository.getWorkTree().getAbsolutePath(), ""); - cat = cat + "/"; - ((TextView) findViewById(R.id.crypto_password_category)).setText(cat); - } else if (extra.getString("Operation").equals("GET_KEY_ID")) { - setContentView(R.layout.key_id); - if (!keyIDs.isEmpty()) { - String keys = keyIDs.split(",").length > 1 ? keyIDs : keyIDs.split(",")[0]; - ((TextView) findViewById(R.id.crypto_key_ids)).setText(keys); - } - } + bindingDialog = new ProgressDialog(this); + bindingDialog.setMessage("Waiting for OpenKeychain..."); + bindingDialog.setCancelable(false); + bindingDialog.show(); ActionBar actionBar = getActionBar(); actionBar.setDisplayHomeAsUpEnabled(true); @@ -176,7 +161,6 @@ public class PgpHandler extends Activity { Toast.LENGTH_LONG).show(); Log.e(Constants.TAG, "onError getErrorId:" + error.getErrorId()); Log.e(Constants.TAG, "onError getMessage:" + error.getMessage()); - Log.e(Constants.TAG, " " + error.toString()); } }); } @@ -279,6 +263,8 @@ public class PgpHandler extends Activity { @Override public void onReturn(Intent result) { + bindingDialog.dismiss(); + switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) { case OpenPgpApi.RESULT_CODE_SUCCESS: { showToast("SUCCESS"); @@ -366,6 +352,7 @@ public class PgpHandler extends Activity { handleError(error); break; } + } } } @@ -462,5 +449,32 @@ public class PgpHandler extends Activity { } + @Override + public void onBound(IOpenPgpService service) { + Log.i("PGP", "ISBOUND!!"); + + Bundle extra = getIntent().getExtras(); + if (extra.getString("Operation").equals("DECRYPT")) { + setContentView(R.layout.decrypt_layout); + ((TextView) findViewById(R.id.crypto_password_file)).setText(extra.getString("NAME")); + String cat = new File(extra.getString("FILE_PATH").replace(PasswordRepository.getWorkTree().getAbsolutePath(), "")) + .getParentFile().getName(); + + ((TextView) findViewById(R.id.crypto_password_category)).setText(cat + "/"); + decryptAndVerify(new Intent()); + } else if (extra.getString("Operation").equals("ENCRYPT")) { + setContentView(R.layout.encrypt_layout); + String cat = extra.getString("FILE_PATH"); + cat = cat.replace(PasswordRepository.getWorkTree().getAbsolutePath(), ""); + cat = cat + "/"; + ((TextView) findViewById(R.id.crypto_password_category)).setText(cat); + } else if (extra.getString("Operation").equals("GET_KEY_ID")) { + setContentView(R.layout.key_id); + if (!keyIDs.isEmpty()) { + String keys = keyIDs.split(",").length > 1 ? keyIDs : keyIDs.split(",")[0]; + ((TextView) findViewById(R.id.crypto_key_ids)).setText(keys); + } + } + } } diff --git a/app/src/main/java/com/zeapo/pwdstore/utils/PasswordAdapter.java b/app/src/main/java/com/zeapo/pwdstore/utils/PasswordAdapter.java index fbc7d817..2aaa0bf5 100644 --- a/app/src/main/java/com/zeapo/pwdstore/utils/PasswordAdapter.java +++ b/app/src/main/java/com/zeapo/pwdstore/utils/PasswordAdapter.java @@ -9,9 +9,11 @@ import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.AbsListView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.ExpandableListAdapter; +import android.widget.GridLayout; import android.widget.ImageButton; import android.widget.TextView; @@ -23,13 +25,14 @@ import org.apache.commons.io.FileUtils; import java.util.ArrayList; -public class PasswordAdapter extends ArrayAdapter implements ExpandableListAdapter{ +public class PasswordAdapter extends ArrayAdapter{ private final PasswordStore activity; private final ArrayList values; static class ViewHolder { public TextView name; public TextView type; + public TextView back_name; } public PasswordAdapter(PasswordStore activity, ArrayList values) { @@ -38,74 +41,47 @@ public class PasswordAdapter extends ArrayAdapter implements Exp this.activity = activity; } - @Override - public void registerDataSetObserver(DataSetObserver dataSetObserver) { - - } @Override - public void unregisterDataSetObserver(DataSetObserver dataSetObserver) { - - } - - @Override - public int getGroupCount() { - return values.size(); - } - - @Override - public int getChildrenCount(int i) { - if (values.get(i).getType() == PasswordItem.TYPE_CATEGORY) - return 0; - else - return 1; - } - - @Override - public Object getGroup(int i) { - return values.get(i); - } - - @Override - public Object getChild(int i, int i2) { - return null; - } - - @Override - public long getGroupId(int i) { - return 0; - } - - @Override - public long getChildId(int i, int i2) { - return 0; - } - - @Override - public boolean hasStableIds() { - return false; - } - - @Override - public View getGroupView(int i, boolean b, View convertView, ViewGroup viewGroup) { + public View getView(int i, View convertView, ViewGroup viewGroup) { View rowView = convertView; - PasswordItem pass = values.get(i); + final PasswordItem pass = values.get(i); // reuse for performance, holder pattern! if (rowView == null) { LayoutInflater inflater = (LayoutInflater) activity .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - rowView = inflater.inflate(R.layout.password_row_layout, null); + rowView = inflater.inflate(R.layout.password_row_layout, viewGroup, false); ViewHolder viewHolder = new ViewHolder(); viewHolder.name = (TextView) rowView.findViewById(R.id.label); + viewHolder.back_name = (TextView) rowView.findViewById(R.id.label_back); viewHolder.type = (TextView) rowView.findViewById(R.id.type); rowView.setTag(viewHolder); + + + View.OnClickListener onClickListener = new View.OnClickListener() { + @Override + public void onClick(View view) { + switch (view.getId()) { + case R.id.crypto_show_button: + activity.decryptPassword(pass); + break; + case R.id.crypto_delete_button: + activity.deletePassword(pass); + break; + } + } + }; + + ((ImageButton) rowView.findViewById(R.id.crypto_show_button)).setOnClickListener(onClickListener); + ((ImageButton) rowView.findViewById(R.id.crypto_delete_button)).setOnClickListener(onClickListener); } ViewHolder holder = (ViewHolder) rowView.getTag(); holder.name.setText(pass.toString()); + holder.back_name.setText(pass.toString()); if (pass.getType() == PasswordItem.TYPE_CATEGORY) { holder.name.setTextColor(this.activity.getResources().getColor(android.R.color.holo_blue_dark)); @@ -115,71 +91,11 @@ public class PasswordAdapter extends ArrayAdapter implements Exp holder.type.setText("Password: "); holder.name.setTextColor(this.activity.getResources().getColor(android.R.color.holo_orange_dark)); holder.name.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.NORMAL)); + + holder.back_name.setTextColor(this.activity.getResources().getColor(android.R.color.white)); + holder.back_name.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD_ITALIC)); } return rowView; } - - @Override - public View getChildView(int i, int i2, boolean b, View view, ViewGroup viewGroup) { - final PasswordItem pass = values.get(i); - - LayoutInflater inflater = (LayoutInflater) this.activity - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - view = inflater.inflate(R.layout.child_row_layout, null); - - View.OnClickListener onClickListener = new View.OnClickListener() { - @Override - public void onClick(View view) { - switch (view.getId()) { - case R.id.crypto_show_button: - activity.decryptPassword(pass); - break; - case R.id.crypto_delete_button: - activity.deletePassword(pass); - break; - } - } - }; - - ((ImageButton) view.findViewById(R.id.crypto_show_button)).setOnClickListener(onClickListener); - ((ImageButton) view.findViewById(R.id.crypto_delete_button)).setOnClickListener(onClickListener); - - return view; - } - - @Override - public boolean isChildSelectable(int i, int i2) { - return false; - } - - @Override - public boolean areAllItemsEnabled() { - return false; - } - - @Override - public boolean isEmpty() { - return false; - } - - @Override - public void onGroupExpanded(int i) { - - } - - @Override - public void onGroupCollapsed(int i) { - - } - - @Override - public long getCombinedChildId(long l, long l2) { - return 0; - } - - @Override - public long getCombinedGroupId(long l) { - return 0; - } } \ No newline at end of file diff --git a/app/src/main/java/com/zeapo/pwdstore/utils/PasswordItem.java b/app/src/main/java/com/zeapo/pwdstore/utils/PasswordItem.java index 4403d16b..75d0838c 100644 --- a/app/src/main/java/com/zeapo/pwdstore/utils/PasswordItem.java +++ b/app/src/main/java/com/zeapo/pwdstore/utils/PasswordItem.java @@ -11,6 +11,7 @@ public class PasswordItem implements Comparable{ private String name; private PasswordItem parent; private File file; + public boolean selected = false; /** Create a password item * diff --git a/app/src/main/res/drawable-xxhdpi/gray_rectangle.xml b/app/src/main/res/drawable-xxhdpi/gray_rectangle.xml new file mode 100644 index 00000000..b1858c80 --- /dev/null +++ b/app/src/main/res/drawable-xxhdpi/gray_rectangle.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/child_row_layout.xml b/app/src/main/res/layout/child_row_layout.xml index 0fc5e33d..75efefad 100644 --- a/app/src/main/res/layout/child_row_layout.xml +++ b/app/src/main/res/layout/child_row_layout.xml @@ -2,7 +2,9 @@ + android:layout_height="match_parent" + android:id="@+id/child_row_layout" + android:layout_marginTop="@dimen/activity_vertical_margin"> - + android:background="@drawable/rectangle" + android:orientation="vertical"> + android:layout_marginLeft="@dimen/activity_horizontal_margin"/> - - - - - - - + android:layout_marginLeft="@dimen/activity_horizontal_margin"/> + - - + swipe:swipeFrontView="@+id/front" + swipe:swipeBackView="@+id/back" + swipe:swipeActionLeft="reveal" + swipe:swipeActionRight="reveal" + swipe:swipeMode="both" + swipe:swipeCloseAllItemsWhenMoveList="true" + swipe:swipeOpenOnLongPress="true" + swipe:swipeAnimationTime="200" + android:listSelector="#00000000"/> + diff --git a/app/src/main/res/layout/password_row_layout.xml b/app/src/main/res/layout/password_row_layout.xml index f8d656fd..641f4f85 100644 --- a/app/src/main/res/layout/password_row_layout.xml +++ b/app/src/main/res/layout/password_row_layout.xml @@ -1,25 +1,71 @@ - - + + + - - + android:tag="back" + android:background="@drawable/gray_rectangle" + android:layout_gravity="left|center_vertical"> + + + + + + + + + + + + + +