Merge pull request #11321 from eraser2021999/master

Fix issues with Media Tab & performance improvement.
This commit is contained in:
Tobias Kaminsky 2023-04-12 12:40:03 +02:00 committed by GitHub
commit 426669816d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 112 additions and 116 deletions

View file

@ -24,6 +24,7 @@ package com.owncloud.android.ui.asynctasks;
import android.os.AsyncTask; import android.os.AsyncTask;
import com.nextcloud.client.account.User; import com.nextcloud.client.account.User;
import com.owncloud.android.BuildConfig;
import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.operations.RemoteOperationResult;
@ -37,6 +38,7 @@ import com.owncloud.android.ui.fragment.SearchType;
import com.owncloud.android.utils.FileStorageUtils; import com.owncloud.android.utils.FileStorageUtils;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
@ -51,19 +53,16 @@ public class GallerySearchTask extends AsyncTask<Void, Void, GallerySearchTask.R
private final WeakReference<GalleryFragment> photoFragmentWeakReference; private final WeakReference<GalleryFragment> photoFragmentWeakReference;
private final FileDataStorageManager storageManager; private final FileDataStorageManager storageManager;
private final int limit; private final int limit;
private final long startDate;
private final long endDate; private final long endDate;
public GallerySearchTask(GalleryFragment photoFragment, public GallerySearchTask(GalleryFragment photoFragment,
User user, User user,
FileDataStorageManager storageManager, FileDataStorageManager storageManager,
long startDate,
long endDate, long endDate,
int limit) { int limit) {
this.user = user; this.user = user;
this.photoFragmentWeakReference = new WeakReference<>(photoFragment); this.photoFragmentWeakReference = new WeakReference<>(photoFragment);
this.storageManager = storageManager; this.storageManager = storageManager;
this.startDate = startDate;
this.endDate = endDate; this.endDate = endDate;
this.limit = limit; this.limit = limit;
} }
@ -85,25 +84,24 @@ public class GallerySearchTask extends AsyncTask<Void, Void, GallerySearchTask.R
false, false,
ocCapability); ocCapability);
searchRemoteOperation.setLimit(limit); searchRemoteOperation.setLimit(limit);
searchRemoteOperation.setStartDate(startDate);
searchRemoteOperation.setEndDate(endDate); searchRemoteOperation.setEndDate(endDate);
if (photoFragment.getContext() != null) { //workaround to keep SearchRemoteOperation functioning correctly even if we don't actively use startDate
Log_OC.d(this, searchRemoteOperation.setStartDate(0L);
"Start gallery search with " + new Date(startDate * 1000L) +
" - " + new Date(endDate * 1000L) +
" with limit: " + limit);
if (photoFragment.getContext() != null) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Log_OC.d(this,
"Start gallery search since " + dateFormat.format(new Date(endDate * 1000L)) +
" with limit: " + limit);
RemoteOperationResult result = searchRemoteOperation.execute(user, photoFragment.getContext()); RemoteOperationResult result = searchRemoteOperation.execute(user, photoFragment.getContext());
if (result.isSuccess()) { if (result.isSuccess()) {
boolean emptySearch = parseMedia(startDate, endDate, result.getData());
long lastTimeStamp = findLastTimestamp(result.getData()); long lastTimeStamp = findLastTimestamp(result.getData());
//query the local storage based on the lastTimeStamp retrieved, not by 1970-01-01
boolean emptySearch = parseMedia(lastTimeStamp, this.endDate, result.getData());
return new Result(result.isSuccess(), emptySearch, lastTimeStamp); return new Result(result.isSuccess(), emptySearch, lastTimeStamp);
} else { } else {
return new Result(false, false, -1); return new Result(false, false, -1);
@ -118,15 +116,7 @@ public class GallerySearchTask extends AsyncTask<Void, Void, GallerySearchTask.R
protected void onPostExecute(GallerySearchTask.Result result) { protected void onPostExecute(GallerySearchTask.Result result) {
if (photoFragmentWeakReference.get() != null) { if (photoFragmentWeakReference.get() != null) {
GalleryFragment photoFragment = photoFragmentWeakReference.get(); GalleryFragment photoFragment = photoFragmentWeakReference.get();
photoFragment.setLoading(false);
photoFragment.searchCompleted(result.emptySearch, result.lastTimestamp); photoFragment.searchCompleted(result.emptySearch, result.lastTimestamp);
if (result.success && photoFragment.getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) {
photoFragment.showAllGalleryItems();
} else {
photoFragment.setEmptyListMessage(SearchType.GALLERY_SEARCH);
}
} }
} }
@ -142,56 +132,66 @@ public class GallerySearchTask extends AsyncTask<Void, Void, GallerySearchTask.R
} }
private boolean parseMedia(long startDate, long endDate, List<Object> remoteFiles) { 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; List<OCFile> localFiles = storageManager.getGalleryItems(startDate * 1000L, endDate * 1000L);
if (BuildConfig.DEBUG) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Log_OC.d(this, "parseMedia - start: " + dateFormat.format(new Date(startDate * 1000L)) + " - " + dateFormat.format(new Date(endDate * 1000L)));
for (OCFile localFile : localFiles) {
Log_OC.d(this, "local file: modified: " + dateFormat.format(new Date(localFile.getModificationTimestamp())) + " path: " + localFile.getRemotePath());
}
}
Map<String, OCFile> localFilesMap = RefreshFolderOperation.prefillLocalFilesMap(null, localFiles);
long filesAdded = 0, filesUpdated = 0, filesDeleted = 0, unchangedFiles = 0;
for (Object file : remoteFiles) { for (Object file : remoteFiles) {
OCFile ocFile = FileStorageUtils.fillOCFile((RemoteFile) file); OCFile ocFile = FileStorageUtils.fillOCFile((RemoteFile) file);
localFile = localFilesMap.remove(ocFile.getRemotePath()); if (BuildConfig.DEBUG) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Log_OC.d(this, "remote file: modified: " + dateFormat.format(new Date(ocFile.getModificationTimestamp())) + " path: " + ocFile.getRemotePath());
}
OCFile localFile = localFilesMap.remove(ocFile.getRemotePath());
if (localFile == null) { if (localFile == null) {
// add new file // add new file
filesToAdd.add(ocFile); storageManager.saveFile(ocFile);
filesAdded++;
} else if (!localFile.getEtag().equals(ocFile.getEtag())) { } else if (!localFile.getEtag().equals(ocFile.getEtag())) {
// update file // update file
ocFile.setLastSyncDateForData(System.currentTimeMillis()); ocFile.setLastSyncDateForData(System.currentTimeMillis());
filesToUpdate.add(ocFile); storageManager.saveFile(ocFile);
filesUpdated++;
} else {
unchangedFiles++;
} }
} }
// add new files
for (OCFile file : filesToAdd) {
storageManager.saveFile(file);
}
// update existing files
for (OCFile file : filesToUpdate) {
storageManager.saveFile(file);
}
// existing files to remove // existing files to remove
filesDeleted = localFilesMap.values().size();
for (OCFile file : localFilesMap.values()) { for (OCFile file : localFilesMap.values()) {
if (BuildConfig.DEBUG) {
Log_OC.d(this, "Gallery Sync: File deleted " + file.getRemotePath());
}
storageManager.removeFile(file, true, true); storageManager.removeFile(file, true, true);
} }
if (BuildConfig.DEBUG) {
Log_OC.d(this, "Gallery search result:" + Log_OC.d(this, "Gallery search result:" +
" new: " + filesToAdd.size() + " new: " + filesAdded +
" updated: " + filesToUpdate.size() + " updated: " + filesUpdated +
" deleted: " + localFilesMap.size()); " deleted: " + filesDeleted +
" unchanged: " + unchangedFiles);
return didNotFindNewResults(filesToAdd, filesToUpdate, localFilesMap.values());
} }
final long totalFiles = filesAdded + filesUpdated + filesDeleted + unchangedFiles;
private boolean didNotFindNewResults(List<OCFile> filesToAdd, return totalFiles <= 0;
List<OCFile> filesToUpdate,
Collection<OCFile> filesToRemove) {
return filesToAdd.isEmpty() && filesToUpdate.isEmpty() && filesToRemove.isEmpty();
} }
public static class Result { public static class Result {

View file

@ -35,6 +35,7 @@ import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import com.owncloud.android.BuildConfig;
import com.owncloud.android.R; import com.owncloud.android.R;
import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.datamodel.OCFile;
@ -65,10 +66,8 @@ public class GalleryFragment extends OCFileListFragment implements GalleryFragme
private boolean photoSearchQueryRunning = false; private boolean photoSearchQueryRunning = false;
private AsyncTask<Void, Void, GallerySearchTask.Result> photoSearchTask; private AsyncTask<Void, Void, GallerySearchTask.Result> photoSearchTask;
private long startDate;
private long endDate; private long endDate;
private long daySpan = 30; private int limit = 150;
private int limit = 300;
private GalleryAdapter mAdapter; private GalleryAdapter mAdapter;
private static final int SELECT_LOCATION_REQUEST_CODE = 212; private static final int SELECT_LOCATION_REQUEST_CODE = 212;
@ -80,6 +79,15 @@ public class GalleryFragment extends OCFileListFragment implements GalleryFragme
private final int maxColumnSizePortrait = 2; private final int maxColumnSizePortrait = 2;
private int columnSize; private int columnSize;
protected void setPhotoSearchQueryRunning(boolean value) {
this.photoSearchQueryRunning = value;
this.setLoading(value); // link the photoSearchQueryRunning variable with UI progress loading
}
public boolean isPhotoSearchQueryRunning() {
return this.photoSearchQueryRunning;
}
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@ -191,7 +199,7 @@ public class GalleryFragment extends OCFileListFragment implements GalleryFragme
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
setLoading(photoSearchQueryRunning); setLoading(this.isPhotoSearchQueryRunning());
final FragmentActivity activity = getActivity(); final FragmentActivity activity = getActivity();
if (activity instanceof FileDisplayActivity) { if (activity instanceof FileDisplayActivity) {
FileDisplayActivity fileDisplayActivity = ((FileDisplayActivity) activity); FileDisplayActivity fileDisplayActivity = ((FileDisplayActivity) activity);
@ -218,50 +226,31 @@ public class GalleryFragment extends OCFileListFragment implements GalleryFragme
} }
private void searchAndDisplay() { private void searchAndDisplay() {
// first: always search from now to -30 days if (!this.isPhotoSearchQueryRunning() && this.endDate <= 0) {
if (!photoSearchQueryRunning) { // fix an issue when the method is called after loading the gallery and pressing play on a movie (--> endDate <= 0)
photoSearchQueryRunning = true; // to avoid reloading the gallery, check if endDate has already a value which is not -1 or 0 (which generally means some kind of reset/init)
startDate = (System.currentTimeMillis() / 1000) - 30 * 24 * 60 * 60;
endDate = System.currentTimeMillis() / 1000; endDate = System.currentTimeMillis() / 1000;
this.setPhotoSearchQueryRunning(true);
runGallerySearchTask(); runGallerySearchTask();
} }
} }
@SuppressLint("NotifyDataSetChanged")
public void searchCompleted(boolean emptySearch, long lastTimeStamp) { public void searchCompleted(boolean emptySearch, long lastTimeStamp) {
photoSearchQueryRunning = false; this.setPhotoSearchQueryRunning(false);
mAdapter.notifyDataSetChanged();
if (mAdapter.isEmpty()) {
setEmptyListMessage(SearchType.GALLERY_SEARCH);
}
if (emptySearch && mAdapter.getItemCount() > 0) {
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;
}
if (lastTimeStamp > -1) { if (lastTimeStamp > -1) {
endDate = lastTimeStamp; endDate = lastTimeStamp;
} }
startDate = endDate - (daySpan * 24 * 60 * 60); if (mAdapter.isEmpty()) {
setEmptyListMessage(SearchType.GALLERY_SEARCH);
}
runGallerySearchTask(); if(!emptySearch) {
this.showAllGalleryItems();
}
Log_OC.d(this, "End gallery search");
} }
@Override @Override
@ -282,7 +271,7 @@ public class GalleryFragment extends OCFileListFragment implements GalleryFragme
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection // Handle item selection
if (item.getItemId() == R.id.action_three_dot_icon && !photoSearchQueryRunning if (item.getItemId() == R.id.action_three_dot_icon && !this.isPhotoSearchQueryRunning()
&& galleryFragmentBottomSheetDialog != null) { && galleryFragmentBottomSheetDialog != null) {
showBottomSheet(); showBottomSheet();
return true; return true;
@ -309,7 +298,9 @@ public class GalleryFragment extends OCFileListFragment implements GalleryFragme
} }
private void searchAndDisplayAfterChangingFolder() { private void searchAndDisplayAfterChangingFolder() {
mAdapter.clear(); //TODO: Fix folder change, it seems it doesn't work at all
this.endDate = System.currentTimeMillis() / 1000;
this.setPhotoSearchQueryRunning(true);
runGallerySearchTask(); runGallerySearchTask();
} }
@ -318,46 +309,51 @@ public class GalleryFragment extends OCFileListFragment implements GalleryFragme
photoSearchTask = new GallerySearchTask(this, photoSearchTask = new GallerySearchTask(this,
accountManager.getUser(), accountManager.getUser(),
mContainerActivity.getStorageManager(), mContainerActivity.getStorageManager(),
startDate,
endDate, endDate,
limit) limit)
.execute(); .execute();
} }
} }
@Override
public boolean isLoading() {
return photoSearchQueryRunning;
}
private void loadMoreWhenEndReached(@NonNull RecyclerView recyclerView, int dy) { private void loadMoreWhenEndReached(@NonNull RecyclerView recyclerView, int dy) {
if (recyclerView.getLayoutManager() instanceof GridLayoutManager) { if (recyclerView.getLayoutManager() instanceof GridLayoutManager) {
GridLayoutManager gridLayoutManager = (GridLayoutManager) recyclerView.getLayoutManager(); GridLayoutManager gridLayoutManager = (GridLayoutManager) recyclerView.getLayoutManager();
// scroll down // scroll down
if (dy > 0 && !photoSearchQueryRunning) { if (dy > 0 && !this.isPhotoSearchQueryRunning()) {
int visibleItemCount = gridLayoutManager.getChildCount();
int totalItemCount = gridLayoutManager.getItemCount(); int totalItemCount = gridLayoutManager.getItemCount();
int lastVisibleItem = gridLayoutManager.findLastCompletelyVisibleItemPosition(); int lastVisibleItem = gridLayoutManager.findLastCompletelyVisibleItemPosition();
int visibleItemCount = gridLayoutManager.getChildCount();
if (lastVisibleItem == RecyclerView.NO_POSITION) { if (lastVisibleItem == RecyclerView.NO_POSITION) {
return; return;
} }
if ((totalItemCount - visibleItemCount) <= (lastVisibleItem + MAX_ITEMS_PER_ROW)
&& (totalItemCount - visibleItemCount) > 0) {
// Almost reached the end, continue to load new photos
OCFile lastFile = mAdapter.getItem(lastVisibleItem - 1); OCFile lastFile = mAdapter.getItem(lastVisibleItem - 1);
if (lastFile == null) { if (lastFile == null) {
return; return;
} }
long lastItemTimestamp = lastFile.getModificationTimestamp() / 1000;
daySpan = 30; // if we have already older media in the gallery then retrieve file in chronological order to fill the gap
endDate = lastFile.getModificationTimestamp() / 1000; if (lastItemTimestamp < this.endDate) {
startDate = endDate - (daySpan * 24 * 60 * 60);
photoSearchQueryRunning = true; if (BuildConfig.DEBUG) {
Log_OC.d(this, "Gallery swipe: retrieve items to check the chronology");
}
this.setPhotoSearchQueryRunning(true);
runGallerySearchTask();
} else if ((totalItemCount - visibleItemCount) <= (lastVisibleItem + MAX_ITEMS_PER_ROW) //no more files in the gallery, retrieve the next ones
&& (totalItemCount - visibleItemCount) > 0) {
if (BuildConfig.DEBUG) {
Log_OC.d(this, "Gallery swipe: retrieve items because end of gallery display");
}
// Almost reached the end, continue to load new photos
endDate = lastItemTimestamp;
this.setPhotoSearchQueryRunning(true);
runGallerySearchTask(); runGallerySearchTask();
} }
} }