فهرست منبع

Merge pull request #742 from nextcloud/favourites

Search and others
Andy Scherzinger 8 سال پیش
والد
کامیت
2fdbf5d8e7
100فایلهای تغییر یافته به همراه1949 افزوده شده و 484 حذف شده
  1. 2 2
      androidTest/java/com/owncloud/android/datamodel/OCFileUnitTest.java
  2. 1 1
      automationTest/src/test/java/com/owncloud/android/test/ui/models/FileListView.java
  3. 10 2
      build.gradle
  4. 56 0
      drawable_resources/ic_list_empty_error.svg
  5. 62 0
      drawable_resources/ic_list_empty_home.svg
  6. 58 0
      drawable_resources/ic_list_empty_image.svg
  7. 62 0
      drawable_resources/ic_list_empty_recent.svg
  8. 56 0
      drawable_resources/ic_list_empty_shared.svg
  9. 58 0
      drawable_resources/ic_list_empty_video.svg
  10. 57 0
      drawable_resources/ic_star_light_grey.svg
  11. 1 1
      gradle/wrapper/gradle-wrapper.properties
  12. 8 9
      src/main/java/com/owncloud/android/authentication/AccountUtils.java
  13. 9 5
      src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java
  14. 24 12
      src/main/java/com/owncloud/android/datamodel/OCFile.java
  15. 2 1
      src/main/java/com/owncloud/android/db/ProviderMeta.java
  16. 43 10
      src/main/java/com/owncloud/android/files/FileMenuFilter.java
  17. 11 11
      src/main/java/com/owncloud/android/operations/RefreshFolderOperation.java
  18. 1 1
      src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java
  19. 1 1
      src/main/java/com/owncloud/android/operations/SynchronizeFolderOperation.java
  20. 15 10
      src/main/java/com/owncloud/android/operations/UpdateOCVersionOperation.java
  21. 1 1
      src/main/java/com/owncloud/android/operations/UploadFileOperation.java
  22. 135 115
      src/main/java/com/owncloud/android/providers/FileContentProvider.java
  23. 1 1
      src/main/java/com/owncloud/android/syncadapter/FileSyncAdapter.java
  24. 168 25
      src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java
  25. 51 60
      src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java
  26. 0 1
      src/main/java/com/owncloud/android/ui/activity/Preferences.java
  27. 100 13
      src/main/java/com/owncloud/android/ui/adapter/FileListListAdapter.java
  28. 2 1
      src/main/java/com/owncloud/android/ui/adapter/LocalFileListAdapter.java
  29. 3 3
      src/main/java/com/owncloud/android/ui/dialog/RemoveFileDialogFragment.java
  30. 1 1
      src/main/java/com/owncloud/android/ui/dialog/RemoveFilesDialogFragment.java
  31. 26 0
      src/main/java/com/owncloud/android/ui/events/ChangeMenuEvent.java
  32. 26 0
      src/main/java/com/owncloud/android/ui/events/DummyDrawerEvent.java
  33. 35 0
      src/main/java/com/owncloud/android/ui/events/FavoriteEvent.java
  34. 33 0
      src/main/java/com/owncloud/android/ui/events/MenuItemClickEvent.java
  35. 59 0
      src/main/java/com/owncloud/android/ui/events/SearchEvent.java
  36. 199 81
      src/main/java/com/owncloud/android/ui/fragment/ExtendedListFragment.java
  37. 17 10
      src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java
  38. 444 68
      src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java
  39. 2 1
      src/main/java/com/owncloud/android/ui/fragment/UploadListFragment.java
  40. 37 8
      src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java
  41. 1 1
      src/main/java/com/owncloud/android/ui/interfaces/OCFileListFragmentInterface.java
  42. 14 8
      src/main/java/com/owncloud/android/ui/preview/PreviewImageFragment.java
  43. 15 8
      src/main/java/com/owncloud/android/ui/preview/PreviewMediaFragment.java
  44. 15 0
      src/main/java/com/owncloud/android/ui/preview/PreviewTextFragment.java
  45. 19 4
      src/main/java/com/owncloud/android/utils/FileStorageUtils.java
  46. 8 8
      src/main/java/third_parties/in/srain/cube/GridViewWithHeaderAndFooter.java
  47. BIN
      src/main/res/drawable-hdpi/ic_favorite_grey.png
  48. BIN
      src/main/res/drawable-hdpi/ic_home.png
  49. BIN
      src/main/res/drawable-hdpi/ic_list_empty_error.png
  50. BIN
      src/main/res/drawable-hdpi/ic_list_empty_home.png
  51. BIN
      src/main/res/drawable-hdpi/ic_list_empty_image.png
  52. BIN
      src/main/res/drawable-hdpi/ic_list_empty_recent.png
  53. BIN
      src/main/res/drawable-hdpi/ic_list_empty_shared.png
  54. BIN
      src/main/res/drawable-hdpi/ic_list_empty_video.png
  55. BIN
      src/main/res/drawable-hdpi/ic_recent.png
  56. BIN
      src/main/res/drawable-hdpi/ic_shared.png
  57. BIN
      src/main/res/drawable-hdpi/ic_star.png
  58. BIN
      src/main/res/drawable-hdpi/ic_star_light_grey.png
  59. BIN
      src/main/res/drawable-hdpi/ic_synced.png
  60. BIN
      src/main/res/drawable-mdpi/ic_favorite_grey.png
  61. BIN
      src/main/res/drawable-mdpi/ic_home.png
  62. BIN
      src/main/res/drawable-mdpi/ic_list_empty_error.png
  63. BIN
      src/main/res/drawable-mdpi/ic_list_empty_home.png
  64. BIN
      src/main/res/drawable-mdpi/ic_list_empty_image.png
  65. BIN
      src/main/res/drawable-mdpi/ic_list_empty_recent.png
  66. BIN
      src/main/res/drawable-mdpi/ic_list_empty_shared.png
  67. BIN
      src/main/res/drawable-mdpi/ic_list_empty_video.png
  68. BIN
      src/main/res/drawable-mdpi/ic_recent.png
  69. BIN
      src/main/res/drawable-mdpi/ic_shared.png
  70. BIN
      src/main/res/drawable-mdpi/ic_star.png
  71. BIN
      src/main/res/drawable-mdpi/ic_star_light_grey.png
  72. BIN
      src/main/res/drawable-mdpi/ic_synced.png
  73. BIN
      src/main/res/drawable-xhdpi/ic_favorite_grey.png
  74. BIN
      src/main/res/drawable-xhdpi/ic_home.png
  75. BIN
      src/main/res/drawable-xhdpi/ic_list_empty_error.png
  76. BIN
      src/main/res/drawable-xhdpi/ic_list_empty_home.png
  77. BIN
      src/main/res/drawable-xhdpi/ic_list_empty_image.png
  78. BIN
      src/main/res/drawable-xhdpi/ic_list_empty_recent.png
  79. BIN
      src/main/res/drawable-xhdpi/ic_list_empty_shared.png
  80. BIN
      src/main/res/drawable-xhdpi/ic_list_empty_video.png
  81. BIN
      src/main/res/drawable-xhdpi/ic_recent.png
  82. BIN
      src/main/res/drawable-xhdpi/ic_shared.png
  83. BIN
      src/main/res/drawable-xhdpi/ic_star.png
  84. BIN
      src/main/res/drawable-xhdpi/ic_star_light_grey.png
  85. BIN
      src/main/res/drawable-xhdpi/ic_synced.png
  86. BIN
      src/main/res/drawable-xxhdpi/ic_favorite.png
  87. BIN
      src/main/res/drawable-xxhdpi/ic_favorite_grey.png
  88. BIN
      src/main/res/drawable-xxhdpi/ic_home.png
  89. BIN
      src/main/res/drawable-xxhdpi/ic_list_empty_error.png
  90. BIN
      src/main/res/drawable-xxhdpi/ic_list_empty_home.png
  91. BIN
      src/main/res/drawable-xxhdpi/ic_list_empty_image.png
  92. BIN
      src/main/res/drawable-xxhdpi/ic_list_empty_recent.png
  93. BIN
      src/main/res/drawable-xxhdpi/ic_list_empty_shared.png
  94. BIN
      src/main/res/drawable-xxhdpi/ic_list_empty_video.png
  95. BIN
      src/main/res/drawable-xxhdpi/ic_recent.png
  96. BIN
      src/main/res/drawable-xxhdpi/ic_shared.png
  97. BIN
      src/main/res/drawable-xxhdpi/ic_star.png
  98. BIN
      src/main/res/drawable-xxhdpi/ic_star_light_grey.png
  99. BIN
      src/main/res/drawable-xxhdpi/ic_synced.png
  100. BIN
      src/main/res/drawable-xxxhdpi/ic_favorite.png

