mirror of
https://github.com/nextcloud/android.git
synced 2024-11-23 21:55:48 +03:00
Fix merge conflict
Signed-off-by: alperozturk <alper_ozturk@proton.me>
This commit is contained in:
commit
2f1e3ea2b4
47 changed files with 533 additions and 484 deletions
2
.github/workflows/assembleFlavors.yml
vendored
2
.github/workflows/assembleFlavors.yml
vendored
|
@ -21,7 +21,7 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v3
|
||||
- name: set up JDK 17
|
||||
uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3
|
||||
uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v3
|
||||
with:
|
||||
distribution: "temurin"
|
||||
java-version: 17
|
||||
|
|
2
.github/workflows/check.yml
vendored
2
.github/workflows/check.yml
vendored
|
@ -21,7 +21,7 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v3
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3
|
||||
uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v3
|
||||
with:
|
||||
distribution: "temurin"
|
||||
java-version: 17
|
||||
|
|
2
.github/workflows/detectWrongSettings.yml
vendored
2
.github/workflows/detectWrongSettings.yml
vendored
|
@ -18,7 +18,7 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v3
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3
|
||||
uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v3
|
||||
with:
|
||||
distribution: "temurin"
|
||||
java-version: 17
|
||||
|
|
2
.github/workflows/qa.yml
vendored
2
.github/workflows/qa.yml
vendored
|
@ -22,7 +22,7 @@ jobs:
|
|||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v3
|
||||
if: ${{ steps.check-secrets.outputs.ok == 'true' }}
|
||||
- name: set up JDK 17
|
||||
uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3
|
||||
uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v3
|
||||
if: ${{ steps.check-secrets.outputs.ok == 'true' }}
|
||||
with:
|
||||
distribution: "temurin"
|
||||
|
|
2
.github/workflows/screenShotTest.yml
vendored
2
.github/workflows/screenShotTest.yml
vendored
|
@ -40,7 +40,7 @@ jobs:
|
|||
~/.android/adb*
|
||||
key: avd-${{ matrix.api-level }}
|
||||
|
||||
- uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3
|
||||
- uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v3
|
||||
with:
|
||||
distribution: "temurin"
|
||||
java-version: 17
|
||||
|
|
2
.github/workflows/unit-tests.yml
vendored
2
.github/workflows/unit-tests.yml
vendored
|
@ -20,7 +20,7 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3.13.0
|
||||
uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0
|
||||
with:
|
||||
distribution: "temurin"
|
||||
java-version: 17
|
||||
|
|
|
@ -126,6 +126,10 @@ android {
|
|||
}
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
buildConfig = true
|
||||
}
|
||||
|
||||
productFlavors {
|
||||
// used for f-droid
|
||||
generic {
|
||||
|
|
|
@ -169,6 +169,9 @@
|
|||
<receiver
|
||||
android:name="com.nextcloud.client.jobs.NotificationWork$NotificationReceiver"
|
||||
android:exported="false" />
|
||||
<receiver
|
||||
android:name="com.owncloud.android.files.services.FileUploader$UploadNotificationActionReceiver"
|
||||
android:exported="false" />
|
||||
<receiver
|
||||
android:name="com.nextcloud.client.widget.DashboardWidgetProvider"
|
||||
android:exported="false">
|
||||
|
|
|
@ -43,6 +43,7 @@ import com.owncloud.android.datamodel.FileDataStorageManager
|
|||
import com.owncloud.android.datamodel.ThumbnailsCacheManager
|
||||
import com.owncloud.android.datamodel.UploadsStorageManager
|
||||
import com.owncloud.android.db.OCUpload
|
||||
import com.owncloud.android.files.services.FileUploader
|
||||
import com.owncloud.android.lib.common.OwnCloudAccount
|
||||
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory
|
||||
import com.owncloud.android.lib.common.network.OnDatatransferProgressListener
|
||||
|
@ -197,6 +198,18 @@ class FilesUploadWorker(
|
|||
* adapted from [com.owncloud.android.files.services.FileUploader.notifyUploadStart]
|
||||
*/
|
||||
private fun createNotification(uploadFileOperation: UploadFileOperation) {
|
||||
val notificationActionIntent = Intent(context, FileUploader.UploadNotificationActionReceiver::class.java)
|
||||
notificationActionIntent.putExtra(FileUploader.EXTRA_ACCOUNT_NAME, uploadFileOperation.user.accountName)
|
||||
notificationActionIntent.putExtra(FileUploader.EXTRA_REMOTE_PATH, uploadFileOperation.remotePath)
|
||||
notificationActionIntent.action = FileUploader.ACTION_CANCEL_BROADCAST
|
||||
|
||||
val pendingIntent = PendingIntent.getBroadcast(
|
||||
context,
|
||||
SecureRandom().nextInt(),
|
||||
notificationActionIntent,
|
||||
PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
|
||||
notificationBuilder
|
||||
.setOngoing(true)
|
||||
.setSmallIcon(R.drawable.notification_icon)
|
||||
|
@ -209,6 +222,8 @@ class FilesUploadWorker(
|
|||
uploadFileOperation.fileName
|
||||
)
|
||||
)
|
||||
.clearActions() // to make sure there is only one action
|
||||
.addAction(R.drawable.ic_action_cancel_grey, context.getString(R.string.common_cancel), pendingIntent)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
notificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_UPLOAD)
|
||||
|
@ -275,6 +290,7 @@ class FilesUploadWorker(
|
|||
.setAutoCancel(true)
|
||||
.setOngoing(false)
|
||||
.setProgress(0, 0, false)
|
||||
.clearActions()
|
||||
|
||||
val content = ErrorMessageAdapter.getErrorCauseMessage(uploadResult, uploadFileOperation, context.resources)
|
||||
|
||||
|
|
|
@ -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<Bitmap>
|
||||
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<Bitmap> = 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<Bitmap> {
|
||||
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<Bitmap> {
|
||||
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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ import android.app.Notification;
|
|||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ServiceInfo;
|
||||
|
@ -128,6 +129,10 @@ public class FileUploader extends Service
|
|||
public static final String EXTRA_LINKED_TO_PATH = "LINKED_TO";
|
||||
public static final String ACCOUNT_NAME = "ACCOUNT_NAME";
|
||||
|
||||
public static final String EXTRA_ACCOUNT_NAME = "ACCOUNT_NAME";
|
||||
public static final String ACTION_CANCEL_BROADCAST = "CANCEL";
|
||||
public static final String ACTION_PAUSE_BROADCAST = "PAUSE";
|
||||
|
||||
private static final int FOREGROUND_SERVICE_ID = 411;
|
||||
|
||||
public static final String KEY_FILE = "FILE";
|
||||
|
@ -198,11 +203,13 @@ public class FileUploader extends Service
|
|||
private Notification mNotification;
|
||||
private Looper mServiceLooper;
|
||||
private ServiceHandler mServiceHandler;
|
||||
private IBinder mBinder;
|
||||
private static IBinder mBinder;
|
||||
private OwnCloudClient mUploadClient;
|
||||
private Account mCurrentAccount;
|
||||
private FileDataStorageManager mStorageManager;
|
||||
|
||||
private SecureRandom secureRandomGenerator = new SecureRandom();
|
||||
|
||||
@Inject UserAccountManager accountManager;
|
||||
@Inject UploadsStorageManager mUploadsStorageManager;
|
||||
@Inject ConnectivityService connectivityService;
|
||||
|
@ -233,6 +240,7 @@ public class FileUploader extends Service
|
|||
/**
|
||||
* Service initialization
|
||||
*/
|
||||
@SuppressFBWarnings("ST")
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
@ -280,6 +288,7 @@ public class FileUploader extends Service
|
|||
/**
|
||||
* Service clean up
|
||||
*/
|
||||
@SuppressFBWarnings("ST")
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
Log_OC.v(TAG, "Destroying service");
|
||||
|
@ -708,6 +717,12 @@ public class FileUploader extends Service
|
|||
*/
|
||||
private void notifyUploadStart(UploadFileOperation upload) {
|
||||
// / create status notification with a progress bar
|
||||
Intent notificationActionIntent = new Intent(getApplicationContext(),UploadNotificationActionReceiver.class);
|
||||
notificationActionIntent.putExtra(EXTRA_ACCOUNT_NAME,upload.getUser().getAccountName());
|
||||
notificationActionIntent.putExtra(EXTRA_REMOTE_PATH,upload.getRemotePath());
|
||||
notificationActionIntent.setAction(ACTION_CANCEL_BROADCAST);
|
||||
|
||||
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(),secureRandomGenerator.nextInt(),notificationActionIntent, PendingIntent.FLAG_IMMUTABLE);
|
||||
mLastPercent = 0;
|
||||
mNotificationBuilder = NotificationUtils.newNotificationBuilder(this, viewThemeUtils);
|
||||
mNotificationBuilder
|
||||
|
@ -718,7 +733,10 @@ public class FileUploader extends Service
|
|||
.setProgress(100, 0, false)
|
||||
.setContentText(
|
||||
String.format(getString(R.string.uploader_upload_in_progress_content), 0, upload.getFileName())
|
||||
);
|
||||
)
|
||||
.clearActions() // to make sure there is only one action
|
||||
.addAction(R.drawable.ic_action_cancel_grey,getApplicationContext().getString(R.string.common_cancel),pendingIntent);
|
||||
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
mNotificationBuilder.setChannelId(NotificationUtils.NOTIFICATION_CHANNEL_UPLOAD);
|
||||
|
@ -811,7 +829,8 @@ public class FileUploader extends Service
|
|||
.setContentTitle(getString(tickerId))
|
||||
.setAutoCancel(true)
|
||||
.setOngoing(false)
|
||||
.setProgress(0, 0, false);
|
||||
.setProgress(0, 0, false)
|
||||
.clearActions();
|
||||
|
||||
content = ErrorMessageAdapter.getErrorCauseMessage(uploadResult, upload, getResources());
|
||||
|
||||
|
@ -859,7 +878,7 @@ public class FileUploader extends Service
|
|||
|
||||
mNotificationBuilder.setContentText(content);
|
||||
if (!uploadResult.isSuccess()) {
|
||||
mNotificationManager.notify((new SecureRandom()).nextInt(), mNotificationBuilder.build());
|
||||
mNotificationManager.notify(secureRandomGenerator.nextInt(), mNotificationBuilder.build());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1408,4 +1427,32 @@ public class FileUploader extends Service
|
|||
mService.stopSelf(msg.arg1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* When cancel action in upload notification is pressed, cancel upload of item
|
||||
*/
|
||||
public static class UploadNotificationActionReceiver extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
|
||||
String accountName = intent.getStringExtra(EXTRA_ACCOUNT_NAME);
|
||||
String remotePath = intent.getStringExtra(EXTRA_REMOTE_PATH);
|
||||
String action = intent.getAction();
|
||||
|
||||
if (ACTION_CANCEL_BROADCAST.equals(action)) {
|
||||
Log_OC.d(TAG, "Cancel broadcast received for file " + remotePath + " at " + System.currentTimeMillis());
|
||||
|
||||
if (accountName == null || remotePath == null) return;
|
||||
|
||||
FileUploaderBinder uploadBinder = (FileUploaderBinder) mBinder;
|
||||
uploadBinder.cancel(accountName, remotePath, null);
|
||||
}else if(ACTION_PAUSE_BROADCAST.equals(action)){
|
||||
|
||||
} else {
|
||||
Log_OC.d(TAG, "Unknown action to perform as UploadNotificationActionReceiver.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<OCFile> tmpFiles = getStorageManager().getFolderContent(mFile, false);
|
||||
tmpFiles = sortFileList(tmpFiles);
|
||||
|
||||
if (tmpFiles.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
// filter on dirtype
|
||||
Vector<OCFile> 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<Map<String, Object>> data = new LinkedList<>();
|
||||
for (OCFile f : files) {
|
||||
Map<String, Object> 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<OCFile> 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;
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Alper Ozturk
|
||||
* Copyright (C) 2023 Alper Ozturk
|
||||
* Copyright (C) 2023 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 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<OCFile>,
|
||||
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<ReceiveExternalFilesAdapter.ReceiveExternalViewHolder>() {
|
||||
|
||||
private var filteredFiles: List<OCFile> = 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
|
||||
}
|
|
@ -1,156 +0,0 @@
|
|||
/*
|
||||
* ownCloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2016 ownCloud Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
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<? extends Map<String, ?>> 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<String, OCFile> data = (HashMap<String, OCFile>) 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;
|
||||
}
|
||||
}
|
|
@ -18,13 +18,9 @@
|
|||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.owncloud.android.ui.events;
|
||||
package com.owncloud.android.ui.events
|
||||
|
||||
/**
|
||||
* Event that notifies that an account was removed
|
||||
*/
|
||||
|
||||
public class AccountRemovedEvent {
|
||||
|
||||
}
|
||||
class AccountRemovedEvent
|
|
@ -15,12 +15,11 @@
|
|||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* along with this program. If not, see <http:></http:>//www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.owncloud.android.ui.events;
|
||||
package com.owncloud.android.ui.events
|
||||
|
||||
/**
|
||||
* Currently a dummy event to restore grid view, sort, and search
|
||||
*/
|
||||
public class ChangeMenuEvent {
|
||||
}
|
||||
class ChangeMenuEvent
|
|
@ -18,16 +18,9 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.owncloud.android.ui.events;
|
||||
package com.owncloud.android.ui.events
|
||||
|
||||
/**
|
||||
* Event for refreshing comment state of a file
|
||||
*/
|
||||
public class CommentsEvent {
|
||||
public final String remoteId;
|
||||
|
||||
public CommentsEvent(String remoteId) {
|
||||
this.remoteId = remoteId;
|
||||
}
|
||||
}
|
||||
class CommentsEvent(val remoteId: String)
|
|
@ -15,12 +15,11 @@
|
|||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* along with this program. If not, see <http:></http:>//www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.owncloud.android.ui.events;
|
||||
package com.owncloud.android.ui.events
|
||||
|
||||
/**
|
||||
* Dummy drawer event
|
||||
*/
|
||||
public class DummyDrawerEvent {
|
||||
}
|
||||
class DummyDrawerEvent
|
|
@ -1,37 +0,0 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2017 Tobias Kaminsky
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.owncloud.android.ui.events;
|
||||
|
||||
/**
|
||||
* Event for set folder as encrypted/decrypted
|
||||
*/
|
||||
public class EncryptionEvent {
|
||||
public final long localId;
|
||||
public final String remotePath;
|
||||
public final String remoteId;
|
||||
public final boolean shouldBeEncrypted;
|
||||
|
||||
public EncryptionEvent(long localId, String remoteId, String remotePath, boolean shouldBeEncrypted) {
|
||||
this.localId = localId;
|
||||
this.remoteId = remoteId;
|
||||
this.remotePath = remotePath;
|
||||
this.shouldBeEncrypted = shouldBeEncrypted;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Tobias Kaminsky
|
||||
* Copyright (C) 2017 Tobias Kaminsky
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.owncloud.android.ui.events
|
||||
|
||||
/**
|
||||
* Event for set folder as encrypted/decrypted
|
||||
*/
|
||||
class EncryptionEvent(
|
||||
val localId: Long,
|
||||
val remoteId: String,
|
||||
val remotePath: String,
|
||||
val shouldBeEncrypted: Boolean
|
||||
)
|
|
@ -1,33 +0,0 @@
|
|||
/**
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Mario Danic
|
||||
* Copyright (C) 2017 Mario Danic
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.owncloud.android.ui.events;
|
||||
|
||||
/**
|
||||
* Event for making favoriting work
|
||||
*/
|
||||
public class FavoriteEvent {
|
||||
public final String remotePath;
|
||||
public final boolean shouldFavorite;
|
||||
|
||||
public FavoriteEvent(String remotePath, boolean shouldFavorite) {
|
||||
this.remotePath = remotePath;
|
||||
this.shouldFavorite = shouldFavorite;
|
||||
}
|
||||
}
|
|
@ -15,14 +15,11 @@
|
|||
* 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 <http://www.gnu.org/licenses/>.
|
||||
* along with this program. If not, see <http:></http:>//www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.owncloud.android.ui.events;
|
||||
package com.owncloud.android.ui.events
|
||||
|
||||
public class VCardToggleEvent {
|
||||
public boolean showRestoreButton;
|
||||
|
||||
public VCardToggleEvent(boolean showRestore) {
|
||||
this.showRestoreButton = showRestore;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Event for making favoriting work
|
||||
*/
|
||||
class FavoriteEvent(val remotePath: String, val shouldFavorite: Boolean)
|
|
@ -1,35 +0,0 @@
|
|||
/**
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Mario Danic
|
||||
* Copyright (C) 2017 Mario Danic
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.owncloud.android.ui.events;
|
||||
|
||||
import com.owncloud.android.datamodel.SyncedFolder;
|
||||
|
||||
public class InitiateSyncedFolder {
|
||||
private final SyncedFolder syncedFolder;
|
||||
|
||||
|
||||
public InitiateSyncedFolder(SyncedFolder syncedFolder) {
|
||||
this.syncedFolder = syncedFolder;
|
||||
}
|
||||
|
||||
public SyncedFolder getSyncedFolder() {
|
||||
return syncedFolder;
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
/**
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Mario Danic
|
||||
* Copyright (C) 2017 Mario Danic
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.owncloud.android.ui.events;
|
||||
|
||||
import android.view.MenuItem;
|
||||
|
||||
/**
|
||||
* Menu item click event
|
||||
*/
|
||||
public class MenuItemClickEvent {
|
||||
public final MenuItem menuItem;
|
||||
|
||||
public MenuItemClickEvent(MenuItem menuItem) {
|
||||
this.menuItem = menuItem;
|
||||
}
|
||||
}
|
|
@ -17,10 +17,9 @@
|
|||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.owncloud.android.ui.events;
|
||||
package com.owncloud.android.ui.events
|
||||
|
||||
/**
|
||||
* Event to send push token where it belongs
|
||||
*/
|
||||
public class TokenPushEvent {
|
||||
}
|
||||
class TokenPushEvent
|
|
@ -0,0 +1,22 @@
|
|||
/**
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Mario Danic
|
||||
* Copyright (C) 2017 Mario Danic
|
||||
*
|
||||
* 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 <http:></http:>//www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.owncloud.android.ui.events
|
||||
|
||||
class VCardToggleEvent(var showRestoreButton: Boolean)
|
|
@ -783,13 +783,13 @@ public class FileDetailFragment extends FileFragment implements OnClickListener,
|
|||
OwnCloudClient client = clientFactory.create(user);
|
||||
|
||||
ToggleFavoriteRemoteOperation toggleFavoriteOperation = new ToggleFavoriteRemoteOperation(
|
||||
event.shouldFavorite, event.remotePath);
|
||||
event.getShouldFavorite(), event.getRemotePath());
|
||||
RemoteOperationResult remoteOperationResult = toggleFavoriteOperation.execute(client);
|
||||
|
||||
if (remoteOperationResult.isSuccess()) {
|
||||
getFile().setFavorite(event.shouldFavorite);
|
||||
OCFile file = storageManager.getFileByEncryptedRemotePath(event.remotePath);
|
||||
file.setFavorite(event.shouldFavorite);
|
||||
getFile().setFavorite(event.getShouldFavorite());
|
||||
OCFile file = storageManager.getFileByEncryptedRemotePath(event.getRemotePath());
|
||||
file.setFavorite(event.getShouldFavorite());
|
||||
storageManager.saveFile(file);
|
||||
}
|
||||
|
||||
|
|
|
@ -1588,7 +1588,7 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
|
||||
@Subscribe(threadMode = ThreadMode.BACKGROUND)
|
||||
public void onMessageEvent(CommentsEvent event) {
|
||||
mAdapter.refreshCommentsCount(event.remoteId);
|
||||
mAdapter.refreshCommentsCount(event.getRemoteId());
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.BACKGROUND)
|
||||
|
@ -1598,13 +1598,13 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
OwnCloudClient client = clientFactory.create(user);
|
||||
|
||||
ToggleFavoriteRemoteOperation toggleFavoriteOperation = new ToggleFavoriteRemoteOperation(
|
||||
event.shouldFavorite, event.remotePath);
|
||||
event.getShouldFavorite(), event.getRemotePath());
|
||||
RemoteOperationResult remoteOperationResult = toggleFavoriteOperation.execute(client);
|
||||
|
||||
if (remoteOperationResult.isSuccess()) {
|
||||
boolean removeFromList = currentSearchType == SearchType.FAVORITE_SEARCH && !event.shouldFavorite;
|
||||
boolean removeFromList = currentSearchType == SearchType.FAVORITE_SEARCH && !event.getShouldFavorite();
|
||||
setEmptyListMessage(SearchType.FAVORITE_SEARCH);
|
||||
mAdapter.setFavoriteAttributeForItemID(event.remotePath, event.shouldFavorite, removeFromList);
|
||||
mAdapter.setFavoriteAttributeForItemID(event.getRemotePath(), event.getShouldFavorite(), removeFromList);
|
||||
}
|
||||
|
||||
} catch (ClientFactory.CreationException e) {
|
||||
|
@ -1692,7 +1692,7 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
String privateKey = arbitraryDataProvider.getValue(user, EncryptionUtils.PRIVATE_KEY);
|
||||
|
||||
FileDataStorageManager storageManager = mContainerActivity.getStorageManager();
|
||||
OCFile file = storageManager.getFileByRemoteId(event.remoteId);
|
||||
OCFile file = storageManager.getFileByRemoteId(event.getRemoteId());
|
||||
|
||||
if (publicKey.isEmpty() || privateKey.isEmpty()) {
|
||||
Log_OC.d(TAG, "no public key for " + user.getAccountName());
|
||||
|
@ -1706,10 +1706,10 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
dialog.show(getParentFragmentManager(), SETUP_ENCRYPTION_DIALOG_TAG);
|
||||
} else {
|
||||
encryptFolder(file,
|
||||
event.localId,
|
||||
event.remoteId,
|
||||
event.remotePath,
|
||||
event.shouldBeEncrypted,
|
||||
event.getLocalId(),
|
||||
event.getRemoteId(),
|
||||
event.getRemotePath(),
|
||||
event.getShouldBeEncrypted(),
|
||||
publicKey,
|
||||
privateKey);
|
||||
}
|
||||
|
|
|
@ -270,7 +270,7 @@ public class BackupListFragment extends FileFragment implements Injectable {
|
|||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onMessageEvent(VCardToggleEvent event) {
|
||||
if (event.showRestoreButton) {
|
||||
if (event.getShowRestoreButton()) {
|
||||
binding.contactlistRestoreSelectedContainer.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
binding.contactlistRestoreSelectedContainer.setVisibility(View.GONE);
|
||||
|
|
|
@ -436,6 +436,8 @@ public class PreviewImageFragment extends FileFragment implements Injectable {
|
|||
seeDetails();
|
||||
} else if (itemId == R.id.action_download_file || itemId == R.id.action_sync_file) {
|
||||
containerActivity.getFileOperationsHelper().syncFile(getFile());
|
||||
}else if(itemId == R.id.action_cancel_sync){
|
||||
containerActivity.getFileOperationsHelper().cancelTransference(getFile());
|
||||
} else if (itemId == R.id.action_set_as_wallpaper) {
|
||||
containerActivity.getFileOperationsHelper().setPictureAs(getFile(), getImageView());
|
||||
} else if (itemId == R.id.action_export_file) {
|
||||
|
|
|
@ -482,6 +482,8 @@ public class PreviewMediaFragment extends FileFragment implements OnTouchListene
|
|||
seeDetails();
|
||||
} else if (itemId == R.id.action_sync_file) {
|
||||
containerActivity.getFileOperationsHelper().syncFile(getFile());
|
||||
} else if (itemId == R.id.action_cancel_sync) {
|
||||
containerActivity.getFileOperationsHelper().cancelTransference(getFile());
|
||||
} else if (itemId == R.id.action_stream_media) {
|
||||
containerActivity.getFileOperationsHelper().streamMediaFile(getFile());
|
||||
} else if (itemId == R.id.action_export_file) {
|
||||
|
|
|
@ -330,6 +330,8 @@ public class PreviewTextFileFragment extends PreviewTextFragment {
|
|||
seeDetails();
|
||||
} else if (itemId == R.id.action_sync_file) {
|
||||
containerActivity.getFileOperationsHelper().syncFile(getFile());
|
||||
} else if(itemId == R.id.action_cancel_sync){
|
||||
containerActivity.getFileOperationsHelper().cancelTransference(getFile());
|
||||
} else if (itemId == R.id.action_edit) {
|
||||
containerActivity.getFileOperationsHelper().openFileWithTextEditor(getFile(), getContext());
|
||||
}
|
||||
|
|
|
@ -34,10 +34,11 @@
|
|||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
|
||||
<ListView
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@android:id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="@color/bg_default"
|
||||
android:divider="@color/transparent"
|
||||
android:dividerHeight="0dip"
|
||||
|
|
|
@ -891,6 +891,7 @@
|
|||
<string name="upload_lock_failed">فشل قفّل المجلد</string>
|
||||
<string name="upload_old_android">التشفير ممكن فقط مع >= Android 5.0</string>
|
||||
<string name="upload_query_move_foreign_files">يمنع وجود مساحة غير كافية نسخ الملفات المحددة إلى المجلد %1$s. هل ترغب في نقلهم إلى هناك بدلاً من ذلك؟</string>
|
||||
<string name="upload_quota_exceeded">الحصة التخزينية تمّ استنفاذها</string>
|
||||
<string name="upload_scan_doc_upload">مسح مستند عبر الكاميرا</string>
|
||||
<string name="upload_sync_conflict">تعارض المزامنة ، يرجى حلها يدويًا</string>
|
||||
<string name="upload_unknown_error">خطأ غير معروف</string>
|
||||
|
|
|
@ -884,6 +884,7 @@
|
|||
<string name="upload_lock_failed">Uzamčení složky se nezdařilo</string>
|
||||
<string name="upload_old_android">Šifrování je možné pouze na systému Android verze 5.0 a novějším</string>
|
||||
<string name="upload_query_move_foreign_files">Pro zkopírování vybraných souborů do složky %1$s není dostatek volného místa. Chcete je tam namísto toho přesunout?</string>
|
||||
<string name="upload_quota_exceeded">Kvóta úložiště překročena</string>
|
||||
<string name="upload_scan_doc_upload">Naskenovat dokument kamerou</string>
|
||||
<string name="upload_sync_conflict">Konflikt synchronizace – vyřešte ručně</string>
|
||||
<string name="upload_unknown_error">Neznámá chyba</string>
|
||||
|
|
|
@ -885,6 +885,7 @@
|
|||
<string name="upload_lock_failed">Fehler beim Sperren des Ordners</string>
|
||||
<string name="upload_old_android">Verschlüsselung ist nur möglich mit >= Android 5.0</string>
|
||||
<string name="upload_query_move_foreign_files">Es steht nicht genügend Speicherplatz zur Verfügung, um die ausgewählten Dateien in das Verzeichnis %1$s zu kopieren. Sollen diese stattdessen verschoben werden?</string>
|
||||
<string name="upload_quota_exceeded">Speicherkontingent überschritten</string>
|
||||
<string name="upload_scan_doc_upload">Dokument von der Kamera scannen</string>
|
||||
<string name="upload_sync_conflict">Synchronisierungskonflikt, bitte manuell beheben</string>
|
||||
<string name="upload_unknown_error">Unbekannter Fehler</string>
|
||||
|
|
|
@ -885,6 +885,7 @@
|
|||
<string name="upload_lock_failed">Produciuse un fallo ao bloquear o cartafol</string>
|
||||
<string name="upload_old_android">O cifrado só é posíbel con >= Android 5.0</string>
|
||||
<string name="upload_query_move_foreign_files">Non hai espazo abondo para copiar os ficheiros seleccionados no cartafol %1$s. No canto diso, gustaríalle movelos?</string>
|
||||
<string name="upload_quota_exceeded">Superouse a cota de almacenamento</string>
|
||||
<string name="upload_scan_doc_upload">Escanear o documento dende a cámara</string>
|
||||
<string name="upload_sync_conflict">Conflito ao sincronizar, resólvao manualmente</string>
|
||||
<string name="upload_unknown_error">Produciuse un erro descoñecido</string>
|
||||
|
|
|
@ -884,6 +884,7 @@
|
|||
<string name="upload_lock_failed">Неуспело закључавање фасцикле</string>
|
||||
<string name="upload_old_android">Шифровање је могуће само са >= Андроидом 5.0</string>
|
||||
<string name="upload_query_move_foreign_files">Недостатак простора спречава копирање фајлова у фасциклу %1$s. Желите ли да их преместите тамо?</string>
|
||||
<string name="upload_quota_exceeded">Прекорачена је квота за складиште</string>
|
||||
<string name="upload_scan_doc_upload">Скенирање документа камером</string>
|
||||
<string name="upload_sync_conflict">Сукоб синхронизације. Разрешите га ручно</string>
|
||||
<string name="upload_unknown_error">Непозната грешка</string>
|
||||
|
|
|
@ -731,7 +731,7 @@
|
|||
<string name="shared_icon_share">поділитися</string>
|
||||
<string name="shared_icon_shared">надано доступ</string>
|
||||
<string name="shared_icon_shared_via_link">доступ надано за посиланням</string>
|
||||
<string name="shared_with_you_by">%1$s поділився з вами</string>
|
||||
<string name="shared_with_you_by">%1$s поділив(-ла-)ся з вами</string>
|
||||
<string name="sharee_add_failed">Помилка додавання користувача, з яким ви хочете поділитися</string>
|
||||
<string name="show_images">Показувати зображення</string>
|
||||
<string name="show_video">Показувати відео</string>
|
||||
|
@ -793,7 +793,7 @@
|
|||
<string name="sub_folder_rule_month">Рік/місяць</string>
|
||||
<string name="sub_folder_rule_year">Рік</string>
|
||||
<string name="subject_shared_with_you">Вам було надано доступ до \"%1$s\"</string>
|
||||
<string name="subject_user_shared_with_you">%1$s поділився %2$s з вами</string>
|
||||
<string name="subject_user_shared_with_you">%1$s поділив(-ла-)ся %2$s з вами</string>
|
||||
<string name="subtitle_photos_only">Лише зображення</string>
|
||||
<string name="subtitle_photos_videos">Зображення та відео</string>
|
||||
<string name="subtitle_videos_only">Лише відео</string>
|
||||
|
|
|
@ -887,6 +887,7 @@
|
|||
<string name="upload_lock_failed">锁定文件夹失败</string>
|
||||
<string name="upload_old_android">加密功能仅适用于安卓 5.0 及以上版本</string>
|
||||
<string name="upload_query_move_foreign_files">空间不足将阻止将所选文件复制到%1$s文件夹中。 你想把它们移到那里吗?</string>
|
||||
<string name="upload_quota_exceeded">超出存储限额</string>
|
||||
<string name="upload_scan_doc_upload">使用相机扫描文档</string>
|
||||
<string name="upload_sync_conflict">同步时发生异常,请手动同步</string>
|
||||
<string name="upload_unknown_error">未知错误</string>
|
||||
|
|
|
@ -884,6 +884,7 @@
|
|||
<string name="upload_lock_failed">鎖定資料夾失敗</string>
|
||||
<string name="upload_old_android">加密功能僅適用於 Android 5.0 及更新版本</string>
|
||||
<string name="upload_query_move_foreign_files">空間不足以將選擇的檔案複製到 %1$s 資料夾,是否要改成移動它們?</string>
|
||||
<string name="upload_quota_exceeded">超過儲存空間配額</string>
|
||||
<string name="upload_scan_doc_upload">使用相機掃描文件</string>
|
||||
<string name="upload_sync_conflict">同步發生衝突,請手動處理</string>
|
||||
<string name="upload_unknown_error">未知的錯誤</string>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
buildscript {
|
||||
ext {
|
||||
androidPluginVersion = '8.1.4'
|
||||
androidPluginVersion = '8.2.0'
|
||||
appCompatVersion = '1.6.1'
|
||||
jacoco_version = '0.8.10'
|
||||
kotlin_version = '1.8.22'
|
||||
|
|
|
@ -4,7 +4,6 @@ NC_TEST_SERVER_USERNAME=test
|
|||
NC_TEST_SERVER_PASSWORD=test
|
||||
android.enableJetifier=true
|
||||
android.useAndroidX=true
|
||||
android.defaults.buildfeatures.buildconfig=true
|
||||
android.nonTransitiveRClass=false
|
||||
android.nonFinalResIds=false
|
||||
#android.debug.obsoleteApi=true
|
||||
|
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,6 +1,6 @@
|
|||
#Fri Jan 13 08:21:45 CET 2023
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
DO NOT TOUCH; GENERATED BY DRONE
|
||||
<span class="mdl-layout-title">Lint Report: 71 warnings</span>
|
||||
<span class="mdl-layout-title">Lint Report: 9 errors and 75 warnings</span>
|
||||
|
|
Loading…
Reference in a new issue