Sync all downloaded files in background

Signed-off-by: tobiasKaminsky <tobias@kaminsky.me>
This commit is contained in:
tobiasKaminsky 2018-08-10 15:48:13 +02:00
parent 824a91ad5d
commit 6cf499828c
No known key found for this signature in database
GPG key ID: 0E00D4D47D0C5AF7
30 changed files with 351 additions and 510 deletions

View file

@ -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));

View file

@ -181,7 +181,6 @@ public class MainApp extends MultiDexApplication {
.build()
.schedule();
// register global protection with pass code
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {

View file

@ -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());

View file

@ -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);

View file

@ -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";

View file

@ -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;
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}
}

View file

@ -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).");
}
}
}

View file

@ -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()

View file

@ -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());

View file

@ -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

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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) {

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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

View file

@ -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"

View file

@ -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"

View file

@ -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>

View file

@ -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"

View file

@ -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"

View file

@ -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>

View file

@ -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>