Эх сурвалжийг харах

Enhance media tab

Signed-off-by: tobiasKaminsky <tobias@kaminsky.me>
tobiasKaminsky 3 жил өмнө
parent
commit
3bfc373e50

+ 1 - 1
build.gradle

@@ -64,7 +64,7 @@ ext {
 	daggerVersion = "2.40.5"
     markwonVersion =  "4.6.2"
     prismVersion = "2.0.0"
-    androidLibraryVersion = "master-SNAPSHOT"
+    androidLibraryVersion = "limitDates-SNAPSHOT"
     mockitoVersion = "4.3.1"
     mockkVersion = "1.12.2"
     powermockVersion = "2.0.9"

+ 79 - 0
src/androidTest/java/com/owncloud/android/ui/adapter/OCFileListAdapterIT.kt

@@ -0,0 +1,79 @@
+/*
+ *
+ * Nextcloud Android client application
+ *
+ * @author Tobias Kaminsky
+ * Copyright (C) 2022 Tobias Kaminsky
+ * Copyright (C) 2022 Nextcloud GmbH
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+package com.owncloud.android.ui.adapter
+
+import com.owncloud.android.AbstractIT
+import com.owncloud.android.datamodel.OCFile
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+class OCFileListAdapterIT : AbstractIT() {
+    @Test
+    fun testParseMedia() {
+        // empty start
+        storageManager.deleteAllFiles()
+
+        val startDate: Long = 0
+        val endDate: Long = 3642752043
+        assertEquals(0, storageManager.getGalleryItems(startDate, endDate).size)
+
+        // create dummy files
+        OCFile("/test.txt", "01").apply {
+            mimeType = "text/plain"
+        }.let {
+            storageManager.saveFile(it)
+        }
+
+        OCFile("/image.png", "02").apply {
+            mimeType = "image/png"
+            modificationTimestamp = 1000000
+        }.let {
+            storageManager.saveFile(it)
+        }
+
+        OCFile("/image2.png", "03").apply {
+            mimeType = "image/png"
+            modificationTimestamp = 1000050
+        }.let {
+            storageManager.saveFile(it)
+        }
+
+        OCFile("/video.mpg", "04").apply {
+            mimeType = "video/mpg"
+            modificationTimestamp = 1000045
+        }.let {
+            storageManager.saveFile(it)
+        }
+
+        OCFile("/video2.avi", "05").apply {
+            mimeType = "video/avi"
+            modificationTimestamp = endDate + 10
+        }.let {
+            storageManager.saveFile(it)
+        }
+
+        // list of remoteFiles
+        assertEquals(5, storageManager.allFiles.size)
+        assertEquals(3, storageManager.getGalleryItems(startDate, endDate).size)
+        assertEquals(4, storageManager.allGalleryItems.size)
+    }
+}

+ 104 - 0
src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java

@@ -2274,6 +2274,110 @@ public class FileDataStorageManager {
         }
     }
 
+    public boolean virtualExists(VirtualFolderType type, OCFile file) {
+        Cursor cursor;
+
+        if (getContentProviderClient() != null) {
+            try {
+                cursor = getContentProviderClient().query(
+                    ProviderTableMeta.CONTENT_URI_VIRTUAL,
+                    null,
+                    ProviderTableMeta.VIRTUAL_TYPE + AND + ProviderTableMeta.VIRTUAL_OCFILE_REMOTE_ID + " =?",
+                    new String[]{String.valueOf(type), file.getRemoteId()},
+                    null
+                                                         );
+            } catch (RemoteException e) {
+                Log_OC.e(TAG, e.getMessage(), e);
+                return false;
+            }
+        } else {
+            cursor = getContentResolver().query(
+                ProviderTableMeta.CONTENT_URI_VIRTUAL,
+                null,
+                ProviderTableMeta.VIRTUAL_TYPE + AND + ProviderTableMeta.VIRTUAL_OCFILE_REMOTE_ID + " =?",
+                new String[]{String.valueOf(type), file.getRemoteId()},
+                null
+                                               );
+        }
+
+        if (cursor == null) {
+            Log_OC.e(TAG, "Couldn't determine file existence, assuming non existence");
+
+            return false;
+        } else {
+            boolean exists = cursor.moveToFirst();
+            cursor.close();
+
+            return exists;
+        }
+    }
+
+    public List<OCFile> getAllGalleryItems() {
+        return getGalleryItems(0, Long.MAX_VALUE);
+    }
+
+    public List<OCFile> getGalleryItems(long startDate, long endDate) {
+        List<OCFile> files = new ArrayList<>();
+
+        Uri requestURI = ProviderTableMeta.CONTENT_URI;
+        Cursor cursor;
+
+        if (getContentProviderClient() != null) {
+            try {
+                cursor = getContentProviderClient().query(
+                    requestURI,
+                    null,
+                    ProviderTableMeta.FILE_ACCOUNT_OWNER + AND +
+                        ProviderTableMeta.FILE_MODIFIED + ">=? AND " +
+                        ProviderTableMeta.FILE_MODIFIED + "<? AND (" +
+                        ProviderTableMeta.FILE_CONTENT_TYPE + " LIKE ? OR " +
+                        ProviderTableMeta.FILE_CONTENT_TYPE + " LIKE ? )",
+                    new String[]{
+                        user.getAccountName(),
+                        String.valueOf(startDate),
+                        String.valueOf(endDate),
+                        "image/%",
+                        "video/%"
+                    },
+                    null
+                                                         );
+            } catch (RemoteException e) {
+                Log_OC.e(TAG, e.getMessage(), e);
+                return files;
+            }
+        } else {
+            cursor = getContentResolver().query(
+                requestURI,
+                null,
+                ProviderTableMeta.FILE_ACCOUNT_OWNER + AND +
+                    ProviderTableMeta.FILE_MODIFIED + ">=? AND " +
+                    ProviderTableMeta.FILE_MODIFIED + "<? AND (" +
+                    ProviderTableMeta.FILE_CONTENT_TYPE + " LIKE ? OR " +
+                    ProviderTableMeta.FILE_CONTENT_TYPE + " LIKE ? )",
+                new String[]{
+                    user.getAccountName(),
+                    String.valueOf(startDate),
+                    String.valueOf(endDate),
+                    "image/%",
+                    "video/%"
+                },
+                null
+                                               );
+        }
+
+        if (cursor != null) {
+            if (cursor.moveToFirst()) {
+                do {
+                    OCFile child = createFileInstance(cursor);
+                    files.add(child);
+                } while (cursor.moveToNext());
+            }
+            cursor.close();
+        }
+
+        return files;
+    }
+
     public List<OCFile> getVirtualFolderContent(VirtualFolderType type, boolean onlyImages) {
         List<OCFile> ocFiles = new ArrayList<>();
         Uri req_uri = ProviderTableMeta.CONTENT_URI_VIRTUAL;

+ 3 - 0
src/main/java/com/owncloud/android/datamodel/OCFile.java

@@ -603,6 +603,9 @@ public class OCFile implements Parcelable, Comparable<OCFile>, ServerFileInterfa
         return this.creationTimestamp;
     }
 
+    /**
+     * @return unix timestamp in milliseconds
+     */
     public long getModificationTimestamp() {
         return this.modificationTimestamp;
     }

+ 2 - 1
src/main/java/com/owncloud/android/db/ProviderMeta.java

@@ -35,7 +35,7 @@ import java.util.List;
  */
 public class ProviderMeta {
     public static final String DB_NAME = "filelist";
-    public static final int DB_VERSION = 62;
+    public static final int DB_VERSION = 63;
 
     private ProviderMeta() {
         // No instance
@@ -286,6 +286,7 @@ public class ProviderMeta {
         // Columns of virtual
         public static final String VIRTUAL_TYPE = "type";
         public static final String VIRTUAL_OCFILE_ID = "ocfile_id";
+        public static final String VIRTUAL_OCFILE_REMOTE_ID = "ocfile_remote_id";
 
         // Columns of filesystem data table
         public static final String FILESYSTEM_FILE_LOCAL_PATH = "local_path";

+ 23 - 1
src/main/java/com/owncloud/android/providers/FileContentProvider.java

@@ -916,7 +916,8 @@ public class FileContentProvider extends ContentProvider {
                        + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, "          // id
                        + ProviderTableMeta.VIRTUAL_TYPE + " TEXT, "                // type
                        + ProviderTableMeta.VIRTUAL_OCFILE_ID + " INTEGER )"        // file id
-        );
+                       + ProviderTableMeta.VIRTUAL_OCFILE_REMOTE_ID + " STRNING )"        // remote id
+                  );
     }
 
     private void createFileSystemTable(SQLiteDatabase db) {
@@ -2467,6 +2468,27 @@ public class FileContentProvider extends ContentProvider {
             if (!upgraded) {
                 Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion));
             }
+
+            if (oldVersion < 63 && newVersion >= 63) {
+                Log_OC.i(SQL, "Entering in the #63 add remote_id to virtuals");
+                db.beginTransaction();
+                try {
+                    db.execSQL(ALTER_TABLE + ProviderTableMeta.VIRTUAL_TABLE_NAME +
+                                   ADD_COLUMN + ProviderTableMeta.VIRTUAL_OCFILE_REMOTE_ID + " TEXT ");
+
+                    // delete all virtual
+                    db.execSQL("DELETE FROM `virtual`");
+
+                    upgraded = true;
+                    db.setTransactionSuccessful();
+                } finally {
+                    db.endTransaction();
+                }
+            }
+
+            if (!upgraded) {
+                Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion));
+            }
         }
     }
 }