+ 2 - 2
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));

+ 1 - 1
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";
 	

+ 10 - 2
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'

+ 56 - 0
drawable_resources/ic_list_empty_error.svg

@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   height="16"
+   width="16"
+   version="1.1"
+   id="svg4"
+   sodipodi:docname="ic_list_empty_error.svg"
+   inkscape:export-filename="C:\DEV\src\Android\Nextcloud\favourites\src\main\res\drawable-mdpi\ic_list_empty_error.png"
+   inkscape:export-xdpi="432"
+   inkscape:export-ydpi="432"
+   inkscape:version="0.92.1 r15371">
+  <metadata
+     id="metadata10">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs8" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1920"
+     inkscape:window-height="1005"
+     id="namedview6"
+     showgrid="false"
+     inkscape:zoom="14.75"
+     inkscape:cx="8"
+     inkscape:cy="8"
+     inkscape:window-x="-9"
+     inkscape:window-y="-9"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg4" />
+  <path
+     d="M5.516 2L2 5.516v4.968L5.516 14h4.968L14 10.484V5.516L10.484 2H5.516zM7 4h2v5H7V4zm0 6h2v2H7v-2z"
+     id="path2"
+     style="fill:#000000;fill-opacity:1;opacity:0.5" />
+</svg>

+ 62 - 0
drawable_resources/ic_list_empty_home.svg

@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   height="16"
+   width="16"
+   version="1"
+   id="svg6"
+   sodipodi:docname="ic_list_empty_home.svg"
+   inkscape:version="0.92.1 r15371"
+   inkscape:export-filename="C:\DEV\src\Android\Nextcloud\favourites\src\main\res\drawable-xxxhdpi\ic_home.png"
+   inkscape:export-xdpi="576"
+   inkscape:export-ydpi="576">
+  <metadata
+     id="metadata12">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs10" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1920"
+     inkscape:window-height="1005"
+     id="namedview8"
+     showgrid="false"
+     inkscape:zoom="14.75"
+     inkscape:cx="8"
+     inkscape:cy="8"
+     inkscape:window-x="-9"
+     inkscape:window-y="-9"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg6" />
+  <path
+     color="#000"
+     fill="none"
+     d="M-62.897-32.993h163.31v97.986h-163.31z"
+     id="path2" />
+  <path
+     d="M 8,1.4367797 0.46588938,8.9426374 H 3.2911808 V 14.59322 H 12.708819 V 8.9426374 h 2.825292 L 12.708819,6.089093 V 2.3502906 H 9.8835281 v 1.0171049 z"
+     id="path4"
+     inkscape:connector-curvature="0"
+     style="opacity:1;fill-rule:evenodd;stroke-width:0.94176388;fill:#757575;fill-opacity:1" />
+</svg>

+ 58 - 0
drawable_resources/ic_list_empty_image.svg

@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   height="16"
+   width="16"
+   version="1"
+   id="svg4"
+   sodipodi:docname="ic_list_empty_image.svg"
+   inkscape:version="0.92.1 r15371"
+   inkscape:export-filename="C:\DEV\src\Android\Nextcloud\favourites\src\main\res\drawable-mdpi\ic_list_empty_image.png"
+   inkscape:export-xdpi="432"
+   inkscape:export-ydpi="432">
+  <metadata
+     id="metadata10">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs8" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1920"
+     inkscape:window-height="1005"
+     id="namedview6"
+     showgrid="false"
+     inkscape:zoom="14.75"
+     inkscape:cx="8"
+     inkscape:cy="8"
+     inkscape:window-x="-9"
+     inkscape:window-y="-9"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg4" />
+  <path
+     style="block-progression:tb;text-transform:none;text-indent:0;fill:#000000;fill-opacity:1;opacity:0.5"
+     d="M1.344 2A.445.445 0 0 0 1 2.438v11.124c0 .23.212.44.438.44h13.125a.457.457 0 0 0 .437-.44V2.61c0-.337-.264-.61-.515-.61zM2 3h12v5l-1-1-3 4-3-3-4 4H2zm2.5 1a1.5 1.5 0 1 0 0 3 1.5 1.5 0 0 0 0-3z"
+     fill="#969696"
+     color="#000"
+     id="path2" />
+</svg>

