diff --git a/.idea/misc.xml b/.idea/misc.xml
index 7158618b..cca2cdae 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -37,7 +37,7 @@
-
+
diff --git a/README.md b/README.md
index 4b30f127..c7ff06b9 100644
--- a/README.md
+++ b/README.md
@@ -39,6 +39,7 @@ goes to Bruno.
* [Apache Commons Code](https://commons.apache.org/proper/commons-codec/)
* [Code Parts from Google's Android Samples](https://android.googlesource.com/platform/development/+/master/samples/Vault/src/com/example/android/vault)
+ * [SimpleItemTouchHelperCallback](https://github.com/iPaulPro/Android-ItemTouchHelper-Demo/blob/master/app/src/main/java/co/paulburke/android/itemtouchhelperdemo/helper/SimpleItemTouchHelperCallback.java) from [Android-ItemTouchHelper-Demo](https://github.com/iPaulPro/Android-ItemTouchHelper-Demo) by Paul Burke
* [MaterialProgressBar](https://github.com/DreaminginCodeZH/MaterialProgressBar)
* [ZXing](https://github.com/zxing/zxing)
* [ZXing Android Embedded](https://github.com/journeyapps/zxing-android-embedded)
diff --git a/app/src/main/java/org/shadowice/flocke/andotp/EntriesCardAdapter.java b/app/src/main/java/org/shadowice/flocke/andotp/EntriesCardAdapter.java
index ae158410..ef3c4e6f 100644
--- a/app/src/main/java/org/shadowice/flocke/andotp/EntriesCardAdapter.java
+++ b/app/src/main/java/org/shadowice/flocke/andotp/EntriesCardAdapter.java
@@ -28,13 +28,19 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
-import java.util.List;
+import org.shadowice.flocke.andotp.ItemTouchHelper.ItemTouchHelperAdapter;
+import org.shadowice.flocke.andotp.ItemTouchHelper.ItemTouchHelperViewHolder;
-public class EntriesCardAdapter extends RecyclerView.Adapter {
+import java.util.ArrayList;
+import java.util.Collections;
- private List entries;
+public class EntriesCardAdapter extends RecyclerView.Adapter
+ implements ItemTouchHelperAdapter {
- public EntriesCardAdapter(List entries) {
+ private ArrayList entries;
+ public MoveEventCallback moveEventCallback;
+
+ public EntriesCardAdapter(ArrayList entries) {
this.entries = entries;
}
@@ -50,28 +56,75 @@ public class EntriesCardAdapter extends RecyclerView.Adapter toPosition; i--) {
+ Collections.swap(entries, i, i - 1);
+ }
+ }
+ notifyItemMoved(fromPosition, toPosition);
+
+ return true;
+ }
+
+ public void setMoveEventCallback(MoveEventCallback cb) {
+ this.moveEventCallback = cb;
+ }
+
+ public static class EntryViewHolder extends RecyclerView.ViewHolder
+ implements ItemTouchHelperViewHolder {
+
+ private MoveEventCallback moveEventCallback;
protected TextView OTPValue;
protected TextView OTPLabel;
public EntryViewHolder(View v) {
super(v);
- OTPValue = (TextView) v.findViewById(R.id.textViewOTP);
- OTPLabel = (TextView) v.findViewById(R.id.textViewLabel);
+
+ OTPValue = (TextView) v.findViewById(R.id.textViewOTP);
+ OTPLabel = (TextView) v.findViewById(R.id.textViewLabel);
+ }
+
+ @Override
+ public void onItemSelected() {
+ if (moveEventCallback != null)
+ moveEventCallback.onMoveEventStart();
+ }
+
+ @Override
+ public void onItemClear() {
+ if (moveEventCallback != null)
+ moveEventCallback.onMoveEventStop();
}
}
+
+ public interface MoveEventCallback {
+ void onMoveEventStart();
+ void onMoveEventStop();
+ }
}
diff --git a/app/src/main/java/org/shadowice/flocke/andotp/ItemTouchHelper/ItemTouchHelperAdapter.java b/app/src/main/java/org/shadowice/flocke/andotp/ItemTouchHelper/ItemTouchHelperAdapter.java
new file mode 100644
index 00000000..d7504656
--- /dev/null
+++ b/app/src/main/java/org/shadowice/flocke/andotp/ItemTouchHelper/ItemTouchHelperAdapter.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 Paul Burke
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this 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 org.shadowice.flocke.andotp.ItemTouchHelper;
+
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.helper.ItemTouchHelper;
+
+/**
+ * Interface to listen for a move or dismissal event from a {@link ItemTouchHelper.Callback}.
+ *
+ * @author Paul Burke (ipaulpro)
+ */
+public interface ItemTouchHelperAdapter {
+
+ /**
+ * Called when an item has been dragged far enough to trigger a move. This is called every time
+ * an item is shifted, and not at the end of a "drop" event.
+ *
+ * Implementations should call {@link RecyclerView.Adapter#notifyItemMoved(int, int)} after
+ * adjusting the underlying data to reflect this move.
+ *
+ * @param fromPosition The start position of the moved item.
+ * @param toPosition Then resolved position of the moved item.
+ * @return True if the item was moved to the new adapter position.
+ *
+ * @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder)
+ * @see RecyclerView.ViewHolder#getAdapterPosition()
+ */
+ boolean onItemMove(int fromPosition, int toPosition);
+
+
+ /**
+ * Called when an item has been dismissed by a swipe.
+ *
+ * Implementations should call {@link RecyclerView.Adapter#notifyItemRemoved(int)} after
+ * adjusting the underlying data to reflect this removal.
+ *
+ * @param position The position of the item dismissed.
+ *
+ * @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder)
+ * @see RecyclerView.ViewHolder#getAdapterPosition()
+ */
+ void onItemDismiss(int position);
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/shadowice/flocke/andotp/ItemTouchHelper/ItemTouchHelperViewHolder.java b/app/src/main/java/org/shadowice/flocke/andotp/ItemTouchHelper/ItemTouchHelperViewHolder.java
new file mode 100644
index 00000000..8051939e
--- /dev/null
+++ b/app/src/main/java/org/shadowice/flocke/andotp/ItemTouchHelper/ItemTouchHelperViewHolder.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 Paul Burke
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this 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 org.shadowice.flocke.andotp.ItemTouchHelper;
+
+import android.support.v7.widget.helper.ItemTouchHelper;
+
+/**
+ * Interface to notify an item ViewHolder of relevant callbacks from {@link
+ * android.support.v7.widget.helper.ItemTouchHelper.Callback}.
+ *
+ * @author Paul Burke (ipaulpro)
+ */
+public interface ItemTouchHelperViewHolder {
+
+ /**
+ * Called when the {@link ItemTouchHelper} first registers an item as being moved or swiped.
+ * Implementations should update the item view to indicate it's active state.
+ */
+ void onItemSelected();
+
+
+ /**
+ * Called when the {@link ItemTouchHelper} has completed the move or swipe, and the active item
+ * state should be cleared.
+ */
+ void onItemClear();
+}
diff --git a/app/src/main/java/org/shadowice/flocke/andotp/ItemTouchHelper/SimpleItemTouchHelperCallback.java b/app/src/main/java/org/shadowice/flocke/andotp/ItemTouchHelper/SimpleItemTouchHelperCallback.java
new file mode 100644
index 00000000..c495806c
--- /dev/null
+++ b/app/src/main/java/org/shadowice/flocke/andotp/ItemTouchHelper/SimpleItemTouchHelperCallback.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2015 Paul Burke
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this 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 org.shadowice.flocke.andotp.ItemTouchHelper;
+
+import android.graphics.Canvas;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.helper.ItemTouchHelper;
+
+/**
+ * An implementation of {@link ItemTouchHelper.Callback} that enables basic drag & drop and
+ * swipe-to-dismiss. Drag events are automatically started by an item long-press.
+ *
+ * Expects the RecyclerView.Adapter
to listen for {@link
+ * ItemTouchHelperAdapter} callbacks and the RecyclerView.ViewHolder
to implement
+ * {@link ItemTouchHelperViewHolder}.
+ *
+ * @author Paul Burke (ipaulpro)
+ */
+public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
+
+ public static final float ALPHA_FULL = 1.0f;
+
+ private final ItemTouchHelperAdapter mAdapter;
+
+ public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {
+ mAdapter = adapter;
+ }
+
+ @Override
+ public boolean isLongPressDragEnabled() {
+ return true;
+ }
+
+ @Override
+ public boolean isItemViewSwipeEnabled() {
+ return true;
+ }
+
+ @Override
+ public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
+ // Set movement flags based on the layout manager
+ if (recyclerView.getLayoutManager() instanceof GridLayoutManager) {
+ final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
+ final int swipeFlags = 0;
+ return makeMovementFlags(dragFlags, swipeFlags);
+ } else {
+ final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
+ final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
+ return makeMovementFlags(dragFlags, swipeFlags);
+ }
+ }
+
+ @Override
+ public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {
+ if (source.getItemViewType() != target.getItemViewType()) {
+ return false;
+ }
+
+ // Notify the adapter of the move
+ mAdapter.onItemMove(source.getAdapterPosition(), target.getAdapterPosition());
+ return true;
+ }
+
+ @Override
+ public void onSwiped(RecyclerView.ViewHolder viewHolder, int i) {
+ // Notify the adapter of the dismissal
+ mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
+ }
+
+ @Override
+ public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
+ if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
+ // Fade out the view as it is swiped out of the parent's bounds
+ final float alpha = ALPHA_FULL - Math.abs(dX) / (float) viewHolder.itemView.getWidth();
+ viewHolder.itemView.setAlpha(alpha);
+ viewHolder.itemView.setTranslationX(dX);
+ } else {
+ super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
+ }
+ }
+
+ @Override
+ public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
+ // We only want the active item to change
+ if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
+ if (viewHolder instanceof ItemTouchHelperViewHolder) {
+ // Let the view holder know that this item is being moved or dragged
+ ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
+ itemViewHolder.onItemSelected();
+ }
+ }
+
+ super.onSelectedChanged(viewHolder, actionState);
+ }
+
+ @Override
+ public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
+ super.clearView(recyclerView, viewHolder);
+
+ viewHolder.itemView.setAlpha(ALPHA_FULL);
+
+ if (viewHolder instanceof ItemTouchHelperViewHolder) {
+ // Tell the view holder it's time to restore the idle state
+ ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
+ itemViewHolder.onItemClear();
+ }
+ }
+}
diff --git a/app/src/main/java/org/shadowice/flocke/andotp/MainActivity.java b/app/src/main/java/org/shadowice/flocke/andotp/MainActivity.java
index 3cbaf2bc..5fca8be1 100644
--- a/app/src/main/java/org/shadowice/flocke/andotp/MainActivity.java
+++ b/app/src/main/java/org/shadowice/flocke/andotp/MainActivity.java
@@ -40,6 +40,7 @@ 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.support.v7.widget.helper.ItemTouchHelper;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
@@ -51,6 +52,8 @@ import android.widget.TextView;
import com.google.zxing.client.android.Intents;
import com.google.zxing.integration.android.IntentIntegrator;
+import org.shadowice.flocke.andotp.ItemTouchHelper.SimpleItemTouchHelperCallback;
+
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
@@ -157,6 +160,7 @@ public class MainActivity extends AppCompatActivity {
});
final ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar);
+
RecyclerView recList = (RecyclerView) findViewById(R.id.cardList);
recList.setHasFixedSize(true);
LinearLayoutManager llm = new LinearLayoutManager(this);
@@ -168,6 +172,24 @@ public class MainActivity extends AppCompatActivity {
adapter = new EntriesCardAdapter(entries);
recList.setAdapter(adapter);
+ ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(adapter);
+ ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
+ touchHelper.attachToRecyclerView(recList);
+
+ adapter.setMoveEventCallback(new EntriesCardAdapter.MoveEventCallback() {
+ @Override
+ public void onMoveEventStart() {
+ stopUpdater();
+ }
+
+ @Override
+ public void onMoveEventStop() {
+ startUpdater();
+
+ SettingsHelper.store(getBaseContext(), entries);
+ }
+ });
+
if(entries.isEmpty()){
showNoAccount();
}