mirror of
https://github.com/nextcloud/android.git
synced 2024-11-25 06:35:48 +03:00
Enhance media tab
Signed-off-by: tobiasKaminsky <tobias@kaminsky.me>
This commit is contained in:
parent
6b8ce02a2e
commit
3bfc373e50
11 changed files with 445 additions and 121 deletions
|
@ -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"
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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";
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -48,4 +48,6 @@ public interface OCFileListFragmentInterface {
|
||||||
boolean isLoading();
|
boolean isLoading();
|
||||||
|
|
||||||
void onHeaderClicked();
|
void onHeaderClicked();
|
||||||
|
|
||||||
|
boolean isSearchFragment();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue