diff --git a/androidTest/java/com/owncloud/android/datamodel/OCFileUnitTest.java b/androidTest/java/com/owncloud/android/datamodel/OCFileUnitTest.java index a66dac922f..725f855553 100644 --- a/androidTest/java/com/owncloud/android/datamodel/OCFileUnitTest.java +++ b/androidTest/java/com/owncloud/android/datamodel/OCFileUnitTest.java @@ -85,7 +85,7 @@ 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.setFavorite(true); + mFile.setAvailableOffline(true); mFile.setEtag(ETAG); mFile.setShareViaLink(true); mFile.setShareWithSharee(true); @@ -120,7 +120,7 @@ public class OCFileUnitTest { ); assertThat(fileReadFromParcel.getLastSyncDateForProperties(), is(LAST_SYNC_DATE_FOR_PROPERTIES)); assertThat(fileReadFromParcel.getLastSyncDateForData(), is(LAST_SYNC_DATE_FOR_DATA)); - assertThat(fileReadFromParcel.isFavorite(), is(true)); + assertThat(fileReadFromParcel.setAvailableOffline(), is(true)); assertThat(fileReadFromParcel.getEtag(), is(ETAG)); assertThat(fileReadFromParcel.isSharedViaLink(), is(true)); assertThat(fileReadFromParcel.isSharedWithSharee(), is(true)); diff --git a/automationTest/src/test/java/com/owncloud/android/test/ui/models/FileListView.java b/automationTest/src/test/java/com/owncloud/android/test/ui/models/FileListView.java index 3c33864e0b..024f251f3f 100644 --- a/automationTest/src/test/java/com/owncloud/android/test/ui/models/FileListView.java +++ b/automationTest/src/test/java/com/owncloud/android/test/ui/models/FileListView.java @@ -89,7 +89,7 @@ public class FileListView { private static String localFileIndicator = "com.owncloud.android:id/localFileIndicator"; private static String favoriteFileIndicator = - "com.owncloud.android:id/favoriteIcon"; + "com.owncloud.android:id/keptOfflineIcon"; private static String sharedElementIndicator = "com.owncloud.android:id/sharedIcon"; diff --git a/build.gradle b/build.gradle index f0c7c4111e..7408ef9ccf 100644 --- a/build.gradle +++ b/build.gradle @@ -23,6 +23,11 @@ apply plugin: 'checkstyle' apply plugin: 'pmd' apply plugin: 'findbugs' +configurations.all { + // check for updates every build + resolutionStrategy.cacheChangingModulesFor 0, 'seconds' +} + ext { supportLibraryVersion = '25.0.0' @@ -173,7 +178,6 @@ dependencies { compile name: 'touch-image-view' compile 'com.android.support:multidex:1.0.1' - compile 'com.github.nextcloud:android-library:1.0.14' compile "com.android.support:support-v4:${supportLibraryVersion}" compile "com.android.support:design:${supportLibraryVersion}" @@ -187,6 +191,10 @@ dependencies { compile 'com.github.evernote:android-job:v1.1.8' compile 'com.jakewharton:butterknife:8.4.0' annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0' + compile 'org.greenrobot:eventbus:3.0.0' + + compile 'org.parceler:parceler-api:1.1.6' + annotationProcessor 'org.parceler:parceler:1.1.6' compile 'com.github.bumptech.glide:glide:3.7.0' compile 'com.caverock:androidsvg:1.2.1' @@ -202,7 +210,7 @@ dependencies { androidTestCompile 'com.android.support.test:runner:0.5' // Android Annotation Support - androidTestCompile "com.android.support:support-annotations:25.0.0" + androidTestCompile "com.android.support:support-annotations:${supportLibraryVersion}" // Espresso core androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2' diff --git a/drawable_resources/ic_list_empty_error.svg b/drawable_resources/ic_list_empty_error.svg new file mode 100644 index 0000000000..0f2a0360be --- /dev/null +++ b/drawable_resources/ic_list_empty_error.svg @@ -0,0 +1,56 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/drawable_resources/ic_list_empty_home.svg b/drawable_resources/ic_list_empty_home.svg new file mode 100644 index 0000000000..aa11e74102 --- /dev/null +++ b/drawable_resources/ic_list_empty_home.svg @@ -0,0 +1,62 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/drawable_resources/ic_list_empty_image.svg b/drawable_resources/ic_list_empty_image.svg new file mode 100644 index 0000000000..bbaa5b6e3f --- /dev/null +++ b/drawable_resources/ic_list_empty_image.svg @@ -0,0 +1,58 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/drawable_resources/ic_list_empty_recent.svg b/drawable_resources/ic_list_empty_recent.svg new file mode 100644 index 0000000000..8a40be5fa5 --- /dev/null +++ b/drawable_resources/ic_list_empty_recent.svg @@ -0,0 +1,62 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/drawable_resources/ic_list_empty_shared.svg b/drawable_resources/ic_list_empty_shared.svg new file mode 100644 index 0000000000..e64e6ab64c --- /dev/null +++ b/drawable_resources/ic_list_empty_shared.svg @@ -0,0 +1,56 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/drawable_resources/ic_list_empty_video.svg b/drawable_resources/ic_list_empty_video.svg new file mode 100644 index 0000000000..b2372ef628 --- /dev/null +++ b/drawable_resources/ic_list_empty_video.svg @@ -0,0 +1,58 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/drawable_resources/ic_star_light_grey.svg b/drawable_resources/ic_star_light_grey.svg new file mode 100644 index 0000000000..f1d57fb690 --- /dev/null +++ b/drawable_resources/ic_star_light_grey.svg @@ -0,0 +1,57 @@ + + + + + + image/svg+xml + + + + + + + + diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 554db405e4..f36e070336 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,4 +1,4 @@ -#Thu Mar 16 17:57:46 CET 2017 +#Wed Mar 15 00:10:20 CET 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/src/main/java/com/owncloud/android/authentication/AccountUtils.java b/src/main/java/com/owncloud/android/authentication/AccountUtils.java index 7a3043bd2e..1f536492f8 100644 --- a/src/main/java/com/owncloud/android/authentication/AccountUtils.java +++ b/src/main/java/com/owncloud/android/authentication/AccountUtils.java @@ -182,6 +182,7 @@ public class AccountUtils { if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).equals(authTokenType)) { return SAML_SSO_PATH; } + return WEBDAV_PATH_4_0_AND_LATER; } return null; @@ -322,14 +323,12 @@ public class AccountUtils { } public static boolean hasSearchUsersSupport(Account account){ - OwnCloudVersion serverVersion = null; - if (account != null) { - AccountManager accountMgr = AccountManager.get(MainApp.getAppContext()); - String serverVersionStr = accountMgr.getUserData(account, Constants.KEY_OC_VERSION); - if (serverVersionStr != null) { - serverVersion = new OwnCloudVersion(serverVersionStr); - } - } - return (serverVersion != null ? serverVersion.isSearchUsersSupported() : false); + OwnCloudVersion serverVersion = getServerVersion(account); + return (serverVersion != null && serverVersion.isSearchUsersSupported()); + } + + public static boolean hasSearchSupport(Account account) { + OwnCloudVersion serverVersion = getServerVersion(account); + return (serverVersion != null && serverVersion.isSearchSupported()); } } diff --git a/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java b/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java index cb33f54b72..f3a71caef7 100644 --- a/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java +++ b/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java @@ -190,7 +190,7 @@ public class FileDataStorageManager { cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.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.isFavorite() ? 1 : 0); + cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.isAvailableOffline() ? 1 : 0); cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag()); cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, file.isSharedViaLink() ? 1 : 0); cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, file.isSharedWithSharee() ? 1 : 0); @@ -303,7 +303,7 @@ public class FileDataStorageManager { cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.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.isFavorite() ? 1 : 0); + cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.isAvailableOffline() ? 1 : 0); cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag()); cv.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, file.isSharedViaLink() ? 1 : 0); cv.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, file.isSharedWithSharee() ? 1 : 0); @@ -313,6 +313,7 @@ public class FileDataStorageManager { cv.put(ProviderTableMeta.FILE_UPDATE_THUMBNAIL, file.needsUpdateThumbnail()); cv.put(ProviderTableMeta.FILE_IS_DOWNLOADING, file.isDownloading()); cv.put(ProviderTableMeta.FILE_ETAG_IN_CONFLICT, file.getEtagInConflict()); + cv.put(ProviderTableMeta.FILE_FAVORITE, file.getIsFavorite()); boolean existsByPath = fileExists(file.getRemotePath()); if (existsByPath || fileExists(file.getFileId())) { @@ -380,13 +381,14 @@ public class FileDataStorageManager { cv.put(ProviderTableMeta.FILE_ACCOUNT_OWNER, mAccount.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.isFavorite() ? 1 : 0); + cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, folder.isAvailableOffline() ? 1 : 0); cv.put(ProviderTableMeta.FILE_ETAG, folder.getEtag()); 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()); cv.put(ProviderTableMeta.FILE_PERMISSIONS, folder.getPermissions()); cv.put(ProviderTableMeta.FILE_REMOTE_ID, folder.getRemoteId()); + cv.put(ProviderTableMeta.FILE_FAVORITE, folder.getIsFavorite()); operations.add(ContentProviderOperation.newUpdate(ProviderTableMeta.CONTENT_URI). withValues(cv). @@ -895,7 +897,7 @@ 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.setFavorite(c.getInt(c.getColumnIndex(ProviderTableMeta.FILE_KEEP_IN_SYNC)) == 1 ? true : false); + file.setAvailableOffline(c.getInt(c.getColumnIndex(ProviderTableMeta.FILE_KEEP_IN_SYNC)) == 1 ? true : false); file.setEtag(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_ETAG))); file.setShareViaLink(c.getInt( c.getColumnIndex(ProviderTableMeta.FILE_SHARED_VIA_LINK)) == 1 ? true : false); @@ -909,6 +911,7 @@ public class FileDataStorageManager { file.setDownloading(c.getInt( c.getColumnIndex(ProviderTableMeta.FILE_IS_DOWNLOADING)) == 1 ? true : false); file.setEtagInConflict(c.getString(c.getColumnIndex(ProviderTableMeta.FILE_ETAG_IN_CONFLICT))); + file.setFavorite(c.getInt(c.getColumnIndex(ProviderTableMeta.FILE_FAVORITE)) == 1 ? true : false); } return file; @@ -1315,13 +1318,14 @@ public class FileDataStorageManager { ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA, file.getLastSyncDateForData() ); - cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.isFavorite() ? 1 : 0); + cv.put(ProviderTableMeta.FILE_KEEP_IN_SYNC, file.isAvailableOffline() ? 1 : 0); cv.put(ProviderTableMeta.FILE_ETAG, file.getEtag()); 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.getIsFavorite()); cv.put( ProviderTableMeta.FILE_UPDATE_THUMBNAIL, file.needsUpdateThumbnail() ? 1 : 0 diff --git a/src/main/java/com/owncloud/android/datamodel/OCFile.java b/src/main/java/com/owncloud/android/datamodel/OCFile.java index b260671300..5efc357b8a 100644 --- a/src/main/java/com/owncloud/android/datamodel/OCFile.java +++ b/src/main/java/com/owncloud/android/datamodel/OCFile.java @@ -74,7 +74,7 @@ public class OCFile implements Parcelable, Comparable { private boolean mNeedsUpdating; private long mLastSyncDateForProperties; private long mLastSyncDateForData; - private boolean mFavorite; + private boolean mAvailableOffline; private String mEtag; @@ -92,6 +92,8 @@ public class OCFile implements Parcelable, Comparable { private boolean mShareWithSharee; + private boolean mIsFavorite; + /** * URI to the local path of the file contents, if stored in the device; cached after first call * to {@link #getStorageUri()} @@ -139,7 +141,7 @@ public class OCFile implements Parcelable, Comparable { mLocalPath = source.readString(); mMimeType = source.readString(); mNeedsUpdating = source.readInt() == 0; - mFavorite = source.readInt() == 1; + mAvailableOffline = source.readInt() == 1; mLastSyncDateForProperties = source.readLong(); mLastSyncDateForData = source.readLong(); mEtag = source.readString(); @@ -151,7 +153,7 @@ public class OCFile implements Parcelable, Comparable { mIsDownloading = source.readInt() == 1; mEtagInConflict = source.readString(); mShareWithSharee = source.readInt() == 1; - + mIsFavorite = source.readInt() == 1; } @Override @@ -166,7 +168,7 @@ public class OCFile implements Parcelable, Comparable { dest.writeString(mLocalPath); dest.writeString(mMimeType); dest.writeInt(mNeedsUpdating ? 1 : 0); - dest.writeInt(mFavorite ? 1 : 0); + dest.writeInt(mAvailableOffline ? 1 : 0); dest.writeLong(mLastSyncDateForProperties); dest.writeLong(mLastSyncDateForData); dest.writeString(mEtag); @@ -178,6 +180,15 @@ public class OCFile implements Parcelable, Comparable { dest.writeInt(mIsDownloading ? 1 : 0); dest.writeString(mEtagInConflict); dest.writeInt(mShareWithSharee ? 1 : 0); + dest.writeInt(mIsFavorite ? 1 : 0); + } + + public boolean getIsFavorite() { + return mIsFavorite; + } + + public void setFavorite(boolean mIsFavorite) { + this.mIsFavorite = mIsFavorite; } /** @@ -412,7 +423,7 @@ public class OCFile implements Parcelable, Comparable { mModifiedTimestampAtLastSyncForData = 0; mLastSyncDateForProperties = 0; mLastSyncDateForData = 0; - mFavorite = false; + mAvailableOffline = false; mNeedsUpdating = false; mEtag = null; mShareByLink = false; @@ -423,6 +434,7 @@ public class OCFile implements Parcelable, Comparable { mIsDownloading = false; mEtagInConflict = null; mShareWithSharee = false; + mIsFavorite = false; } /** @@ -521,12 +533,12 @@ public class OCFile implements Parcelable, Comparable { mLastSyncDateForData = lastSyncDate; } - public void setFavorite(boolean favorite) { - mFavorite = favorite; + public void setAvailableOffline(boolean availableOffline) { + mAvailableOffline = availableOffline; } - public boolean isFavorite() { - return mFavorite; + public boolean isAvailableOffline() { + return mAvailableOffline; } @Override @@ -570,10 +582,10 @@ public class OCFile implements Parcelable, Comparable { @Override public String toString() { String asString = "[id=%s, name=%s, mime=%s, downloaded=%s, local=%s, remote=%s, " + - "parentId=%s, favorite=%s etag=%s]"; + "parentId=%s, availableOffline=%s etag=%s favourite=%s]"; asString = String.format(asString, mId, getFileName(), mMimeType, isDown(), - mLocalPath, mRemotePath, mParentId, mFavorite, - mEtag); + mLocalPath, mRemotePath, mParentId, mAvailableOffline, + mEtag, mIsFavorite); return asString; } diff --git a/src/main/java/com/owncloud/android/db/ProviderMeta.java b/src/main/java/com/owncloud/android/db/ProviderMeta.java index 2be0499985..a75d6a4d91 100644 --- a/src/main/java/com/owncloud/android/db/ProviderMeta.java +++ b/src/main/java/com/owncloud/android/db/ProviderMeta.java @@ -33,7 +33,7 @@ import com.owncloud.android.MainApp; public class ProviderMeta { public static final String DB_NAME = "filelist"; - public static final int DB_VERSION = 16; + public static final int DB_VERSION = 17; private ProviderMeta() { } @@ -88,6 +88,7 @@ public class ProviderMeta { public static final String FILE_UPDATE_THUMBNAIL = "update_thumbnail"; public static final String FILE_IS_DOWNLOADING= "is_downloading"; public static final String FILE_ETAG_IN_CONFLICT = "etag_in_conflict"; + public static final String FILE_FAVORITE = "favorite"; public static final String FILE_DEFAULT_SORT_ORDER = FILE_NAME + " collate nocase asc"; diff --git a/src/main/java/com/owncloud/android/files/FileMenuFilter.java b/src/main/java/com/owncloud/android/files/FileMenuFilter.java index 4189cd8b3c..b3cbb988c4 100644 --- a/src/main/java/com/owncloud/android/files/FileMenuFilter.java +++ b/src/main/java/com/owncloud/android/files/FileMenuFilter.java @@ -229,20 +229,35 @@ public class FileMenuFilter { toShow.add(R.id.action_send_file); } - // FAVORITES - if (!allFiles() || synchronizing || allFavorites()) { - toHide.add(R.id.action_favorite_file); + // Kept available offline + if (!allFiles() || synchronizing || allKeptAvailableOffline()) { + toHide.add(R.id.action_keep_files_offline); } else { - toShow.add(R.id.action_favorite_file); + toShow.add(R.id.action_keep_files_offline); } - // UNFAVORITES - if (!allFiles() || synchronizing || allUnfavorites()) { - toHide.add(R.id.action_unfavorite_file); + // Not kept available offline + if (!allFiles() || synchronizing || allNotKeptAvailableOffline()) { + toHide.add(R.id.action_unset_keep_files_offline); } else { - toShow.add(R.id.action_unfavorite_file); + toShow.add(R.id.action_unset_keep_files_offline); } + // Favorite + if (!allFiles() || synchronizing || allFavorites()) { + toHide.add(R.id.action_favorite); + } else { + toShow.add(R.id.action_favorite); + } + + // Unfavorite + if (!allFiles() || synchronizing || allNotFavorites()) { + toHide.add(R.id.action_unset_favorite); + } else { + toShow.add(R.id.action_unset_favorite); + } + + } private boolean anyFileSynchronizing() { @@ -320,18 +335,36 @@ public class FileMenuFilter { return false; } - private boolean allFavorites() { + private boolean allKeptAvailableOffline() { for(OCFile file: mFiles) { - if(!file.isFavorite()) { + if(!file.isAvailableOffline()) { return false; } } return true; } - private boolean allUnfavorites() { + private boolean allFavorites() { for(OCFile file: mFiles) { - if(file.isFavorite()) { + if(!file.getIsFavorite()) { + return false; + } + } + return true; + } + + private boolean allNotFavorites() { + for(OCFile file: mFiles) { + if(file.getIsFavorite()) { + return false; + } + } + return true; + } + + private boolean allNotKeptAvailableOffline() { + for(OCFile file: mFiles) { + if(file.isAvailableOffline()) { return false; } } diff --git a/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java b/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java index 2294f4c69b..7f6215a971 100644 --- a/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java +++ b/src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java @@ -91,7 +91,7 @@ public class RefreshFolderOperation extends RemoteOperation { private int mConflictsFound; /** Counter of failed operations in synchronization of kept-in-sync files */ - private int mFailsInFavouritesFound; + private int mFailsInKeptInSyncFound; /** * Map of remote and local paths to files that where locally stored in a location @@ -156,8 +156,8 @@ public class RefreshFolderOperation extends RemoteOperation { return mConflictsFound; } - public int getFailsInFavouritesFound() { - return mFailsInFavouritesFound; + public int getFailsInKeptInSyncFound() { + return mFailsInKeptInSyncFound; } public Map getForgottenLocalFiles() { @@ -182,7 +182,7 @@ public class RefreshFolderOperation extends RemoteOperation { @Override protected RemoteOperationResult run(OwnCloudClient client) { RemoteOperationResult result = null; - mFailsInFavouritesFound = 0; + mFailsInKeptInSyncFound = 0; mConflictsFound = 0; mForgottenLocalFiles.clear(); @@ -197,7 +197,7 @@ public class RefreshFolderOperation extends RemoteOperation { if (mRemoteFolderChanged) { result = fetchAndSyncRemoteFolder(client); } else { - fetchFavoritesToSyncFromLocalData(); + fetchKeptInSyncFilesToSyncFromLocalData(); mChildren = mStorageManager.getFolderContent(mLocalFolder, false); } @@ -316,7 +316,7 @@ public class RefreshFolderOperation extends RemoteOperation { if (result.isSuccess()) { synchronizeData(result.getData()); - if (mConflictsFound > 0 || mFailsInFavouritesFound > 0) { + if (mConflictsFound > 0 || mFailsInKeptInSyncFound > 0) { result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT); // should be a different result code, but will do the job } @@ -394,7 +394,7 @@ public class RefreshFolderOperation extends RemoteOperation { updatedFile.setLastSyncDateForProperties(mCurrentSyncTime); if (localFile != null) { updatedFile.setFileId(localFile.getFileId()); - updatedFile.setFavorite(localFile.isFavorite()); + updatedFile.setAvailableOffline(localFile.isAvailableOffline()); updatedFile.setLastSyncDateForData(localFile.getLastSyncDateForData()); updatedFile.setModificationTimestampAtLastSyncForData( localFile.getModificationTimestampAtLastSyncForData() @@ -423,7 +423,7 @@ public class RefreshFolderOperation extends RemoteOperation { FileStorageUtils.searchForLocalFileInDefaultPath(updatedFile, mAccount); /// prepare content synchronization for kept-in-sync files - if (updatedFile.isFavorite()) { + if (updatedFile.isAvailableOffline()) { SynchronizeFileOperation operation = new SynchronizeFileOperation( localFile, remoteFile, mAccount, @@ -463,7 +463,7 @@ public class RefreshFolderOperation extends RemoteOperation { if (contentsResult.getCode() == ResultCode.SYNC_CONFLICT) { mConflictsFound++; } else { - mFailsInFavouritesFound++; + mFailsInKeptInSyncFound++; if (contentsResult.getException() != null) { Log_OC.e(TAG, "Error while synchronizing favourites : " + contentsResult.getLogMessage(), contentsResult.getException()); @@ -536,10 +536,10 @@ public class RefreshFolderOperation extends RemoteOperation { } - private void fetchFavoritesToSyncFromLocalData() { + private void fetchKeptInSyncFilesToSyncFromLocalData() { List children = mStorageManager.getFolderContent(mLocalFolder, false); for (OCFile child : children) { - if (!child.isFolder() && child.isFavorite() && !child.isInConflict()) { + 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 diff --git a/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java b/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java index 286f7e091e..549bf1f749 100644 --- a/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java +++ b/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java @@ -247,7 +247,7 @@ public class SynchronizeFileOperation extends SyncOperation { // service when the upload finishes } 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()); diff --git a/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java b/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java index d8a27dedf1..46288bc6fe 100644 --- a/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java +++ b/src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java @@ -323,7 +323,7 @@ public class SynchronizeFolderOperation extends SyncOperation { updatedFile.setLastSyncDateForProperties(mCurrentSyncTime); if (localFile != null) { updatedFile.setFileId(localFile.getFileId()); - updatedFile.setFavorite(localFile.isFavorite()); + updatedFile.setAvailableOffline(localFile.isAvailableOffline()); updatedFile.setLastSyncDateForData(localFile.getLastSyncDateForData()); updatedFile.setModificationTimestampAtLastSyncForData( localFile.getModificationTimestampAtLastSyncForData() diff --git a/src/main/java/com/owncloud/android/operations/UpdateOCVersionOperation.java b/src/main/java/com/owncloud/android/operations/UpdateOCVersionOperation.java index 6db21f0def..1042e5d88d 100644 --- a/src/main/java/com/owncloud/android/operations/UpdateOCVersionOperation.java +++ b/src/main/java/com/owncloud/android/operations/UpdateOCVersionOperation.java @@ -20,10 +20,9 @@ package com.owncloud.android.operations; -import org.apache.commons.httpclient.HttpStatus; -import org.apache.commons.httpclient.methods.GetMethod; -import org.json.JSONException; -import org.json.JSONObject; +import android.accounts.Account; +import android.accounts.AccountManager; +import android.content.Context; import com.owncloud.android.authentication.AccountUtils; import com.owncloud.android.lib.common.OwnCloudClient; @@ -34,9 +33,10 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCo import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.lib.resources.status.OwnCloudVersion; -import android.accounts.Account; -import android.accounts.AccountManager; -import android.content.Context; +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.httpclient.methods.GetMethod; +import org.json.JSONException; +import org.json.JSONObject; /** @@ -65,6 +65,9 @@ public class UpdateOCVersionOperation extends RemoteOperation { statUrl += AccountUtils.STATUS_PATH; RemoteOperationResult result = null; GetMethod get = null; + + String webDav = client.getWebdavUri().toString(); + try { get = new GetMethod(statUrl); int status = client.executeMethod(get); @@ -96,15 +99,17 @@ public class UpdateOCVersionOperation extends RemoteOperation { result = new RemoteOperationResult(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED); } } - Log_OC.i(TAG, "Check for update of ownCloud server version at " + client.getWebdavUri() + ": " + result.getLogMessage()); + + + Log_OC.i(TAG, "Check for update of ownCloud server version at " + webDav + ": " + result.getLogMessage()); } catch (JSONException e) { result = new RemoteOperationResult(RemoteOperationResult.ResultCode.INSTANCE_NOT_CONFIGURED); - Log_OC.e(TAG, "Check for update of ownCloud server version at " + client.getWebdavUri() + ": " + result.getLogMessage(), e); + Log_OC.e(TAG, "Check for update of ownCloud server version at " + webDav + ": " + result.getLogMessage(), e); } catch (Exception e) { result = new RemoteOperationResult(e); - Log_OC.e(TAG, "Check for update of ownCloud server version at " + client.getWebdavUri() + ": " + result.getLogMessage(), e); + Log_OC.e(TAG, "Check for update of ownCloud server version at " + webDav + ": " + result.getLogMessage(), e); } finally { if (get != null) { diff --git a/src/main/java/com/owncloud/android/operations/UploadFileOperation.java b/src/main/java/com/owncloud/android/operations/UploadFileOperation.java index 87214bcb3d..390a2b11b6 100644 --- a/src/main/java/com/owncloud/android/operations/UploadFileOperation.java +++ b/src/main/java/com/owncloud/android/operations/UploadFileOperation.java @@ -572,7 +572,7 @@ public class UploadFileOperation extends SyncOperation { mFile.getModificationTimestampAtLastSyncForData() ); newFile.setEtag(mFile.getEtag()); - newFile.setFavorite(mFile.isFavorite()); + newFile.setAvailableOffline(mFile.isAvailableOffline()); newFile.setLastSyncDateForProperties(mFile.getLastSyncDateForProperties()); newFile.setLastSyncDateForData(mFile.getLastSyncDateForData()); newFile.setStoragePath(mFile.getStoragePath()); diff --git a/src/main/java/com/owncloud/android/providers/FileContentProvider.java b/src/main/java/com/owncloud/android/providers/FileContentProvider.java index f9854781a7..97baea8419 100644 --- a/src/main/java/com/owncloud/android/providers/FileContentProvider.java +++ b/src/main/java/com/owncloud/android/providers/FileContentProvider.java @@ -1,24 +1,23 @@ /** - * ownCloud Android client application - * - * @author Bartek Przybylski - * @author David A. Velasco - * @author masensio - * Copyright (C) 2011 Bartek Przybylski - * Copyright (C) 2016 ownCloud Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * ownCloud Android client application * + * @author Bartek Przybylski + * @author David A. Velasco + * @author masensio + * Copyright (C) 2011 Bartek Przybylski + * Copyright (C) 2016 ownCloud Inc. + *

+ * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + *

+ * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + *

+ * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ package com.owncloud.android.providers; @@ -139,7 +138,7 @@ public class FileContentProvider extends ContentProvider { } */ Cursor children = query(uri, null, null, null, null); - if (children != null && children.moveToFirst()) { + if (children != null && children.moveToFirst()) { long childId; boolean isDir; while (!children.isAfterLast()) { @@ -208,13 +207,13 @@ public class FileContentProvider extends ContentProvider { @Override public String getType(Uri uri) { switch (mUriMatcher.match(uri)) { - case ROOT_DIRECTORY: - return ProviderTableMeta.CONTENT_TYPE; - case SINGLE_FILE: - return ProviderTableMeta.CONTENT_TYPE_ITEM; - default: - throw new IllegalArgumentException("Unknown Uri id." - + uri.toString()); + case ROOT_DIRECTORY: + return ProviderTableMeta.CONTENT_TYPE; + case SINGLE_FILE: + return ProviderTableMeta.CONTENT_TYPE_ITEM; + default: + throw new IllegalArgumentException("Unknown Uri id." + + uri.toString()); } } @@ -234,18 +233,18 @@ public class FileContentProvider extends ContentProvider { } private Uri insert(SQLiteDatabase db, Uri uri, ContentValues values) { - switch (mUriMatcher.match(uri)){ + switch (mUriMatcher.match(uri)) { case ROOT_DIRECTORY: case SINGLE_FILE: String remotePath = values.getAsString(ProviderTableMeta.FILE_PATH); String accountName = values.getAsString(ProviderTableMeta.FILE_ACCOUNT_OWNER); - String[] projection = new String[] { + String[] projection = new String[]{ ProviderTableMeta._ID, ProviderTableMeta.FILE_PATH, ProviderTableMeta.FILE_ACCOUNT_OWNER }; String where = ProviderTableMeta.FILE_PATH + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?"; - String[] whereArgs = new String[] {remotePath, accountName}; + String[] whereArgs = new String[]{remotePath, accountName}; Cursor doubleCheck = query(db, uri, projection, where, whereArgs, null); // ugly patch; serious refactorization is needed to reduce work in // FileDataStorageManager and bring it to FileContentProvider @@ -273,7 +272,7 @@ public class FileContentProvider extends ContentProvider { case SHARES: Uri insertedShareUri = null; long rowId = db.insert(ProviderTableMeta.OCSHARES_TABLE_NAME, null, values); - if (rowId >0) { + if (rowId > 0) { insertedShareUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_SHARE, rowId); } else { @@ -286,7 +285,7 @@ public class FileContentProvider extends ContentProvider { case CAPABILITIES: Uri insertedCapUri = null; long id = db.insert(ProviderTableMeta.CAPABILITIES_TABLE_NAME, null, values); - if (id >0) { + if (id > 0) { insertedCapUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_CAPABILITIES, id); } else { @@ -298,7 +297,7 @@ public class FileContentProvider extends ContentProvider { case UPLOADS: Uri insertedUploadUri = null; long uploadId = db.insert(ProviderTableMeta.UPLOADS_TABLE_NAME, null, values); - if (uploadId >0) { + if (uploadId > 0) { insertedUploadUri = ContentUris.withAppendedId(ProviderTableMeta.CONTENT_URI_UPLOADS, uploadId); trimSuccessfulUploads(db); @@ -328,22 +327,22 @@ public class FileContentProvider extends ContentProvider { private void updateFilesTableAccordingToShareInsertion( SQLiteDatabase db, ContentValues newShare - ) { + ) { ContentValues fileValues = new ContentValues(); int newShareType = newShare.getAsInteger(ProviderTableMeta.OCSHARES_SHARE_TYPE); if (newShareType == ShareType.PUBLIC_LINK.getValue()) { fileValues.put(ProviderTableMeta.FILE_SHARED_VIA_LINK, 1); } else if ( newShareType == ShareType.USER.getValue() || - newShareType == ShareType.GROUP.getValue() || - newShareType == ShareType.EMAIL.getValue() || - newShareType == ShareType.FEDERATED.getValue() ) { + newShareType == ShareType.GROUP.getValue() || + newShareType == ShareType.EMAIL.getValue() || + newShareType == ShareType.FEDERATED.getValue()) { fileValues.put(ProviderTableMeta.FILE_SHARED_WITH_SHAREE, 1); } String where = ProviderTableMeta.FILE_PATH + "=? AND " + ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?"; - String[] whereArgs = new String[] { + String[] whereArgs = new String[]{ newShare.getAsString(ProviderTableMeta.OCSHARES_PATH), newShare.getAsString(ProviderTableMeta.OCSHARES_ACCOUNT_OWNER) }; @@ -381,7 +380,7 @@ public class FileContentProvider extends ContentProvider { String selection, String[] selectionArgs, String sortOrder - ) { + ) { Cursor result = null; SQLiteDatabase db = mDbHelper.getReadableDatabase(); @@ -402,7 +401,7 @@ public class FileContentProvider extends ContentProvider { String selection, String[] selectionArgs, String sortOrder - ) { + ) { SQLiteQueryBuilder sqlQuery = new SQLiteQueryBuilder(); @@ -501,17 +500,16 @@ public class FileContentProvider extends ContentProvider { } - private int update( SQLiteDatabase db, Uri uri, ContentValues values, String selection, String[] selectionArgs - ) { + ) { switch (mUriMatcher.match(uri)) { case DIRECTORY: - return 0; //updateFolderSize(db, selectionArgs[0]); + return 0; //updateFolderSize(db, selectionArgs[0]); case SHARES: return db.update( ProviderTableMeta.OCSHARES_TABLE_NAME, values, selection, selectionArgs @@ -536,12 +534,12 @@ public class FileContentProvider extends ContentProvider { } @Override - public ContentProviderResult[] applyBatch (ArrayList operations) + public ContentProviderResult[] applyBatch(ArrayList operations) throws OperationApplicationException { Log_OC.d("FileContentProvider", "applying batch in provider " + this + - " (temporary: " + isTemporary() + ")" ); + " (temporary: " + isTemporary() + ")"); ContentProviderResult[] results = new ContentProviderResult[operations.size()]; - int i=0; + int i = 0; SQLiteDatabase db = mDbHelper.getWritableDatabase(); db.beginTransaction(); // it's supposed that transactions can be nested @@ -592,8 +590,8 @@ public class FileContentProvider extends ContentProvider { if (oldVersion == 1 && newVersion >= 2) { Log_OC.i(SQL, "Entering in the #1 ADD in onUpgrade"); db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME + - ADD_COLUMN + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER " + - " DEFAULT 0"); + ADD_COLUMN + ProviderTableMeta.FILE_KEEP_IN_SYNC + " INTEGER " + + " DEFAULT 0"); upgraded = true; } if (oldVersion < 3 && newVersion >= 3) { @@ -601,8 +599,8 @@ public class FileContentProvider extends ContentProvider { db.beginTransaction(); try { db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME + - ADD_COLUMN + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + - " INTEGER " + " DEFAULT 0"); + ADD_COLUMN + ProviderTableMeta.FILE_LAST_SYNC_DATE_FOR_DATA + + " INTEGER " + " DEFAULT 0"); // assume there are not local changes pending to upload db.execSQL("UPDATE " + ProviderTableMeta.FILE_TABLE_NAME + @@ -625,9 +623,9 @@ public class FileContentProvider extends ContentProvider { " INTEGER " + " DEFAULT 0"); db.execSQL("UPDATE " + ProviderTableMeta.FILE_TABLE_NAME + - " SET " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " = " + + " SET " + ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA + " = " + ProviderTableMeta.FILE_MODIFIED + - " WHERE " + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL"); + " WHERE " + ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL"); upgraded = true; db.setTransactionSuccessful(); @@ -635,6 +633,7 @@ public class FileContentProvider extends ContentProvider { db.endTransaction(); } } + if (!upgraded) { Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion)); } @@ -661,11 +660,11 @@ public class FileContentProvider extends ContentProvider { Log_OC.i(SQL, "Entering in the #5 ADD in onUpgrade"); db.beginTransaction(); try { - db .execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME + + db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME + ADD_COLUMN + ProviderTableMeta.FILE_SHARED_VIA_LINK + " INTEGER " + " DEFAULT 0"); - db .execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME + + db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME + ADD_COLUMN + ProviderTableMeta.FILE_PUBLIC_LINK + " TEXT " + " DEFAULT NULL"); @@ -726,7 +725,7 @@ public class FileContentProvider extends ContentProvider { Log_OC.i(SQL, "Entering in the #9 ADD in onUpgrade"); db.beginTransaction(); try { - db .execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME + + db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME + ADD_COLUMN + ProviderTableMeta.FILE_IS_DOWNLOADING + " INTEGER " + " DEFAULT 0"); @@ -745,15 +744,15 @@ public class FileContentProvider extends ContentProvider { updateAccountName(db); upgraded = true; } - if (!upgraded) { - Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion)); - } + if (!upgraded) { + Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion)); + } if (oldVersion < 11 && newVersion >= 11) { Log_OC.i(SQL, "Entering in the #11 ADD in onUpgrade"); db.beginTransaction(); try { - db .execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME + + db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME + ADD_COLUMN + ProviderTableMeta.FILE_ETAG_IN_CONFLICT + " TEXT " + " DEFAULT NULL"); @@ -771,7 +770,7 @@ public class FileContentProvider extends ContentProvider { Log_OC.i(SQL, "Entering in the #12 ADD in onUpgrade"); db.beginTransaction(); try { - db .execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME + + db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME + ADD_COLUMN + ProviderTableMeta.FILE_SHARED_WITH_SHAREE + " INTEGER " + " DEFAULT 0"); upgraded = true; @@ -843,35 +842,56 @@ public class FileContentProvider extends ContentProvider { if (!upgraded) { Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion)); } + + if (oldVersion < 17 && newVersion >= 17) { + Log_OC.i(SQL, "Entering in the #4 ADD in onUpgrade"); + db.beginTransaction(); + try { + db.execSQL(ALTER_TABLE + ProviderTableMeta.FILE_TABLE_NAME + + ADD_COLUMN + ProviderTableMeta.FILE_FAVORITE + + " INTEGER " + " DEFAULT 0"); + + upgraded = true; + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + + } + + if (!upgraded) { + Log_OC.i(SQL, String.format(Locale.ENGLISH, UPGRADE_VERSION_MSG, oldVersion, newVersion)); + } } } - private void createFilesTable(SQLiteDatabase db){ + private void createFilesTable(SQLiteDatabase db) { db.execSQL("CREATE TABLE " + ProviderTableMeta.FILE_TABLE_NAME + "(" - + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, " - + ProviderTableMeta.FILE_NAME + TEXT - + ProviderTableMeta.FILE_PATH + TEXT - + ProviderTableMeta.FILE_PARENT + INTEGER - + ProviderTableMeta.FILE_CREATION + INTEGER - + ProviderTableMeta.FILE_MODIFIED + INTEGER - + ProviderTableMeta.FILE_CONTENT_TYPE + TEXT - + ProviderTableMeta.FILE_CONTENT_LENGTH + INTEGER - + 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_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_IS_DOWNLOADING + INTEGER //boolean - + ProviderTableMeta.FILE_ETAG_IN_CONFLICT + TEXT - + ProviderTableMeta.FILE_SHARED_WITH_SHAREE + " INTEGER);" + + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, " + + ProviderTableMeta.FILE_NAME + TEXT + + ProviderTableMeta.FILE_PATH + TEXT + + ProviderTableMeta.FILE_PARENT + INTEGER + + ProviderTableMeta.FILE_CREATION + INTEGER + + ProviderTableMeta.FILE_MODIFIED + INTEGER + + ProviderTableMeta.FILE_CONTENT_TYPE + TEXT + + ProviderTableMeta.FILE_CONTENT_LENGTH + INTEGER + + 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_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_IS_DOWNLOADING + INTEGER //boolean + + ProviderTableMeta.FILE_FAVORITE + INTEGER // boolean + + ProviderTableMeta.FILE_ETAG_IN_CONFLICT + TEXT + + ProviderTableMeta.FILE_SHARED_WITH_SHAREE + " INTEGER);" ); } @@ -884,7 +904,7 @@ public class FileContentProvider extends ContentProvider { + ProviderTableMeta.OCSHARES_SHARE_TYPE + INTEGER + ProviderTableMeta.OCSHARES_SHARE_WITH + TEXT + ProviderTableMeta.OCSHARES_PATH + TEXT - + ProviderTableMeta.OCSHARES_PERMISSIONS+ INTEGER + + ProviderTableMeta.OCSHARES_PERMISSIONS + INTEGER + ProviderTableMeta.OCSHARES_SHARED_DATE + INTEGER + ProviderTableMeta.OCSHARES_EXPIRATION_DATE + INTEGER + ProviderTableMeta.OCSHARES_TOKEN + TEXT @@ -892,10 +912,10 @@ public class FileContentProvider extends ContentProvider { + ProviderTableMeta.OCSHARES_IS_DIRECTORY + INTEGER // boolean + ProviderTableMeta.OCSHARES_USER_ID + INTEGER + ProviderTableMeta.OCSHARES_ID_REMOTE_SHARED + INTEGER - + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + " TEXT );" ); + + ProviderTableMeta.OCSHARES_ACCOUNT_OWNER + " TEXT );"); } - private void createCapabilitiesTable(SQLiteDatabase db){ + private void createCapabilitiesTable(SQLiteDatabase db) { // Create capabilities table db.execSQL("CREATE TABLE " + ProviderTableMeta.CAPABILITIES_TABLE_NAME + "(" + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, " @@ -921,10 +941,10 @@ public class FileContentProvider extends ContentProvider { + ProviderTableMeta.CAPABILITIES_FILES_BIGFILECHUNKING + INTEGER // boolean + ProviderTableMeta.CAPABILITIES_FILES_UNDELETE + INTEGER // boolean + ProviderTableMeta.CAPABILITIES_FILES_VERSIONING + INTEGER // boolean - + ProviderTableMeta.CAPABILITIES_FILES_DROP + " INTEGER );" ); // boolean + + ProviderTableMeta.CAPABILITIES_FILES_DROP + " INTEGER );"); // boolean } - private void createUploadsTable(SQLiteDatabase db){ + private void createUploadsTable(SQLiteDatabase db) { // Create uploads table db.execSQL("CREATE TABLE " + ProviderTableMeta.UPLOADS_TABLE_NAME + "(" + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, " @@ -953,10 +973,10 @@ public class FileContentProvider extends ContentProvider { */ } - private void createSyncedFoldersTable(SQLiteDatabase db){ + private void createSyncedFoldersTable(SQLiteDatabase db) { db.execSQL("CREATE TABLE " + ProviderTableMeta.SYNCED_FOLDERS_TABLE_NAME + "(" - + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, " // id - + ProviderTableMeta.SYNCED_FOLDER_LOCAL_PATH + " TEXT, " // local path + + ProviderTableMeta._ID + " INTEGER PRIMARY KEY, " // id + + ProviderTableMeta.SYNCED_FOLDER_LOCAL_PATH + " TEXT, " // local path + ProviderTableMeta.SYNCED_FOLDER_REMOTE_PATH + " TEXT, " // remote path + ProviderTableMeta.SYNCED_FOLDER_WIFI_ONLY + " INTEGER, " // wifi_only + ProviderTableMeta.SYNCED_FOLDER_CHARGING_ONLY + " INTEGER, " // charging only @@ -976,7 +996,7 @@ public class FileContentProvider extends ContentProvider { * * @param db Database where table of files is included. */ - private void updateAccountName(SQLiteDatabase db){ + private void updateAccountName(SQLiteDatabase db) { Log_OC.d(SQL, "THREAD: " + Thread.currentThread().getName()); AccountManager ama = AccountManager.get(getContext()); try { @@ -986,7 +1006,7 @@ public class FileContentProvider extends ContentProvider { Account[] accounts = AccountManager.get(getContext()).getAccountsByType( MainApp.getAccountType()); String serverUrl, username, oldAccountName, newAccountName; - for (Account account : accounts) { + for (Account account : accounts) { // build both old and new account name serverUrl = ama.getUserData(account, AccountUtils.Constants.KEY_OC_BASE_URL); username = AccountUtils.getUsernameForAccount(account); @@ -1016,7 +1036,7 @@ public class FileContentProvider extends ContentProvider { } finally { db.endTransaction(); } - } + } } catch (Exception e) { Log_OC.e(TAG, "Exception upgrading account names or paths in database", e); } @@ -1038,10 +1058,10 @@ public class FileContentProvider extends ContentProvider { ProviderTableMeta.FILE_STORAGE_PATH + " IS NOT NULL"; Cursor c = db.query(ProviderTableMeta.FILE_TABLE_NAME, - null, - whereClause, - new String[]{newAccountName}, - null, null, null); + null, + whereClause, + new String[]{newAccountName}, + null, null, null); try { if (c.moveToFirst()) { @@ -1091,30 +1111,30 @@ public class FileContentProvider extends ContentProvider { try { String MAX_SUCCESSFUL_UPLOADS = "30"; c = db.rawQuery( - "delete from " + ProviderTableMeta.UPLOADS_TABLE_NAME + - " where " + ProviderTableMeta.UPLOADS_STATUS + " == " - + UploadsStorageManager.UploadStatus.UPLOAD_SUCCEEDED.getValue() + - " and " + ProviderTableMeta._ID + - " not in (select " + ProviderTableMeta._ID + - " from " + ProviderTableMeta.UPLOADS_TABLE_NAME + - " where " + ProviderTableMeta.UPLOADS_STATUS + " == " - + UploadsStorageManager.UploadStatus.UPLOAD_SUCCEEDED.getValue() + - " order by " + ProviderTableMeta.UPLOADS_UPLOAD_END_TIMESTAMP + - " desc limit " + MAX_SUCCESSFUL_UPLOADS + - ")", - null + "delete from " + ProviderTableMeta.UPLOADS_TABLE_NAME + + " where " + ProviderTableMeta.UPLOADS_STATUS + " == " + + UploadsStorageManager.UploadStatus.UPLOAD_SUCCEEDED.getValue() + + " and " + ProviderTableMeta._ID + + " not in (select " + ProviderTableMeta._ID + + " from " + ProviderTableMeta.UPLOADS_TABLE_NAME + + " where " + ProviderTableMeta.UPLOADS_STATUS + " == " + + UploadsStorageManager.UploadStatus.UPLOAD_SUCCEEDED.getValue() + + " order by " + ProviderTableMeta.UPLOADS_UPLOAD_END_TIMESTAMP + + " desc limit " + MAX_SUCCESSFUL_UPLOADS + + ")", + null ); c.moveToFirst(); // do something with the cursor, or deletion doesn't happen; true story } catch (Exception e) { Log_OC.e( - TAG, - "Something wrong trimming successful uploads, database could grow more than expected", - e + TAG, + "Something wrong trimming successful uploads, database could grow more than expected", + e ); } finally { - if (c!= null) { + if (c != null) { c.close(); } } diff --git a/src/main/java/com/owncloud/android/syncadapter/FileSyncAdapter.java b/src/main/java/com/owncloud/android/syncadapter/FileSyncAdapter.java index ed040eb3af..1213e19175 100644 --- a/src/main/java/com/owncloud/android/syncadapter/FileSyncAdapter.java +++ b/src/main/java/com/owncloud/android/syncadapter/FileSyncAdapter.java @@ -279,7 +279,7 @@ public class FileSyncAdapter extends AbstractOwnCloudSyncAdapter { if (result.getCode() == ResultCode.SYNC_CONFLICT) { mConflictsFound += synchFolderOp.getConflictsFound(); - mFailsInFavouritesFound += synchFolderOp.getFailsInFavouritesFound(); + mFailsInFavouritesFound += synchFolderOp.getFailsInKeptInSyncFound(); } if (synchFolderOp.getForgottenLocalFiles().size() > 0) { mForgottenLocalFiles.putAll(synchFolderOp.getForgottenLocalFiles()); diff --git a/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java b/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java index e294863db8..b698306179 100644 --- a/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java +++ b/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java @@ -1,23 +1,23 @@ /** - * Nextcloud Android client application + * Nextcloud Android client application * - * @author Andy Scherzinger - * Copyright (C) 2016 Andy Scherzinger - * Copyright (C) 2016 Nextcloud - * Copyright (C) 2016 ownCloud Inc. + * @author Andy Scherzinger + * Copyright (C) 2016 Andy Scherzinger + * Copyright (C) 2016 Nextcloud + * Copyright (C) 2016 ownCloud Inc. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. * - * You should have received a copy of the GNU Affero General Public - * License along with this program. If not, see . + * You should have received a copy of the GNU Affero General Public + * License along with this program. If not, see . */ package com.owncloud.android.ui.activity; @@ -53,10 +53,19 @@ import com.owncloud.android.lib.common.UserInfo; import com.owncloud.android.lib.common.operations.RemoteOperation; import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.utils.Log_OC; +import com.owncloud.android.lib.resources.files.SearchOperation; import com.owncloud.android.lib.resources.users.GetRemoteUserInfoOperation; import com.owncloud.android.ui.TextDrawable; +import com.owncloud.android.ui.events.ChangeMenuEvent; +import com.owncloud.android.ui.events.DummyDrawerEvent; +import com.owncloud.android.ui.events.MenuItemClickEvent; +import com.owncloud.android.ui.events.SearchEvent; import com.owncloud.android.utils.DisplayUtils; +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + /** * Base class to handle setup of the drawer implementation including user switching and avatar fetching and fallback * generation. @@ -176,7 +185,8 @@ public abstract class DrawerActivity extends ToolbarActivity implements DisplayU setupQuotaElement(); // show folder sync menu item only for Android 6+ - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M && + mNavigationView.getMenu().findItem(R.id.nav_folder_sync) != null) { mNavigationView.getMenu().removeItem(R.id.nav_folder_sync); } } @@ -285,14 +295,99 @@ public abstract class DrawerActivity extends ToolbarActivity implements DisplayU } else { navigationView.getMenu().setGroupVisible(R.id.drawer_menu_accounts, false); } + + Account account = AccountUtils. + getCurrentOwnCloudAccount(MainApp.getAppContext()); + boolean searchSupported = AccountUtils.hasSearchSupport(account); + + if ((getResources().getBoolean(R.bool.bottom_toolbar_enabled) || (!searchSupported)) && + (account != null)){ + navigationView.getMenu().removeItem(R.id.nav_photos); + if (getResources().getBoolean(R.bool.bottom_toolbar_enabled)) { + navigationView.getMenu().removeItem(R.id.nav_all_files); + navigationView.getMenu().removeItem(R.id.nav_settings); + navigationView.getMenu().removeItem(R.id.nav_favorites); + } + if (!searchSupported) { + navigationView.getMenu().removeItem(R.id.nav_videos); + } + } + + if (getResources().getBoolean(R.bool.use_home) && navigationView.getMenu().findItem(R.id.nav_all_files) != + null) { + navigationView.getMenu().findItem(R.id.nav_all_files).setTitle(getResources(). + getString(R.string.drawer_item_home)); + navigationView.getMenu().findItem(R.id.nav_all_files).setIcon(R.drawable.ic_home); + } + + if (!getResources().getBoolean(R.bool.participate_enabled)) { + navigationView.getMenu().removeItem(R.id.nav_participate); + } + + if (!getResources().getBoolean(R.bool.shared_enabled)) { + navigationView.getMenu().removeItem(R.id.nav_shared); + } + + if (AccountUtils.hasSearchSupport(account)) { + if (!getResources().getBoolean(R.bool.recently_added_enabled)) { + navigationView.getMenu().removeItem(R.id.nav_recently_added); + } + + if (!getResources().getBoolean(R.bool.recently_modified_enabled)) { + navigationView.getMenu().removeItem(R.id.nav_recently_modified); + } + + if (!getResources().getBoolean(R.bool.videos_enabled)) { + navigationView.getMenu().removeItem(R.id.nav_videos); + } + } else if (account != null) { + navigationView.getMenu().removeItem(R.id.nav_recently_added); + navigationView.getMenu().removeItem(R.id.nav_recently_modified); + navigationView.getMenu().removeItem(R.id.nav_videos); + } } + @Subscribe(threadMode = ThreadMode.MAIN) + public void onMessageEvent(MenuItemClickEvent event) { + unsetAllDrawerMenuItems(); + + switch (event.menuItem.getItemId()) { + case R.id.nav_bar_files: + showFiles(false); + break; + case R.id.nav_bar_settings: + Intent settingsIntent = new Intent(getApplicationContext(), Preferences.class); + startActivity(settingsIntent); + break; + default: + break; + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onMessageEvent(DummyDrawerEvent event) { + unsetAllDrawerMenuItems(); + } + + private void selectNavigationItem(final MenuItem menuItem) { + switch (menuItem.getItemId()) { case R.id.nav_all_files: menuItem.setChecked(true); mCheckedMenuItem = menuItem.getItemId(); showFiles(false); + EventBus.getDefault().post(new ChangeMenuEvent()); + break; + case R.id.nav_favorites: + menuItem.setChecked(true); + mCheckedMenuItem = menuItem.getItemId(); + EventBus.getDefault().post(new SearchEvent("", SearchOperation.SearchType.FAVORITE_SEARCH, + SearchEvent.UnsetType.NO_UNSET)); + break; + case R.id.nav_photos: + EventBus.getDefault().post(new SearchEvent("image/%", + SearchOperation.SearchType.CONTENT_TYPE_SEARCH, SearchEvent.UnsetType.NO_UNSET)); break; case R.id.nav_on_device: menuItem.setChecked(true); @@ -311,7 +406,7 @@ public abstract class DrawerActivity extends ToolbarActivity implements DisplayU startActivity(activityIntent); break; case R.id.nav_folder_sync: - Intent folderSyncIntent = new Intent(getApplicationContext(),FolderSyncActivity.class); + Intent folderSyncIntent = new Intent(getApplicationContext(), FolderSyncActivity.class); startActivity(folderSyncIntent); break; case R.id.nav_settings: @@ -331,6 +426,30 @@ public abstract class DrawerActivity extends ToolbarActivity implements DisplayU ManageAccountsActivity.class); startActivityForResult(manageAccountsIntent, ACTION_MANAGE_ACCOUNTS); break; + case R.id.nav_recently_added: + menuItem.setChecked(true); + mCheckedMenuItem = menuItem.getItemId(); + EventBus.getDefault().post(new SearchEvent("%", SearchOperation.SearchType.CONTENT_TYPE_SEARCH, + SearchEvent.UnsetType.UNSET_BOTTOM_NAV_BAR)); + break; + case R.id.nav_recently_modified: + menuItem.setChecked(true); + mCheckedMenuItem = menuItem.getItemId(); + EventBus.getDefault().post(new SearchEvent("", SearchOperation.SearchType.RECENTLY_MODIFIED_SEARCH, + SearchEvent.UnsetType.UNSET_BOTTOM_NAV_BAR)); + break; + case R.id.nav_shared: + menuItem.setChecked(true); + mCheckedMenuItem = menuItem.getItemId(); + EventBus.getDefault().post(new SearchEvent("", SearchOperation.SearchType.SHARED_SEARCH, + SearchEvent.UnsetType.UNSET_BOTTOM_NAV_BAR)); + break; + case R.id.nav_videos: + menuItem.setChecked(true); + mCheckedMenuItem = menuItem.getItemId(); + EventBus.getDefault().post(new SearchEvent("video/%", SearchOperation.SearchType.CONTENT_TYPE_SEARCH, + SearchEvent.UnsetType.UNSET_BOTTOM_NAV_BAR)); + break; case Menu.NONE: // account clicked accountClicked(menuItem.getTitle().toString()); @@ -346,6 +465,7 @@ public abstract class DrawerActivity extends ToolbarActivity implements DisplayU */ public abstract void showFiles(boolean onDeviceOnly); + /** * sets the new/current account and restarts. In case the given account equals the actual/current account the * call will be ignored. @@ -514,7 +634,7 @@ public abstract class DrawerActivity extends ToolbarActivity implements DisplayU /// set home button properties if (mDrawerToggle != null && chosenFile != null) { mDrawerToggle.setDrawerIndicatorEnabled(isRoot(chosenFile)); - } else { + } else if (mDrawerToggle != null){ mDrawerToggle.setDrawerIndicatorEnabled(false); } } @@ -596,9 +716,9 @@ public abstract class DrawerActivity extends ToolbarActivity implements DisplayU /** * configured the quota to be displayed. * - * @param usedSpace the used space + * @param usedSpace the used space * @param totalSpace the total space - * @param relative the percentage of space already used + * @param relative the percentage of space already used */ private void setQuotaInformation(long usedSpace, long totalSpace, int relative) { mQuotaProgressBar.setProgress(relative); @@ -612,6 +732,17 @@ public abstract class DrawerActivity extends ToolbarActivity implements DisplayU showQuota(true); } + protected void unsetAllDrawerMenuItems() { + if (mNavigationView != null && mNavigationView.getMenu() != null) { + Menu menu = mNavigationView.getMenu(); + for (int i = 0; i < menu.size(); i++) { + menu.getItem(i).setChecked(false); + } + } + + mCheckedMenuItem = Menu.NONE; + } + /** * checks/highlights the provided menu item if the drawer has been initialized and the menu item exists. * @@ -823,10 +954,10 @@ public abstract class DrawerActivity extends ToolbarActivity implements DisplayU @Override public void avatarGenerated(Drawable avatarDrawable, Object callContext) { if (callContext instanceof MenuItem) { - MenuItem mi = (MenuItem)callContext; + MenuItem mi = (MenuItem) callContext; mi.setIcon(avatarDrawable); } else if (callContext instanceof ImageView) { - ImageView iv = (ImageView)callContext; + ImageView iv = (ImageView) callContext; iv.setImageDrawable(avatarDrawable); } } @@ -834,10 +965,10 @@ public abstract class DrawerActivity extends ToolbarActivity implements DisplayU @Override public boolean shouldCallGeneratedCallback(String tag, Object callContext) { if (callContext instanceof MenuItem) { - MenuItem mi = (MenuItem)callContext; + MenuItem mi = (MenuItem) callContext; return String.valueOf(mi.getTitle()).equals(tag); } else if (callContext instanceof ImageView) { - ImageView iv = (ImageView)callContext; + ImageView iv = (ImageView) callContext; return String.valueOf(iv.getTag()).equals(tag); } return false; @@ -846,7 +977,7 @@ public abstract class DrawerActivity extends ToolbarActivity implements DisplayU /** * Adds other listeners to react on changes of the drawer layout. * - * @param listener Object interested in changes of the drawer layout. + * @param listener Object interested in changes of the drawer layout. */ public void addDrawerListener(DrawerLayout.DrawerListener listener) { if (mDrawerLayout != null) { @@ -859,4 +990,16 @@ public abstract class DrawerActivity extends ToolbarActivity implements DisplayU public boolean isDrawerIndicatorAvailable() { return true; } + + @Override + protected void onStart() { + super.onStart(); + EventBus.getDefault().register(this); + } + + @Override + protected void onStop() { + EventBus.getDefault().unregister(this); + super.onStop(); + } } diff --git a/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 28749a76cc..237baec695 100644 --- a/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -1,22 +1,22 @@ /** - * ownCloud Android client application + * ownCloud Android client application * - * @author Bartek Przybylski - * @author David A. Velasco - * Copyright (C) 2011 Bartek Przybylski - * Copyright (C) 2016 ownCloud Inc. + * @author Bartek Przybylski + * @author David A. Velasco + * Copyright (C) 2011 Bartek Przybylski + * Copyright (C) 2016 ownCloud Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, - * as published by the Free Software Foundation. + * This program is 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. + * 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 . + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ package com.owncloud.android.ui.activity; @@ -41,6 +41,7 @@ import android.os.Build; import android.os.Bundle; import android.os.IBinder; import android.os.Parcelable; +import android.support.design.widget.BottomNavigationView; import android.support.design.widget.Snackbar; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; @@ -81,6 +82,7 @@ import com.owncloud.android.operations.UploadFileOperation; import com.owncloud.android.services.observer.FileObserverService; import com.owncloud.android.syncadapter.FileSyncAdapter; import com.owncloud.android.ui.dialog.SortingOrderDialogFragment; +import com.owncloud.android.ui.fragment.ExtendedListFragment; import com.owncloud.android.ui.fragment.FileDetailFragment; import com.owncloud.android.ui.fragment.FileFragment; import com.owncloud.android.ui.fragment.OCFileListFragment; @@ -148,6 +150,7 @@ public class FileDisplayActivity extends HookActivity private OCFile mWaitingToSend; private Collection mDrawerMenuItemstoShowHideList; + private String searchQuery; private SearchView searchView; @@ -188,12 +191,13 @@ public class FileDisplayActivity extends HookActivity setupToolbar(); // setup drawer - if(MainApp.isOnlyOnDevice()) { + if (MainApp.isOnlyOnDevice()) { setupDrawer(R.id.nav_on_device); } else { setupDrawer(R.id.nav_all_files); } + mDualPane = getResources().getBoolean(R.bool.large_land_layout); mLeftFragmentContainer = findViewById(R.id.left_fragment_container); mRightFragmentContainer = findViewById(R.id.right_fragment_container); @@ -322,27 +326,6 @@ public class FileDisplayActivity extends HookActivity } } - @Override - protected void onStart() { - Log_OC.v(TAG, "onStart() start"); - super.onStart(); - Log_OC.v(TAG, "onStart() end"); - } - - @Override - protected void onStop() { - Log_OC.v(TAG, "onStop() start"); - super.onStop(); - Log_OC.v(TAG, "onStop() end"); - } - - @Override - protected void onDestroy() { - Log_OC.v(TAG, "onDestroy() start"); - super.onDestroy(); - Log_OC.v(TAG, "onDestroy() end"); - } - /** * Called when the ownCloud {@link Account} associated to the Activity was just updated. */ @@ -377,6 +360,7 @@ public class FileDisplayActivity extends HookActivity if (mAccountWasSet) { setAccountInDrawer(getAccount()); + setupDrawer(); } if (!stateWasRecovered) { @@ -599,7 +583,7 @@ public class FileDisplayActivity extends HookActivity public boolean onPrepareOptionsMenu(Menu menu) { boolean drawerOpen = isDrawerOpen(); - for (MenuItem menuItem:mDrawerMenuItemstoShowHideList) { + for (MenuItem menuItem : mDrawerMenuItemstoShowHideList) { menuItem.setVisible(!drawerOpen); } @@ -776,16 +760,16 @@ public class FileDisplayActivity extends HookActivity protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE__SELECT_CONTENT_FROM_APPS && - (resultCode == RESULT_OK || - resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) { + (resultCode == RESULT_OK || + resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE)) { requestUploadOfContentFromApps(data, resultCode); } else if (requestCode == REQUEST_CODE__SELECT_FILES_FROM_FILE_SYSTEM && - (resultCode == RESULT_OK || - resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE || - resultCode == UploadFilesActivity.RESULT_OK_AND_DO_NOTHING || - resultCode == UploadFilesActivity.RESULT_OK_AND_DELETE)) { + (resultCode == RESULT_OK || + resultCode == UploadFilesActivity.RESULT_OK_AND_MOVE || + resultCode == UploadFilesActivity.RESULT_OK_AND_DO_NOTHING || + resultCode == UploadFilesActivity.RESULT_OK_AND_DELETE)) { requestUploadOfFilesFromFileSystem(data, resultCode); @@ -874,8 +858,8 @@ public class FileDisplayActivity extends HookActivity //getClipData is only supported on api level 16+, Jelly Bean if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && - contentIntent.getClipData() != null && - contentIntent.getClipData().getItemCount() > 0) { + contentIntent.getClipData() != null && + contentIntent.getClipData().getItemCount() > 0) { for (int i = 0; i < contentIntent.getClipData().getItemCount(); i++) { streamsToUpload.add(contentIntent.getClipData().getItemAt(i).getUri()); @@ -932,6 +916,15 @@ public class FileDisplayActivity extends HookActivity return (mSearchEditFrame != null && mSearchEditFrame.getVisibility() == View.VISIBLE); } + private void revertBottomNavigationBarToAllFiles() { + if (getResources().getBoolean(R.bool.bottom_toolbar_enabled)) { + BottomNavigationView bottomNavigationView = (BottomNavigationView) getListOfFilesFragment().getView() + .findViewById(R.id.bottom_navigation_view); + if (bottomNavigationView.getMenu().findItem(R.id.nav_bar_settings).isChecked()) { + bottomNavigationView.getMenu().findItem(R.id.nav_bar_files).setChecked(true); + } + } + } @Override public void onBackPressed() { @@ -946,14 +939,15 @@ public class FileDisplayActivity extends HookActivity * 3. close FAB if open (only if drawer isn't open) * 4. navigate up (only if drawer and FAB aren't open) */ + if (isSearchOpen && searchView != null) { searchView.setQuery("", true); searchView.onActionViewCollapsed(); setDrawerIndicatorEnabled(isDrawerIndicatorAvailable()); - } else if(isDrawerOpen && isFabOpen) { + } else if (isDrawerOpen && isFabOpen) { // close drawer first super.onBackPressed(); - } else if(isDrawerOpen && !isFabOpen) { + } else if (isDrawerOpen && !isFabOpen) { // close drawer super.onBackPressed(); } else if (!isDrawerOpen && isFabOpen) { @@ -1001,6 +995,8 @@ public class FileDisplayActivity extends HookActivity Log_OC.v(TAG, "onResume() start"); super.onResume(); + + revertBottomNavigationBarToAllFiles(); // refresh list of files if (searchView != null && !TextUtils.isEmpty(searchQuery)) { @@ -1059,13 +1055,9 @@ public class FileDisplayActivity extends HookActivity } public boolean isFabOpen() { - if(getListOfFilesFragment() != null + return (getListOfFilesFragment() != null && getListOfFilesFragment().getFabMain() != null - && getListOfFilesFragment().getFabMain().isExpanded()) { - return true; - } else { - return false; - } + && getListOfFilesFragment().getFabMain().isExpanded()); } @Override @@ -1151,7 +1143,7 @@ public class FileDisplayActivity extends HookActivity OCFileListFragment fileListFragment = getListOfFilesFragment(); if (fileListFragment != null) { fileListFragment.listDirectory(currentDir, - MainApp.isOnlyOnDevice(), false); + MainApp.isOnlyOnDevice(), false); } } setFile(currentFile); @@ -1216,7 +1208,7 @@ public class FileDisplayActivity extends HookActivity OCFileListFragment ocFileListFragment = getListOfFilesFragment(); if (ocFileListFragment != null) { if (!mSyncInProgress) { - ocFileListFragment.setEmptyListMessage(false); + ocFileListFragment.setEmptyListMessage(ExtendedListFragment.SearchType.NO_SEARCH); } else { ocFileListFragment.setEmptyListLoadingMessage(); } @@ -1291,8 +1283,7 @@ public class FileDisplayActivity extends HookActivity OCFile ocFile = getFile(); if (PreviewImageFragment.canBePreviewed(ocFile)) { startImagePreview(getFile()); - } - else if (PreviewTextFragment.canBePreviewed(ocFile)) { + } else if (PreviewTextFragment.canBePreviewed(ocFile)) { startTextPreview(ocFile); } // TODO what about other kind of previews? @@ -1571,8 +1562,8 @@ public class FileDisplayActivity extends HookActivity private void onRemoveFileOperationFinish(RemoveFileOperation operation, RemoteOperationResult result) { Toast msg = Toast.makeText(this, - ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), - Toast.LENGTH_LONG); + ErrorMessageAdapter.getErrorCauseMessage(result, operation, getResources()), + Toast.LENGTH_LONG); msg.show(); if (result.isSuccess()) { @@ -1952,7 +1943,7 @@ public class FileDisplayActivity extends HookActivity * @param files collection of {@link OCFile} files which operations are wanted to be cancel */ public void cancelTransference(Collection files) { - for(OCFile file: files) { + for (OCFile file : files) { cancelTransference(file); } } diff --git a/src/main/java/com/owncloud/android/ui/activity/Preferences.java b/src/main/java/com/owncloud/android/ui/activity/Preferences.java index 9c751603a5..22bb937e60 100644 --- a/src/main/java/com/owncloud/android/ui/activity/Preferences.java +++ b/src/main/java/com/owncloud/android/ui/activity/Preferences.java @@ -808,5 +808,4 @@ public class Preferences extends PreferenceActivity public void onCancelMigration() { // Migration was canceled so we don't do anything } - } diff --git a/src/main/java/com/owncloud/android/ui/adapter/FileListListAdapter.java b/src/main/java/com/owncloud/android/ui/adapter/FileListListAdapter.java index 1165b6a1ed..4321a016c6 100644 --- a/src/main/java/com/owncloud/android/ui/adapter/FileListListAdapter.java +++ b/src/main/java/com/owncloud/android/ui/adapter/FileListListAdapter.java @@ -27,6 +27,8 @@ import android.accounts.Account; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Color; +import android.os.Handler; +import android.os.Looper; import android.text.TextUtils; import android.util.SparseBooleanArray; import android.view.LayoutInflater; @@ -37,7 +39,6 @@ import android.widget.BaseAdapter; import android.widget.Filter; import android.widget.GridView; import android.widget.ImageView; -import android.widget.LinearLayout; import android.widget.TextView; import com.owncloud.android.R; @@ -48,13 +49,17 @@ import com.owncloud.android.datamodel.ThumbnailsCacheManager; import com.owncloud.android.db.PreferenceManager; import com.owncloud.android.files.services.FileDownloader.FileDownloaderBinder; import com.owncloud.android.files.services.FileUploader.FileUploaderBinder; +import com.owncloud.android.lib.resources.files.RemoteFile; +import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.services.OperationsService.OperationsServiceBinder; import com.owncloud.android.ui.activity.ComponentsGetter; -import com.owncloud.android.ui.interfaces.ExtendedListFragmentInterface; +import com.owncloud.android.ui.fragment.ExtendedListFragment; +import com.owncloud.android.ui.interfaces.OCFileListFragmentInterface; import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.FileStorageUtils; import com.owncloud.android.utils.MimeTypeUtil; +import java.io.File; import java.util.ArrayList; import java.util.Vector; @@ -74,7 +79,7 @@ public class FileListListAdapter extends BaseAdapter { private FileDataStorageManager mStorageManager; private Account mAccount; private ComponentsGetter mTransferServiceGetter; - private ExtendedListFragmentInterface extendedListFragmentInterface; + private OCFileListFragmentInterface OCFileListFragmentInterface; private FilesFilter mFilesFilter; private OCFile currentDirectory; @@ -83,10 +88,10 @@ public class FileListListAdapter extends BaseAdapter { boolean justFolders, Context context, ComponentsGetter transferServiceGetter, - ExtendedListFragmentInterface extendedListFragmentInterface + OCFileListFragmentInterface OCFileListFragmentInterface ) { - this.extendedListFragmentInterface = extendedListFragmentInterface; + this.OCFileListFragmentInterface = OCFileListFragmentInterface; mJustFolders = justFolders; mContext = context; mAccount = AccountUtils.getCurrentOwnCloudAccount(mContext); @@ -127,6 +132,29 @@ public class FileListListAdapter extends BaseAdapter { return mFiles.get(position); } + public void setFavoriteAttributeForItemID(String fileId, boolean favorite) { + for (int i = 0; i < mFiles.size(); i++) { + if (mFiles.get(i).getRemoteId().equals(fileId)) { + mFiles.get(i).setFavorite(favorite); + break; + } + } + + for (int i = 0; i < mFilesAll.size(); i++) { + if (mFilesAll.get(i).getRemoteId().equals(fileId)) { + mFilesAll.get(i).setFavorite(favorite); + break; + } + } + + new Handler(Looper.getMainLooper()).post(new Runnable() { + @Override + public void run() { + notifyDataSetChanged(); + } + }); + } + @Override public long getItemId(int position) { if (mFiles == null || mFiles.size() <= position) { @@ -190,9 +218,6 @@ public class FileListListAdapter extends BaseAdapter { TextView fileName; String name = file.getFileName(); - LinearLayout linearLayout = (LinearLayout) view.findViewById(R.id.ListItemLayout); - linearLayout.setContentDescription("LinearLayout-" + name); - switch (viewType) { case LIST_ITEM: TextView fileSizeV = (TextView) view.findViewById(R.id.file_size); @@ -208,6 +233,7 @@ public class FileListListAdapter extends BaseAdapter { fileSizeV.setVisibility(View.VISIBLE); fileSizeV.setText(DisplayUtils.bytesToHumanReadable(file.getFileLength())); + case GRID_ITEM: // filename fileName = (TextView) view.findViewById(R.id.Filename); @@ -276,6 +302,12 @@ public class FileListListAdapter extends BaseAdapter { // For all Views + if (file.getIsFavorite()) { + view.findViewById(R.id.favorite_action).setVisibility(View.VISIBLE); + } else { + view.findViewById(R.id.favorite_action).setVisibility(View.GONE); + } + ImageView checkBoxV = (ImageView) view.findViewById(R.id.custom_checkbox); checkBoxV.setVisibility(View.GONE); view.setBackgroundColor(Color.WHITE); @@ -297,14 +329,15 @@ public class FileListListAdapter extends BaseAdapter { checkBoxV.setVisibility(View.VISIBLE); } - // this if-else is needed even though favorite icon is visible by default + // this if-else is needed even though kept-in-sync icon is visible by default // because android reuses views in listview - if (!file.isFavorite()) { - view.findViewById(R.id.favoriteIcon).setVisibility(View.GONE); + if (!file.isAvailableOffline()) { + view.findViewById(R.id.keptOfflineIcon).setVisibility(View.GONE); } else { - view.findViewById(R.id.favoriteIcon).setVisibility(View.VISIBLE); + view.findViewById(R.id.keptOfflineIcon).setVisibility(View.VISIBLE); } + // No Folder if (!file.isFolder()) { if ((MimeTypeUtil.isImage(file) || MimeTypeUtil.isVideo(file)) && file.getRemoteId() != null) { @@ -419,6 +452,60 @@ public class FileListListAdapter extends BaseAdapter { notifyDataSetChanged(); } + private void searchForLocalFileInDefaultPath(OCFile file) { + if (file.getStoragePath() == null && !file.isFolder()) { + File f = new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, file)); + if (f.exists()) { + file.setStoragePath(f.getAbsolutePath()); + file.setLastSyncDateForData(f.lastModified()); + } + } + } + + public void setData(ArrayList objects, ExtendedListFragment.SearchType searchType) { + mFiles = new Vector<>(); + if (searchType.equals(ExtendedListFragment.SearchType.SHARED_FILTER)) { + ArrayList shares = new ArrayList<>(); + for (int i = 0; i < objects.size(); i++) { + shares.add((OCShare) objects.get(i)); + } + mStorageManager.saveShares(shares); + } + for (int i = 0; i < objects.size(); i++) { + if (!searchType.equals(ExtendedListFragment.SearchType.SHARED_FILTER)) { + OCFile ocFile = FileStorageUtils.fillOCFile((RemoteFile) objects.get(i)); + searchForLocalFileInDefaultPath(ocFile); + mFiles.add(ocFile); + } else { + OCShare ocShare = (OCShare) objects.get(i); + OCFile ocFile = mStorageManager.getFileByPath(ocShare.getPath()); + if (!mFiles.contains(ocFile)) { + mFiles.add(ocFile); + } + } + } + + if (!searchType.equals(ExtendedListFragment.SearchType.PHOTO_SEARCH) && + !searchType.equals(ExtendedListFragment.SearchType.PHOTOS_SEARCH_FILTER) && + !searchType.equals(ExtendedListFragment.SearchType.RECENTLY_MODIFIED_SEARCH) && + !searchType.equals(ExtendedListFragment.SearchType.RECENTLY_MODIFIED_SEARCH_FILTER)) { + mFiles = FileStorageUtils.sortOcFolder(mFiles); + } else { + mFiles = FileStorageUtils.sortOcFolderDescDateModified(mFiles); + } + + mFilesAll = new Vector<>(); + mFilesAll.addAll(mFiles); + + new Handler(Looper.getMainLooper()).post(new Runnable() { + @Override + public void run() { + notifyDataSetChanged(); + OCFileListFragmentInterface.finishedFiltering(); + } + }); + } + /** * Filter for getting only the folders * @@ -510,7 +597,7 @@ public class FileListListAdapter extends BaseAdapter { } notifyDataSetChanged(); - extendedListFragmentInterface.finishedFiltering(); + OCFileListFragmentInterface.finishedFiltering(); } } diff --git a/src/main/java/com/owncloud/android/ui/adapter/LocalFileListAdapter.java b/src/main/java/com/owncloud/android/ui/adapter/LocalFileListAdapter.java index f69cf9fcff..11980dffad 100644 --- a/src/main/java/com/owncloud/android/ui/adapter/LocalFileListAdapter.java +++ b/src/main/java/com/owncloud/android/ui/adapter/LocalFileListAdapter.java @@ -241,7 +241,8 @@ public class LocalFileListAdapter extends BaseAdapter implements FilterableListA // not GONE; the alignment changes; ugly way to keep it view.findViewById(R.id.localFileIndicator).setVisibility(View.INVISIBLE); - view.findViewById(R.id.favoriteIcon).setVisibility(View.GONE); + view.findViewById(R.id.keptOfflineIcon).setVisibility(View.GONE); + view.findViewById(R.id.favorite_action).setVisibility(View.GONE); view.findViewById(R.id.sharedIcon).setVisibility(View.GONE); } diff --git a/src/main/java/com/owncloud/android/ui/dialog/RemoveFileDialogFragment.java b/src/main/java/com/owncloud/android/ui/dialog/RemoveFileDialogFragment.java index a62850a2e0..7bad6a973a 100644 --- a/src/main/java/com/owncloud/android/ui/dialog/RemoveFileDialogFragment.java +++ b/src/main/java/com/owncloud/android/ui/dialog/RemoveFileDialogFragment.java @@ -57,7 +57,7 @@ implements ConfirmationDialogFragmentListener { int messageStringId = R.string.confirmation_remove_file_alert; - int localRemoveButton = (!file.isFavorite() && (file.isFolder() || file.isDown())) ? + int localRemoveButton = (!file.isAvailableOffline() && (file.isFolder() || file.isDown())) ? R.string.confirmation_remove_local : -1; if (file.isFolder()) { @@ -115,7 +115,7 @@ implements ConfirmationDialogFragmentListener { if (mTargetFile.isFolder()) { Vector files = storageManager.getFolderContent(mTargetFile, false); for(OCFile file: files) { - containsFavorite = file.isFavorite() || containsFavorite; + containsFavorite = file.isAvailableOffline() || containsFavorite; if (containsFavorite) { break; @@ -125,7 +125,7 @@ implements ConfirmationDialogFragmentListener { // Remove etag for parent, if file is a favorite // or is a folder and contains favorite - if (mTargetFile.isFavorite() || containsFavorite) { + if (mTargetFile.isAvailableOffline() || containsFavorite) { OCFile folder = null; if (mTargetFile.isFolder()) { folder = mTargetFile; diff --git a/src/main/java/com/owncloud/android/ui/dialog/RemoveFilesDialogFragment.java b/src/main/java/com/owncloud/android/ui/dialog/RemoveFilesDialogFragment.java index a3e7261682..b4a429348c 100644 --- a/src/main/java/com/owncloud/android/ui/dialog/RemoveFilesDialogFragment.java +++ b/src/main/java/com/owncloud/android/ui/dialog/RemoveFilesDialogFragment.java @@ -61,7 +61,7 @@ implements ConfirmationDialogFragmentListener { for (OCFile file: files) { containsFolder |= file.isFolder(); containsDown |= file.isDown(); - containsFavorite |= file.isFavorite(); + containsFavorite |= file.isAvailableOffline(); } if (files.size() == 1) { diff --git a/src/main/java/com/owncloud/android/ui/events/ChangeMenuEvent.java b/src/main/java/com/owncloud/android/ui/events/ChangeMenuEvent.java new file mode 100644 index 0000000000..a661414a70 --- /dev/null +++ b/src/main/java/com/owncloud/android/ui/events/ChangeMenuEvent.java @@ -0,0 +1,26 @@ +/** + * Nextcloud Android client application + * + * @author Mario Danic + * Copyright (C) 2017 Mario Danic + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package com.owncloud.android.ui.events; + +/** + * Currently a dummy event to restore grid view, sort, and search + */ +public class ChangeMenuEvent { +} diff --git a/src/main/java/com/owncloud/android/ui/events/DummyDrawerEvent.java b/src/main/java/com/owncloud/android/ui/events/DummyDrawerEvent.java new file mode 100644 index 0000000000..4236872c0c --- /dev/null +++ b/src/main/java/com/owncloud/android/ui/events/DummyDrawerEvent.java @@ -0,0 +1,26 @@ +/** + * Nextcloud Android client application + * + * @author Mario Danic + * Copyright (C) 2017 Mario Danic + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package com.owncloud.android.ui.events; + +/** + * Dummy drawer event + */ +public class DummyDrawerEvent { +} diff --git a/src/main/java/com/owncloud/android/ui/events/FavoriteEvent.java b/src/main/java/com/owncloud/android/ui/events/FavoriteEvent.java new file mode 100644 index 0000000000..490db2ccbf --- /dev/null +++ b/src/main/java/com/owncloud/android/ui/events/FavoriteEvent.java @@ -0,0 +1,35 @@ +/** + * Nextcloud Android client application + * + * @author Mario Danic + * Copyright (C) 2017 Mario Danic + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package com.owncloud.android.ui.events; + +/** + * Event for making favoriting work + */ +public class FavoriteEvent { + public final String remotePath; + public final boolean shouldFavorite; + public final String remoteId; + + public FavoriteEvent(String remotePath, boolean shouldFavorite, String remoteId) { + this.remotePath = remotePath; + this.shouldFavorite = shouldFavorite; + this.remoteId = remoteId; + } +} diff --git a/src/main/java/com/owncloud/android/ui/events/MenuItemClickEvent.java b/src/main/java/com/owncloud/android/ui/events/MenuItemClickEvent.java new file mode 100644 index 0000000000..46aebcd79e --- /dev/null +++ b/src/main/java/com/owncloud/android/ui/events/MenuItemClickEvent.java @@ -0,0 +1,33 @@ +/** + * Nextcloud Android client application + * + * @author Mario Danic + * Copyright (C) 2017 Mario Danic + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package com.owncloud.android.ui.events; + +import android.view.MenuItem; + +/** + * Menu item click event + */ +public class MenuItemClickEvent { + public final MenuItem menuItem; + + public MenuItemClickEvent(MenuItem menuItem) { + this.menuItem = menuItem; + } +} diff --git a/src/main/java/com/owncloud/android/ui/events/SearchEvent.java b/src/main/java/com/owncloud/android/ui/events/SearchEvent.java new file mode 100644 index 0000000000..da31b6c265 --- /dev/null +++ b/src/main/java/com/owncloud/android/ui/events/SearchEvent.java @@ -0,0 +1,59 @@ +/** + * Nextcloud Android client application + * + * @author Mario Danic + * Copyright (C) 2017 Mario Danic + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package com.owncloud.android.ui.events; + +import com.owncloud.android.lib.resources.files.SearchOperation; + +/** + * Search event + */ +public class SearchEvent { + public final String searchQuery; + + public final SearchOperation.SearchType searchType; + + public final UnsetType unsetType; + + public enum UnsetType { + NO_UNSET, + UNSET_DRAWER, + UNSET_BOTTOM_NAV_BAR; + } + + public SearchEvent(String searchQuery, SearchOperation.SearchType searchType, UnsetType unsetType) { + + this.searchQuery = searchQuery; + this.searchType = searchType; + this.unsetType = unsetType; + + } + + public UnsetType getUnsetType() { + return unsetType; + } + + public String getSearchQuery() { + return searchQuery; + } + + public SearchOperation.SearchType getSearchType() { + return searchType; + } +} diff --git a/src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.java b/src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.java index cc014c1baa..1cab83fbac 100644 --- a/src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.java +++ b/src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.java @@ -1,21 +1,22 @@ /** - * ownCloud Android client application + * ownCloud Android client application * - * Copyright (C) 2012 Bartek Przybylski - * Copyright (C) 2012-2016 ownCloud Inc. + * @author Mario Danic + * Copyright (C) 2017 Mario Danic + * Copyright (C) 2012 Bartek Przybylski + * Copyright (C) 2012-2016 ownCloud Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, - * as published by the Free Software Foundation. + * This program is 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 . + * 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 . */ package com.owncloud.android.ui.fragment; @@ -24,8 +25,10 @@ import android.animation.LayoutTransition; import android.app.Activity; import android.os.Bundle; import android.os.Handler; +import android.os.Looper; import android.support.annotation.DrawableRes; import android.support.annotation.StringRes; +import android.support.design.widget.BottomNavigationView; import android.support.v4.app.Fragment; import android.support.v4.view.MenuItemCompat; import android.support.v4.widget.SwipeRefreshLayout; @@ -47,12 +50,16 @@ import android.widget.GridView; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ProgressBar; +import android.widget.RelativeLayout; import android.widget.TextView; import com.getbase.floatingactionbutton.FloatingActionButton; import com.getbase.floatingactionbutton.FloatingActionsMenu; +import com.owncloud.android.MainApp; import com.owncloud.android.R; +import com.owncloud.android.authentication.AccountUtils; import com.owncloud.android.lib.common.utils.Log_OC; +import com.owncloud.android.lib.resources.files.SearchOperation; import com.owncloud.android.ui.ExtendedListView; import com.owncloud.android.ui.activity.FileDisplayActivity; import com.owncloud.android.ui.activity.FolderPickerActivity; @@ -60,6 +67,10 @@ import com.owncloud.android.ui.activity.OnEnforceableRefreshListener; import com.owncloud.android.ui.activity.UploadFilesActivity; import com.owncloud.android.ui.adapter.FileListListAdapter; import com.owncloud.android.ui.adapter.LocalFileListAdapter; +import com.owncloud.android.ui.events.SearchEvent; + +import org.greenrobot.eventbus.EventBus; +import org.parceler.Parcel; import java.util.ArrayList; @@ -72,10 +83,10 @@ public class ExtendedListFragment extends Fragment protected static final String TAG = ExtendedListFragment.class.getSimpleName(); - protected static final String KEY_SAVED_LIST_POSITION = "SAVED_LIST_POSITION"; + protected static final String KEY_SAVED_LIST_POSITION = "SAVED_LIST_POSITION"; private static final String KEY_INDEXES = "INDEXES"; - private static final String KEY_FIRST_POSITIONS= "FIRST_POSITIONS"; + private static final String KEY_FIRST_POSITIONS = "FIRST_POSITIONS"; private static final String KEY_TOPS = "TOPS"; private static final String KEY_HEIGHT_CELL = "HEIGHT_CELL"; private static final String KEY_EMPTY_LIST_MESSAGE = "EMPTY_LIST_MESSAGE"; @@ -114,6 +125,25 @@ public class ExtendedListFragment extends Fragment protected SearchView searchView; private Handler handler = new Handler(); + @Parcel + public enum SearchType { + NO_SEARCH, + REGULAR_FILTER, + FILE_SEARCH, + FAVORITE_SEARCH, + FAVORITE_SEARCH_FILTER, + VIDEO_SEARCH, + VIDEO_SEARCH_FILTER, + PHOTO_SEARCH, + PHOTOS_SEARCH_FILTER, + RECENTLY_MODIFIED_SEARCH, + RECENTLY_MODIFIED_SEARCH_FILTER, + RECENTLY_ADDED_SEARCH, + RECENTLY_ADDED_SEARCH_FILTER, + // not a real filter, but nevertheless + SHARED_FILTER + } + protected void setListAdapter(BaseAdapter listAdapter) { mAdapter = listAdapter; mCurrentListView.setAdapter(listAdapter); @@ -160,7 +190,7 @@ public class ExtendedListFragment extends Fragment } } - public boolean isGridEnabled(){ + public boolean isGridEnabled() { return (mCurrentListView != null && mCurrentListView.equals(mGridView)); } @@ -200,6 +230,20 @@ public class ExtendedListFragment extends Fragment public void run() { if (getActivity() != null && !(getActivity() instanceof FolderPickerActivity)) { setFabEnabled(!hasFocus); + + boolean searchSupported = AccountUtils.hasSearchSupport(AccountUtils. + getCurrentOwnCloudAccount(MainApp.getAppContext())); + + if (getResources().getBoolean(R.bool.bottom_toolbar_enabled) && searchSupported) { + BottomNavigationView bottomNavigationView = (BottomNavigationView) getActivity(). + findViewById(R.id.bottom_navigation_view); + if (hasFocus) { + bottomNavigationView.setVisibility(View.GONE); + } else { + bottomNavigationView.setVisibility(View.VISIBLE); + } + } + } } }, 100); @@ -220,9 +264,10 @@ public class ExtendedListFragment extends Fragment if (currentVisibility != oldVisibility) { if (currentVisibility == View.VISIBLE) { - setEmptyListMessage(true); + + setEmptyListMessage(SearchType.REGULAR_FILTER); } else { - setEmptyListMessage(false); + setEmptyListMessage(SearchType.NO_SEARCH); } oldVisibility = currentVisibility; @@ -262,8 +307,14 @@ public class ExtendedListFragment extends Fragment handler.postDelayed(new Runnable() { @Override public void run() { - FileListListAdapter fileListListAdapter = (FileListListAdapter) mAdapter; - fileListListAdapter.getFilter().filter(query); + if (AccountUtils.hasSearchSupport(AccountUtils. + getCurrentOwnCloudAccount(MainApp.getAppContext()))) { + EventBus.getDefault().post(new SearchEvent(query, SearchOperation.SearchType.FILE_SEARCH, + SearchEvent.UnsetType.NO_UNSET)); + } else { + FileListListAdapter fileListListAdapter = (FileListListAdapter) mAdapter; + fileListListAdapter.getFilter().filter(query); + } } }, delay); } else if (mAdapter != null && mAdapter instanceof LocalFileListAdapter) { @@ -284,11 +335,11 @@ public class ExtendedListFragment extends Fragment if ((activity = getActivity()) != null) { if (activity instanceof FileDisplayActivity) { ((FileDisplayActivity) activity).refreshListOfFilesFragment(true); - } else if (activity instanceof UploadFilesActivity){ + } else if (activity instanceof UploadFilesActivity) { LocalFileListAdapter localFileListAdapter = (LocalFileListAdapter) mAdapter; localFileListAdapter.filter(query); } else if (activity instanceof FolderPickerActivity) { - ((FolderPickerActivity)activity).refreshListOfFilesFragment(true); + ((FolderPickerActivity) activity).refreshListOfFilesFragment(true); } } @@ -305,7 +356,7 @@ public class ExtendedListFragment extends Fragment View v = inflater.inflate(R.layout.list_fragment, null); setupEmptyList(v); - mListView = (ExtendedListView)(v.findViewById(R.id.list_root)); + mListView = (ExtendedListView) (v.findViewById(R.id.list_root)); mListView.setOnItemClickListener(this); mListFooterView = inflater.inflate(R.layout.list_footer, null, false); @@ -332,6 +383,21 @@ public class ExtendedListFragment extends Fragment mFabMkdir = (FloatingActionButton) v.findViewById(R.id.fab_mkdir); mFabUploadFromApp = (FloatingActionButton) v.findViewById(R.id.fab_upload_from_app); + boolean searchSupported = AccountUtils.hasSearchSupport(AccountUtils. + getCurrentOwnCloudAccount(MainApp.getAppContext())); + + if (getResources().getBoolean(R.bool.bottom_toolbar_enabled) && searchSupported) { + RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) mFabMain.getLayoutParams(); + final float scale = v.getResources().getDisplayMetrics().density; + + BottomNavigationView bottomNavigationView = (BottomNavigationView) + v.findViewById(R.id.bottom_navigation_view); + + // convert the DP into pixel + int pixel = (int) (32 * scale + 0.5f); + layoutParams.setMargins(0, 0, pixel / 2, bottomNavigationView.getMeasuredHeight() + pixel * 2); + } + mCurrentListView = mListView; // list by default if (savedInstanceState != null) { @@ -366,23 +432,23 @@ public class ExtendedListFragment extends Fragment @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - + if (savedInstanceState != null) { mIndexes = savedInstanceState.getIntegerArrayList(KEY_INDEXES); mFirstPositions = savedInstanceState.getIntegerArrayList(KEY_FIRST_POSITIONS); mTops = savedInstanceState.getIntegerArrayList(KEY_TOPS); mHeightCell = savedInstanceState.getInt(KEY_HEIGHT_CELL); setMessageForEmptyList(savedInstanceState.getString(KEY_EMPTY_LIST_MESSAGE)); - + } else { mIndexes = new ArrayList<>(); mFirstPositions = new ArrayList<>(); mTops = new ArrayList<>(); mHeightCell = 0; } - } - - + } + + @Override public void onSaveInstanceState(Bundle savedInstanceState) { super.onSaveInstanceState(savedInstanceState); @@ -400,12 +466,12 @@ public class ExtendedListFragment extends Fragment * Calculates the position of the item that will be used as a reference to * reposition the visible items in the list when the device is turned to * other position. - * + * * The current policy is take as a reference the visible item in the center * of the screen. - * + * * @return The position in the list of the visible item in the center of the - * screen. + * screen. */ protected int getReferencePosition() { if (mCurrentListView != null) { @@ -421,25 +487,25 @@ public class ExtendedListFragment extends Fragment * Restore index and position */ protected void restoreIndexAndTopPosition() { - if (mIndexes.size() > 0) { + if (mIndexes.size() > 0) { // needs to be checked; not every browse-up had a browse-down before - + int index = mIndexes.remove(mIndexes.size() - 1); - final int firstPosition = mFirstPositions.remove(mFirstPositions.size() -1); + final int firstPosition = mFirstPositions.remove(mFirstPositions.size() - 1); int top = mTops.remove(mTops.size() - 1); Log_OC.v(TAG, "Setting selection to position: " + firstPosition + "; top: " + top + "; index: " + index); - if (mCurrentListView!= null && mCurrentListView.equals(mListView)) { - if (mHeightCell*index <= mListView.getHeight()) { + if (mCurrentListView != null && mCurrentListView.equals(mListView)) { + if (mHeightCell * index <= mListView.getHeight()) { mListView.setSelectionFromTop(firstPosition, top); } else { mListView.setSelectionFromTop(index, 0); } } else { - if (mHeightCell*index <= mGridView.getHeight()) { + if (mHeightCell * index <= mGridView.getHeight()) { mGridView.setSelection(firstPosition); //mGridView.smoothScrollToPosition(firstPosition); } else { @@ -450,29 +516,29 @@ public class ExtendedListFragment extends Fragment } } - + /* * Save index and top position */ protected void saveIndexAndTopPosition(int index) { - + mIndexes.add(index); - + int firstPosition = mCurrentListView.getFirstVisiblePosition(); mFirstPositions.add(firstPosition); - + View view = mCurrentListView.getChildAt(0); - int top = (view == null) ? 0 : view.getTop() ; + int top = (view == null) ? 0 : view.getTop(); mTops.add(top); - + // Save the height of a cell mHeightCell = (view == null || mHeightCell != 0) ? mHeightCell : view.getHeight(); } - - + + @Override - public void onItemClick (AdapterView parent, View view, int position, long id) { + public void onItemClick(AdapterView parent, View view, int position, long id) { // to be @overriden } @@ -501,7 +567,7 @@ public class ExtendedListFragment extends Fragment public void setOnRefreshListener(OnEnforceableRefreshListener listener) { mOnRefreshListener = listener; } - + /** * Disables swipe gesture. @@ -510,7 +576,7 @@ public class ExtendedListFragment extends Fragment * * When 'false' is set, prevents user gestures but keeps the option to refresh programatically, * - * @param enabled Desired state for capturing swipe gesture. + * @param enabled Desired state for capturing swipe gesture. */ public void setSwipeEnabled(boolean enabled) { mRefreshListLayout.setEnabled(enabled); @@ -523,10 +589,10 @@ public class ExtendedListFragment extends Fragment * * When 'false' is set, FAB visibility is set to View.GONE programmatically, * - * @param enabled Desired visibility for the FAB. + * @param enabled Desired visibility for the FAB. */ public void setFabEnabled(boolean enabled) { - if(enabled) { + if (enabled) { mFabMain.setVisibility(View.VISIBLE); } else { mFabMain.setVisibility(View.GONE); @@ -549,47 +615,99 @@ public class ExtendedListFragment extends Fragment * @param message the message * @param icon the icon to be shown */ - public void setMessageForEmptyList(@StringRes int headline, @StringRes int message, @DrawableRes int icon) { - if (mEmptyListContainer != null && mEmptyListMessage != null) { - mEmptyListHeadline.setText(headline); - mEmptyListMessage.setText(message); - mEmptyListIcon.setImageResource(icon); + public void setMessageForEmptyList(@StringRes final int headline, @StringRes final int message, @DrawableRes final int icon) { + new Handler(Looper.getMainLooper()).post(new Runnable() { + @Override + public void run() { - mEmptyListIcon.setVisibility(View.VISIBLE); - mEmptyListProgress.setVisibility(View.GONE); - } + if (mEmptyListContainer != null && mEmptyListMessage != null) { + mEmptyListHeadline.setText(headline); + mEmptyListMessage.setText(message); + mEmptyListIcon.setImageResource(icon); + + mEmptyListIcon.setVisibility(View.VISIBLE); + mEmptyListProgress.setVisibility(View.GONE); + } + } + }); } - public void setEmptyListMessage(boolean isSearch) { - if (isSearch) { - setMessageForEmptyList(R.string.file_list_empty_headline_search, - R.string.file_list_empty_search, R.drawable.ic_search_light_grey); + public void setEmptyListMessage(final SearchType searchType) { + new Handler(Looper.getMainLooper()).post(new Runnable() { + @Override + public void run() { - } else { - setMessageForEmptyList( - R.string.file_list_empty_headline, - R.string.file_list_empty, - R.drawable.ic_list_empty_folder - ); - } + if (searchType == SearchType.NO_SEARCH) { + setMessageForEmptyList( + R.string.file_list_empty_headline, + R.string.file_list_empty, + R.drawable.ic_list_empty_folder + ); + } else if (searchType == SearchType.FILE_SEARCH) { + setMessageForEmptyList(R.string.file_list_empty_headline_server_search, + R.string.file_list_empty, R.drawable.ic_search_light_grey); + } else if (searchType == SearchType.FAVORITE_SEARCH) { + setMessageForEmptyList(R.string.file_list_empty_favorite_headline, + R.string.file_list_empty_favorites_filter_list, R.drawable.ic_star_light_grey); + } else if (searchType == SearchType.VIDEO_SEARCH) { + setMessageForEmptyList(R.string.file_list_empty_headline_server_search_videos, + R.string.file_list_empty_text_videos, R.drawable.ic_list_empty_video); + } else if (searchType == SearchType.PHOTO_SEARCH) { + setMessageForEmptyList(R.string.file_list_empty_headline_server_search_photos, + R.string.file_list_empty_text_photos, R.drawable.ic_list_empty_image); + } else if (searchType == SearchType.RECENTLY_MODIFIED_SEARCH) { + setMessageForEmptyList(R.string.file_list_empty_headline_server_search, + R.string.file_list_empty_recently_modified, R.drawable.ic_list_empty_recent); + } else if (searchType == SearchType.RECENTLY_ADDED_SEARCH) { + setMessageForEmptyList(R.string.file_list_empty_headline_server_search, + R.string.file_list_empty_recently_added, R.drawable.ic_list_empty_recent); + } else if (searchType == SearchType.REGULAR_FILTER) { + setMessageForEmptyList(R.string.file_list_empty_headline_search, + R.string.file_list_empty_search, R.drawable.ic_search_light_grey); + } else if (searchType == SearchType.FAVORITE_SEARCH_FILTER) { + setMessageForEmptyList(R.string.file_list_empty_headline_server_search, + R.string.file_list_empty_favorites_filter, R.drawable.ic_star_light_grey); + } else if (searchType == SearchType.VIDEO_SEARCH_FILTER) { + setMessageForEmptyList(R.string.file_list_empty_headline_server_search_videos, + R.string.file_list_empty_text_videos_filter, R.drawable.ic_list_empty_video); + } else if (searchType == SearchType.PHOTOS_SEARCH_FILTER) { + setMessageForEmptyList(R.string.file_list_empty_headline_server_search_photos, + R.string.file_list_empty_text_photos_filter, R.drawable.ic_list_empty_image); + } else if (searchType == SearchType.RECENTLY_MODIFIED_SEARCH_FILTER) { + setMessageForEmptyList(R.string.file_list_empty_headline_server_search, + R.string.file_list_empty_recently_modified_filter, R.drawable.ic_list_empty_recent); + } else if (searchType == SearchType.RECENTLY_ADDED_SEARCH_FILTER) { + setMessageForEmptyList(R.string.file_list_empty_headline_server_search, + R.string.file_list_empty_recently_added_filter, R.drawable.ic_list_empty_recent); + } else if (searchType == SearchType.SHARED_FILTER) { + setMessageForEmptyList(R.string.file_list_empty_shared_headline, + R.string.file_list_empty_shared, R.drawable.ic_list_empty_shared); + } + } + }); } /** * Set message for empty list view. */ public void setEmptyListLoadingMessage() { - if (mEmptyListContainer != null && mEmptyListMessage != null) { - mEmptyListHeadline.setText(R.string.file_list_loading); - mEmptyListMessage.setText(""); + new Handler(Looper.getMainLooper()).post(new Runnable() { + @Override + public void run() { + if (mEmptyListContainer != null && mEmptyListMessage != null) { + mEmptyListHeadline.setText(R.string.file_list_loading); + mEmptyListMessage.setText(""); - mEmptyListIcon.setVisibility(View.GONE); - mEmptyListProgress.setVisibility(View.VISIBLE); - } + mEmptyListIcon.setVisibility(View.GONE); + mEmptyListProgress.setVisibility(View.VISIBLE); + } + } + }); } /** * Get the text of EmptyListMessage TextView. - * + * * @return String empty text view text-value */ public String getEmptyViewText() { @@ -632,7 +750,7 @@ public class ExtendedListFragment extends Fragment protected void setFooterEnabled(boolean enabled) { if (enabled) { if (mGridView.getFooterViewCount() == 0 && mGridView.isCorrectAdapter()) { - if (mGridFooterView.getParent() != null ) { + if (mGridFooterView.getParent() != null) { ((ViewGroup) mGridFooterView.getParent()).removeView(mGridFooterView); } mGridView.addFooterView(mGridFooterView, null, false); @@ -640,7 +758,7 @@ public class ExtendedListFragment extends Fragment mGridFooterView.invalidate(); if (mListView.getFooterViewsCount() == 0) { - if (mListFooterView.getParent() != null ) { + if (mListFooterView.getParent() != null) { ((ViewGroup) mListFooterView.getParent()).removeView(mListFooterView); } mListView.addFooterView(mListFooterView, null, false); @@ -660,8 +778,8 @@ public class ExtendedListFragment extends Fragment */ protected void setFooterText(String text) { if (text != null && text.length() > 0) { - ((TextView)mListFooterView.findViewById(R.id.footerText)).setText(text); - ((TextView)mGridFooterView.findViewById(R.id.footerText)).setText(text); + ((TextView) mListFooterView.findViewById(R.id.footerText)).setText(text); + ((TextView) mGridFooterView.findViewById(R.id.footerText)).setText(text); setFooterEnabled(true); } else { diff --git a/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index ccba220381..4093623eab 100644 --- a/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -219,6 +219,21 @@ public class FileDetailFragment extends FileFragment implements OnClickListener item.setEnabled(false); } + // additional restriction for this fragment + item = menu.findItem(R.id.action_favorite); + if (item != null) { + item.setVisible(false); + item.setEnabled(false); + } + + // additional restriction for this fragment + item = menu.findItem(R.id.action_unset_favorite); + if (item != null) { + item.setVisible(false); + item.setEnabled(false); + } + + Boolean dualPane = getResources().getBoolean(R.bool.large_land_layout); item = menu.findItem(R.id.action_switch_view); @@ -285,14 +300,6 @@ public class FileDetailFragment extends FileFragment implements OnClickListener } return true; } - case R.id.action_favorite_file:{ - mContainerActivity.getFileOperationsHelper().toggleFavorite(getFile(), true); - return true; - } - case R.id.action_unfavorite_file:{ - mContainerActivity.getFileOperationsHelper().toggleFavorite(getFile(), false); - return true; - } default: return super.onOptionsItemSelected(item); } @@ -303,7 +310,7 @@ public class FileDetailFragment extends FileFragment implements OnClickListener switch (v.getId()) { case R.id.fdFavorite: { CheckBox cb = (CheckBox) getView().findViewById(R.id.fdFavorite); - mContainerActivity.getFileOperationsHelper().toggleFavorite(getFile(),cb.isChecked()); + mContainerActivity.getFileOperationsHelper().toggleOfflineFile(getFile(),cb.isChecked()); break; } case R.id.fdCancelBtn: { @@ -362,7 +369,7 @@ public class FileDetailFragment extends FileFragment implements OnClickListener setTimeModified(file.getModificationTimestamp()); CheckBox cb = (CheckBox)getView().findViewById(R.id.fdFavorite); - cb.setChecked(file.isFavorite()); + cb.setChecked(file.isAvailableOffline()); // configure UI for depending upon local state of the file FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder(); diff --git a/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index a63eaac872..00738fbca3 100644 --- a/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -1,34 +1,40 @@ /** - * ownCloud Android client application + * ownCloud Android client application * - * @author Bartek Przybylski - * @author masensio - * @author David A. Velasco - * Copyright (C) 2011 Bartek Przybylski - * Copyright (C) 2016 ownCloud Inc. + * @author Bartek Przybylski + * @author masensio + * @author David A. Velasco + * Copyright (C) 2011 Bartek Przybylski + * Copyright (C) 2016 ownCloud Inc. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, - * as published by the Free Software Foundation. + * This program is 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 . + * 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 . */ package com.owncloud.android.ui.fragment; +import android.accounts.Account; +import android.accounts.AuthenticatorException; +import android.accounts.OperationCanceledException; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.os.Build; import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; import android.preference.PreferenceManager; +import android.support.annotation.NonNull; +import android.support.design.widget.BottomNavigationView; import android.support.v4.widget.DrawerLayout; import android.support.v4.widget.SwipeRefreshLayout; import android.util.SparseBooleanArray; @@ -42,6 +48,7 @@ import android.view.ViewGroup; import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.ListView; +import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; @@ -51,7 +58,14 @@ import com.owncloud.android.authentication.AccountUtils; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.files.FileMenuFilter; +import com.owncloud.android.lib.common.OwnCloudAccount; +import com.owncloud.android.lib.common.OwnCloudClient; +import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; +import com.owncloud.android.lib.common.operations.RemoteOperationResult; import com.owncloud.android.lib.common.utils.Log_OC; +import com.owncloud.android.lib.resources.files.SearchOperation; +import com.owncloud.android.lib.resources.files.ToggleFavoriteOperation; +import com.owncloud.android.lib.resources.shares.GetRemoteSharesOperation; import com.owncloud.android.lib.resources.status.OwnCloudVersion; import com.owncloud.android.ui.activity.FileActivity; import com.owncloud.android.ui.activity.FileDisplayActivity; @@ -63,15 +77,26 @@ import com.owncloud.android.ui.dialog.ConfirmationDialogFragment; import com.owncloud.android.ui.dialog.CreateFolderDialogFragment; import com.owncloud.android.ui.dialog.RemoveFilesDialogFragment; import com.owncloud.android.ui.dialog.RenameFileDialogFragment; +import com.owncloud.android.ui.events.ChangeMenuEvent; +import com.owncloud.android.ui.events.DummyDrawerEvent; +import com.owncloud.android.ui.events.FavoriteEvent; +import com.owncloud.android.ui.events.MenuItemClickEvent; +import com.owncloud.android.ui.events.SearchEvent; import com.owncloud.android.ui.helpers.SparseBooleanArrayParcelable; -import com.owncloud.android.ui.interfaces.ExtendedListFragmentInterface; +import com.owncloud.android.ui.interfaces.OCFileListFragmentInterface; import com.owncloud.android.ui.preview.PreviewImageFragment; import com.owncloud.android.ui.preview.PreviewMediaFragment; import com.owncloud.android.ui.preview.PreviewTextFragment; import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.FileStorageUtils; +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; +import org.parceler.Parcels; + import java.io.File; +import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -80,7 +105,7 @@ import java.util.List; * * TODO refactor to get rid of direct dependency on FileDisplayActivity */ -public class OCFileListFragment extends ExtendedListFragment implements ExtendedListFragmentInterface { +public class OCFileListFragment extends ExtendedListFragment implements OCFileListFragmentInterface { private static final String TAG = OCFileListFragment.class.getSimpleName(); @@ -94,6 +119,8 @@ public class OCFileListFragment extends ExtendedListFragment implements Extended private static final String KEY_FILE = MY_PACKAGE + ".extra.FILE"; private static final String KEY_FAB_EVER_CLICKED = "FAB_EVER_CLICKED"; + private static final String KEY_CURRENT_SEARCH_TYPE = "CURRENT_SEARCH_TYPE"; + private static final String GRID_IS_PREFERED_PREFERENCE = "gridIsPrefered"; private static final String DIALOG_CREATE_FOLDER = "DIALOG_CREATE_FOLDER"; @@ -116,6 +143,19 @@ public class OCFileListFragment extends ExtendedListFragment implements Extended private ActionMode mActiveActionMode; private OCFileListFragment.MultiChoiceModeListener mMultiChoiceModeListener; + private BottomNavigationView bottomNavigationView; + + private SearchType currentSearchType; + + private enum MenuItemAddRemove { + DO_NOTHING, REMOVE_SORT, REMOVE_GRID_AND_SORT, ADD_SORT, ADD_GRID_AND_SORT, ADD_GRID_AND_SORT_WITH_SEARCH, + REMOVE_SEARCH + } + + private MenuItemAddRemove menuItemAddRemoveValue = MenuItemAddRemove.DO_NOTHING; + + private ArrayList mOriginalMenuItems = new ArrayList<>(); + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -157,6 +197,36 @@ public class OCFileListFragment extends ExtendedListFragment implements Extended public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Log_OC.i(TAG, "onCreateView() start"); View v = super.onCreateView(inflater, container, savedInstanceState); + bottomNavigationView = (BottomNavigationView) v.findViewById(R.id.bottom_navigation_view); + + if (savedInstanceState != null) { + currentSearchType = Parcels.unwrap(savedInstanceState.getParcelable(KEY_CURRENT_SEARCH_TYPE)); + } else { + currentSearchType = SearchType.NO_SEARCH; + } + + + if (getResources().getBoolean(R.bool.bottom_toolbar_enabled)) { + bottomNavigationView.setVisibility(View.VISIBLE); + prepareBottomNavigationView(); + } + + if (!getResources().getBoolean(R.bool.bottom_toolbar_enabled) || savedInstanceState != null) { + + final View fabView = v.findViewById(R.id.fab_main); + final RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) + fabView.getLayoutParams(); + layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, 1); + Handler handler = new Handler(); + handler.post(new Runnable() { + @Override + public void run() { + fabView.setLayoutParams(layoutParams); + fabView.invalidate(); + } + }); + } + Bundle args = getArguments(); boolean allowContextualActions = (args != null) && args.getBoolean(ARG_ALLOW_CONTEXTUAL_ACTIONS, false); if (allowContextualActions) { @@ -166,6 +236,48 @@ public class OCFileListFragment extends ExtendedListFragment implements Extended return v; } + private void prepareBottomNavigationView() { + if (getResources().getBoolean(R.bool.use_home)) { + bottomNavigationView.getMenu().findItem(R.id.nav_bar_files).setTitle(getResources(). + getString(R.string.drawer_item_home)); + bottomNavigationView.getMenu().findItem(R.id.nav_bar_files).setIcon(R.drawable.ic_home); + } + + bottomNavigationView.setOnNavigationItemSelectedListener( + new BottomNavigationView.OnNavigationItemSelectedListener() { + @Override + public boolean onNavigationItemSelected(@NonNull MenuItem item) { + switch (item.getItemId()) { + case R.id.nav_bar_files: + EventBus.getDefault().post(new MenuItemClickEvent(item)); + menuItemAddRemoveValue = MenuItemAddRemove.ADD_GRID_AND_SORT_WITH_SEARCH; + if (getActivity() != null) { + getActivity().invalidateOptionsMenu(); + } + break; + case R.id.nav_bar_favorites: + EventBus.getDefault().post(new SearchEvent("", SearchOperation.SearchType.FAVORITE_SEARCH, + SearchEvent.UnsetType.UNSET_DRAWER)); + break; + case R.id.nav_bar_photos: + EventBus.getDefault().post(new SearchEvent("image/%", + SearchOperation.SearchType.CONTENT_TYPE_SEARCH, SearchEvent.UnsetType.UNSET_DRAWER)); + break; + case R.id.nav_bar_settings: + EventBus.getDefault().post(new MenuItemClickEvent(item)); + break; + default: + break; + } + return true; + } + }); + } + + @Override + public void onResume() { + super.onResume(); + } @Override public void onDetach() { @@ -211,12 +323,12 @@ public class OCFileListFragment extends ExtendedListFragment implements Extended // detect if a mini FAB has ever been clicked final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); - if(prefs.getLong(KEY_FAB_EVER_CLICKED, 0) > 0) { + if (prefs.getLong(KEY_FAB_EVER_CLICKED, 0) > 0) { miniFabClicked = true; } // add labels to the min FABs when none of them has ever been clicked on - if(!miniFabClicked) { + if (!miniFabClicked) { setFabLabels(); } else { removeFabLabels(); @@ -328,13 +440,13 @@ public class OCFileListFragment extends ExtendedListFragment implements Extended /** * records a click on a mini FAB and thus: *
    - *
  1. persists the click fact
  2. - *
  3. removes the mini FAB labels
  4. + *
  5. persists the click fact
  6. + *
  7. removes the mini FAB labels
  8. *
*/ private void recordMiniFabClick() { // only record if it hasn't been done already at some other time - if(!miniFabClicked) { + if (!miniFabClicked) { final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity()); sp.edit().putLong(KEY_FAB_EVER_CLICKED, 1).apply(); miniFabClicked = true; @@ -370,7 +482,7 @@ public class OCFileListFragment extends ExtendedListFragment implements Extended * and closed. */ private class MultiChoiceModeListener - implements AbsListView.MultiChoiceModeListener, DrawerLayout.DrawerListener { + implements AbsListView.MultiChoiceModeListener, DrawerLayout.DrawerListener { private static final String KEY_ACTION_MODE_CLOSED_BY_DRAWER = "KILLED_ACTION_MODE"; private static final String KEY_SELECTION_WHEN_CLOSED_BY_DRAWER = "CHECKED_ITEMS"; @@ -399,16 +511,16 @@ public class OCFileListFragment extends ExtendedListFragment implements Extended * When the navigation drawer is closed, action mode is recovered in the same state as was * when the drawer was (started to be) opened. * - * @param drawerView Navigation drawer just closed. + * @param drawerView Navigation drawer just closed. */ @Override public void onDrawerClosed(View drawerView) { - if (mSelectionWhenActionModeClosedByDrawer !=null && mActionModeClosedByDrawer) { - for (int i = 0; i< mSelectionWhenActionModeClosedByDrawer.size(); i++) { + if (mSelectionWhenActionModeClosedByDrawer != null && mActionModeClosedByDrawer) { + for (int i = 0; i < mSelectionWhenActionModeClosedByDrawer.size(); i++) { if (mSelectionWhenActionModeClosedByDrawer.valueAt(i)) { getListView().setItemChecked( - mSelectionWhenActionModeClosedByDrawer.keyAt(i), - true + mSelectionWhenActionModeClosedByDrawer.keyAt(i), + true ); } } @@ -420,7 +532,7 @@ public class OCFileListFragment extends ExtendedListFragment implements Extended * If the action mode is active when the navigation drawer starts to move, the action * mode is closed and the selection stored to be recovered when the drawer is closed. * - * @param newState One of STATE_IDLE, STATE_DRAGGING or STATE_SETTLING. + * @param newState One of STATE_IDLE, STATE_DRAGGING or STATE_SETTLING. */ @Override public void onDrawerStateChanged(int newState) { @@ -470,16 +582,16 @@ public class OCFileListFragment extends ExtendedListFragment implements Extended List checkedFiles = mAdapter.getCheckedItems(getListView()); final int checkedCount = checkedFiles.size(); String title = getResources().getQuantityString( - R.plurals.items_selected_count, - checkedCount, - checkedCount + R.plurals.items_selected_count, + checkedCount, + checkedCount ); mode.setTitle(title); FileMenuFilter mf = new FileMenuFilter( - checkedFiles, - ((FileActivity) getActivity()).getAccount(), - mContainerActivity, - getActivity() + checkedFiles, + ((FileActivity) getActivity()).getAccount(), + mContainerActivity, + getActivity() ); mf.filter(menu); return true; @@ -505,7 +617,7 @@ public class OCFileListFragment extends ExtendedListFragment implements Extended DisplayUtils.colorToolbarProgressBar(getActivity(), mProgressBarColor); // show FAB on multi selection mode exit - if(!mHideFab) { + if (!mHideFab) { setFabEnabled(true); } } @@ -515,7 +627,7 @@ public class OCFileListFragment extends ExtendedListFragment implements Extended outState.putBoolean(KEY_ACTION_MODE_CLOSED_BY_DRAWER, mActionModeClosedByDrawer); if (mSelectionWhenActionModeClosedByDrawer != null) { SparseBooleanArrayParcelable sbap = new SparseBooleanArrayParcelable( - mSelectionWhenActionModeClosedByDrawer + mSelectionWhenActionModeClosedByDrawer ); outState.putParcelable(KEY_SELECTION_WHEN_CLOSED_BY_DRAWER, sbap); } @@ -523,11 +635,11 @@ public class OCFileListFragment extends ExtendedListFragment implements Extended public void loadStateFrom(Bundle savedInstanceState) { mActionModeClosedByDrawer = savedInstanceState.getBoolean( - KEY_ACTION_MODE_CLOSED_BY_DRAWER, - mActionModeClosedByDrawer + KEY_ACTION_MODE_CLOSED_BY_DRAWER, + mActionModeClosedByDrawer ); SparseBooleanArrayParcelable sbap = savedInstanceState.getParcelable( - KEY_SELECTION_WHEN_CLOSED_BY_DRAWER + KEY_SELECTION_WHEN_CLOSED_BY_DRAWER ); if (sbap != null) { mSelectionWhenActionModeClosedByDrawer = sbap.getSparseBooleanArray(); @@ -544,7 +656,7 @@ public class OCFileListFragment extends ExtendedListFragment implements Extended mMultiChoiceModeListener.loadStateFrom(savedInstanceState); } setMultiChoiceModeListener(mMultiChoiceModeListener); - ((FileActivity)getActivity()).addDrawerListener(mMultiChoiceModeListener); + ((FileActivity) getActivity()).addDrawerListener(mMultiChoiceModeListener); } /** @@ -554,12 +666,74 @@ public class OCFileListFragment extends ExtendedListFragment implements Extended public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putParcelable(KEY_FILE, mFile); + outState.putParcelable(KEY_CURRENT_SEARCH_TYPE, Parcels.wrap(currentSearchType)); mMultiChoiceModeListener.storeStateIn(outState); } @Override - public void onPrepareOptionsMenu (Menu menu) { + public void onPrepareOptionsMenu(Menu menu) { + Menu mMenu = menu; + + if (mOriginalMenuItems.size() == 0) { + mOriginalMenuItems.add(mMenu.findItem(R.id.action_switch_view)); + mOriginalMenuItems.add(mMenu.findItem(R.id.action_sort)); + mOriginalMenuItems.add(mMenu.findItem(R.id.action_search)); + } + changeGridIcon(menu); // this is enough if the option stays out of the action bar + + MenuItem menuItemOrig; + + if (menuItemAddRemoveValue.equals(MenuItemAddRemove.ADD_SORT)) { + if (menu.findItem(R.id.action_sort) == null) { + menuItemOrig = mOriginalMenuItems.get(1); + menu.add(menuItemOrig.getGroupId(), menuItemOrig.getItemId(), menuItemOrig.getOrder(), + menuItemOrig.getTitle()); + } + + } else if (menuItemAddRemoveValue.equals(MenuItemAddRemove.ADD_GRID_AND_SORT)) + + { + if (menu.findItem(R.id.action_switch_view) == null) { + menuItemOrig = mOriginalMenuItems.get(0); + menu.add(menuItemOrig.getGroupId(), menuItemOrig.getItemId(), menuItemOrig.getOrder(), + menuItemOrig.getTitle()); + } + + if (menu.findItem(R.id.action_sort) == null) { + menuItemOrig = mOriginalMenuItems.get(1); + menu.add(menuItemOrig.getGroupId(), menuItemOrig.getItemId(), menuItemOrig.getOrder(), + menuItemOrig.getTitle()); + } + } else if (menuItemAddRemoveValue.equals(MenuItemAddRemove.REMOVE_SEARCH)) { + menu.removeItem(R.id.action_search); + } else if (menuItemAddRemoveValue.equals(MenuItemAddRemove.ADD_GRID_AND_SORT_WITH_SEARCH)) { + if (menu.findItem(R.id.action_switch_view) == null) { + menuItemOrig = mOriginalMenuItems.get(0); + menu.add(menuItemOrig.getGroupId(), menuItemOrig.getItemId(), menuItemOrig.getOrder(), + menuItemOrig.getTitle()); + } + + if (menu.findItem(R.id.action_sort) == null) { + menuItemOrig = mOriginalMenuItems.get(1); + menu.add(menuItemOrig.getGroupId(), menuItemOrig.getItemId(), menuItemOrig.getOrder(), + menuItemOrig.getTitle()); + } + + if (menu.findItem(R.id.action_search) == null) { + menuItemOrig = mOriginalMenuItems.get(2); + menu.add(menuItemOrig.getGroupId(), menuItemOrig.getItemId(), menuItemOrig.getOrder(), + menuItemOrig.getTitle()); + } + } else if (menuItemAddRemoveValue.equals(MenuItemAddRemove.REMOVE_SORT)) { + menu.removeItem(R.id.action_sort); + menu.removeItem(R.id.action_search); + } else if (menuItemAddRemoveValue.equals(MenuItemAddRemove.REMOVE_GRID_AND_SORT)) { + menu.removeItem(R.id.action_sort); + menu.removeItem(R.id.action_switch_view); + menu.removeItem(R.id.action_search); + } + } /** @@ -611,6 +785,7 @@ public class OCFileListFragment extends ExtendedListFragment implements Extended @Override public void onItemClick(AdapterView l, View v, int position, long id) { OCFile file = (OCFile) mAdapter.getItem(position); + if (file != null) { if (file.isFolder()) { // update state and view of this fragment @@ -623,9 +798,9 @@ public class OCFileListFragment extends ExtendedListFragment implements Extended } else { /// Click on a file if (PreviewImageFragment.canBePreviewed(file)) { // preview image - it handles the download, if needed - ((FileDisplayActivity)mContainerActivity).startImagePreview(file); - } else if (PreviewTextFragment.canBePreviewed(file)){ - ((FileDisplayActivity)mContainerActivity).startTextPreview(file); + ((FileDisplayActivity) mContainerActivity).startImagePreview(file); + } else if (PreviewTextFragment.canBePreviewed(file)) { + ((FileDisplayActivity) mContainerActivity).startTextPreview(file); } else if (file.isDown()) { if (PreviewMediaFragment.canBePreviewed(file)) { // media preview @@ -650,8 +825,8 @@ public class OCFileListFragment extends ExtendedListFragment implements Extended /** * Start the appropriate action(s) on the currently selected files given menu selected by the user. * - * @param menuId Identifier of the action menu selected by the user - * @return 'true' if the menu selection started any action, 'false' otherwise. + * @param menuId Identifier of the action menu selected by the user + * @return 'true' if the menu selection started any action, 'false' otherwise. */ public boolean onFileActionChosen(int menuId) { final ArrayList checkedFiles = mAdapter.getCheckedItems(getListView()); @@ -713,12 +888,20 @@ public class OCFileListFragment extends ExtendedListFragment implements Extended ((FileDisplayActivity) mContainerActivity).cancelTransference(checkedFiles); return true; } - case R.id.action_favorite_file: { - mContainerActivity.getFileOperationsHelper().toggleFavorites(checkedFiles, true); + case R.id.action_keep_files_offline: { + mContainerActivity.getFileOperationsHelper().toogleOfflineFiles(checkedFiles, true); return true; } - case R.id.action_unfavorite_file: { - mContainerActivity.getFileOperationsHelper().toggleFavorites(checkedFiles, false); + case R.id.action_unset_keep_files_offline: { + mContainerActivity.getFileOperationsHelper().toogleOfflineFiles(checkedFiles, false); + return true; + } + case R.id.action_favorite: { + mContainerActivity.getFileOperationsHelper().toggleFavoriteFiles(checkedFiles, true); + return true; + } + case R.id.action_unset_favorite: { + mContainerActivity.getFileOperationsHelper().toggleFavoriteFiles(checkedFiles, false); return true; } case R.id.action_move: { @@ -752,11 +935,11 @@ public class OCFileListFragment extends ExtendedListFragment implements Extended /** * Calls {@link OCFileListFragment#listDirectory(OCFile, boolean, boolean)} with a null parameter */ - public void listDirectory(boolean onlyOnDevice, boolean fromSearch){ + public void listDirectory(boolean onlyOnDevice, boolean fromSearch) { listDirectory(null, onlyOnDevice, fromSearch); } - public void refreshDirectory(){ + public void refreshDirectory() { listDirectory(getCurrentFile(), MainApp.isOnlyOnDevice(), false); } @@ -846,7 +1029,7 @@ public class OCFileListFragment extends ExtendedListFragment implements Extended updateFooter(); // decide grid vs list view OwnCloudVersion version = AccountUtils.getServerVersion( - ((FileActivity)mContainerActivity).getAccount()); + ((FileActivity) mContainerActivity).getAccount()); if (version != null && version.supportsRemoteThumbnails() && isGridViewPreferred(mFile)) { switchToGridView(); @@ -858,7 +1041,7 @@ public class OCFileListFragment extends ExtendedListFragment implements Extended } private void invalidateActionMode() { - if(mActiveActionMode != null){ + if (mActiveActionMode != null) { mActiveActionMode.invalidate(); } } @@ -918,10 +1101,11 @@ public class OCFileListFragment extends ExtendedListFragment implements Extended /** * Determines if user set folder to grid or list view. If folder is not set itself, * it finds a parent that is set (at least root is set). - * @param file Folder to check. - * @return 'true' is folder should be shown in grid mode, 'false' if list mode is preferred. + * + * @param file Folder to check. + * @return 'true' is folder should be shown in grid mode, 'false' if list mode is preferred. */ - public boolean isGridViewPreferred(OCFile file){ + public boolean isGridViewPreferred(OCFile file) { if (file != null) { OCFile fileToTest = file; OCFile parentDir; @@ -969,14 +1153,16 @@ public class OCFileListFragment extends ExtendedListFragment implements Extended } } - private void changeGridIcon(Menu menu){ + private void changeGridIcon(Menu menu) { MenuItem menuItem = menu.findItem(R.id.action_switch_view); - if (isGridViewPreferred(mFile)){ - menuItem.setTitle(getString(R.string.action_switch_list_view)); - menuItem.setIcon(R.drawable.ic_view_list); - } else { - menuItem.setTitle(getString(R.string.action_switch_grid_view)); - menuItem.setIcon(R.drawable.ic_view_module); + if (menuItem != null) { + if (isGridViewPreferred(mFile)) { + menuItem.setTitle(getString(R.string.action_switch_list_view)); + menuItem.setIcon(R.drawable.ic_view_list); + } else { + menuItem.setTitle(getString(R.string.action_switch_grid_view)); + menuItem.setIcon(R.drawable.ic_view_module); + } } } @@ -990,7 +1176,7 @@ public class OCFileListFragment extends ExtendedListFragment implements Extended switchToGridView(); } - private void saveGridAsPreferred(boolean setGrid){ + private void saveGridAsPreferred(boolean setGrid) { SharedPreferences setting = getActivity().getSharedPreferences( GRID_IS_PREFERED_PREFERENCE, Context.MODE_PRIVATE ); @@ -999,4 +1185,194 @@ public class OCFileListFragment extends ExtendedListFragment implements Extended editor.putBoolean(String.valueOf(mFile.getFileId()), setGrid); editor.apply(); } + + private void unsetAllMenuItems(final boolean unsetDrawer) { + new Handler(Looper.getMainLooper()).post(new Runnable() { + @Override + public void run() { + if (unsetDrawer) { + EventBus.getDefault().post(new DummyDrawerEvent()); + } else { + if (bottomNavigationView != null) { + bottomNavigationView.getMenu().findItem(R.id.nav_bar_files).setChecked(true); + } + } + } + }); + + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onMessageEvent(ChangeMenuEvent changeMenuEvent) { + menuItemAddRemoveValue = MenuItemAddRemove.ADD_GRID_AND_SORT_WITH_SEARCH; + if (getActivity() != null) { + getActivity().invalidateOptionsMenu(); + } + } + + @Subscribe(threadMode = ThreadMode.BACKGROUND) + public void onMessageEvent(FavoriteEvent event) { + Account currentAccount = AccountUtils.getCurrentOwnCloudAccount(MainApp.getAppContext()); + + OwnCloudAccount ocAccount = null; + try { + ocAccount = new OwnCloudAccount( + currentAccount, + MainApp.getAppContext() + ); + + OwnCloudClient mClient = OwnCloudClientManagerFactory.getDefaultSingleton(). + getClientFor(ocAccount, MainApp.getAppContext()); + + ToggleFavoriteOperation toggleFavoriteOperation = new ToggleFavoriteOperation(event.shouldFavorite, + event.remotePath); + RemoteOperationResult remoteOperationResult = toggleFavoriteOperation.execute(mClient); + + if (remoteOperationResult.isSuccess()) { + mAdapter.setFavoriteAttributeForItemID(event.remoteId, event.shouldFavorite); + } + + } catch (com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException e) { + Log_OC.e(TAG, "Account not found", e); + } catch (AuthenticatorException e) { + Log_OC.e(TAG, "Authentication failed", e); + } catch (IOException e) { + Log_OC.e(TAG, "IO error", e); + } catch (OperationCanceledException e) { + Log_OC.e(TAG, "Operation has been canceled", e); + } + } + + @Subscribe(threadMode = ThreadMode.BACKGROUND) + public void onMessageEvent(SearchEvent event) { + setEmptyListLoadingMessage(); + mAdapter.setData(new ArrayList<>(), SearchType.NO_SEARCH); + + if (event.getUnsetType().equals(SearchEvent.UnsetType.UNSET_BOTTOM_NAV_BAR)) { + unsetAllMenuItems(false); + } else if (event.getUnsetType().equals(SearchEvent.UnsetType.UNSET_DRAWER)) { + unsetAllMenuItems(true); + } + + if (event.getSearchType().equals(SearchOperation.SearchType.FILE_SEARCH)) { + currentSearchType = SearchType.FILE_SEARCH; + + } else if (event.getSearchType().equals(SearchOperation.SearchType.CONTENT_TYPE_SEARCH)) { + if (event.getSearchQuery().equals("image/%")) { + currentSearchType = SearchType.PHOTO_SEARCH; + } else if (event.getSearchQuery().equals("video/%")) { + currentSearchType = SearchType.VIDEO_SEARCH; + } + } else if (event.getSearchType().equals(SearchOperation.SearchType.FAVORITE_SEARCH)) { + currentSearchType = SearchType.FAVORITE_SEARCH; + } else if (event.getSearchType().equals(SearchOperation.SearchType.RECENTLY_ADDED_SEARCH)) { + currentSearchType = SearchType.RECENTLY_ADDED_SEARCH; + } else if (event.getSearchType().equals(SearchOperation.SearchType.RECENTLY_MODIFIED_SEARCH)) { + currentSearchType = SearchType.RECENTLY_MODIFIED_SEARCH; + } else if (event.getSearchType().equals(SearchOperation.SearchType.SHARED_SEARCH)) { + currentSearchType = SearchType.SHARED_FILTER; + } + + Runnable switchViewsRunnable = new Runnable() { + @Override + public void run() { + if (isGridViewPreferred(mFile) && !isGridEnabled()) { + switchToGridView(); + } else if (!isGridViewPreferred(mFile) && isGridEnabled()) { + switchToListView(); + } + } + }; + + Account currentAccount = AccountUtils.getCurrentOwnCloudAccount(MainApp.getAppContext()); + + try { + OwnCloudAccount ocAccount = new OwnCloudAccount( + currentAccount, + MainApp.getAppContext() + ); + + OwnCloudClient mClient = OwnCloudClientManagerFactory.getDefaultSingleton(). + getClientFor(ocAccount, MainApp.getAppContext()); + if (!currentSearchType.equals(SearchType.SHARED_FILTER)) { + SearchOperation operation = new SearchOperation(event.getSearchQuery(), event.getSearchType()); + RemoteOperationResult remoteOperationResult = operation.execute(mClient); + if (remoteOperationResult.isSuccess() && remoteOperationResult.getData() != null) { + mAdapter.setData(remoteOperationResult.getData(), currentSearchType); + } + } else { + GetRemoteSharesOperation operation = new GetRemoteSharesOperation(); + RemoteOperationResult remoteOperationResult = operation.execute(mClient); + if (remoteOperationResult.isSuccess() && remoteOperationResult.getData() != null) { + mAdapter.setData(remoteOperationResult.getData(), currentSearchType); + } + } + + if (event.getSearchType().equals(SearchOperation.SearchType.FILE_SEARCH)) { + setEmptyListMessage(SearchType.FILE_SEARCH); + + } else if (event.getSearchType().equals(SearchOperation.SearchType.CONTENT_TYPE_SEARCH)) { + if (event.getSearchQuery().equals("image/%")) { + setEmptyListMessage(SearchType.PHOTO_SEARCH); + menuItemAddRemoveValue = MenuItemAddRemove.REMOVE_GRID_AND_SORT; + } else if (event.getSearchQuery().equals("video/%")) { + setEmptyListMessage(SearchType.VIDEO_SEARCH); + menuItemAddRemoveValue = MenuItemAddRemove.REMOVE_SEARCH; + } + } else if (event.getSearchType().equals(SearchOperation.SearchType.FAVORITE_SEARCH)) { + setEmptyListMessage(SearchType.FAVORITE_SEARCH); + menuItemAddRemoveValue = MenuItemAddRemove.REMOVE_SORT; + } else if (event.getSearchType().equals(SearchOperation.SearchType.RECENTLY_ADDED_SEARCH)) { + setEmptyListMessage(SearchType.RECENTLY_ADDED_SEARCH); + menuItemAddRemoveValue = MenuItemAddRemove.REMOVE_SORT; + } else if (event.getSearchType().equals(SearchOperation.SearchType.RECENTLY_MODIFIED_SEARCH)) { + setEmptyListMessage(SearchType.RECENTLY_MODIFIED_SEARCH); + menuItemAddRemoveValue = MenuItemAddRemove.REMOVE_SORT; + } else if (event.getSearchType().equals(SearchOperation.SearchType.SHARED_SEARCH)) { + setEmptyListMessage(SearchType.SHARED_FILTER); + menuItemAddRemoveValue = MenuItemAddRemove.REMOVE_SEARCH; + } + + if (!currentSearchType.equals(SearchType.FILE_SEARCH) && getActivity() != null) { + getActivity().invalidateOptionsMenu(); + } + + if (currentSearchType.equals(SearchType.PHOTO_SEARCH)) { + new Handler(Looper.getMainLooper()).post(new Runnable() { + @Override + public void run() { + switchToGridView(); + } + }); + } else if (currentSearchType.equals(SearchType.NO_SEARCH) || currentSearchType.equals( + SearchType.REGULAR_FILTER)) { + new Handler(Looper.getMainLooper()).post(switchViewsRunnable); + } else { + new Handler(Looper.getMainLooper()).post(switchViewsRunnable); + } + + } catch (com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException e) { + Log_OC.e(TAG, "Account not found", e); + } catch (AuthenticatorException e) { + Log_OC.e(TAG, "Authentication failed", e); + } catch (IOException e) { + Log_OC.e(TAG, "IO error", e); + } catch (OperationCanceledException e) { + Log_OC.e(TAG, "Operation has been canceled", e); + } + + + } + + @Override + public void onStart() { + super.onStart(); + EventBus.getDefault().register(this); + } + + @Override + public void onStop() { + EventBus.getDefault().unregister(this); + super.onStop(); + } } diff --git a/src/main/java/com/owncloud/android/ui/fragment/UploadListFragment.java b/src/main/java/com/owncloud/android/ui/fragment/UploadListFragment.java index 3093f987a9..8d6f6d5cb4 100755 --- a/src/main/java/com/owncloud/android/ui/fragment/UploadListFragment.java +++ b/src/main/java/com/owncloud/android/ui/fragment/UploadListFragment.java @@ -65,7 +65,8 @@ public class UploadListFragment extends ExpandableListFragment { View v = super.onCreateView(inflater, container, savedInstanceState); getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); setMessageForEmptyList( - R.string.upload_list_empty_headline, R.string.upload_list_empty_text, R.drawable.ic_list_empty_upload + R.string.upload_list_empty_headline, R.string.upload_list_empty_text_auto_upload, + R.drawable.ic_list_empty_upload ); setOnRefreshListener(this); return v; diff --git a/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index 539b8682ba..a0d21f5866 100755 --- a/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -49,6 +49,9 @@ import com.owncloud.android.services.observer.FileObserverService; import com.owncloud.android.ui.activity.FileActivity; import com.owncloud.android.ui.activity.ShareActivity; import com.owncloud.android.ui.dialog.ShareLinkToDialog; +import com.owncloud.android.ui.events.FavoriteEvent; + +import org.greenrobot.eventbus.EventBus; import java.io.BufferedReader; import java.io.FileInputStream; @@ -60,6 +63,9 @@ import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; +import static com.owncloud.android.R.drawable.file; +import static com.owncloud.android.R.layout.files; + /** * */ @@ -546,10 +552,10 @@ public class FileOperationsHelper { } } - public void toggleFavorites(Collection files, boolean isFavorite){ + public void toggleFavoriteFiles(Collection files, boolean shouldBeFavorite) { List alreadyRightStateList = new ArrayList<>(); for(OCFile file : files) { - if(file.isFavorite() == isFavorite) { + if(file.getIsFavorite() == shouldBeFavorite) { alreadyRightStateList.add(file); } } @@ -557,13 +563,36 @@ public class FileOperationsHelper { files.removeAll(alreadyRightStateList); for (OCFile file: files) { - toggleFavorite(file, isFavorite); + toggleFavoriteFile(file, shouldBeFavorite); } } - public void toggleFavorite(OCFile file, boolean isFavorite) { - if (file.isFavorite() != isFavorite) { - file.setFavorite(isFavorite); + public void toggleFavoriteFile(OCFile file, boolean shouldBeFavorite) { + if(file.getIsFavorite() != shouldBeFavorite) { + EventBus.getDefault().post(new FavoriteEvent(file.getRemotePath(), shouldBeFavorite, file.getRemoteId())); + } + } + + + public void toogleOfflineFiles(Collection files, boolean isAvailableOffline){ + List 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); /// register the OCFile instance in the observer service to monitor local updates @@ -571,11 +600,11 @@ public class FileOperationsHelper { mFileActivity, file, mFileActivity.getAccount(), - isFavorite); + isAvailableOffline); mFileActivity.startService(observedFileIntent); /// immediate content synchronization - if (file.isFavorite()) { + if (file.isAvailableOffline()) { syncFile(file); } } diff --git a/src/main/java/com/owncloud/android/ui/interfaces/ExtendedListFragmentInterface.java b/src/main/java/com/owncloud/android/ui/interfaces/OCFileListFragmentInterface.java similarity index 95% rename from src/main/java/com/owncloud/android/ui/interfaces/ExtendedListFragmentInterface.java rename to src/main/java/com/owncloud/android/ui/interfaces/OCFileListFragmentInterface.java index 600fc7ffc8..051d71638b 100644 --- a/src/main/java/com/owncloud/android/ui/interfaces/ExtendedListFragmentInterface.java +++ b/src/main/java/com/owncloud/android/ui/interfaces/OCFileListFragmentInterface.java @@ -24,6 +24,6 @@ package com.owncloud.android.ui.interfaces; * Interface for signaling filter finish */ -public interface ExtendedListFragmentInterface { +public interface OCFileListFragmentInterface { void finishedFiltering(); } diff --git a/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.java b/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.java index 0eef9f7627..a704ba88b5 100644 --- a/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.java +++ b/src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.java @@ -280,6 +280,20 @@ public class PreviewImageFragment extends FileFragment { item.setEnabled(false); } + // additional restriction for this fragment + item = menu.findItem(R.id.action_favorite); + if (item != null) { + item.setVisible(false); + item.setEnabled(false); + } + + // additional restriction for this fragment + item = menu.findItem(R.id.action_unset_favorite); + if (item != null) { + item.setVisible(false); + item.setEnabled(false); + } + } @@ -314,14 +328,6 @@ public class PreviewImageFragment extends FileFragment { mContainerActivity.getFileOperationsHelper().syncFile(getFile()); return true; } - case R.id.action_favorite_file:{ - mContainerActivity.getFileOperationsHelper().toggleFavorite(getFile(), true); - return true; - } - case R.id.action_unfavorite_file:{ - mContainerActivity.getFileOperationsHelper().toggleFavorite(getFile(), false); - return true; - } default: return super.onOptionsItemSelected(item); } diff --git a/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java b/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java index b073968b73..77786561a5 100644 --- a/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java +++ b/src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java @@ -344,6 +344,21 @@ public class PreviewMediaFragment extends FileFragment implements item.setVisible(false); item.setEnabled(false); } + + // additional restriction for this fragment + item = menu.findItem(R.id.action_favorite); + if (item != null) { + item.setVisible(false); + item.setEnabled(false); + } + + // additional restriction for this fragment + item = menu.findItem(R.id.action_unset_favorite); + if (item != null) { + item.setVisible(false); + item.setEnabled(false); + } + } @@ -378,14 +393,6 @@ public class PreviewMediaFragment extends FileFragment implements mContainerActivity.getFileOperationsHelper().syncFile(getFile()); return true; } - case R.id.action_favorite_file:{ - mContainerActivity.getFileOperationsHelper().toggleFavorite(getFile(), true); - return true; - } - case R.id.action_unfavorite_file:{ - mContainerActivity.getFileOperationsHelper().toggleFavorite(getFile(), false); - return true; - } default: return super.onOptionsItemSelected(item); } diff --git a/src/main/java/com/owncloud/android/ui/preview/PreviewTextFragment.java b/src/main/java/com/owncloud/android/ui/preview/PreviewTextFragment.java index 46f61b152c..9978905a60 100644 --- a/src/main/java/com/owncloud/android/ui/preview/PreviewTextFragment.java +++ b/src/main/java/com/owncloud/android/ui/preview/PreviewTextFragment.java @@ -331,6 +331,21 @@ public class PreviewTextFragment extends FileFragment { item.setVisible(false); item.setEnabled(false); } + + // additional restriction for this fragment + item = menu.findItem(R.id.action_favorite); + if (item != null) { + item.setVisible(false); + item.setEnabled(false); + } + + // additional restriction for this fragment + item = menu.findItem(R.id.action_unset_favorite); + if (item != null) { + item.setVisible(false); + item.setEnabled(false); + } + } /** diff --git a/src/main/java/com/owncloud/android/utils/FileStorageUtils.java b/src/main/java/com/owncloud/android/utils/FileStorageUtils.java index eb0b757fba..5275557a11 100644 --- a/src/main/java/com/owncloud/android/utils/FileStorageUtils.java +++ b/src/main/java/com/owncloud/android/utils/FileStorageUtils.java @@ -228,6 +228,7 @@ public class FileStorageUtils { file.setEtag(remote.getEtag()); file.setPermissions(remote.getPermissions()); file.setRemoteId(remote.getRemoteId()); + file.setFavorite(remote.getIsFavorite()); return file; } @@ -246,9 +247,23 @@ public class FileStorageUtils { file.setEtag(ocFile.getEtag()); file.setPermissions(ocFile.getPermissions()); file.setRemoteId(ocFile.getRemoteId()); + file.setFavorite(ocFile.getIsFavorite()); return file; } - + + public static Vector sortOcFolderDescDateModified(Vector files) { + final int multiplier = -1; + Collections.sort(files, new Comparator() { + @SuppressFBWarnings(value = "Bx", justification = "Would require stepping up API level") + public int compare(OCFile o1, OCFile o2) { + Long obj1 = o1.getModificationTimestamp(); + return multiplier * obj1.compareTo(o2.getModificationTimestamp()); + } + }); + + return sortOCFilesByFavourite(files); + } + /** * Sorts all filenames, regarding last user decision */ @@ -454,11 +469,11 @@ public class FileStorageUtils { public static Vector sortOCFilesByFavourite(Vector files){ Collections.sort(files, new Comparator() { public int compare(OCFile o1, OCFile o2) { - if (o1.isFavorite() && o2.isFavorite()) { + if (o1.getIsFavorite() && o2.getIsFavorite()) { return 0; - } else if (o1.isFavorite()) { + } else if (o1.getIsFavorite()) { return -1; - } else if (o2.isFavorite()) { + } else if (o2.getIsFavorite()) { return 1; } return 0; diff --git a/src/main/java/third_parties/in/srain/cube/GridViewWithHeaderAndFooter.java b/src/main/java/third_parties/in/srain/cube/GridViewWithHeaderAndFooter.java index dbbbb4fcdd..e6175160b1 100644 --- a/src/main/java/third_parties/in/srain/cube/GridViewWithHeaderAndFooter.java +++ b/src/main/java/third_parties/in/srain/cube/GridViewWithHeaderAndFooter.java @@ -47,6 +47,14 @@ public class GridViewWithHeaderAndFooter extends GridView { public static final boolean DEBUG = false; + private int mNumColumns = AUTO_FIT; + private View mViewForMeasureRowHeight = null; + private int mRowHeight = -1; + private static final String LOG_TAG = "GridViewWHeaderNFooter"; + + private ArrayList mHeaderViewInfos = new ArrayList<>(); + private ArrayList mFooterViewInfos = new ArrayList<>(); + /** * A class that represents a fixed view in a list, for example a header at the top * or a footer at the bottom. @@ -67,14 +75,6 @@ public class GridViewWithHeaderAndFooter extends GridView { public boolean isSelectable; } - private int mNumColumns = AUTO_FIT; - private View mViewForMeasureRowHeight = null; - private int mRowHeight = -1; - private static final String LOG_TAG = "grid-view-with-header-and-footer"; - - private ArrayList mHeaderViewInfos = new ArrayList(); - private ArrayList mFooterViewInfos = new ArrayList(); - private void initHeaderGridView() { } diff --git a/src/main/res/drawable-hdpi/ic_favorite_grey.png b/src/main/res/drawable-hdpi/ic_favorite_grey.png new file mode 100644 index 0000000000..eeac324496 Binary files /dev/null and b/src/main/res/drawable-hdpi/ic_favorite_grey.png differ diff --git a/src/main/res/drawable-hdpi/ic_home.png b/src/main/res/drawable-hdpi/ic_home.png new file mode 100644 index 0000000000..99073d8358 Binary files /dev/null and b/src/main/res/drawable-hdpi/ic_home.png differ diff --git a/src/main/res/drawable-hdpi/ic_list_empty_error.png b/src/main/res/drawable-hdpi/ic_list_empty_error.png new file mode 100644 index 0000000000..2bfdf36279 Binary files /dev/null and b/src/main/res/drawable-hdpi/ic_list_empty_error.png differ diff --git a/src/main/res/drawable-hdpi/ic_list_empty_home.png b/src/main/res/drawable-hdpi/ic_list_empty_home.png new file mode 100644 index 0000000000..9de63e4b9a Binary files /dev/null and b/src/main/res/drawable-hdpi/ic_list_empty_home.png differ diff --git a/src/main/res/drawable-hdpi/ic_list_empty_image.png b/src/main/res/drawable-hdpi/ic_list_empty_image.png new file mode 100644 index 0000000000..edcc05be24 Binary files /dev/null and b/src/main/res/drawable-hdpi/ic_list_empty_image.png differ diff --git a/src/main/res/drawable-hdpi/ic_list_empty_recent.png b/src/main/res/drawable-hdpi/ic_list_empty_recent.png new file mode 100644 index 0000000000..c87e4ef2ce Binary files /dev/null and b/src/main/res/drawable-hdpi/ic_list_empty_recent.png differ diff --git a/src/main/res/drawable-hdpi/ic_list_empty_shared.png b/src/main/res/drawable-hdpi/ic_list_empty_shared.png new file mode 100644 index 0000000000..185b96816c Binary files /dev/null and b/src/main/res/drawable-hdpi/ic_list_empty_shared.png differ diff --git a/src/main/res/drawable-hdpi/ic_list_empty_video.png b/src/main/res/drawable-hdpi/ic_list_empty_video.png new file mode 100644 index 0000000000..545dadf770 Binary files /dev/null and b/src/main/res/drawable-hdpi/ic_list_empty_video.png differ diff --git a/src/main/res/drawable-hdpi/ic_recent.png b/src/main/res/drawable-hdpi/ic_recent.png new file mode 100644 index 0000000000..e09c642e09 Binary files /dev/null and b/src/main/res/drawable-hdpi/ic_recent.png differ diff --git a/src/main/res/drawable-hdpi/ic_shared.png b/src/main/res/drawable-hdpi/ic_shared.png new file mode 100644 index 0000000000..d50ef7a2f1 Binary files /dev/null and b/src/main/res/drawable-hdpi/ic_shared.png differ diff --git a/src/main/res/drawable-hdpi/ic_star.png b/src/main/res/drawable-hdpi/ic_star.png new file mode 100644 index 0000000000..57be19b931 Binary files /dev/null and b/src/main/res/drawable-hdpi/ic_star.png differ diff --git a/src/main/res/drawable-hdpi/ic_star_light_grey.png b/src/main/res/drawable-hdpi/ic_star_light_grey.png new file mode 100644 index 0000000000..5bc906dd36 Binary files /dev/null and b/src/main/res/drawable-hdpi/ic_star_light_grey.png differ diff --git a/src/main/res/drawable-hdpi/ic_synced.png b/src/main/res/drawable-hdpi/ic_synced.png new file mode 100644 index 0000000000..a476c54e4d Binary files /dev/null and b/src/main/res/drawable-hdpi/ic_synced.png differ diff --git a/src/main/res/drawable-mdpi/ic_favorite_grey.png b/src/main/res/drawable-mdpi/ic_favorite_grey.png new file mode 100644 index 0000000000..46a2f3066b Binary files /dev/null and b/src/main/res/drawable-mdpi/ic_favorite_grey.png differ diff --git a/src/main/res/drawable-mdpi/ic_home.png b/src/main/res/drawable-mdpi/ic_home.png new file mode 100644 index 0000000000..47814fdef0 Binary files /dev/null and b/src/main/res/drawable-mdpi/ic_home.png differ diff --git a/src/main/res/drawable-mdpi/ic_list_empty_error.png b/src/main/res/drawable-mdpi/ic_list_empty_error.png new file mode 100644 index 0000000000..70e09829dc Binary files /dev/null and b/src/main/res/drawable-mdpi/ic_list_empty_error.png differ diff --git a/src/main/res/drawable-mdpi/ic_list_empty_home.png b/src/main/res/drawable-mdpi/ic_list_empty_home.png new file mode 100644 index 0000000000..24ebf9d294 Binary files /dev/null and b/src/main/res/drawable-mdpi/ic_list_empty_home.png differ diff --git a/src/main/res/drawable-mdpi/ic_list_empty_image.png b/src/main/res/drawable-mdpi/ic_list_empty_image.png new file mode 100644 index 0000000000..ad947cf1fa Binary files /dev/null and b/src/main/res/drawable-mdpi/ic_list_empty_image.png differ diff --git a/src/main/res/drawable-mdpi/ic_list_empty_recent.png b/src/main/res/drawable-mdpi/ic_list_empty_recent.png new file mode 100644 index 0000000000..2b09f923e8 Binary files /dev/null and b/src/main/res/drawable-mdpi/ic_list_empty_recent.png differ diff --git a/src/main/res/drawable-mdpi/ic_list_empty_shared.png b/src/main/res/drawable-mdpi/ic_list_empty_shared.png new file mode 100644 index 0000000000..c477b67ab6 Binary files /dev/null and b/src/main/res/drawable-mdpi/ic_list_empty_shared.png differ diff --git a/src/main/res/drawable-mdpi/ic_list_empty_video.png b/src/main/res/drawable-mdpi/ic_list_empty_video.png new file mode 100644 index 0000000000..f97634a29e Binary files /dev/null and b/src/main/res/drawable-mdpi/ic_list_empty_video.png differ diff --git a/src/main/res/drawable-mdpi/ic_recent.png b/src/main/res/drawable-mdpi/ic_recent.png new file mode 100644 index 0000000000..b9a605068a Binary files /dev/null and b/src/main/res/drawable-mdpi/ic_recent.png differ diff --git a/src/main/res/drawable-mdpi/ic_shared.png b/src/main/res/drawable-mdpi/ic_shared.png new file mode 100644 index 0000000000..7447f5ee6d Binary files /dev/null and b/src/main/res/drawable-mdpi/ic_shared.png differ diff --git a/src/main/res/drawable-mdpi/ic_star.png b/src/main/res/drawable-mdpi/ic_star.png new file mode 100644 index 0000000000..3e05c1154b Binary files /dev/null and b/src/main/res/drawable-mdpi/ic_star.png differ diff --git a/src/main/res/drawable-mdpi/ic_star_light_grey.png b/src/main/res/drawable-mdpi/ic_star_light_grey.png new file mode 100644 index 0000000000..9421cd68c8 Binary files /dev/null and b/src/main/res/drawable-mdpi/ic_star_light_grey.png differ diff --git a/src/main/res/drawable-mdpi/ic_synced.png b/src/main/res/drawable-mdpi/ic_synced.png new file mode 100644 index 0000000000..bd6be883be Binary files /dev/null and b/src/main/res/drawable-mdpi/ic_synced.png differ diff --git a/src/main/res/drawable-xhdpi/ic_favorite_grey.png b/src/main/res/drawable-xhdpi/ic_favorite_grey.png new file mode 100644 index 0000000000..1e9eaa4bd5 Binary files /dev/null and b/src/main/res/drawable-xhdpi/ic_favorite_grey.png differ diff --git a/src/main/res/drawable-xhdpi/ic_home.png b/src/main/res/drawable-xhdpi/ic_home.png new file mode 100644 index 0000000000..20665f6541 Binary files /dev/null and b/src/main/res/drawable-xhdpi/ic_home.png differ diff --git a/src/main/res/drawable-xhdpi/ic_list_empty_error.png b/src/main/res/drawable-xhdpi/ic_list_empty_error.png new file mode 100644 index 0000000000..efde5f21fb Binary files /dev/null and b/src/main/res/drawable-xhdpi/ic_list_empty_error.png differ diff --git a/src/main/res/drawable-xhdpi/ic_list_empty_home.png b/src/main/res/drawable-xhdpi/ic_list_empty_home.png new file mode 100644 index 0000000000..a244aed1f6 Binary files /dev/null and b/src/main/res/drawable-xhdpi/ic_list_empty_home.png differ diff --git a/src/main/res/drawable-xhdpi/ic_list_empty_image.png b/src/main/res/drawable-xhdpi/ic_list_empty_image.png new file mode 100644 index 0000000000..e5f5293195 Binary files /dev/null and b/src/main/res/drawable-xhdpi/ic_list_empty_image.png differ diff --git a/src/main/res/drawable-xhdpi/ic_list_empty_recent.png b/src/main/res/drawable-xhdpi/ic_list_empty_recent.png new file mode 100644 index 0000000000..a12ca58bb9 Binary files /dev/null and b/src/main/res/drawable-xhdpi/ic_list_empty_recent.png differ diff --git a/src/main/res/drawable-xhdpi/ic_list_empty_shared.png b/src/main/res/drawable-xhdpi/ic_list_empty_shared.png new file mode 100644 index 0000000000..cc8b8adbb1 Binary files /dev/null and b/src/main/res/drawable-xhdpi/ic_list_empty_shared.png differ diff --git a/src/main/res/drawable-xhdpi/ic_list_empty_video.png b/src/main/res/drawable-xhdpi/ic_list_empty_video.png new file mode 100644 index 0000000000..196290a3b3 Binary files /dev/null and b/src/main/res/drawable-xhdpi/ic_list_empty_video.png differ diff --git a/src/main/res/drawable-xhdpi/ic_recent.png b/src/main/res/drawable-xhdpi/ic_recent.png new file mode 100644 index 0000000000..895e61f8e2 Binary files /dev/null and b/src/main/res/drawable-xhdpi/ic_recent.png differ diff --git a/src/main/res/drawable-xhdpi/ic_shared.png b/src/main/res/drawable-xhdpi/ic_shared.png new file mode 100644 index 0000000000..566f7c4d22 Binary files /dev/null and b/src/main/res/drawable-xhdpi/ic_shared.png differ diff --git a/src/main/res/drawable-xhdpi/ic_star.png b/src/main/res/drawable-xhdpi/ic_star.png new file mode 100644 index 0000000000..0b13a35816 Binary files /dev/null and b/src/main/res/drawable-xhdpi/ic_star.png differ diff --git a/src/main/res/drawable-xhdpi/ic_star_light_grey.png b/src/main/res/drawable-xhdpi/ic_star_light_grey.png new file mode 100644 index 0000000000..40dd6fdcda Binary files /dev/null and b/src/main/res/drawable-xhdpi/ic_star_light_grey.png differ diff --git a/src/main/res/drawable-xhdpi/ic_synced.png b/src/main/res/drawable-xhdpi/ic_synced.png new file mode 100644 index 0000000000..c44bf59189 Binary files /dev/null and b/src/main/res/drawable-xhdpi/ic_synced.png differ diff --git a/src/main/res/drawable-xxhdpi/ic_favorite.png b/src/main/res/drawable-xxhdpi/ic_favorite.png new file mode 100644 index 0000000000..f3b8b257fb Binary files /dev/null and b/src/main/res/drawable-xxhdpi/ic_favorite.png differ diff --git a/src/main/res/drawable-xxhdpi/ic_favorite_grey.png b/src/main/res/drawable-xxhdpi/ic_favorite_grey.png new file mode 100644 index 0000000000..26a843ba57 Binary files /dev/null and b/src/main/res/drawable-xxhdpi/ic_favorite_grey.png differ diff --git a/src/main/res/drawable-xxhdpi/ic_home.png b/src/main/res/drawable-xxhdpi/ic_home.png new file mode 100644 index 0000000000..ee942c87d4 Binary files /dev/null and b/src/main/res/drawable-xxhdpi/ic_home.png differ diff --git a/src/main/res/drawable-xxhdpi/ic_list_empty_error.png b/src/main/res/drawable-xxhdpi/ic_list_empty_error.png new file mode 100644 index 0000000000..9da6688cdc Binary files /dev/null and b/src/main/res/drawable-xxhdpi/ic_list_empty_error.png differ diff --git a/src/main/res/drawable-xxhdpi/ic_list_empty_home.png b/src/main/res/drawable-xxhdpi/ic_list_empty_home.png new file mode 100644 index 0000000000..5e0e160d9c Binary files /dev/null and b/src/main/res/drawable-xxhdpi/ic_list_empty_home.png differ diff --git a/src/main/res/drawable-xxhdpi/ic_list_empty_image.png b/src/main/res/drawable-xxhdpi/ic_list_empty_image.png new file mode 100644 index 0000000000..f8f9930aaa Binary files /dev/null and b/src/main/res/drawable-xxhdpi/ic_list_empty_image.png differ diff --git a/src/main/res/drawable-xxhdpi/ic_list_empty_recent.png b/src/main/res/drawable-xxhdpi/ic_list_empty_recent.png new file mode 100644 index 0000000000..046baa02e4 Binary files /dev/null and b/src/main/res/drawable-xxhdpi/ic_list_empty_recent.png differ diff --git a/src/main/res/drawable-xxhdpi/ic_list_empty_shared.png b/src/main/res/drawable-xxhdpi/ic_list_empty_shared.png new file mode 100644 index 0000000000..3ec8aad6f7 Binary files /dev/null and b/src/main/res/drawable-xxhdpi/ic_list_empty_shared.png differ diff --git a/src/main/res/drawable-xxhdpi/ic_list_empty_video.png b/src/main/res/drawable-xxhdpi/ic_list_empty_video.png new file mode 100644 index 0000000000..8123fcca8f Binary files /dev/null and b/src/main/res/drawable-xxhdpi/ic_list_empty_video.png differ diff --git a/src/main/res/drawable-xxhdpi/ic_recent.png b/src/main/res/drawable-xxhdpi/ic_recent.png new file mode 100644 index 0000000000..ce6f97fa17 Binary files /dev/null and b/src/main/res/drawable-xxhdpi/ic_recent.png differ diff --git a/src/main/res/drawable-xxhdpi/ic_shared.png b/src/main/res/drawable-xxhdpi/ic_shared.png new file mode 100644 index 0000000000..179b0ad095 Binary files /dev/null and b/src/main/res/drawable-xxhdpi/ic_shared.png differ diff --git a/src/main/res/drawable-xxhdpi/ic_star.png b/src/main/res/drawable-xxhdpi/ic_star.png new file mode 100644 index 0000000000..541bf1b1b9 Binary files /dev/null and b/src/main/res/drawable-xxhdpi/ic_star.png differ diff --git a/src/main/res/drawable-xxhdpi/ic_star_light_grey.png b/src/main/res/drawable-xxhdpi/ic_star_light_grey.png new file mode 100644 index 0000000000..b655930680 Binary files /dev/null and b/src/main/res/drawable-xxhdpi/ic_star_light_grey.png differ diff --git a/src/main/res/drawable-xxhdpi/ic_synced.png b/src/main/res/drawable-xxhdpi/ic_synced.png new file mode 100644 index 0000000000..09216aef44 Binary files /dev/null and b/src/main/res/drawable-xxhdpi/ic_synced.png differ diff --git a/src/main/res/drawable-xxxhdpi/ic_favorite.png b/src/main/res/drawable-xxxhdpi/ic_favorite.png new file mode 100644 index 0000000000..5ef53e4c11 Binary files /dev/null and b/src/main/res/drawable-xxxhdpi/ic_favorite.png differ diff --git a/src/main/res/drawable-xxxhdpi/ic_favorite_grey.png b/src/main/res/drawable-xxxhdpi/ic_favorite_grey.png new file mode 100644 index 0000000000..800daea167 Binary files /dev/null and b/src/main/res/drawable-xxxhdpi/ic_favorite_grey.png differ diff --git a/src/main/res/drawable-xxxhdpi/ic_home.png b/src/main/res/drawable-xxxhdpi/ic_home.png new file mode 100644 index 0000000000..6a1de9486f Binary files /dev/null and b/src/main/res/drawable-xxxhdpi/ic_home.png differ diff --git a/src/main/res/drawable-xxxhdpi/ic_list_empty_error.png b/src/main/res/drawable-xxxhdpi/ic_list_empty_error.png new file mode 100644 index 0000000000..28dcf6599b Binary files /dev/null and b/src/main/res/drawable-xxxhdpi/ic_list_empty_error.png differ diff --git a/src/main/res/drawable-xxxhdpi/ic_list_empty_home.png b/src/main/res/drawable-xxxhdpi/ic_list_empty_home.png new file mode 100644 index 0000000000..bee7a19c84 Binary files /dev/null and b/src/main/res/drawable-xxxhdpi/ic_list_empty_home.png differ diff --git a/src/main/res/drawable-xxxhdpi/ic_list_empty_image.png b/src/main/res/drawable-xxxhdpi/ic_list_empty_image.png new file mode 100644 index 0000000000..fcb77de38b Binary files /dev/null and b/src/main/res/drawable-xxxhdpi/ic_list_empty_image.png differ diff --git a/src/main/res/drawable-xxxhdpi/ic_list_empty_recent.png b/src/main/res/drawable-xxxhdpi/ic_list_empty_recent.png new file mode 100644 index 0000000000..d90477e6e7 Binary files /dev/null and b/src/main/res/drawable-xxxhdpi/ic_list_empty_recent.png differ diff --git a/src/main/res/drawable-xxxhdpi/ic_list_empty_shared.png b/src/main/res/drawable-xxxhdpi/ic_list_empty_shared.png new file mode 100644 index 0000000000..ab08bce1eb Binary files /dev/null and b/src/main/res/drawable-xxxhdpi/ic_list_empty_shared.png differ diff --git a/src/main/res/drawable-xxxhdpi/ic_list_empty_video.png b/src/main/res/drawable-xxxhdpi/ic_list_empty_video.png new file mode 100644 index 0000000000..366085e98f Binary files /dev/null and b/src/main/res/drawable-xxxhdpi/ic_list_empty_video.png differ diff --git a/src/main/res/drawable-xxxhdpi/ic_recent.png b/src/main/res/drawable-xxxhdpi/ic_recent.png new file mode 100644 index 0000000000..7b41026e1d Binary files /dev/null and b/src/main/res/drawable-xxxhdpi/ic_recent.png differ diff --git a/src/main/res/drawable-xxxhdpi/ic_shared.png b/src/main/res/drawable-xxxhdpi/ic_shared.png new file mode 100644 index 0000000000..e9f6f13b49 Binary files /dev/null and b/src/main/res/drawable-xxxhdpi/ic_shared.png differ diff --git a/src/main/res/drawable-xxxhdpi/ic_star.png b/src/main/res/drawable-xxxhdpi/ic_star.png new file mode 100644 index 0000000000..7852689bb1 Binary files /dev/null and b/src/main/res/drawable-xxxhdpi/ic_star.png differ diff --git a/src/main/res/drawable-xxxhdpi/ic_star_light_grey.png b/src/main/res/drawable-xxxhdpi/ic_star_light_grey.png new file mode 100644 index 0000000000..f35d7cb709 Binary files /dev/null and b/src/main/res/drawable-xxxhdpi/ic_star_light_grey.png differ diff --git a/src/main/res/drawable-xxxhdpi/ic_synced.png b/src/main/res/drawable-xxxhdpi/ic_synced.png new file mode 100644 index 0000000000..6313ed578c Binary files /dev/null and b/src/main/res/drawable-xxxhdpi/ic_synced.png differ diff --git a/src/main/res/drawable/favorite_button_selector.xml b/src/main/res/drawable/favorite_button_selector.xml new file mode 100644 index 0000000000..3868e80cca --- /dev/null +++ b/src/main/res/drawable/favorite_button_selector.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/main/res/drawable/ic_synced.png b/src/main/res/drawable/ic_synced.png deleted file mode 100644 index 0f1aabe4be..0000000000 Binary files a/src/main/res/drawable/ic_synced.png and /dev/null differ diff --git a/src/main/res/layout/grid_image.xml b/src/main/res/layout/grid_image.xml index e19bf994b2..6c13b9962c 100644 --- a/src/main/res/layout/grid_image.xml +++ b/src/main/res/layout/grid_image.xml @@ -23,7 +23,7 @@ android:layout_gravity="center_horizontal" android:background="@drawable/list_selector" android:gravity="center_horizontal" - android:orientation="vertical" > + android:orientation="vertical"> + + + + android:layout_marginTop="24dp" + android:layout_marginRight="4dp" + android:src="@drawable/shared_via_link"/> + android:layout_marginTop="@dimen/standard_quarter_margin" + android:src="@drawable/ic_synced"/> + android:layout_gravity="center_vertical|top" + android:src="@android:drawable/checkbox_off_background" + /> \ No newline at end of file diff --git a/src/main/res/layout/grid_item.xml b/src/main/res/layout/grid_item.xml index 28c1ff8162..bbd734d9f1 100644 --- a/src/main/res/layout/grid_item.xml +++ b/src/main/res/layout/grid_item.xml @@ -23,57 +23,66 @@ android:layout_gravity="center_horizontal" android:background="@drawable/list_selector" android:gravity="center" - android:orientation="vertical" > + android:orientation="vertical"> + android:layout_gravity="center_horizontal"> + android:layout_gravity="center" + android:src="@drawable/ic_menu_archive"/> + + + android:layout_marginTop="24dp" + android:layout_marginRight="4dp" + android:src="@drawable/shared_via_link"/> + android:layout_marginBottom="@dimen/standard_quarter_margin" + android:layout_marginRight="@dimen/standard_quarter_margin" + android:layout_marginTop="@dimen/standard_quarter_margin" + android:src="@drawable/ic_synced"/> + /> diff --git a/src/main/res/layout/list_fragment.xml b/src/main/res/layout/list_fragment.xml index 1faeb16aef..876ae2f3d5 100644 --- a/src/main/res/layout/list_fragment.xml +++ b/src/main/res/layout/list_fragment.xml @@ -18,15 +18,14 @@ along with this program. If not, see . --> + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent"> - + android:layout_height="match_parent" + android:id="@+id/list_fragment_layout"> + android:visibility="visible" + android:descendantFocusability="blocksDescendants"/> @@ -62,7 +62,7 @@ android:horizontalSpacing="@dimen/list_fragment_spacing" android:stretchMode="columnWidth" android:verticalSpacing="@dimen/list_fragment_spacing" - android:visibility="visible" /> + android:visibility="visible"/> @@ -80,52 +80,67 @@ - + + + + app:fab_size="mini" + app:fab_icon="@drawable/ic_action_upload" + app:fab_colorNormal="@color/primary_button_background_color" + app:fab_colorPressed="@color/owncloud_blue" + app:fab_title=""/> + app:fab_size="mini" + app:fab_icon="@drawable/ic_import" + app:fab_colorNormal="@color/primary_button_background_color" + app:fab_colorPressed="@color/owncloud_blue" + app:fab_title=""/> + app:fab_size="mini" + app:fab_icon="@drawable/ic_action_create_dir" + app:fab_colorNormal="@color/primary_button_background_color" + app:fab_colorPressed="@color/owncloud_blue" + app:fab_title=""/> + + + + \ No newline at end of file diff --git a/src/main/res/layout/list_item.xml b/src/main/res/layout/list_item.xml index b3c2c907f0..d57ccf7811 100644 --- a/src/main/res/layout/list_item.xml +++ b/src/main/res/layout/list_item.xml @@ -22,46 +22,61 @@ android:layout_width="match_parent" android:background="@drawable/list_selector" android:orientation="vertical" - android:layout_height="@dimen/standard_list_item_size"> + android:layout_height="@dimen/standard_list_item_size" + android:descendantFocusability="blocksDescendants"> - - - + android:paddingRight="4dp"> + + + - + + + + - + - - + + + + + + + + - + diff --git a/src/main/res/menu/file_actions_menu.xml b/src/main/res/menu/file_actions_menu.xml index 6bef48f5ac..0b0b5dff53 100644 --- a/src/main/res/menu/file_actions_menu.xml +++ b/src/main/res/menu/file_actions_menu.xml @@ -93,19 +93,31 @@ android:showAsAction="never" android:orderInCategory="1" /> + + . --> + xmlns:app="http://schemas.android.com/apk/res-auto" + > + + + + + + \ No newline at end of file diff --git a/src/main/res/values/setup.xml b/src/main/res/values/setup.xml index 55537f634c..8198e0851a 100644 --- a/src/main/res/values/setup.xml +++ b/src/main/res/values/setup.xml @@ -66,7 +66,7 @@ false false - false + true false @@ -89,6 +89,8 @@ + + true https://f-droid.org/repository/browse/?fdid=com.nextcloud.android.beta https://download.nextcloud.com/android/nightly/latest.apk @@ -109,6 +111,9 @@ false + + false + diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 1c526cd1c5..c2cf60b7c4 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -22,7 +22,15 @@ Smallest first All files + Files + Home + Favorites + Photos On device + Recently added + Recently modified + Shared + Videos Settings Uploads Activities @@ -86,13 +94,32 @@ seconds ago No files in here Upload some content or sync with your devices! + Favorite some files or sync with your devices! + Files and folders you mark as favorite will show up here + No favorited files found for your query! Loading… No app found for file type! There are no files in this folder. No results in this folder + No results + No favorites + Nothing shared yet + Files and folders you share will show up here + No videos + No photos Try looking in another folder? + No files modified in the last 7 days found + No files for your query that were modified + in the last 7 days found! + No recently added files found + No recently added files for your query found! + Upload some photos or activate auto upload! + No photos for your query found! + Upload some videos or activate auto upload! + No videos for your query found! No uploads available Upload some content or activate instant upload! + Upload some content or activate auto upload! folder folders file @@ -248,6 +275,8 @@ Set as available offline Unset as available offline + Set as favorite + Unset favorite Rename Remove "Do you really want to remove %1$s?" diff --git a/src/modified/res/values/setup.xml b/src/modified/res/values/setup.xml index bef516f6f2..6860913222 100644 --- a/src/modified/res/values/setup.xml +++ b/src/modified/res/values/setup.xml @@ -60,7 +60,7 @@ true - true + false true true true @@ -85,6 +85,8 @@ + + false https://f-droid.org/repository/browse/?fdid=com.nextcloud.android.beta https://github.com/nextcloud/android/raw/beta/apks/latest.apk @@ -102,6 +104,9 @@ false + + true +