mirror of
https://github.com/nextcloud/android.git
synced 2024-11-27 09:39:25 +03:00
Sync all downloaded files in background
Signed-off-by: tobiasKaminsky <tobias@kaminsky.me>
This commit is contained in:
parent
824a91ad5d
commit
6cf499828c
30 changed files with 351 additions and 510 deletions
|
@ -85,7 +85,6 @@ public class OCFileUnitTest {
|
|||
mFile.setModificationTimestampAtLastSyncForData(MODIFICATION_TIMESTAMP_AT_LAST_SYNC_FOR_DATA);
|
||||
mFile.setLastSyncDateForProperties(LAST_SYNC_DATE_FOR_PROPERTIES);
|
||||
mFile.setLastSyncDateForData(LAST_SYNC_DATE_FOR_DATA);
|
||||
mFile.setAvailableOffline(true);
|
||||
mFile.setEtag(ETAG);
|
||||
mFile.setSharedViaLink(true);
|
||||
mFile.setSharedWithSharee(true);
|
||||
|
@ -120,7 +119,6 @@ public class OCFileUnitTest {
|
|||
);
|
||||
assertThat(fileReadFromParcel.getLastSyncDateForProperties(), is(LAST_SYNC_DATE_FOR_PROPERTIES));
|
||||
assertThat(fileReadFromParcel.getLastSyncDateForData(), is(LAST_SYNC_DATE_FOR_DATA));
|
||||
assertThat(fileReadFromParcel.isAvailableOffline(), is(true));
|
||||
assertThat(fileReadFromParcel.getEtag(), is(ETAG));
|
||||
assertThat(fileReadFromParcel.isSharedViaLink(), is(true));
|
||||
assertThat(fileReadFromParcel.isSharedWithSharee(), is(true));
|
||||
|
|
|
@ -181,7 +181,6 @@ public class MainApp extends MultiDexApplication {
|
|||
.build()
|
||||
.schedule();
|
||||
|
||||
|
||||
// register global protection with pass code
|
||||
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
|
||||
|
||||
|
|
|
@ -194,8 +194,8 @@ public class FileDataStorageManager {
|
|||
cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, account.name);
|
||||
cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDateForProperties());
|
||||
cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData());
|
||||
cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.isAvailableOffline() ? 1 : 0);
|
||||
cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag());
|
||||
cv.put(ProviderTableMeta.FILE_ETAG_ON_SERVER, file.getEtagOnServer());
|
||||
cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, file.isSharedViaLink() ? 1 : 0);
|
||||
cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, file.isSharedWithSharee() ? 1 : 0);
|
||||
cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, file.getPublicLink());
|
||||
|
@ -433,8 +433,8 @@ public class FileDataStorageManager {
|
|||
cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, account.name);
|
||||
cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, folder.getLastSyncDateForProperties());
|
||||
cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, folder.getLastSyncDateForData());
|
||||
cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, folder.isAvailableOffline() ? 1 : 0);
|
||||
cv.put(ProviderTableMeta.FILE_ETAG, folder.getEtag());
|
||||
cv.put(ProviderTableMeta.FILE_ETAG_ON_SERVER, folder.getEtagOnServer());
|
||||
cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, folder.isSharedViaLink() ? 1 : 0);
|
||||
cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, folder.isSharedWithSharee() ? 1 : 0);
|
||||
cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, folder.getPublicLink());
|
||||
|
@ -464,8 +464,8 @@ public class FileDataStorageManager {
|
|||
cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, account.name);
|
||||
cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE, file.getLastSyncDateForProperties());
|
||||
cv.put(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData());
|
||||
cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.isAvailableOffline() ? 1 : 0);
|
||||
cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag());
|
||||
cv.put(ProviderTableMeta.FILE_ETAG_ON_SERVER, file.getEtagOnServer());
|
||||
cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, file.isSharedViaLink() ? 1 : 0);
|
||||
cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, file.isSharedWithSharee() ? 1 : 0);
|
||||
cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, file.getPublicLink());
|
||||
|
@ -956,8 +956,8 @@ public class FileDataStorageManager {
|
|||
c.getColumnIndex(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA)));
|
||||
file.setLastSyncDateForProperties(c.getLong(c.getColumnIndex(ProviderTableMeta.FILE_LAST_SYNC_DATE)));
|
||||
file.setLastSyncDateForData(c.getLong(c.getColumnIndex(ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA)));
|
||||
file.setAvailableOffline(c.getInt(c.getColumnIndex(ProviderTableMeta.FILE_KEEP_IN_SYNC)) == 1);
|
||||
file.setEtag(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_ETAG)));
|
||||
file.setEtagOnServer(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_ETAG_ON_SERVER)));
|
||||
file.setSharedViaLink(c.getInt(c.getColumnIndex(ProviderTableMeta.FILE_SHARED_VIA_LINK)) == 1);
|
||||
file.setSharedWithSharee(c.getInt(c.getColumnIndex(ProviderTableMeta.FILE_SHARED_WITH_SHAREE)) == 1);
|
||||
file.setPublicLink(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_PUBLIC_LINK)));
|
||||
|
@ -1383,22 +1383,16 @@ public class FileDataStorageManager {
|
|||
ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA,
|
||||
file.getLastSyncDateForData()
|
||||
);
|
||||
cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.isAvailableOffline() ? 1 : 0);
|
||||
cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag());
|
||||
cv.put(ProviderTableMeta.FILE_ETAG_ON_SERVER, file.getEtagOnServer());
|
||||
cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, file.isSharedViaLink() ? 1 : 0);
|
||||
cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, file.isSharedWithSharee() ? 1 : 0);
|
||||
cv.put(ProviderTableMeta.FILE_PUBLIC_LINK, file.getPublicLink());
|
||||
cv.put(ProviderTableMeta.FILE_PERMISSIONS, file.getPermissions());
|
||||
cv.put(ProviderTableMeta.FILE_REMOTE_ID, file.getRemoteId());
|
||||
cv.put(ProviderTableMeta.FILE_FAVORITE, file.isFavorite());
|
||||
cv.put(
|
||||
ProviderTableMeta.FILE_UPDATE_THUMBNAIL,
|
||||
file.isUpdateThumbnailNeeded() ? 1 : 0
|
||||
);
|
||||
cv.put(
|
||||
ProviderTableMeta.FILE_IS_DOWNLOADING,
|
||||
file.isDownloading() ? 1 : 0
|
||||
);
|
||||
cv.put(ProviderTableMeta.FILE_UPDATE_THUMBNAIL, file.isUpdateThumbnailNeeded() ? 1 : 0);
|
||||
cv.put(ProviderTableMeta.FILE_IS_DOWNLOADING, file.isDownloading() ? 1 : 0);
|
||||
cv.put(ProviderTableMeta.FILE_ETAG_IN_CONFLICT, file.getEtagInConflict());
|
||||
|
||||
boolean existsByPath = fileExists(file.getRemotePath());
|
||||
|
|
|
@ -54,18 +54,11 @@ public class OCFile implements Parcelable, Comparable<OCFile>, ServerFileInterfa
|
|||
|
||||
private static final String TAG = OCFile.class.getSimpleName();
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private long fileId; // android internal ID of the file
|
||||
@Getter @Setter private long fileId; // android internal ID of the file
|
||||
@Getter @Setter private long parentId;
|
||||
@Getter @Setter private long fileLength;
|
||||
@Getter
|
||||
@Setter
|
||||
private long creationTimestamp; // UNIX timestamp of the time the file was created
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private long modificationTimestamp; // UNIX timestamp of the file modification time
|
||||
@Getter @Setter private long creationTimestamp; // UNIX timestamp of the time the file was created
|
||||
@Getter @Setter private long modificationTimestamp; // UNIX timestamp of the file modification time
|
||||
/** UNIX timestamp of the modification time, corresponding to the value returned by the server
|
||||
* in the last synchronization of THE CONTENTS of this file.
|
||||
*/
|
||||
|
@ -79,6 +72,7 @@ public class OCFile implements Parcelable, Comparable<OCFile>, ServerFileInterfa
|
|||
@Getter @Setter private boolean availableOffline;
|
||||
@Getter @Setter private boolean previewAvailable;
|
||||
@Getter private String etag;
|
||||
@Getter private String etagOnServer;
|
||||
@Getter @Setter private boolean sharedViaLink;
|
||||
@Getter @Setter private String publicLink;
|
||||
@Getter @Setter private String permissions;
|
||||
|
@ -142,10 +136,10 @@ public class OCFile implements Parcelable, Comparable<OCFile>, ServerFileInterfa
|
|||
localPath = source.readString();
|
||||
mimeType = source.readString();
|
||||
needsUpdatingWhileSaving = source.readInt() == 0;
|
||||
availableOffline = source.readInt() == 1;
|
||||
lastSyncDateForProperties = source.readLong();
|
||||
lastSyncDateForData = source.readLong();
|
||||
etag = source.readString();
|
||||
etagOnServer = source.readString();
|
||||
sharedViaLink = source.readInt() == 1;
|
||||
publicLink = source.readString();
|
||||
permissions = source.readString();
|
||||
|
@ -172,10 +166,10 @@ public class OCFile implements Parcelable, Comparable<OCFile>, ServerFileInterfa
|
|||
dest.writeString(localPath);
|
||||
dest.writeString(mimeType);
|
||||
dest.writeInt(needsUpdatingWhileSaving ? 1 : 0);
|
||||
dest.writeInt(availableOffline ? 1 : 0);
|
||||
dest.writeLong(lastSyncDateForProperties);
|
||||
dest.writeLong(lastSyncDateForData);
|
||||
dest.writeString(etag);
|
||||
dest.writeString(etagOnServer);
|
||||
dest.writeInt(sharedViaLink ? 1 : 0);
|
||||
dest.writeString(publicLink);
|
||||
dest.writeString(permissions);
|
||||
|
@ -392,9 +386,9 @@ public class OCFile implements Parcelable, Comparable<OCFile>, ServerFileInterfa
|
|||
modificationTimestampAtLastSyncForData = 0;
|
||||
lastSyncDateForProperties = 0;
|
||||
lastSyncDateForData = 0;
|
||||
availableOffline = false;
|
||||
needsUpdatingWhileSaving = false;
|
||||
etag = null;
|
||||
etagOnServer = null;
|
||||
sharedViaLink = false;
|
||||
publicLink = null;
|
||||
permissions = null;
|
||||
|
@ -458,10 +452,9 @@ public class OCFile implements Parcelable, Comparable<OCFile>, ServerFileInterfa
|
|||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
String asString = "[fileId=%s, name=%s, mime=%s, downloaded=%s, local=%s, remote=%s, " +
|
||||
"parentId=%s, availableOffline=%s etag=%s favourite=%s]";
|
||||
return String.format(asString, fileId, getFileName(), mimeType, isDown(),
|
||||
localPath, remotePath, parentId, availableOffline,
|
||||
String asString = "[id=%s, name=%s, mime=%s, downloaded=%s, local=%s, remote=%s, " +
|
||||
"parentId=%s, etag=%s, favourite=%s]";
|
||||
return String.format(asString, fileId, getFileName(), mimeType, isDown(), localPath, remotePath, parentId,
|
||||
etag, favorite);
|
||||
}
|
||||
|
||||
|
@ -469,6 +462,10 @@ public class OCFile implements Parcelable, Comparable<OCFile>, ServerFileInterfa
|
|||
this.etag = etag != null ? etag : "";
|
||||
}
|
||||
|
||||
public void setEtagOnServer(String etag) {
|
||||
this.etagOnServer = etag != null ? etag : "";
|
||||
}
|
||||
|
||||
public long getLocalModificationTimestamp() {
|
||||
if (localPath != null && localPath.length() > 0) {
|
||||
File f = new File(localPath);
|
||||
|
|
|
@ -32,7 +32,7 @@ import com.owncloud.android.MainApp;
|
|||
public class ProviderMeta {
|
||||
|
||||
public static final String DB_NAME = "filelist";
|
||||
public static final int DB_VERSION = 40;
|
||||
public static final int DB_VERSION = 41;
|
||||
|
||||
private ProviderMeta() {
|
||||
}
|
||||
|
@ -92,6 +92,7 @@ public class ProviderMeta {
|
|||
public static final String FILE_LAST_SYNC_DATE_FOR_DATA = "last_sync_date_for_data";
|
||||
public static final String FILE_KEEP_IN_SYNC = "keep_in_sync";
|
||||
public static final String FILE_ETAG = "etag";
|
||||
public static final String FILE_ETAG_ON_SERVER = "etag_on_server";
|
||||
public static final String FILE_SHARED_VIA_LINK = "share_by_link";
|
||||
public static final String FILE_SHARED_WITH_SHAREE = "shared_via_users";
|
||||
public static final String FILE_PUBLIC_LINK = "public_link";
|
||||
|
@ -109,10 +110,11 @@ public class ProviderMeta {
|
|||
public static final String[] FILE_ALL_COLUMNS = {
|
||||
_ID, FILE_PARENT, FILE_NAME, FILE_CREATION, FILE_MODIFIED,
|
||||
FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, FILE_CONTENT_LENGTH, FILE_CONTENT_TYPE, FILE_STORAGE_PATH,
|
||||
FILE_PATH, FILE_ACCOUNT_OWNER, FILE_LAST_SYNC_DATE, FILE_LAST_SYNC_DATE_FOR_DATA, FILE_KEEP_IN_SYNC,
|
||||
FILE_ETAG, FILE_SHARED_VIA_LINK, FILE_SHARED_WITH_SHAREE, FILE_PUBLIC_LINK, FILE_PERMISSIONS,
|
||||
FILE_PATH, FILE_ACCOUNT_OWNER, FILE_LAST_SYNC_DATE, FILE_LAST_SYNC_DATE_FOR_DATA, FILE_ETAG,
|
||||
FILE_ETAG_ON_SERVER, FILE_SHARED_VIA_LINK, FILE_SHARED_WITH_SHAREE, FILE_PUBLIC_LINK, FILE_PERMISSIONS,
|
||||
FILE_REMOTE_ID, FILE_UPDATE_THUMBNAIL, FILE_IS_DOWNLOADING, FILE_ETAG_IN_CONFLICT, FILE_FAVORITE,
|
||||
FILE_IS_ENCRYPTED, FILE_MOUNT_TYPE, FILE_HAS_PREVIEW, FILE_UNREAD_COMMENTS_COUNT};
|
||||
FILE_IS_ENCRYPTED, FILE_MOUNT_TYPE, FILE_HAS_PREVIEW, FILE_UNREAD_COMMENTS_COUNT
|
||||
};
|
||||
|
||||
public static final String FILE_DEFAULT_SORT_ORDER = FILE_NAME + " collate nocase asc";
|
||||
|
||||
|
|
|
@ -178,8 +178,6 @@ public class FileMenuFilter {
|
|||
filterSync(toShow, toHide, synchronizing);
|
||||
filterShareFile(toShow, toHide, capability);
|
||||
filterDetails(toShow, toHide);
|
||||
filterKeepAvailableOffline(toShow, toHide, synchronizing);
|
||||
filterDontKeepAvailableOffline(toShow, toHide, synchronizing);
|
||||
filterFavorite(toShow, toHide, synchronizing);
|
||||
filterUnfavorite(toShow, toHide, synchronizing);
|
||||
filterEncrypt(toShow, toHide, endToEndEncryptionEnabled);
|
||||
|
@ -207,22 +205,6 @@ public class FileMenuFilter {
|
|||
}
|
||||
}
|
||||
|
||||
private void filterKeepAvailableOffline(List<Integer> toShow, List<Integer> toHide, boolean synchronizing) {
|
||||
if (!allFiles() || synchronizing || allKeptAvailableOffline()) {
|
||||
toHide.add(R.id.action_keep_files_offline);
|
||||
} else {
|
||||
toShow.add(R.id.action_keep_files_offline);
|
||||
}
|
||||
}
|
||||
|
||||
private void filterDontKeepAvailableOffline(List<Integer> toShow, List<Integer> toHide, boolean synchronizing) {
|
||||
if (!allFiles() || synchronizing || allNotKeptAvailableOffline()) {
|
||||
toHide.add(R.id.action_unset_keep_files_offline);
|
||||
} else {
|
||||
toShow.add(R.id.action_unset_keep_files_offline);
|
||||
}
|
||||
}
|
||||
|
||||
private void filterFavorite(List<Integer> toShow, List<Integer> toHide, boolean synchronizing) {
|
||||
if (mFiles.isEmpty() || synchronizing || allFavorites()) {
|
||||
toHide.add(R.id.action_favorite);
|
||||
|
@ -497,15 +479,6 @@ public class FileMenuFilter {
|
|||
return false;
|
||||
}
|
||||
|
||||
private boolean allKeptAvailableOffline() {
|
||||
for (OCFile file : mFiles) {
|
||||
if (!file.isAvailableOffline()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean allFavorites() {
|
||||
for (OCFile file : mFiles) {
|
||||
if (!file.isFavorite()) {
|
||||
|
@ -523,13 +496,4 @@ public class FileMenuFilter {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean allNotKeptAvailableOffline() {
|
||||
for (OCFile file : mFiles) {
|
||||
if (file.isAvailableOffline()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,8 +21,6 @@ package com.owncloud.android.jobs;
|
|||
|
||||
import android.accounts.Account;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.os.Build;
|
||||
import android.os.PowerManager;
|
||||
|
||||
|
@ -34,15 +32,15 @@ import com.owncloud.android.MainApp;
|
|||
import com.owncloud.android.authentication.AccountUtils;
|
||||
import com.owncloud.android.datamodel.FileDataStorageManager;
|
||||
import com.owncloud.android.datamodel.OCFile;
|
||||
import com.owncloud.android.db.ProviderMeta;
|
||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.lib.resources.files.CheckEtagRemoteOperation;
|
||||
import com.owncloud.android.operations.SynchronizeFileOperation;
|
||||
import com.owncloud.android.ui.activity.ConflictsResolveActivity;
|
||||
import com.owncloud.android.utils.ConnectivityUtils;
|
||||
import com.owncloud.android.utils.FileStorageUtils;
|
||||
import com.owncloud.android.utils.PowerUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.io.File;
|
||||
import java.util.Set;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
@ -51,12 +49,11 @@ public class OfflineSyncJob extends Job {
|
|||
public static final String TAG = "OfflineSyncJob";
|
||||
|
||||
private static final String WAKELOCK_TAG_SEPARATION = ":";
|
||||
private List<OfflineFile> offlineFileList = new ArrayList<>();
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Result onRunJob(@NonNull Params params) {
|
||||
final Context context = MainApp.getAppContext();
|
||||
final Context context = getContext();
|
||||
|
||||
PowerManager.WakeLock wakeLock = null;
|
||||
if (!PowerUtils.isPowerSaveMode(context) &&
|
||||
|
@ -71,58 +68,27 @@ public class OfflineSyncJob extends Job {
|
|||
|
||||
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
|
||||
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, MainApp.getAuthority() +
|
||||
|
||||
if (powerManager != null) {
|
||||
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, MainApp.getAuthority() +
|
||||
WAKELOCK_TAG_SEPARATION + TAG);
|
||||
wakeLock.acquire(10 * 60 * 1000);
|
||||
wakeLock.acquire(10 * 60 * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
Cursor cursorOnKeptInSync = context.getContentResolver().query(
|
||||
ProviderMeta.ProviderTableMeta.CONTENT_URI,
|
||||
null,
|
||||
ProviderMeta.ProviderTableMeta.FILE_KEEP_IN_SYNC + " = ?",
|
||||
new String[]{String.valueOf(1)},
|
||||
null
|
||||
);
|
||||
Account[] accounts = AccountUtils.getAccounts(context);
|
||||
|
||||
if (cursorOnKeptInSync != null) {
|
||||
if (cursorOnKeptInSync.moveToFirst()) {
|
||||
for (Account account : accounts) {
|
||||
FileDataStorageManager storageManager = new FileDataStorageManager(account,
|
||||
getContext().getContentResolver());
|
||||
|
||||
String localPath;
|
||||
String accountName;
|
||||
Account account;
|
||||
do {
|
||||
localPath = cursorOnKeptInSync.getString(cursorOnKeptInSync
|
||||
.getColumnIndex(ProviderMeta.ProviderTableMeta.FILE_STORAGE_PATH));
|
||||
accountName = cursorOnKeptInSync.getString(cursorOnKeptInSync
|
||||
.getColumnIndex(ProviderMeta.ProviderTableMeta.FILE_ACCOUNT_OWNER));
|
||||
|
||||
account = new Account(accountName, MainApp.getAccountType(getContext()));
|
||||
if (!AccountUtils.exists(account, context) || localPath == null || localPath.length() <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
offlineFileList.add(new OfflineFile(localPath, account));
|
||||
|
||||
} while (cursorOnKeptInSync.moveToNext());
|
||||
OCFile ocRoot = storageManager.getFileByPath("/");
|
||||
|
||||
if (ocRoot.getStoragePath() == null) {
|
||||
break;
|
||||
}
|
||||
cursorOnKeptInSync.close();
|
||||
}
|
||||
|
||||
FileDataStorageManager storageManager;
|
||||
for (OfflineFile offlineFile : offlineFileList) {
|
||||
storageManager = new FileDataStorageManager(offlineFile.getAccount(), context.getContentResolver());
|
||||
OCFile file = storageManager.getFileByLocalPath(offlineFile.getLocalPath());
|
||||
SynchronizeFileOperation sfo =
|
||||
new SynchronizeFileOperation(file, null, offlineFile.getAccount(), true, context);
|
||||
RemoteOperationResult result = sfo.execute(storageManager, context);
|
||||
if (result.getCode() == RemoteOperationResult.ResultCode.SYNC_CONFLICT) {
|
||||
Intent i = new Intent(context, ConflictsResolveActivity.class);
|
||||
i.setFlags(i.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
i.putExtra(ConflictsResolveActivity.EXTRA_FILE, file);
|
||||
i.putExtra(ConflictsResolveActivity.EXTRA_ACCOUNT, offlineFile.getAccount());
|
||||
context.startActivity(i);
|
||||
}
|
||||
recursive(new File(ocRoot.getStoragePath()), storageManager, account);
|
||||
}
|
||||
|
||||
if (wakeLock != null) {
|
||||
|
@ -133,30 +99,72 @@ public class OfflineSyncJob extends Job {
|
|||
return Result.SUCCESS;
|
||||
}
|
||||
|
||||
private void recursive(File folder, FileDataStorageManager storageManager, Account account) {
|
||||
String downloadFolder = FileStorageUtils.getSavePath(account.name);
|
||||
String folderName = folder.getAbsolutePath().replaceFirst(downloadFolder, "") + "/";
|
||||
Log_OC.d(TAG, folderName + ": enter");
|
||||
|
||||
private class OfflineFile {
|
||||
private String localPath;
|
||||
private Account account;
|
||||
|
||||
private OfflineFile(String localPath, Account account) {
|
||||
this.localPath = localPath;
|
||||
this.account = account;
|
||||
// exit
|
||||
if (folder.listFiles() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
public String getLocalPath() {
|
||||
return localPath;
|
||||
OCFile ocFolder = storageManager.getFileByPath(folderName);
|
||||
Log_OC.d(TAG, folderName + ": currentEtag: " + ocFolder.getEtag());
|
||||
|
||||
// check for etag change, if false, skip
|
||||
CheckEtagRemoteOperation checkEtagOperation = new CheckEtagRemoteOperation(ocFolder.getRemotePath(),
|
||||
ocFolder.getEtagOnServer());
|
||||
RemoteOperationResult result = checkEtagOperation.execute(account, getContext());
|
||||
|
||||
// eTag changed, sync file
|
||||
switch (result.getCode()) {
|
||||
case ETAG_UNCHANGED:
|
||||
Log_OC.d(TAG, folderName + ": eTag unchanged");
|
||||
return;
|
||||
|
||||
case FILE_NOT_FOUND:
|
||||
boolean removalResult = storageManager.removeFolder(ocFolder, true, true);
|
||||
if (!removalResult) {
|
||||
Log_OC.e(TAG, "removal of " + ocFolder.getStoragePath() + " failed: file not found");
|
||||
}
|
||||
return;
|
||||
|
||||
default:
|
||||
case ETAG_CHANGED:
|
||||
Log_OC.d(TAG, folderName + ": eTag changed");
|
||||
break;
|
||||
}
|
||||
|
||||
public void setLocalPath(String localPath) {
|
||||
this.localPath = localPath;
|
||||
// iterate over downloaded files
|
||||
File[] files = folder.listFiles(File::isFile);
|
||||
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
OCFile ocFile = storageManager.getFileByLocalPath(file.getPath());
|
||||
SynchronizeFileOperation synchronizeFileOperation = new SynchronizeFileOperation(ocFile.getRemotePath(),
|
||||
account, true, getContext());
|
||||
|
||||
synchronizeFileOperation.execute(storageManager, getContext());
|
||||
}
|
||||
}
|
||||
|
||||
public Account getAccount() {
|
||||
return account;
|
||||
// recursive into folder
|
||||
File[] subfolders = folder.listFiles(File::isDirectory);
|
||||
|
||||
if (subfolders != null) {
|
||||
for (File subfolder : subfolders) {
|
||||
recursive(subfolder, storageManager, account);
|
||||
}
|
||||
}
|
||||
|
||||
public void setAccount(Account account) {
|
||||
this.account = account;
|
||||
// update eTag
|
||||
try {
|
||||
String updatedEtag = (String) result.getData().get(0);
|
||||
ocFolder.setEtagOnServer(updatedEtag);
|
||||
storageManager.saveFile(ocFolder);
|
||||
} catch (Exception e) {
|
||||
Log_OC.e(TAG, "Failed to update etag on " + folder.getAbsolutePath(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -196,7 +196,6 @@ public class RefreshFolderOperation extends RemoteOperation {
|
|||
if (mRemoteFolderChanged) {
|
||||
result = fetchAndSyncRemoteFolder(client);
|
||||
} else {
|
||||
fetchKeptInSyncFilesToSyncFromLocalData();
|
||||
mChildren = mStorageManager.getFolderContent(mLocalFolder, false);
|
||||
}
|
||||
|
||||
|
@ -399,13 +398,6 @@ public class RefreshFolderOperation extends RemoteOperation {
|
|||
// check and fix, if needed, local storage path
|
||||
FileStorageUtils.searchForLocalFileInDefaultPath(updatedFile, mAccount);
|
||||
|
||||
// prepare content synchronization for kept-in-sync files
|
||||
if (updatedFile.isAvailableOffline()) {
|
||||
mFilesToSyncContents.add(
|
||||
new SynchronizeFileOperation(localFile, remoteFile, mAccount, true, mContext)
|
||||
);
|
||||
}
|
||||
|
||||
// update file name for encrypted files
|
||||
if (metadata != null) {
|
||||
updateFileNameForEncryptedFile(metadata, updatedFile);
|
||||
|
@ -456,7 +448,6 @@ public class RefreshFolderOperation extends RemoteOperation {
|
|||
private void setLocalFileDataOnUpdatedFile(OCFile remoteFile, OCFile localFile, OCFile updatedFile, boolean remoteFolderChanged) {
|
||||
if (localFile != null) {
|
||||
updatedFile.setFileId(localFile.getFileId());
|
||||
updatedFile.setAvailableOffline(localFile.isAvailableOffline());
|
||||
updatedFile.setLastSyncDateForData(localFile.getLastSyncDateForData());
|
||||
updatedFile.setModificationTimestampAtLastSyncForData(
|
||||
localFile.getModificationTimestampAtLastSyncForData()
|
||||
|
@ -488,6 +479,9 @@ public class RefreshFolderOperation extends RemoteOperation {
|
|||
// remote eTag will not be updated unless file CONTENTS are synchronized
|
||||
updatedFile.setEtag("");
|
||||
}
|
||||
|
||||
// eTag on Server is used for thumbnail validation
|
||||
updatedFile.setEtagOnServer(remoteFile.getEtag());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
@ -592,24 +586,5 @@ public class RefreshFolderOperation extends RemoteOperation {
|
|||
|
||||
intent.setPackage(mContext.getPackageName());
|
||||
mContext.sendStickyBroadcast(intent);
|
||||
//LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent);
|
||||
}
|
||||
|
||||
|
||||
private void fetchKeptInSyncFilesToSyncFromLocalData() {
|
||||
List<OCFile> children = mStorageManager.getFolderContent(mLocalFolder, false);
|
||||
for (OCFile child : children) {
|
||||
if (!child.isFolder() && child.isAvailableOffline() && !child.isInConflict()) {
|
||||
SynchronizeFileOperation operation = new SynchronizeFileOperation(
|
||||
child,
|
||||
child, // cheating with the remote file to get an update to server; to refactor
|
||||
mAccount,
|
||||
true,
|
||||
mContext
|
||||
);
|
||||
mFilesToSyncContents.add(operation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -246,7 +246,6 @@ public class SynchronizeFileOperation extends SyncOperation {
|
|||
} else {
|
||||
// TODO CHECK: is this really useful in some point in the code?
|
||||
mServerFile.setFavorite(mLocalFile.isFavorite());
|
||||
mServerFile.setAvailableOffline(mLocalFile.isAvailableOffline());
|
||||
mServerFile.setLastSyncDateForData(mLocalFile.getLastSyncDateForData());
|
||||
mServerFile.setStoragePath(mLocalFile.getStoragePath());
|
||||
mServerFile.setParentId(mLocalFile.getParentId());
|
||||
|
@ -265,6 +264,13 @@ public class SynchronizeFileOperation extends SyncOperation {
|
|||
if (result.getCode() != ResultCode.SYNC_CONFLICT) {
|
||||
getStorageManager().saveConflict(mLocalFile, null);
|
||||
}
|
||||
} else {
|
||||
// remote file does not exist, deleting local copy
|
||||
boolean deleteResult = getStorageManager().removeFile(mLocalFile, true, true);
|
||||
|
||||
if (!deleteResult) {
|
||||
Log_OC.e(TAG, "Removal of local copy failed (remote file does not exist any longer).");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -308,7 +308,6 @@ public class SynchronizeFolderOperation extends SyncOperation {
|
|||
updatedFile.setLastSyncDateForProperties(mCurrentSyncTime);
|
||||
if (localFile != null) {
|
||||
updatedFile.setFileId(localFile.getFileId());
|
||||
updatedFile.setAvailableOffline(localFile.isAvailableOffline());
|
||||
updatedFile.setLastSyncDateForData(localFile.getLastSyncDateForData());
|
||||
updatedFile.setModificationTimestampAtLastSyncForData(
|
||||
localFile.getModificationTimestampAtLastSyncForData()
|
||||
|
|
|
@ -1055,7 +1055,6 @@ public class UploadFileOperation extends SyncOperation {
|
|||
mFile.getModificationTimestampAtLastSyncForData()
|
||||
);
|
||||
newFile.setEtag(mFile.getEtag());
|
||||
newFile.setAvailableOffline(mFile.isAvailableOffline());
|
||||
newFile.setLastSyncDateForProperties(mFile.getLastSyncDateForProperties());
|
||||
newFile.setLastSyncDateForData(mFile.getLastSyncDateForData());
|
||||
newFile.setStoragePath(mFile.getStoragePath());
|
||||
|
|
|
@ -735,15 +735,15 @@ public class FileContentProvider extends ContentProvider {
|
|||
+ ProviderTableMeta.FILE_STORAGE_PATH + TEXT
|
||||
+ ProviderTableMeta.FILE_ACCOUNT_OWNER + TEXT
|
||||
+ ProviderTableMeta.FILE_LAST_SYNC_DATE + INTEGER
|
||||
+ ProviderTableMeta.FILE_KEEP_IN_SYNC + INTEGER
|
||||
+ ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + INTEGER
|
||||
+ ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + INTEGER
|
||||
+ ProviderTableMeta.FILE_ETAG + TEXT
|
||||
+ ProviderTableMeta.FILE_ETAG_ON_SERVER + TEXT
|
||||
+ ProviderTableMeta.FILE_SHARED_VIA_LINK + INTEGER
|
||||
+ ProviderTableMeta.FILE_PUBLIC_LINK + TEXT
|
||||
+ ProviderTableMeta.FILE_PERMISSIONS + " TEXT null,"
|
||||
+ ProviderTableMeta.FILE_REMOTE_ID + " TEXT null,"
|
||||
+ ProviderTableMeta.FILE_UPDATE_THUMBNAIL + INTEGER //boolean
|
||||
+ ProviderTableMeta.FILE_UPDATE_THUMBNAIL + INTEGER //boolean
|
||||
+ ProviderTableMeta.FILE_IS_DOWNLOADING + INTEGER //boolean
|
||||
+ ProviderTableMeta.FILE_FAVORITE + INTEGER // boolean
|
||||
+ ProviderTableMeta.FILE_IS_ENCRYPTED + INTEGER // boolean
|
||||
|
@ -1863,6 +1863,24 @@ public class FileContentProvider extends ContentProvider {
|
|||
if (!upgraded) {
|
||||
Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion));
|
||||
}
|
||||
|
||||
if (oldVersion < 41 && newVersion >= 41) {
|
||||
Log_OC.i(SQL, "Entering in the #41 add eTagOnServer");
|
||||
db.beginTransaction();
|
||||
try {
|
||||
db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME +
|
||||
ADD_COLUMN + ProviderTableMeta.FILE_ETAG_ON_SERVER + " TEXT ");
|
||||
|
||||
upgraded = true;
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
if (!upgraded) {
|
||||
Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -440,7 +440,6 @@ public class LocalFileListAdapter extends RecyclerView.Adapter<RecyclerView.View
|
|||
|
||||
itemView.findViewById(R.id.sharedIcon).setVisibility(View.GONE);
|
||||
itemView.findViewById(R.id.favorite_action).setVisibility(View.GONE);
|
||||
itemView.findViewById(R.id.keptOfflineIcon).setVisibility(View.GONE);
|
||||
itemView.findViewById(R.id.localFileIndicator).setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -359,7 +359,6 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
|
|||
}
|
||||
|
||||
gridViewHolder.favorite.setVisibility(file.isFavorite() ? View.VISIBLE : View.GONE);
|
||||
gridViewHolder.offlineIcon.setVisibility(file.isAvailableOffline() ? View.VISIBLE : View.GONE);
|
||||
|
||||
if (multiSelect) {
|
||||
gridViewHolder.checkbox.setVisibility(View.VISIBLE);
|
||||
|
@ -848,7 +847,6 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
|
|||
static class OCFileListGridImageViewHolder extends RecyclerView.ViewHolder {
|
||||
private final ImageView thumbnail;
|
||||
private final ImageView favorite;
|
||||
private final ImageView offlineIcon;
|
||||
private final ImageView localFileIndicator;
|
||||
private final ImageView shared;
|
||||
private final ImageView checkbox;
|
||||
|
@ -860,7 +858,6 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
|
|||
|
||||
thumbnail = itemView.findViewById(R.id.thumbnail);
|
||||
favorite = itemView.findViewById(R.id.favorite_action);
|
||||
offlineIcon = itemView.findViewById(R.id.keptOfflineIcon);
|
||||
localFileIndicator = itemView.findViewById(R.id.localFileIndicator);
|
||||
shared = itemView.findViewById(R.id.sharedIcon);
|
||||
checkbox = itemView.findViewById(R.id.custom_checkbox);
|
||||
|
|
|
@ -79,7 +79,7 @@ public class RemoveFilesDialogFragment extends ConfirmationDialogFragment implem
|
|||
for (OCFile file: files) {
|
||||
containsFolder |= file.isFolder();
|
||||
containsDown |= file.isDown();
|
||||
containsFavorite |= file.isAvailableOffline();
|
||||
containsFavorite |= file.isFavorite();
|
||||
}
|
||||
|
||||
if (files.size() == SINGLE_SELECTION) {
|
||||
|
|
|
@ -419,14 +419,6 @@ public class FileDetailFragment extends FileFragment implements OnClickListener
|
|||
mContainerActivity.getFileOperationsHelper().syncFile(getFile());
|
||||
return true;
|
||||
}
|
||||
case R.id.action_keep_files_offline: {
|
||||
mContainerActivity.getFileOperationsHelper().toggleOfflineFile(getFile(), true);
|
||||
return true;
|
||||
}
|
||||
case R.id.action_unset_keep_files_offline: {
|
||||
mContainerActivity.getFileOperationsHelper().toggleOfflineFile(getFile(), false);
|
||||
return true;
|
||||
}
|
||||
case R.id.action_encrypted: {
|
||||
// TODO implement or remove
|
||||
return true;
|
||||
|
|
|
@ -1030,16 +1030,6 @@ public class OCFileListFragment extends ExtendedListFragment implements
|
|||
((FileDisplayActivity) mContainerActivity).cancelTransference(checkedFiles);
|
||||
return true;
|
||||
}
|
||||
case R.id.action_keep_files_offline: {
|
||||
mContainerActivity.getFileOperationsHelper().toggleOfflineFiles(checkedFiles, true);
|
||||
exitSelectionMode();
|
||||
return true;
|
||||
}
|
||||
case R.id.action_unset_keep_files_offline: {
|
||||
mContainerActivity.getFileOperationsHelper().toggleOfflineFiles(checkedFiles, false);
|
||||
exitSelectionMode();
|
||||
return true;
|
||||
}
|
||||
case R.id.action_favorite: {
|
||||
mContainerActivity.getFileOperationsHelper().toggleFavoriteFiles(checkedFiles, true);
|
||||
return true;
|
||||
|
|
|
@ -834,34 +834,6 @@ public class FileOperationsHelper {
|
|||
}
|
||||
}
|
||||
|
||||
public void toggleOfflineFiles(Collection<OCFile> files, boolean isAvailableOffline) {
|
||||
List<OCFile> alreadyRightStateList = new ArrayList<>();
|
||||
for (OCFile file : files) {
|
||||
if (file.isAvailableOffline() == isAvailableOffline) {
|
||||
alreadyRightStateList.add(file);
|
||||
}
|
||||
}
|
||||
|
||||
files.removeAll(alreadyRightStateList);
|
||||
|
||||
for (OCFile file : files) {
|
||||
toggleOfflineFile(file, isAvailableOffline);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void toggleOfflineFile(OCFile file, boolean isAvailableOffline) {
|
||||
if (file.isAvailableOffline() != isAvailableOffline) {
|
||||
file.setAvailableOffline(isAvailableOffline);
|
||||
mFileActivity.getStorageManager().saveFile(file);
|
||||
|
||||
/// immediate content synchronization
|
||||
if (file.isAvailableOffline()) {
|
||||
syncFile(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void renameFile(OCFile file, String newFilename) {
|
||||
// RenameFile
|
||||
Intent service = new Intent(mFileActivity, OperationsService.class);
|
||||
|
|
|
@ -261,10 +261,10 @@ public final class FilesSyncHelper {
|
|||
Set<JobRequest> jobRequests = JobManager.instance().getAllJobRequestsForTag(OfflineSyncJob.TAG);
|
||||
if (jobRequests.isEmpty()) {
|
||||
new JobRequest.Builder(OfflineSyncJob.TAG)
|
||||
.setPeriodic(TimeUnit.MINUTES.toMillis(15), TimeUnit.MINUTES.toMillis(5))
|
||||
.setUpdateCurrent(false)
|
||||
.build()
|
||||
.schedule();
|
||||
.setPeriodic(TimeUnit.MINUTES.toMillis(15), TimeUnit.MINUTES.toMillis(5))
|
||||
.setUpdateCurrent(false)
|
||||
.build()
|
||||
.schedule();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 532 B |
Binary file not shown.
Before Width: | Height: | Size: 434 B |
Binary file not shown.
Before Width: | Height: | Size: 572 B |
Binary file not shown.
Before Width: | Height: | Size: 685 B |
|
@ -85,17 +85,6 @@
|
|||
android:contentDescription="@string/synced_icon"
|
||||
android:src="@drawable/ic_synced" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/keptOfflineIcon"
|
||||
android:layout_width="@dimen/grid_image_kept_offline_icon_layout_width"
|
||||
android:layout_height="@dimen/grid_image_kept_offline_icon_layout_height"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_marginBottom="@dimen/standard_quarter_margin"
|
||||
android:layout_marginEnd="@dimen/grid_image_kept_offline_icon_layout_right_end_margin"
|
||||
android:layout_marginRight="@dimen/grid_image_kept_offline_icon_layout_right_end_margin"
|
||||
android:contentDescription="@string/available_offline_icon"
|
||||
android:src="@drawable/ic_available_offline" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/custom_checkbox"
|
||||
android:layout_width="wrap_content"
|
||||
|
|
|
@ -83,17 +83,6 @@
|
|||
android:src="@drawable/ic_synced"
|
||||
android:contentDescription="@string/synced_icon"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/keptOfflineIcon"
|
||||
android:layout_width="@dimen/grid_item_kept_offline_icon_layout_width"
|
||||
android:layout_height="@dimen/grid_item_kept_offline_icon_layout_height"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_marginBottom="@dimen/standard_quarter_margin"
|
||||
android:layout_marginRight="@dimen/grid_item_kept_offline_icon_layout_right_end_margin"
|
||||
android:layout_marginEnd="@dimen/grid_item_kept_offline_icon_layout_right_end_margin"
|
||||
android:src="@drawable/ic_available_offline"
|
||||
android:contentDescription="@string/available_offline_icon"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/custom_checkbox"
|
||||
android:layout_width="wrap_content"
|
||||
|
|
|
@ -1,220 +1,208 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><!--
|
||||
ownCloud Android client application
|
||||
|
||||
Copyright (C) 2012 Bartek Przybylski
|
||||
Copyright (C) 2015 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/>.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/ListItemLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/standard_list_item_size"
|
||||
android:background="@drawable/list_selector"
|
||||
android:descendantFocusability="blocksDescendants"
|
||||
android:foreground="?android:attr/selectableItemBackground"
|
||||
android:baselineAligned="false"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="@dimen/standard_list_item_size"
|
||||
android:layout_height="@dimen/standard_list_item_size"
|
||||
android:paddingBottom="@dimen/standard_padding"
|
||||
android:paddingEnd="@dimen/standard_quarter_padding"
|
||||
android:paddingLeft="@dimen/zero"
|
||||
android:paddingRight="@dimen/standard_quarter_padding"
|
||||
android:paddingStart="@dimen/zero"
|
||||
android:paddingTop="@dimen/standard_padding">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/thumbnail"
|
||||
android:layout_width="@dimen/file_icon_size"
|
||||
android:layout_height="@dimen/file_icon_size"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_marginLeft="@dimen/standard_half_margin"
|
||||
android:layout_marginStart="@dimen/standard_half_margin"
|
||||
android:contentDescription="@null"
|
||||
android:src="@drawable/folder" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/favorite_action"
|
||||
android:layout_width="@dimen/list_item_favorite_action_layout_width"
|
||||
android:layout_height="@dimen/list_item_favorite_action_layout_height"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginEnd="@dimen/standard_quarter_margin"
|
||||
android:layout_marginRight="@dimen/standard_quarter_margin"
|
||||
android:contentDescription="@string/favorite"
|
||||
android:src="@drawable/badge_favorite" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/keptOfflineIcon"
|
||||
android:layout_width="@dimen/list_item_kept_offline_icon_layout_width"
|
||||
android:layout_height="@dimen/list_item_kept_offline_icon_layout_height"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginEnd="@dimen/list_item_kept_offline_icon_layout_right_end_margin"
|
||||
android:layout_marginRight="@dimen/list_item_kept_offline_icon_layout_right_end_margin"
|
||||
android:contentDescription="@string/available_offline_icon"
|
||||
android:src="@drawable/ic_available_offline" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/localFileIndicator"
|
||||
android:layout_width="@dimen/list_item_local_file_indicator_layout_width"
|
||||
android:layout_height="@dimen/list_item_local_file_indicator_layout_height"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginEnd="@dimen/standard_quarter_margin"
|
||||
android:layout_marginRight="@dimen/standard_quarter_margin"
|
||||
android:contentDescription="@string/downloader_download_succeeded_ticker"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/ic_synced" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:gravity="top"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="@dimen/standard_padding">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/Filename"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:ellipsize="middle"
|
||||
android:singleLine="true"
|
||||
android:text="@string/placeholder_filename"
|
||||
android:textColor="@color/textColor"
|
||||
android:textSize="@dimen/two_line_primary_text_size" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/file_size"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/placeholder_fileSize"
|
||||
android:textColor="@color/list_item_lastmod_and_filesize_text"
|
||||
android:textSize="@dimen/two_line_secondary_text_size" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/file_separator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
android:paddingEnd="@dimen/standard_quarter_padding"
|
||||
android:paddingLeft="@dimen/zero"
|
||||
android:paddingRight="@dimen/standard_quarter_padding"
|
||||
android:paddingStart="@dimen/zero"
|
||||
android:text="@string/info_separator"
|
||||
android:textColor="@color/list_item_lastmod_and_filesize_text"
|
||||
android:textSize="@dimen/two_line_secondary_text_size" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/last_mod"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
android:text="@string/placeholder_media_time"
|
||||
android:textColor="@color/list_item_lastmod_and_filesize_text"
|
||||
android:textSize="@dimen/two_line_secondary_text_size" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:paddingEnd="@dimen/zero"
|
||||
android:paddingLeft="@dimen/standard_half_padding"
|
||||
android:paddingRight="@dimen/zero"
|
||||
android:paddingStart="@dimen/standard_half_padding">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/unreadComments"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_centerVertical="true"
|
||||
android:clickable="true"
|
||||
android:contentDescription="@string/unread_comments"
|
||||
android:focusable="true"
|
||||
android:paddingEnd="@dimen/list_item_share_right_margin"
|
||||
android:paddingLeft="@dimen/standard_half_padding"
|
||||
android:paddingRight="@dimen/list_item_share_right_margin"
|
||||
android:paddingStart="@dimen/standard_half_padding"
|
||||
android:src="@drawable/ic_comment"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/sharedIcon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toEndOf="@id/unreadComments"
|
||||
android:layout_toRightOf="@id/unreadComments"
|
||||
android:clickable="true"
|
||||
android:contentDescription="@string/shared_icon_share"
|
||||
android:focusable="true"
|
||||
android:paddingEnd="@dimen/list_item_share_right_margin"
|
||||
android:paddingLeft="@dimen/standard_half_padding"
|
||||
android:paddingRight="@dimen/list_item_share_right_margin"
|
||||
android:paddingStart="@dimen/standard_half_padding"
|
||||
android:src="@drawable/ic_unshared" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/custom_checkbox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toEndOf="@id/sharedIcon"
|
||||
android:layout_toRightOf="@id/sharedIcon"
|
||||
android:clickable="false"
|
||||
android:contentDescription="@string/checkbox"
|
||||
android:focusable="false"
|
||||
android:paddingEnd="@dimen/alternate_padding"
|
||||
android:paddingLeft="@dimen/standard_half_padding"
|
||||
android:paddingRight="@dimen/alternate_padding"
|
||||
android:paddingStart="@dimen/standard_half_padding"
|
||||
android:src="@drawable/ic_checkbox_blank_outline" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/overflow_menu"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toEndOf="@id/custom_checkbox"
|
||||
android:layout_toRightOf="@id/custom_checkbox"
|
||||
android:clickable="true"
|
||||
android:contentDescription="@string/overflow_menu"
|
||||
android:focusable="true"
|
||||
android:paddingEnd="@dimen/alternate_padding"
|
||||
android:paddingLeft="@dimen/standard_half_padding"
|
||||
android:paddingRight="@dimen/alternate_padding"
|
||||
android:paddingStart="@dimen/standard_half_padding"
|
||||
android:src="@drawable/ic_dots_vertical" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
<?xml version="1.0" encoding="UTF-8"?><!--
|
||||
ownCloud Android client application
|
||||
|
||||
Copyright (C) 2012 Bartek Przybylski
|
||||
Copyright (C) 2015 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/>.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/ListItemLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/standard_list_item_size"
|
||||
android:background="@drawable/list_selector"
|
||||
android:descendantFocusability="blocksDescendants"
|
||||
android:foreground="?android:attr/selectableItemBackground"
|
||||
android:baselineAligned="false"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="@dimen/standard_list_item_size"
|
||||
android:layout_height="@dimen/standard_list_item_size"
|
||||
android:paddingBottom="@dimen/standard_padding"
|
||||
android:paddingEnd="@dimen/standard_quarter_padding"
|
||||
android:paddingLeft="@dimen/zero"
|
||||
android:paddingRight="@dimen/standard_quarter_padding"
|
||||
android:paddingStart="@dimen/zero"
|
||||
android:paddingTop="@dimen/standard_padding">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/thumbnail"
|
||||
android:layout_width="@dimen/file_icon_size"
|
||||
android:layout_height="@dimen/file_icon_size"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_marginLeft="@dimen/standard_half_margin"
|
||||
android:layout_marginStart="@dimen/standard_half_margin"
|
||||
android:contentDescription="@null"
|
||||
android:src="@drawable/folder" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/favorite_action"
|
||||
android:layout_width="@dimen/list_item_favorite_action_layout_width"
|
||||
android:layout_height="@dimen/list_item_favorite_action_layout_height"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginEnd="@dimen/standard_quarter_margin"
|
||||
android:layout_marginRight="@dimen/standard_quarter_margin"
|
||||
android:contentDescription="@string/favorite"
|
||||
android:src="@drawable/badge_favorite" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/localFileIndicator"
|
||||
android:layout_width="@dimen/list_item_local_file_indicator_layout_width"
|
||||
android:layout_height="@dimen/list_item_local_file_indicator_layout_height"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginEnd="@dimen/standard_quarter_margin"
|
||||
android:layout_marginRight="@dimen/standard_quarter_margin"
|
||||
android:contentDescription="@string/downloader_download_succeeded_ticker"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/ic_synced" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:gravity="top"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="@dimen/standard_padding">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/Filename"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:ellipsize="middle"
|
||||
android:singleLine="true"
|
||||
android:text="@string/placeholder_filename"
|
||||
android:textColor="@color/textColor"
|
||||
android:textSize="@dimen/two_line_primary_text_size" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/file_size"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/placeholder_fileSize"
|
||||
android:textColor="@color/list_item_lastmod_and_filesize_text"
|
||||
android:textSize="@dimen/two_line_secondary_text_size" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/file_separator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
android:paddingEnd="@dimen/standard_quarter_padding"
|
||||
android:paddingLeft="@dimen/zero"
|
||||
android:paddingRight="@dimen/standard_quarter_padding"
|
||||
android:paddingStart="@dimen/zero"
|
||||
android:text="@string/info_separator"
|
||||
android:textColor="@color/list_item_lastmod_and_filesize_text"
|
||||
android:textSize="@dimen/two_line_secondary_text_size" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/last_mod"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="end"
|
||||
android:text="@string/placeholder_media_time"
|
||||
android:textColor="@color/list_item_lastmod_and_filesize_text"
|
||||
android:textSize="@dimen/two_line_secondary_text_size" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:paddingEnd="@dimen/zero"
|
||||
android:paddingLeft="@dimen/standard_half_padding"
|
||||
android:paddingRight="@dimen/zero"
|
||||
android:paddingStart="@dimen/standard_half_padding">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/unreadComments"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_centerVertical="true"
|
||||
android:clickable="true"
|
||||
android:contentDescription="@string/unread_comments"
|
||||
android:focusable="true"
|
||||
android:paddingEnd="@dimen/list_item_share_right_margin"
|
||||
android:paddingLeft="@dimen/standard_half_padding"
|
||||
android:paddingRight="@dimen/list_item_share_right_margin"
|
||||
android:paddingStart="@dimen/standard_half_padding"
|
||||
android:src="@drawable/ic_comment"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/sharedIcon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toEndOf="@id/unreadComments"
|
||||
android:layout_toRightOf="@id/unreadComments"
|
||||
android:clickable="true"
|
||||
android:contentDescription="@string/shared_icon_share"
|
||||
android:focusable="true"
|
||||
android:paddingEnd="@dimen/list_item_share_right_margin"
|
||||
android:paddingLeft="@dimen/standard_half_padding"
|
||||
android:paddingRight="@dimen/list_item_share_right_margin"
|
||||
android:paddingStart="@dimen/standard_half_padding"
|
||||
android:src="@drawable/ic_unshared" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/custom_checkbox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toEndOf="@id/sharedIcon"
|
||||
android:layout_toRightOf="@id/sharedIcon"
|
||||
android:clickable="false"
|
||||
android:contentDescription="@string/checkbox"
|
||||
android:focusable="false"
|
||||
android:paddingEnd="@dimen/alternate_padding"
|
||||
android:paddingLeft="@dimen/standard_half_padding"
|
||||
android:paddingRight="@dimen/alternate_padding"
|
||||
android:paddingStart="@dimen/standard_half_padding"
|
||||
android:src="@drawable/ic_checkbox_blank_outline" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/overflow_menu"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toEndOf="@id/custom_checkbox"
|
||||
android:layout_toRightOf="@id/custom_checkbox"
|
||||
android:clickable="true"
|
||||
android:contentDescription="@string/overflow_menu"
|
||||
android:focusable="true"
|
||||
android:paddingEnd="@dimen/alternate_padding"
|
||||
android:paddingLeft="@dimen/standard_half_padding"
|
||||
android:paddingRight="@dimen/alternate_padding"
|
||||
android:paddingStart="@dimen/standard_half_padding"
|
||||
android:src="@drawable/ic_dots_vertical" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
|
|
@ -24,13 +24,13 @@
|
|||
|
||||
<item
|
||||
android:id="@+id/action_favorite"
|
||||
android:title="@string/favorite_real"
|
||||
android:title="@string/favorite"
|
||||
app:showAsAction="never"
|
||||
android:showAsAction="never" />
|
||||
|
||||
|
||||
<item
|
||||
android:id="@+id/action_unset_favorite"
|
||||
android:title="@string/unset_favorite_real"
|
||||
android:title="@string/unset_favorite"
|
||||
app:showAsAction="never"
|
||||
android:showAsAction="never" />
|
||||
|
||||
|
@ -70,7 +70,7 @@
|
|||
app:showAsAction="never"
|
||||
android:showAsAction="never"
|
||||
android:orderInCategory="1"/>
|
||||
|
||||
|
||||
<item
|
||||
android:id="@+id/action_send_share_file"
|
||||
android:title="@string/action_send_share"
|
||||
|
@ -113,18 +113,6 @@
|
|||
app:showAsAction="never"
|
||||
android:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_keep_files_offline"
|
||||
android:title="@string/favorite"
|
||||
app:showAsAction="never"
|
||||
android:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_unset_keep_files_offline"
|
||||
android:title="@string/unfavorite"
|
||||
app:showAsAction="never"
|
||||
android:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_encrypted"
|
||||
android:title="@string/encrypted"
|
||||
|
|
|
@ -53,16 +53,6 @@
|
|||
android:title="@string/common_cancel_sync"
|
||||
app:showAsAction="never"
|
||||
android:showAsAction="never" />
|
||||
<item
|
||||
android:id="@+id/action_keep_files_offline"
|
||||
android:title="@string/favorite"
|
||||
app:showAsAction="never"
|
||||
android:showAsAction="never" />
|
||||
<item
|
||||
android:id="@+id/action_unset_keep_files_offline"
|
||||
android:title="@string/unfavorite"
|
||||
app:showAsAction="never"
|
||||
android:showAsAction="never" />
|
||||
<item
|
||||
android:id="@+id/action_encrypted"
|
||||
android:title="@string/encrypted"
|
||||
|
|
|
@ -114,22 +114,13 @@
|
|||
<dimen name="grid_image_shared_icon_layout_top_margin">24dp</dimen>
|
||||
<dimen name="grid_image_local_file_indicator_layout_width">16dp</dimen>
|
||||
<dimen name="grid_image_local_file_indicator_layout_height">16dp</dimen>
|
||||
<dimen name="grid_image_kept_offline_icon_layout_width">16dp</dimen>
|
||||
<dimen name="grid_image_kept_offline_icon_layout_height">16dp</dimen>
|
||||
<dimen name="grid_image_kept_offline_icon_layout_right_end_margin">24dp</dimen>
|
||||
<dimen name="grid_item_shared_icon_layout_top_margin">24dp</dimen>
|
||||
<dimen name="grid_item_local_file_indicator_layout_width">16dp</dimen>
|
||||
<dimen name="grid_item_local_file_indicator_layout_height">16dp</dimen>
|
||||
<dimen name="grid_item_kept_offline_icon_layout_width">16dp</dimen>
|
||||
<dimen name="grid_item_kept_offline_icon_layout_height">16dp</dimen>
|
||||
<dimen name="grid_item_kept_offline_icon_layout_right_end_margin">24dp</dimen>
|
||||
<dimen name="grid_sync_item_layout_next_text_size">22sp</dimen>
|
||||
<dimen name="grid_sync_item_layout_counter_text_size">22sp</dimen>
|
||||
<dimen name="list_item_favorite_action_layout_width">16dp</dimen>
|
||||
<dimen name="list_item_favorite_action_layout_height">16dp</dimen>
|
||||
<dimen name="list_item_kept_offline_icon_layout_width">12dp</dimen>
|
||||
<dimen name="list_item_kept_offline_icon_layout_height">12dp</dimen>
|
||||
<dimen name="list_item_kept_offline_icon_layout_right_end_margin">20dp</dimen>
|
||||
<dimen name="list_item_local_file_indicator_layout_width">12dp</dimen>
|
||||
<dimen name="list_item_local_file_indicator_layout_height">12dp</dimen>
|
||||
<dimen name="preview_error_image_layout_width">72dp</dimen>
|
||||
|
|
|
@ -268,10 +268,8 @@
|
|||
<string name="auth_access_failed">Access failed: %1$s</string>
|
||||
<string name="auth_illegal_login_used">Illegal login data URL used</string>
|
||||
|
||||
<string name="favorite">Set as available offline</string>
|
||||
<string name="unfavorite">Unset as available offline</string>
|
||||
<string name="favorite_real">Add to favorites</string>
|
||||
<string name="unset_favorite_real">Remove from favourites</string>
|
||||
<string name="favorite">Add to favorites</string>
|
||||
<string name="unset_favorite">Remove from favourites</string>
|
||||
<string name="encrypted">Set as encrypted</string>
|
||||
<string name="unset_encrypted">Unset encryption</string>
|
||||
<string name="common_rename">Rename</string>
|
||||
|
@ -677,7 +675,6 @@
|
|||
<string name="user_icon">User</string>
|
||||
<string name="favorite_icon">Favorite</string>
|
||||
<string name="synced_icon">Synced</string>
|
||||
<string name="available_offline_icon">Available offline</string>
|
||||
<string name="checkbox">Checkbox</string>
|
||||
<string name="shared_icon_share">share</string>
|
||||
<string name="shared_icon_shared_via_link">shared via link</string>
|
||||
|
|
Loading…
Reference in a new issue