+ 62 - 0
drawable_resources/ic_list_empty_recent.svg

@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   height="16"
+   width="16"
+   version="1"
+   id="svg6"
+   sodipodi:docname="ic_list_empty_recent.svg"
+   inkscape:export-filename="C:\DEV\src\Android\Nextcloud\favourites\src\main\res\drawable-mdpi\ic_recent.png"
+   inkscape:export-xdpi="144"
+   inkscape:export-ydpi="144"
+   inkscape:version="0.92.1 r15371">
+  <metadata
+     id="metadata12">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs10" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1920"
+     inkscape:window-height="1005"
+     id="namedview8"
+     showgrid="false"
+     inkscape:zoom="14.75"
+     inkscape:cx="8"
+     inkscape:cy="8"
+     inkscape:window-x="-9"
+     inkscape:window-y="-9"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg6" />
+  <path
+     color="#000"
+     fill="none"
+     d="M-62.897-32.993h163.31v97.986h-163.31z"
+     id="path2" />
+  <path
+     style="color:#000000;text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;white-space:normal;isolation:auto;mix-blend-mode:normal;stroke-width:0.93220341;fill:#757575;fill-opacity:1;opacity:1"
+     d="M 8,0.54237288 C 3.8927119,0.54237288 0.54237288,3.8927119 0.54237288,8 c 0,4.107288 3.35033902,7.457627 7.45762712,7.457627 4.107288,0 7.457627,-3.350339 7.457627,-7.457627 C 15.457627,3.8927119 12.107288,0.54237288 8,0.54237288 Z M 8,2.4067797 c 3.100508,0 5.59322,2.4927118 5.59322,5.5932203 0,3.100508 -2.492712,5.59322 -5.59322,5.59322 C 4.8994915,13.59322 2.4067797,11.100508 2.4067797,8 2.4067797,4.8994915 4.8994915,2.4067797 8,2.4067797 Z M 7.5898305,3.2755932 A 0.57516949,0.57516949 0 0 0 7.0258475,3.8470339 L 6.2316102,7.9860169 V 8 C 6.0610169,8.7038136 6.5457627,8.9322034 7.0864407,9.260339 h 0.00466 L 9.8858475,10.73322 C 10.494576,11.201186 11.197458,10.289492 10.588729,9.819661 L 8.9322034,8.009322 V 8 L 8.1771186,3.8516949 A 0.57516949,0.57516949 0 0 0 7.5898305,3.2755932 Z"
+     id="path4"
+     inkscape:connector-curvature="0" />
+</svg>

+ 56 - 0
drawable_resources/ic_list_empty_shared.svg

@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   height="16"
+   width="16"
+   version="1.1"
+   id="svg4"
+   sodipodi:docname="ic_list_empty_shared.svg"
+   inkscape:export-filename="C:\DEV\src\Android\Nextcloud\favourites\src\main\res\drawable-mdpi\ic_shared.png"
+   inkscape:export-xdpi="144"
+   inkscape:export-ydpi="144"
+   inkscape:version="0.92.1 r15371">
+  <metadata
+     id="metadata10">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs8" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1920"
+     inkscape:window-height="1005"
+     id="namedview6"
+     showgrid="false"
+     inkscape:zoom="14.75"
+     inkscape:cx="-10.20339"
+     inkscape:cy="8"
+     inkscape:window-x="-9"
+     inkscape:window-y="-9"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg4" />
+  <path
+     d="M12.228 1a2.457 2.457 0 0 0-2.46 2.454c0 .075.01.15.016.224L5.05 6.092a2.445 2.445 0 0 0-1.596-.586A2.453 2.453 0 0 0 1 7.96a2.453 2.453 0 0 0 2.454 2.455 2.45 2.45 0 0 0 1.46-.477l4.865 2.474c-.004.044-.01.09-.01.134a2.457 2.457 0 1 0 .804-1.818l-4.696-2.4c.02-.123.035-.25.035-.378 0-.072-.01-.144-.015-.214l4.74-2.414A2.457 2.457 0 1 0 12.228.99z"
+     id="path2"
+     style="fill:#757575;fill-opacity:1;opacity:1" />
+</svg>

