Enhance media tab

Signed-off-by: tobiasKaminsky <tobias@kaminsky.me>
This commit is contained in:
tobiasKaminsky 2022-01-31 11:28:02 +01:00
parent 6b8ce02a2e
commit 3bfc373e50
No known key found for this signature in database
GPG key ID: 0E00D4D47D0C5AF7
11 changed files with 445 additions and 121 deletions

View file

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

View file

@ -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)
}
}

View file

@ -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) { public List<OCFile> getVirtualFolderContent(VirtualFolderType type, boolean onlyImages) {
List<OCFile> ocFiles = new ArrayList<>(); List<OCFile> ocFiles = new ArrayList<>();
Uri req_uri = ProviderTableMeta.CONTENT_URI_VIRTUAL; Uri req_uri = ProviderTableMeta.CONTENT_URI_VIRTUAL;

View file

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

View file

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

View file

@ -916,7 +916,8 @@ public class FileContentProvider extends ContentProvider {
+ ProviderTableMeta._ID + " INTEGER PRIMARY KEY, " // id + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, " // id
+ ProviderTableMeta.VIRTUAL_TYPE + " TEXT, " // type + ProviderTableMeta.VIRTUAL_TYPE + " TEXT, " // type
+ ProviderTableMeta.VIRTUAL_OCFILE_ID + " INTEGER )" // file id + ProviderTableMeta.VIRTUAL_OCFILE_ID + " INTEGER )" // file id
); + ProviderTableMeta.VIRTUAL_OCFILE_REMOTE_ID + " STRNING )" // remote id
);
} }
private void createFileSystemTable(SQLiteDatabase db) { private void createFileSystemTable(SQLiteDatabase db) {
@ -2467,6 +2468,27 @@ public class FileContentProvider extends ContentProvider {
if (!upgraded) { if (!upgraded) {
Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion)); 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));
}
} }
} }
} }

View file

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

View file