+ 25 - 6
src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java

@@ -753,7 +753,7 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
             return false;
         }
 
-        if (MainApp.isOnlyOnDevice()) {
+        if (MainApp.isOnlyOnDevice() || ocFileListFragmentInterface.isSearchFragment()) {
             return false;
         }
 
@@ -857,13 +857,14 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
         notifyDataSetChanged();
     }
 
-
-
+    // TODO split up
     public void setData(List<Object> objects,
                         ExtendedListFragment.SearchType searchType,
                         FileDataStorageManager storageManager,
                         @Nullable OCFile folder,
-                        boolean clear) {
+                        boolean clear,
+                        long startDate,
+                        long endDate) {
         if (storageManager != null && mStorageManager == null) {
             mStorageManager = storageManager;
             showShareAvatar = mStorageManager.getCapability(user.getAccountName()).getVersion().isShareesOnDavSupported();
@@ -891,7 +892,9 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
                     break;
             }
 
-            mStorageManager.deleteVirtuals(type);
+            if (type != VirtualFolderType.GALLERY) {
+                mStorageManager.deleteVirtuals(type);
+            }
         }
 
         // early exit
@@ -899,7 +902,9 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
             if (searchType == ExtendedListFragment.SearchType.SHARED_FILTER) {
                 parseShares(objects);
             } else {
-                parseVirtuals(objects, searchType);
+                if (searchType != ExtendedListFragment.SearchType.GALLERY_SEARCH) {
+                    parseVirtuals(objects, searchType);
+                }
             }
         }
 
