diff --git a/app/src/androidTest/java/com/veniosg/dir/test/acceptance/FileManagerActivityTest.java b/app/src/androidTest/java/com/veniosg/dir/test/acceptance/FileManagerActivityTest.java index 6aaebf32..71c2f6dc 100644 --- a/app/src/androidTest/java/com/veniosg/dir/test/acceptance/FileManagerActivityTest.java +++ b/app/src/androidTest/java/com/veniosg/dir/test/acceptance/FileManagerActivityTest.java @@ -49,12 +49,14 @@ public class FileManagerActivityTest { private final Android android = android(intentsRule); private final File storageDir = Environment.getExternalStorageDirectory(); private final File testDirectory = new File(storageDir, "testDir"); + private final File testEmptyDirectory = new File(testDirectory, "emptyDir"); private final File testChildFile = new File(testDirectory, "testChildFile"); @SuppressWarnings("ResultOfMethodCallIgnored") @Before public void setUp() throws Exception { testDirectory.mkdir(); + testEmptyDirectory.mkdir(); testChildFile.createNewFile(); } @@ -96,6 +98,20 @@ public void launchesSearchForCurrentDirectory() throws Exception { android.launched().searchIntentFor(testDirectory); } + @Test + public void showsEmptyViewWhenDirectoryEmpty() throws Exception { + user.launches().viewWithFileScheme(testEmptyDirectory); + + user.sees().emptyView(); + } + + @Test + public void doesNotShowEmptyViewWhenDirectoryHasItems() throws Exception { + user.launches().viewWithFileScheme(testDirectory); + + user.cannotSee().emptyView(); + } + @Test @Ignore public void filtersBasedOnMimetypeExtra() { diff --git a/app/src/androidTest/java/com/veniosg/dir/test/actor/assertion/CannotSeeAssertions.java b/app/src/androidTest/java/com/veniosg/dir/test/actor/assertion/CannotSeeAssertions.java index 0f4b49af..50b587c3 100644 --- a/app/src/androidTest/java/com/veniosg/dir/test/actor/assertion/CannotSeeAssertions.java +++ b/app/src/androidTest/java/com/veniosg/dir/test/actor/assertion/CannotSeeAssertions.java @@ -40,6 +40,10 @@ public void visibleSearchResult(File result) { } public void searchEmptyView() { + emptyView(); + } + + public void emptyView() { onView(withId(R.id.empty_text)) .check(matches(not(isDisplayed()))); onView(withId(R.id.empty_img)) diff --git a/app/src/androidTest/java/com/veniosg/dir/test/actor/assertion/SeesAssertions.java b/app/src/androidTest/java/com/veniosg/dir/test/actor/assertion/SeesAssertions.java index b735e079..99f23e14 100644 --- a/app/src/androidTest/java/com/veniosg/dir/test/actor/assertion/SeesAssertions.java +++ b/app/src/androidTest/java/com/veniosg/dir/test/actor/assertion/SeesAssertions.java @@ -77,6 +77,14 @@ public void searchEmptyView() { viewWithId(R.id.empty_img); } + public void emptyView() { + onView(allOf( + withId(R.id.empty_text), + withText("Folder empty") + )).check(matches(isDisplayed())); + viewWithId(R.id.empty_img); + } + private void viewWithId(@IdRes int id) { onView(withId(id)).check(matches(isDisplayed())); } diff --git a/app/src/main/java/com/veniosg/dir/android/adapter/FileHolderListAdapter.java b/app/src/main/java/com/veniosg/dir/android/adapter/FileHolderListAdapter.java index 8efc792b..4256fe74 100644 --- a/app/src/main/java/com/veniosg/dir/android/adapter/FileHolderListAdapter.java +++ b/app/src/main/java/com/veniosg/dir/android/adapter/FileHolderListAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 George Venios + * Copyright (C) 2018 George Venios * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,47 +16,36 @@ package com.veniosg.dir.android.adapter; -import android.content.Context; import android.support.annotation.Nullable; -import android.view.LayoutInflater; -import android.view.View; +import android.support.v7.widget.RecyclerView; import android.view.ViewGroup; -import android.widget.BaseAdapter; -import android.widget.ImageView; -import android.widget.TextView; -import com.veniosg.dir.R; +import com.veniosg.dir.android.adapter.viewholder.FileListViewHolder; +import com.veniosg.dir.android.adapter.viewholder.FileListViewHolder.OnItemClickListener; +import com.veniosg.dir.android.fragment.RecyclerViewFragment; import com.veniosg.dir.mvvm.model.FileHolder; -import com.veniosg.dir.android.ui.ViewHolder; import java.util.List; -import static com.nostra13.universalimageloader.core.ImageLoader.getInstance; -import static com.veniosg.dir.android.misc.ThumbnailHelper.requestIcon; - -public class FileHolderListAdapter extends BaseAdapter { +public class FileHolderListAdapter extends RecyclerView.Adapter + implements RecyclerViewFragment.ClickableAdapter { private List mItems; - private int mItemLayoutId = R.layout.item_filelist; - private OnItemToggleListener mOnItemToggleListener; + private OnItemToggleListener mOnItemToggleListener; + private OnItemClickListener onItemClickListener; public FileHolderListAdapter(List files){ mItems = files; + setHasStableIds(true); } @Override - public boolean hasStableIds() { - return true; - } - - @Override - public int getCount() { + public int getItemCount() { return mItems.size(); } - @Override @Nullable - public Object getItem(int position) { + public FileHolder getItem(int position) { if (position < 0 || position >= mItems.size()) return null; return mItems.get(position); @@ -67,53 +56,15 @@ public long getItemId(int position) { return position; } - /** - * Set the layout to be used for item drawing. - * @param resId The item layout id. 0 to reset. - */ - public void setItemLayout(int resId){ - if(resId > 0) - mItemLayoutId = resId; - else - mItemLayoutId = R.layout.item_filelist; - } - - /** - * Creates a new list item view, along with it's ViewHolder set as a tag. - * @return The new view. - */ - private View newView(Context context){ - View view = LayoutInflater.from(context).inflate(mItemLayoutId, null); - - ViewHolder holder = new ViewHolder(); - holder.icon = (ImageView) view.findViewById(R.id.icon); - holder.primaryInfo = (TextView) view.findViewById(R.id.primary_info); - holder.secondaryInfo = (TextView) view.findViewById(R.id.secondary_info); - holder.tertiaryInfo = (TextView) view.findViewById(R.id.tertiary_info); - - view.setTag(holder); - return view; - } + @Override + public FileListViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return new FileListViewHolder(parent); + } - @Override - public View getView(int position, View convertView, ViewGroup parent) { - FileHolder item = mItems.get(position); - if(convertView == null) - convertView = newView(parent.getContext()); - ViewHolder holder = (ViewHolder) convertView.getTag(); - - getInstance().cancelDisplayTask(holder.icon); - holder.icon.setImageDrawable(item.getBestIcon()); - holder.primaryInfo.setText(item.getName()); - holder.secondaryInfo.setText(item.getFormattedModificationDate(convertView.getContext())); - // Hide directories' size as it's irrelevant if we can't recursively find it. - holder.tertiaryInfo.setText(item.getFile().isDirectory()? "" : item.getFormattedSize( - convertView.getContext(), false)); - - requestIcon(item, holder.icon); - - return convertView; - } + @Override + public void onBindViewHolder(FileListViewHolder holder, int position) { + holder.bind(getItem(position), onItemClickListener); + } public OnItemToggleListener getOnItemToggleListener() { return mOnItemToggleListener; @@ -123,11 +74,12 @@ public void setOnItemToggleListener(OnItemToggleListener mOnItemToggleListener) this.mOnItemToggleListener = mOnItemToggleListener; } - private boolean shouldLoadIcon(FileHolder item){ - return item.getFile().isFile() && !item.getMimeType().equals("video/mpeg"); - } + @Override + public void setOnItemClickListener(OnItemClickListener onClickListener) { + this.onItemClickListener = onClickListener; + } public interface OnItemToggleListener { - public void onItemToggle(int position); + void onItemToggle(int position); } } \ No newline at end of file diff --git a/app/src/main/java/com/veniosg/dir/android/adapter/SearchListAdapter.java b/app/src/main/java/com/veniosg/dir/android/adapter/SearchListAdapter.java index 5b3e07fc..3ed25748 100644 --- a/app/src/main/java/com/veniosg/dir/android/adapter/SearchListAdapter.java +++ b/app/src/main/java/com/veniosg/dir/android/adapter/SearchListAdapter.java @@ -20,7 +20,8 @@ import android.support.v7.widget.RecyclerView; import android.view.ViewGroup; -import com.veniosg.dir.android.adapter.FileListViewHolder.OnItemClickListener; +import com.veniosg.dir.android.adapter.viewholder.FileListViewHolder.OnItemClickListener; +import com.veniosg.dir.android.adapter.viewholder.SearchListViewHolder; import java.util.List; diff --git a/app/src/main/java/com/veniosg/dir/android/adapter/SearchListViewHolder.java b/app/src/main/java/com/veniosg/dir/android/adapter/SearchListViewHolder.java deleted file mode 100644 index f86985f4..00000000 --- a/app/src/main/java/com/veniosg/dir/android/adapter/SearchListViewHolder.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.veniosg.dir.android.adapter; - -import android.view.ViewGroup; - -public class SearchListViewHolder extends FileListViewHolder { - SearchListViewHolder(ViewGroup parent) { - super(parent); - } - - @Override - void bind(String filePath, OnItemClickListener listener) { - super.bind(filePath, listener); - secondaryInfo.setText(filePath); - } -} diff --git a/app/src/main/java/com/veniosg/dir/android/adapter/FileListViewHolder.java b/app/src/main/java/com/veniosg/dir/android/adapter/viewholder/FileListViewHolder.java similarity index 53% rename from app/src/main/java/com/veniosg/dir/android/adapter/FileListViewHolder.java rename to app/src/main/java/com/veniosg/dir/android/adapter/viewholder/FileListViewHolder.java index ba8943b3..e1a053e0 100644 --- a/app/src/main/java/com/veniosg/dir/android/adapter/FileListViewHolder.java +++ b/app/src/main/java/com/veniosg/dir/android/adapter/viewholder/FileListViewHolder.java @@ -1,4 +1,20 @@ -package com.veniosg.dir.android.adapter; +/* + * Copyright (C) 2018 George Venios + * + * 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 com.veniosg.dir.android.adapter.viewholder; import android.content.Context; import android.support.v7.widget.RecyclerView; @@ -10,9 +26,8 @@ import com.veniosg.dir.R; import com.veniosg.dir.mvvm.model.FileHolder; -import java.io.File; - import static android.view.LayoutInflater.from; +import static com.nostra13.universalimageloader.core.ImageLoader.getInstance; import static com.veniosg.dir.android.misc.ThumbnailHelper.requestIcon; import static com.veniosg.dir.android.ui.Themer.getThemedResourceId; @@ -22,25 +37,26 @@ public class FileListViewHolder extends RecyclerView.ViewHolder { TextView secondaryInfo; private TextView tertiaryInfo; - FileListViewHolder(ViewGroup parent) { + public FileListViewHolder(ViewGroup parent) { super(from(parent.getContext()).inflate(R.layout.item_filelist, parent, false)); - icon = (ImageView) itemView.findViewById(R.id.icon); - primaryInfo = (TextView) itemView.findViewById(R.id.primary_info); - secondaryInfo = (TextView) itemView.findViewById(R.id.secondary_info); - tertiaryInfo = (TextView) itemView.findViewById(R.id.tertiary_info); + icon = itemView.findViewById(R.id.icon); + primaryInfo = itemView.findViewById(R.id.primary_info); + secondaryInfo = itemView.findViewById(R.id.secondary_info); + tertiaryInfo = itemView.findViewById(R.id.tertiary_info); int selectorRes = getThemedResourceId(parent.getContext(), android.R.attr.listChoiceBackgroundIndicator); itemView.setBackgroundResource(selectorRes); } - void bind(String filePath, OnItemClickListener listener) { + public void bind(FileHolder item, OnItemClickListener listener) { Context context = itemView.getContext(); - FileHolder item = new FileHolder(new File(filePath), context); boolean isDirectory = item.getFile().isDirectory(); + getInstance().cancelDisplayTask(icon); primaryInfo.setText(item.getName()); secondaryInfo.setText(item.getFormattedModificationDate(context)); + // Hide directories' size as it's irrelevant if we can't recursively find it. tertiaryInfo.setText(isDirectory ? "" : item.getFormattedSize(context, false)); icon.setImageDrawable(item.getBestIcon()); requestIcon(item, icon); @@ -49,6 +65,6 @@ void bind(String filePath, OnItemClickListener listener) { } public interface OnItemClickListener { - public void onClick(View itemView, FileHolder item); + void onClick(View itemView, FileHolder item); } } diff --git a/app/src/main/java/com/veniosg/dir/android/adapter/viewholder/SearchListViewHolder.java b/app/src/main/java/com/veniosg/dir/android/adapter/viewholder/SearchListViewHolder.java new file mode 100644 index 00000000..1db8bd7f --- /dev/null +++ b/app/src/main/java/com/veniosg/dir/android/adapter/viewholder/SearchListViewHolder.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2018 George Venios + * + * 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 com.veniosg.dir.android.adapter.viewholder; + +import android.view.ViewGroup; + +import com.veniosg.dir.mvvm.model.FileHolder; + +import java.io.File; + +public class SearchListViewHolder extends FileListViewHolder { + public SearchListViewHolder(ViewGroup parent) { + super(parent); + } + + public void bind(String filePath, OnItemClickListener listener) { + FileHolder fileHolder = new FileHolder(new File(filePath), itemView.getContext()); + super.bind(fileHolder, listener); + secondaryInfo.setText(filePath); + } +} diff --git a/app/src/main/java/com/veniosg/dir/android/fragment/FileListFragment.java b/app/src/main/java/com/veniosg/dir/android/fragment/FileListFragment.java index da458546..8d7f9461 100644 --- a/app/src/main/java/com/veniosg/dir/android/fragment/FileListFragment.java +++ b/app/src/main/java/com/veniosg/dir/android/fragment/FileListFragment.java @@ -33,14 +33,14 @@ import android.view.View; import android.view.ViewGroup; -import com.veniosg.dir.android.FileManagerApplication; import com.veniosg.dir.R; +import com.veniosg.dir.android.FileManagerApplication; import com.veniosg.dir.android.adapter.FileHolderListAdapter; -import com.veniosg.dir.mvvm.model.DirectoryHolder; import com.veniosg.dir.android.misc.DirectoryScanner; -import com.veniosg.dir.mvvm.model.FileHolder; -import com.veniosg.dir.android.util.Logger; import com.veniosg.dir.android.ui.widget.WaitingViewFlipper; +import com.veniosg.dir.android.util.Logger; +import com.veniosg.dir.mvvm.model.DirectoryHolder; +import com.veniosg.dir.mvvm.model.FileHolder; import java.io.File; import java.util.ArrayList; @@ -49,10 +49,11 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.preference.PreferenceManager.getDefaultSharedPreferences; import static android.support.v4.content.ContextCompat.checkSelfPermission; -import static com.veniosg.dir.IntentConstants.*; import static com.veniosg.dir.IntentConstants.ACTION_REFRESH_LIST; import static com.veniosg.dir.IntentConstants.EXTRA_DIRECTORIES_ONLY; import static com.veniosg.dir.IntentConstants.EXTRA_DIR_PATH; +import static com.veniosg.dir.IntentConstants.EXTRA_FILENAME; +import static com.veniosg.dir.IntentConstants.EXTRA_FILTER_FILETYPE; import static com.veniosg.dir.IntentConstants.EXTRA_FILTER_MIMETYPE; import static com.veniosg.dir.IntentConstants.EXTRA_WRITEABLE_ONLY; import static com.veniosg.dir.android.fragment.PreferenceFragment.PREFS_THEME; @@ -61,7 +62,7 @@ import static com.veniosg.dir.android.ui.widget.WaitingViewFlipper.PAGE_INDEX_PERMISSION_DENIED; /** - * An {@link AbsListFragment} that displays the contents of a directory. + * An {@link RecyclerViewFragment} that displays the contents of a directory. *

* Clicks do nothing. *

@@ -73,8 +74,7 @@ * Requests permissions if they're not granted. *

*/ -public abstract class FileListFragment extends AbsListFragment { - +public abstract class FileListFragment extends RecyclerViewFragment { private static final int REQUEST_CODE_STORAGE_PERMISSION = 0; private static final String INSTANCE_STATE_PATH = "path"; private static final String INSTANCE_STATE_FILES = "files"; @@ -150,7 +150,7 @@ public void onDestroy() { } @Override - public void onSaveInstanceState(Bundle outState) { + public void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); outState.putString(INSTANCE_STATE_PATH, mPath); @@ -159,12 +159,12 @@ public void onSaveInstanceState(Bundle outState) { } @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_filelist, null); } @Override - public void onViewCreated(View view, Bundle savedInstanceState) { + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); // Set auto refresh on preference change. @@ -172,10 +172,10 @@ public void onViewCreated(View view, Bundle savedInstanceState) { .registerOnSharedPreferenceChangeListener(preferenceListener); // Set list properties - getListView().requestFocus(); - getListView().requestFocusFromTouch(); + getRecyclerView().requestFocus(); + getRecyclerView().requestFocusFromTouch(); - mFlipper = (WaitingViewFlipper) view.findViewById(R.id.flipper); + mFlipper = view.findViewById(R.id.flipper); view.findViewById(R.id.empty_img).setOnClickListener(mEmptyViewClickListener); view.findViewById(R.id.permissions_button).setOnClickListener(mRequestPermissionsListener); @@ -303,9 +303,11 @@ public void handleMessage(Message msg) { mFiles.addAll(c.listFile); onDataReady(); + // TODO Run a diff instead of updating everything mAdapter.notifyDataSetChanged(); + // TODO Scroll up, we had other content. Check if needed. if (getView() != null) { - getListView().setSelection(0); + getRecyclerView().setSelection(0); } showLoading(false); onDataApplied(); diff --git a/app/src/main/java/com/veniosg/dir/android/fragment/PickFileListFragment.java b/app/src/main/java/com/veniosg/dir/android/fragment/PickFileListFragment.java index 4c63c812..f9c949ef 100644 --- a/app/src/main/java/com/veniosg/dir/android/fragment/PickFileListFragment.java +++ b/app/src/main/java/com/veniosg/dir/android/fragment/PickFileListFragment.java @@ -20,6 +20,7 @@ import android.content.Intent; import android.net.Uri; import android.os.Bundle; +import android.support.annotation.NonNull; import android.view.LayoutInflater; import android.view.Menu; import android.view.View; @@ -44,7 +45,7 @@ public class PickFileListFragment extends SimpleFileListFragment { private PickBar mPickBar; @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); return inflater.inflate(R.layout.fragment_filelist_pick, container, false); } @@ -56,7 +57,7 @@ public void onPrepareOptionsMenu(Menu menu) { } @Override - public void onViewCreated(View view, Bundle savedInstanceState) { + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); ViewFlipper modeSelector = (ViewFlipper) view.findViewById(R.id.modeSelector); @@ -95,16 +96,14 @@ public void pickRequested(String filename) { } } - @Override - public void onListItemClick(AbsListView l, View v, int position, long id) { - FileHolder item = (FileHolder) mAdapter.getItem(position); - + @Override + public void onListItemClick(View itemView, FileHolder item) { if (item != null && item.getFile().isFile()) { mPickBar.setText(item.getName()); } else { - super.onListItemClick(l, v, position, id); + super.onListItemClick(itemView, item); } - } + } /** * Act upon picking. diff --git a/app/src/main/java/com/veniosg/dir/android/fragment/AbsListFragment.java b/app/src/main/java/com/veniosg/dir/android/fragment/RecyclerViewFragment.java similarity index 63% rename from app/src/main/java/com/veniosg/dir/android/fragment/AbsListFragment.java rename to app/src/main/java/com/veniosg/dir/android/fragment/RecyclerViewFragment.java index 7d42c78a..54df8482 100644 --- a/app/src/main/java/com/veniosg/dir/android/fragment/AbsListFragment.java +++ b/app/src/main/java/com/veniosg/dir/android/fragment/RecyclerViewFragment.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2011 The Android Open Source Project - * Copyright (C) 2014 George Venios + * Copyright (C) 2018 George Venios * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,21 +20,22 @@ import android.content.Context; import android.os.Bundle; import android.os.Handler; +import android.support.annotation.NonNull; import android.support.v4.app.Fragment; +import android.support.v7.widget.RecyclerView; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.animation.AnimationUtils; -import android.widget.AbsListView; -import android.widget.AdapterView; import android.widget.FrameLayout; import android.widget.LinearLayout; -import android.widget.ListAdapter; import android.widget.ProgressBar; import android.widget.TextView; -import com.veniosg.dir.android.ui.widget.DividerGridView; +import com.veniosg.dir.android.adapter.viewholder.FileListViewHolder.OnItemClickListener; +import com.veniosg.dir.android.ui.widget.DividerRecyclerView; +import com.veniosg.dir.mvvm.model.FileHolder; /** * Static library support version of the framework's {@link android.app.ListFragment}. @@ -43,7 +44,7 @@ * to switch to the framework's implementation. See the framework SDK * documentation for a class overview. */ -public class AbsListFragment extends Fragment { +public class RecyclerViewFragment extends Fragment { static final int INTERNAL_EMPTY_ID = 0x00ff0001; static final int INTERNAL_PROGRESS_CONTAINER_ID = 0x00ff0002; static final int INTERNAL_LIST_CONTAINER_ID = 0x00ff0003; @@ -56,33 +57,61 @@ public void run() { } }; - final private AdapterView.OnItemClickListener mOnClickListener - = new AdapterView.OnItemClickListener() { - public void onItemClick(AdapterView parent, View v, int position, long id) { - onListItemClick((AbsListView)parent, v, position, id); - } - }; + final private OnItemClickListener mOnClickListener = this::onListItemClick; - ListAdapter mAdapter; - AbsListView mList; - View mEmptyView; + RecyclerView.Adapter mAdapter; + RecyclerView mList; + View mCustomEmptyView; TextView mStandardEmptyView; View mProgressContainer; View mListContainer; CharSequence mEmptyText; + View mEmptyView; boolean mListShown; + private final RecyclerView.AdapterDataObserver mEmptyViewUpdatingObserver = new RecyclerView.AdapterDataObserver() { + @Override + public void onChanged() { + super.onChanged(); + ensureEmptyView(true); + } + + @Override + public void onItemRangeChanged(int positionStart, int itemCount) { + onChanged(); + } + + @Override + public void onItemRangeChanged(int positionStart, int itemCount, Object payload) { + onChanged(); + } + + @Override + public void onItemRangeInserted(int positionStart, int itemCount) { + onChanged(); + } + + @Override + public void onItemRangeRemoved(int positionStart, int itemCount) { + onChanged(); + } + + @Override + public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) { + onChanged(); + } + }; - public AbsListFragment() { + public RecyclerViewFragment() { } /** * Provide default implementation to return a simple list view. Subclasses * can override to replace with their own layout. If doing so, the - * returned view hierarchy must have a AbsListView whose id + * returned view hierarchy must have a RecyclerView whose id * is {@link android.R.id#list android.R.id.list} and can optionally * have a sibling view id {@link android.R.id#empty android.R.id.empty} * that is to be shown when the list is empty. - * + *

*

If you are overriding this method with your own custom content, * consider including the standard layout {@link android.R.layout#list_content} * in your layout file, so that you continue to retain all of the standard @@ -90,7 +119,7 @@ public AbsListFragment() { * way to have the built-in indeterminant progress state be shown. */ @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final Context context = getActivity(); @@ -110,7 +139,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); root.addView(pframe, new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); // ------------------------------------------------------------------ @@ -121,21 +150,20 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, tv.setId(INTERNAL_EMPTY_ID); tv.setGravity(Gravity.CENTER); lframe.addView(tv, new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - AbsListView lv = new DividerGridView(getActivity()); + RecyclerView lv = new DividerRecyclerView(getActivity()); lv.setId(android.R.id.list); - lv.setDrawSelectorOnTop(false); lframe.addView(lv, new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); root.addView(lframe, new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); // ------------------------------------------------------------------ root.setLayoutParams(new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); return root; } @@ -144,7 +172,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, * Attach to list view once the view hierarchy has been created. */ @Override - public void onViewCreated(View view, Bundle savedInstanceState) { + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); ensureList(); } @@ -157,7 +185,7 @@ public void onDestroyView() { mHandler.removeCallbacks(mRequestFocus); mList = null; mListShown = false; - mEmptyView = mProgressContainer = mListContainer = null; + mCustomEmptyView = mProgressContainer = mListContainer = null; mStandardEmptyView = null; super.onDestroyView(); } @@ -165,70 +193,73 @@ public void onDestroyView() { /** * This method will be called when an item in the list is selected. * Subclasses should override. Subclasses can call - * getListView().getItemAtPosition(position) if they need to access the + * getRecyclerView().getItemAtPosition(position) if they need to access the * data associated with the selected item. * - * @param l The AbsListView where the click happened - * @param v The view that was clicked within the AbsListView - * @param position The position of the view in the list - * @param id The row id of the item that was clicked + * @param itemView The view that was clicked within the RecyclerView + * @param item The data item represented by itemView */ - public void onListItemClick(AbsListView l, View v, int position, long id) { + public void onListItemClick(View itemView, FileHolder item) { } /** * Provide the cursor for the list view. */ - public void setListAdapter(ListAdapter adapter) { + public void setListAdapter(@NonNull RecyclerView.Adapter adapter) { boolean hadAdapter = mAdapter != null; + if (hadAdapter) { + mAdapter.unregisterAdapterDataObserver(mEmptyViewUpdatingObserver); + } mAdapter = adapter; if (mList != null) { mList.setAdapter(adapter); + boolean shouldAnimate = getView() != null && getView().getWindowToken() != null; if (!mListShown && !hadAdapter) { // The list was hidden, and previously didn't have an - // adapter. It is now time to show it. - setListShown(true, getView().getWindowToken() != null); + // adapter. It is now time to show it. + setListShown(true, shouldAnimate); + } else { + ensureEmptyView(shouldAnimate); } } + mAdapter.registerAdapterDataObserver(mEmptyViewUpdatingObserver); } - /** - * Set the currently selected list item to the specified - * position with the adapter's data - * - * @param position - */ - public void setSelection(int position) { - ensureList(); - mList.setSelection(position); - } - - /** - * Get the position of the currently selected list item. - */ - public int getSelectedItemPosition() { - ensureList(); - return mList.getSelectedItemPosition(); - } + private void ensureEmptyView(boolean animate) { + boolean hideEmpty = false; + if (mAdapter != null) { + hideEmpty = !mListShown || mAdapter.getItemCount() > 0; + } - /** - * Get the cursor row ID of the currently selected list item. - */ - public long getSelectedItemId() { - ensureList(); - return mList.getSelectedItemId(); + if (hideEmpty) { + if (animate) { + mEmptyView.startAnimation(AnimationUtils.loadAnimation( + getActivity(), android.R.anim.fade_out)); + } else { + mEmptyView.clearAnimation(); + } + mEmptyView.setVisibility(View.GONE); + } else { + if (animate) { + mEmptyView.startAnimation(AnimationUtils.loadAnimation( + getActivity(), android.R.anim.fade_in)); + } else { + mEmptyView.clearAnimation(); + } + mEmptyView.setVisibility(View.VISIBLE); + } } /** * Get the activity's list view widget. */ - public AbsListView getListView() { + public RecyclerView getRecyclerView() { ensureList(); return mList; } /** - * The default content for a ListFragment has a TextView that can + * The default content for a RecyclerViewFragment has a TextView that can * be shown when the list is empty. If you would like to have it * shown, call this method to supply the text it should use. */ @@ -239,7 +270,7 @@ public void setEmptyText(CharSequence text) { } mStandardEmptyView.setText(text); if (mEmptyText == null) { - mList.setEmptyView(mStandardEmptyView); + setEmptyView(mStandardEmptyView); } mEmptyText = text; } @@ -248,15 +279,15 @@ public void setEmptyText(CharSequence text) { * Control whether the list is being displayed. You can make it not * displayed if you are waiting for the initial data to show in it. During * this time an indeterminant progress indicator will be shown instead. - * + *

*

Applications do not normally need to use this themselves. The default * behavior of ListFragment is to start with the list not being shown, only - * showing it once an adapter is given with {@link #setListAdapter(ListAdapter)}. + * showing it once an adapter is given with {@link #setListAdapter(RecyclerView.Adapter)}. * If the list at that point had not been shown, when it does get shown * it will be do without the user ever seeing the hidden state. * * @param shown If true, the list view is shown; if false, the progress - * indicator. The initial value is true. + * indicator. The initial value is true. */ public void setListShown(boolean shown) { setListShown(shown, true); @@ -275,10 +306,10 @@ public void setListShownNoAnimation(boolean shown) { * displayed if you are waiting for the initial data to show in it. During * this time an indeterminant progress indicator will be shown instead. * - * @param shown If true, the list view is shown; if false, the progress - * indicator. The initial value is true. + * @param shown If true, the list view is shown; if false, the progress + * indicator. The initial value is true. * @param animate If true, an animation will be used to transition to the - * new state. + * new state. */ private void setListShown(boolean shown, boolean animate) { ensureList(); @@ -314,12 +345,13 @@ private void setListShown(boolean shown, boolean animate) { mProgressContainer.setVisibility(View.VISIBLE); mListContainer.setVisibility(View.GONE); } + ensureEmptyView(animate); } /** - * Get the ListAdapter associated with this activity's AbsListView. + * Get the RecyclerView.Adapter associated with this activity's RecyclerView. */ - public ListAdapter getListAdapter() { + public RecyclerView.Adapter getListAdapter() { return mAdapter; } @@ -331,42 +363,44 @@ private void ensureList() { if (root == null) { throw new IllegalStateException("Content view not yet created"); } - if (root instanceof AbsListView) { - mList = (AbsListView)root; + if (root instanceof RecyclerView) { + mList = (RecyclerView) root; } else { - mStandardEmptyView = (TextView)root.findViewById(INTERNAL_EMPTY_ID); + mStandardEmptyView = (TextView) root.findViewById(INTERNAL_EMPTY_ID); if (mStandardEmptyView == null) { - mEmptyView = root.findViewById(android.R.id.empty); + mCustomEmptyView = root.findViewById(android.R.id.empty); } else { mStandardEmptyView.setVisibility(View.GONE); } mProgressContainer = root.findViewById(INTERNAL_PROGRESS_CONTAINER_ID); mListContainer = root.findViewById(INTERNAL_LIST_CONTAINER_ID); - View rawAbsListView = root.findViewById(android.R.id.list); - if (!(rawAbsListView instanceof AbsListView)) { - if (rawAbsListView == null) { + View rawRecyclerView = root.findViewById(android.R.id.list); + if (!(rawRecyclerView instanceof RecyclerView)) { + if (rawRecyclerView == null) { throw new RuntimeException( - "Your content must have a AbsListView whose id attribute is " + + "Your content must have a RecyclerView whose id attribute is " + "'android.R.id.list'"); } throw new RuntimeException( "Content has view with id attribute 'android.R.id.list' " - + "that is not a AbsListView class"); + + "that is not a RecyclerView class"); } - mList = (AbsListView)rawAbsListView; - if (mEmptyView != null) { - mList.setEmptyView(mEmptyView); + mList = (RecyclerView) rawRecyclerView; + if (mCustomEmptyView != null) { + setEmptyView(mCustomEmptyView); } else if (mEmptyText != null) { mStandardEmptyView.setText(mEmptyText); - mList.setEmptyView(mStandardEmptyView); + setEmptyView(mStandardEmptyView); } } mListShown = true; - mList.setOnItemClickListener(mOnClickListener); if (mAdapter != null) { - ListAdapter adapter = mAdapter; + RecyclerView.Adapter adapter = mAdapter; mAdapter = null; setListAdapter(adapter); + if (adapter instanceof ClickableAdapter) { + ((ClickableAdapter) adapter).setOnItemClickListener(mOnClickListener); + } } else { // We are starting without an adapter, so assume we won't // have our data right away and start with the progress indicator. @@ -376,4 +410,18 @@ private void ensureList() { } mHandler.post(mRequestFocus); } + + private void setEmptyView(View emptyView) { + if (emptyView != mEmptyView) { + if (mEmptyView != null) { + mEmptyView.setVisibility(View.GONE); + } + } + mEmptyView = emptyView; + ensureEmptyView(false); + } + + public interface ClickableAdapter { + void setOnItemClickListener(OnItemClickListener onClickListener); + } } diff --git a/app/src/main/java/com/veniosg/dir/android/fragment/SearchListFragment.java b/app/src/main/java/com/veniosg/dir/android/fragment/SearchListFragment.java index e8368fb3..f3c43e28 100644 --- a/app/src/main/java/com/veniosg/dir/android/fragment/SearchListFragment.java +++ b/app/src/main/java/com/veniosg/dir/android/fragment/SearchListFragment.java @@ -35,7 +35,7 @@ import com.veniosg.dir.R; import com.veniosg.dir.android.activity.FileManagerActivity; -import com.veniosg.dir.android.adapter.FileListViewHolder.OnItemClickListener; +import com.veniosg.dir.android.adapter.viewholder.FileListViewHolder.OnItemClickListener; import com.veniosg.dir.android.adapter.SearchListAdapter; import com.veniosg.dir.android.util.Logger; import com.veniosg.dir.android.ui.widget.WaitingViewFlipper; diff --git a/app/src/main/java/com/veniosg/dir/android/fragment/SideNavFragment.java b/app/src/main/java/com/veniosg/dir/android/fragment/SideNavFragment.java index 34ae8332..61b91bbf 100644 --- a/app/src/main/java/com/veniosg/dir/android/fragment/SideNavFragment.java +++ b/app/src/main/java/com/veniosg/dir/android/fragment/SideNavFragment.java @@ -19,6 +19,7 @@ import android.content.Intent; import android.database.Cursor; import android.os.Bundle; +import android.support.annotation.NonNull; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; @@ -29,7 +30,6 @@ import android.view.View; import android.view.ViewGroup; import android.widget.AbsListView; -import android.widget.GridView; import android.widget.ListView; import android.widget.TextView; @@ -46,41 +46,34 @@ import static com.veniosg.dir.android.ui.Themer.getThemedResourceId; import static com.veniosg.dir.android.ui.Themer.setStatusBarColour; -public class SideNavFragment extends AbsListFragment implements LoaderManager.LoaderCallbacks { +public class SideNavFragment extends RecyclerViewFragment + implements LoaderManager.LoaderCallbacks { private WaitingViewFlipper mFlipper; - private View.OnClickListener mSettingsClickListener = new View.OnClickListener() { - @Override - public void onClick(View v) { - Intent intent = new Intent(getActivity(), PreferenceActivity.class); - startActivity(intent); - } + private View.OnClickListener mSettingsClickListener = v -> { + Intent intent = new Intent(getActivity(), PreferenceActivity.class); + startActivity(intent); }; - private View.OnClickListener mAboutClickListener = new View.OnClickListener() { - @Override - public void onClick(View v) { - Intent intent = new Intent(getActivity(), AboutActivity.class); - startActivity(intent); - } + private View.OnClickListener mAboutClickListener = v -> { + Intent intent = new Intent(getActivity(), AboutActivity.class); + startActivity(intent); }; @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_drawer, null); } @Override - public void onViewCreated(View view, Bundle savedInstanceState) { + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - mFlipper = (WaitingViewFlipper) view.findViewById(R.id.flipper); + mFlipper = view.findViewById(R.id.flipper); setLoading(true); view.findViewById(R.id.empty_img).setVisibility(GONE); ((TextView) view.findViewById(R.id.empty_text)).setText(R.string.bookmark_empty); - if (getListView() instanceof GridView) { - ((GridView) getListView()).setNumColumns(1); - } setListAdapter(new BookmarkListAdapter(getActivity(), null)); setListChoiceListener(); view.setBackgroundResource(getThemedResourceId(getActivity(), android.R.attr.colorBackground)); @@ -91,7 +84,7 @@ public void onViewCreated(View view, Bundle savedInstanceState) { } @Override - public void onListItemClick(AbsListView l, View v, int position, long id) { + public void onListItemClick(View itemView, int position, long id) { Cursor c = ((Cursor) getListAdapter().getItem(position)); ((BookmarkContract) getActivity()).onBookmarkSelected(c.getString( c.getColumnIndex(BookmarkProvider.PATH))); @@ -109,13 +102,13 @@ void setLoading(boolean loading) { } private void setListChoiceListener() { - getListView().setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() { + getRecyclerView().setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() { @Override public boolean onPrepareActionMode(android.view.ActionMode mode, Menu menu) { menu.clear(); mode.getMenuInflater().inflate(R.menu.cab_bookmarks, menu); - if (getListView().getCheckedItemCount() != 1) { + if (getRecyclerView().getCheckedItemCount() != 1) { menu.removeItem(R.id.menu_open_parent); } return true; @@ -136,9 +129,9 @@ public boolean onCreateActionMode(android.view.ActionMode mode, Menu menu) { public boolean onActionItemClicked(android.view.ActionMode mode, MenuItem item) { switch (item.getItemId()) { case R.id.menu_delete: - long[] ids = getListView().getCheckedItemIds(); + long[] ids = getRecyclerView().getCheckedItemIds(); for (long id : ids) { - getListView().getContext().getContentResolver().delete(BookmarkProvider.CONTENT_URI, + getRecyclerView().getContext().getContentResolver().delete(BookmarkProvider.CONTENT_URI, BookmarkProvider._ID + "=?", new String[]{"" + id}); } mode.finish(); @@ -146,8 +139,8 @@ public boolean onActionItemClicked(android.view.ActionMode mode, MenuItem item) case R.id.menu_open_parent: int pos = 0; - SparseBooleanArray checked = getListView().getCheckedItemPositions(); - for (int i = 0; i < getListView().getCount(); i++) { + SparseBooleanArray checked = getRecyclerView().getCheckedItemPositions(); + for (int i = 0; i < getRecyclerView().getCount(); i++) { if (checked.get(i)) { pos = i; } @@ -165,16 +158,16 @@ public boolean onActionItemClicked(android.view.ActionMode mode, MenuItem item) @Override public void onItemCheckedStateChanged(android.view.ActionMode mode, int position, long id, boolean checked) { - if (getListView().getCheckedItemCount() != 0) { + if (getRecyclerView().getCheckedItemCount() != 0) { - mode.setTitle(getListView().getCheckedItemCount() + " " + getString(R.string.selected)); + mode.setTitle(getRecyclerView().getCheckedItemCount() + " " + getString(R.string.selected)); // Force actions' refresh mode.invalidate(); } } }); - getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); + getRecyclerView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); } @Override diff --git a/app/src/main/java/com/veniosg/dir/android/fragment/SimpleFileListFragment.java b/app/src/main/java/com/veniosg/dir/android/fragment/SimpleFileListFragment.java index 9aeeb906..4e6f9f97 100644 --- a/app/src/main/java/com/veniosg/dir/android/fragment/SimpleFileListFragment.java +++ b/app/src/main/java/com/veniosg/dir/android/fragment/SimpleFileListFragment.java @@ -25,6 +25,7 @@ import android.net.Uri; import android.os.Bundle; import android.os.Parcelable; +import android.support.annotation.NonNull; import android.support.v4.app.DialogFragment; import android.view.ActionMode; import android.view.LayoutInflater; @@ -97,10 +98,10 @@ public class SimpleFileListFragment extends FileListFragment { @Override public boolean onPrepareActionMode(android.view.ActionMode mode, Menu menu) { - if (getView() == null) return false; // Prevent crash from getListView()'s ensureList(). + if (getView() == null) return false; // Prevent crash from getRecyclerView()'s ensureList(). menu.clear(); - switch (getListView().getCheckedItemCount()) { + switch (getRecyclerView().getCheckedItemCount()) { // Single selection case 1: FileHolder fHolder = (FileHolder) getListAdapter().getItem(getCheckedItemPosition()); @@ -158,12 +159,12 @@ public boolean onCreateActionMode(android.view.ActionMode mode, Menu menu) { @Override public boolean onActionItemClicked(android.view.ActionMode mode, MenuItem item) { if (item.getItemId() == R.id.menu_select_all) { - for (int i = 0; i < getListView().getCount(); i++) - getListView().setItemChecked(i, true); + for (int i = 0; i < getRecyclerView().getCount(); i++) + getRecyclerView().setItemChecked(i, true); return true; } - switch (getListView().getCheckedItemCount()) { + switch (getRecyclerView().getCheckedItemCount()) { // Single selection case 1: return handleSingleSelectionAction(mode, item); @@ -176,8 +177,8 @@ public boolean onActionItemClicked(android.view.ActionMode mode, MenuItem item) @Override public void onItemCheckedStateChanged(android.view.ActionMode mode, int position, long id, boolean checked) { - if (getListView().getCheckedItemCount() != 0) { - mode.setTitle(getListView().getCheckedItemCount() + " " + if (getRecyclerView().getCheckedItemCount() != 0) { + mode.setTitle(getRecyclerView().getCheckedItemCount() + " " + getString(R.string.selected)); // Force actions' refresh @@ -188,8 +189,8 @@ public void onItemCheckedStateChanged(android.view.ActionMode mode, private FileHolderListAdapter.OnItemToggleListener mOnItemToggleListener = new FileHolderListAdapter.OnItemToggleListener() { @Override public void onItemToggle(int position) { - getListView().setItemChecked(position, - !Utils.getItemChecked(getListView(), position)); + getRecyclerView().setItemChecked(position, + !Utils.getItemChecked(getRecyclerView(), position)); } }; private ActivityProvider mActivityProvider = new ActivityProvider() { @@ -372,12 +373,12 @@ private void addBookmark(File file) { } @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_filelist_simple, container, false); } @Override - public void onViewCreated(View view, Bundle savedInstanceState) { + public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); // We expect the pathbar to add the bottom shadow in this case @@ -417,8 +418,8 @@ public void directoryChanged(File newCurrentDir) { private void initContextualActions() { if (mActionsEnabled) { - getListView().setMultiChoiceModeListener(mMultiChoiceModeListener); - getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); + getRecyclerView().setMultiChoiceModeListener(mMultiChoiceModeListener); + getRecyclerView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); ((FileHolderListAdapter) getListAdapter()).setOnItemToggleListener(mOnItemToggleListener); setHasOptionsMenu(true); @@ -426,10 +427,9 @@ private void initContextualActions() { } @Override - public void onListItemClick(AbsListView l, View v, int position, long id) { - FileHolder item = (FileHolder) mAdapter.getItem(position); + public void onListItemClick(View itemView, FileHolder item) { if (item != null) { - heroView = v; + heroView = itemView; openInformingPathBar(item); heroView = null; } @@ -692,18 +692,18 @@ void inflateMultipleChoiceMenu(MenuInflater menuInflater, Menu menu) { * @return */ int getCheckedItemPosition() { - return (int) getListView().getCheckedItemIds()[0]; + return (int) getRecyclerView().getCheckedItemIds()[0]; } private void useFolderScroll(final ScrollPosition pos) { if (getView() != null) { - Utils.scrollToPosition(getListView(), pos, false); + Utils.scrollToPosition(getRecyclerView(), pos, false); } } private void keepFolderScroll() { - int firstVisiblePosition = getListView().getFirstVisiblePosition(); - View firstVisibleChild = getListView().getChildAt(0); + int firstVisiblePosition = getRecyclerView().getFirstVisiblePosition(); + View firstVisibleChild = getRecyclerView().getChildAt(0); if (firstVisibleChild != null) { sScrollPositions.put(getPath(), new ScrollPosition(firstVisiblePosition, @@ -717,7 +717,7 @@ private void keepFolderScroll() { private ArrayList getCheckedItems() { ArrayList items = new ArrayList(); - for (long pos : getListView().getCheckedItemIds()) { + for (long pos : getRecyclerView().getCheckedItemIds()) { FileHolder item = (FileHolder) getListAdapter().getItem((int) pos); if (item != null) items.add(item); } diff --git a/app/src/main/java/com/veniosg/dir/android/ui/widget/DividerGridView.java b/app/src/main/java/com/veniosg/dir/android/ui/widget/DividerRecyclerView.java similarity index 89% rename from app/src/main/java/com/veniosg/dir/android/ui/widget/DividerGridView.java rename to app/src/main/java/com/veniosg/dir/android/ui/widget/DividerRecyclerView.java index 23e45c12..bc373267 100644 --- a/app/src/main/java/com/veniosg/dir/android/ui/widget/DividerGridView.java +++ b/app/src/main/java/com/veniosg/dir/android/ui/widget/DividerRecyclerView.java @@ -20,28 +20,28 @@ import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; import android.view.View; -import android.widget.GridView; import static android.R.attr.listDivider; import static com.veniosg.dir.android.ui.Themer.getThemedResourceId; -public class DividerGridView extends GridView { +public class DividerRecyclerView extends RecyclerView { private int mDividerSize; private Drawable mDivider; - public DividerGridView(Context context) { + public DividerRecyclerView(Context context) { super(context); init(context); } - public DividerGridView(Context context, AttributeSet attrs) { + public DividerRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } - public DividerGridView(Context context, AttributeSet attrs, int defStyle) { + public DividerRecyclerView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } @@ -54,6 +54,7 @@ private void init(Context context) { @Override protected void dispatchDraw(Canvas canvas) { + // TODO move this to default item decoration double count = getChildCount(); int bottom, top, right; int numColumns = getNumColumns(); diff --git a/app/src/main/res/layout/fragment_filelist.xml b/app/src/main/res/layout/fragment_filelist.xml index d88530f1..02a8d673 100644 --- a/app/src/main/res/layout/fragment_filelist.xml +++ b/app/src/main/res/layout/fragment_filelist.xml @@ -30,7 +30,7 @@ android:orientation="vertical"> -