+ 58 - 0
drawable_resources/ic_list_empty_video.svg

@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   height="16"
+   width="16"
+   version="1"
+   id="svg4"
+   sodipodi:docname="ic_list_empty_video.svg"
+   inkscape:version="0.92.1 r15371"
+   inkscape:export-filename="C:\DEV\src\Android\Nextcloud\favourites\src\main\res\drawable-mdpi\ic_list_empty_video.png"
+   inkscape:export-xdpi="432"
+   inkscape:export-ydpi="432">
+  <metadata
+     id="metadata10">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs8" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1920"
+     inkscape:window-height="1005"
+     id="namedview6"
+     showgrid="false"
+     inkscape:zoom="14.75"
+     inkscape:cx="8"
+     inkscape:cy="8"
+     inkscape:window-x="-9"
+     inkscape:window-y="-9"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg4" />
+  <path
+     style="block-progression:tb;text-transform:none;text-indent:0;fill:#000000;fill-opacity:1;opacity:0.5"
+     d="M1.344 2A.445.445 0 0 0 1 2.438v11.124c0 .23.212.44.438.44h13.124a.457.457 0 0 0 .438-.44V2.61c0-.336-.265-.61-.516-.61zM2 3h12v10H2zm3 2v6l6-3z"
+     fill="#969696"
+     color="#000"
+     id="path2" />
+</svg>

+ 57 - 0
drawable_resources/ic_star_light_grey.svg

@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   width="24"
+   height="24"
+   viewBox="0 0 24 24"
+   id="svg4"
+   sodipodi:docname="ic_star_light_grey.svg"
+   inkscape:version="0.92.1 r15371"
+   inkscape:export-filename="C:\DEV\src\Android\Nextcloud\favourites\src\main\res\drawable-xxxhdpi\ic_star_light_grey.png"
+   inkscape:export-xdpi="1152"
+   inkscape:export-ydpi="1152">
+  <metadata
+     id="metadata10">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs8" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1920"
+     inkscape:window-height="1005"
+     id="namedview6"
+     showgrid="false"
+     inkscape:zoom="9.8333333"
+     inkscape:cx="12"
+     inkscape:cy="12"
+     inkscape:window-x="-9"
+     inkscape:window-y="-9"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg4" />
+  <path
+     d="M12,17.27L18.18,21L16.54,13.97L22,9.24L14.81,8.62L12,2L9.19,8.62L2,9.24L7.45,13.97L5.82,21L12,17.27Z"
+     id="path2"
+     style="fill:#000000;fill-opacity:1;opacity:0.5" />
+</svg>

+ 1 - 1
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

+ 8 - 9
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());
     }
 }

+ 9 - 5
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

+ 24 - 12
src/main/java/com/owncloud/android/datamodel/OCFile.java

