diff --git a/build.gradle b/build.gradle
index ea48488f2..41ed6e668 100644
--- a/build.gradle
+++ b/build.gradle
@@ -33,7 +33,6 @@ ext {
}
dependencies {
- implementation project(':libs:EnhancedListView')
playstoreImplementation 'com.google.android.gms:play-services-gcm:12.0.1'
implementation 'org.sufficientlysecure:openpgp-api:10.0'
implementation 'com.soundcloud.android:android-crop:1.0.1@aar'
diff --git a/libs/EnhancedListView/build.gradle b/libs/EnhancedListView/build.gradle
deleted file mode 100644
index b43eedae8..000000000
--- a/libs/EnhancedListView/build.gradle
+++ /dev/null
@@ -1,33 +0,0 @@
-apply plugin: 'com.android.library'
-
-repositories {
- mavenCentral()
- google()
-}
-
-dependencies {
- implementation 'com.android.support:support-v4:27.0.2'
- implementation 'com.nineoldandroids:library:2.4.0'
-}
-
-android {
- compileSdkVersion 27
- buildToolsVersion "27.0.3"
-
- defaultConfig {
- minSdkVersion 14
- targetSdkVersion 25
- versionName "0.3.4"
- versionCode 9
- }
-
- lintOptions {
- abortOnError false
- }
-}
-
-apply plugin: 'maven'
-apply plugin: 'signing'
-
-version = android.defaultConfig.versionName
-group = "de.timroes.android"
diff --git a/libs/EnhancedListView/src/main/AndroidManifest.xml b/libs/EnhancedListView/src/main/AndroidManifest.xml
deleted file mode 100644
index 5f9f17429..000000000
--- a/libs/EnhancedListView/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/libs/EnhancedListView/src/main/java/de/timroes/android/listview/EnhancedListView.java b/libs/EnhancedListView/src/main/java/de/timroes/android/listview/EnhancedListView.java
deleted file mode 100644
index 45222f968..000000000
--- a/libs/EnhancedListView/src/main/java/de/timroes/android/listview/EnhancedListView.java
+++ /dev/null
@@ -1,969 +0,0 @@
-/*
- * Copyright 2012 - 2013 Roman Nurik, Jake Wharton, Tim Roes
- *
- * 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 de.timroes.android.listview;
-
-import android.content.Context;
-import android.graphics.Rect;
-import android.os.Build;
-import android.os.Handler;
-import android.os.Message;
-import android.util.AttributeSet;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.widget.AbsListView;
-import android.widget.Button;
-import android.widget.ListView;
-import android.widget.PopupWindow;
-import android.widget.TextView;
-
-import com.nineoldandroids.animation.Animator;
-import com.nineoldandroids.animation.AnimatorListenerAdapter;
-import com.nineoldandroids.animation.ValueAnimator;
-import com.nineoldandroids.view.ViewHelper;
-import com.nineoldandroids.view.ViewPropertyAnimator;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
-/**
- * A {@link android.widget.ListView} offering enhanced features like Swipe To Dismiss and an
- * undo functionality. See the documentation on GitHub for more information.
- *
- * @author Tim Roes
- */
-public class EnhancedListView extends ListView {
-
- /**
- * Defines the style in which undos should be displayed and handled in the list.
- * Pass this to {@link #setUndoStyle(de.timroes.android.listview.EnhancedListView.UndoStyle)}
- * to change the default behavior from {@link #SINGLE_POPUP}.
- */
- public enum UndoStyle {
-
- /**
- * Shows a popup window, that allows the user to undo the last
- * dismiss. If another element is deleted, the undo popup will undo that deletion.
- * The user is only able to undo the last deletion.
- */
- SINGLE_POPUP,
-
- /**
- * Shows a popup window, that allows the user to undo the last dismiss.
- * If another item is deleted, this will be added to the chain of undos. So pressing
- * undo will undo the last deletion, pressing it again will undo the deletion before that,
- * and so on. As soon as the popup vanished (e.g. because {@link #setUndoHideDelay(int) autoHideDelay}
- * is over) all saved undos will be discarded.
- */
- MULTILEVEL_POPUP,
-
- /**
- * Shows a popup window, that allows the user to undo the last dismisses.
- * If another item is deleted, while there is still an undo popup visible, the label
- * of the button changes to Undo all and a press on the button, will discard
- * all stored undos. As soon as the popup vanished (e.g. because {@link #setUndoHideDelay(int) autoHideDelay}
- * is over) all saved undos will be discarded.
- */
- COLLAPSED_POPUP
-
- }
-
- /**
- * Defines the direction in which list items can be swiped out to delete them.
- * Use {@link #setSwipeDirection(de.timroes.android.listview.EnhancedListView.SwipeDirection)}
- * to change the default behavior.
- *
- * Note: This method requires the Swipe to Dismiss feature enabled. Use
- * {@link #enableSwipeToDismiss()}
- * to enable the feature.
- */
- public enum SwipeDirection {
-
- /**
- * The user can swipe each item into both directions (left and right) to delete it.
- */
- BOTH,
-
- /**
- * The user can only swipe the items to the beginning of the item to
- * delete it. The start of an item is in Left-To-Right languages the left
- * side and in Right-To-Left languages the right side. Before API level
- * 17 this is always the left side.
- */
- START,
-
- /**
- * The user can only swipe the items to the end of the item to delete it.
- * This is in Left-To-Right languages the right side in Right-To-Left
- * languages the left side. Before API level 17 this will always be the
- * right side.
- */
- END
-
- }
-
- /**
- * The callback interface used by {@link #setShouldSwipeCallback(EnhancedListView.OnShouldSwipeCallback)}
- * to inform its client that a list item is going to be swiped and check whether is
- * should or not. Implement this to prevent some items from be swiped.
- */
- public interface OnShouldSwipeCallback {
-
- /**
- * Called when the user is swiping an item from the list.
- *
- * If the user should get the possibility to swipe the item, return true.
- * Otherwise, return false to disable swiping for this item.
- *
- * @param listView The {@link EnhancedListView} the item is wiping from.
- * @param position The position of the item to swipe in your adapter.
- * @return Whether the item should be swiped or not.
- */
- boolean onShouldSwipe(EnhancedListView listView, int position);
-
- }
-
- /**
- * The callback interface used by {@link #setDismissCallback(EnhancedListView.OnDismissCallback)}
- * to inform its client about a successful dismissal of one or more list item positions.
- * Implement this to remove items from your adapter, that has been swiped from the list.
- */
- public interface OnDismissCallback {
-
- /**
- * Called when the user has deleted an item from the list. The item has been deleted from
- * the {@code listView} at {@code position}. Delete this item from your adapter.
- *
- * Don't return from this method, before your item has been deleted from the adapter, meaning
- * if you delete the item in another thread, you have to make sure, you don't return from
- * this method, before the item has been deleted. Since the way how you delete your item
- * depends on your data and adapter, the {@link de.timroes.android.listview.EnhancedListView}
- * cannot handle that synchronizing for you. If you return from this method before you removed
- * the view from the adapter, you will most likely get errors like exceptions and flashing
- * items in the list.
- *
- * If the user should get the possibility to undo this deletion, return an implementation
- * of {@link de.timroes.android.listview.EnhancedListView.Undoable} from this method.
- * If you return {@code null} no undo will be possible. You are free to return an {@code Undoable}
- * for some items, and {@code null} for others, though it might be a horrible user experience.
- *
- * @param listView The {@link EnhancedListView} the item has been deleted from.
- * @param position The position of the item to delete from your adapter.
- * @return An {@link de.timroes.android.listview.EnhancedListView.Undoable}, if you want
- * to give the user the possibility to undo the deletion.
- */
- Undoable onDismiss(EnhancedListView listView, int position);
-
- }
-
- /**
- * Extend this abstract class and return it from
- * {@link EnhancedListView.OnDismissCallback#onDismiss(EnhancedListView, int)}
- * to let the user undo the deletion you've done with your {@link EnhancedListView.OnDismissCallback}.
- * You have at least to implement the {@link #undo()} method, and can override {@link #discard()}
- * and {@link #getTitle()} to offer more functionality. See the README file for example implementations.
- */
- public abstract static class Undoable {
-
- /**
- * This method must undo the deletion you've done in
- * {@link EnhancedListView.OnDismissCallback#onDismiss(EnhancedListView, int)} and reinsert
- * the element into the adapter.
- *
- * In the most implementations, you will only remove the list item from your adapter
- * in the {@code onDismiss} method and delete it from the database (or your permanent
- * storage) in {@link #discard()}. In that case you only need to reinsert the item
- * to the adapter.
- */
- public abstract void undo();
-
- /**
- * Returns the individual undo message for this undo. This will be displayed in the undo
- * window, beside the undo button. The default implementation returns {@code null},
- * what will lead in a default message to be displayed in the undo window.
- * Don't call the super method, when overriding this method.
- *
- * @return The title for a special string.
- */
- public String getTitle() {
- return null;
- }
-
- /**
- * Discard the undo, meaning the user has no longer the possibility to undo the deletion.
- * Implement this, to finally delete your stuff from permanent storages like databases
- * (whereas in {@link de.timroes.android.listview.EnhancedListView.OnDismissCallback#onKeyDown(int, android.view.KeyEvent)}
- * you should only remove it from the list adapter).
- */
- public void discard() { }
-
- }
-
- private class PendingDismissData implements Comparable {
-
- public int position;
- /**
- * The view that should get swiped out.
- */
- public View view;
- /**
- * The whole list item view.
- */
- public View childView;
-
- PendingDismissData(int position, View view, View childView) {
- this.position = position;
- this.view = view;
- this.childView = childView;
- }
-
- @Override
- public int compareTo(PendingDismissData other) {
- // Sort by descending position
- return other.position - position;
- }
-
- }
-
- private class UndoClickListener implements OnClickListener {
-
- /**
- * Called when a view has been clicked.
- *
- * @param v The view that was clicked.
- */
- @Override
- public void onClick(View v) {
- if(!mUndoActions.isEmpty()) {
- switch(mUndoStyle) {
- case SINGLE_POPUP:
- mUndoActions.get(0).undo();
- mUndoActions.clear();
- break;
- case COLLAPSED_POPUP:
- Collections.reverse(mUndoActions);
- for(Undoable undo : mUndoActions) {
- undo.undo();
- }
- mUndoActions.clear();
- break;
- case MULTILEVEL_POPUP:
- mUndoActions.get(mUndoActions.size() - 1).undo();
- mUndoActions.remove(mUndoActions.size() - 1);
- break;
- }
- }
-
- // Dismiss dialog or change text
- if(mUndoActions.isEmpty()) {
- if(mUndoPopup.isShowing()) {
- mUndoPopup.dismiss();
- }
- } else {
- changePopupText();
- changeButtonLabel();
- }
-
- mValidDelayedMsgId++;
- }
- }
-
- private class HideUndoPopupHandler extends Handler {
-
- /**
- * Subclasses must implement this to receive messages.
- */
- @Override
- public void handleMessage(Message msg) {
- if(msg.what == mValidDelayedMsgId) {
- discardUndo();
- }
- }
- }
-
- // Cached ViewConfiguration and system-wide constant values
- private float mSlop;
- private int mMinFlingVelocity;
- private int mMaxFlingVelocity;
- private long mAnimationTime;
-
- private final Object[] mAnimationLock = new Object[0];
-
- // Swipe-To-Dismiss
- private boolean mSwipeEnabled;
- private OnDismissCallback mDismissCallback;
- private OnShouldSwipeCallback mShouldSwipeCallback;
- private UndoStyle mUndoStyle = UndoStyle.SINGLE_POPUP;
- private boolean mTouchBeforeAutoHide = true;
- private SwipeDirection mSwipeDirection = SwipeDirection.BOTH;
- private int mUndoHideDelay = 5000;
- private int mSwipingLayout;
-
- private List mUndoActions = new ArrayList();
- private SortedSet mPendingDismisses = new TreeSet();
- private List mAnimatedViews = new LinkedList();
- private int mDismissAnimationRefCount;
-
- private boolean mSwipePaused;
- private boolean mSwiping;
- private int mViewWidth = 1; // 1 and not 0 to prevent dividing by zero
- private View mSwipeDownView;
- private View mSwipeDownChild;
- private TextView mUndoPopupTextView;
- private VelocityTracker mVelocityTracker;
- private float mDownX;
- private int mDownPosition;
- private float mScreenDensity;
-
- private PopupWindow mUndoPopup;
- private int mValidDelayedMsgId;
- private Handler mHideUndoHandler = new HideUndoPopupHandler();
- private Button mUndoButton;
- // END Swipe-To-Dismiss
-
- /**
- * {@inheritDoc}
- */
- public EnhancedListView(Context context) {
- super(context);
- init(context);
- }
-
- /**
- * {@inheritDoc}
- */
- public EnhancedListView(Context context, AttributeSet attrs) {
- super(context, attrs);
- init(context);
- }
-
- /**
- * {@inheritDoc}
- */
- public EnhancedListView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- init(context);
- }
-
- private void init(Context ctx) {
-
- if(isInEditMode()) {
- // Skip initializing when in edit mode (IDE preview).
- return;
- }
- ViewConfiguration vc =ViewConfiguration.get(ctx);
- mSlop = getResources().getDimension(R.dimen.elv_touch_slop);
- mMinFlingVelocity = vc.getScaledMinimumFlingVelocity();
- mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();
- mAnimationTime = ctx.getResources().getInteger(
- android.R.integer.config_shortAnimTime);
-
- // Initialize undo popup
- LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- View undoView = inflater.inflate(R.layout.elv_undo_popup, null);
- mUndoButton = (Button)undoView.findViewById(R.id.undo);
- mUndoButton.setOnClickListener(new UndoClickListener());
- mUndoButton.setOnTouchListener(new OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- // If the user touches the screen invalidate the current running delay by incrementing
- // the valid message id. So this delay won't hide the undo popup anymore
- mValidDelayedMsgId++;
- return false;
- }
- });
- mUndoPopupTextView = (TextView)undoView.findViewById(R.id.text);
-
- mUndoPopup = new PopupWindow(undoView, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, false);
- mUndoPopup.setAnimationStyle(R.style.elv_fade_animation);
-
- mScreenDensity = getResources().getDisplayMetrics().density;
- // END initialize undo popup
-
- setOnScrollListener(makeScrollListener());
-
- }
-
- /**
- * Enables the Swipe to Dismiss feature for this list. This allows users to swipe out
- * an list item element to delete it from the list. Every time the user swipes out an element
- * {@link de.timroes.android.listview.EnhancedListView.OnDismissCallback#onDismiss(EnhancedListView, int)}
- * of the given {@link de.timroes.android.listview.EnhancedListView} will be called. To enable
- * undo of the deletion, return an {@link de.timroes.android.listview.EnhancedListView.Undoable}
- * from {@link de.timroes.android.listview.EnhancedListView.OnDismissCallback#onDismiss(EnhancedListView, int)}.
- * Return {@code null}, if you don't want the undo feature enabled. Read the README file
- * or the demo project for more detailed samples.
- *
- * @return The {@link de.timroes.android.listview.EnhancedListView}
- * @throws java.lang.IllegalStateException when you haven't passed an {@link EnhancedListView.OnDismissCallback}
- * to {@link #setDismissCallback(EnhancedListView.OnDismissCallback)} before calling this
- * method.
- */
- public EnhancedListView enableSwipeToDismiss() {
-
- if(mDismissCallback == null) {
- throw new IllegalStateException("You must pass an OnDismissCallback to the list before enabling Swipe to Dismiss.");
- }
-
- mSwipeEnabled = true;
-
- return this;
- }
-
- /**
- * Disables the Swipe to Dismiss feature for this list.
- *
- * @return This {@link de.timroes.android.listview.EnhancedListView}
- */
- public EnhancedListView disableSwipeToDismiss() {
- mSwipeEnabled = false;
- return this;
- }
-
- /**
- * Sets the callback to be called when the user dismissed an item from the list (either by
- * swiping it out - with Swipe to Dismiss enabled - or by deleting it with
- * {@link #delete(int)}). You must call this, before you call {@link #delete(int)} or
- * {@link #enableSwipeToDismiss()} otherwise you will get an {@link java.lang.IllegalStateException}.
- *
- * @param dismissCallback The callback used to handle dismisses of list items.
- * @return This {@link de.timroes.android.listview.EnhancedListView}
- */
- public EnhancedListView setDismissCallback(OnDismissCallback dismissCallback) {
- mDismissCallback = dismissCallback;
- return this;
- }
-
- /**
- * Sets the callback to be called when the user is swiping an item from the list.
- *
- * @param shouldSwipeCallback The callback used to handle swipes of list items.
- * @return This {@link de.timroes.android.listview.EnhancedListView}
- */
- public EnhancedListView setShouldSwipeCallback(OnShouldSwipeCallback shouldSwipeCallback) {
- mShouldSwipeCallback = shouldSwipeCallback;
- return this;
- }
-
- /**
- * Sets the undo style of this list. See the javadoc of {@link de.timroes.android.listview.EnhancedListView.UndoStyle}
- * for a detailed explanation of the different styles. The default style (if you never call this
- * method) is {@link de.timroes.android.listview.EnhancedListView.UndoStyle#SINGLE_POPUP}.
- *
- * @param undoStyle The style of this listview.
- * @return This {@link de.timroes.android.listview.EnhancedListView}
- */
- public EnhancedListView setUndoStyle(UndoStyle undoStyle) {
- mUndoStyle = undoStyle;
- return this;
- }
-
- /**
- * Sets the time in milliseconds after which the undo popup automatically disappears.
- * The countdown will start when the user touches the screen. If you want to start the countdown
- * immediately when the popups appears, call {@link #setRequireTouchBeforeDismiss(boolean)} with
- * {@code false}.
- *
- * @param hideDelay The delay in milliseconds.
- * @return This {@link de.timroes.android.listview.EnhancedListView}
- */
- public EnhancedListView setUndoHideDelay(int hideDelay) {
- mUndoHideDelay = hideDelay;
- return this;
- }
-
- /**
- * Sets whether another touch on the view is required before the popup counts down to dismiss
- * the undo popup. By default this is set to {@code true}.
- *
- * @param touchBeforeDismiss Whether the screen needs to be touched before the countdown starts.
- * @return This {@link de.timroes.android.listview.EnhancedListView}
- *
- * @see #setUndoHideDelay(int)
- */
- public EnhancedListView setRequireTouchBeforeDismiss(boolean touchBeforeDismiss) {
- mTouchBeforeAutoHide = touchBeforeDismiss;
- return this;
- }
-
- /**
- * Sets the directions in which a list item can be swiped to delete.
- * By default this is set to {@link SwipeDirection#BOTH} so that an item
- * can be swiped into both directions.
- *
- * Note: This method requires the Swipe to Dismiss feature enabled. Use
- * {@link #enableSwipeToDismiss()} to enable the feature.
- *
- * @param direction The direction to which the swipe should be limited.
- * @return This {@link de.timroes.android.listview.EnhancedListView}
- */
- public EnhancedListView setSwipeDirection(SwipeDirection direction) {
- mSwipeDirection = direction;
- return this;
- }
-
- /**
- * Sets the id of the view, that should be moved, when the user swipes an item.
- * Only the view with the specified id will move, while all other views in the list item, will
- * stay where they are. This might be usefull to have a background behind the view that is swiped
- * out, to stay where it is (and maybe explain that the item is going to be deleted).
- * If you never call this method (or call it with 0), the whole view will be swiped. Also if there
- * is no view in a list item, with the given id, the whole view will be swiped.
- *
- * Note: This method requires the Swipe to Dismiss feature enabled. Use
- * {@link #enableSwipeToDismiss()} to enable the feature.
- *
- * @param swipingLayoutId The id (from R.id) of the view, that should be swiped.
- * @return This {@link de.timroes.android.listview.EnhancedListView}
- */
- public EnhancedListView setSwipingLayout(int swipingLayoutId) {
- mSwipingLayout = swipingLayoutId;
- return this;
- }
-
- /**
- * Discard all stored undos and hide the undo popup dialog.
- * This method must be called in {@link android.app.Activity#onStop()}. Otherwise
- * {@link EnhancedListView.Undoable#discard()} might not be called for several items, what might
- * break your data consistency.
- */
- public void discardUndo() {
- for(Undoable undoable : mUndoActions) {
- undoable.discard();
- }
- mUndoActions.clear();
- if(mUndoPopup.isShowing()) {
- mUndoPopup.dismiss();
- }
- }
-
- /**
- * Delete the list item at the specified position. This will animate the item sliding out of the
- * list and then collapsing until it vanished (same as if the user slides out an item).
- *
- * NOTE: If you are using list headers, be aware, that the position argument must take care of
- * them. Meaning 0 references the first list header. So if you want to delete the first list
- * item, you have to pass the number of list headers as {@code position}. Most of the times
- * that shouldn't be a problem, since you most probably will evaluate the position which should
- * be deleted in a way, that respects the list headers.
- *
- * @param position The position of the item in the list.
- * @throws java.lang.IndexOutOfBoundsException when trying to delete an item outside of the list range.
- * @throws java.lang.IllegalStateException when this method is called before an {@link EnhancedListView.OnDismissCallback}
- * is set via {@link #setDismissCallback(de.timroes.android.listview.EnhancedListView.OnDismissCallback)}.
- * */
- public void delete(int position) {
- if(mDismissCallback == null) {
- throw new IllegalStateException("You must set an OnDismissCallback, before deleting items.");
- }
- if(position < 0 || position >= getCount()) {
- throw new IndexOutOfBoundsException(String.format("Tried to delete item %d. #items in list: %d", position, getCount()));
- }
- View childView = getChildAt(position - getFirstVisiblePosition());
- View view = null;
- if(mSwipingLayout > 0) {
- view = childView.findViewById(mSwipingLayout);
- }
- if(view == null) {
- view = childView;
- }
- slideOutView(view, childView, position, true);
- }
-
- /**
- * Slide out a view to the right or left of the list. After the animation has finished, the
- * view will be dismissed by calling {@link #performDismiss(android.view.View, android.view.View, int)}.
- *
- * @param view The view, that should be slided out.
- * @param childView The whole view of the list item.
- * @param position The item position of the item.
- * @param toRightSide Whether it should slide out to the right side.
- */
- private void slideOutView(final View view, final View childView, final int position, boolean toRightSide) {
-
- // Only start new animation, if this view isn't already animated (too fast swiping bug)
- synchronized(mAnimationLock) {
- if(mAnimatedViews.contains(view)) {
- return;
- }
- ++mDismissAnimationRefCount;
- mAnimatedViews.add(view);
- }
-
- ViewPropertyAnimator.animate(view)
- .translationX(toRightSide ? mViewWidth : -mViewWidth)
- .alpha(0)
- .setDuration(mAnimationTime)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- performDismiss(view, childView, position);
- }
- });
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
-
- if (!mSwipeEnabled) {
- return super.onTouchEvent(ev);
- }
-
- // Send a delayed message to hide popup
- if(mTouchBeforeAutoHide && mUndoPopup.isShowing()) {
- mHideUndoHandler.sendMessageDelayed(mHideUndoHandler.obtainMessage(mValidDelayedMsgId), mUndoHideDelay);
- }
-
- // Store width of this list for usage of swipe distance detection
- if (mViewWidth < 2) {
- mViewWidth = getWidth();
- }
-
- switch (ev.getActionMasked()) {
- case MotionEvent.ACTION_DOWN: {
- if (mSwipePaused) {
- return super.onTouchEvent(ev);
- }
-
- // TODO: ensure this is a finger, and set a flag
-
- // Find the child view that was touched (perform a hit test)
- Rect rect = new Rect();
- int childCount = getChildCount();
- int[] listViewCoords = new int[2];
- getLocationOnScreen(listViewCoords);
- int x = (int) ev.getRawX() - listViewCoords[0];
- int y = (int) ev.getRawY() - listViewCoords[1];
- View child;
- for (int i = getHeaderViewsCount(); i < childCount; i++) {
- child = getChildAt(i);
- if(child != null) {
- child.getHitRect(rect);
- if (rect.contains(x, y)) {
- // if a specific swiping layout has been giving, use this to swipe.
- if(mSwipingLayout > 0) {
- View swipingView = child.findViewById(mSwipingLayout);
- if(swipingView != null) {
- mSwipeDownView = swipingView;
- mSwipeDownChild = child;
- break;
- }
- }
- // If no swiping layout has been found, swipe the whole child
- mSwipeDownView = mSwipeDownChild = child;
- break;
- }
- }
- }
-
- if (mSwipeDownView != null) {
- // test if the item should be swiped
- int position = getPositionForView(mSwipeDownView) - getHeaderViewsCount();
- if ((mShouldSwipeCallback == null) ||
- mShouldSwipeCallback.onShouldSwipe(this, position)) {
- mDownX = ev.getRawX();
- mDownPosition = position;
-
- mVelocityTracker = VelocityTracker.obtain();
- mVelocityTracker.addMovement(ev);
- } else {
- // set back to null to revert swiping
- mSwipeDownView = mSwipeDownChild = null;
- }
- }
- super.onTouchEvent(ev);
- return true;
- }
-
- case MotionEvent.ACTION_UP: {
- if (mVelocityTracker == null) {
- break;
- }
-
- float deltaX = ev.getRawX() - mDownX;
- mVelocityTracker.addMovement(ev);
- mVelocityTracker.computeCurrentVelocity(1000);
- float velocityX = Math.abs(mVelocityTracker.getXVelocity());
- float velocityY = Math.abs(mVelocityTracker.getYVelocity());
- boolean dismiss = false;
- boolean dismissRight = false;
- if (Math.abs(deltaX) > mViewWidth / 2 && mSwiping) {
- dismiss = true;
- dismissRight = deltaX > 0;
- } else if (mMinFlingVelocity <= velocityX && velocityX <= mMaxFlingVelocity
- && velocityY < velocityX && mSwiping && isSwipeDirectionValid(mVelocityTracker.getXVelocity())
- && deltaX >= mViewWidth * 0.2f) {
- dismiss = true;
- dismissRight = mVelocityTracker.getXVelocity() > 0;
- }
- if (dismiss) {
- // dismiss
- slideOutView(mSwipeDownView, mSwipeDownChild, mDownPosition, dismissRight);
- } else if(mSwiping) {
- // Swipe back to regular position
- ViewPropertyAnimator.animate(mSwipeDownView)
- .translationX(0)
- .alpha(1)
- .setDuration(mAnimationTime)
- .setListener(null);
- }
- mVelocityTracker = null;
- mDownX = 0;
- mSwipeDownView = null;
- mSwipeDownChild = null;
- mDownPosition = AbsListView.INVALID_POSITION;
- mSwiping = false;
- break;
- }
-
- case MotionEvent.ACTION_MOVE: {
-
- if (mVelocityTracker == null || mSwipePaused) {
- break;
- }
-
- mVelocityTracker.addMovement(ev);
- float deltaX = ev.getRawX() - mDownX;
- // Only start swipe in correct direction
- if(isSwipeDirectionValid(deltaX)) {
- ViewParent parent = getParent();
- if(parent != null) {
- // If we swipe don't allow parent to intercept touch (e.g. like NavigationDrawer does)
- // otherwise swipe would not be working.
- parent.requestDisallowInterceptTouchEvent(true);
- }
- if (Math.abs(deltaX) > mSlop) {
- mSwiping = true;
- requestDisallowInterceptTouchEvent(true);
-
- // Cancel ListView's touch (un-highlighting the item)
- MotionEvent cancelEvent = MotionEvent.obtain(ev);
- cancelEvent.setAction(MotionEvent.ACTION_CANCEL
- | (ev.getActionIndex()
- << MotionEvent.ACTION_POINTER_INDEX_SHIFT));
- super.onTouchEvent(cancelEvent);
- }
- } else {
- // If we swiped into wrong direction, act like this was the new
- // touch down point
- mDownX = ev.getRawX();
- deltaX = 0;
- }
-
- if (mSwiping) {
- ViewHelper.setTranslationX(mSwipeDownView, deltaX);
- ViewHelper.setAlpha(mSwipeDownView, Math.max(0f, Math.min(1f,
- 1f - 2f * Math.abs(deltaX) / mViewWidth)));
- return true;
- }
- break;
- }
- }
- return super.onTouchEvent(ev);
- }
-
- /**
- * Animate the dismissed list item to zero-height and fire the dismiss callback when
- * all dismissed list item animations have completed.
- *
- * @param dismissView The view that has been slided out.
- * @param listItemView The list item view. This is the whole view of the list item, and not just
- * the part, that the user swiped.
- * @param dismissPosition The position of the view inside the list.
- */
- private void performDismiss(final View dismissView, final View listItemView, final int dismissPosition) {
-
- final ViewGroup.LayoutParams lp = listItemView.getLayoutParams();
- final int originalLayoutHeight = lp.height;
-
- int originalHeight = listItemView.getHeight();
- ValueAnimator animator = ValueAnimator.ofInt(originalHeight, 1).setDuration(mAnimationTime);
-
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
-
- // Make sure no other animation is running. Remove animation from running list, that just finished
- boolean noAnimationLeft;
- synchronized(mAnimationLock) {
- --mDismissAnimationRefCount;
- mAnimatedViews.remove(dismissView);
- noAnimationLeft = mDismissAnimationRefCount == 0;
- }
-
- if (noAnimationLeft) {
- // No active animations, process all pending dismisses.
-
- for(PendingDismissData dismiss : mPendingDismisses) {
- if(mUndoStyle == UndoStyle.SINGLE_POPUP) {
- for(Undoable undoable : mUndoActions) {
- undoable.discard();
- }
- mUndoActions.clear();
- }
- Undoable undoable = mDismissCallback.onDismiss(EnhancedListView.this, dismiss.position);
- if(undoable != null) {
- mUndoActions.add(undoable);
- }
- mValidDelayedMsgId++;
- }
-
- if(!mUndoActions.isEmpty()) {
- changePopupText();
- changeButtonLabel();
-
- // Show undo popup
- float yLocationOffset = getResources().getDimension(R.dimen.elv_undo_bottom_offset);
- mUndoPopup.setWidth((int)Math.min(mScreenDensity * 400, getWidth() * 0.9f));
- mUndoPopup.showAtLocation(EnhancedListView.this,
- Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM,
- 0, (int) yLocationOffset);
-
- // Queue the dismiss only if required
- if(!mTouchBeforeAutoHide) {
- // Send a delayed message to hide popup
- mHideUndoHandler.sendMessageDelayed(mHideUndoHandler.obtainMessage(mValidDelayedMsgId),
- mUndoHideDelay);
- }
- }
-
- ViewGroup.LayoutParams lp;
- for (PendingDismissData pendingDismiss : mPendingDismisses) {
- ViewHelper.setAlpha(pendingDismiss.view, 1f);
- ViewHelper.setTranslationX(pendingDismiss.view, 0);
- lp = pendingDismiss.childView.getLayoutParams();
- lp.height = originalLayoutHeight;
- pendingDismiss.childView.setLayoutParams(lp);
- }
-
- mPendingDismisses.clear();
- }
- }
- });
-
- animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator valueAnimator) {
- lp.height = (Integer) valueAnimator.getAnimatedValue();
- listItemView.setLayoutParams(lp);
- }
- });
-
- mPendingDismisses.add(new PendingDismissData(dismissPosition, dismissView, listItemView));
- animator.start();
- }
-
- /**
- * Changes the text of the undo popup. If more then one item can be undone, the number of deleted
- * items will be shown. If only one deletion can be undone, the title of this deletion (or a default
- * string in case the title is {@code null}) will be shown.
- */
- private void changePopupText() {
- String msg = null;
- if(mUndoActions.size() > 1) {
- msg = getResources().getString(R.string.elv_n_items_deleted, mUndoActions.size());
- } else if(mUndoActions.size() >= 1) {
- // Set title from single undoable or when no multiple deletion string
- // is given
- msg = mUndoActions.get(mUndoActions.size() - 1).getTitle();
-
- if(msg == null) {
- msg = getResources().getString(R.string.elv_item_deleted);
- }
- }
- mUndoPopupTextView.setText(msg);
- }
-
- /**
- * Changes the label of the undo button.
- */
- private void changeButtonLabel() {
- String msg;
- if(mUndoActions.size() > 1 && mUndoStyle == UndoStyle.COLLAPSED_POPUP) {
- msg = getResources().getString(R.string.elv_undo_all);
- } else {
- msg = getResources().getString(R.string.elv_undo);
- }
- mUndoButton.setText(msg);
- }
-
- private OnScrollListener makeScrollListener() {
- return new OnScrollListener() {
- @Override
- public void onScrollStateChanged(AbsListView view, int scrollState) {
- mSwipePaused = scrollState == OnScrollListener.SCROLL_STATE_TOUCH_SCROLL;
- }
-
- @Override
- public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
- }
- };
- }
-
- /**
- * Checks whether the delta of a swipe indicates, that the swipe is in the
- * correct direction, regarding the direction set via
- * {@link #setSwipeDirection(de.timroes.android.listview.EnhancedListView.SwipeDirection)}
- *
- * @param deltaX The delta of x coordinate of the swipe.
- * @return Whether the delta of a swipe is in the right direction.
- */
- private boolean isSwipeDirectionValid(float deltaX) {
-
- int rtlSign = 1;
- // On API level 17 and above, check if we are in a Right-To-Left layout
- if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- if(getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
- rtlSign = -1;
- }
- }
-
- // Check if swipe has been done in the correct direction
- switch(mSwipeDirection) {
- default:
- case BOTH:
- return true;
- case START:
- return rtlSign * deltaX < 0;
- case END:
- return rtlSign * deltaX > 0;
- }
-
- }
-
- @Override
- protected void onWindowVisibilityChanged(int visibility) {
- super.onWindowVisibilityChanged(visibility);
-
- /*
- * If the container window no longer visiable,
- * dismiss visible undo popup window so it won't leak,
- * cos the container window will be destroyed before dismissing the popup window.
- */
- if(visibility != View.VISIBLE) {
- discardUndo();
- }
- }
-}
diff --git a/libs/EnhancedListView/src/main/res/anim/elv_popup_hide.xml b/libs/EnhancedListView/src/main/res/anim/elv_popup_hide.xml
deleted file mode 100644
index 9fd948e92..000000000
--- a/libs/EnhancedListView/src/main/res/anim/elv_popup_hide.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/libs/EnhancedListView/src/main/res/anim/elv_popup_show.xml b/libs/EnhancedListView/src/main/res/anim/elv_popup_show.xml
deleted file mode 100644
index 9749c97d9..000000000
--- a/libs/EnhancedListView/src/main/res/anim/elv_popup_show.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/libs/EnhancedListView/src/main/res/drawable-hdpi/elv_ic_action_undo.png b/libs/EnhancedListView/src/main/res/drawable-hdpi/elv_ic_action_undo.png
deleted file mode 100644
index 67c2496f5..000000000
Binary files a/libs/EnhancedListView/src/main/res/drawable-hdpi/elv_ic_action_undo.png and /dev/null differ
diff --git a/libs/EnhancedListView/src/main/res/drawable-hdpi/elv_toast_frame.9.png b/libs/EnhancedListView/src/main/res/drawable-hdpi/elv_toast_frame.9.png
deleted file mode 100644
index 1574c0882..000000000
Binary files a/libs/EnhancedListView/src/main/res/drawable-hdpi/elv_toast_frame.9.png and /dev/null differ
diff --git a/libs/EnhancedListView/src/main/res/drawable-ldpi/elv_ic_action_undo.png b/libs/EnhancedListView/src/main/res/drawable-ldpi/elv_ic_action_undo.png
deleted file mode 100644
index 4a9714756..000000000
Binary files a/libs/EnhancedListView/src/main/res/drawable-ldpi/elv_ic_action_undo.png and /dev/null differ
diff --git a/libs/EnhancedListView/src/main/res/drawable-ldpi/elv_toast_frame.9.png b/libs/EnhancedListView/src/main/res/drawable-ldpi/elv_toast_frame.9.png
deleted file mode 100644
index 6f0f9d2d0..000000000
Binary files a/libs/EnhancedListView/src/main/res/drawable-ldpi/elv_toast_frame.9.png and /dev/null differ
diff --git a/libs/EnhancedListView/src/main/res/drawable-mdpi/elv_ic_action_undo.png b/libs/EnhancedListView/src/main/res/drawable-mdpi/elv_ic_action_undo.png
deleted file mode 100644
index 93261188a..000000000
Binary files a/libs/EnhancedListView/src/main/res/drawable-mdpi/elv_ic_action_undo.png and /dev/null differ
diff --git a/libs/EnhancedListView/src/main/res/drawable-mdpi/elv_toast_frame.9.png b/libs/EnhancedListView/src/main/res/drawable-mdpi/elv_toast_frame.9.png
deleted file mode 100644
index e1ff0ebe8..000000000
Binary files a/libs/EnhancedListView/src/main/res/drawable-mdpi/elv_toast_frame.9.png and /dev/null differ
diff --git a/libs/EnhancedListView/src/main/res/drawable-xhdpi/elv_ic_action_undo.png b/libs/EnhancedListView/src/main/res/drawable-xhdpi/elv_ic_action_undo.png
deleted file mode 100644
index 2b7996036..000000000
Binary files a/libs/EnhancedListView/src/main/res/drawable-xhdpi/elv_ic_action_undo.png and /dev/null differ
diff --git a/libs/EnhancedListView/src/main/res/drawable-xhdpi/elv_toast_frame.9.png b/libs/EnhancedListView/src/main/res/drawable-xhdpi/elv_toast_frame.9.png
deleted file mode 100644
index 334a5bde2..000000000
Binary files a/libs/EnhancedListView/src/main/res/drawable-xhdpi/elv_toast_frame.9.png and /dev/null differ
diff --git a/libs/EnhancedListView/src/main/res/drawable-xxhdpi/elv_ic_action_undo.png b/libs/EnhancedListView/src/main/res/drawable-xxhdpi/elv_ic_action_undo.png
deleted file mode 100644
index aafe28670..000000000
Binary files a/libs/EnhancedListView/src/main/res/drawable-xxhdpi/elv_ic_action_undo.png and /dev/null differ
diff --git a/libs/EnhancedListView/src/main/res/drawable-xxhdpi/elv_toast_frame.9.png b/libs/EnhancedListView/src/main/res/drawable-xxhdpi/elv_toast_frame.9.png
deleted file mode 100644
index 99efd3fe9..000000000
Binary files a/libs/EnhancedListView/src/main/res/drawable-xxhdpi/elv_toast_frame.9.png and /dev/null differ
diff --git a/libs/EnhancedListView/src/main/res/drawable/elv_popup_bg.xml b/libs/EnhancedListView/src/main/res/drawable/elv_popup_bg.xml
deleted file mode 100644
index 4dfc0880e..000000000
--- a/libs/EnhancedListView/src/main/res/drawable/elv_popup_bg.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/libs/EnhancedListView/src/main/res/drawable/elv_undo_btn_bg.xml b/libs/EnhancedListView/src/main/res/drawable/elv_undo_btn_bg.xml
deleted file mode 100644
index fde26ad09..000000000
--- a/libs/EnhancedListView/src/main/res/drawable/elv_undo_btn_bg.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/libs/EnhancedListView/src/main/res/drawable/elv_undo_btn_bg_focused.xml b/libs/EnhancedListView/src/main/res/drawable/elv_undo_btn_bg_focused.xml
deleted file mode 100644
index d3c63634a..000000000
--- a/libs/EnhancedListView/src/main/res/drawable/elv_undo_btn_bg_focused.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/libs/EnhancedListView/src/main/res/drawable/elv_undo_btn_bg_pressed.xml b/libs/EnhancedListView/src/main/res/drawable/elv_undo_btn_bg_pressed.xml
deleted file mode 100644
index ca09bdb8a..000000000
--- a/libs/EnhancedListView/src/main/res/drawable/elv_undo_btn_bg_pressed.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/libs/EnhancedListView/src/main/res/layout-v19/elv_undo_popup.xml b/libs/EnhancedListView/src/main/res/layout-v19/elv_undo_popup.xml
deleted file mode 100644
index 23081757d..000000000
--- a/libs/EnhancedListView/src/main/res/layout-v19/elv_undo_popup.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/libs/EnhancedListView/src/main/res/layout/elv_undo_popup.xml b/libs/EnhancedListView/src/main/res/layout/elv_undo_popup.xml
deleted file mode 100644
index 4e807221a..000000000
--- a/libs/EnhancedListView/src/main/res/layout/elv_undo_popup.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/libs/EnhancedListView/src/main/res/values-v19/colors.xml b/libs/EnhancedListView/src/main/res/values-v19/colors.xml
deleted file mode 100644
index c6e7400c3..000000000
--- a/libs/EnhancedListView/src/main/res/values-v19/colors.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
- #33FFFFFF
-
\ No newline at end of file
diff --git a/libs/EnhancedListView/src/main/res/values/colors.xml b/libs/EnhancedListView/src/main/res/values/colors.xml
deleted file mode 100644
index 9d081f2c1..000000000
--- a/libs/EnhancedListView/src/main/res/values/colors.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
- #ff33b5e5
- #ff0099cc
- #00000000
-
- #EE666666
- #BBBBBB
- #FFFFFF
-
\ No newline at end of file
diff --git a/libs/EnhancedListView/src/main/res/values/dimens.xml b/libs/EnhancedListView/src/main/res/values/dimens.xml
deleted file mode 100644
index f2b863a12..000000000
--- a/libs/EnhancedListView/src/main/res/values/dimens.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
- 15dp
-
- 32dp
-
\ No newline at end of file
diff --git a/libs/EnhancedListView/src/main/res/values/strings.xml b/libs/EnhancedListView/src/main/res/values/strings.xml
deleted file mode 100644
index b758828d7..000000000
--- a/libs/EnhancedListView/src/main/res/values/strings.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
- Undo
- Undo All
- Item deleted
- %1$s items deleted
-
\ No newline at end of file
diff --git a/libs/EnhancedListView/src/main/res/values/styles.xml b/libs/EnhancedListView/src/main/res/values/styles.xml
deleted file mode 100644
index 43b2f0938..000000000
--- a/libs/EnhancedListView/src/main/res/values/styles.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationsOverviewFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationsOverviewFragment.java
index d67bb13ee..8761a4710 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationsOverviewFragment.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationsOverviewFragment.java
@@ -32,7 +32,13 @@ package eu.siacs.conversations.ui;
import android.app.Activity;
import android.app.Fragment;
import android.databinding.DataBindingUtil;
+import android.graphics.Canvas;
+import android.graphics.Paint;
import android.os.Bundle;
+import android.support.design.widget.Snackbar;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.helper.ItemTouchHelper;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -41,7 +47,6 @@ import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;
-import de.timroes.android.listview.EnhancedListView;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.FragmentConversationsOverviewBinding;
@@ -49,10 +54,15 @@ import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.ui.adapter.ConversationAdapter;
import eu.siacs.conversations.ui.interfaces.OnConversationArchived;
import eu.siacs.conversations.ui.interfaces.OnConversationSelected;
+import eu.siacs.conversations.ui.util.Color;
+import eu.siacs.conversations.ui.util.PendingActionHelper;
import eu.siacs.conversations.ui.util.PendingItem;
import eu.siacs.conversations.ui.util.ScrollState;
-public class ConversationsOverviewFragment extends XmppFragment implements EnhancedListView.OnDismissCallback {
+import static android.support.v7.widget.helper.ItemTouchHelper.LEFT;
+import static android.support.v7.widget.helper.ItemTouchHelper.RIGHT;
+
+public class ConversationsOverviewFragment extends XmppFragment {
private static final String STATE_SCROLL_POSITION = ConversationsOverviewFragment.class.getName()+".scroll_state";
@@ -62,6 +72,98 @@ public class ConversationsOverviewFragment extends XmppFragment implements Enhan
private FragmentConversationsOverviewBinding binding;
private ConversationAdapter conversationsAdapter;
private XmppActivity activity;
+ private PendingActionHelper pendingActionHelper = new PendingActionHelper();
+
+ private ItemTouchHelper.SimpleCallback callback = new ItemTouchHelper.SimpleCallback(0,LEFT|RIGHT) {
+ @Override
+ public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
+ //todo maybe we can manually changing the position of the conversation
+ return false;
+ }
+
+ @Override
+ public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
+ float dX, float dY, int actionState, boolean isCurrentlyActive) {
+ super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
+ if(actionState != ItemTouchHelper.ACTION_STATE_IDLE){
+ Paint paint = new Paint();
+ paint.setColor(Color.get(activity,R.attr.conversations_overview_background));
+ paint.setStyle(Paint.Style.FILL);
+ c.drawRect(viewHolder.itemView.getLeft(),viewHolder.itemView.getTop()
+ ,viewHolder.itemView.getRight(),viewHolder.itemView.getBottom(), paint);
+ }
+ }
+
+ @Override
+ public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
+ super.clearView(recyclerView, viewHolder);
+ viewHolder.itemView.setAlpha(1f);
+ }
+
+ @Override
+ public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
+ pendingActionHelper.execute();
+ int position = viewHolder.getLayoutPosition();
+ try {
+ swipedConversation.push(conversations.get(position));
+ } catch (IndexOutOfBoundsException e) {
+ return;
+ }
+ conversationsAdapter.remove(swipedConversation.peek(), position);
+ activity.xmppConnectionService.markRead(swipedConversation.peek());
+
+ if (position == 0 && conversationsAdapter.getItemCount() == 0) {
+ final Conversation c = swipedConversation.pop();
+ activity.xmppConnectionService.archiveConversation(c);
+ return;
+ }
+ final boolean formerlySelected = ConversationFragment.getConversation(getActivity()) == swipedConversation.peek();
+ if (activity instanceof OnConversationArchived) {
+ ((OnConversationArchived) activity).onConversationArchived(swipedConversation.peek());
+ }
+ boolean isMuc = swipedConversation.peek().getMode() == Conversation.MODE_MULTI;
+ int title = isMuc ? R.string.title_undo_swipe_out_muc : R.string.title_undo_swipe_out_conversation;
+
+ pendingActionHelper.push(() -> {
+ Conversation c = swipedConversation.pop();
+ if(c != null){
+ if (!c.isRead() && c.getMode() == Conversation.MODE_SINGLE) {
+ return;
+ }
+ activity.xmppConnectionService.archiveConversation(c);
+ }
+ });
+ Snackbar.make(binding.list, title, 5000)
+ .setAction(R.string.undo, v -> {
+ pendingActionHelper.undo();
+ Conversation c = swipedConversation.pop();
+ conversationsAdapter.insert(c, position);
+ if (formerlySelected) {
+ if (activity instanceof OnConversationSelected) {
+ ((OnConversationSelected) activity).onConversationSelected(c);
+ }
+ }
+ LinearLayoutManager layoutManager = (LinearLayoutManager) binding.list.getLayoutManager();
+ if (position > layoutManager.findLastVisibleItemPosition()) {
+ binding.list.smoothScrollToPosition(position);
+ }
+ })
+ .addCallback(new Snackbar.Callback() {
+ @Override
+ public void onDismissed(Snackbar transientBottomBar, int event) {
+ switch (event) {
+ case DISMISS_EVENT_SWIPE:
+ case DISMISS_EVENT_TIMEOUT:
+ pendingActionHelper.execute();
+ break;
+ }
+ }
+ })
+ .show();
+ }
+ };
+
+ private ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
public static Conversation getSuggestion(Activity activity) {
final Conversation exception;
@@ -112,6 +214,13 @@ public class ConversationsOverviewFragment extends XmppFragment implements Enhan
}
}
+ @Override
+ public void onPause() {
+ Log.d(Config.LOGTAG,"ConversationsOverviewFragment.onPause()");
+ pendingActionHelper.execute();
+ super.onPause();
+ }
+
@Override
public void onDetach() {
super.onDetach();
@@ -125,22 +234,16 @@ public class ConversationsOverviewFragment extends XmppFragment implements Enhan
this.binding.fab.setOnClickListener((view) -> StartConversationActivity.launch(getActivity()));
this.conversationsAdapter = new ConversationAdapter(this.activity, this.conversations);
- this.binding.list.setAdapter(this.conversationsAdapter);
- this.binding.list.setOnItemClickListener((parent, view, position, id) -> {
- Conversation conversation = this.conversations.get(position);
+ this.conversationsAdapter.setConversationClickListener((view, conversation) -> {
if (activity instanceof OnConversationSelected) {
((OnConversationSelected) activity).onConversationSelected(conversation);
} else {
Log.w(ConversationsOverviewFragment.class.getCanonicalName(), "Activity does not implement OnConversationSelected");
}
});
- this.binding.list.setDismissCallback(this);
- this.binding.list.enableSwipeToDismiss();
- this.binding.list.setSwipeDirection(EnhancedListView.SwipeDirection.BOTH);
- this.binding.list.setSwipingLayout(R.id.swipeable_item);
- this.binding.list.setUndoStyle(EnhancedListView.UndoStyle.SINGLE_POPUP);
- this.binding.list.setUndoHideDelay(5000);
- this.binding.list.setRequireTouchBeforeDismiss(false);
+ this.binding.list.setAdapter(this.conversationsAdapter);
+ this.binding.list.setLayoutManager(new LinearLayoutManager(getActivity(),LinearLayoutManager.VERTICAL,false));
+ this.touchHelper.attachToRecyclerView(this.binding.list);
return binding.getRoot();
}
@@ -162,7 +265,8 @@ public class ConversationsOverviewFragment extends XmppFragment implements Enhan
if (this.binding == null) {
return null;
}
- int position = this.binding.list.getFirstVisiblePosition();
+ LinearLayoutManager layoutManager = (LinearLayoutManager) this.binding.list.getLayoutManager();
+ int position = layoutManager.findFirstVisibleItemPosition();
final View view = this.binding.list.getChildAt(0);
if (view != null) {
return new ScrollState(position,view.getTop());
@@ -198,7 +302,7 @@ public class ConversationsOverviewFragment extends XmppFragment implements Enhan
if (removed.isRead()) {
this.conversations.remove(removed);
} else {
- this.binding.list.discardUndo(); //will be ignored during discard when conversation is unRead
+ pendingActionHelper.execute();
}
}
this.conversationsAdapter.notifyDataSetChanged();
@@ -210,62 +314,8 @@ public class ConversationsOverviewFragment extends XmppFragment implements Enhan
private void setScrollPosition(ScrollState scrollPosition) {
if (scrollPosition != null) {
- this.binding.list.setSelectionFromTop(scrollPosition.position, scrollPosition.offset);
+ LinearLayoutManager layoutManager = (LinearLayoutManager) binding.list.getLayoutManager();
+ layoutManager.scrollToPositionWithOffset(scrollPosition.position, scrollPosition.offset);
}
}
-
- @Override
- public EnhancedListView.Undoable onDismiss(EnhancedListView listView, int position) {
- try {
- swipedConversation.push(this.conversationsAdapter.getItem(position));
- } catch (IndexOutOfBoundsException e) {
- return null;
- }
- this.conversationsAdapter.remove(swipedConversation.peek());
- this.activity.xmppConnectionService.markRead(swipedConversation.peek());
-
- if (position == 0 && this.conversationsAdapter.getCount() == 0) {
- final Conversation c = swipedConversation.pop();
- activity.xmppConnectionService.archiveConversation(c);
- return null;
- }
- final boolean formerlySelected = ConversationFragment.getConversation(getActivity()) == swipedConversation.peek();
- if (activity instanceof OnConversationArchived) {
- ((OnConversationArchived) activity).onConversationArchived(swipedConversation.peek());
- }
- return new EnhancedListView.Undoable() {
-
- @Override
- public void undo() {
- Conversation c = swipedConversation.pop();
- conversationsAdapter.insert(c, position);
- if (formerlySelected) {
- if (activity instanceof OnConversationSelected) {
- ((OnConversationSelected) activity).onConversationSelected(c);
- }
- }
- if (position > listView.getLastVisiblePosition()) {
- listView.smoothScrollToPosition(position);
- }
- }
-
- @Override
- public void discard() {
- Conversation c = swipedConversation.pop();
- if (!c.isRead() && c.getMode() == Conversation.MODE_SINGLE) {
- return;
- }
- activity.xmppConnectionService.archiveConversation(c);
- }
-
- @Override
- public String getTitle() {
- if (swipedConversation.peek().getMode() == Conversation.MODE_MULTI) {
- return getResources().getString(R.string.title_undo_swipe_out_muc);
- } else {
- return getResources().getString(R.string.title_undo_swipe_out_conversation);
- }
- }
- };
- }
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java
index febdc4c07..3c267c77a 100644
--- a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java
@@ -5,13 +5,11 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.ListView;
import android.widget.Toast;
import java.net.URLConnection;
@@ -58,7 +56,7 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
private Share share;
private static final int REQUEST_START_NEW_CONVERSATION = 0x0501;
- private ListView mListView;
+ private RecyclerView mListView;
private ConversationAdapter mAdapter;
private List mConversations = new ArrayList<>();
private Toast mToast;
@@ -170,15 +168,9 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
mListView = findViewById(R.id.choose_conversation_list);
mAdapter = new ConversationAdapter(this, this.mConversations);
+ mListView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false));
mListView.setAdapter(mAdapter);
- mListView.setOnItemClickListener(new OnItemClickListener() {
-
- @Override
- public void onItemClick(AdapterView> arg0, View arg1, int position, long arg3) {
- share(mConversations.get(position));
- }
- });
-
+ mAdapter.setConversationClickListener((view, conversation) -> share(conversation));
this.share = new Share();
}
diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java
index e0b6595e9..4de873b2f 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java
@@ -8,12 +8,11 @@ import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.support.annotation.NonNull;
-import android.util.Log;
+import android.support.v7.widget.RecyclerView;
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
@@ -21,28 +20,26 @@ import java.lang.ref.WeakReference;
import java.util.List;
import java.util.concurrent.RejectedExecutionException;
-import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.Transferable;
-import eu.siacs.conversations.ui.ConversationFragment;
import eu.siacs.conversations.ui.XmppActivity;
-import eu.siacs.conversations.ui.util.Color;
import eu.siacs.conversations.ui.widget.UnreadCountCustomView;
import eu.siacs.conversations.utils.EmojiWrapper;
import eu.siacs.conversations.utils.IrregularUnicodeDetector;
import eu.siacs.conversations.utils.UIHelper;
import rocks.xmpp.addr.Jid;
-public class ConversationAdapter extends ArrayAdapter {
+public class ConversationAdapter extends RecyclerView.Adapter {
private XmppActivity activity;
- private Conversation selectedConversation = null;
+ private List conversations;
+ private OnConversationClickListener listener;
public ConversationAdapter(XmppActivity activity, List conversations) {
- super(activity, 0, conversations);
this.activity = activity;
+ this.conversations = conversations;
}
private static boolean cancelPotentialWork(Conversation conversation, ImageView imageView) {
@@ -70,20 +67,21 @@ public class ConversationAdapter extends ArrayAdapter {
return null;
}
+ @NonNull
@Override
- public @NonNull
- View getView(int position, View view, @NonNull ViewGroup parent) {
- if (view == null) {
- LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- view = inflater.inflate(R.layout.conversation_list_row, parent, false);
- }
- ViewHolder viewHolder = ViewHolder.get(view);
- Conversation conversation = getItem(position);
+ public ConversationViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ View view = inflater.inflate(R.layout.conversation_list_row, parent, false);
+ ConversationViewHolder conversationViewHolder = ConversationViewHolder.get(view);
+ return conversationViewHolder;
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ConversationViewHolder viewHolder, int position) {
+ Conversation conversation = conversations.get(position);
if (conversation == null) {
- return view;
+ return;
}
- int c = Color.get(activity, conversation == selectedConversation ? R.attr.color_background_secondary : R.attr.color_background_primary);
- viewHolder.swipeableItem.setBackgroundColor(c);
if (conversation.getMode() == Conversation.MODE_SINGLE || activity.useSubjectToIdentifyConference()) {
CharSequence name = conversation.getName();
if (name instanceof Jid) {
@@ -218,14 +216,16 @@ public class ConversationAdapter extends ArrayAdapter {
}
viewHolder.timestamp.setText(UIHelper.readableTimeDifference(activity, timestamp));
loadAvatar(conversation, viewHolder.avatar);
-
- return view;
+ viewHolder.itemView.setOnClickListener(v -> listener.onConversationClick(v,conversation));
}
@Override
- public void notifyDataSetChanged() {
- this.selectedConversation = ConversationFragment.getConversation(activity);
- super.notifyDataSetChanged();
+ public int getItemCount() {
+ return conversations.size();
+ }
+
+ public void setConversationClickListener(OnConversationClickListener listener) {
+ this.listener = listener;
}
private void loadAvatar(Conversation conversation, ImageView imageView) {
@@ -249,8 +249,17 @@ public class ConversationAdapter extends ArrayAdapter {
}
}
- public static class ViewHolder {
- private View swipeableItem;
+ public void insert(Conversation c, int position) {
+ conversations.add(position,c);
+ notifyDataSetChanged();
+ }
+
+ public void remove(Conversation conversation,int position) {
+ conversations.remove(conversation);
+ notifyItemRemoved(position);
+ }
+
+ public static class ConversationViewHolder extends RecyclerView.ViewHolder {
private TextView name;
private TextView lastMessage;
private ImageView lastMessageIcon;
@@ -260,26 +269,25 @@ public class ConversationAdapter extends ArrayAdapter {
private UnreadCountCustomView unreadCount;
private ImageView avatar;
- private ViewHolder() {
-
+ private ConversationViewHolder(View view) {
+ super(view);
}
- public static ViewHolder get(View layout) {
- ViewHolder viewHolder = (ViewHolder) layout.getTag();
- if (viewHolder == null) {
- viewHolder = new ViewHolder();
- viewHolder.swipeableItem = layout.findViewById(R.id.swipeable_item);
- viewHolder.name = layout.findViewById(R.id.conversation_name);
- viewHolder.lastMessage = layout.findViewById(R.id.conversation_lastmsg);
- viewHolder.lastMessageIcon = layout.findViewById(R.id.conversation_lastmsg_img);
- viewHolder.timestamp = layout.findViewById(R.id.conversation_lastupdate);
- viewHolder.sender = layout.findViewById(R.id.sender_name);
- viewHolder.notificationIcon = layout.findViewById(R.id.notification_status);
- viewHolder.unreadCount = layout.findViewById(R.id.unread_count);
- viewHolder.avatar = layout.findViewById(R.id.conversation_image);
- layout.setTag(viewHolder);
+ public static ConversationViewHolder get(View layout) {
+ ConversationViewHolder conversationViewHolder = (ConversationViewHolder) layout.getTag();
+ if (conversationViewHolder == null) {
+ conversationViewHolder = new ConversationViewHolder(layout);
+ conversationViewHolder.name = layout.findViewById(R.id.conversation_name);
+ conversationViewHolder.lastMessage = layout.findViewById(R.id.conversation_lastmsg);
+ conversationViewHolder.lastMessageIcon = layout.findViewById(R.id.conversation_lastmsg_img);
+ conversationViewHolder.timestamp = layout.findViewById(R.id.conversation_lastupdate);
+ conversationViewHolder.sender = layout.findViewById(R.id.sender_name);
+ conversationViewHolder.notificationIcon = layout.findViewById(R.id.notification_status);
+ conversationViewHolder.unreadCount = layout.findViewById(R.id.unread_count);
+ conversationViewHolder.avatar = layout.findViewById(R.id.conversation_image);
+ layout.setTag(conversationViewHolder);
}
- return viewHolder;
+ return conversationViewHolder;
}
}
@@ -321,4 +329,8 @@ public class ConversationAdapter extends ArrayAdapter {
}
}
}
+
+ public interface OnConversationClickListener {
+ void onConversationClick(View view, Conversation conversation);
+ }
}
diff --git a/src/main/java/eu/siacs/conversations/ui/util/PendingActionHelper.java b/src/main/java/eu/siacs/conversations/ui/util/PendingActionHelper.java
new file mode 100644
index 000000000..236cfc795
--- /dev/null
+++ b/src/main/java/eu/siacs/conversations/ui/util/PendingActionHelper.java
@@ -0,0 +1,29 @@
+package eu.siacs.conversations.ui.util;
+
+/**
+ * Created by mxf on 2018/4/3.
+ */
+
+public class PendingActionHelper {
+
+ private PendingAction pendingAction;
+
+ public void push(PendingAction pendingAction) {
+ this.pendingAction = pendingAction;
+ }
+
+ public void execute() {
+ if(pendingAction != null){
+ pendingAction.execute();
+ pendingAction = null;
+ }
+ }
+
+ public void undo() {
+ pendingAction = null;
+ }
+
+ public interface PendingAction {
+ void execute();
+ }
+}
diff --git a/src/main/res/layout/activity_share_with.xml b/src/main/res/layout/activity_share_with.xml
index 9f4afc745..472a27dc6 100644
--- a/src/main/res/layout/activity_share_with.xml
+++ b/src/main/res/layout/activity_share_with.xml
@@ -8,7 +8,7 @@
-
-
-
@@ -81,7 +75,7 @@
android:layout_width="?attr/IconSize"
android:layout_height="?attr/IconSize"
android:layout_marginRight="?attr/TextSeparation"/>
-
+
-
-
+ />
-
+
\ No newline at end of file
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 62d7bf10a..7252c3b9b 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -749,4 +749,5 @@
MediumLargeMessage was not encrypted for this device.
+ undo