diff --git a/app/build.gradle b/app/build.gradle index c53951140..858c362c0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -64,11 +64,11 @@ dependencies { testCompile "org.robolectric:robolectric:3.2.2" compile fileTree(dir: 'libs', include: ['*.jar']) - compile 'com.android.support:appcompat-v7:25.2.0' - compile 'com.android.support:cardview-v7:25.2.0' - compile 'com.android.support:recyclerview-v7:25.2.0' - compile 'com.android.support:support-v4:25.2.0' - compile 'com.android.support:design:25.2.0' + compile 'com.android.support:appcompat-v7:25.3.1' + compile 'com.android.support:cardview-v7:25.3.1' + compile 'com.android.support:recyclerview-v7:25.3.1' + compile 'com.android.support:support-v4:25.3.1' + compile 'com.android.support:design:25.3.1' compile 'com.github.tony19:logback-android-classic:1.1.1-4' compile 'org.slf4j:slf4j-api:1.7.7' compile 'com.github.PhilJay:MPAndroidChart:v3.0.1' @@ -76,7 +76,6 @@ dependencies { compile 'de.cketti.library.changelog:ckchangelog:1.2.2' compile 'net.e175.klaus:solarpositioning:0.0.9' compile 'com.github.freeyourgadget:greendao:1998d7cd2d21f662c6044f6ccf3b3a251bbad341' - compile 'com.github.woxthebox:draglistview:1.2.9' compile 'org.apache.commons:commons-lang3:3.4' // compile project(":DaoCore") diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/appmanager/AbstractAppManagerFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/appmanager/AbstractAppManagerFragment.java index 4eea9ec33..c9ebb69af 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/appmanager/AbstractAppManagerFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/appmanager/AbstractAppManagerFragment.java @@ -27,7 +27,8 @@ import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.content.LocalBroadcastManager; import android.support.v7.widget.LinearLayoutManager; -import android.view.HapticFeedbackConstants; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.helper.ItemTouchHelper; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; @@ -35,8 +36,6 @@ import android.view.View; import android.view.ViewGroup; import android.widget.PopupMenu; -import com.woxthebox.draglistview.DragListView; - import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -64,6 +63,8 @@ public abstract class AbstractAppManagerFragment extends Fragment { = "nodomain.freeyourgadget.gadgetbridge.appmanager.action.refresh_applist"; private static final Logger LOG = LoggerFactory.getLogger(AbstractAppManagerFragment.class); + private ItemTouchHelper appManagementTouchHelper; + protected abstract List getSystemAppsInCategory(); protected abstract String getSortFilename(); @@ -72,9 +73,13 @@ public abstract class AbstractAppManagerFragment extends Fragment { protected abstract boolean filterApp(GBDeviceApp gbDeviceApp); + public void startDragging(RecyclerView.ViewHolder viewHolder) { + appManagementTouchHelper.startDrag(viewHolder); + } + protected void onChangedAppOrder() { List uuidList = new ArrayList<>(); - for (GBDeviceApp gbDeviceApp : mGBDeviceAppAdapter.getItemList()) { + for (GBDeviceApp gbDeviceApp : mGBDeviceAppAdapter.getAppList()) { uuidList.add(gbDeviceApp.getUUID()); } AppManagerActivity.rewriteAppOrderFile(getSortFilename(), uuidList); @@ -133,7 +138,6 @@ public abstract class AbstractAppManagerFragment extends Fragment { } }; - private DragListView appListView; protected final List appList = new ArrayList<>(); private GBDeviceAppAdapter mGBDeviceAppAdapter; protected GBDevice mGBDevice = null; @@ -237,10 +241,6 @@ public abstract class AbstractAppManagerFragment extends Fragment { super.onActivityCreated(savedInstanceState); mGBDevice = ((AppManagerActivity) getActivity()).getGBDevice(); - if (PebbleUtils.getFwMajor(mGBDevice.getFirmwareVersion()) < 3 && !isCacheManager()) { - appListView.setDragEnabled(false); - } - IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_REFRESH_APPLIST); @@ -261,31 +261,21 @@ public abstract class AbstractAppManagerFragment extends Fragment { View rootView = inflater.inflate(R.layout.activity_appmanager, container, false); - appListView = (DragListView) (rootView.findViewById(R.id.appListView)); + RecyclerView appListView = (RecyclerView) (rootView.findViewById(R.id.appListView)); appListView.setLayoutManager(new LinearLayoutManager(getActivity())); - mGBDeviceAppAdapter = new GBDeviceAppAdapter(appList, R.layout.item_with_details, R.id.item_image, this.getContext(), this); - appListView.setAdapter(mGBDeviceAppAdapter, false); - appListView.setCanDragHorizontally(false); - appListView.setDragListListener(new DragListView.DragListListener() { - @Override - public void onItemDragStarted(int position) { - } + mGBDeviceAppAdapter = new GBDeviceAppAdapter(appList, R.layout.item_with_details_and_drag_handle, this); + appListView.setAdapter(mGBDeviceAppAdapter); - @Override - public void onItemDragging(int itemPosition, float x, float y) { - } + ItemTouchHelper.Callback appItemTouchHelperCallback = new AppItemTouchHelperCallback(mGBDeviceAppAdapter); + appManagementTouchHelper = new ItemTouchHelper(appItemTouchHelperCallback); - @Override - public void onItemDragEnded(int fromPosition, int toPosition) { - onChangedAppOrder(); - } - }); + appManagementTouchHelper.attachToRecyclerView(appListView); return rootView; } protected void sendOrderToDevice(String concatFilename) { ArrayList uuids = new ArrayList<>(); - for (GBDeviceApp gbDeviceApp : mGBDeviceAppAdapter.getItemList()) { + for (GBDeviceApp gbDeviceApp : mGBDeviceAppAdapter.getAppList()) { uuids.add(gbDeviceApp.getUUID()); } if (concatFilename != null) { @@ -295,11 +285,11 @@ public abstract class AbstractAppManagerFragment extends Fragment { GBApplication.deviceService().onAppReorder(uuids.toArray(new UUID[uuids.size()])); } - public boolean openPopupMenu(View view, int position) { + public boolean openPopupMenu(View view, GBDeviceApp deviceApp) { PopupMenu popupMenu = new PopupMenu(getContext(), view); popupMenu.getMenuInflater().inflate(R.menu.appmanager_context, popupMenu.getMenu()); Menu menu = popupMenu.getMenu(); - final GBDeviceApp selectedApp = appList.get(position); + final GBDeviceApp selectedApp = deviceApp; if (!selectedApp.isInCache()) { menu.removeItem(R.id.appmanager_app_reinstall); @@ -352,12 +342,11 @@ public abstract class AbstractAppManagerFragment extends Fragment { } ); - view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); popupMenu.show(); return true; } - public boolean onContextItemSelected(MenuItem item, GBDeviceApp selectedApp) { + private boolean onContextItemSelected(MenuItem item, GBDeviceApp selectedApp) { switch (item.getItemId()) { case R.id.appmanager_app_delete_cache: String baseName; @@ -440,4 +429,46 @@ public abstract class AbstractAppManagerFragment extends Fragment { LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(mReceiver); super.onDestroy(); } + + public class AppItemTouchHelperCallback extends ItemTouchHelper.Callback { + + private final GBDeviceAppAdapter gbDeviceAppAdapter; + + public AppItemTouchHelperCallback(GBDeviceAppAdapter gbDeviceAppAdapter) { + this.gbDeviceAppAdapter = gbDeviceAppAdapter; + } + + @Override + public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { + //app reordering is not possible on old firmwares + if (PebbleUtils.getFwMajor(mGBDevice.getFirmwareVersion()) < 3 && !isCacheManager()) { + return 0; + } + //we only support up and down movement and only for moving, not for swiping apps away + return makeMovementFlags(ItemTouchHelper.UP | ItemTouchHelper.DOWN, 0); + } + + @Override + public boolean isLongPressDragEnabled() { + return false; + } + + @Override + public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) { + gbDeviceAppAdapter.onItemMove(source.getAdapterPosition(), target.getAdapterPosition()); + return true; + } + + @Override + public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { + //nothing to do + } + + @Override + public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { + super.clearView(recyclerView, viewHolder); + onChangedAppOrder(); + } + + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAppAdapter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAppAdapter.java index cb1c9b939..403304809 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAppAdapter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAppAdapter.java @@ -16,15 +16,15 @@ along with this program. If not, see . */ package nodomain.freeyourgadget.gadgetbridge.adapter; -import android.content.Context; +import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; -import com.woxthebox.draglistview.DragItemAdapter; - +import java.util.Collections; import java.util.List; import java.util.UUID; @@ -37,40 +37,41 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp; * Adapter for displaying GBDeviceApp instances. */ -public class GBDeviceAppAdapter extends DragItemAdapter { +public class GBDeviceAppAdapter extends RecyclerView.Adapter { private final int mLayoutId; - private final int mGrabHandleId; - private final Context mContext; + private final List appList; private final AbstractAppManagerFragment mParentFragment; - public GBDeviceAppAdapter(List list, int layoutId, int grabHandleId, Context context, AbstractAppManagerFragment parentFragment) { - super(true); // longpress + public List getAppList() { + return appList; + } + + public GBDeviceAppAdapter(List list, int layoutId, AbstractAppManagerFragment parentFragment) { mLayoutId = layoutId; - mGrabHandleId = grabHandleId; - mContext = context; + appList = list; mParentFragment = parentFragment; - setHasStableIds(true); - setItemList(list); } @Override public long getItemId(int position) { - return mItemList.get(position).getUUID().getLeastSignificantBits(); + return appList.get(position).getUUID().getLeastSignificantBits(); } @Override - public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + public int getItemCount() { + return appList.size(); + } + @Override + public GBDeviceAppAdapter.AppViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(mLayoutId, parent, false); - return new ViewHolder(view); + return new AppViewHolder(view); } @Override - public void onBindViewHolder(ViewHolder holder, int position) { - super.onBindViewHolder(holder, position); - GBDeviceApp deviceApp = mItemList.get(position); - + public void onBindViewHolder(final AppViewHolder holder, int position) { + final GBDeviceApp deviceApp = appList.get(position); holder.mDeviceAppVersionAuthorLabel.setText(GBApplication.getContext().getString(R.string.appversion_by_creator, deviceApp.getVersion(), deviceApp.getCreator())); // FIXME: replace with small icons @@ -93,29 +94,51 @@ public class GBDeviceAppAdapter extends DragItemAdapter.ViewHolder { - TextView mDeviceAppVersionAuthorLabel; - TextView mDeviceAppNameLabel; - ImageView mDeviceImageView; + public void onItemMove(int from, int to) { + Collections.swap(appList, from, to); + notifyItemMoved(from, to); + } - public ViewHolder(final View itemView) { - super(itemView, mGrabHandleId); + public class AppViewHolder extends RecyclerView.ViewHolder { + final TextView mDeviceAppVersionAuthorLabel; + final TextView mDeviceAppNameLabel; + final ImageView mDeviceImageView; + final ImageView mDragHandle; + + AppViewHolder(View itemView) { + super(itemView); mDeviceAppVersionAuthorLabel = (TextView) itemView.findViewById(R.id.item_details); mDeviceAppNameLabel = (TextView) itemView.findViewById(R.id.item_name); mDeviceImageView = (ImageView) itemView.findViewById(R.id.item_image); + mDragHandle = (ImageView) itemView.findViewById(R.id.drag_handle); } - @Override - public void onItemClicked(View view) { - UUID uuid = mItemList.get(getAdapterPosition()).getUUID(); - GBApplication.deviceService().onAppStart(uuid, true); - } - - @Override - public boolean onItemLongClicked(View view) { - return mParentFragment.openPopupMenu(view, getAdapterPosition()); - } } + } diff --git a/app/src/main/res/drawable/ic_drag_handle_black_24dp.xml b/app/src/main/res/drawable/ic_drag_handle_black_24dp.xml new file mode 100644 index 000000000..8f7f335a3 --- /dev/null +++ b/app/src/main/res/drawable/ic_drag_handle_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/activity_appmanager.xml b/app/src/main/res/layout/activity_appmanager.xml index bf304a271..ed6a70f38 100644 --- a/app/src/main/res/layout/activity_appmanager.xml +++ b/app/src/main/res/layout/activity_appmanager.xml @@ -3,8 +3,9 @@ android:layout_height="match_parent" xmlns:tools="http://schemas.android.com/tools" tools:context="nodomain.freeyourgadget.gadgetbridge.activities.appmanager.AbstractAppManagerFragment"> - + android:layout_height="fill_parent" /> diff --git a/app/src/main/res/layout/item_with_details_and_drag_handle.xml b/app/src/main/res/layout/item_with_details_and_drag_handle.xml new file mode 100644 index 000000000..58943cb68 --- /dev/null +++ b/app/src/main/res/layout/item_with_details_and_drag_handle.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + \ No newline at end of file