@@ -74,7 +74,7 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
     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<OCFile> {
 
     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<OCFile> {
         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<OCFile> {
         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<OCFile> {
         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<OCFile> {
         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<OCFile> {
         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<OCFile> {
         mIsDownloading = false;
         mEtagInConflict = null;
         mShareWithSharee = false;
+        mIsFavorite = false;
     }
 
     /**
@@ -521,12 +533,12 @@ public class OCFile implements Parcelable, Comparable<OCFile> {
         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<OCFile> {
     @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;
     }
 

+ 2 - 1
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";

+ 43 - 10
src/main/java/com/owncloud/android/files/FileMenuFilter.java

@@ -229,20 +229,35 @@ public class FileMenuFilter {
             toShow.add(R.id.action_send_file);
         }
 
-        // FAVORITES
+        // Kept available offline
+        if (!allFiles() || synchronizing || allKeptAvailableOffline()) {
+            toHide.add(R.id.action_keep_files_offline);
+        } else {
+            toShow.add(R.id.action_keep_files_offline);
+        }
+
+        // Not kept available offline
+        if (!allFiles() || synchronizing || allNotKeptAvailableOffline()) {
+            toHide.add(R.id.action_unset_keep_files_offline);
+        } else {
+            toShow.add(R.id.action_unset_keep_files_offline);
+        }
+
+        // Favorite
         if (!allFiles() || synchronizing || allFavorites()) {
-            toHide.add(R.id.action_favorite_file);
+            toHide.add(R.id.action_favorite);
         } else {
-            toShow.add(R.id.action_favorite_file);
+            toShow.add(R.id.action_favorite);
         }
 
-        // UNFAVORITES
-        if (!allFiles() || synchronizing || allUnfavorites()) {
-            toHide.add(R.id.action_unfavorite_file);
+        // Unfavorite
+        if (!allFiles() || synchronizing || allNotFavorites()) {
+            toHide.add(R.id.action_unset_favorite);
         } else {
-            toShow.add(R.id.action_unfavorite_file);
+            toShow.add(R.id.action_unset_favorite);
         }
 
+
     }
 
     private boolean anyFileSynchronizing() {
@@ -320,18 +335,36 @@ public class FileMenuFilter {
         return false;
     }
 
+    private boolean allKeptAvailableOffline() {
+        for(OCFile file: mFiles) {
+            if(!file.isAvailableOffline()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     private boolean allFavorites() {
         for(OCFile file: mFiles) {
-            if(!file.isFavorite()) {
+            if(!file.getIsFavorite()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private boolean allNotFavorites() {
+        for(OCFile file: mFiles) {
+            if(file.getIsFavorite()) {
                 return false;
             }
         }
         return true;
     }
 
-    private boolean allUnfavorites() {
+    private boolean allNotKeptAvailableOffline() {
         for(OCFile file: mFiles) {
-            if(file.isFavorite()) {
+            if(file.isAvailableOffline()) {
                 return false;
             }
         }

+ 11 - 11
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<String, String> 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<OCFile> 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

+ 1 - 1
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());

+ 1 - 1
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()

+ 15 - 10
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) {

+ 1 - 1
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());

+ 135 - 115
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 <http://www.gnu.org/licenses/>.
+ * ownCloud Android client application
  *
+ * @author Bartek Przybylski
+ * @author David A. Velasco
+ * @author masensio
+ * Copyright (C) 2011  Bartek Przybylski
+ * Copyright (C) 2016 ownCloud Inc.
+ * <p>
+ * 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.
+ * <p>
+ * 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.
+ * <p>
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 package com.owncloud.android.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<ContentProviderOperation> operations)
+    public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> 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();
             }
         }

+ 1 - 1
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());

+ 168 - 25
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 <http://www.gnu.org/licenses/>.
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 package com.owncloud.android.ui.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();
+    }
 }

+ 51 - 60
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 <http://www.gnu.org/licenses/>.
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 package com.owncloud.android.ui.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<MenuItem> 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<OCFile> files) {
-        for(OCFile file: files) {
+        for (OCFile file : files) {
             cancelTransference(file);
         }
     }

+ 0 - 1
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
     }
-
 }

+ 100 - 13
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<Object> objects, ExtendedListFragment.SearchType searchType) {
+        mFiles = new Vector<>();
+        if (searchType.equals(ExtendedListFragment.SearchType.SHARED_FILTER)) {
+            ArrayList<OCShare> 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();
 
         }
     }

+ 2 - 1
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);
         }

+ 3 - 3
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<OCFile> 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;

+ 1 - 1
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) {

+ 26 - 0
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 <http://www.gnu.org/licenses/>.
+ */
+package com.owncloud.android.ui.events;
+
+/**
+ * Currently a dummy event to restore grid view, sort, and search
+ */
+public class ChangeMenuEvent {
+}

+ 26 - 0
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 <http://www.gnu.org/licenses/>.
+ */
+package com.owncloud.android.ui.events;
+
+/**
+ * Dummy drawer event
+ */
+public class DummyDrawerEvent {
+}

+ 35 - 0
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 <http://www.gnu.org/licenses/>.
+ */
+package com.owncloud.android.ui.events;
+
+/**
+ * Event for making favoriting work
+ */
+public class FavoriteEvent {
+    public final String remotePath;
+    public final boolean shouldFavorite;
+    public final String remoteId;
+
+    public FavoriteEvent(String remotePath, boolean shouldFavorite, String remoteId) {
+        this.remotePath = remotePath;
+        this.shouldFavorite = shouldFavorite;
+        this.remoteId = remoteId;
+    }
+}

+ 33 - 0
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 <http://www.gnu.org/licenses/>.
+ */
+package com.owncloud.android.ui.events;
+
+import android.view.MenuItem;
+
+/**
+ * Menu item click event
+ */
+public class MenuItemClickEvent {
+    public final MenuItem menuItem;
+
+    public MenuItemClickEvent(MenuItem menuItem) {
+        this.menuItem = menuItem;
+    }
+}

+ 59 - 0
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 <http://www.gnu.org/licenses/>.
+ */
+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;
+    }
+}

+ 199 - 81
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 <http://www.gnu.org/licenses/>.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 package com.owncloud.android.ui.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);
 
-    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);
+                    mEmptyListIcon.setVisibility(View.VISIBLE);
+                    mEmptyListProgress.setVisibility(View.GONE);
+                }
+            }
+        });
+    }
 
-        } else {
-            setMessageForEmptyList(
-                    R.string.file_list_empty_headline,
-                    R.string.file_list_empty,
-                    R.drawable.ic_list_empty_folder
-            );
-        }
+    public void setEmptyListMessage(final SearchType searchType) {
+        new Handler(Looper.getMainLooper()).post(new Runnable() {
+            @Override
+            public void run() {
+
+                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 {

+ 17 - 10
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();

+ 444 - 68
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 <http://www.gnu.org/licenses/>.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 package com.owncloud.android.ui.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<MenuItem> 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:
      * <ol>
-     *     <li>persists the click fact</li>
-     *     <li>removes the mini FAB labels</li>
+     * <li>persists the click fact</li>
+     * <li>removes the mini FAB labels</li>
      * </ol>
      */
     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<OCFile> 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<OCFile> 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_unset_keep_files_offline: {
+                mContainerActivity.getFileOperationsHelper().toogleOfflineFiles(checkedFiles, false);
                 return true;
             }
-            case R.id.action_unfavorite_file: {
-                mContainerActivity.getFileOperationsHelper().toggleFavorites(checkedFiles, false);
+            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();
+    }
 }

+ 2 - 1
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;

+ 37 - 8
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<OCFile> files, boolean isFavorite){
+    public void toggleFavoriteFiles(Collection<OCFile> files, boolean shouldBeFavorite) {
         List<OCFile> 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 toggleFavoriteFile(OCFile file, boolean shouldBeFavorite) {
+        if(file.getIsFavorite() != shouldBeFavorite) {
+            EventBus.getDefault().post(new FavoriteEvent(file.getRemotePath(), shouldBeFavorite, file.getRemoteId()));
         }
     }
 
-    public void toggleFavorite(OCFile file, boolean isFavorite) {
-        if (file.isFavorite() != isFavorite) {
-            file.setFavorite(isFavorite);
+
+    public void toogleOfflineFiles(Collection<OCFile> files, boolean isAvailableOffline){
+        List<OCFile> alreadyRightStateList = new ArrayList<>();
+        for(OCFile file : files) {
+            if(file.isAvailableOffline() == isAvailableOffline) {
+                alreadyRightStateList.add(file);
+            }
+        }
+
+        files.removeAll(alreadyRightStateList);
+
+        for (OCFile file: files) {
+            toggleOfflineFile(file, isAvailableOffline);
+        }
+    }
+
+
+    public void toggleOfflineFile(OCFile file, boolean isAvailableOffline) {
+        if (file.isAvailableOffline() != isAvailableOffline) {
+            file.setAvailableOffline(isAvailableOffline);
             mFileActivity.getStorageManager().saveFile(file);
 
             /// 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);
             }
         }

+ 1 - 1
src/main/java/com/owncloud/android/ui/interfaces/ExtendedListFragmentInterface.java → 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();
 }

+ 14 - 8
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);
         }

+ 15 - 8
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);
         }

+ 15 - 0
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);
+        }
+
     }
 
     /**

+ 19 - 4
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<OCFile> sortOcFolderDescDateModified(Vector<OCFile> files) {
+        final int multiplier = -1;
+        Collections.sort(files, new Comparator<OCFile>() {
+            @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<OCFile> sortOCFilesByFavourite(Vector<OCFile> files){
         Collections.sort(files, new Comparator<OCFile>() {
             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;

+ 8 - 8
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<FixedViewInfo> mHeaderViewInfos = new ArrayList<>();
+    private ArrayList<FixedViewInfo> 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<FixedViewInfo> mHeaderViewInfos = new ArrayList<FixedViewInfo>();
-    private ArrayList<FixedViewInfo> mFooterViewInfos = new ArrayList<FixedViewInfo>();
-
     private void initHeaderGridView() {
     }
 

BIN
src/main/res/drawable-hdpi/ic_favorite_grey.png


BIN
src/main/res/drawable-hdpi/ic_home.png


BIN
src/main/res/drawable-hdpi/ic_list_empty_error.png


BIN
src/main/res/drawable-hdpi/ic_list_empty_home.png


BIN
src/main/res/drawable-hdpi/ic_list_empty_image.png


BIN
src/main/res/drawable-hdpi/ic_list_empty_recent.png


BIN
src/main/res/drawable-hdpi/ic_list_empty_shared.png


BIN
src/main/res/drawable-hdpi/ic_list_empty_video.png


BIN
src/main/res/drawable-hdpi/ic_recent.png


BIN
src/main/res/drawable-hdpi/ic_shared.png


BIN
src/main/res/drawable-hdpi/ic_star.png


BIN
src/main/res/drawable-hdpi/ic_star_light_grey.png


BIN
src/main/res/drawable-hdpi/ic_synced.png


BIN
src/main/res/drawable-mdpi/ic_favorite_grey.png


BIN
src/main/res/drawable-mdpi/ic_home.png


BIN
src/main/res/drawable-mdpi/ic_list_empty_error.png


BIN
src/main/res/drawable-mdpi/ic_list_empty_home.png


BIN
src/main/res/drawable-mdpi/ic_list_empty_image.png


BIN
src/main/res/drawable-mdpi/ic_list_empty_recent.png


BIN
src/main/res/drawable-mdpi/ic_list_empty_shared.png


BIN
src/main/res/drawable-mdpi/ic_list_empty_video.png


BIN
src/main/res/drawable-mdpi/ic_recent.png


BIN
src/main/res/drawable-mdpi/ic_shared.png


BIN
src/main/res/drawable-mdpi/ic_star.png


BIN
src/main/res/drawable-mdpi/ic_star_light_grey.png


BIN
src/main/res/drawable-mdpi/ic_synced.png


BIN
src/main/res/drawable-xhdpi/ic_favorite_grey.png


BIN
src/main/res/drawable-xhdpi/ic_home.png


BIN
src/main/res/drawable-xhdpi/ic_list_empty_error.png


BIN
src/main/res/drawable-xhdpi/ic_list_empty_home.png


BIN
src/main/res/drawable-xhdpi/ic_list_empty_image.png


BIN
src/main/res/drawable-xhdpi/ic_list_empty_recent.png


BIN
src/main/res/drawable-xhdpi/ic_list_empty_shared.png


BIN
src/main/res/drawable-xhdpi/ic_list_empty_video.png


BIN
src/main/res/drawable-xhdpi/ic_recent.png


BIN
src/main/res/drawable-xhdpi/ic_shared.png


BIN
src/main/res/drawable-xhdpi/ic_star.png


BIN
src/main/res/drawable-xhdpi/ic_star_light_grey.png


BIN
src/main/res/drawable-xhdpi/ic_synced.png


BIN
src/main/res/drawable-xxhdpi/ic_favorite.png


BIN
src/main/res/drawable-xxhdpi/ic_favorite_grey.png


BIN
src/main/res/drawable-xxhdpi/ic_home.png


BIN
src/main/res/drawable-xxhdpi/ic_list_empty_error.png


BIN
src/main/res/drawable-xxhdpi/ic_list_empty_home.png


BIN
src/main/res/drawable-xxhdpi/ic_list_empty_image.png


BIN
src/main/res/drawable-xxhdpi/ic_list_empty_recent.png


BIN
src/main/res/drawable-xxhdpi/ic_list_empty_shared.png


BIN
src/main/res/drawable-xxhdpi/ic_list_empty_video.png


BIN
src/main/res/drawable-xxhdpi/ic_recent.png


BIN
src/main/res/drawable-xxhdpi/ic_shared.png


BIN
src/main/res/drawable-xxhdpi/ic_star.png


BIN
src/main/res/drawable-xxhdpi/ic_star_light_grey.png


BIN
src/main/res/drawable-xxhdpi/ic_synced.png


BIN
src/main/res/drawable-xxxhdpi/ic_favorite.png


برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است