diff --git a/app/build.gradle b/app/build.gradle index 889227461c..6c56f0ccca 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -126,6 +126,10 @@ android { } } + buildFeatures { + buildConfig = true + } + productFlavors { // used for f-droid generic { diff --git a/app/src/main/java/com/nextcloud/client/widget/DashboardWidgetService.kt b/app/src/main/java/com/nextcloud/client/widget/DashboardWidgetService.kt index 29805dbe47..e92471b442 100644 --- a/app/src/main/java/com/nextcloud/client/widget/DashboardWidgetService.kt +++ b/app/src/main/java/com/nextcloud/client/widget/DashboardWidgetService.kt @@ -86,7 +86,7 @@ class StackRemoteViewsFactory( val userAccountManager: UserAccountManager, val clientFactory: ClientFactory, val intent: Intent, - val widgetRepository: WidgetRepository + private val widgetRepository: WidgetRepository ) : RemoteViewsService.RemoteViewsFactory { private lateinit var widgetConfiguration: WidgetConfiguration @@ -163,58 +163,20 @@ class StackRemoteViewsFactory( // we will switch soon to coil and then streamline all of this // Kotlin cannot catch multiple exception types at same time - @Suppress("NestedBlockDepth", "TooGenericExceptionCaught") + @Suppress("NestedBlockDepth") private fun createItemView(position: Int): RemoteViews { return RemoteViews(context.packageName, R.layout.widget_item).apply { + if (widgetItems.isEmpty()) { + return@apply + } + val widgetItem = widgetItems[position] - // icon bitmap/svg if (widgetItem.iconUrl.isNotEmpty()) { - val glide: FutureTarget - if (Uri.parse(widgetItem.iconUrl).encodedPath!!.endsWith(".svg")) { - glide = Glide.with(context) - .using( - CustomGlideUriLoader(userAccountManager.user, clientFactory), - InputStream::class.java - ) - .from(Uri::class.java) - .`as`(SVGorImage::class.java) - .transcode(SvgOrImageBitmapTranscoder(SVG_SIZE, SVG_SIZE), Bitmap::class.java) - .sourceEncoder(StreamEncoder()) - .cacheDecoder(FileToStreamDecoder(SvgOrImageDecoder())) - .decoder(SvgOrImageDecoder()) - .diskCacheStrategy(DiskCacheStrategy.SOURCE) - .load(Uri.parse(widgetItem.iconUrl)) - .into(SVG_SIZE, SVG_SIZE) - } else { - glide = Glide.with(context) - .using(CustomGlideStreamLoader(widgetConfiguration.user.get(), clientFactory)) - .load(widgetItem.iconUrl) - .asBitmap() - .into(SVG_SIZE, SVG_SIZE) - } - - try { - if (widgetConfiguration.roundIcon) { - setImageViewBitmap(R.id.icon, BitmapUtils.roundBitmap(glide.get())) - } else { - setImageViewBitmap(R.id.icon, glide.get()) - } - } catch (e: Exception) { - Log_OC.d(TAG, "Error setting icon", e) - setImageViewResource(R.id.icon, R.drawable.ic_dashboard) - } + loadIcon(widgetItem, this) } - // text - setTextViewText(R.id.title, widgetItem.title) - - if (widgetItem.subtitle.isNotEmpty()) { - setViewVisibility(R.id.subtitle, View.VISIBLE) - setTextViewText(R.id.subtitle, widgetItem.subtitle) - } else { - setViewVisibility(R.id.subtitle, View.GONE) - } + updateTexts(widgetItem, this) if (widgetItem.link.isNotEmpty()) { val clickIntent = Intent(Intent.ACTION_VIEW, Uri.parse(widgetItem.link)) @@ -223,6 +185,65 @@ class StackRemoteViewsFactory( } } + @Suppress("TooGenericExceptionCaught") + private fun loadIcon(widgetItem: DashboardWidgetItem, remoteViews: RemoteViews) { + val isIconSVG = Uri.parse(widgetItem.iconUrl).encodedPath!!.endsWith(".svg") + val source: FutureTarget = if (isIconSVG) { + loadSVGIcon(widgetItem) + } else { + loadBitmapIcon(widgetItem) + } + + try { + val bitmap: Bitmap = if (widgetConfiguration.roundIcon) { + BitmapUtils.roundBitmap(source.get()) + } else { + source.get() + } + + remoteViews.setImageViewBitmap(R.id.icon, bitmap) + } catch (e: Exception) { + Log_OC.d(TAG, "Error setting icon", e) + remoteViews.setImageViewResource(R.id.icon, R.drawable.ic_dashboard) + } + } + + private fun loadSVGIcon(widgetItem: DashboardWidgetItem): FutureTarget { + return Glide.with(context) + .using( + CustomGlideUriLoader(userAccountManager.user, clientFactory), + InputStream::class.java + ) + .from(Uri::class.java) + .`as`(SVGorImage::class.java) + .transcode(SvgOrImageBitmapTranscoder(SVG_SIZE, SVG_SIZE), Bitmap::class.java) + .sourceEncoder(StreamEncoder()) + .cacheDecoder(FileToStreamDecoder(SvgOrImageDecoder())) + .decoder(SvgOrImageDecoder()) + .diskCacheStrategy(DiskCacheStrategy.SOURCE) + .load(Uri.parse(widgetItem.iconUrl)) + .into(SVG_SIZE, SVG_SIZE) + } + + private fun loadBitmapIcon(widgetItem: DashboardWidgetItem): FutureTarget { + return Glide.with(context) + .using(CustomGlideStreamLoader(widgetConfiguration.user.get(), clientFactory)) + .load(widgetItem.iconUrl) + .asBitmap() + .into(SVG_SIZE, SVG_SIZE) + } + + private fun updateTexts(widgetItem: DashboardWidgetItem, remoteViews: RemoteViews) { + remoteViews.setTextViewText(R.id.title, widgetItem.title) + + if (widgetItem.subtitle.isNotEmpty()) { + remoteViews.setViewVisibility(R.id.subtitle, View.VISIBLE) + remoteViews.setTextViewText(R.id.subtitle, widgetItem.subtitle) + } else { + remoteViews.setViewVisibility(R.id.subtitle, View.GONE) + } + } + override fun getLoadingView(): RemoteViews? { return null } diff --git a/app/src/main/java/com/owncloud/android/db/UploadResult.java b/app/src/main/java/com/owncloud/android/db/UploadResult.java index 34a6d99d02..17533f0413 100644 --- a/app/src/main/java/com/owncloud/android/db/UploadResult.java +++ b/app/src/main/java/com/owncloud/android/db/UploadResult.java @@ -44,7 +44,8 @@ public enum UploadResult { OLD_ANDROID_API(18), SYNC_CONFLICT(19), CANNOT_CREATE_FILE(20), - LOCAL_STORAGE_NOT_COPIED(21); + LOCAL_STORAGE_NOT_COPIED(21), + QUOTA_EXCEEDED(22); private final int value; @@ -104,6 +105,8 @@ public enum UploadResult { return CANNOT_CREATE_FILE; case 21: return LOCAL_STORAGE_NOT_COPIED; + case 22: + return QUOTA_EXCEEDED; } return UNKNOWN; } @@ -162,6 +165,8 @@ public enum UploadResult { return VIRUS_DETECTED; case CANNOT_CREATE_FILE: return CANNOT_CREATE_FILE; + case QUOTA_EXCEEDED: + return QUOTA_EXCEEDED; default: return UNKNOWN; } diff --git a/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java b/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java index c7b80930bb..288436788f 100644 --- a/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java +++ b/app/src/main/java/com/owncloud/android/files/services/FileDownloader.java @@ -83,6 +83,7 @@ import java.util.Vector; import javax.inject.Inject; import androidx.core.app.NotificationCompat; +import androidx.core.app.ServiceCompat; import androidx.localbroadcastmanager.content.LocalBroadcastManager; import dagger.android.AndroidInjection; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; @@ -203,7 +204,11 @@ public class FileDownloader extends Service Log_OC.d(TAG, "Starting command with id " + startId); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - startForeground(FOREGROUND_SERVICE_ID, mNotification, ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC); + ServiceCompat.startForeground( + this, + FOREGROUND_SERVICE_ID, + mNotification, + ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC); } else { startForeground(FOREGROUND_SERVICE_ID, mNotification); } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 16478cd5b6..5b0908e037 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -350,14 +350,18 @@ public class FileDisplayActivity extends FileActivity public void onConfigurationChanged(@NonNull Configuration newConfig) { super.onConfigurationChanged(newConfig); - StoragePermissionDialogFragment fragment = (StoragePermissionDialogFragment) getSupportFragmentManager().findFragmentByTag(PERMISSION_CHOICE_DIALOG_TAG); - if (fragment != null) { - Dialog dialog = fragment.getDialog(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + StoragePermissionDialogFragment fragment = + (StoragePermissionDialogFragment) getSupportFragmentManager() + .findFragmentByTag(PERMISSION_CHOICE_DIALOG_TAG); + if (fragment != null) { + Dialog dialog = fragment.getDialog(); - if (dialog != null && dialog.isShowing()) { - dialog.dismiss(); - getSupportFragmentManager().beginTransaction().remove(fragment).commitNowAllowingStateLoss(); - PermissionUtil.requestExternalStoragePermission(this, viewThemeUtils); + if (dialog != null && dialog.isShowing()) { + dialog.dismiss(); + getSupportFragmentManager().beginTransaction().remove(fragment).commitNowAllowingStateLoss(); + PermissionUtil.requestExternalStoragePermission(this, viewThemeUtils); + } } } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java index aaf6f6bb4c..2cda4d2de0 100755 --- a/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java @@ -41,10 +41,21 @@ import android.os.Looper; import android.os.Parcelable; import android.text.TextUtils; import android.text.format.DateFormat; -import android.view.*; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; import android.view.WindowManager.LayoutParams; -import android.widget.*; +import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; +import android.widget.ArrayAdapter; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.Spinner; +import android.widget.TextView; +import android.widget.Toast; import com.google.android.material.button.MaterialButton; import com.nextcloud.client.account.User; @@ -66,13 +77,21 @@ import com.owncloud.android.operations.CreateFolderOperation; import com.owncloud.android.operations.RefreshFolderOperation; import com.owncloud.android.operations.UploadFileOperation; import com.owncloud.android.syncadapter.FileSyncAdapter; -import com.owncloud.android.ui.adapter.UploaderAdapter; +import com.owncloud.android.ui.adapter.ReceiveExternalFilesAdapter; import com.owncloud.android.ui.asynctasks.CopyAndUploadContentUrisTask; -import com.owncloud.android.ui.dialog.*; +import com.owncloud.android.ui.dialog.AccountChooserInterface; +import com.owncloud.android.ui.dialog.ConfirmationDialogFragment; +import com.owncloud.android.ui.dialog.CreateFolderDialogFragment; +import com.owncloud.android.ui.dialog.MultipleAccountsDialog; +import com.owncloud.android.ui.dialog.SortingOrderDialogFragment; import com.owncloud.android.ui.fragment.TaskRetainerFragment; import com.owncloud.android.ui.helpers.FileOperationsHelper; import com.owncloud.android.ui.helpers.UriUploader; -import com.owncloud.android.utils.*; +import com.owncloud.android.utils.DataHolderUtil; +import com.owncloud.android.utils.DisplayUtils; +import com.owncloud.android.utils.ErrorMessageAdapter; +import com.owncloud.android.utils.FileSortOrder; +import com.owncloud.android.utils.MimeType; import com.owncloud.android.utils.theme.ViewThemeUtils; import java.io.File; @@ -80,7 +99,12 @@ import java.io.FileWriter; import java.io.IOException; import java.lang.reflect.Method; import java.nio.charset.Charset; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.List; +import java.util.Stack; +import java.util.Vector; import javax.inject.Inject; @@ -96,6 +120,7 @@ import androidx.core.view.MenuItemCompat; import androidx.fragment.app.DialogFragment; import androidx.fragment.app.FragmentManager; import androidx.localbroadcastmanager.content.LocalBroadcastManager; +import androidx.recyclerview.widget.LinearLayoutManager; import static com.owncloud.android.utils.DisplayUtils.openSortingOrderDialogFragment; @@ -103,8 +128,8 @@ import static com.owncloud.android.utils.DisplayUtils.openSortingOrderDialogFrag * This can be used to upload things to an ownCloud instance. */ public class ReceiveExternalFilesActivity extends FileActivity - implements OnItemClickListener, View.OnClickListener, CopyAndUploadContentUrisTask.OnCopyTmpFilesTaskListener, - SortingOrderDialogFragment.OnSortingOrderListener, Injectable, AccountChooserInterface { + implements View.OnClickListener, CopyAndUploadContentUrisTask.OnCopyTmpFilesTaskListener, + SortingOrderDialogFragment.OnSortingOrderListener, Injectable, AccountChooserInterface, ReceiveExternalFilesAdapter.OnItemClickListener { private static final String TAG = ReceiveExternalFilesActivity.class.getSimpleName(); @@ -125,6 +150,7 @@ public class ReceiveExternalFilesActivity extends FileActivity private OCFile mFile; private SyncBroadcastReceiver mSyncBroadcastReceiver; + private ReceiveExternalFilesAdapter receiveExternalFilesAdapter; private boolean mSyncInProgress; private final static int REQUEST_CODE__SETUP_ACCOUNT = REQUEST_CODE__LAST_SHARED + 1; @@ -273,6 +299,22 @@ public class ReceiveExternalFilesActivity extends FileActivity populateDirectoryList(); } + @Override + public void selectFile(OCFile file) { + if (file.isFolder()) { + if (file.isEncrypted() && + !FileOperationsHelper.isEndToEndEncryptionSetup(this, getUser().orElseThrow(IllegalAccessError::new))) { + DisplayUtils.showSnackMessage(this, R.string.e2e_not_yet_setup); + + return; + } + + startSyncFolderOperation(file); + mParents.push(file.getFileName()); + populateDirectoryList(); + } + } + public static class DialogNoAccount extends DialogFragment { @NonNull @Override @@ -611,39 +653,6 @@ public class ReceiveExternalFilesActivity extends FileActivity } } - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - // click on folder in the list - Log_OC.d(TAG, "on item click"); - List tmpFiles = getStorageManager().getFolderContent(mFile, false); - tmpFiles = sortFileList(tmpFiles); - - if (tmpFiles.isEmpty()) { - return; - } - // filter on dirtype - Vector files = new Vector<>(); - files.addAll(tmpFiles); - - if (files.size() < position) { - throw new IndexOutOfBoundsException("Incorrect item selected"); - } - OCFile ocFile = files.get(position); - if (ocFile.isFolder()) { - if (ocFile.isEncrypted() && - !FileOperationsHelper.isEndToEndEncryptionSetup(this, getUser().orElseThrow(IllegalAccessError::new))) { - DisplayUtils.showSnackMessage(this, R.string.e2e_not_yet_setup); - - return; - } - - OCFile folderToEnter = files.get(position); - startSyncFolderOperation(folderToEnter); - mParents.push(folderToEnter.getFileName()); - populateDirectoryList(); - } - } - @Override public void onClick(View v) { // click on button @@ -740,29 +749,10 @@ public class ReceiveExternalFilesActivity extends FileActivity binding.list.setVisibility(View.GONE); } else { mEmptyListContainer.setVisibility(View.GONE); - files = sortFileList(files); - - List> data = new LinkedList<>(); - for (OCFile f : files) { - Map h = new HashMap<>(); - h.put("dirname", f); - data.add(h); - } - - UploaderAdapter sa = new UploaderAdapter(this, - data, - R.layout.uploader_list_item_layout, - new String[]{"dirname"}, - new int[]{R.id.filename}, - getStorageManager(), - getUser().get(), - syncedFolderProvider, - viewThemeUtils); - - binding.list.setAdapter(sa); - binding.list.setVisibility(View.VISIBLE); + setupReceiveExternalFilesAdapter(files); } + MaterialButton btnChooseFolder = binding.uploaderChooseFolder; viewThemeUtils.material.colorMaterialButtonPrimaryFilled(btnChooseFolder); btnChooseFolder.setOnClickListener(this); @@ -774,8 +764,6 @@ public class ReceiveExternalFilesActivity extends FileActivity viewThemeUtils.material.colorMaterialButtonPrimaryOutlined(binding.uploaderCancel); binding.uploaderCancel.setOnClickListener(this); - binding.list.setOnItemClickListener(this); - sortButton = binding.toolbarLayout.sortButton; FileSortOrder sortOrder = preferences.getSortOrderByFolder(mFile); sortButton.setText(DisplayUtils.getSortOrderStringId(sortOrder)); @@ -783,6 +771,21 @@ public class ReceiveExternalFilesActivity extends FileActivity } } + private void setupReceiveExternalFilesAdapter(List files) { + receiveExternalFilesAdapter = new ReceiveExternalFilesAdapter(files, + this, + getUser().get(), + getStorageManager(), + viewThemeUtils, + syncedFolderProvider, + this); + + + binding.list.setLayoutManager(new LinearLayoutManager(this)); + binding.list.setAdapter(receiveExternalFilesAdapter); + binding.list.setVisibility(View.VISIBLE); + } + protected void setupEmptyList() { mEmptyListContainer = binding.emptyView.emptyListView; mEmptyListMessage = binding.emptyView.emptyListViewText; @@ -1016,19 +1019,35 @@ public class ReceiveExternalFilesActivity extends FileActivity menu.findItem(R.id.action_create_dir).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); } - // tint search event - final MenuItem searchMenuItem = menu.findItem(R.id.action_search); - SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchMenuItem); + setupSearchView(menu); MenuItem newFolderMenuItem = menu.findItem(R.id.action_create_dir); newFolderMenuItem.setEnabled(mFile.canWrite()); - // hacky as no default way is provided - viewThemeUtils.androidx.themeToolbarSearchView(searchView); - return true; } + private void setupSearchView(Menu menu) { + final MenuItem searchMenuItem = menu.findItem(R.id.action_search); + + SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchMenuItem); + searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { + @Override + public boolean onQueryTextSubmit(String query) { + receiveExternalFilesAdapter.filter(query); + return false; + } + + @Override + public boolean onQueryTextChange(String newText) { + receiveExternalFilesAdapter.filter(newText); + return false; + } + }); + + viewThemeUtils.androidx.themeToolbarSearchView(searchView); + } + @Override public boolean onOptionsItemSelected(MenuItem item) { boolean retval = true; diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java index 92478acdca..941b188a66 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java @@ -178,6 +178,8 @@ public class OCFileListAdapter extends RecyclerView.Adapter. + */ + +package com.owncloud.android.ui.adapter + +import android.annotation.SuppressLint +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.recyclerview.widget.RecyclerView +import com.nextcloud.client.account.User +import com.owncloud.android.databinding.UploaderListItemLayoutBinding +import com.owncloud.android.datamodel.FileDataStorageManager +import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.datamodel.SyncedFolderProvider +import com.owncloud.android.datamodel.ThumbnailsCacheManager +import com.owncloud.android.datamodel.ThumbnailsCacheManager.AsyncThumbnailDrawable +import com.owncloud.android.datamodel.ThumbnailsCacheManager.ThumbnailGenerationTask +import com.owncloud.android.datamodel.ThumbnailsCacheManager.ThumbnailGenerationTaskObject +import com.owncloud.android.utils.DisplayUtils +import com.owncloud.android.utils.MimeTypeUtil +import com.owncloud.android.utils.theme.ViewThemeUtils + +@Suppress("LongParameterList") +class ReceiveExternalFilesAdapter( + private val files: List, + private val context: Context, + private val user: User, + private val storageManager: FileDataStorageManager, + private val viewThemeUtils: ViewThemeUtils, + private val syncedFolderProvider: SyncedFolderProvider, + private val onItemClickListener: OnItemClickListener +) : RecyclerView.Adapter() { + + private var filteredFiles: List = files + + interface OnItemClickListener { + fun selectFile(file: OCFile) + } + + inner class ReceiveExternalViewHolder(val binding: UploaderListItemLayoutBinding) : + RecyclerView.ViewHolder(binding.root) { + init { + binding.root.setOnClickListener { + val position = bindingAdapterPosition + if (position != RecyclerView.NO_POSITION) { + onItemClickListener.selectFile(filteredFiles[position]) + } + } + } + } + + @SuppressLint("NotifyDataSetChanged") + fun filter(query: String) { + filteredFiles = if (query.isEmpty()) { + files + } else { + files.filter { file -> + file.fileName.contains(query, ignoreCase = true) + } + } + notifyDataSetChanged() + } + + override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ReceiveExternalViewHolder { + val binding = UploaderListItemLayoutBinding + .inflate(LayoutInflater.from(viewGroup.context), viewGroup, false) + return ReceiveExternalViewHolder(binding) + } + + override fun onBindViewHolder(viewHolder: ReceiveExternalViewHolder, position: Int) { + val file = filteredFiles[position] + + viewHolder.binding.filename.text = file.fileName + viewHolder.binding.lastMod.text = DisplayUtils.getRelativeTimestamp(context, file.modificationTimestamp) + + if (!file.isFolder) { + viewHolder.binding.fileSize.text = DisplayUtils.bytesToHumanReadable(file.fileLength) + } + + viewHolder.binding.fileSize.visibility = if (file.isFolder) { + View.GONE + } else { + View.VISIBLE + } + viewHolder.binding.fileSeparator.visibility = if (file.isFolder) { + View.GONE + } else { + View.VISIBLE + } + + val thumbnailImageView = viewHolder.binding.thumbnail + setupThumbnail(thumbnailImageView, file) + } + + private fun setupThumbnail(thumbnailImageView: ImageView, file: OCFile) { + thumbnailImageView.tag = file.fileId + + if (file.isFolder) { + setupThumbnailForFolder(thumbnailImageView, file) + } else if (MimeTypeUtil.isImage(file) && file.remoteId != null) { + setupThumbnailForImage(thumbnailImageView, file) + } else { + setupDefaultThumbnail(thumbnailImageView, file) + } + } + + private fun setupThumbnailForFolder(thumbnailImageView: ImageView, file: OCFile) { + val isAutoUploadFolder = SyncedFolderProvider.isAutoUploadFolder(syncedFolderProvider, file, user) + val isDarkModeActive = syncedFolderProvider.preferences.isDarkModeEnabled + val overlayIconId = file.getFileOverlayIconId(isAutoUploadFolder) + val icon = MimeTypeUtil.getFileIcon(isDarkModeActive, overlayIconId, context, viewThemeUtils) + thumbnailImageView.setImageDrawable(icon) + } + + @Suppress("NestedBlockDepth") + private fun setupThumbnailForImage(thumbnailImageView: ImageView, file: OCFile) { + var thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(file.remoteId.toString()) + if (thumbnail != null && !file.isUpdateThumbnailNeeded) { + thumbnailImageView.setImageBitmap(thumbnail) + } else { + // generate new Thumbnail + if (ThumbnailsCacheManager.cancelPotentialThumbnailWork(file, thumbnailImageView)) { + val task = ThumbnailGenerationTask(thumbnailImageView, storageManager, user) + if (thumbnail == null) { + thumbnail = if (MimeTypeUtil.isVideo(file)) { + ThumbnailsCacheManager.mDefaultVideo + } else { + ThumbnailsCacheManager.mDefaultImg + } + } + val asyncDrawable = AsyncThumbnailDrawable( + context.resources, + thumbnail, + task + ) + thumbnailImageView.setImageDrawable(asyncDrawable) + + @Suppress("DEPRECATION") + task.execute(ThumbnailGenerationTaskObject(file, file.remoteId)) + } + } + } + + private fun setupDefaultThumbnail(thumbnailImageView: ImageView, file: OCFile) { + val icon = MimeTypeUtil.getFileTypeIcon( + file.mimeType, + file.fileName, + context, + viewThemeUtils + ) + thumbnailImageView.setImageDrawable(icon) + } + + override fun getItemCount() = filteredFiles.size +} diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java index 821d44ac3c..9d0f1b74ce 100755 --- a/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/UploadListAdapter.java @@ -711,6 +711,9 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter. - * - */ - -package com.owncloud.android.ui.adapter; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.LayerDrawable; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.SimpleAdapter; -import android.widget.TextView; - -import com.nextcloud.client.account.User; -import com.nextcloud.client.preferences.DarkMode; -import com.owncloud.android.R; -import com.owncloud.android.datamodel.FileDataStorageManager; -import com.owncloud.android.datamodel.OCFile; -import com.owncloud.android.datamodel.SyncedFolderProvider; -import com.owncloud.android.datamodel.ThumbnailsCacheManager; -import com.owncloud.android.datamodel.ThumbnailsCacheManager.AsyncThumbnailDrawable; -import com.owncloud.android.utils.DisplayUtils; -import com.owncloud.android.utils.MimeTypeUtil; -import com.owncloud.android.utils.theme.ViewThemeUtils; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class UploaderAdapter extends SimpleAdapter { - - private final Context mContext; - private final User user; - private final FileDataStorageManager mStorageManager; - private final LayoutInflater inflater; - private final ViewThemeUtils viewThemeUtils; - private SyncedFolderProvider syncedFolderProvider; - - public UploaderAdapter(Context context, - List> data, - int resource, - String[] from, - int[] to, - FileDataStorageManager storageManager, - User user, - SyncedFolderProvider syncedFolderProvider, - ViewThemeUtils viewThemeUtils) { - super(context, data, resource, from, to); - this.user = user; - mStorageManager = storageManager; - mContext = context; - this.syncedFolderProvider = syncedFolderProvider; - inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - this.viewThemeUtils = viewThemeUtils; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - View vi = convertView; - if (convertView == null) { - vi = inflater.inflate(R.layout.uploader_list_item_layout, parent, false); - } - - HashMap data = (HashMap) getItem(position); - OCFile file = data.get("dirname"); - - TextView filename = vi.findViewById(R.id.filename); - filename.setText(file.getFileName()); - - ImageView fileIcon = vi.findViewById(R.id.thumbnail); - fileIcon.setTag(file.getFileId()); - - TextView lastModV = vi.findViewById(R.id.last_mod); - lastModV.setText(DisplayUtils.getRelativeTimestamp(mContext, file.getModificationTimestamp())); - - TextView fileSizeV = vi.findViewById(R.id.file_size); - TextView fileSizeSeparatorV = vi.findViewById(R.id.file_separator); - - if(!file.isFolder()) { - fileSizeV.setVisibility(View.VISIBLE); - fileSizeSeparatorV.setVisibility(View.VISIBLE); - fileSizeV.setText(DisplayUtils.bytesToHumanReadable(file.getFileLength())); - } else { - fileSizeV.setVisibility(View.GONE); - fileSizeSeparatorV.setVisibility(View.GONE); - } - - if (file.isFolder()) { - boolean isAutoUploadFolder = SyncedFolderProvider.isAutoUploadFolder(syncedFolderProvider, file, user); - boolean isDarkModeActive = syncedFolderProvider.getPreferences().isDarkModeEnabled(); - - Integer overlayIconId = file.getFileOverlayIconId(isAutoUploadFolder); - final LayerDrawable icon = MimeTypeUtil.getFileIcon(isDarkModeActive, overlayIconId, mContext, viewThemeUtils); - fileIcon.setImageDrawable(icon); - } else { - // get Thumbnail if file is image - if (MimeTypeUtil.isImage(file) && file.getRemoteId() != null) { - // Thumbnail in Cache? - Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache( - String.valueOf(file.getRemoteId()) - ); - if (thumbnail != null && !file.isUpdateThumbnailNeeded()) { - fileIcon.setImageBitmap(thumbnail); - } else { - // generate new Thumbnail - if (ThumbnailsCacheManager.cancelPotentialThumbnailWork(file, fileIcon)) { - final ThumbnailsCacheManager.ThumbnailGenerationTask task = - new ThumbnailsCacheManager.ThumbnailGenerationTask(fileIcon, mStorageManager, user); - if (thumbnail == null) { - if (MimeTypeUtil.isVideo(file)) { - thumbnail = ThumbnailsCacheManager.mDefaultVideo; - } else { - thumbnail = ThumbnailsCacheManager.mDefaultImg; - } - } - final AsyncThumbnailDrawable asyncDrawable = new AsyncThumbnailDrawable( - mContext.getResources(), - thumbnail, - task - ); - fileIcon.setImageDrawable(asyncDrawable); - task.execute(new ThumbnailsCacheManager.ThumbnailGenerationTaskObject(file, file.getRemoteId())); - } - } - } else { - final Drawable icon = MimeTypeUtil.getFileTypeIcon(file.getMimeType(), - file.getFileName(), - mContext, - viewThemeUtils); - fileIcon.setImageDrawable(icon); - } - } - - return vi; - } -} diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.java index c7260043e8..fb825925b3 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.java @@ -467,7 +467,7 @@ public class ExtendedListFragment extends Fragment implements private void scrollToPosition(int position) { LinearLayoutManager linearLayoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager(); - if (mRecyclerView != null) { + if (linearLayoutManager != null) { int visibleItemCount = linearLayoutManager.findLastCompletelyVisibleItemPosition() - linearLayoutManager.findFirstCompletelyVisibleItemPosition(); linearLayoutManager.scrollToPositionWithOffset(position, (visibleItemCount / 2) * mHeightCell); diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java index f1c71f112f..cb842af067 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java @@ -445,21 +445,8 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda ShareType.PUBLIC_LINK, ""); -// -// boolean supportsSecureFiledrop = file.isEncrypted() && -// capabilities.getVersion().isNewerOrEqual(NextcloudVersion.nextcloud_26); -// -// if (publicShares.isEmpty() && -// containsNoNewPublicShare(adapter.getShares()) && -// (!file.isEncrypted() || supportsSecureFiledrop)) { -// final OCShare ocShare = new OCShare(); -// ocShare.setShareType(ShareType.NEW_PUBLIC_LINK); -// publicShares.add(ocShare); -// } else { -// adapter.removeNewPublicShare(); -// } - - if (publicShares.isEmpty() && containsNoNewPublicShare(adapter.getShares())) { + if (publicShares.isEmpty() && containsNoNewPublicShare(adapter.getShares()) && + (!file.isEncrypted() || capabilities.getEndToEndEncryption().isTrue())) { final OCShare ocShare = new OCShare(); ocShare.setShareType(ShareType.NEW_PUBLIC_LINK); publicShares.add(ocShare); diff --git a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java index 2813e306cc..4f8daf5627 100644 --- a/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/preview/PreviewImageActivity.java @@ -205,7 +205,7 @@ public class PreviewImageActivity extends FileActivity implements } return true; } else { - return onOptionsItemSelected(item); + return super.onOptionsItemSelected(item); } } diff --git a/app/src/main/res/layout/receive_external_files.xml b/app/src/main/res/layout/receive_external_files.xml index 01b220ae51..810adae015 100644 --- a/app/src/main/res/layout/receive_external_files.xml +++ b/app/src/main/res/layout/receive_external_files.xml @@ -34,10 +34,11 @@ android:layout_height="0dp" android:layout_weight="1"> - Неуспело закључавање фасцикле Шифровање је могуће само са >= Андроидом 5.0 Недостатак простора спречава копирање фајлова у фасциклу %1$s. Желите ли да их преместите тамо? + Прекорачена је квота за складиште Скенирање документа камером Сукоб синхронизације. Разрешите га ручно Непозната грешка diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index fc07a77084..c3383c2a6b 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -887,6 +887,7 @@ 锁定文件夹失败 加密功能仅适用于安卓 5.0 及以上版本 空间不足将阻止将所选文件复制到%1$s文件夹中。 你想把它们移到那里吗? + 超出存储限额 使用相机扫描文档 同步时发生异常,请手动同步 未知错误 diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index ec14ded2e1..cc4503ab5f 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -233,13 +233,6 @@ bold - -