Re-implement reorder and delete (drag&drop and swipe)
This commit is contained in:
parent
d7df8fcc19
commit
0324218735
7 changed files with 309 additions and 11 deletions
|
@ -37,7 +37,7 @@
|
|||
<ConfirmationsSetting value="0" id="Add" />
|
||||
<ConfirmationsSetting value="0" id="Remove" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<EntriesCardAdapter.EntryViewHolder> {
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
private List<Entry> entries;
|
||||
public class EntriesCardAdapter extends RecyclerView.Adapter<EntriesCardAdapter.EntryViewHolder>
|
||||
implements ItemTouchHelperAdapter {
|
||||
|
||||
public EntriesCardAdapter(List<Entry> entries) {
|
||||
private ArrayList<Entry> entries;
|
||||
public MoveEventCallback moveEventCallback;
|
||||
|
||||
public EntriesCardAdapter(ArrayList<Entry> entries) {
|
||||
this.entries = entries;
|
||||
}
|
||||
|
||||
|
@ -50,28 +56,75 @@ public class EntriesCardAdapter extends RecyclerView.Adapter<EntriesCardAdapter.
|
|||
@Override
|
||||
public void onBindViewHolder(EntryViewHolder entryViewHolder, int i) {
|
||||
Entry entry = entries.get(i);
|
||||
|
||||
entryViewHolder.OTPValue.setText(entry.getCurrentOTP());
|
||||
entryViewHolder.OTPLabel.setText(entry.getLabel());
|
||||
entryViewHolder.moveEventCallback = moveEventCallback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntryViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
|
||||
View itemView = LayoutInflater.
|
||||
from(viewGroup.getContext()).
|
||||
inflate(R.layout.card_layout, viewGroup, false);
|
||||
View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.card_layout, viewGroup, false);
|
||||
|
||||
return new EntryViewHolder(itemView);
|
||||
}
|
||||
|
||||
public static class EntryViewHolder extends RecyclerView.ViewHolder {
|
||||
@Override
|
||||
public void onItemDismiss(int position) {
|
||||
entries.remove(position);
|
||||
notifyItemRemoved(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onItemMove(int fromPosition, int toPosition) {
|
||||
if (fromPosition < toPosition) {
|
||||
for (int i = fromPosition; i < toPosition; i++) {
|
||||
Collections.swap(entries, i, i + 1);
|
||||
}
|
||||
} else {
|
||||
for (int i = fromPosition; i > 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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 <strong>not</strong> at the end of a "drop" event.<br/>
|
||||
* <br/>
|
||||
* 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.<br/>
|
||||
* <br/>
|
||||
* 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);
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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.<br/>
|
||||
* </br/>
|
||||
* Expects the <code>RecyclerView.Adapter</code> to listen for {@link
|
||||
* ItemTouchHelperAdapter} callbacks and the <code>RecyclerView.ViewHolder</code> 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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue