Merge remote-tracking branch 'origin/master' into dev

This commit is contained in:
Tobias Kaminsky 2023-12-15 03:34:15 +01:00
commit ef86b65793
8 changed files with 181 additions and 146 deletions

View file

@ -260,24 +260,6 @@ public final class ThumbnailsCacheManager {
return null;
}
public static class GalleryImageGenerationTaskObject {
private final OCFile file;
private final String imageKey;
public GalleryImageGenerationTaskObject(OCFile file, String imageKey) {
this.file = file;
this.imageKey = imageKey;
}
private OCFile getFile() {
return file;
}
private String getImageKey() {
return imageKey;
}
}
public static class GalleryImageGenerationTask extends AsyncTask<Object, Void, Bitmap> {
private final User user;
private final FileDataStorageManager storageManager;

View file

@ -171,7 +171,6 @@ public class FileDisplayActivity extends FileActivity implements FileFragment.Co
public static final String RESTART = "RESTART";
public static final String ALL_FILES = "ALL_FILES";
public static final String LIST_GROUPFOLDERS = "LIST_GROUPFOLDERS";
public static final String PHOTO_SEARCH = "PHOTO_SEARCH";
public static final int SINGLE_USER_SIZE = 1;
public static final String OPEN_FILE = "NC_OPEN_FILE";
@ -205,7 +204,6 @@ public class FileDisplayActivity extends FileActivity implements FileFragment.Co
public static final int REQUEST_CODE__SELECT_FILES_FROM_FILE_SYSTEM = REQUEST_CODE__LAST_SHARED + 2;
public static final int REQUEST_CODE__MOVE_OR_COPY_FILES = REQUEST_CODE__LAST_SHARED + 3;
public static final int REQUEST_CODE__UPLOAD_FROM_CAMERA = REQUEST_CODE__LAST_SHARED + 5;
public static final int REQUEST_CODE__UPLOAD_SCAN_DOC_FROM_CAMERA = REQUEST_CODE__LAST_SHARED + 6;
protected static final long DELAY_TO_REQUEST_REFRESH_OPERATION_LATER = DELAY_TO_REQUEST_OPERATIONS_LATER + 350;
@ -254,6 +252,7 @@ public class FileDisplayActivity extends FileActivity implements FileFragment.Co
@Override
protected void onCreate(Bundle savedInstanceState) {
Log_OC.v(TAG, "onCreate() start");
// Set the default theme to replace the launch screen theme.
setTheme(R.style.Theme_ownCloud_Toolbar_Drawer);
@ -611,6 +610,28 @@ public class FileDisplayActivity extends FileActivity implements FileFragment.Co
transaction.commit();
}
private OCFileListFragment getOCFileListFragmentFromFile() {
final Fragment leftFragment = getLeftFragment();
OCFileListFragment listOfFiles = null;
if (leftFragment instanceof OCFileListFragment) {
listOfFiles = (OCFileListFragment) leftFragment;
} else {
listOfFiles = new OCFileListFragment();
Bundle args = new Bundle();
args.putBoolean(OCFileListFragment.ARG_ALLOW_CONTEXTUAL_ACTIONS, true);
listOfFiles.setArguments(args);
setLeftFragment(listOfFiles);
getSupportFragmentManager().executePendingTransactions();
}
return listOfFiles;
}
public void showFileActions(OCFile file) {
dismissLoadingDialog();
OCFileListFragment listOfFiles = getOCFileListFragmentFromFile();
browseUp(listOfFiles);
listOfFiles.onOverflowIconClicked(file, null);
}
public @androidx.annotation.Nullable Fragment getLeftFragment() {
return getSupportFragmentManager().findFragmentByTag(FileDisplayActivity.TAG_LIST_OF_FILES);
@ -626,7 +647,6 @@ public class FileDisplayActivity extends FileActivity implements FileFragment.Co
return null;
}
protected void resetTitleBarAndScrolling() {
updateActionBarTitleAndHomeButton(null);
resetScrolling(true);
@ -782,6 +802,7 @@ public class FileDisplayActivity extends FileActivity implements FileFragment.Co
@Override
public boolean onOptionsItemSelected(MenuItem item) {
boolean retval = true;
int itemId = item.getItemId();
if (itemId == android.R.id.home) {
@ -876,24 +897,11 @@ public class FileDisplayActivity extends FileActivity implements FileFragment.Co
remotePaths[j] = remotePathBase + relativePath;
}
int behaviour;
switch (resultCode) {
case UploadFilesActivity.RESULT_OK_AND_MOVE:
behaviour = FileUploader.LOCAL_BEHAVIOUR_MOVE;
break;
case UploadFilesActivity.RESULT_OK_AND_DELETE:
behaviour = FileUploader.LOCAL_BEHAVIOUR_DELETE;
break;
case UploadFilesActivity.RESULT_OK_AND_DO_NOTHING:
behaviour = FileUploader.LOCAL_BEHAVIOUR_FORGET;
break;
default:
behaviour = FileUploader.LOCAL_BEHAVIOUR_FORGET;
break;
}
int behaviour = switch (resultCode) {
case UploadFilesActivity.RESULT_OK_AND_MOVE -> FileUploader.LOCAL_BEHAVIOUR_MOVE;
case UploadFilesActivity.RESULT_OK_AND_DELETE -> FileUploader.LOCAL_BEHAVIOUR_DELETE;
default -> FileUploader.LOCAL_BEHAVIOUR_FORGET;
};
FileUploader.uploadNewFile(this, getUser().orElseThrow(RuntimeException::new), filePaths, remotePaths, null, // MIME type will be detected from file name
behaviour, true, UploadFileOperation.CREATED_BY_USER, false, false, NameCollisionPolicy.ASK_USER);
@ -940,6 +948,11 @@ public class FileDisplayActivity extends FileActivity implements FileFragment.Co
}
}
private Boolean isRootDirectory() {
OCFile currentDir = getCurrentDir();
return (currentDir == null || currentDir.getParentId() == FileDataStorageManager.ROOT_PARENT_ID);
}
/*
* BackPressed priority/hierarchy:
* 1. close search view if opened
@ -959,8 +972,7 @@ public class FileDisplayActivity extends FileActivity implements FileFragment.Co
resetSearchAction();
} else if (isDrawerOpen) {
super.onBackPressed();
} else if (leftFragment instanceof OCFileListFragment) {
OCFileListFragment listOfFiles = (OCFileListFragment) leftFragment;
} else if (leftFragment instanceof OCFileListFragment listOfFiles) {
// all closed
OCFile currentDir = getCurrentDir();
@ -974,18 +986,6 @@ public class FileDisplayActivity extends FileActivity implements FileFragment.Co
}
}
/**
* Use this method when want to pop the fragment on back press. It resets Scrolling (See
* {@link #resetScrolling(boolean) with true} and pop the visibility for sortListGroup (See
* {@link #setSortListGroup(boolean, boolean)}. At last call to super.onBackPressed()
*/
private void popBack() {
// pop back fragment
resetScrolling(true);
popSortListGroupVisibility();
super.onBackPressed();
}
private void browseUp(OCFileListFragment listOfFiles) {
listOfFiles.onBrowseUp();
setFile(listOfFiles.getCurrentFile());
@ -995,9 +995,6 @@ public class FileDisplayActivity extends FileActivity implements FileFragment.Co
setDrawerAllFiles();
}
/**
* It resets the Search Action (call when search is open)
*/
private void resetSearchAction() {
Fragment leftFragment = getLeftFragment();
if (isSearchOpen() && searchView != null) {
@ -1005,8 +1002,7 @@ public class FileDisplayActivity extends FileActivity implements FileFragment.Co
searchView.onActionViewCollapsed();
searchView.clearFocus();
if (isRoot(getCurrentDir()) && leftFragment instanceof OCFileListFragment) {
OCFileListFragment listOfFiles = (OCFileListFragment) leftFragment;
if (isRoot(getCurrentDir()) && leftFragment instanceof OCFileListFragment listOfFiles) {
// Remove the list to the original state
ArrayList<String> listOfHiddenFiles = listOfFiles.getAdapter().listOfHiddenFiles;
@ -1022,6 +1018,18 @@ public class FileDisplayActivity extends FileActivity implements FileFragment.Co
}
}
/**
* Use this method when want to pop the fragment on back press. It resets Scrolling (See
* {@link #resetScrolling(boolean) with true} and pop the visibility for sortListGroup (See
* {@link #setSortListGroup(boolean, boolean)}. At last call to super.onBackPressed()
*/
private void popBack() {
// pop back fragment
resetScrolling(true);
popSortListGroupVisibility();
super.onBackPressed();
}
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
// responsibility of restore is preferred in onCreate() before than in
@ -1369,7 +1377,7 @@ public class FileDisplayActivity extends FileActivity implements FileFragment.Co
if (uploadWasFine) {
OCFile ocFile = getFile();
if (PreviewImageFragment.canBePreviewed(ocFile)) {
startImagePreview(getFile(), true);
startImagePreview(getFile(),true);
} else if (PreviewTextFileFragment.canBePreviewed(ocFile)) {
startTextPreview(ocFile, true);
}
@ -1979,11 +1987,6 @@ public class FileDisplayActivity extends FileActivity implements FileFragment.Co
requestForDownload(mWaitingToSend, downloadBehaviour, packageName, activityName);
}
/**
* Opens the image gallery showing the image {@link OCFile} received as parameter.
*
* @param file Image {@link OCFile} to show.
*/
public void startImagePreview(OCFile file, boolean showPreview) {
Intent showDetailsIntent = new Intent(this, PreviewImageActivity.class);
showDetailsIntent.putExtra(EXTRA_FILE, file);
@ -1997,22 +2000,20 @@ public class FileDisplayActivity extends FileActivity implements FileFragment.Co
}
}
/**
* Opens the image gallery showing the image {@link OCFile} received as parameter.
*
* @param file Image {@link OCFile} to show.
*/
public void startImagePreview(OCFile file, VirtualFolderType type, boolean showPreview) {
Intent showDetailsIntent = new Intent(this, PreviewImageActivity.class);
showDetailsIntent.putExtra(PreviewImageActivity.EXTRA_FILE, file);
showDetailsIntent.putExtra(EXTRA_LIVE_PHOTO_FILE, file.livePhotoVideo);
showDetailsIntent.putExtra(EXTRA_USER, getUser().orElseThrow(RuntimeException::new));
showDetailsIntent.putExtra(PreviewImageActivity.EXTRA_VIRTUAL_TYPE, type);
if (showPreview) {
startActivity(showDetailsIntent);
} else {
FileOperationsHelper fileOperationsHelper = new FileOperationsHelper(this, getUserAccountManager(), connectivityService, editorUtils);
FileOperationsHelper fileOperationsHelper = new FileOperationsHelper(this,
getUserAccountManager(),
connectivityService,
editorUtils);
fileOperationsHelper.startSyncForFileAndIntent(file, showDetailsIntent);
}
}
@ -2441,21 +2442,10 @@ public class FileDisplayActivity extends FileActivity implements FileFragment.Co
binding.fabMain.setVisibility(visibility);
}
public void showFile(String message) {
public void showFile(OCFile selectedFile, String message) {
dismissLoadingDialog();
final Fragment leftFragment = getLeftFragment();
OCFileListFragment listOfFiles = null;
if (leftFragment instanceof OCFileListFragment) {
listOfFiles = (OCFileListFragment) leftFragment;
} else {
listOfFiles = new OCFileListFragment();
Bundle args = new Bundle();
args.putBoolean(OCFileListFragment.ARG_ALLOW_CONTEXTUAL_ACTIONS, true);
listOfFiles.setArguments(args);
setLeftFragment(listOfFiles);
getSupportFragmentManager().executePendingTransactions();
}
OCFileListFragment listOfFiles = getOCFileListFragmentFromFile();
if (TextUtils.isEmpty(message)) {
OCFile temp = getFile();
@ -2465,6 +2455,10 @@ public class FileDisplayActivity extends FileActivity implements FileFragment.Co
} else {
DisplayUtils.showSnackMessage(listOfFiles.getView(), message);
}
if (selectedFile != null) {
listOfFiles.onItemClicked(selectedFile);
}
}
/**

View file

@ -89,6 +89,7 @@ import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.UUID;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -134,6 +135,9 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
private final ViewThemeUtils viewThemeUtils;
private SearchType searchType;
private final long footerId = UUID.randomUUID().getLeastSignificantBits();
private final long headerId = UUID.randomUUID().getLeastSignificantBits();
public OCFileListAdapter(
Activity activity,
@NonNull User user,
@ -289,21 +293,67 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
new Handler(Looper.getMainLooper()).post(this::notifyDataSetChanged);
}
@Override
public long getItemId(int position) {
if (mFiles == null || mFiles.size() <= position) {
return 0;
if (shouldShowHeader()) {
if (position == 0) {
return headerId;
}
// skip header
position--;
}
return mFiles.get(position).getFileId();
if (position == mFiles.size()) {
return footerId;
} if (position < mFiles.size()) {
return mFiles.get(position).getFileId();
}
// fallback
return RecyclerView.NO_ID;
}
@Override
public int getItemCount() {
if (shouldShowHeader()) {
return mFiles.size() + 2; // for header and footer
return mFiles.size() + (shouldShowHeader() ? 2 : 1);
}
@Nullable
public OCFile getItem(int position) {
int newPosition = position;
if (shouldShowHeader() && position > 0) {
newPosition = position - 1;
}
if (newPosition >= mFiles.size()) {
return null;
}
return mFiles.get(newPosition);
}
@Override
public int getItemViewType(int position) {
if (shouldShowHeader() && position == 0) {
return VIEWTYPE_HEADER;
}
if (shouldShowHeader() && position == mFiles.size() + 1 ||
(!shouldShowHeader() && position == mFiles.size())) {
return VIEWTYPE_FOOTER;
}
OCFile item = getItem(position);
if (item == null) {
return VIEWTYPE_ITEM;
}
if (MimeTypeUtil.isImageOrVideo(item)) {
return VIEWTYPE_IMAGE;
} else {
return mFiles.size() + 1; // for footer
return VIEWTYPE_ITEM;
}
}
@ -607,21 +657,6 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
return output;
}
public @Nullable
OCFile getItem(int position) {
int newPosition = position;
if (shouldShowHeader() && position > 0) {
newPosition = position - 1;
}
if (newPosition >= mFiles.size()) {
return null;
}
return mFiles.get(newPosition);
}
public boolean shouldShowHeader() {
if (currentDirectory == null) {
return false;
@ -638,34 +673,6 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
return !TextUtils.isEmpty(currentDirectory.getRichWorkspace().trim());
}
@Override
public int getItemViewType(int position) {
if (shouldShowHeader()) {
if (position == 0) {
return VIEWTYPE_HEADER;
} else {
if (position == mFiles.size() + 1) {
return VIEWTYPE_FOOTER;
}
}
} else {
if (position == mFiles.size()) {
return VIEWTYPE_FOOTER;
}
}
OCFile item = getItem(position);
if (item == null) {
return VIEWTYPE_ITEM;
}
if (MimeTypeUtil.isImageOrVideo(item)) {
return VIEWTYPE_IMAGE;
} else {
return VIEWTYPE_ITEM;
}
}
/**
* Change the adapted directory for a new one
*
@ -678,7 +685,8 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
@NonNull User account,
@NonNull OCFile directory,
@NonNull FileDataStorageManager updatedStorageManager,
boolean onlyOnDevice, @NonNull String limitToMimeType) {
boolean onlyOnDevice,
@NonNull String limitToMimeType) {
this.onlyOnDevice = onlyOnDevice;
if (!updatedStorageManager.equals(mStorageManager)) {

View file

@ -49,11 +49,16 @@ class UnifiedSearchItemViewHolder(
val clientFactory: ClientFactory,
private val storageManager: FileDataStorageManager,
private val listInterface: UnifiedSearchListInterface,
private val filesAction: FilesAction,
val context: Context,
private val viewThemeUtils: ViewThemeUtils
) :
SectionedViewHolder(binding.root) {
interface FilesAction {
fun showFilesAction(searchResultEntry: SearchResultEntry)
}
fun bind(entry: SearchResultEntry) {
binding.title.text = entry.title
binding.subline.text = entry.subline
@ -77,6 +82,13 @@ class UnifiedSearchItemViewHolder(
.listener(RoundIfNeededListener(entry))
.into(binding.thumbnail)
if (entry.isFile) {
binding.more.visibility = View.VISIBLE
binding.more.setOnClickListener { filesAction.showFilesAction(entry) }
} else {
binding.more.visibility = View.GONE
}
binding.unifiedSearchItemLayout.setOnClickListener { listInterface.onSearchResultClicked(entry) }
}

View file

@ -50,6 +50,7 @@ import com.owncloud.android.utils.theme.ViewThemeUtils
class UnifiedSearchListAdapter(
private val storageManager: FileDataStorageManager,
private val listInterface: UnifiedSearchListInterface,
private val filesAction: UnifiedSearchItemViewHolder.FilesAction,
private val user: User,
private val clientFactory: ClientFactory,
private val context: Context,
@ -92,6 +93,7 @@ class UnifiedSearchListAdapter(
clientFactory,
storageManager,
listInterface,
filesAction,
context,
viewThemeUtils
)

View file

@ -43,6 +43,7 @@ public class FetchRemoteFileTask extends AsyncTask<Void, Void, String> {
private final String fileId;
private final FileDataStorageManager storageManager;
private final FileDisplayActivity fileDisplayActivity;
private OCFile ocFile;
public FetchRemoteFileTask(User user,
String fileId,
@ -84,7 +85,7 @@ public class FetchRemoteFileTask extends AsyncTask<Void, Void, String> {
RemoteFile remoteFile = (RemoteFile) result.getData().get(0);
OCFile ocFile = FileStorageUtils.fillOCFile(remoteFile);
ocFile = FileStorageUtils.fillOCFile(remoteFile);
FileStorageUtils.searchForLocalFileInDefaultPath(ocFile, user.getAccountName());
ocFile = storageManager.saveFileWithParent(ocFile, fileDisplayActivity);
@ -118,6 +119,6 @@ public class FetchRemoteFileTask extends AsyncTask<Void, Void, String> {
protected void onPostExecute(String message) {
super.onPostExecute(message);
fileDisplayActivity.showFile(message);
fileDisplayActivity.showFile(ocFile, message);
}
}

View file

@ -47,6 +47,7 @@ import com.owncloud.android.datamodel.OCFile
import com.owncloud.android.lib.common.SearchResultEntry
import com.owncloud.android.lib.common.utils.Log_OC
import com.owncloud.android.ui.activity.FileDisplayActivity
import com.owncloud.android.ui.adapter.UnifiedSearchItemViewHolder
import com.owncloud.android.ui.adapter.UnifiedSearchListAdapter
import com.owncloud.android.ui.fragment.util.PairMediatorLiveData
import com.owncloud.android.ui.interfaces.UnifiedSearchListInterface
@ -63,7 +64,12 @@ import javax.inject.Inject
* Starts query to all capable unified search providers and displays them Opens result in our app, redirect to other
* apps, if installed, or opens browser
*/
class UnifiedSearchFragment : Fragment(), Injectable, UnifiedSearchListInterface, SearchView.OnQueryTextListener {
class UnifiedSearchFragment :
Fragment(),
Injectable,
UnifiedSearchListInterface,
SearchView.OnQueryTextListener,
UnifiedSearchItemViewHolder.FilesAction {
private lateinit var adapter: UnifiedSearchListAdapter
private var _binding: ListFragmentBinding? = null
private val binding get() = _binding!!
@ -106,6 +112,8 @@ class UnifiedSearchFragment : Fragment(), Injectable, UnifiedSearchListInterface
private var listOfHiddenFiles = ArrayList<String>()
private var showMoreActions = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
vm = ViewModelProvider(this, vmFactory)[UnifiedSearchViewModel::class.java]
@ -200,7 +208,7 @@ class UnifiedSearchFragment : Fragment(), Injectable, UnifiedSearchListInterface
startActivity(browserIntent)
}
vm.file.observe(this) {
showFile(it)
showFile(it, showMoreActions)
}
}
@ -210,6 +218,21 @@ class UnifiedSearchFragment : Fragment(), Injectable, UnifiedSearchListInterface
}
}
private fun showFile(file: OCFile, showFileActions: Boolean) {
activity.let {
if (activity is FileDisplayActivity) {
val fda = activity as FileDisplayActivity
fda.file = file
if (showFileActions) {
fda.showFileActions(file)
} else {
fda.showFile(file, "")
}
}
}
}
private fun setupFileDisplayActivity() {
(activity as? FileDisplayActivity)?.run {
setMainFabVisible(false)
@ -222,6 +245,7 @@ class UnifiedSearchFragment : Fragment(), Injectable, UnifiedSearchListInterface
adapter = UnifiedSearchListAdapter(
storageManager,
this,
this,
currentAccountProvider.user,
clientFactory,
requireContext(),
@ -233,14 +257,8 @@ class UnifiedSearchFragment : Fragment(), Injectable, UnifiedSearchListInterface
binding.listRoot.adapter = adapter
}
private fun showFile(file: OCFile) {
(activity as? FileDisplayActivity)?.let {
it.file = file
it.showFile("")
}
}
override fun onSearchResultClicked(searchResultEntry: SearchResultEntry) {
showMoreActions = false
vm.openResult(searchResultEntry)
}
@ -277,4 +295,9 @@ class UnifiedSearchFragment : Fragment(), Injectable, UnifiedSearchListInterface
super.onDestroyView()
_binding = null
}
override fun showFilesAction(searchResultEntry: SearchResultEntry) {
showMoreActions = true
vm.openResult(searchResultEntry)
}
}

View file

@ -107,5 +107,18 @@
tools:text="in TestFolder" />
</LinearLayout>
<ImageButton
android:id="@+id/more"
android:visibility="gone"
android:background="@color/transparent"
app:srcCompat="@drawable/ic_dots_vertical"
app:tint="@color/standard_grey"
android:layout_gravity="center"
android:layout_width="50dp"
android:layout_height="50dp"
android:contentDescription="@string/overflow_menu"
tools:visibility="visible" />
</LinearLayout>