Initial framework to allow for dismissing apps in updates tab.

This commit is contained in:
Peter Serwylo 2017-09-27 22:53:00 +10:00
parent 13e2eddb6a
commit 32c17e5f72
4 changed files with 112 additions and 0 deletions

View File

@ -26,6 +26,7 @@ import android.widget.ImageButton;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast;
import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.ImageLoader;
@ -160,6 +161,11 @@ public abstract class AppListItemController extends RecyclerView.ViewHolder {
itemView.setOnClickListener(onAppClicked); itemView.setOnClickListener(onAppClicked);
} }
@Nullable
protected final AppUpdateStatus getCurrentStatus() {
return currentStatus;
}
public void bindModel(@NonNull App app) { public void bindModel(@NonNull App app) {
currentApp = app; currentApp = app;
@ -187,6 +193,36 @@ public abstract class AppListItemController extends RecyclerView.ViewHolder {
broadcastManager.registerReceiver(onStatusChanged, intentFilter); broadcastManager.registerReceiver(onStatusChanged, intentFilter);
} }
/** To be overridden if required */
public boolean canDismiss() {
return false;
}
/**
* If able, forwards the request onto {@link #onDismissApp(App)}.
* This mainly exists to keep the API consistent, in that the {@link App} is threaded through to the relevant
* method with a guarantee that it is not null, rather than every method having to check if it is null or not.
*/
public final void onDismiss() {
if (currentApp != null && canDismiss()) {
CharSequence message = onDismissApp(currentApp);
if (message != null) {
Toast.makeText(activity, message, Toast.LENGTH_SHORT).show();
}
}
}
/**
* Override to respond to the user swiping an app to dismiss it from the list.
* @return Optionally return a description of what you did if it is not obvious to the user. It will be shown as
* a {@link android.widget.Toast} for a {@link android.widget.Toast#LENGTH_SHORT} time.
* @see #canDismiss() This must also be overriden and should return true.
*/
@Nullable
protected CharSequence onDismissApp(@NonNull App app) {
return null;
}
/** /**
* Updates both the progress bar and the circular install button (which shows progress around the outside of * Updates both the progress bar and the circular install button (which shows progress around the outside of
* the circle). Also updates the app label to indicate that the app is being downloaded. * the circle). Also updates the app label to indicate that the app is being downloaded.

View File

@ -341,4 +341,6 @@ public class UpdatesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
} }
}; };
public void onItemDismissed() {
}
} }

View File

@ -0,0 +1,70 @@
package org.fdroid.fdroid.views.updates;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import org.fdroid.fdroid.views.apps.AppListItemController;
import org.fdroid.fdroid.views.updates.items.AppStatusListItemController;
import org.fdroid.fdroid.views.updates.items.KnownVulnAppListItemController;
import org.fdroid.fdroid.views.updates.items.UpdateableAppListItemController;
/**
* Certain views within the {@link UpdatesAdapter} can be swiped to dismiss. Depending on which item is swiped, there
* is a different behaviour, but all of it revolves around dismissing the item.
*
* <ul>
* <li>
* {@link KnownVulnAppListItemController}: Will be marked as "Ignored" and wont warn the user in the future.
* </li>
* <li>
* {@link UpdateableAppListItemController}: Will get marked as "Ignore this update".
* </li>
* <li>
* {@link AppStatusListItemController}:
* <ul>
* <li>If downloading or queued to download, cancel the download.</li>
* <li>If downloaded waiting to install, forget that we downloaded it.</li>
* <li>If installed ready to run, stop prompting the user to run the app.</li>
* </ul>
* <li>
* </ul>
*/
public class UpdatesItemTouchCallback extends ItemTouchHelper.Callback {
private final UpdatesAdapter adapter;
public UpdatesItemTouchCallback(UpdatesAdapter adapter) {
this.adapter = adapter;
}
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int swipeFlags = 0;
if (viewHolder instanceof AppListItemController) {
AppListItemController controller = (AppListItemController) viewHolder;
if (controller.canDismiss()) {
swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
}
}
return makeMovementFlags(0, swipeFlags);
}
@Override
public boolean onMove(
RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
return false;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
AppListItemController controller = (AppListItemController) viewHolder;
controller.onDismiss();
adapter.onItemDismissed();
}
@Override
public boolean isItemViewSwipeEnabled() {
return true;
}
}

View File

@ -3,6 +3,7 @@ package org.fdroid.fdroid.views.updates;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.view.View; import android.view.View;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.ImageView; import android.widget.ImageView;
@ -28,6 +29,9 @@ public class UpdatesViewBinder {
list.setLayoutManager(new LinearLayoutManager(activity)); list.setLayoutManager(new LinearLayoutManager(activity));
list.setAdapter(adapter); list.setAdapter(adapter);
ItemTouchHelper touchHelper = new ItemTouchHelper(new UpdatesItemTouchCallback(adapter));
touchHelper.attachToRecyclerView(list);
emptyState = (TextView) view.findViewById(R.id.empty_state); emptyState = (TextView) view.findViewById(R.id.empty_state);
emptyImage = (ImageView) view.findViewById(R.id.image); emptyImage = (ImageView) view.findViewById(R.id.image);
} }