@@ -1020,6 +1025,7 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
                 ContentValues cv = new ContentValues();
                 cv.put(ProviderMeta.ProviderTableMeta.VIRTUAL_TYPE, type.toString());
                 cv.put(ProviderMeta.ProviderTableMeta.VIRTUAL_OCFILE_ID, ocFile.getFileId());
+                cv.put(ProviderMeta.ProviderTableMeta.VIRTUAL_OCFILE_REMOTE_ID, ocFile.getRemoteId());
 
                 contentValues.add(cv);
             } catch (RemoteOperationFailedException e) {
@@ -1031,6 +1037,19 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
         mStorageManager.saveVirtuals(contentValues);
     }
 
+    public void showAllGalleryItems(FileDataStorageManager storageManager) {
+        if (mStorageManager == null) {
+            mStorageManager = storageManager;
+        }
+        mFiles = mStorageManager.getAllGalleryItems();
+        FileStorageUtils.sortOcFolderDescDateModifiedWithoutFavoritesFirst(mFiles);
+
+        mFilesAll.clear();
+        mFilesAll.addAll(mFiles);
+
+        new Handler(Looper.getMainLooper()).post(this::notifyDataSetChanged);
+    }
+
     public void showVirtuals(VirtualFolderType type, boolean onlyImages, FileDataStorageManager storageManager) {
         mFiles = storageManager.getVirtualFolderContent(type, onlyImages);
 

+ 127 - 48
src/main/java/com/owncloud/android/ui/asynctasks/GallerySearchTask.java

@@ -25,69 +25,92 @@ import android.os.AsyncTask;
 
 import com.nextcloud.client.account.User;
 import com.owncloud.android.datamodel.FileDataStorageManager;
+import com.owncloud.android.datamodel.OCFile;
 import com.owncloud.android.lib.common.operations.RemoteOperationResult;
 import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.lib.resources.files.SearchRemoteOperation;
+import com.owncloud.android.lib.resources.files.model.RemoteFile;
+import com.owncloud.android.lib.resources.status.OCCapability;
+import com.owncloud.android.operations.RefreshFolderOperation;
 import com.owncloud.android.ui.adapter.OCFileListAdapter;
 import com.owncloud.android.ui.fragment.ExtendedListFragment;
 import com.owncloud.android.ui.fragment.GalleryFragment;
+import com.owncloud.android.utils.FileStorageUtils;
 
 import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
 
 public class GallerySearchTask extends AsyncTask<Void, Void, RemoteOperationResult> {
 
-    private int columnCount;
-    private User user;
-    private WeakReference<GalleryFragment> photoFragmentWeakReference;
-    private SearchRemoteOperation searchRemoteOperation;
-    private FileDataStorageManager storageManager;
-    private int limit;
+    private final User user;
+    private final WeakReference<GalleryFragment> photoFragmentWeakReference;
+    private final FileDataStorageManager storageManager;
+    private final int limit;
+    private final long startDate;
+    private final long endDate;
 
-    public GallerySearchTask(int columnsCount,
-                             GalleryFragment photoFragment,
+    public GallerySearchTask(GalleryFragment photoFragment,
                              User user,
-                             SearchRemoteOperation searchRemoteOperation,
-                             FileDataStorageManager storageManager) {
-        this.columnCount = columnsCount;
+                             FileDataStorageManager storageManager,
+                             long startDate,
+                             long endDate,
+                             int limit) {
         this.user = user;
         this.photoFragmentWeakReference = new WeakReference<>(photoFragment);
-        this.searchRemoteOperation = searchRemoteOperation;
         this.storageManager = storageManager;
+        this.startDate = startDate;
+        this.endDate = endDate;
+        this.limit = limit;
     }
 
-    @Override
-    protected void onPreExecute() {
-        super.onPreExecute();
-
-        if (photoFragmentWeakReference.get() == null) {
-            return;
-        }
-        GalleryFragment photoFragment = photoFragmentWeakReference.get();
-        photoFragment.setPhotoSearchQueryRunning(true);
-    }
+//    @Override
+//    protected void onPreExecute() {
+//        super.onPreExecute();
+//
+//        if (photoFragmentWeakReference.get() == null) {
+//            return;
+//        }
+//        GalleryFragment photoFragment = photoFragmentWeakReference.get();
+//        // photoFragment.searchCompleted(true, lastTimeStamp);
+//    }
 
     @Override
     protected RemoteOperationResult doInBackground(Void... voids) {
+//        try {
+//            Thread.sleep(5 * 1000);
+//        } catch (InterruptedException e) {
+//            e.printStackTrace();
+//        }
+
         if (photoFragmentWeakReference.get() == null) {
             return new RemoteOperationResult(new Exception("Photo fragment is null"));
         }
         GalleryFragment photoFragment = photoFragmentWeakReference.get();
-        OCFileListAdapter adapter = photoFragment.getAdapter();
 
         if (isCancelled()) {
             return new RemoteOperationResult(new Exception("Cancelled"));
         } else {
-            limit = 15 * columnCount;
+            OCCapability ocCapability = storageManager.getCapability(user.getAccountName());
+
+            SearchRemoteOperation searchRemoteOperation = new SearchRemoteOperation("",
+                                                                                    SearchRemoteOperation.SearchType.GALLERY_SEARCH,
+                                                                                    false,
+                                                                                    ocCapability);
 
-            long timestamp = -1;
-            if (adapter.getLastTimestamp() > 0) {
-                timestamp = adapter.getLastTimestamp();
-            }
 
             searchRemoteOperation.setLimit(limit);
-            searchRemoteOperation.setTimestamp(timestamp);
+            searchRemoteOperation.setStartDate(startDate);
+            searchRemoteOperation.setEndDate(endDate);
 
             if (photoFragment.getContext() != null) {
+                Log_OC.d(this,
+                         "Start gallery search with " + new Date(startDate * 1000L) +
+                             " - " + new Date(endDate * 1000L) +
+                             " with limit: " + limit);
                 return searchRemoteOperation.execute(user.toPlatformAccount(), photoFragment.getContext());
             } else {
                 return new RemoteOperationResult(new IllegalStateException("No context available"));
@@ -100,35 +123,91 @@ public class GallerySearchTask extends AsyncTask<Void, Void, RemoteOperationResu
         if (photoFragmentWeakReference.get() != null) {
             GalleryFragment photoFragment = photoFragmentWeakReference.get();
 
+            photoFragment.setLoading(false);
+
+            OCFileListAdapter adapter = photoFragment.getAdapter();
+
             if (result.isSuccess() && result.getData() != null && !isCancelled()) {
                 if (result.getData() == null || result.getData().size() == 0) {
-                    photoFragment.setSearchDidNotFindNewPhotos(true);
                     photoFragment.setEmptyListMessage(ExtendedListFragment.SearchType.GALLERY_SEARCH);
-                } else {
-                    OCFileListAdapter adapter = photoFragment.getAdapter();
-
-                    if (result.getData().size() < limit) {
-                        // stop loading spinner
-                        photoFragment.setSearchDidNotFindNewPhotos(true);
-                    }
-
-                    adapter.setData(result.getData(),
-                                    ExtendedListFragment.SearchType.GALLERY_SEARCH,
-                                    storageManager,
-                                    null,
-                                    false);
-                    adapter.notifyDataSetChanged();
-                    Log_OC.d(this, "Search: count: " + result.getData().size() + " total: " + adapter.getFiles().size());
                 }
             }
 
-            photoFragment.setLoading(false);
-
             if (!result.isSuccess() && !isCancelled()) {
                 photoFragment.setEmptyListMessage(ExtendedListFragment.SearchType.GALLERY_SEARCH);
             }
 
-            photoFragment.setPhotoSearchQueryRunning(false);
+            // TODO move this to backgroundThread
+            boolean emptySearch = parseMedia(startDate, endDate, result.getData());
+            long lastTimeStamp = findLastTimestamp(result.getData());
+
+            adapter.showAllGalleryItems(storageManager);
+
+            photoFragment.searchCompleted(emptySearch, lastTimeStamp);
         }
     }
+
+    private long findLastTimestamp(ArrayList<RemoteFile> remoteFiles) {
+        int lastPosition = remoteFiles.size() - 1;
+
+        if (lastPosition < 0) {
+            return -1;
+        }
+
+        RemoteFile lastFile = remoteFiles.get(lastPosition);
+        return lastFile.getModifiedTimestamp() / 1000;
+    }
+
+    private boolean parseMedia(long startDate, long endDate, List<Object> remoteFiles) {
+        // retrieve all between startDate and endDate
+        Map<String, OCFile> localFilesMap = RefreshFolderOperation.prefillLocalFilesMap(null,
+                                                                                        storageManager.getGalleryItems(startDate * 1000L,
+                                                                                                                       endDate * 1000L));
+        List<OCFile> filesToAdd = new ArrayList<>();
+        List<OCFile> filesToUpdate = new ArrayList<>();
+
+        OCFile localFile;
+        for (Object file : remoteFiles) {
+            OCFile ocFile = FileStorageUtils.fillOCFile((RemoteFile) file);
+
+            localFile = localFilesMap.remove(ocFile.getRemotePath());
+
+            if (localFile == null) {
+                // add new file
+                filesToAdd.add(ocFile);
+            } else if (!localFile.getEtag().equals(ocFile.getEtag())) {
+                // update file
+                ocFile.setLastSyncDateForData(System.currentTimeMillis());
+                filesToUpdate.add(ocFile);
+            }
+        }
+
+        // add new files
+        for (OCFile file : filesToAdd) {
+            storageManager.saveFile(file);
+        }
+
+        // update existing files
+        for (OCFile file : filesToUpdate) {
+            storageManager.saveFile(file);
+        }
+
+        // existing files to remove
+        for (OCFile file : localFilesMap.values()) {
+            storageManager.removeFile(file, true, true);
+        }
+
+        Log_OC.d(this, "Gallery search result:" +
+            " new: " + filesToAdd.size() +
+            " updated: " + filesToUpdate.size() +
+            " deleted: " + localFilesMap.values().size());
+
+        return didNotFindNewResults(filesToAdd, filesToUpdate, localFilesMap.values());
+    }
+
+    private boolean didNotFindNewResults(List<OCFile> filesToAdd,
+                                         List<OCFile> filesToUpdate,
+                                         Collection<OCFile> filesToRemove) {
+        return filesToAdd.isEmpty() && filesToUpdate.isEmpty() && filesToRemove.isEmpty();
+    }
 }

+ 69 - 62
src/main/java/com/owncloud/android/ui/fragment/GalleryFragment.java

@@ -27,52 +27,32 @@ import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 
-import com.owncloud.android.datamodel.VirtualFolderType;
+import com.owncloud.android.datamodel.OCFile;
+import com.owncloud.android.lib.common.operations.RemoteOperationResult;
 import com.owncloud.android.lib.common.utils.Log_OC;
-import com.owncloud.android.lib.resources.files.SearchRemoteOperation;
-import com.owncloud.android.lib.resources.status.OCCapability;
 import com.owncloud.android.ui.asynctasks.GallerySearchTask;
 import com.owncloud.android.ui.events.ChangeMenuEvent;
-import com.owncloud.android.ui.events.SearchEvent;
-
-import java.util.ArrayList;
 
 import androidx.annotation.NonNull;
 import androidx.recyclerview.widget.GridLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
 
 /**
- * A Fragment that lists all files and folders in a given path. TODO refactor to get rid of direct dependency on
- * FileDisplayActivity
+ * A Fragment that lists all files and folders in a given path
  */
 public class GalleryFragment extends OCFileListFragment {
     private static final int MAX_ITEMS_PER_ROW = 10;
     private boolean photoSearchQueryRunning = false;
-    private boolean photoSearchNoNew = false;
-    private SearchRemoteOperation searchRemoteOperation;
-    private AsyncTask photoSearchTask;
-    private SearchEvent searchEvent;
-    private boolean refresh;
-
-    private void createOperation() {
-        if(searchEvent == null) {
-            searchEvent = new SearchEvent("", SearchRemoteOperation.SearchType.GALLERY_SEARCH);
-        }
-        if(searchRemoteOperation == null) {
-            OCCapability ocCapability = mContainerActivity.getStorageManager()
-                .getCapability(accountManager.getUser().getAccountName());
-
-            searchRemoteOperation = new SearchRemoteOperation(searchEvent.getSearchQuery(),
-                                                              searchEvent.getSearchType(),
-                                                              false,
-                                                              ocCapability);
-        }
-    }
+    private AsyncTask<Void, Void, RemoteOperationResult> photoSearchTask;
+    private long startDate;
+    private long endDate;
+    private long daySpan = 30;
+    private int limit = 300;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        refresh = true;
+        searchFragment = true;
     }
 
     @Override
@@ -89,7 +69,6 @@ public class GalleryFragment extends OCFileListFragment {
      */
     @Override
     public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-        createOperation();
         View v = super.onCreateView(inflater, container, savedInstanceState);
 
         getRecyclerView().addOnScrollListener(new RecyclerView.OnScrollListener() {
@@ -121,7 +100,6 @@ public class GalleryFragment extends OCFileListFragment {
     public void onRefresh() {
         super.onRefresh();
 
-        refresh = true;
         handleSearchEvent();
     }
 
@@ -138,25 +116,10 @@ public class GalleryFragment extends OCFileListFragment {
 
     private void handleSearchEvent() {
         prepareCurrentSearch(searchEvent);
-        searchFragment = true;
         setEmptyListLoadingMessage();
 
-        if (refresh || preferences.getPhotoSearchTimestamp() == 0 ||
-            System.currentTimeMillis() - preferences.getPhotoSearchTimestamp() >= 30 * 1000) {
-            mAdapter.setData(
-                new ArrayList<>(),
-                SearchType.GALLERY_SEARCH,
-                mContainerActivity.getStorageManager(),
-                mFile,
-                true);
-            photoSearchNoNew = false;
-            refresh = false;
-        } else {
-            mAdapter.showVirtuals(VirtualFolderType.GALLERY, true, mContainerActivity.getStorageManager());
-            preferences.setPhotoSearchTimestamp(System.currentTimeMillis());
-
-            return;
-        }
+        // always show first stored items
+        mAdapter.showAllGalleryItems(mContainerActivity.getStorageManager());
 
         setFabVisible(false);
 
@@ -164,27 +127,59 @@ public class GalleryFragment extends OCFileListFragment {
     }
 
     private void searchAndDisplay() {
-        if (!photoSearchQueryRunning && !photoSearchNoNew) {
-            photoSearchTask = new GallerySearchTask(getColumnsCount(),
-                                                    this,
+        // first: always search from now to -30 days
+
+        if (!photoSearchQueryRunning) {
+            photoSearchQueryRunning = true;
+
+            startDate = (System.currentTimeMillis() / 1000) - 30 * 24 * 60 * 60;
+            endDate = System.currentTimeMillis() / 1000;
+
+            photoSearchTask = new GallerySearchTask(this,
                                                     accountManager.getUser(),
-                                                    searchRemoteOperation,
-                                                    mContainerActivity.getStorageManager())
+                                                    mContainerActivity.getStorageManager(),
+                                                    startDate,
+                                                    endDate,
+                                                    limit)
                 .execute();
         }
     }
 
-    public void setPhotoSearchQueryRunning(boolean bool) {
-        photoSearchQueryRunning = bool;
-    }
+    public void searchCompleted(boolean emptySearch, long lastTimeStamp) {
+        photoSearchQueryRunning = false;
+
+        if (emptySearch) {
+            Log_OC.d(this, "End gallery search");
+            return;
+        }
+        if (daySpan == 30) {
+            daySpan = 90;
+        } else if (daySpan == 90) {
+            daySpan = 180;
+        } else if (daySpan == 180) {
+            daySpan = 999;
+        } else if (daySpan == 999 && limit > 0) {
+            limit = -1; // no limit
+        } else {
+            Log_OC.d(this, "End gallery search");
+            return;
+        }
+
+        endDate = lastTimeStamp;
+        startDate = endDate - (daySpan * 24 * 60 * 60);
 
-    public void setSearchDidNotFindNewPhotos(boolean noNewPhotos) {
-        photoSearchNoNew = noNewPhotos;
+        photoSearchTask = new GallerySearchTask(this,
+                                                accountManager.getUser(),
+                                                mContainerActivity.getStorageManager(),
+                                                startDate,
+                                                endDate,
+                                                limit)
+            .execute();
     }
 
     @Override
     public boolean isLoading() {
-        return !photoSearchNoNew;
+        return photoSearchQueryRunning;
     }
 
     private void loadMoreWhenEndReached(@NonNull RecyclerView recyclerView, int dy) {
@@ -195,12 +190,24 @@ public class GalleryFragment extends OCFileListFragment {
             if (dy > 0 && !photoSearchQueryRunning) {
                 int visibleItemCount = gridLayoutManager.getChildCount();
                 int totalItemCount = gridLayoutManager.getItemCount();
-                int firstVisibleItem = gridLayoutManager.findFirstCompletelyVisibleItemPosition();
+                int lastVisibleItem = gridLayoutManager.findLastCompletelyVisibleItemPosition();
 
-                if ((totalItemCount - visibleItemCount) <= (firstVisibleItem + MAX_ITEMS_PER_ROW)
+                if ((totalItemCount - visibleItemCount) <= (lastVisibleItem + MAX_ITEMS_PER_ROW)
                     && (totalItemCount - visibleItemCount) > 0) {
                     // Almost reached the end, continue to load new photos
-                    searchAndDisplay();
+                    OCFile lastFile = mAdapter.getItem(lastVisibleItem - 1);
+
+                    daySpan = 30;
+                    endDate = lastFile.getModificationTimestamp() / 1000;
+                    startDate = endDate - (daySpan * 24 * 60 * 60);
+
+                    photoSearchTask = new GallerySearchTask(this,
+                                                            accountManager.getUser(),
+                                                            mContainerActivity.getStorageManager(),
+                                                            startDate,
+                                                            endDate,
+                                                            limit)
+                        .execute();
                 }
             }
         }

+ 10 - 2
src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java

@@ -1499,7 +1499,13 @@ public class OCFileListFragment extends ExtendedListFragment implements
         prepareCurrentSearch(event);
         searchFragment = true;
         setEmptyListLoadingMessage();
-        mAdapter.setData(new ArrayList<>(), SearchType.NO_SEARCH, mContainerActivity.getStorageManager(), mFile, true);
+        mAdapter.setData(new ArrayList<>(),
+                         SearchType.NO_SEARCH,
+                         mContainerActivity.getStorageManager(),
+                         mFile,
+                         true,
+                         -1,
+                         -1);
 
         setFabVisible(false);
 
@@ -1557,7 +1563,9 @@ public class OCFileListFragment extends ExtendedListFragment implements
                                              currentSearchType,
                                              storageManager,
                                              mFile,
-                                             true);
+                                             true,
+                                             -1,
+                                             -1);
                         }
 
                         final ToolbarActivity fileDisplayActivity = (ToolbarActivity) getActivity();

+ 2 - 0
src/main/java/com/owncloud/android/ui/interfaces/OCFileListFragmentInterface.java

@@ -48,4 +48,6 @@ public interface OCFileListFragmentInterface {
     boolean isLoading();
 
     void onHeaderClicked();
+
+    boolean isSearchFragment();
 }