@ -25,69 +25,92 @@ import android.os.AsyncTask;
import com.nextcloud.client.account.User; import com.nextcloud.client.account.User;
import com.owncloud.android.datamodel.FileDataStorageManager; 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.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.files.SearchRemoteOperation; 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.adapter.OCFileListAdapter;
import com.owncloud.android.ui.fragment.ExtendedListFragment; import com.owncloud.android.ui.fragment.ExtendedListFragment;
import com.owncloud.android.ui.fragment.GalleryFragment; import com.owncloud.android.ui.fragment.GalleryFragment;
import com.owncloud.android.utils.FileStorageUtils;
import java.lang.ref.WeakReference; 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> { public class GallerySearchTask extends AsyncTask<Void, Void, RemoteOperationResult> {
private int columnCount; private final User user;
private User user; private final WeakReference<GalleryFragment> photoFragmentWeakReference;
private WeakReference<GalleryFragment> photoFragmentWeakReference; private final FileDataStorageManager storageManager;
private SearchRemoteOperation searchRemoteOperation; private final int limit;
private FileDataStorageManager storageManager; private final long startDate;
private int limit; private final long endDate;
public GallerySearchTask(int columnsCount, public GallerySearchTask(GalleryFragment photoFragment,
GalleryFragment photoFragment,
User user, User user,
SearchRemoteOperation searchRemoteOperation, FileDataStorageManager storageManager,
FileDataStorageManager storageManager) { long startDate,
this.columnCount = columnsCount; long endDate,
int limit) {
this.user = user; this.user = user;
this.photoFragmentWeakReference = new WeakReference<>(photoFragment); this.photoFragmentWeakReference = new WeakReference<>(photoFragment);
this.searchRemoteOperation = searchRemoteOperation;
this.storageManager = storageManager; this.storageManager = storageManager;
this.startDate = startDate;
this.endDate = endDate;
this.limit = limit;
} }
@Override // @Override
protected void onPreExecute() { // protected void onPreExecute() {
super.onPreExecute(); // super.onPreExecute();
//
if (photoFragmentWeakReference.get() == null) { // if (photoFragmentWeakReference.get() == null) {
return; // return;
} // }
GalleryFragment photoFragment = photoFragmentWeakReference.get(); // GalleryFragment photoFragment = photoFragmentWeakReference.get();
photoFragment.setPhotoSearchQueryRunning(true); // // photoFragment.searchCompleted(true, lastTimeStamp);
} // }
@Override @Override
protected RemoteOperationResult doInBackground(Void... voids) { protected RemoteOperationResult doInBackground(Void... voids) {
// try {
// Thread.sleep(5 * 1000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
if (photoFragmentWeakReference.get() == null) { if (photoFragmentWeakReference.get() == null) {
return new RemoteOperationResult(new Exception("Photo fragment is null")); return new RemoteOperationResult(new Exception("Photo fragment is null"));
} }
GalleryFragment photoFragment = photoFragmentWeakReference.get(); GalleryFragment photoFragment = photoFragmentWeakReference.get();
OCFileListAdapter adapter = photoFragment.getAdapter();
if (isCancelled()) { if (isCancelled()) {
return new RemoteOperationResult(new Exception("Cancelled")); return new RemoteOperationResult(new Exception("Cancelled"));
} else { } 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.setLimit(limit);
searchRemoteOperation.setTimestamp(timestamp); searchRemoteOperation.setStartDate(startDate);
searchRemoteOperation.setEndDate(endDate);
if (photoFragment.getContext() != null) { 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()); return searchRemoteOperation.execute(user.toPlatformAccount(), photoFragment.getContext());
} else { } else {
return new RemoteOperationResult(new IllegalStateException("No context available")); return new RemoteOperationResult(new IllegalStateException("No context available"));
@ -100,35 +123,91 @@ public class GallerySearchTask extends AsyncTask<Void, Void, RemoteOperationResu
if (photoFragmentWeakReference.get() != null) { if (photoFragmentWeakReference.get() != null) {
GalleryFragment photoFragment = photoFragmentWeakReference.get(); GalleryFragment photoFragment = photoFragmentWeakReference.get();
photoFragment.setLoading(false);
OCFileListAdapter adapter = photoFragment.getAdapter();
if (result.isSuccess() && result.getData() != null && !isCancelled()) { if (result.isSuccess() && result.getData() != null && !isCancelled()) {
if (result.getData() == null || result.getData().size() == 0) { if (result.getData() == null || result.getData().size() == 0) {
photoFragment.setSearchDidNotFindNewPhotos(true);
photoFragment.setEmptyListMessage(ExtendedListFragment.SearchType.GALLERY_SEARCH); 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()) { if (!result.isSuccess() && !isCancelled()) {
photoFragment.setEmptyListMessage(ExtendedListFragment.SearchType.GALLERY_SEARCH); 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();
}
} }

View file

@ -27,52 +27,32 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; 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.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.asynctasks.GallerySearchTask;
import com.owncloud.android.ui.events.ChangeMenuEvent; import com.owncloud.android.ui.events.ChangeMenuEvent;
import com.owncloud.android.ui.events.SearchEvent;
import java.util.ArrayList;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView; 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 * A Fragment that lists all files and folders in a given path
* FileDisplayActivity
*/ */
public class GalleryFragment extends OCFileListFragment { public class GalleryFragment extends OCFileListFragment {
private static final int MAX_ITEMS_PER_ROW = 10; private static final int MAX_ITEMS_PER_ROW = 10;
private boolean photoSearchQueryRunning = false; private boolean photoSearchQueryRunning = false;
private boolean photoSearchNoNew = false; private AsyncTask<Void, Void, RemoteOperationResult> photoSearchTask;
private SearchRemoteOperation searchRemoteOperation; private long startDate;
private AsyncTask photoSearchTask; private long endDate;
private SearchEvent searchEvent; private long daySpan = 30;
private boolean refresh; private int limit = 300;
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);
}
}
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
refresh = true; searchFragment = true;
} }
@Override @Override
@ -89,7 +69,6 @@ public class GalleryFragment extends OCFileListFragment {
*/ */
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
createOperation();
View v = super.onCreateView(inflater, container, savedInstanceState); View v = super.onCreateView(inflater, container, savedInstanceState);
getRecyclerView().addOnScrollListener(new RecyclerView.OnScrollListener() { getRecyclerView().addOnScrollListener(new RecyclerView.OnScrollListener() {
@ -121,7 +100,6 @@ public class GalleryFragment extends OCFileListFragment {
public void onRefresh() { public void onRefresh() {
super.onRefresh(); super.onRefresh();
refresh = true;
handleSearchEvent(); handleSearchEvent();
} }
@ -138,25 +116,10 @@ public class GalleryFragment extends OCFileListFragment {
private void handleSearchEvent() { private void handleSearchEvent() {
prepareCurrentSearch(searchEvent); prepareCurrentSearch(searchEvent);
searchFragment = true;
setEmptyListLoadingMessage(); setEmptyListLoadingMessage();
if (refresh || preferences.getPhotoSearchTimestamp() == 0 || // always show first stored items
System.currentTimeMillis() - preferences.getPhotoSearchTimestamp() >= 30 * 1000) { mAdapter.showAllGalleryItems(mContainerActivity.getStorageManager());
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;
}
setFabVisible(false); setFabVisible(false);
@ -164,27 +127,59 @@ public class GalleryFragment extends OCFileListFragment {
} }
private void searchAndDisplay() { private void searchAndDisplay() {
if (!photoSearchQueryRunning && !photoSearchNoNew) { // first: always search from now to -30 days
photoSearchTask = new GallerySearchTask(getColumnsCount(),
this, if (!photoSearchQueryRunning) {
photoSearchQueryRunning = true;
startDate = (System.currentTimeMillis() / 1000) - 30 * 24 * 60 * 60;
endDate = System.currentTimeMillis() / 1000;
photoSearchTask = new GallerySearchTask(this,
accountManager.getUser(), accountManager.getUser(),
searchRemoteOperation, mContainerActivity.getStorageManager(),
mContainerActivity.getStorageManager()) startDate,
endDate,
limit)
.execute(); .execute();
} }
} }
public void setPhotoSearchQueryRunning(boolean bool) { public void searchCompleted(boolean emptySearch, long lastTimeStamp) {
photoSearchQueryRunning = bool; photoSearchQueryRunning = false;
}
public void setSearchDidNotFindNewPhotos(boolean noNewPhotos) { if (emptySearch) {
photoSearchNoNew = noNewPhotos; 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);
photoSearchTask = new GallerySearchTask(this,
accountManager.getUser(),
mContainerActivity.getStorageManager(),
startDate,
endDate,
limit)
.execute();
} }
@Override @Override
public boolean isLoading() { public boolean isLoading() {
return !photoSearchNoNew; return photoSearchQueryRunning;
} }
private void loadMoreWhenEndReached(@NonNull RecyclerView recyclerView, int dy) { private void loadMoreWhenEndReached(@NonNull RecyclerView recyclerView, int dy) {
@ -195,12 +190,24 @@ public class GalleryFragment extends OCFileListFragment {
if (dy > 0 && !photoSearchQueryRunning) { if (dy > 0 && !photoSearchQueryRunning) {
int visibleItemCount = gridLayoutManager.getChildCount(); int visibleItemCount = gridLayoutManager.getChildCount();
int totalItemCount = gridLayoutManager.getItemCount(); 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) { && (totalItemCount - visibleItemCount) > 0) {
// Almost reached the end, continue to load new photos // 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();
} }
} }
} }

View file

@ -1499,7 +1499,13 @@ public class OCFileListFragment extends ExtendedListFragment implements
prepareCurrentSearch(event); prepareCurrentSearch(event);
searchFragment = true; searchFragment = true;
setEmptyListLoadingMessage(); 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); setFabVisible(false);
@ -1557,7 +1563,9 @@ public class OCFileListFragment extends ExtendedListFragment implements
currentSearchType, currentSearchType,
storageManager, storageManager,
mFile, mFile,
true); true,
-1,
-1);
} }
final ToolbarActivity fileDisplayActivity = (ToolbarActivity) getActivity(); final ToolbarActivity fileDisplayActivity = (ToolbarActivity) getActivity();

View file

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