Ver código fonte

Fresco and sharing (#531)

* Various improvements

This is literally the worst commit I ever did, but due to rebasing issues this is how it is.

* Fixes after rebase

Signed-off-by: Mario Danic <mario@lovelyhq.com>

* Updates post-rebase

Signed-off-by: Mario Danic <mario@lovelyhq.com>

* Updates #2 post rebase

Signed-off-by: Mario Danic <mario@lovelyhq.com>

* Update deps

Signed-off-by: Mario Danic <mario@lovelyhq.com>
Mario Đanić 6 anos atrás
pai
commit
4143bd841e
100 arquivos alterados com 3179 adições e 781 exclusões
  1. 2 1
      .idea/copyright/GPL3.xml
  2. 59 42
      app/build.gradle
  3. 20 0
      app/gplay.gradle
  4. 20 0
      app/src/gplay/AndroidManifest.xml
  5. 20 0
      app/src/main/AndroidManifest.xml
  6. 16 27
      app/src/main/java/com/nextcloud/talk/adapters/items/AdvancedUserItem.java
  7. 16 34
      app/src/main/java/com/nextcloud/talk/adapters/items/CallItem.java
  8. 34 66
      app/src/main/java/com/nextcloud/talk/adapters/items/ConversationItem.java
  9. 1 8
      app/src/main/java/com/nextcloud/talk/adapters/items/GenericTextHeaderItem.java
  10. 15 28
      app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.java
  11. 20 37
      app/src/main/java/com/nextcloud/talk/adapters/items/NotificationSoundItem.java
  12. 1 1
      app/src/main/java/com/nextcloud/talk/adapters/items/ProgressItem.java
  13. 52 63
      app/src/main/java/com/nextcloud/talk/adapters/items/UserItem.java
  14. 3 3
      app/src/main/java/com/nextcloud/talk/adapters/messages/MagicIncomingTextMessageViewHolder.java
  15. 3 3
      app/src/main/java/com/nextcloud/talk/adapters/messages/MagicOutcomingTextMessageViewHolder.java
  16. 76 4
      app/src/main/java/com/nextcloud/talk/adapters/messages/MagicPreviewMessageViewHolder.java
  17. 1 1
      app/src/main/java/com/nextcloud/talk/adapters/messages/MagicSystemMessageViewHolder.java
  18. 7 0
      app/src/main/java/com/nextcloud/talk/api/NcApi.java
  19. 5 0
      app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.java
  20. 186 0
      app/src/main/java/com/nextcloud/talk/components/filebrowser/adapters/items/BrowserFileItem.java
  21. 333 0
      app/src/main/java/com/nextcloud/talk/components/filebrowser/controllers/BrowserController.java
  22. 4 21
      app/src/main/java/com/nextcloud/talk/components/filebrowser/interfaces/ListingInterface.java
  23. 106 0
      app/src/main/java/com/nextcloud/talk/components/filebrowser/models/BrowserFile.java
  24. 30 0
      app/src/main/java/com/nextcloud/talk/components/filebrowser/models/DavResponse.java
  25. 73 0
      app/src/main/java/com/nextcloud/talk/components/filebrowser/models/properties/NCEncrypted.java
  26. 73 0
      app/src/main/java/com/nextcloud/talk/components/filebrowser/models/properties/NCPreview.java
  27. 73 0
      app/src/main/java/com/nextcloud/talk/components/filebrowser/models/properties/OCFavorite.java
  28. 73 0
      app/src/main/java/com/nextcloud/talk/components/filebrowser/models/properties/OCId.java
  29. 73 0
      app/src/main/java/com/nextcloud/talk/components/filebrowser/models/properties/OCSize.java
  30. 69 0
      app/src/main/java/com/nextcloud/talk/components/filebrowser/operations/DavListing.java
  31. 48 0
      app/src/main/java/com/nextcloud/talk/components/filebrowser/operations/ListingAbstractClass.java
  32. 110 0
      app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/DavUtils.java
  33. 100 0
      app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/ReadFilesystemOperation.java
  34. 29 33
      app/src/main/java/com/nextcloud/talk/controllers/CallController.java
  35. 56 92
      app/src/main/java/com/nextcloud/talk/controllers/CallNotificationController.java
  36. 25 7
      app/src/main/java/com/nextcloud/talk/controllers/ChatController.java
  37. 5 10
      app/src/main/java/com/nextcloud/talk/controllers/ContactsController.java
  38. 1 1
      app/src/main/java/com/nextcloud/talk/controllers/ConversationInfoController.java
  39. 28 36
      app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java
  40. 1 1
      app/src/main/java/com/nextcloud/talk/controllers/LockedController.java
  41. 66 58
      app/src/main/java/com/nextcloud/talk/controllers/RingtoneSelectionController.java
  42. 12 54
      app/src/main/java/com/nextcloud/talk/controllers/SettingsController.java
  43. 0 6
      app/src/main/java/com/nextcloud/talk/controllers/SwitchAccountController.java
  44. 18 18
      app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/CallMenuController.java
  45. 12 9
      app/src/main/java/com/nextcloud/talk/dagger/modules/RestModule.java
  46. 27 0
      app/src/main/java/com/nextcloud/talk/interfaces/SelectionInterface.java
  47. 1 0
      app/src/main/java/com/nextcloud/talk/jobs/DeleteConversationWorker.java
  48. 1 0
      app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.java
  49. 105 0
      app/src/main/java/com/nextcloud/talk/jobs/ShareOperationWorker.java
  50. 14 0
      app/src/main/java/com/nextcloud/talk/models/database/User.java
  51. 9 0
      app/src/main/java/com/nextcloud/talk/models/json/capabilities/Capabilities.java
  52. 61 0
      app/src/main/java/com/nextcloud/talk/models/json/capabilities/ThemingCapability.java
  53. 11 20
      app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.java
  54. 0 1
      app/src/main/java/com/nextcloud/talk/models/json/mention/Mention.java
  55. 21 0
      app/src/main/java/com/nextcloud/talk/utils/AccountUtils.java
  56. 15 0
      app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java
  57. 43 0
      app/src/main/java/com/nextcloud/talk/utils/DateUtils.java
  58. 19 6
      app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java
  59. 161 0
      app/src/main/java/com/nextcloud/talk/utils/DrawableUtils.java
  60. 0 5
      app/src/main/java/com/nextcloud/talk/utils/PushUtils.java
  61. 1 2
      app/src/main/java/com/nextcloud/talk/utils/TextMatchers.java
  62. 4 0
      app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.java
  63. 0 54
      app/src/main/java/com/nextcloud/talk/utils/glide/CachingGlideModule.java
  64. 26 29
      app/src/main/java/com/nextcloud/talk/utils/power/PowerManagerUtils.java
  65. 25 0
      app/src/main/res/drawable/ic_arrow_back_black_24dp.xml
  66. 25 0
      app/src/main/res/drawable/ic_check_black_24dp.xml
  67. 20 0
      app/src/main/res/drawable/ic_close_grey600_24dp.xml
  68. 20 0
      app/src/main/res/drawable/ic_delete_grey600_24dp.xml
  69. 27 0
      app/src/main/res/drawable/ic_file_icon_black_24h.xml
  70. 20 0
      app/src/main/res/drawable/ic_group_grey600_24px.xml
  71. 25 0
      app/src/main/res/drawable/ic_insert_emoticon_black_24dp.xml
  72. 20 0
      app/src/main/res/drawable/ic_launcher_background.xml
  73. 20 0
      app/src/main/res/drawable/ic_launcher_foreground.xml
  74. 20 0
      app/src/main/res/drawable/ic_link_grey600_24px.xml
  75. 20 0
      app/src/main/res/drawable/ic_link_white_24px.xml
  76. 20 0
      app/src/main/res/drawable/ic_lock_open_grey600_24dp.xml
  77. 20 0
      app/src/main/res/drawable/ic_lock_plus_grey600_24dp.xml
  78. 20 0
      app/src/main/res/drawable/ic_logo.xml
  79. 27 0
      app/src/main/res/drawable/ic_mimetype_application.xml
  80. 19 0
      app/src/main/res/drawable/ic_mimetype_application_pdf.xml
  81. 16 0
      app/src/main/res/drawable/ic_mimetype_audio.xml
  82. 12 0
      app/src/main/res/drawable/ic_mimetype_file.xml
  83. 12 0
      app/src/main/res/drawable/ic_mimetype_folder.xml
  84. 13 0
      app/src/main/res/drawable/ic_mimetype_folder_drag_accept.xml
  85. 20 0
      app/src/main/res/drawable/ic_mimetype_folder_encrypted.xml
  86. 19 0
      app/src/main/res/drawable/ic_mimetype_folder_external.xml
  87. 29 0
      app/src/main/res/drawable/ic_mimetype_folder_public.xml
  88. 19 0
      app/src/main/res/drawable/ic_mimetype_folder_shared.xml
  89. 14 0
      app/src/main/res/drawable/ic_mimetype_folder_starred.xml
  90. 14 0
      app/src/main/res/drawable/ic_mimetype_image.xml
  91. 32 0
      app/src/main/res/drawable/ic_mimetype_link.xml
  92. 16 0
      app/src/main/res/drawable/ic_mimetype_location.xml
  93. 12 0
      app/src/main/res/drawable/ic_mimetype_package_x_generic.xml
  94. 14 0
      app/src/main/res/drawable/ic_mimetype_text.xml
  95. 16 0
      app/src/main/res/drawable/ic_mimetype_text_calendar.xml
  96. 16 0
      app/src/main/res/drawable/ic_mimetype_text_code.xml
  97. 23 0
      app/src/main/res/drawable/ic_mimetype_text_vcard.xml
  98. 13 0
      app/src/main/res/drawable/ic_mimetype_video.xml
  99. 14 0
      app/src/main/res/drawable/ic_mimetype_x_office_document.xml
  100. 13 0
      app/src/main/res/drawable/ic_mimetype_x_office_presentation.xml

+ 2 - 1
.idea/copyright/GPL3.xml

@@ -1,6 +1,7 @@
 <component name="CopyrightManager">
   <copyright>
-    <option name="notice" value="Nextcloud Talk application&#10; &#10;@author Mario Danic&#10;Copyright (C) 2017-2018 Mario Danic &lt;mario@lovelyhq.com&gt;&#10; &#10;This program is free software: you can redistribute it and/or modify&#10;it under the terms of the GNU General Public License as published by&#10;the Free Software Foundation, either version 3 of the License, or&#10;at your option) any later version.&#10; &#10;This program is distributed in the hope that it will be useful,&#10;but WITHOUT ANY WARRANTY; without even the implied warranty of&#10;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&#10;GNU General Public License for more details.&#10; &#10;You should have received a copy of the GNU General Public License&#10;along with this program.  If not, see &lt;http://www.gnu.org/licenses/&gt;." />
+    <option name="allowReplaceRegexp" value="true" />
+    <option name="notice" value="Nextcloud Talk application&#10; &#10;@author Mario Danic&#10;Copyright (C) 2017-2019 Mario Danic &lt;mario@lovelyhq.com&gt;&#10; &#10;This program is free software: you can redistribute it and/or modify&#10;it under the terms of the GNU General Public License as published by&#10;the Free Software Foundation, either version 3 of the License, or&#10;at your option) any later version.&#10; &#10;This program is distributed in the hope that it will be useful,&#10;but WITHOUT ANY WARRANTY; without even the implied warranty of&#10;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&#10;GNU General Public License for more details.&#10; &#10;You should have received a copy of the GNU General Public License&#10;along with this program.  If not, see &lt;http://www.gnu.org/licenses/&gt;." />
     <option name="myName" value="GPL3" />
   </copyright>
 </component>

+ 59 - 42
app/build.gradle

@@ -1,6 +1,27 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 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/>.
+ */
+
 apply plugin: 'com.android.application'
 apply plugin: 'kotlin-android'
 apply plugin: 'findbugs'
+apply plugin: 'kotlin-kapt'
 
 def taskRequest = getGradle().getStartParameter().getTaskRequests().toString()
 if (taskRequest.contains("Gplay") || taskRequest.contains("findbugs") || taskRequest.contains("lint")) {
@@ -17,8 +38,8 @@ android {
         targetSdkVersion 28
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
 
-        versionCode 92
-        versionName "6.0.0beta4"
+        versionCode 93
+        versionName "6.0.0"
 
         flavorDimensions "default"
         renderscriptTargetApi 19
@@ -110,8 +131,9 @@ configurations.all {
     exclude group: 'com.google.firebase', module: 'firebase-measurement-connector'
 }
 
+
 dependencies {
-    implementation fileTree(dir: 'libs', include: ['*.jar'])
+    implementation fileTree(include: ['*'], dir: 'libs')
     implementation 'androidx.appcompat:appcompat:1.0.2'
     implementation 'com.google.android.material:material:1.0.0'
     implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha4'
@@ -121,6 +143,13 @@ dependencies {
     implementation "android.arch.work:work-rxjava2:${workVersion}"
     implementation 'com.google.android:flexbox:1.1.0'
     androidTestImplementation "android.arch.work:work-testing:${workVersion}"
+    implementation ('com.gitlab.bitfireAT:dav4jvm:f2078bc846', {
+        exclude group: 'org.ogce', module: 'xpp3'	// Android comes with its own XmlPullParser
+    })
+    compile 'org.conscrypt:conscrypt-android:2.0.0'
+
+
+    implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
 
     implementation 'androidx.biometric:biometric:1.0.0-alpha04'
     implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"
@@ -139,76 +168,57 @@ dependencies {
 
     implementation 'com.bluelinelabs:logansquare:1.3.7'
     implementation group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.9.8'
-    annotationProcessor 'com.bluelinelabs:logansquare-compiler:1.3.7'
+    kapt 'com.bluelinelabs:logansquare-compiler:1.3.7'
 
     implementation 'com.squareup.retrofit2:retrofit:2.5.0'
     implementation 'com.squareup.retrofit2:adapter-rxjava2:2.5.0'
     implementation 'com.github.aurae.retrofit2:converter-logansquare:1.4.1'
 
     implementation 'com.google.dagger:dagger:2.21'
-    annotationProcessor 'com.google.dagger:dagger-compiler:2.21'
+    kapt 'com.google.dagger:dagger-compiler:2.21'
     implementation 'com.github.lukaspili.autodagger2:autodagger2:1.1'
-    annotationProcessor 'com.github.lukaspili.autodagger2:autodagger2-compiler:1.1'
-
-    compileOnly 'javax.annotation:jsr250-api:1.0' // Android only
-
+    kapt 'com.github.lukaspili.autodagger2:autodagger2-compiler:1.1'
+    compileOnly 'javax.annotation:jsr250-api:1.0'
+    // Android only
     implementation 'org.greenrobot:eventbus:3.1.1'
-
     implementation 'io.requery:requery:1.5.1'
     implementation 'io.requery:requery-android:1.5.1'
     implementation 'net.zetetic:android-database-sqlcipher:3.5.9'
-    annotationProcessor 'io.requery:requery-processor:1.5.1'
-
+    kapt 'io.requery:requery-processor:1.5.1'
     implementation 'org.parceler:parceler-api:1.1.12'
-    annotationProcessor 'org.parceler:parceler:1.1.12'
-
+    kapt 'org.parceler:parceler:1.1.12'
     implementation 'net.orange-box.storebox:storebox-lib:1.4.0'
-
-    compileOnly "org.projectlombok:lombok:1.18.6"
+    compileOnly 'org.projectlombok:lombok:1.18.6'
     annotationProcessor "org.projectlombok:lombok:1.18.6"
-
     implementation 'com.jakewharton:butterknife:10.1.0'
-    annotationProcessor 'com.jakewharton:butterknife-compiler:10.1.0'
-
+    kapt 'com.jakewharton:butterknife-compiler:10.1.0'
     implementation 'com.github.HITGIF:TextFieldBoxes:1.4.3'
-
     implementation 'eu.davidea:flexible-adapter:5.1.0'
     implementation 'eu.davidea:flexible-adapter-ui:1.0.0'
-
-    implementation 'com.github.bumptech.glide:glide:4.9.0'
-    annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0'
-    implementation 'com.github.bumptech.glide:okhttp3-integration:4.9.0@aar'
-    implementation 'com.facebook.fresco:fresco:1.13.0'
-    implementation 'com.facebook.fresco:animated-webp:1.13.0'
-    implementation 'com.facebook.fresco:webpsupport:1.13.0'
-    implementation 'com.facebook.fresco:animated-gif:1.13.0'
-    implementation "com.facebook.fresco:imagepipeline-okhttp3:1.13.0"
     implementation 'org.webrtc:google-webrtc:1.0.23295'
     implementation "org.jetbrains.kotlin:kotlin-stdlib:${kotlinVersion}"
-
     implementation 'com.yarolegovich:lovely-dialog:1.1.0'
     implementation 'com.yarolegovich:lovelyinput:1.0.9'
     implementation 'com.yarolegovich:mp:1.0.9'
-
     implementation 'me.zhanghai.android.effortlesspermissions:library:1.1.0'
-
-    implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.8.1'
-
+    implementation 'org.apache.commons:commons-lang3:3.8.1'
     implementation 'com.github.wooplr:Spotlight:1.3'
+    implementation('com.github.mario:chatkit:d63d61db95', {
+        exclude group: 'com.facebook.fresco'
+    })
 
-    implementation 'com.github.mario:chatkit:d63d61db95'
+    implementation 'com.mario.fresco:fresco:1.11.1-headers'
+    implementation 'com.mario.fresco:animated-webp:1.11.1-headers'
+    implementation 'com.mario.fresco:webpsupport:1.11.1-headers'
+    implementation 'com.mario.fresco:animated-gif:1.11.1-headers'
+    implementation "com.mario.fresco:imagepipeline-okhttp3:1.11.1-headers"
 
     implementation 'com.github.natario1:Autocomplete:v1.1.0'
 
     implementation 'com.github.Kennyc1012:BottomSheet:2.4.1'
-    implementation 'eu.davidea:flipview:1.2.0'
     implementation 'com.github.mario:PopupBubble:a365177d96'
-
     implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
-    implementation 'com.kevalpatel2106:emoticongifkeyboard:1.1'
-
-    implementation group: 'eu.medsea.mimeutil', name: 'mime-util', version: '2.1.3'
-
+    implementation 'eu.medsea.mimeutil:mime-util:2.1.3'
     testImplementation 'junit:junit:4.12'
     testImplementation 'org.mockito:mockito-core:2.26.0'
     testImplementation 'org.powermock:powermock-core:2.0.0'
@@ -218,7 +228,14 @@ dependencies {
     androidTestImplementation ('androidx.test.espresso:espresso-core:3.1.0-alpha4', {
         exclude group: 'com.android.support', module: 'support-annotations'
     })
-
     findbugsPlugins 'com.h3xstream.findsecbugs:findsecbugs-plugin:1.8.0'
     findbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:7.4.3'
 }
+
+gradle.projectsEvaluated {
+    tasks.withType(JavaCompile) {
+        options.compilerArgs +=
+                ['-Adagger.floatingBindsMethods=enabled',
+                 '-AparcelerStacktrace',]
+    }
+}

+ 20 - 0
app/gplay.gradle

@@ -1,3 +1,23 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 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/>.
+ */
+
 dependencies {
   implementation "com.google.firebase:firebase-messaging:17.3.4"
 }

+ 20 - 0
app/src/gplay/AndroidManifest.xml

@@ -1,3 +1,23 @@
+<!--
+  ~ Nextcloud Talk application
+  ~
+  ~ @author Mario Danic
+  ~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
+  ~
+  ~ This program is free software: you can redistribute it and/or modify
+  ~ it under the terms of the GNU 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 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/>.
+  -->
+
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           xmlns:tools="http://schemas.android.com/tools"
           package="com.nextcloud.talk">

+ 20 - 0
app/src/main/AndroidManifest.xml

@@ -1,3 +1,23 @@
+<!--
+  ~ Nextcloud Talk application
+  ~
+  ~ @author Mario Danic
+  ~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
+  ~
+  ~ This program is free software: you can redistribute it and/or modify
+  ~ it under the terms of the GNU 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 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/>.
+  -->
+
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           xmlns:tools="http://schemas.android.com/tools"
           package="com.nextcloud.talk">

+ 16 - 27
app/src/main/java/com/nextcloud/talk/adapters/items/AdvancedUserItem.java

@@ -26,26 +26,23 @@ import android.widget.*;
 import androidx.annotation.Nullable;
 import butterknife.BindView;
 import butterknife.ButterKnife;
-import com.bumptech.glide.load.engine.DiskCacheStrategy;
-import com.bumptech.glide.load.model.GlideUrl;
-import com.bumptech.glide.load.model.LazyHeaders;
-import com.bumptech.glide.load.resource.bitmap.CircleCrop;
-import com.bumptech.glide.request.RequestOptions;
+import com.facebook.drawee.backends.pipeline.Fresco;
+import com.facebook.drawee.interfaces.DraweeController;
+import com.facebook.drawee.view.SimpleDraweeView;
 import com.nextcloud.talk.R;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
 import com.nextcloud.talk.models.database.UserEntity;
 import com.nextcloud.talk.models.json.participants.Participant;
 import com.nextcloud.talk.utils.ApiUtils;
-import com.nextcloud.talk.utils.glide.GlideApp;
+import com.nextcloud.talk.utils.DisplayUtils;
 import eu.davidea.flexibleadapter.FlexibleAdapter;
 import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
 import eu.davidea.flexibleadapter.items.IFilterable;
 import eu.davidea.flexibleadapter.utils.FlexibleUtils;
-import eu.davidea.flipview.FlipView;
 import eu.davidea.viewholders.FlexibleViewHolder;
-import org.apache.commons.lang3.StringUtils;
 
 import java.util.List;
+import java.util.regex.Pattern;
 
 public class AdvancedUserItem extends AbstractFlexibleItem<AdvancedUserItem.UserItemViewHolder> implements
         IFilterable<String> {
@@ -116,23 +113,15 @@ public class AdvancedUserItem extends AbstractFlexibleItem<AdvancedUserItem.User
 
         if (userEntity != null && userEntity.getBaseUrl() != null && userEntity.getBaseUrl().startsWith("http://") || userEntity.getBaseUrl().startsWith("https://")) {
             holder.avatarImageView.setVisibility(View.VISIBLE);
-            GlideUrl glideUrl = new GlideUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
-                    participant.getUserId(), R.dimen.avatar_size), new LazyHeaders.Builder()
-                    .setHeader("Accept", "image/*")
-                    .setHeader("User-Agent", ApiUtils.getUserAgent())
-                    .build());
-
-            int avatarSize = Math.round(NextcloudTalkApplication
-                    .getSharedApplication().getResources().getDimension(R.dimen.avatar_size));
-
-            GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext())
-                    .asBitmap()
-                    .diskCacheStrategy(DiskCacheStrategy.NONE)
-                    .load(glideUrl)
-                    .centerInside()
-                    .override(avatarSize, avatarSize)
-                    .apply(RequestOptions.bitmapTransform(new CircleCrop()))
-                    .into(holder.avatarImageView.getFrontImageView());
+
+            DraweeController draweeController = Fresco.newDraweeControllerBuilder()
+                    .setOldController(holder.avatarImageView.getController())
+                    .setAutoPlayAnimations(true)
+                    .setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
+                            participant.getUserId(), R.dimen.avatar_size), null))
+                    .build();
+            holder.avatarImageView.setController(draweeController);
+
         } else {
             holder.avatarImageView.setVisibility(View.GONE);
             RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) holder.linearLayout.getLayoutParams();
@@ -146,7 +135,7 @@ public class AdvancedUserItem extends AbstractFlexibleItem<AdvancedUserItem.User
     @Override
     public boolean filter(String constraint) {
         return participant.getName() != null &&
-                StringUtils.containsIgnoreCase(participant.getName().trim(), constraint);
+                Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(participant.getName().trim()).find();
     }
 
 
@@ -157,7 +146,7 @@ public class AdvancedUserItem extends AbstractFlexibleItem<AdvancedUserItem.User
         @BindView(R.id.secondary_text)
         public TextView serverUrl;
         @BindView(R.id.avatar_image)
-        public FlipView avatarImageView;
+        public SimpleDraweeView avatarImageView;
         @BindView(R.id.linear_layout)
         LinearLayout linearLayout;
         @BindView(R.id.more_menu)

+ 16 - 34
app/src/main/java/com/nextcloud/talk/adapters/items/CallItem.java

@@ -29,11 +29,9 @@ import android.widget.ImageView;
 import android.widget.TextView;
 import butterknife.BindView;
 import butterknife.ButterKnife;
-import com.bumptech.glide.load.engine.DiskCacheStrategy;
-import com.bumptech.glide.load.model.GlideUrl;
-import com.bumptech.glide.load.model.LazyHeaders;
-import com.bumptech.glide.load.resource.bitmap.CircleCrop;
-import com.bumptech.glide.request.RequestOptions;
+import com.facebook.drawee.backends.pipeline.Fresco;
+import com.facebook.drawee.interfaces.DraweeController;
+import com.facebook.drawee.view.SimpleDraweeView;
 import com.nextcloud.talk.R;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
 import com.nextcloud.talk.events.MoreMenuClickEvent;
@@ -41,17 +39,15 @@ import com.nextcloud.talk.models.database.UserEntity;
 import com.nextcloud.talk.models.json.rooms.Conversation;
 import com.nextcloud.talk.utils.ApiUtils;
 import com.nextcloud.talk.utils.DisplayUtils;
-import com.nextcloud.talk.utils.glide.GlideApp;
 import eu.davidea.flexibleadapter.FlexibleAdapter;
 import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
 import eu.davidea.flexibleadapter.items.IFilterable;
 import eu.davidea.flexibleadapter.utils.FlexibleUtils;
-import eu.davidea.flipview.FlipView;
 import eu.davidea.viewholders.FlexibleViewHolder;
-import org.apache.commons.lang3.StringUtils;
 import org.greenrobot.eventbus.EventBus;
 
 import java.util.List;
+import java.util.regex.Pattern;
 
 public class CallItem extends AbstractFlexibleItem<CallItem.RoomItemViewHolder> implements IFilterable<String> {
 
@@ -134,21 +130,14 @@ public class CallItem extends AbstractFlexibleItem<CallItem.RoomItemViewHolder>
                         .nc_description_more_menu_one_to_one), conversation.getDisplayName()));
 
                 if (!TextUtils.isEmpty(conversation.getName())) {
-                    GlideUrl glideUrl = new GlideUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
-                            conversation.getName(), R.dimen.avatar_size), new LazyHeaders.Builder()
-                            .setHeader("Accept", "image/*")
-                            .setHeader("User-Agent", ApiUtils.getUserAgent())
-                            .build());
-
-                    GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext())
-                            .asBitmap()
-                            .diskCacheStrategy(DiskCacheStrategy.NONE)
-                            .load(glideUrl)
-                            .centerInside()
-                            .override(avatarSize, avatarSize)
-                            .apply(RequestOptions.bitmapTransform(new CircleCrop()))
-                            .into(holder.avatarImageView.getFrontImageView());
-
+                    DraweeController draweeController = Fresco.newDraweeControllerBuilder()
+                            .setOldController(holder.avatarImageView.getController())
+                            .setAutoPlayAnimations(true)
+                            .setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
+                                    conversation.getLastMessage().getActorId(),
+                                    R.dimen.avatar_size), null))
+                            .build();
+                    holder.avatarImageView.setController(draweeController);
                 } else {
                     holder.avatarImageView.setVisibility(View.GONE);
                 }
@@ -156,19 +145,13 @@ public class CallItem extends AbstractFlexibleItem<CallItem.RoomItemViewHolder>
             case ROOM_GROUP_CALL:
                 holder.moreMenuButton.setContentDescription(String.format(resources.getString(R.string
                         .nc_description_more_menu_group), conversation.getDisplayName()));
-
-                holder.avatarImageView.setFrontImageBitmap(DisplayUtils
-                        .getRoundedBitmapFromVectorDrawableResource(resources,
-                                R.drawable.ic_people_group_white_24px));
+                holder.avatarImageView.setActualImageResource(R.drawable.ic_people_group_white_24px);
                 holder.avatarImageView.setVisibility(View.VISIBLE);
                 break;
             case ROOM_PUBLIC_CALL:
                 holder.moreMenuButton.setContentDescription(String.format(resources.getString(R.string
                         .nc_description_more_menu_public), conversation.getDisplayName()));
-
-                holder.avatarImageView.setFrontImageBitmap(DisplayUtils
-                        .getRoundedBitmapFromVectorDrawableResource(resources,
-                                R.drawable.ic_link_white_24px));
+                holder.avatarImageView.setActualImageResource(R.drawable.ic_link_white_24px);
                 holder.avatarImageView.setVisibility(View.VISIBLE);
                 break;
             default:
@@ -182,8 +165,7 @@ public class CallItem extends AbstractFlexibleItem<CallItem.RoomItemViewHolder>
     @Override
     public boolean filter(String constraint) {
         return conversation.getDisplayName() != null &&
-                StringUtils.containsIgnoreCase(conversation.getDisplayName().trim(), constraint);
-
+                Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(conversation.getDisplayName().trim()).find();
     }
 
     static class RoomItemViewHolder extends FlexibleViewHolder {
@@ -193,7 +175,7 @@ public class CallItem extends AbstractFlexibleItem<CallItem.RoomItemViewHolder>
         @BindView(R.id.secondary_text)
         public TextView roomLastPing;
         @BindView(R.id.avatar_image)
-        public FlipView avatarImageView;
+        public SimpleDraweeView avatarImageView;
         @BindView(R.id.more_menu)
         public ImageButton moreMenuButton;
         @BindView(R.id.password_protected_image_view)

+ 34 - 66
app/src/main/java/com/nextcloud/talk/adapters/items/ConversationItem.java

@@ -21,6 +21,7 @@
 package com.nextcloud.talk.adapters.items;
 
 import android.content.Context;
+import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
 import android.text.TextUtils;
@@ -31,11 +32,9 @@ import android.widget.TextView;
 import butterknife.BindView;
 import butterknife.ButterKnife;
 import com.amulyakhare.textdrawable.TextDrawable;
-import com.bumptech.glide.load.engine.DiskCacheStrategy;
-import com.bumptech.glide.load.model.GlideUrl;
-import com.bumptech.glide.load.model.LazyHeaders;
-import com.bumptech.glide.load.resource.bitmap.CircleCrop;
-import com.bumptech.glide.request.RequestOptions;
+import com.facebook.drawee.backends.pipeline.Fresco;
+import com.facebook.drawee.interfaces.DraweeController;
+import com.facebook.drawee.view.SimpleDraweeView;
 import com.nextcloud.talk.R;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
 import com.nextcloud.talk.models.database.UserEntity;
@@ -43,7 +42,6 @@ import com.nextcloud.talk.models.json.chat.ChatMessage;
 import com.nextcloud.talk.models.json.rooms.Conversation;
 import com.nextcloud.talk.utils.ApiUtils;
 import com.nextcloud.talk.utils.DisplayUtils;
-import com.nextcloud.talk.utils.glide.GlideApp;
 import com.vanniktech.emoji.EmojiTextView;
 import eu.davidea.flexibleadapter.FlexibleAdapter;
 import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
@@ -51,9 +49,9 @@ import eu.davidea.flexibleadapter.items.IFilterable;
 import eu.davidea.flexibleadapter.items.IFlexible;
 import eu.davidea.flexibleadapter.utils.FlexibleUtils;
 import eu.davidea.viewholders.FlexibleViewHolder;
-import org.apache.commons.lang3.StringUtils;
 
 import java.util.List;
+import java.util.regex.Pattern;
 
 public class ConversationItem extends AbstractFlexibleItem<ConversationItem.ConversationItemViewHolder> implements
         IFilterable<String> {
@@ -146,10 +144,10 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
                 holder.dialogLastMessage.setText(conversation.getLastMessage().getText());
             } else {
                 String authorDisplayName = "";
-                conversation.getLastMessage().setActiveUserId(userEntity.getUserId());
+                conversation.getLastMessage().setActiveUser(userEntity);
                 String text;
                 if (conversation.getLastMessage().getMessageType().equals(ChatMessage.MessageType.REGULAR_TEXT_MESSAGE)) {
-                    if (conversation.getLastMessage().getActorId().equals(conversation.getLastMessage().getActiveUserId())) {
+                    if (conversation.getLastMessage().getActorId().equals(userEntity.getUserId())) {
                         text = String.format(context.getString(R.string.nc_formatted_message_you), conversation.getLastMessage().getLastMessageDisplayText());
                     } else {
                         authorDisplayName = !TextUtils.isEmpty(conversation.getLastMessage().getActorDisplayName()) ?
@@ -166,8 +164,6 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
 
                 holder.dialogLastMessage.setText(text);
 
-                int smallAvatarSize = Math.round(context.getResources().getDimension(R.dimen.small_item_height));
-
                 if (conversation.getLastMessage().getActorType().equals("guests")) {
                     if (TextUtils.isEmpty(authorDisplayName)) {
                         authorDisplayName = NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_guest);
@@ -176,26 +172,18 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
                     TextDrawable drawable = TextDrawable.builder().beginConfig().bold()
                             .endConfig().buildRound(String.valueOf(authorDisplayName.charAt(0)),
                                     context.getResources().getColor(R.color.nc_grey));
-                    holder.dialogLastMessageUserAvatar.setImageDrawable(drawable);
-                } else if (!conversation.getLastMessage().getActorId().equals(userEntity.getUserId())
-                        && !conversation.getType().equals(Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL)) {
+                    holder.dialogLastMessageUserAvatar.getHierarchy().setImage(drawable, 100, true);
+                } else if (conversation.getLastMessage().getActorId().equals(userEntity.getUserId())
+                        || !conversation.getType().equals(Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL)) {
                     holder.dialogLastMessageUserAvatar.setVisibility(View.VISIBLE);
 
                     if (!"bots".equals(conversation.getLastMessage().getActorType())) {
-                        GlideUrl glideUrl = new GlideUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
-                                conversation.getLastMessage().getActorId(), R.dimen.small_item_height), new LazyHeaders.Builder()
-                                .setHeader("Accept", "image/*")
-                                .setHeader("User-Agent", ApiUtils.getUserAgent())
-                                .build());
-
-                        GlideApp.with(context)
-                                .asBitmap()
-                                .diskCacheStrategy(DiskCacheStrategy.NONE)
-                                .load(glideUrl)
-                                .centerInside()
-                                .override(smallAvatarSize, smallAvatarSize)
-                                .apply(RequestOptions.bitmapTransform(new CircleCrop()))
-                                .into(holder.dialogLastMessageUserAvatar);
+                        DraweeController draweeController = Fresco.newDraweeControllerBuilder()
+                                .setOldController(holder.dialogLastMessageUserAvatar.getController())
+                                .setAutoPlayAnimations(true)
+                                .setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(), conversation.getLastMessage().getActorId(), R.dimen.small_item_height), userEntity))
+                                .build();
+                        holder.dialogLastMessageUserAvatar.setController(draweeController);
                     } else {
                         TextDrawable drawable =
                                 TextDrawable.builder().beginConfig().bold().endConfig().buildRound(">", context.getResources().getColor(R.color.black));
@@ -213,8 +201,6 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
             holder.dialogLastMessage.setText(R.string.nc_no_messages_yet);
         }
 
-        int avatarSize = Math.round(context.getResources().getDimension(R.dimen.avatar_size));
-
 
         holder.dialogAvatar.setVisibility(View.VISIBLE);
 
@@ -224,15 +210,15 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
             switch (objectType) {
                 case "share:password":
                     shouldLoadAvatar = false;
-                    holder.dialogAvatar.setImageBitmap(DisplayUtils
+                    holder.dialogAvatar.getHierarchy().setImage(new BitmapDrawable(DisplayUtils
                             .getRoundedBitmapFromVectorDrawableResource(context.getResources(),
-                                    R.drawable.ic_file_password_request));
+                                    R.drawable.ic_file_password_request)), 100, true);
                     break;
                 case "file":
                     shouldLoadAvatar = false;
-                    holder.dialogAvatar.setImageBitmap(DisplayUtils
+                    holder.dialogAvatar.getHierarchy().setImage(new BitmapDrawable(DisplayUtils
                             .getRoundedBitmapFromVectorDrawableResource(context.getResources(),
-                                    R.drawable.ic_file_icon));
+                                    R.drawable.ic_file_icon)), 100, true);
                     break;
                 default:
                     break;
@@ -245,14 +231,7 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
             layers[1] = context.getDrawable(R.drawable.ic_launcher_foreground);
             LayerDrawable layerDrawable = new LayerDrawable(layers);
 
-            GlideApp.with(context)
-                    .asDrawable()
-                    .diskCacheStrategy(DiskCacheStrategy.NONE)
-                    .load(layerDrawable)
-                    .centerInside()
-                    .override(avatarSize, avatarSize)
-                    .apply(RequestOptions.bitmapTransform(new CircleCrop()))
-                    .into(holder.dialogAvatar);
+            holder.dialogAvatar.getHierarchy().setPlaceholderImage(DisplayUtils.getRoundedDrawable(layerDrawable));
 
             shouldLoadAvatar = false;
         }
@@ -260,37 +239,26 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
         if (shouldLoadAvatar) {
             switch (conversation.getType()) {
                 case ROOM_TYPE_ONE_TO_ONE_CALL:
-
                     if (!TextUtils.isEmpty(conversation.getName())) {
-                        GlideUrl glideUrl = new GlideUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
-                                conversation.getName(), R.dimen.avatar_size), new LazyHeaders.Builder()
-                                .setHeader("Accept", "image/*")
-                                .setHeader("User-Agent", ApiUtils.getUserAgent())
-                                .build());
-
-                        GlideApp.with(context)
-                                .asBitmap()
-                                .diskCacheStrategy(DiskCacheStrategy.NONE)
-                                .load(glideUrl)
-                                .centerInside()
-                                .override(avatarSize, avatarSize)
-                                .apply(RequestOptions.bitmapTransform(new CircleCrop()))
-                                .into(holder.dialogAvatar);
-
+                        DraweeController draweeController = Fresco.newDraweeControllerBuilder()
+                                .setOldController(holder.dialogAvatar.getController())
+                                .setAutoPlayAnimations(true)
+                                .setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(), conversation.getName(), R.dimen.avatar_size), null))
+                                .build();
+                        holder.dialogAvatar.setController(draweeController);
                     } else {
                         holder.dialogAvatar.setVisibility(View.GONE);
                     }
                     break;
                 case ROOM_GROUP_CALL:
-                    holder.dialogAvatar.setImageBitmap(DisplayUtils
+                    holder.dialogAvatar.getHierarchy().setImage(new BitmapDrawable(DisplayUtils
                             .getRoundedBitmapFromVectorDrawableResource(context.getResources(),
-                                    R.drawable.ic_people_group_white_24px));
+                                    R.drawable.ic_people_group_white_24px)), 100, true);
                     break;
                 case ROOM_PUBLIC_CALL:
-                    holder.dialogAvatar.setImageBitmap(DisplayUtils
+                    holder.dialogAvatar.getHierarchy().setImage(new BitmapDrawable(DisplayUtils
                             .getRoundedBitmapFromVectorDrawableResource(context.getResources(),
-                                    R.drawable.ic_link_white_24px));
-
+                                    R.drawable.ic_link_white_24px)), 100, true);
                     break;
                 default:
                     holder.dialogAvatar.setVisibility(View.GONE);
@@ -301,18 +269,18 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
     @Override
     public boolean filter(String constraint) {
         return conversation.getDisplayName() != null &&
-                StringUtils.containsIgnoreCase(conversation.getDisplayName().trim(), constraint);
+                Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(conversation.getDisplayName().trim()).find();
     }
 
     static class ConversationItemViewHolder extends FlexibleViewHolder {
         @BindView(R.id.dialogAvatar)
-        ImageView dialogAvatar;
+        SimpleDraweeView dialogAvatar;
         @BindView(R.id.dialogName)
         EmojiTextView dialogName;
         @BindView(R.id.dialogDate)
         TextView dialogDate;
         @BindView(R.id.dialogLastMessageUserAvatar)
-        ImageView dialogLastMessageUserAvatar;
+        SimpleDraweeView dialogLastMessageUserAvatar;
         @BindView(R.id.dialogLastMessage)
         EmojiTextView dialogLastMessage;
         @BindView(R.id.dialogUnreadBubble)

+ 1 - 8
app/src/main/java/com/nextcloud/talk/adapters/items/GenericTextHeaderItem.java

@@ -28,14 +28,12 @@ import butterknife.ButterKnife;
 import com.nextcloud.talk.R;
 import eu.davidea.flexibleadapter.FlexibleAdapter;
 import eu.davidea.flexibleadapter.items.AbstractHeaderItem;
-import eu.davidea.flexibleadapter.items.IFilterable;
 import eu.davidea.flexibleadapter.items.IFlexible;
 import eu.davidea.viewholders.FlexibleViewHolder;
-import org.apache.commons.lang3.StringUtils;
 
 import java.util.List;
 
-public class GenericTextHeaderItem extends AbstractHeaderItem<GenericTextHeaderItem.HeaderViewHolder> implements IFilterable<String> {
+public class GenericTextHeaderItem extends AbstractHeaderItem<GenericTextHeaderItem.HeaderViewHolder> {
     private static final String TAG = "GenericTextHeaderItem";
 
     private String title;
@@ -47,11 +45,6 @@ public class GenericTextHeaderItem extends AbstractHeaderItem<GenericTextHeaderI
         this.title = title;
     }
 
-    @Override
-    public boolean filter(String constraint) {
-        return StringUtils.containsIgnoreCase(title, constraint);
-    }
-
     public String getModel() {
         return title;
     }

+ 15 - 28
app/src/main/java/com/nextcloud/talk/adapters/items/MentionAutocompleteItem.java

@@ -22,25 +22,21 @@ package com.nextcloud.talk.adapters.items;
 
 import android.annotation.SuppressLint;
 import android.view.View;
-import com.bumptech.glide.load.engine.DiskCacheStrategy;
-import com.bumptech.glide.load.model.GlideUrl;
-import com.bumptech.glide.load.model.LazyHeaders;
-import com.bumptech.glide.load.resource.bitmap.CircleCrop;
-import com.bumptech.glide.request.RequestOptions;
+import com.facebook.drawee.backends.pipeline.Fresco;
+import com.facebook.drawee.interfaces.DraweeController;
 import com.nextcloud.talk.R;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
 import com.nextcloud.talk.models.database.UserEntity;
 import com.nextcloud.talk.utils.ApiUtils;
 import com.nextcloud.talk.utils.DisplayUtils;
-import com.nextcloud.talk.utils.glide.GlideApp;
 import eu.davidea.flexibleadapter.FlexibleAdapter;
 import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
 import eu.davidea.flexibleadapter.items.IFilterable;
 import eu.davidea.flexibleadapter.items.IFlexible;
 import eu.davidea.flexibleadapter.utils.FlexibleUtils;
-import org.apache.commons.lang3.StringUtils;
 
 import java.util.List;
+import java.util.regex.Pattern;
 
 public class MentionAutocompleteItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder>
         implements IFilterable<String> {
@@ -115,32 +111,23 @@ public class MentionAutocompleteItem extends AbstractFlexibleItem<UserItem.UserI
         }
 
         if (source.equals("calls")) {
-            holder.avatarFlipView.setFrontImageBitmap(DisplayUtils.getRoundedBitmapFromVectorDrawableResource(NextcloudTalkApplication.getSharedApplication().getResources(), R.drawable.ic_people_group_white_24px));
+            holder.simpleDraweeView.getHierarchy().setPlaceholderImage(DisplayUtils.getRoundedBitmapDrawableFromVectorDrawableResource(NextcloudTalkApplication.getSharedApplication().getResources(), R.drawable.ic_people_group_white_24px));
         } else {
-            GlideUrl glideUrl = new GlideUrl(ApiUtils.getUrlForAvatarWithName(currentUser.getBaseUrl(),
-                    objectId, R.dimen.avatar_size), new LazyHeaders.Builder()
-                    .setHeader("Accept", "image/*")
-                    .setHeader("User-Agent", ApiUtils.getUserAgent())
-                    .build());
-
-            int avatarSize = Math.round(NextcloudTalkApplication
-                    .getSharedApplication().getResources().getDimension(R.dimen.avatar_size));
-
-            GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext())
-                    .asBitmap()
-                    .diskCacheStrategy(DiskCacheStrategy.NONE)
-                    .load(glideUrl)
-                    .centerInside()
-                    .override(avatarSize, avatarSize)
-                    .apply(RequestOptions.bitmapTransform(new CircleCrop()))
-                    .into(holder.avatarFlipView.getFrontImageView());
+        holder.simpleDraweeView.setController(null);
+            DraweeController draweeController = Fresco.newDraweeControllerBuilder()
+                    .setOldController(holder.simpleDraweeView.getController())
+                    .setAutoPlayAnimations(true)
+                    .setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(currentUser.getBaseUrl(),
+                            objectId, R.dimen.avatar_size_big), null))
+                    .build();
+            holder.simpleDraweeView.setController(draweeController);
         }
     }
 
     @Override
     public boolean filter(String constraint) {
-        return objectId != null && StringUtils.containsIgnoreCase(objectId, constraint) ||
-                displayName != null && StringUtils.containsIgnoreCase(displayName, constraint);
-
+        return objectId != null && Pattern.compile(constraint,
+                Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(objectId).find()
+                || displayName != null && Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(displayName).find();
     }
 }

+ 20 - 37
app/src/main/java/com/nextcloud/talk/adapters/items/NotificationSoundItem.java

@@ -20,12 +20,16 @@
 
 package com.nextcloud.talk.adapters.items;
 
+import android.content.res.Resources;
+import android.graphics.drawable.ColorDrawable;
 import android.view.View;
+import android.widget.ImageView;
 import android.widget.TextView;
 import butterknife.BindView;
 import butterknife.ButterKnife;
+import com.facebook.drawee.view.SimpleDraweeView;
 import com.nextcloud.talk.R;
-import com.nextcloud.talk.utils.MagicFlipView;
+import com.nextcloud.talk.application.NextcloudTalkApplication;
 import eu.davidea.flexibleadapter.FlexibleAdapter;
 import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
 import eu.davidea.flexibleadapter.items.IFlexible;
@@ -38,10 +42,6 @@ public class NotificationSoundItem extends AbstractFlexibleItem<NotificationSoun
     private String notificationSoundName;
     private String notificationSoundUri;
 
-    private boolean selected;
-
-    private MagicFlipView flipView;
-
     public NotificationSoundItem(String notificationSoundName, String notificationSoundUri) {
         this.notificationSoundName = notificationSoundName;
         this.notificationSoundUri = notificationSoundUri;
@@ -70,51 +70,34 @@ public class NotificationSoundItem extends AbstractFlexibleItem<NotificationSoun
         return new NotificationSoundItemViewHolder(view, adapter);
     }
 
-    public boolean isSelected() {
-        return selected;
-    }
-
-    public void setSelected(boolean selected) {
-        this.selected = selected;
-    }
-
-    public void flipToFront() {
-        if (flipView != null && flipView.isFlipped()) {
-            flipView.flip(false);
-        }
-    }
-
-    public void flipItemSelection() {
-        if (flipView != null) {
-            flipView.flip(!flipView.isFlipped());
-        }
-    }
-
     @Override
     public void bindViewHolder(FlexibleAdapter<IFlexible> adapter, NotificationSoundItemViewHolder holder, int position, List<Object> payloads) {
-        flipView = holder.magicFlipView;
-
-        holder.magicFlipView.flipSilently(adapter.isSelected(position) || isSelected());
+        holder.notificationName.setText(notificationSoundName);
 
-        if (isSelected() && !adapter.isSelected(position)) {
-            adapter.toggleSelection(position);
-            selected = false;
+        if (adapter.isSelected(position)) {
+            holder.checkedImageView.setVisibility(View.VISIBLE);
+        } else {
+            holder.checkedImageView.setVisibility(View.GONE);
         }
 
-        holder.notificationName.setText(notificationSoundName);
-
+        Resources resources = NextcloudTalkApplication.getSharedApplication().getResources();
+        holder.simpleDraweeView.getHierarchy().setBackgroundImage(new ColorDrawable(resources.getColor(R.color.colorPrimary)));
         if (position == 0) {
-            holder.magicFlipView.setFrontImage(R.drawable.ic_stop_white_24dp);
+            holder.simpleDraweeView.getHierarchy().setImage(resources.getDrawable(R.drawable.ic_stop_white_24dp), 100,
+                    true);
         } else {
-            holder.magicFlipView.setFrontImage(R.drawable.ic_play_circle_outline_white_24dp);
+            holder.simpleDraweeView.getHierarchy().setImage(resources.getDrawable(R.drawable.ic_play_circle_outline_white_24dp), 100,
+                    true);
         }
     }
 
     static class NotificationSoundItemViewHolder extends FlexibleViewHolder {
         @BindView(R.id.notificationNameTextView)
         public TextView notificationName;
-        @BindView(R.id.magicFlipView)
-        MagicFlipView magicFlipView;
+        @BindView(R.id.simpleDraweeView)
+        SimpleDraweeView simpleDraweeView;
+        @BindView(R.id.checkedImageView)
+        ImageView checkedImageView;
 
         /**
          * Default constructor.

+ 1 - 1
app/src/main/java/com/nextcloud/talk/adapters/items/ProgressItem.java

@@ -139,4 +139,4 @@ public class ProgressItem extends AbstractFlexibleItem<ProgressItem.ProgressView
         }
     }
 
-}
+}

+ 52 - 63
app/src/main/java/com/nextcloud/talk/adapters/items/UserItem.java

@@ -21,17 +21,16 @@
 package com.nextcloud.talk.adapters.items;
 
 import android.content.res.Resources;
+import android.graphics.drawable.BitmapDrawable;
 import android.text.TextUtils;
 import android.view.View;
 import android.widget.ImageView;
 import android.widget.TextView;
 import butterknife.BindView;
 import butterknife.ButterKnife;
-import com.bumptech.glide.load.engine.DiskCacheStrategy;
-import com.bumptech.glide.load.model.GlideUrl;
-import com.bumptech.glide.load.model.LazyHeaders;
-import com.bumptech.glide.load.resource.bitmap.CircleCrop;
-import com.bumptech.glide.request.RequestOptions;
+import com.facebook.drawee.backends.pipeline.Fresco;
+import com.facebook.drawee.interfaces.DraweeController;
+import com.facebook.drawee.view.SimpleDraweeView;
 import com.nextcloud.talk.R;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
 import com.nextcloud.talk.models.database.UserEntity;
@@ -39,18 +38,16 @@ import com.nextcloud.talk.models.json.converters.EnumParticipantTypeConverter;
 import com.nextcloud.talk.models.json.participants.Participant;
 import com.nextcloud.talk.utils.ApiUtils;
 import com.nextcloud.talk.utils.DisplayUtils;
-import com.nextcloud.talk.utils.glide.GlideApp;
 import eu.davidea.flexibleadapter.FlexibleAdapter;
 import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
 import eu.davidea.flexibleadapter.items.IFilterable;
 import eu.davidea.flexibleadapter.items.ISectionable;
 import eu.davidea.flexibleadapter.utils.FlexibleUtils;
-import eu.davidea.flipview.FlipView;
 import eu.davidea.viewholders.FlexibleViewHolder;
-import org.apache.commons.lang3.StringUtils;
 
 import javax.annotation.Nullable;
 import java.util.List;
+import java.util.regex.Pattern;
 
 public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder> implements
         ISectionable<UserItem.UserItemViewHolder, GenericTextHeaderItem>, IFilterable<String> {
@@ -59,9 +56,6 @@ public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder>
     private UserEntity userEntity;
     private GenericTextHeaderItem header;
 
-    private FlipView flipView;
-
-
     public UserItem(Participant participant, UserEntity userEntity, GenericTextHeaderItem genericTextHeaderItem) {
         this.participant = participant;
         this.userEntity = userEntity;
@@ -94,9 +88,6 @@ public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder>
         return userEntity;
     }
 
-    public void flipItemSelection() {
-        flipView.flip(!flipView.isFlipped());
-    }
 
     @Override
     public int getLayoutRes() {
@@ -115,9 +106,13 @@ public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder>
     @Override
     public void bindViewHolder(FlexibleAdapter adapter, UserItemViewHolder holder, int position, List payloads) {
 
-        flipView = holder.avatarFlipView;
-
-        flipView.flipSilently(adapter.isSelected(position));
+        if (holder.checkedImageView != null) {
+            if (adapter.isSelected(position)) {
+                holder.checkedImageView.setVisibility(View.VISIBLE);
+            } else {
+                holder.checkedImageView.setVisibility(View.GONE);
+            }
+        }
 
         if (adapter.hasFilter()) {
             FlexibleUtils.highlightText(holder.contactDisplayName, participant.getDisplayName(),
@@ -132,35 +127,23 @@ public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder>
             }
         }
 
-        int avatarSize = Math.round(NextcloudTalkApplication
-                .getSharedApplication().getResources().getDimension(R.dimen.avatar_size));
-
         if (TextUtils.isEmpty(participant.getSource()) || participant.getSource().equals("users")) {
 
             if (Participant.ParticipantType.GUEST.equals(participant.getType()) ||
                     Participant.ParticipantType.USER_FOLLOWING_LINK.equals(participant.getType())) {
                 // TODO: Show generated avatar for guests
             } else {
-                GlideUrl glideUrl = new GlideUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
-                        participant.getUserId(), R.dimen.avatar_size), new LazyHeaders.Builder()
-                        .setHeader("Accept", "image/*")
-                        .setHeader("User-Agent", ApiUtils.getUserAgent())
-                        .build());
-
-                GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext())
-                        .asBitmap()
-                        .diskCacheStrategy(DiskCacheStrategy.NONE)
-                        .load(glideUrl)
-                        .centerInside()
-                        .override(avatarSize, avatarSize)
-                        .apply(RequestOptions.bitmapTransform(new CircleCrop()))
-                        .into(flipView.getFrontImageView());
+                DraweeController draweeController = Fresco.newDraweeControllerBuilder()
+                        .setOldController(holder.simpleDraweeView.getController())
+                        .setAutoPlayAnimations(true)
+                        .setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(),
+                                participant.getUserId(), R.dimen.avatar_size), null))
+                        .build();
+                holder.simpleDraweeView.setController(draweeController);
+
             }
         } else if ("groups".equals(participant.getSource())) {
-
-            flipView.setFrontImageBitmap(DisplayUtils
-                    .getRoundedBitmapFromVectorDrawableResource(NextcloudTalkApplication.getSharedApplication().getResources(),
-                            R.drawable.ic_people_group_white_24px));
+            holder.simpleDraweeView.getHierarchy().setImage(new BitmapDrawable(DisplayUtils.getRoundedBitmapFromVectorDrawableResource(NextcloudTalkApplication.getSharedApplication().getResources(), R.drawable.ic_people_group_white_24px)), 100, true);
         }
 
         if (!isEnabled()) {
@@ -206,37 +189,40 @@ public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder>
                     break;
             }
 
-            String userType = "";
 
-            switch (new EnumParticipantTypeConverter().convertToInt(participant.getType())) {
-                case 1:
-                    //userType = NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_owner);
-                    //break;
-                case 2:
-                    userType = NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_moderator);
-                    break;
-                case 3:
-                    userType = NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_user);
-                    break;
-                case 4:
-                    userType = NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_guest);
-                    break;
-                case 5:
-                    userType = NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_following_link);
-                    break;
-                default:
-                    break;
+            if (holder.contactMentionId != null) {
+                String userType = "";
+
+                switch (new EnumParticipantTypeConverter().convertToInt(participant.getType())) {
+                    case 1:
+                        //userType = NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_owner);
+                        //break;
+                    case 2:
+                        userType = NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_moderator);
+                        break;
+                    case 3:
+                        userType = NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_user);
+                        break;
+                    case 4:
+                        userType = NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_guest);
+                        break;
+                    case 5:
+                        userType = NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_following_link);
+                        break;
+                    default:
+                        break;
+                }
+
+                holder.contactMentionId.setText(userType);
+                holder.contactMentionId.setTextColor(NextcloudTalkApplication.getSharedApplication().getResources().getColor(R.color.colorPrimary));
             }
-
-            holder.contactMentionId.setText(userType);
-            holder.contactMentionId.setTextColor(NextcloudTalkApplication.getSharedApplication().getResources().getColor(R.color.colorPrimary));
         }
     }
 
     @Override
     public boolean filter(String constraint) {
         return participant.getDisplayName() != null &&
-                StringUtils.containsIgnoreCase(participant.getDisplayName().trim(), constraint);
+                Pattern.compile(constraint, Pattern.CASE_INSENSITIVE | Pattern.LITERAL).matcher(participant.getDisplayName().trim()).find();
     }
 
     @Override
@@ -254,8 +240,8 @@ public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder>
 
         @BindView(R.id.name_text)
         public TextView contactDisplayName;
-        @BindView(R.id.avatar_flip_view)
-        public FlipView avatarFlipView;
+        @BindView(R.id.simple_drawee_view)
+        public SimpleDraweeView simpleDraweeView;
         @Nullable
         @BindView(R.id.secondary_text)
         public TextView contactMentionId;
@@ -265,6 +251,9 @@ public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder>
         @Nullable
         @BindView(R.id.videoCallImageView)
         ImageView videoCallImageView;
+        @Nullable
+        @BindView(R.id.checkedImageView)
+        ImageView checkedImageView;
 
         /**
          * Default constructor.

+ 3 - 3
app/src/main/java/com/nextcloud/talk/adapters/messages/MagicIncomingTextMessageViewHolder.java

@@ -145,14 +145,14 @@ public class MagicIncomingTextMessageViewHolder
                 Map<String, String> individualHashMap = message.getMessageParameters().get(key);
                 if (individualHashMap != null) {
                     if (individualHashMap.get("type").equals("user") || individualHashMap.get("type").equals("guest") || individualHashMap.get("type").equals("call")) {
-                        if (individualHashMap.get("id").equals(message.getActiveUserId())) {
+                        if (individualHashMap.get("id").equals(message.getActiveUser().getUserId())) {
                             messageString =
                                     DisplayUtils.searchAndReplaceWithMentionSpan(messageText.getContext(),
                                             messageString,
                                             individualHashMap.get("id"),
                                             individualHashMap.get("name"),
                                             individualHashMap.get("type"),
-                                            userUtils.getUserById(message.getActiveUserId()),
+                                            userUtils.getUserById(message.getActiveUser().getUserId()),
                                             R.xml.chip_accent_background);
                         } else {
                             messageString =
@@ -161,7 +161,7 @@ public class MagicIncomingTextMessageViewHolder
                                             individualHashMap.get("id"),
                                             individualHashMap.get("name"),
                                             individualHashMap.get("type"),
-                                            userUtils.getUserById(message.getActiveUserId()),
+                                            userUtils.getUserById(message.getActiveUser().getUserId()),
                                             R.xml.chip_incoming_others);
                         }
 

+ 3 - 3
app/src/main/java/com/nextcloud/talk/adapters/messages/MagicOutcomingTextMessageViewHolder.java

@@ -92,14 +92,14 @@ public class MagicOutcomingTextMessageViewHolder extends MessageHolders.Outcomin
                 Map<String, String> individualHashMap = message.getMessageParameters().get(key);
                 if (individualHashMap != null) {
                     if (individualHashMap.get("type").equals("user") || individualHashMap.get("type").equals("guest") || individualHashMap.get("type").equals("call")) {
-                        if (!individualHashMap.get("id").equals(message.getActiveUserId())) {
+                        if (!individualHashMap.get("id").equals(message.getActiveUser().getUserId())) {
                             messageString =
                                     DisplayUtils.searchAndReplaceWithMentionSpan(messageText.getContext(),
                                             messageString,
                                             individualHashMap.get("id"),
                                             individualHashMap.get("name"),
                                             individualHashMap.get("type"),
-                                            userUtils.getUserById(message.getActiveUserId()),
+                                            userUtils.getUserById(message.getActiveUser().getUserId()),
                                             R.xml.chip_outgoing_others);
                         } else {
                             messageString =
@@ -108,7 +108,7 @@ public class MagicOutcomingTextMessageViewHolder extends MessageHolders.Outcomin
                                             individualHashMap.get("id"),
                                             individualHashMap.get("name"),
                                             individualHashMap.get("type"),
-                                            userUtils.getUserById(message.getActiveUserId()),
+                                            userUtils.getUserById(message.getActiveUser().getUserId()),
                                             R.xml.chip_outgoing_own_mention);
                         }
                     } else if (individualHashMap.get("type").equals("file")) {

+ 76 - 4
app/src/main/java/com/nextcloud/talk/adapters/messages/MagicPreviewMessageViewHolder.java

@@ -21,23 +21,39 @@
 package com.nextcloud.talk.adapters.messages;
 
 import android.annotation.SuppressLint;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
 import android.net.Uri;
+import android.os.Bundle;
 import android.view.View;
 import autodagger.AutoInjector;
 import butterknife.BindView;
 import butterknife.ButterKnife;
 import com.nextcloud.talk.R;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
+import com.nextcloud.talk.components.filebrowser.models.BrowserFile;
+import com.nextcloud.talk.components.filebrowser.models.DavResponse;
+import com.nextcloud.talk.components.filebrowser.webdav.ReadFilesystemOperation;
+import com.nextcloud.talk.models.database.UserEntity;
 import com.nextcloud.talk.models.json.chat.ChatMessage;
+import com.nextcloud.talk.utils.AccountUtils;
 import com.nextcloud.talk.utils.DisplayUtils;
+import com.nextcloud.talk.utils.DrawableUtils;
+import com.nextcloud.talk.utils.bundle.BundleKeys;
 import com.stfalcon.chatkit.messages.MessageHolders;
 import com.vanniktech.emoji.EmojiTextView;
+import io.reactivex.Single;
+import io.reactivex.SingleObserver;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
+import okhttp3.OkHttpClient;
 
 import javax.inject.Inject;
+import java.util.List;
+import java.util.concurrent.Callable;
 
 @AutoInjector(NextcloudTalkApplication.class)
 public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageMessageViewHolder<ChatMessage> {
@@ -48,6 +64,9 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM
     @Inject
     Context context;
 
+    @Inject
+    OkHttpClient okHttpClient;
+
     public MagicPreviewMessageViewHolder(View itemView) {
         super(itemView);
         ButterKnife.bind(this, itemView);
@@ -58,7 +77,6 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM
     @Override
     public void onBind(ChatMessage message) {
         super.onBind(message);
-
         if (userAvatar != null) {
             if (message.isGrouped) {
                 userAvatar.setVisibility(View.INVISIBLE);
@@ -80,10 +98,32 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM
             // it's a preview for a Nextcloud share
             messageText.setText(message.getSelectedIndividualHashMap().get("name"));
             DisplayUtils.setClickableString(message.getSelectedIndividualHashMap().get("name"), message.getSelectedIndividualHashMap().get("link"), messageText);
+            if (message.getSelectedIndividualHashMap().containsKey("mimetype")) {
+                image.getHierarchy().setPlaceholderImage(context.getDrawable(DrawableUtils.getDrawableResourceIdForMimeType(message.getSelectedIndividualHashMap().get("mimetype"))));
+            } else {
+                fetchFileInformation("/" + message.getSelectedIndividualHashMap().get("path"), message.getActiveUser());
+            }
+
             image.setOnClickListener(v -> {
-                Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(message.getSelectedIndividualHashMap().get("link")));
-                browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                NextcloudTalkApplication.getSharedApplication().getApplicationContext().startActivity(browserIntent);
+
+                String accountString =
+                        message.getActiveUser().getUsername() + "@" + message.getActiveUser().getBaseUrl().replace("https://", "").replace("http://", "");
+
+                if (AccountUtils.canWeOpenFilesApp(context, accountString)) {
+                    Intent filesAppIntent = new Intent(Intent.ACTION_VIEW, null);
+                    final ComponentName componentName = new ComponentName(context.getString(R.string.nc_import_accounts_from), "com.owncloud.android.ui.activity.FileDisplayActivity");
+                    filesAppIntent.setComponent(componentName);
+                    filesAppIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                    filesAppIntent.setPackage(context.getString(R.string.nc_import_accounts_from));
+                    Bundle options = new Bundle();
+                    options.putString(BundleKeys.KEY_ACCOUNT, accountString);
+                    options.putString(BundleKeys.KEY_FILE_PATH, "/" + message.getSelectedIndividualHashMap().get("path"));
+                    context.startActivity(filesAppIntent, options);
+                } else {
+                    Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(message.getSelectedIndividualHashMap().get("link")));
+                    browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                    context.startActivity(browserIntent);
+                }
             });
         } else if (message.getMessageType() == ChatMessage.MessageType.SINGLE_LINK_GIPHY_MESSAGE) {
             messageText.setText("GIPHY");
@@ -95,4 +135,36 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM
             messageText.setText("");
         }
     }
+
+    private void fetchFileInformation(String url, UserEntity activeUser) {
+        Single.fromCallable(new Callable<ReadFilesystemOperation>() {
+            @Override
+            public ReadFilesystemOperation call() {
+                return new ReadFilesystemOperation(okHttpClient, activeUser, url, 0);
+            }
+        }).subscribeOn(Schedulers.newThread())
+                .subscribe(new SingleObserver<ReadFilesystemOperation>() {
+                    @Override
+                    public void onSubscribe(Disposable d) {
+
+                    }
+
+                    @Override
+                    public void onSuccess(ReadFilesystemOperation readFilesystemOperation) {
+                        DavResponse davResponse = readFilesystemOperation.readRemotePath();
+                        if (davResponse.getData() != null) {
+                            List<BrowserFile> browserFileList = (List<BrowserFile>) davResponse.getData();
+                            if (!browserFileList.isEmpty()) {
+                                image.getHierarchy().setPlaceholderImage(context.getDrawable(DrawableUtils.getDrawableResourceIdForMimeType(browserFileList.get(0).getMimeType())));
+                            }
+
+                        }
+                    }
+
+                    @Override
+                    public void onError(Throwable e) {
+                    }
+                });
+
+    }
 }

+ 1 - 1
app/src/main/java/com/nextcloud/talk/adapters/messages/MagicSystemMessageViewHolder.java

@@ -61,7 +61,7 @@ public class MagicSystemMessageViewHolder extends MessageHolders.IncomingTextMes
                 int color;
                 if (individualHashMap != null && (individualHashMap.get("type").equals("user") || individualHashMap.get("type").equals("guest") || individualHashMap.get("type").equals("call"))) {
 
-                    if (individualHashMap.get("id").equals(message.getActiveUserId())) {
+                    if (individualHashMap.get("id").equals(message.getActiveUser().getUserId())) {
                         color = context.getResources().getColor(R.color.nc_incoming_text_mention_you);
                     } else {
                         color = context.getResources().getColor(R.color.nc_incoming_text_mention_others);

+ 7 - 0
app/src/main/java/com/nextcloud/talk/api/NcApi.java

@@ -306,4 +306,11 @@ public interface NcApi {
     @PUT
     Observable<GenericOverall> setReadOnlyState(@Header("Authorization") String authorization, @Url String url, @Field("state") int state);
 
+
+    @FormUrlEncoded
+    @POST
+    Observable<Void> createRemoteShare(@Nullable @Header("Authorization") String authorization, @Url String url,
+                                       @Field("path") String remotePath,
+                                       @Field("shareWith") String roomToken,
+                                       @Field("shareType") String shareType);
 }

+ 5 - 0
app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.java

@@ -35,6 +35,7 @@ import autodagger.AutoInjector;
 import com.facebook.cache.disk.DiskCacheConfig;
 import com.facebook.drawee.backends.pipeline.Fresco;
 import com.facebook.imagepipeline.core.ImagePipelineConfig;
+import com.nextcloud.talk.components.filebrowser.webdav.DavUtils;
 import com.nextcloud.talk.dagger.modules.BusModule;
 import com.nextcloud.talk.dagger.modules.ContextModule;
 import com.nextcloud.talk.dagger.modules.DatabaseModule;
@@ -53,12 +54,14 @@ import com.nextcloud.talk.webrtc.MagicWebRTCUtils;
 import com.vanniktech.emoji.EmojiManager;
 import com.vanniktech.emoji.twitter.TwitterEmojiProvider;
 import okhttp3.OkHttpClient;
+import org.conscrypt.Conscrypt;
 import org.webrtc.PeerConnectionFactory;
 import org.webrtc.voiceengine.WebRtcAudioManager;
 import org.webrtc.voiceengine.WebRtcAudioUtils;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
+import java.security.Security;
 import java.util.concurrent.TimeUnit;
 
 @AutoComponent(
@@ -121,6 +124,7 @@ public class NextcloudTalkApplication extends MultiDexApplication implements Lif
         initializeWebRtc();
         DisplayUtils.useCompatVectorIfNeeded();
         buildComponent();
+        DavUtils.registerCustomFactories();
 
         componentApplication.inject(this);
 
@@ -134,6 +138,7 @@ public class NextcloudTalkApplication extends MultiDexApplication implements Lif
                 .build();
 
         Fresco.initialize(this, imagePipelineConfig);
+        Security.insertProviderAt(Conscrypt.newProvider(), 1);
 
         new ClosedInterfaceImpl().providerInstallerInstallIfNeededAsync();
         DeviceUtils.ignoreSpecialBatteryFeatures();

+ 186 - 0
app/src/main/java/com/nextcloud/talk/components/filebrowser/adapters/items/BrowserFileItem.java

@@ -0,0 +1,186 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 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.nextcloud.talk.components.filebrowser.adapters.items;
+
+import android.content.Context;
+import android.text.format.Formatter;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.ImageView;
+import android.widget.TextView;
+import autodagger.AutoInjector;
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import com.facebook.drawee.backends.pipeline.Fresco;
+import com.facebook.drawee.interfaces.DraweeController;
+import com.facebook.drawee.view.SimpleDraweeView;
+import com.nextcloud.talk.R;
+import com.nextcloud.talk.application.NextcloudTalkApplication;
+import com.nextcloud.talk.components.filebrowser.models.BrowserFile;
+import com.nextcloud.talk.interfaces.SelectionInterface;
+import com.nextcloud.talk.models.database.UserEntity;
+import com.nextcloud.talk.utils.ApiUtils;
+import com.nextcloud.talk.utils.DateUtils;
+import com.nextcloud.talk.utils.DisplayUtils;
+import com.nextcloud.talk.utils.DrawableUtils;
+import eu.davidea.flexibleadapter.FlexibleAdapter;
+import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
+import eu.davidea.flexibleadapter.items.IFilterable;
+import eu.davidea.flexibleadapter.items.IFlexible;
+import eu.davidea.viewholders.FlexibleViewHolder;
+
+import javax.inject.Inject;
+import java.util.List;
+
+@AutoInjector(NextcloudTalkApplication.class)
+public class BrowserFileItem extends AbstractFlexibleItem<BrowserFileItem.ViewHolder> implements IFilterable<String> {
+    @Inject
+    Context context;
+    private BrowserFile browserFile;
+    private UserEntity activeUser;
+    private SelectionInterface selectionInterface;
+    private boolean selected;
+
+    public BrowserFileItem(BrowserFile browserFile, UserEntity activeUser, SelectionInterface selectionInterface) {
+        this.browserFile = browserFile;
+        this.activeUser = activeUser;
+        this.selectionInterface = selectionInterface;
+        NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof BrowserFileItem) {
+            BrowserFileItem inItem = (BrowserFileItem) o;
+            return browserFile.getPath().equals(inItem.getModel().getPath());
+        }
+
+        return false;
+    }
+
+    public BrowserFile getModel() {
+        return browserFile;
+    }
+
+    @Override
+    public int getLayoutRes() {
+        return R.layout.rv_item_browser_file;
+    }
+
+    @Override
+    public ViewHolder createViewHolder(View view, FlexibleAdapter<IFlexible> adapter) {
+        return new ViewHolder(view, adapter);
+
+    }
+
+    private boolean isSelected() {
+        return selected;
+    }
+
+    private void setSelected(boolean selected) {
+        this.selected = selected;
+    }
+
+    @Override
+    public void bindViewHolder(FlexibleAdapter<IFlexible> adapter, ViewHolder holder, int position, List<Object> payloads) {
+        holder.fileIconImageView.setController(null);
+
+        if (browserFile.isEncrypted()) {
+            holder.fileEncryptedImageView.setVisibility(View.VISIBLE);
+            holder.itemView.setEnabled(false);
+            holder.itemView.setAlpha(0.38f);
+        } else {
+            holder.fileEncryptedImageView.setVisibility(View.GONE);
+            holder.itemView.setEnabled(true);
+            holder.itemView.setAlpha(1.0f);
+        }
+
+        if (browserFile.isFavorite()) {
+            holder.fileFavoriteImageView.setVisibility(View.VISIBLE);
+        } else {
+            holder.fileFavoriteImageView.setVisibility(View.GONE);
+        }
+
+        holder.fileIconImageView.getHierarchy().setPlaceholderImage(context.getDrawable(DrawableUtils.getDrawableResourceIdForMimeType(browserFile.getMimeType())));
+
+        if (browserFile.isHasPreview()) {
+            String path = ApiUtils.getUrlForFilePreviewWithRemotePath(activeUser.getBaseUrl(),
+                    browserFile.getPath(),
+                    context.getResources().getDimensionPixelSize(R.dimen.small_item_height));
+
+            if (path.length() > 0) {
+                DraweeController draweeController = Fresco.newDraweeControllerBuilder()
+                        .setAutoPlayAnimations(true)
+                        .setImageRequest(DisplayUtils.getImageRequestForUrl(path, null))
+                        .build();
+                holder.fileIconImageView.setController(draweeController);
+            }
+        }
+
+        holder.filenameTextView.setText(browserFile.getDisplayName());
+        holder.fileModifiedTextView.setText(String.format(context.getString(R.string.nc_last_modified),
+                Formatter.formatShortFileSize(context, browserFile.getSize()),
+                DateUtils.getLocalDateTimeStringFromTimestamp(context, browserFile.getModifiedTimestamp())));
+        setSelected(selectionInterface.isPathSelected(browserFile.getPath()));
+        holder.selectFileCheckbox.setChecked(isSelected());
+
+        if (!browserFile.isEncrypted()) {
+            holder.selectFileCheckbox.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    if (((CheckBox) v).isChecked() != isSelected()) {
+                        setSelected(((CheckBox) v).isChecked());
+                        selectionInterface.toggleBrowserItemSelection(browserFile.getPath());
+                    }
+                }
+            });
+        }
+
+        holder.filenameTextView.setSelected(true);
+        holder.fileModifiedTextView.setSelected(true);
+    }
+
+    @Override
+    public boolean filter(String constraint) {
+        return false;
+    }
+
+    static class ViewHolder extends FlexibleViewHolder {
+
+        @BindView(R.id.file_icon)
+        public SimpleDraweeView fileIconImageView;
+        @BindView(R.id.file_modified_info)
+        public TextView fileModifiedTextView;
+        @BindView(R.id.filename_text_view)
+        public TextView filenameTextView;
+        @BindView(R.id.select_file_checkbox)
+        public CheckBox selectFileCheckbox;
+        @BindView(R.id.fileEncryptedImageView)
+        public ImageView fileEncryptedImageView;
+        @BindView(R.id.fileFavoriteImageView)
+        public ImageView fileFavoriteImageView;
+
+        ViewHolder(View view, FlexibleAdapter adapter) {
+            super(view, adapter);
+            ButterKnife.bind(this, view);
+        }
+    }
+}

+ 333 - 0
app/src/main/java/com/nextcloud/talk/components/filebrowser/controllers/BrowserController.java

@@ -0,0 +1,333 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 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.nextcloud.talk.components.filebrowser.controllers;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.*;
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.work.Data;
+import androidx.work.OneTimeWorkRequest;
+import androidx.work.WorkManager;
+import autodagger.AutoInjector;
+import butterknife.BindView;
+import butterknife.OnClick;
+import com.google.android.material.bottomnavigation.BottomNavigationItemView;
+import com.nextcloud.talk.R;
+import com.nextcloud.talk.application.NextcloudTalkApplication;
+import com.nextcloud.talk.components.filebrowser.adapters.items.BrowserFileItem;
+import com.nextcloud.talk.components.filebrowser.interfaces.ListingInterface;
+import com.nextcloud.talk.components.filebrowser.models.BrowserFile;
+import com.nextcloud.talk.components.filebrowser.models.DavResponse;
+import com.nextcloud.talk.components.filebrowser.operations.DavListing;
+import com.nextcloud.talk.components.filebrowser.operations.ListingAbstractClass;
+import com.nextcloud.talk.controllers.base.BaseController;
+import com.nextcloud.talk.interfaces.SelectionInterface;
+import com.nextcloud.talk.jobs.ShareOperationWorker;
+import com.nextcloud.talk.models.database.UserEntity;
+import com.nextcloud.talk.utils.bundle.BundleKeys;
+import com.nextcloud.talk.utils.database.user.UserUtils;
+import eu.davidea.fastscroller.FastScroller;
+import eu.davidea.flexibleadapter.FlexibleAdapter;
+import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager;
+import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
+import eu.davidea.flexibleadapter.items.IFlexible;
+import okhttp3.OkHttpClient;
+import org.parceler.Parcel;
+import org.parceler.Parcels;
+
+import javax.inject.Inject;
+import java.io.File;
+import java.util.*;
+
+@AutoInjector(NextcloudTalkApplication.class)
+public class BrowserController extends BaseController implements ListingInterface,
+        FlexibleAdapter.OnItemClickListener, SelectionInterface {
+    private final Set<String> selectedPaths;
+    @Inject
+    UserUtils userUtils;
+    @BindView(R.id.recycler_view)
+    RecyclerView recyclerView;
+    @BindView(R.id.fast_scroller)
+    FastScroller fastScroller;
+    @BindView(R.id.action_back)
+    BottomNavigationItemView backMenuItem;
+    @BindView(R.id.action_refresh)
+    BottomNavigationItemView actionRefreshMenuItem;
+    @Inject
+    Context context;
+    @Inject
+    OkHttpClient okHttpClient;
+
+    private MenuItem filesSelectionDoneMenuItem;
+    private RecyclerView.LayoutManager layoutManager;
+
+    private FlexibleAdapter<AbstractFlexibleItem> adapter;
+    private List<AbstractFlexibleItem> recyclerViewItems = new ArrayList<>();
+
+    private ListingAbstractClass listingAbstractClass;
+    private BrowserType browserType;
+    private String currentPath;
+    private UserEntity activeUser;
+    private String roomToken;
+
+    public BrowserController(Bundle args) {
+        super(args);
+        setHasOptionsMenu(true);
+        NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
+        browserType = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_BROWSER_TYPE));
+        activeUser = Parcels.unwrap(args.getParcelable(BundleKeys.KEY_USER_ENTITY));
+        roomToken = args.getString(BundleKeys.KEY_ROOM_TOKEN);
+
+        currentPath = "/";
+        if (BrowserType.DAV_BROWSER.equals(browserType)) {
+            listingAbstractClass = new DavListing(this);
+        } else {
+            //listingAbstractClass = new LocalListing(this);
+        }
+
+        selectedPaths = Collections.synchronizedSet(new TreeSet<>());
+    }
+
+    @Override
+    protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
+        return inflater.inflate(R.layout.controller_browser, container, false);
+    }
+
+    @Override
+    protected void onViewBound(@NonNull View view) {
+        super.onViewBound(view);
+        if (adapter == null) {
+            adapter = new FlexibleAdapter<>(recyclerViewItems, context, false);
+        }
+
+        changeEnabledStatusForBarItems(true);
+        prepareViews();
+    }
+
+    private void onFileSelectionDone() {
+        synchronized (selectedPaths) {
+            Iterator<String> iterator = selectedPaths.iterator();
+
+            List<String> paths = new ArrayList<>();
+            Data data;
+            OneTimeWorkRequest shareWorker;
+
+            while (iterator.hasNext()) {
+                String path = iterator.next();
+                paths.add(path);
+                iterator.remove();
+                if (paths.size() == 10 || !iterator.hasNext()) {
+                    data = new Data.Builder()
+                            .putLong(BundleKeys.KEY_INTERNAL_USER_ID, activeUser.getId())
+                            .putString(BundleKeys.KEY_ROOM_TOKEN, roomToken)
+                            .putStringArray(BundleKeys.KEY_FILE_PATHS, paths.toArray(new String[0]))
+                            .build();
+                    shareWorker = new OneTimeWorkRequest.Builder(ShareOperationWorker.class)
+                            .setInputData(data)
+                            .build();
+                    WorkManager.getInstance().enqueue(shareWorker);
+                    paths = new ArrayList<>();
+                }
+            }
+        }
+
+        getRouter().popCurrentController();
+    }
+
+    @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        super.onCreateOptionsMenu(menu, inflater);
+        inflater.inflate(R.menu.menu_share_files, menu);
+        filesSelectionDoneMenuItem = menu.findItem(R.id.files_selection_done);
+        filesSelectionDoneMenuItem.setVisible(selectedPaths.size() > 0);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.files_selection_done:
+                onFileSelectionDone();
+                return true;
+            default:
+                return super.onOptionsItemSelected(item);
+        }
+    }
+
+    @Override
+    protected void onAttach(@NonNull View view) {
+        super.onAttach(view);
+        refreshCurrentPath();
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        listingAbstractClass.tearDown();
+    }
+
+    @Override
+    protected String getTitle() {
+        return currentPath;
+    }
+
+    @OnClick(R.id.action_back)
+    void goBack() {
+        fetchPath(new File(currentPath).getParent());
+    }
+
+    @OnClick(R.id.action_refresh)
+    void refreshCurrentPath() {
+        fetchPath(currentPath);
+    }
+
+    @SuppressLint("RestrictedApi")
+    private void changeEnabledStatusForBarItems(boolean shouldBeEnabled) {
+        if (actionRefreshMenuItem != null) {
+            actionRefreshMenuItem.setEnabled(shouldBeEnabled);
+        }
+
+        if (backMenuItem != null) {
+            backMenuItem.setEnabled(shouldBeEnabled && !currentPath.equals("/"));
+        }
+    }
+
+    private void fetchPath(String path) {
+        listingAbstractClass.cancelAllJobs();
+        changeEnabledStatusForBarItems(false);
+
+        listingAbstractClass.getFiles(path, activeUser, BrowserType.DAV_BROWSER.equals(browserType) ? okHttpClient : null);
+    }
+
+    @Override
+    public void listingResult(DavResponse davResponse) {
+        adapter.clear();
+        List<AbstractFlexibleItem> fileBrowserItems = new ArrayList<>();
+        if (davResponse.getData() != null) {
+            final List<BrowserFile> objectList = (List<BrowserFile>) davResponse.getData();
+
+            currentPath = objectList.get(0).getPath();
+
+            Objects.requireNonNull(getActivity()).runOnUiThread(this::setTitle);
+
+            for (int i = 1; i < objectList.size(); i++) {
+                fileBrowserItems.add(new BrowserFileItem(objectList.get(i), activeUser, this));
+            }
+        }
+
+        adapter.addItems(0, fileBrowserItems);
+        Objects.requireNonNull(getActivity()).runOnUiThread(() -> {
+            adapter.notifyDataSetChanged();
+            changeEnabledStatusForBarItems(true);
+        });
+    }
+
+    private boolean shouldPathBeSelectedDueToParent(String currentPath) {
+        if (selectedPaths.size() > 0) {
+            File file = new File(currentPath);
+            if (!file.getParent().equals("/")) {
+                while (file.getParent() != null) {
+                    String parent = file.getParent();
+                    if (new File(file.getParent()).getParent() != null) {
+                        parent += "/";
+                    }
+
+                    if (selectedPaths.contains(parent)) {
+                        return true;
+                    }
+
+                    file = new File(file.getParent());
+                }
+            }
+        }
+
+        return false;
+    }
+
+    private void checkAndRemoveAnySelectedParents(String currentPath) {
+        File file = new File(currentPath);
+        selectedPaths.remove(currentPath);
+        while (file.getParent() != null) {
+            selectedPaths.remove(file.getParent() + "/");
+            file = new File(file.getParent());
+        }
+
+        adapter.notifyDataSetChanged();
+    }
+
+    @Override
+    public boolean onItemClick(View view, int position) {
+        BrowserFile browserFile = ((BrowserFileItem) adapter.getItem(position)).getModel();
+        if ("inode/directory".equals((browserFile.getMimeType()))) {
+            fetchPath(browserFile.getPath());
+            return true;
+        }
+
+        return false;
+    }
+
+    private void prepareViews() {
+        if (getActivity() != null) {
+            layoutManager = new SmoothScrollLinearLayoutManager(getActivity());
+            recyclerView.setLayoutManager(layoutManager);
+            recyclerView.setHasFixedSize(true);
+            recyclerView.setAdapter(adapter);
+
+            adapter.setFastScroller(fastScroller);
+            adapter.addListener(this);
+
+            fastScroller.setBubbleTextCreator(position -> {
+                IFlexible abstractFlexibleItem = adapter.getItem(position);
+                if (abstractFlexibleItem instanceof BrowserFileItem) {
+                    return String.valueOf(((BrowserFileItem) adapter.getItem(position)).getModel().getDisplayName().charAt(0));
+                } else {
+                    return "";
+                }
+            });
+        }
+    }
+
+    @SuppressLint("RestrictedApi")
+    @Override
+    public void toggleBrowserItemSelection(String path) {
+        if (selectedPaths.contains(path) || shouldPathBeSelectedDueToParent(path)) {
+            checkAndRemoveAnySelectedParents(path);
+        } else {
+            // TOOD: if it's a folder, remove all the children we added manually
+            selectedPaths.add(path);
+        }
+
+        filesSelectionDoneMenuItem.setVisible(selectedPaths.size() > 0);
+    }
+
+    @Override
+    public boolean isPathSelected(String path) {
+        return (selectedPaths.contains(path) || shouldPathBeSelectedDueToParent(path));
+    }
+
+    @Parcel
+    public enum BrowserType {
+        FILE_BROWSER,
+        DAV_BROWSER,
+    }
+}

+ 4 - 21
app/src/main/java/com/nextcloud/talk/utils/MagicFlipView.java → app/src/main/java/com/nextcloud/talk/components/filebrowser/interfaces/ListingInterface.java

@@ -18,27 +18,10 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-package com.nextcloud.talk.utils;
+package com.nextcloud.talk.components.filebrowser.interfaces;
 
-import android.content.Context;
-import android.util.AttributeSet;
-import eu.davidea.flipview.FlipView;
+import com.nextcloud.talk.components.filebrowser.models.DavResponse;
 
-public class MagicFlipView extends FlipView {
-    public MagicFlipView(Context context) {
-        super(context);
-    }
-
-    public MagicFlipView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        try {
-            super.onDetachedFromWindow();
-        } catch (IllegalArgumentException e) {
-            stopFlipping();
-        }
-    }
+public interface ListingInterface {
+    void listingResult(DavResponse davResponse);
 }

+ 106 - 0
app/src/main/java/com/nextcloud/talk/components/filebrowser/models/BrowserFile.java

@@ -0,0 +1,106 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 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.nextcloud.talk.components.filebrowser.models;
+
+import android.net.Uri;
+import android.text.TextUtils;
+import at.bitfire.dav4android.Property;
+import at.bitfire.dav4android.Response;
+import at.bitfire.dav4android.property.DisplayName;
+import at.bitfire.dav4android.property.GetContentType;
+import at.bitfire.dav4android.property.GetLastModified;
+import at.bitfire.dav4android.property.ResourceType;
+import com.bluelinelabs.logansquare.annotation.JsonObject;
+import com.nextcloud.talk.components.filebrowser.models.properties.*;
+import lombok.Data;
+import org.parceler.Parcel;
+
+import java.io.File;
+import java.util.List;
+
+@Data
+@JsonObject
+@Parcel
+public class BrowserFile {
+    public String path;
+    public String displayName;
+    public String mimeType;
+    public long modifiedTimestamp;
+    public long size;
+    public boolean isFile;
+    // Used for remote files
+    public String remoteId;
+    public boolean hasPreview;
+    public boolean favorite;
+    public boolean encrypted;
+
+    public static BrowserFile getModelFromResponse(Response response, String remotePath) {
+        BrowserFile browserFile = new BrowserFile();
+        browserFile.setPath(Uri.decode(remotePath));
+        browserFile.setDisplayName(Uri.decode(new File(remotePath).getName()));
+        final List<Property> properties = response.getProperties();
+
+        for (Property property : properties) {
+            if (property instanceof OCId) {
+                browserFile.setRemoteId(((OCId) property).getOcId());
+            }
+
+            if (property instanceof ResourceType) {
+                browserFile.isFile =
+                        !(((ResourceType) property).getTypes().contains(ResourceType.Companion.getCOLLECTION()));
+            }
+
+            if (property instanceof GetLastModified) {
+                browserFile.setModifiedTimestamp(((GetLastModified) property).getLastModified());
+            }
+
+            if (property instanceof GetContentType) {
+                browserFile.setMimeType(((GetContentType) property).getType());
+            }
+
+            if (property instanceof OCSize) {
+                browserFile.setSize(((OCSize) property).getOcSize());
+            }
+
+            if (property instanceof NCPreview) {
+                browserFile.setHasPreview(((NCPreview) property).isNcPreview());
+            }
+
+            if (property instanceof OCFavorite) {
+                browserFile.setFavorite(((OCFavorite) property).isOcFavorite());
+            }
+
+            if (property instanceof DisplayName) {
+                browserFile.setDisplayName(((DisplayName) property).getDisplayName());
+            }
+
+            if (property instanceof NCEncrypted) {
+                browserFile.setEncrypted(((NCEncrypted) property).isNcEncrypted());
+            }
+        }
+
+        if (TextUtils.isEmpty(browserFile.getMimeType()) && !browserFile.isFile()) {
+            browserFile.setMimeType("inode/directory");
+        }
+
+        return browserFile;
+    }
+}

+ 30 - 0
app/src/main/java/com/nextcloud/talk/components/filebrowser/models/DavResponse.java

@@ -0,0 +1,30 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 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.nextcloud.talk.components.filebrowser.models;
+
+import at.bitfire.dav4android.Response;
+import lombok.Data;
+
+@Data
+public class DavResponse {
+    Response response;
+    Object data;
+}

+ 73 - 0
app/src/main/java/com/nextcloud/talk/components/filebrowser/models/properties/NCEncrypted.java

@@ -0,0 +1,73 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 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.nextcloud.talk.components.filebrowser.models.properties;
+
+import android.text.TextUtils;
+import at.bitfire.dav4android.Property;
+import at.bitfire.dav4android.PropertyFactory;
+import at.bitfire.dav4android.XmlUtils;
+import com.nextcloud.talk.components.filebrowser.webdav.DavUtils;
+import lombok.Getter;
+import lombok.Setter;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+public class NCEncrypted implements Property {
+    public static final Name NAME = new Name(DavUtils.NC_NAMESPACE, DavUtils.EXTENDED_PROPERTY_IS_ENCRYPTED);
+
+    @Getter
+    @Setter
+    private boolean ncEncrypted;
+
+    private NCEncrypted(boolean isEncrypted) {
+        ncEncrypted = isEncrypted;
+    }
+
+    public static class Factory implements PropertyFactory {
+
+        @Nullable
+        @Override
+        public Property create(@NotNull XmlPullParser xmlPullParser) {
+            try {
+                String text = XmlUtils.INSTANCE.readText(xmlPullParser);
+                if (!TextUtils.isEmpty(text)) {
+                    return new NCEncrypted(Boolean.parseBoolean(text));
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            } catch (XmlPullParserException e) {
+                e.printStackTrace();
+            }
+
+            return new NCEncrypted(false);
+        }
+
+        @NotNull
+        @Override
+        public Name getName() {
+            return NAME;
+        }
+    }
+}

+ 73 - 0
app/src/main/java/com/nextcloud/talk/components/filebrowser/models/properties/NCPreview.java

@@ -0,0 +1,73 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 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.nextcloud.talk.components.filebrowser.models.properties;
+
+import android.text.TextUtils;
+import at.bitfire.dav4android.Property;
+import at.bitfire.dav4android.PropertyFactory;
+import at.bitfire.dav4android.XmlUtils;
+import com.nextcloud.talk.components.filebrowser.webdav.DavUtils;
+import lombok.Getter;
+import lombok.Setter;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+public class NCPreview implements Property {
+    public static final Property.Name NAME = new Property.Name(DavUtils.NC_NAMESPACE, DavUtils.EXTENDED_PROPERTY_HAS_PREVIEW);
+
+    @Getter
+    @Setter
+    private boolean ncPreview;
+
+    private NCPreview(boolean hasPreview) {
+        ncPreview = hasPreview;
+    }
+
+    public static class Factory implements PropertyFactory {
+
+        @Nullable
+        @Override
+        public Property create(@NotNull XmlPullParser xmlPullParser) {
+            try {
+                String text = XmlUtils.INSTANCE.readText(xmlPullParser);
+                if (!TextUtils.isEmpty(text)) {
+                    return new NCPreview(Boolean.parseBoolean(text));
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            } catch (XmlPullParserException e) {
+                e.printStackTrace();
+            }
+
+            return new OCFavorite(false);
+        }
+
+        @NotNull
+        @Override
+        public Property.Name getName() {
+            return NAME;
+        }
+    }
+}

+ 73 - 0
app/src/main/java/com/nextcloud/talk/components/filebrowser/models/properties/OCFavorite.java

@@ -0,0 +1,73 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 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.nextcloud.talk.components.filebrowser.models.properties;
+
+import android.text.TextUtils;
+import at.bitfire.dav4android.Property;
+import at.bitfire.dav4android.PropertyFactory;
+import at.bitfire.dav4android.XmlUtils;
+import com.nextcloud.talk.components.filebrowser.webdav.DavUtils;
+import lombok.Getter;
+import lombok.Setter;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+public class OCFavorite implements Property {
+    public static final Property.Name NAME = new Property.Name(DavUtils.OC_NAMESPACE, DavUtils.EXTENDED_PROPERTY_FAVORITE);
+
+    @Getter
+    @Setter
+    private boolean ocFavorite;
+
+    OCFavorite(boolean isFavorite) {
+        ocFavorite = isFavorite;
+    }
+
+    public static class Factory implements PropertyFactory {
+
+        @Nullable
+        @Override
+        public Property create(@NotNull XmlPullParser xmlPullParser) {
+            try {
+                String text = XmlUtils.INSTANCE.readText(xmlPullParser);
+                if (!TextUtils.isEmpty(text)) {
+                    return new OCFavorite(Boolean.parseBoolean(text));
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            } catch (XmlPullParserException e) {
+                e.printStackTrace();
+            }
+
+            return new OCFavorite(false);
+        }
+
+        @NotNull
+        @Override
+        public Property.Name getName() {
+            return NAME;
+        }
+    }
+}

+ 73 - 0
app/src/main/java/com/nextcloud/talk/components/filebrowser/models/properties/OCId.java

@@ -0,0 +1,73 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 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.nextcloud.talk.components.filebrowser.models.properties;
+
+import android.text.TextUtils;
+import at.bitfire.dav4android.Property;
+import at.bitfire.dav4android.PropertyFactory;
+import at.bitfire.dav4android.XmlUtils;
+import com.nextcloud.talk.components.filebrowser.webdav.DavUtils;
+import lombok.Getter;
+import lombok.Setter;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+public class OCId implements Property {
+    public static final Name NAME = new Name(DavUtils.OC_NAMESPACE, DavUtils.EXTENDED_PROPERTY_NAME_REMOTE_ID);
+
+    @Getter
+    @Setter
+    private String ocId;
+
+    private OCId(String id) {
+        ocId = id;
+    }
+
+    public static class Factory implements PropertyFactory {
+
+        @Nullable
+        @Override
+        public Property create(@NotNull XmlPullParser xmlPullParser) {
+            try {
+                String text = XmlUtils.INSTANCE.readText(xmlPullParser);
+                if (!TextUtils.isEmpty(text)) {
+                    return new OCId(text);
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            } catch (XmlPullParserException e) {
+                e.printStackTrace();
+            }
+
+            return new OCId("");
+        }
+
+        @NotNull
+        @Override
+        public Name getName() {
+            return NAME;
+        }
+    }
+}

+ 73 - 0
app/src/main/java/com/nextcloud/talk/components/filebrowser/models/properties/OCSize.java

@@ -0,0 +1,73 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 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.nextcloud.talk.components.filebrowser.models.properties;
+
+import android.text.TextUtils;
+import at.bitfire.dav4android.Property;
+import at.bitfire.dav4android.PropertyFactory;
+import at.bitfire.dav4android.XmlUtils;
+import com.nextcloud.talk.components.filebrowser.webdav.DavUtils;
+import lombok.Getter;
+import lombok.Setter;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+public class OCSize implements Property {
+    public static final Property.Name NAME = new Property.Name(DavUtils.OC_NAMESPACE, DavUtils.EXTENDED_PROPERTY_NAME_SIZE);
+
+    @Getter
+    @Setter
+    private long ocSize;
+
+    private OCSize(long size) {
+        ocSize = size;
+    }
+
+    public static class Factory implements PropertyFactory {
+
+        @Nullable
+        @Override
+        public Property create(@NotNull XmlPullParser xmlPullParser) {
+            try {
+                String text = XmlUtils.INSTANCE.readText(xmlPullParser);
+                if (!TextUtils.isEmpty(text)) {
+                    return new OCSize(Long.parseLong(text));
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            } catch (XmlPullParserException e) {
+                e.printStackTrace();
+            }
+
+            return new OCSize(-1);
+        }
+
+        @NotNull
+        @Override
+        public Name getName() {
+            return NAME;
+        }
+    }
+}

+ 69 - 0
app/src/main/java/com/nextcloud/talk/components/filebrowser/operations/DavListing.java

@@ -0,0 +1,69 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 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.nextcloud.talk.components.filebrowser.operations;
+
+import androidx.annotation.Nullable;
+import com.nextcloud.talk.components.filebrowser.interfaces.ListingInterface;
+import com.nextcloud.talk.components.filebrowser.models.DavResponse;
+import com.nextcloud.talk.components.filebrowser.webdav.ReadFilesystemOperation;
+import com.nextcloud.talk.models.database.UserEntity;
+import io.reactivex.Single;
+import io.reactivex.SingleObserver;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
+import okhttp3.OkHttpClient;
+
+import java.util.concurrent.Callable;
+
+public class DavListing extends ListingAbstractClass {
+    private DavResponse davResponse = new DavResponse();
+
+    public DavListing(ListingInterface listingInterface) {
+        super(listingInterface);
+    }
+
+    @Override
+    public void getFiles(String path, UserEntity currentUser, @Nullable OkHttpClient okHttpClient) {
+        Single.fromCallable(new Callable<ReadFilesystemOperation>() {
+            @Override
+            public ReadFilesystemOperation call() {
+                return new ReadFilesystemOperation(okHttpClient, currentUser, path, 1);
+            }
+        }).subscribeOn(Schedulers.newThread())
+                .subscribe(new SingleObserver<ReadFilesystemOperation>() {
+                    @Override
+                    public void onSubscribe(Disposable d) {
+
+                    }
+
+                    @Override
+                    public void onSuccess(ReadFilesystemOperation readFilesystemOperation) {
+                        davResponse = readFilesystemOperation.readRemotePath();
+                        listingInterface.listingResult(davResponse);
+                    }
+
+                    @Override
+                    public void onError(Throwable e) {
+                        listingInterface.listingResult(davResponse);
+                    }
+                });
+    }
+}

+ 48 - 0
app/src/main/java/com/nextcloud/talk/components/filebrowser/operations/ListingAbstractClass.java

@@ -0,0 +1,48 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 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.nextcloud.talk.components.filebrowser.operations;
+
+import android.os.Handler;
+import androidx.annotation.Nullable;
+import com.nextcloud.talk.components.filebrowser.interfaces.ListingInterface;
+import com.nextcloud.talk.models.database.UserEntity;
+import okhttp3.OkHttpClient;
+
+public abstract class ListingAbstractClass {
+    Handler handler;
+    ListingInterface listingInterface;
+
+    ListingAbstractClass(ListingInterface listingInterface) {
+        handler = new Handler();
+        this.listingInterface = listingInterface;
+    }
+
+    public abstract void getFiles(String path, UserEntity currentUser, @Nullable OkHttpClient okHttpClient);
+
+    public void cancelAllJobs() {
+        handler.removeCallbacksAndMessages(null);
+    }
+
+    public void tearDown() {
+        cancelAllJobs();
+        handler = null;
+    }
+}

+ 110 - 0
app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/DavUtils.java

@@ -0,0 +1,110 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 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.nextcloud.talk.components.filebrowser.webdav;
+
+import at.bitfire.dav4android.Property;
+import at.bitfire.dav4android.PropertyFactory;
+import at.bitfire.dav4android.PropertyRegistry;
+import at.bitfire.dav4android.property.*;
+import com.nextcloud.talk.components.filebrowser.models.properties.*;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class DavUtils {
+    public static final String OC_NAMESPACE = "http://owncloud.org/ns";
+    public static final String NC_NAMESPACE = "http://nextcloud.org/ns";
+    public static final String DAV_PATH = "/remote.php/dav/files/";
+
+    public static final String EXTENDED_PROPERTY_NAME_PERMISSIONS = "permissions";
+    public static final String EXTENDED_PROPERTY_NAME_REMOTE_ID = "id";
+    public static final String EXTENDED_PROPERTY_NAME_SIZE = "size";
+    public static final String EXTENDED_PROPERTY_FAVORITE = "favorite";
+    public static final String EXTENDED_PROPERTY_IS_ENCRYPTED = "is-encrypted";
+    public static final String EXTENDED_PROPERTY_MOUNT_TYPE = "mount-type";
+    public static final String EXTENDED_PROPERTY_OWNER_ID = "owner-id";
+    public static final String EXTENDED_PROPERTY_OWNER_DISPLAY_NAME = "owner-display-name";
+    public static final String EXTENDED_PROPERTY_UNREAD_COMMENTS = "comments-unread";
+    public static final String EXTENDED_PROPERTY_HAS_PREVIEW = "has-preview";
+    public static final String EXTENDED_PROPERTY_NOTE = "note";
+    public static final String TRASHBIN_FILENAME = "trashbin-filename";
+    public static final String TRASHBIN_ORIGINAL_LOCATION = "trashbin-original-location";
+    public static final String TRASHBIN_DELETION_TIME = "trashbin-deletion-time";
+
+    public static final String PROPERTY_QUOTA_USED_BYTES = "quota-used-bytes";
+    public static final String PROPERTY_QUOTA_AVAILABLE_BYTES = "quota-available-bytes";
+
+    static Property.Name[] getAllPropSet() {
+        List<Property.Name> propSet = new ArrayList<>();
+
+        propSet.add(DisplayName.NAME);
+        propSet.add(GetContentType.NAME);
+        propSet.add(GetContentLength.NAME);
+        propSet.add(GetContentType.NAME);
+        propSet.add(GetContentLength.NAME);
+        propSet.add(GetLastModified.NAME);
+        propSet.add(CreationDate.NAME);
+        propSet.add(GetETag.NAME);
+        propSet.add(ResourceType.NAME);
+
+        propSet.add(new Property.Name(OC_NAMESPACE, EXTENDED_PROPERTY_NAME_PERMISSIONS));
+        propSet.add(OCId.NAME);
+        propSet.add(OCSize.NAME);
+        propSet.add(OCFavorite.NAME);
+        propSet.add(new Property.Name(OC_NAMESPACE, EXTENDED_PROPERTY_OWNER_ID));
+        propSet.add(new Property.Name(OC_NAMESPACE, EXTENDED_PROPERTY_OWNER_DISPLAY_NAME));
+        propSet.add(new Property.Name(OC_NAMESPACE, EXTENDED_PROPERTY_UNREAD_COMMENTS));
+
+        propSet.add(NCEncrypted.NAME);
+        propSet.add(new Property.Name(NC_NAMESPACE, EXTENDED_PROPERTY_MOUNT_TYPE));
+        propSet.add(NCPreview.NAME);
+        propSet.add(new Property.Name(NC_NAMESPACE, EXTENDED_PROPERTY_NOTE));
+
+        return propSet.toArray(new Property.Name[0]);
+    }
+
+    public static void registerCustomFactories() {
+        PropertyRegistry propertyRegistry = PropertyRegistry.INSTANCE;
+        try {
+            Field factories = propertyRegistry.getClass().getDeclaredField("factories");
+            factories.setAccessible(true);
+            Map<Property.Name, PropertyFactory> reflectionMap = (HashMap<Property.Name,
+                    PropertyFactory>) factories.get(propertyRegistry);
+
+            reflectionMap.put(OCId.NAME, new OCId.Factory());
+            reflectionMap.put(NCPreview.NAME, new NCPreview.Factory());
+            reflectionMap.put(NCEncrypted.NAME, new NCEncrypted.Factory());
+            reflectionMap.put(OCFavorite.NAME, new OCFavorite.Factory());
+            reflectionMap.put(OCSize.NAME, new OCSize.Factory());
+
+            factories.set(propertyRegistry, reflectionMap);
+        } catch (NoSuchFieldException e) {
+            e.printStackTrace();
+        } catch (IllegalAccessException e) {
+            e.printStackTrace();
+        }
+
+    }
+
+}

+ 100 - 0
app/src/main/java/com/nextcloud/talk/components/filebrowser/webdav/ReadFilesystemOperation.java

@@ -0,0 +1,100 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 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.nextcloud.talk.components.filebrowser.webdav;
+
+import at.bitfire.dav4android.DavResource;
+import at.bitfire.dav4android.Response;
+import at.bitfire.dav4android.exception.DavException;
+import com.nextcloud.talk.components.filebrowser.models.BrowserFile;
+import com.nextcloud.talk.components.filebrowser.models.DavResponse;
+import com.nextcloud.talk.dagger.modules.RestModule;
+import com.nextcloud.talk.models.database.UserEntity;
+import com.nextcloud.talk.utils.ApiUtils;
+import kotlin.Unit;
+import kotlin.jvm.functions.Function2;
+import okhttp3.HttpUrl;
+import okhttp3.OkHttpClient;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ReadFilesystemOperation {
+    private final OkHttpClient okHttpClient;
+    private final String url;
+    private final String basePath;
+    private final int depth;
+
+    public ReadFilesystemOperation(OkHttpClient okHttpClient, UserEntity currentUser, String path, int depth) {
+        OkHttpClient.Builder okHttpClientBuilder = okHttpClient.newBuilder();
+        okHttpClientBuilder.followRedirects(false);
+        okHttpClientBuilder.followSslRedirects(false);
+        okHttpClientBuilder.authenticator(new RestModule.MagicAuthenticator(ApiUtils.getCredentials(currentUser.getUsername(), currentUser.getToken()), "Authorization"));
+        this.okHttpClient = okHttpClientBuilder.build();
+        basePath = currentUser.getBaseUrl() + DavUtils.DAV_PATH + currentUser.getUserId();
+        this.url = basePath + path;
+        this.depth = depth;
+    }
+
+    public DavResponse readRemotePath() {
+        DavResponse davResponse = new DavResponse();
+        final List<Response> memberElements = new ArrayList<>();
+        final Response[] rootElement = new Response[1];
+        final List<BrowserFile> remoteFiles = new ArrayList<>();
+
+        try {
+            new DavResource(okHttpClient, HttpUrl.parse(url)).propfind(depth, DavUtils.getAllPropSet(),
+                    new Function2<Response, Response.HrefRelation, Unit>() {
+                        @Override
+                        public Unit invoke(Response response, Response.HrefRelation hrefRelation) {
+                            davResponse.setResponse(response);
+                            switch (hrefRelation) {
+                                case MEMBER:
+                                    memberElements.add(response);
+                                    break;
+                                case SELF:
+                                    rootElement[0] = response;
+                                    break;
+                                case OTHER:
+                                default:
+                            }
+                            return Unit.INSTANCE;
+                        }
+                    });
+        } catch (IOException e) {
+            e.printStackTrace();
+        } catch (DavException e) {
+            e.printStackTrace();
+        }
+
+
+        remoteFiles.add(BrowserFile.getModelFromResponse(rootElement[0],
+                rootElement[0].getHref().toString().substring(basePath.length())));
+        for (Response memberElement : memberElements) {
+            remoteFiles.add(BrowserFile.getModelFromResponse(memberElement,
+                    memberElement.getHref().toString().substring(basePath.length())));
+        }
+
+        davResponse.setData(remoteFiles);
+        return davResponse;
+    }
+
+}

+ 29 - 33
app/src/main/java/com/nextcloud/talk/controllers/CallController.java

@@ -44,9 +44,9 @@ import butterknife.BindView;
 import butterknife.OnClick;
 import butterknife.OnLongClick;
 import com.bluelinelabs.logansquare.LoganSquare;
-import com.bumptech.glide.load.engine.DiskCacheStrategy;
-import com.bumptech.glide.load.resource.bitmap.CircleCrop;
-import com.bumptech.glide.request.RequestOptions;
+import com.facebook.drawee.backends.pipeline.Fresco;
+import com.facebook.drawee.interfaces.DraweeController;
+import com.facebook.drawee.view.SimpleDraweeView;
 import com.nextcloud.talk.R;
 import com.nextcloud.talk.api.NcApi;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
@@ -65,18 +65,16 @@ import com.nextcloud.talk.models.json.signaling.*;
 import com.nextcloud.talk.models.json.signaling.settings.IceServer;
 import com.nextcloud.talk.models.json.signaling.settings.SignalingSettingsOverall;
 import com.nextcloud.talk.utils.ApiUtils;
-import com.nextcloud.talk.utils.MagicFlipView;
+import com.nextcloud.talk.utils.DisplayUtils;
 import com.nextcloud.talk.utils.NotificationUtils;
 import com.nextcloud.talk.utils.animations.PulseAnimation;
 import com.nextcloud.talk.utils.bundle.BundleKeys;
 import com.nextcloud.talk.utils.database.user.UserUtils;
-import com.nextcloud.talk.utils.glide.GlideApp;
 import com.nextcloud.talk.utils.power.PowerManagerUtils;
 import com.nextcloud.talk.utils.preferences.AppPreferences;
 import com.nextcloud.talk.utils.singletons.ApplicationWideCurrentRoomHolder;
 import com.nextcloud.talk.webrtc.*;
 import com.wooplr.spotlight.SpotlightView;
-import eu.davidea.flipview.FlipView;
 import io.reactivex.Observable;
 import io.reactivex.Observer;
 import io.reactivex.android.schedulers.AndroidSchedulers;
@@ -117,7 +115,7 @@ public class CallController extends BaseController {
     };
 
     @BindView(R.id.callControlEnableSpeaker)
-    MagicFlipView callControlEnableSpeaker;
+    SimpleDraweeView callControlEnableSpeaker;
 
     @BindView(R.id.pip_video_view)
     SurfaceViewRenderer pipVideoView;
@@ -129,11 +127,11 @@ public class CallController extends BaseController {
     @BindView(R.id.callControlsRelativeLayout)
     RelativeLayout callControls;
     @BindView(R.id.call_control_microphone)
-    FlipView microphoneControlButton;
+    SimpleDraweeView microphoneControlButton;
     @BindView(R.id.call_control_camera)
-    FlipView cameraControlButton;
+    SimpleDraweeView cameraControlButton;
     @BindView(R.id.call_control_switch_camera)
-    FlipView cameraSwitchButton;
+    SimpleDraweeView cameraSwitchButton;
     @BindView(R.id.connectingTextView)
     TextView connectingTextView;
 
@@ -260,7 +258,7 @@ public class CallController extends BaseController {
         microphoneControlButton.setOnTouchListener(new MicrophoneButtonTouchListener());
         videoOnClickListener = new VideoClickListener();
 
-        pulseAnimation = PulseAnimation.create().with(microphoneControlButton.getFrontImageView())
+        pulseAnimation = PulseAnimation.create().with(microphoneControlButton)
                 .setDuration(310)
                 .setRepeatCount(PulseAnimation.INFINITE)
                 .setRepeatMode(PulseAnimation.REVERSE);
@@ -454,7 +452,7 @@ public class CallController extends BaseController {
                     onCameraClick();
                 }
             } else {
-                cameraControlButton.getFrontImageView().setImageResource(R.drawable.ic_videocam_off_white_24px);
+                cameraControlButton.setImageResource(R.drawable.ic_videocam_off_white_24px);
                 cameraControlButton.setAlpha(0.7f);
                 cameraSwitchButton.setVisibility(View.GONE);
             }
@@ -465,7 +463,7 @@ public class CallController extends BaseController {
                 onMicrophoneClick();
             }
         } else {
-            microphoneControlButton.getFrontImageView().setImageResource(R.drawable.ic_mic_off_white_24px);
+            microphoneControlButton.setImageResource(R.drawable.ic_mic_off_white_24px);
         }
 
         if (!inCall) {
@@ -584,7 +582,7 @@ public class CallController extends BaseController {
     public void onEnableSpeakerphoneClick() {
         if (audioManager != null) {
             audioManager.toggleUseSpeakerphone();
-            callControlEnableSpeaker.flipSilently(!callControlEnableSpeaker.isFlipped());
+            //callControlEnableSpeaker.flipSilently(!callControlEnableSpeaker.isFlipped());
         }
     }
 
@@ -620,14 +618,14 @@ public class CallController extends BaseController {
                 audioOn = !audioOn;
 
                 if (audioOn) {
-                    microphoneControlButton.getFrontImageView().setImageResource(R.drawable.ic_mic_white_24px);
+                    microphoneControlButton.setActualImageResource(R.drawable.ic_mic_white_24px);
                 } else {
-                    microphoneControlButton.getFrontImageView().setImageResource(R.drawable.ic_mic_off_white_24px);
+                    microphoneControlButton.setActualImageResource(R.drawable.ic_mic_off_white_24px);
                 }
 
                 toggleMedia(audioOn, false);
             } else {
-                microphoneControlButton.getFrontImageView().setImageResource(R.drawable.ic_mic_white_24px);
+                microphoneControlButton.setActualImageResource(R.drawable.ic_mic_white_24px);
                 pulseAnimation.start();
                 toggleMedia(true, false);
             }
@@ -663,12 +661,12 @@ public class CallController extends BaseController {
             videoOn = !videoOn;
 
             if (videoOn) {
-                cameraControlButton.getFrontImageView().setImageResource(R.drawable.ic_videocam_white_24px);
+                cameraControlButton.setActualImageResource(R.drawable.ic_videocam_white_24px);
                 if (cameraEnumerator.getDeviceNames().length > 1) {
                     cameraSwitchButton.setVisibility(View.VISIBLE);
                 }
             } else {
-                cameraControlButton.getFrontImageView().setImageResource(R.drawable.ic_videocam_off_white_24px);
+                cameraControlButton.setActualImageResource(R.drawable.ic_videocam_off_white_24px);
                 cameraSwitchButton.setVisibility(View.GONE);
             }
 
@@ -1792,21 +1790,19 @@ public class CallController extends BaseController {
         if (remoteRenderersLayout != null) {
             RelativeLayout relativeLayout = remoteRenderersLayout.findViewWithTag(session + "+video");
             if (relativeLayout != null) {
-                ImageView avatarImageView = relativeLayout.findViewById(R.id.avatarImageView);
+                SimpleDraweeView avatarImageView = relativeLayout.findViewById(R.id.avatarImageView);
 
                 if (participantMap.containsKey(session) && avatarImageView.getDrawable() == null) {
 
-                    int size = Math.round(getResources().getDimension(R.dimen.avatar_size_big));
-
                     if (getActivity() != null) {
-                        GlideApp.with(getActivity())
-                                .asBitmap()
-                                .diskCacheStrategy(DiskCacheStrategy.NONE)
-                                .load(ApiUtils.getUrlForAvatarWithName(baseUrl, participantMap.get(session).getUserId(), R.dimen.avatar_size_big))
-                                .centerInside()
-                                .override(size, size)
-                                .apply(RequestOptions.bitmapTransform(new CircleCrop()))
-                                .into(avatarImageView);
+                        DraweeController draweeController = Fresco.newDraweeControllerBuilder()
+                                .setOldController(avatarImageView.getController())
+                                .setAutoPlayAnimations(true)
+                                .setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(baseUrl,
+                                        participantMap.get(session).getUserId(),
+                                        R.dimen.avatar_size_big), null))
+                                .build();
+                        avatarImageView.setController(draweeController);
                     }
                 }
             }
@@ -1822,7 +1818,7 @@ public class CallController extends BaseController {
 
         RelativeLayout relativeLayout = remoteRenderersLayout.findViewWithTag(session + "+" + videoStreamType);
         SurfaceViewRenderer surfaceViewRenderer = relativeLayout.findViewById(R.id.surface_view);
-        ImageView imageView = relativeLayout.findViewById(R.id.avatarImageView);
+        SimpleDraweeView imageView = relativeLayout.findViewById(R.id.avatarImageView);
 
         if (mediaStream != null && mediaStream.videoTracks != null && mediaStream.videoTracks.size() > 0 && enable) {
             VideoTrack videoTrack = mediaStream.videoTracks.get(0);
@@ -1847,7 +1843,7 @@ public class CallController extends BaseController {
         RelativeLayout relativeLayout = remoteRenderersLayout.findViewWithTag(sessionId);
         if (relativeLayout != null) {
             ImageView imageView;
-            ImageView avatarImageView = relativeLayout.findViewById(R.id.avatarImageView);
+            SimpleDraweeView avatarImageView = relativeLayout.findViewById(R.id.avatarImageView);
             SurfaceViewRenderer surfaceViewRenderer = relativeLayout.findViewById(R.id.surface_view);
 
             if (video) {
@@ -1942,7 +1938,7 @@ public class CallController extends BaseController {
             v.onTouchEvent(event);
             if (event.getAction() == MotionEvent.ACTION_UP && isPTTActive) {
                 isPTTActive = false;
-                microphoneControlButton.getFrontImageView().setImageResource(R.drawable.ic_mic_off_white_24px);
+                microphoneControlButton.setActualImageResource(R.drawable.ic_mic_off_white_24px);
                 pulseAnimation.stop();
                 toggleMedia(false, false);
                 animateCallControls(false, 5000);

+ 56 - 92
app/src/main/java/com/nextcloud/talk/controllers/CallNotificationController.java

@@ -30,10 +30,7 @@ import android.media.AudioAttributes;
 import android.media.MediaPlayer;
 import android.net.Uri;
 import android.os.*;
-import android.renderscript.Allocation;
-import android.renderscript.Element;
 import android.renderscript.RenderScript;
-import android.renderscript.ScriptIntrinsicBlur;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.LayoutInflater;
@@ -50,14 +47,16 @@ import butterknife.OnClick;
 import com.bluelinelabs.conductor.RouterTransaction;
 import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
 import com.bluelinelabs.logansquare.LoganSquare;
-import com.bumptech.glide.load.engine.DiskCacheStrategy;
-import com.bumptech.glide.load.model.GlideUrl;
-import com.bumptech.glide.load.model.LazyHeaders;
-import com.bumptech.glide.load.resource.bitmap.CircleCrop;
-import com.bumptech.glide.load.resource.bitmap.TransformationUtils;
-import com.bumptech.glide.request.RequestOptions;
-import com.bumptech.glide.request.target.SimpleTarget;
-import com.bumptech.glide.request.transition.Transition;
+import com.facebook.common.executors.UiThreadImmediateExecutorService;
+import com.facebook.common.references.CloseableReference;
+import com.facebook.datasource.DataSource;
+import com.facebook.drawee.backends.pipeline.Fresco;
+import com.facebook.drawee.view.SimpleDraweeView;
+import com.facebook.imagepipeline.core.ImagePipeline;
+import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber;
+import com.facebook.imagepipeline.image.CloseableImage;
+import com.facebook.imagepipeline.postprocessors.BlurPostProcessor;
+import com.facebook.imagepipeline.request.ImageRequest;
 import com.nextcloud.talk.R;
 import com.nextcloud.talk.api.NcApi;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
@@ -70,10 +69,9 @@ import com.nextcloud.talk.models.json.participants.ParticipantsOverall;
 import com.nextcloud.talk.models.json.rooms.Conversation;
 import com.nextcloud.talk.models.json.rooms.RoomsOverall;
 import com.nextcloud.talk.utils.ApiUtils;
+import com.nextcloud.talk.utils.DisplayUtils;
 import com.nextcloud.talk.utils.DoNotDisturbUtils;
-import com.nextcloud.talk.utils.MagicFlipView;
 import com.nextcloud.talk.utils.bundle.BundleKeys;
-import com.nextcloud.talk.utils.glide.GlideApp;
 import com.nextcloud.talk.utils.preferences.AppPreferences;
 import com.nextcloud.talk.utils.singletons.AvatarStatusCodeHolder;
 import io.reactivex.Observer;
@@ -87,6 +85,7 @@ import org.greenrobot.eventbus.ThreadMode;
 import org.michaelevans.colorart.library.ColorArt;
 import org.parceler.Parcels;
 
+import javax.annotation.Nullable;
 import javax.inject.Inject;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -113,13 +112,13 @@ public class CallNotificationController extends BaseController {
     TextView conversationNameTextView;
 
     @BindView(R.id.avatarImageView)
-    ImageView avatarImageView;
+    SimpleDraweeView avatarImageView;
 
     @BindView(R.id.callAnswerVoiceOnlyView)
-    MagicFlipView callAnswerVoiceOnlyView;
+    SimpleDraweeView callAnswerVoiceOnlyView;
 
     @BindView(R.id.callAnswerCameraView)
-    MagicFlipView callAnswerCameraView;
+    SimpleDraweeView callAnswerCameraView;
 
     @BindView(R.id.backgroundImageView)
     ImageView backgroundImageView;
@@ -148,7 +147,6 @@ public class CallNotificationController extends BaseController {
         this.userBeingCalled = args.getParcelable(BundleKeys.KEY_USER_ENTITY);
 
         this.originalBundle = args;
-
         credentials = ApiUtils.getCredentials(userBeingCalled.getUsername(), userBeingCalled.getToken());
     }
 
@@ -384,7 +382,6 @@ public class CallNotificationController extends BaseController {
 
         layoutParams.width = dimen;
         layoutParams.height = dimen;
-
         avatarImageView.setLayoutParams(layoutParams);
     }
 
@@ -402,92 +399,59 @@ public class CallNotificationController extends BaseController {
     }
 
     private void loadAvatar() {
-        int avatarSize = Math.round(NextcloudTalkApplication
-                .getSharedApplication().getResources().getDimension(R.dimen.avatar_fetching_size_very_big));
-
         switch (currentConversation.getType()) {
             case ROOM_TYPE_ONE_TO_ONE_CALL:
                 avatarImageView.setVisibility(View.VISIBLE);
 
-                GlideUrl glideUrl = new GlideUrl(ApiUtils.getUrlForAvatarWithName(userBeingCalled.getBaseUrl(),
-                        currentConversation.getName(), R.dimen.avatar_size_very_big), new LazyHeaders.Builder()
-                        .setHeader("Accept", "image/*")
-                        .setHeader("User-Agent", ApiUtils.getUserAgent())
-                        .build());
-
-                GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext())
-                        .asBitmap()
-                        .diskCacheStrategy(DiskCacheStrategy.NONE)
-                        .load(glideUrl)
-                        .centerInside()
-                        .override(avatarSize, avatarSize)
-                        .into(new SimpleTarget<Bitmap>() {
-                            @Override
-                            public void onResourceReady(Bitmap resource, Transition<? super Bitmap> transition) {
-                                if (getActivity() != null && avatarImageView != null) {
-                                    avatarImageView.setImageBitmap(TransformationUtils.circleCrop(GlideApp.get
-                                            (getActivity()).getBitmapPool(), resource, avatarSize, avatarSize));
-                                }
+                ImageRequest imageRequest =
+                        DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(userBeingCalled.getBaseUrl(),
+                                currentConversation.getName(), R.dimen.avatar_size_very_big), null);
 
-                                if (getResources() != null && incomingTextRelativeLayout != null) {
-                                    incomingTextRelativeLayout.setBackground(getResources().getDrawable(R.drawable
-                                            .incoming_gradient));
-                                }
+                ImagePipeline imagePipeline = Fresco.getImagePipeline();
+                DataSource<CloseableReference<CloseableImage>> dataSource = imagePipeline.fetchDecodedImage(imageRequest, null);
 
-                                if (AvatarStatusCodeHolder.getInstance().getStatusCode() == 200 &&
-                                        userBeingCalled.hasSpreedCapabilityWithName("no-ping")) {
-                                    final Allocation input = Allocation.createFromBitmap(renderScript, resource);
-                                    final Allocation output = Allocation.createTyped(renderScript, input.getType());
-                                    final ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(renderScript, Element
-                                            .U8_4(renderScript));
-                                    script.setRadius(15f);
-                                    script.setInput(input);
-                                    script.forEach(output);
-                                    output.copyTo(resource);
-
-                                    if (backgroundImageView != null) {
-                                        backgroundImageView.setImageDrawable(new BitmapDrawable(resource));
-                                    }
-                                } else if (AvatarStatusCodeHolder.getInstance().getStatusCode() == 201) {
-                                    ColorArt colorArt = new ColorArt(resource);
-                                    int color = colorArt.getBackgroundColor();
-
-                                    float[] hsv = new float[3];
-                                    Color.colorToHSV(color, hsv);
-                                    hsv[2] *= 0.75f;
-                                    color = Color.HSVToColor(hsv);
-
-                                    if (backgroundImageView != null) {
-                                        backgroundImageView.setImageDrawable(new ColorDrawable(color));
-                                    }
-                                }
+                dataSource.subscribe(new BaseBitmapDataSubscriber() {
+                    @Override
+                    protected void onNewResultImpl(@Nullable Bitmap bitmap) {
+                        avatarImageView.getHierarchy().setImage(new BitmapDrawable(bitmap), 100,
+                                true);
+
+                        if (getResources() != null) {
+                            incomingTextRelativeLayout.setBackground(getResources().getDrawable(R.drawable
+                                    .incoming_gradient));
+                        }
+
+                        if (AvatarStatusCodeHolder.getInstance().getStatusCode() == 200 &&
+                                userBeingCalled.hasSpreedCapabilityWithName("no-ping")) {
+                            if (getActivity() != null) {
+                                Bitmap backgroundBitmap = bitmap.copy(bitmap.getConfig(), true);
+                                new BlurPostProcessor(5, getActivity()).process(backgroundBitmap);
+                                backgroundImageView.setImageDrawable(new BitmapDrawable(backgroundBitmap));
                             }
-                        });
+                        } else if (AvatarStatusCodeHolder.getInstance().getStatusCode() == 201) {
+                            ColorArt colorArt = new ColorArt(bitmap);
+                            int color = colorArt.getBackgroundColor();
+
+                            float[] hsv = new float[3];
+                            Color.colorToHSV(color, hsv);
+                            hsv[2] *= 0.75f;
+                            color = Color.HSVToColor(hsv);
+
+                            backgroundImageView.setImageDrawable(new ColorDrawable(color));
+                        }
+                    }
 
+                    @Override
+                    protected void onFailureImpl(DataSource<CloseableReference<CloseableImage>> dataSource) {
+
+                    }
+                }, UiThreadImmediateExecutorService.getInstance());
 
                 break;
             case ROOM_GROUP_CALL:
-                if (avatarImageView != null) {
-                    GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext())
-                            .asBitmap()
-                            .diskCacheStrategy(DiskCacheStrategy.NONE)
-                            .load(R.drawable.ic_people_group_white_24px)
-                            .centerInside()
-                            .override(avatarSize, avatarSize)
-                            .apply(RequestOptions.bitmapTransform(new CircleCrop()))
-                            .into(avatarImageView);
-                }
+                avatarImageView.setActualImageResource(R.drawable.ic_people_group_white_24px);
             case ROOM_PUBLIC_CALL:
-                if (avatarImageView != null) {
-                    GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext())
-                            .asBitmap()
-                            .diskCacheStrategy(DiskCacheStrategy.NONE)
-                            .load(R.drawable.ic_link_white_24px)
-                            .centerInside()
-                            .override(avatarSize, avatarSize)
-                            .apply(RequestOptions.bitmapTransform(new CircleCrop()))
-                            .into(avatarImageView);
-                }
+                avatarImageView.setActualImageResource(R.drawable.ic_link_white_24px);
                 break;
             default:
         }

+ 25 - 7
app/src/main/java/com/nextcloud/talk/controllers/ChatController.java

@@ -46,6 +46,7 @@ import butterknife.BindView;
 import butterknife.OnClick;
 import com.bluelinelabs.conductor.RouterTransaction;
 import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
+import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler;
 import com.facebook.drawee.backends.pipeline.Fresco;
 import com.facebook.drawee.interfaces.DraweeController;
 import com.facebook.drawee.view.SimpleDraweeView;
@@ -58,6 +59,7 @@ import com.nextcloud.talk.adapters.messages.MagicSystemMessageViewHolder;
 import com.nextcloud.talk.api.NcApi;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
 import com.nextcloud.talk.callbacks.MentionAutocompleteCallback;
+import com.nextcloud.talk.components.filebrowser.controllers.BrowserController;
 import com.nextcloud.talk.controllers.base.BaseController;
 import com.nextcloud.talk.events.UserMentionClickEvent;
 import com.nextcloud.talk.models.RetrofitBucket;
@@ -318,7 +320,7 @@ public class ChatController extends BaseController implements MessagesListAdapte
                 @Override
                 public void loadImage(SimpleDraweeView imageView, String url) {
                     DraweeController draweeController = Fresco.newDraweeControllerBuilder()
-                            .setImageRequest(DisplayUtils.getImageRequestForUrl(url))
+                            .setImageRequest(DisplayUtils.getImageRequestForUrl(url, conversationUser))
                             .setControllerListener(DisplayUtils.getImageControllerListener(imageView))
                             .setOldController(imageView.getController())
                             .setAutoPlayAnimations(true)
@@ -415,6 +417,13 @@ public class ChatController extends BaseController implements MessagesListAdapte
             }
         });
 
+        messageInputView.setAttachmentsListener(new MessageInput.AttachmentsListener() {
+            @Override
+            public void onAddAttachments() {
+                showBrowserScreen(BrowserController.BrowserType.DAV_BROWSER);
+            }
+        });
+
         messageInputView.getButton().setOnClickListener(v -> submitMessage());
         messageInputView.getButton().setContentDescription(getResources()
                 .getString(R.string.nc_description_send_message_button));
@@ -479,6 +488,16 @@ public class ChatController extends BaseController implements MessagesListAdapte
     }
 
 
+    private void showBrowserScreen(BrowserController.BrowserType browserType) {
+        Bundle bundle = new Bundle();
+        bundle.putParcelable(BundleKeys.KEY_BROWSER_TYPE, Parcels.wrap(browserType));
+        bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, Parcels.wrap(conversationUser));
+        bundle.putString(BundleKeys.KEY_ROOM_TOKEN, roomToken);
+        getRouter().pushController((RouterTransaction.with(new BrowserController(bundle))
+                .pushChangeHandler(new VerticalChangeHandler())
+                .popChangeHandler(new VerticalChangeHandler())));
+    }
+
     private void showConversationInfoScreen() {
         Bundle bundle = new Bundle();
         bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, conversationUser);
@@ -486,7 +505,6 @@ public class ChatController extends BaseController implements MessagesListAdapte
         getRouter().pushController((RouterTransaction.with(new ConversationInfoController(bundle))
                 .pushChangeHandler(new HorizontalChangeHandler())
                 .popChangeHandler(new HorizontalChangeHandler())));
-
     }
 
     private void setupMentionAutocomplete() {
@@ -532,7 +550,8 @@ public class ChatController extends BaseController implements MessagesListAdapte
             @Override
             public void onEmojiPopupDismiss() {
                 if (smileyButton != null) {
-                    smileyButton.clearColorFilter();
+                    smileyButton.setColorFilter(getResources().getColor(R.color.emoji_icons),
+                            PorterDuff.Mode.SRC_IN);
                 }
             }
         }).setOnEmojiClickListener(new OnEmojiClickListener() {
@@ -950,8 +969,8 @@ public class ChatController extends BaseController implements MessagesListAdapte
 
                     ChatMessage chatMessage = chatMessageList.get(i);
                     chatMessage.setLinkPreviewAllowed(isLinkPreviewAllowed);
-                    chatMessage.setBaseUrl(conversationUser.getBaseUrl());
-                    chatMessage.setActiveUserId(conversationUser.getUserId());
+                    chatMessage.setActiveUser(conversationUser);
+
                     if (globalLastKnownPastMessageId == -1 || chatMessageList.get(i).getJsonMessageId() <
                             globalLastKnownPastMessageId) {
                         globalLastKnownPastMessageId = chatMessageList.get(i).getJsonMessageId();
@@ -975,8 +994,7 @@ public class ChatController extends BaseController implements MessagesListAdapte
                 for (int i = 0; i < chatMessageList.size(); i++) {
                     chatMessage = chatMessageList.get(i);
 
-                    chatMessage.setBaseUrl(conversationUser.getBaseUrl());
-                    chatMessage.setActiveUserId(conversationUser.getUserId());
+                    chatMessage.setActiveUser(conversationUser);
                     chatMessage.setLinkPreviewAllowed(isLinkPreviewAllowed);
 
                     // if credentials are empty, we're acting as a guest

+ 5 - 10
app/src/main/java/com/nextcloud/talk/controllers/ContactsController.java

@@ -80,7 +80,6 @@ import eu.davidea.flexibleadapter.SelectableAdapter;
 import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager;
 import eu.davidea.flexibleadapter.items.AbstractFlexibleItem;
 import eu.davidea.flexibleadapter.items.IFlexible;
-import eu.davidea.flipview.FlipView;
 import io.reactivex.Observer;
 import io.reactivex.android.schedulers.AndroidSchedulers;
 import io.reactivex.disposables.Disposable;
@@ -190,7 +189,6 @@ public class ContactsController extends BaseController implements SearchView.OnQ
         if (isNewConversationView) {
             toggleNewCallHeaderVisibility(!isPublicCall);
         }
-
     }
 
     @Override
@@ -198,9 +196,6 @@ public class ContactsController extends BaseController implements SearchView.OnQ
         super.onViewBound(view);
         NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
 
-        FlipView.resetLayoutAnimationDelay(true, 1000L);
-        FlipView.stopLayoutAnimation();
-
         currentUser = userUtils.getCurrentUser();
 
         if (currentUser != null) {
@@ -208,7 +203,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ
         }
 
         if (adapter == null) {
-            adapter = new FlexibleAdapter<>(contactItems, getActivity(), false);
+            adapter = new FlexibleAdapter<>(contactItems, getActivity(), true);
 
             if (currentUser != null) {
                 fetchData(true);
@@ -598,6 +593,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ
                             });
 
 
+                            adapter.clearSelection();
                             if (!shouldFilterManually) {
                                 adapter.updateDataSet(newUserItemList, false);
                             } else {
@@ -660,7 +656,7 @@ public class ContactsController extends BaseController implements SearchView.OnQ
 
     private void prepareViews() {
         layoutManager = new SmoothScrollLinearLayoutManager(getActivity());
-        recyclerView.setLayoutManager(new SmoothScrollLinearLayoutManager(getActivity()));
+        recyclerView.setLayoutManager(layoutManager);
         recyclerView.setHasFixedSize(true);
         recyclerView.setAdapter(adapter);
 
@@ -911,7 +907,6 @@ public class ContactsController extends BaseController implements SearchView.OnQ
                             }
                         });
             } else {
-                ((UserItem) adapter.getItem(position)).flipItemSelection();
                 adapter.toggleSelection(position);
 
                 if (currentUser.hasSpreedCapabilityWithName("last-room-activity")
@@ -921,13 +916,14 @@ public class ContactsController extends BaseController implements SearchView.OnQ
                     List<Integer> selectedPositions = adapter.getSelectedPositions();
                     for (int i = 0; i < selectedPositions.size(); i++) {
                         if (!selectedPositions.get(i).equals(position) && "groups".equals(((UserItem) adapter.getItem(selectedPositions.get(i))).getModel().getSource())) {
-                            ((UserItem) adapter.getItem(selectedPositions.get(i))).flipItemSelection();
                             adapter.toggleSelection(selectedPositions.get(i));
                         }
                     }
 
                 }
 
+                adapter.notifyDataSetChanged();
+
                 checkAndHandleDoneMenuItem();
             }
         }
@@ -955,7 +951,6 @@ public class ContactsController extends BaseController implements SearchView.OnQ
                 if (adapter.getItem(selectedPosition) instanceof UserItem) {
                     UserItem userItem = (UserItem) adapter.getItem(selectedPosition);
                     if ("groups".equals(userItem.getModel().getSource())) {
-                        ((UserItem) adapter.getItem(selectedPosition)).flipItemSelection();
                         adapter.toggleSelection(selectedPosition);
                     }
                 }

+ 1 - 1
app/src/main/java/com/nextcloud/talk/controllers/ConversationInfoController.java

@@ -473,7 +473,7 @@ public class ConversationInfoController extends BaseController {
                                 .setOldController(conversationAvatarImageView.getController())
                                 .setAutoPlayAnimations(true)
                                 .setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(conversationUser.getBaseUrl(),
-                                        conversation.getName(), R.dimen.avatar_size_big)))
+                                        conversation.getName(), R.dimen.avatar_size_big), null))
                                 .build();
                         conversationAvatarImageView.setController(draweeController);
                     }

+ 28 - 36
app/src/main/java/com/nextcloud/talk/controllers/ConversationsListController.java

@@ -38,7 +38,6 @@ import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.appcompat.widget.SearchView;
 import androidx.core.view.MenuItemCompat;
-import androidx.recyclerview.widget.DividerItemDecoration;
 import androidx.recyclerview.widget.RecyclerView;
 import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
 import androidx.work.Data;
@@ -51,12 +50,15 @@ import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
 import com.bluelinelabs.conductor.changehandler.TransitionChangeHandlerCompat;
 import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler;
 import com.bluelinelabs.conductor.internal.NoOpControllerChangeHandler;
-import com.bumptech.glide.load.model.GlideUrl;
-import com.bumptech.glide.load.model.LazyHeaders;
-import com.bumptech.glide.load.resource.bitmap.CircleCrop;
-import com.bumptech.glide.request.RequestOptions;
-import com.bumptech.glide.request.target.SimpleTarget;
-import com.bumptech.glide.request.transition.Transition;
+import com.facebook.common.executors.UiThreadImmediateExecutorService;
+import com.facebook.common.references.CloseableReference;
+import com.facebook.datasource.DataSource;
+import com.facebook.drawee.backends.pipeline.Fresco;
+import com.facebook.imagepipeline.core.ImagePipeline;
+import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber;
+import com.facebook.imagepipeline.image.CloseableImage;
+import com.facebook.imagepipeline.postprocessors.RoundPostprocessor;
+import com.facebook.imagepipeline.request.ImageRequest;
 import com.google.android.material.floatingactionbutton.FloatingActionButton;
 import com.kennyc.bottomsheet.BottomSheet;
 import com.nextcloud.talk.R;
@@ -82,7 +84,6 @@ import com.nextcloud.talk.utils.KeyboardUtils;
 import com.nextcloud.talk.utils.animations.SharedElementTransition;
 import com.nextcloud.talk.utils.bundle.BundleKeys;
 import com.nextcloud.talk.utils.database.user.UserUtils;
-import com.nextcloud.talk.utils.glide.GlideApp;
 import com.nextcloud.talk.utils.preferences.AppPreferences;
 import com.yarolegovich.lovelydialog.LovelySaveStateHandler;
 import com.yarolegovich.lovelydialog.LovelyStandardDialog;
@@ -111,10 +112,8 @@ public class ConversationsListController extends BaseController implements Searc
                 .OnScrollStateChangeListener, ConversationMenuInterface {
 
     public static final String TAG = "ConversationsListController";
-
-    private static final String KEY_SEARCH_QUERY = "ContactsController.searchQuery";
     public static final int ID_DELETE_CONVERSATION_DIALOG = 0;
-
+    private static final String KEY_SEARCH_QUERY = "ContactsController.searchQuery";
     @Inject
     UserUtils userUtils;
 
@@ -207,27 +206,25 @@ public class ConversationsListController extends BaseController implements Searc
     private void loadUserAvatar(MenuItem menuItem) {
         if (getActivity() != null) {
             int avatarSize = (int) DisplayUtils.convertDpToPixel(menuItem.getIcon().getIntrinsicHeight(), getActivity());
+            ImageRequest imageRequest = DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithNameAndPixels(currentUser.getBaseUrl(),
+                    currentUser.getUserId(), avatarSize), null);
+
+            ImagePipeline imagePipeline = Fresco.getImagePipeline();
+            DataSource<CloseableReference<CloseableImage>> dataSource = imagePipeline.fetchDecodedImage(imageRequest, null);
+            dataSource.subscribe(new BaseBitmapDataSubscriber() {
+                @Override
+                protected void onNewResultImpl(Bitmap bitmap) {
+                    if (bitmap != null) {
+                        new RoundPostprocessor(true).process(bitmap);
+                        menuItem.setIcon(new BitmapDrawable(bitmap));
+                    }
+                }
 
-            if (currentUser != null) {
-                GlideUrl glideUrl = new GlideUrl(ApiUtils.getUrlForAvatarWithNameAndPixels(currentUser.getBaseUrl(),
-                        currentUser.getUserId(), avatarSize), new LazyHeaders.Builder()
-                        .setHeader("Accept", "image/*")
-                        .setHeader("User-Agent", ApiUtils.getUserAgent())
-                        .build());
-
-                GlideApp.with(getActivity())
-                        .asBitmap()
-                        .centerInside()
-                        .override(avatarSize, avatarSize)
-                        .apply(RequestOptions.bitmapTransform(new CircleCrop()))
-                        .load(glideUrl)
-                        .into(new SimpleTarget<Bitmap>() {
-                            @Override
-                            public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
-                                menuItem.setIcon(new BitmapDrawable(resource));
-                            }
-                        });
-            }
+                @Override
+                protected void onFailureImpl(DataSource<CloseableReference<CloseableImage>> dataSource) {
+                    menuItem.setIcon(R.drawable.ic_settings_white_24dp);
+                }
+            }, UiThreadImmediateExecutorService.getInstance());
         }
     }
 
@@ -434,11 +431,6 @@ public class ConversationsListController extends BaseController implements Searc
 
         recyclerView.setAdapter(adapter);
 
-        recyclerView.addItemDecoration(new DividerItemDecoration(
-                recyclerView.getContext(),
-                layoutManager.getOrientation()
-        ));
-
         swipeRefreshLayout.setOnRefreshListener(() -> fetchData(false));
         swipeRefreshLayout.setColorSchemeResources(R.color.colorPrimary);
 

+ 1 - 1
app/src/main/java/com/nextcloud/talk/controllers/LockedController.java

@@ -154,7 +154,7 @@ public class LockedController extends BaseController {
     public void onActivityResult(int requestCode, int resultCode, Intent data) {
         super.onActivityResult(requestCode, resultCode, data);
 
-        if (requestCode == REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS ) {
+        if (requestCode == REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS) {
             if (resultCode == Activity.RESULT_OK) {
                 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                     if (SecurityUtils.checkIfWeAreAuthenticated(appPreferences.getScreenLockTimeout())) {

+ 66 - 58
app/src/main/java/com/nextcloud/talk/controllers/RingtoneSelectionController.java

@@ -21,6 +21,7 @@
 package com.nextcloud.talk.controllers;
 
 import android.annotation.SuppressLint;
+import android.content.Context;
 import android.database.Cursor;
 import android.media.MediaPlayer;
 import android.media.RingtoneManager;
@@ -70,10 +71,14 @@ public class RingtoneSelectionController extends BaseController implements Flexi
     @Inject
     AppPreferences appPreferences;
 
+    @Inject
+    Context context;
+
     private FlexibleAdapter adapter;
+    private RecyclerView.AdapterDataObserver adapterDataObserver;
     private List<AbstractFlexibleItem> abstractFlexibleItemList = new ArrayList<>();
 
-    private boolean callNotificationSounds = false;
+    private boolean callNotificationSounds;
     private MediaPlayer mediaPlayer;
     private Handler cancelMediaPlayerHandler;
 
@@ -100,21 +105,20 @@ public class RingtoneSelectionController extends BaseController implements Flexi
                     .setMode(SelectableAdapter.Mode.SINGLE);
 
             adapter.addListener(this);
-            fetchNotificationSounds();
 
             cancelMediaPlayerHandler = new Handler();
         }
 
         adapter.addListener(this);
         prepareViews();
+        fetchNotificationSounds();
     }
 
     @Override
     public boolean onOptionsItemSelected(@NonNull MenuItem item) {
         switch (item.getItemId()) {
             case android.R.id.home:
-                getRouter().popCurrentController();
-                return true;
+                return getRouter().popCurrentController();
             default:
                 return super.onOptionsItemSelected(item);
         }
@@ -126,38 +130,72 @@ public class RingtoneSelectionController extends BaseController implements Flexi
         recyclerView.setHasFixedSize(true);
         recyclerView.setAdapter(adapter);
 
+        adapterDataObserver = new RecyclerView.AdapterDataObserver() {
+            @Override
+            public void onChanged() {
+                super.onChanged();
+                findSelectedSound();
+            }
+        };
+
+        adapter.registerAdapterDataObserver(adapterDataObserver);
         swipeRefreshLayout.setEnabled(false);
     }
 
     @SuppressLint("LongLogTag")
-    private void fetchNotificationSounds() {
-        abstractFlexibleItemList = new ArrayList<>();
-        abstractFlexibleItemList.add(new NotificationSoundItem(getResources().getString(R.string.nc_settings_no_ringtone),
-                null));
-
-        String ringtoneString;
-
-        if (callNotificationSounds) {
-            ringtoneString = "android.resource://" + getApplicationContext().getPackageName() +
-                    "/raw/librem_by_feandesign_call";
-        } else {
-            ringtoneString = "android.resource://" + getApplicationContext().getPackageName() +
-                    "/raw/librem_by_feandesign_message";
-        }
-
-        abstractFlexibleItemList.add(new NotificationSoundItem(getResources()
-                .getString(R.string.nc_settings_default_ringtone), ringtoneString));
-
+    private void findSelectedSound() {
         boolean foundDefault = false;
 
         String preferencesString = null;
         if ((callNotificationSounds && TextUtils.isEmpty((preferencesString = appPreferences.getCallRingtoneUri())))
                 || (!callNotificationSounds && TextUtils.isEmpty((preferencesString = appPreferences
                 .getMessageRingtoneUri())))) {
-            ((NotificationSoundItem) abstractFlexibleItemList.get(1)).setSelected(true);
+            adapter.toggleSelection(1);
             foundDefault = true;
         }
 
+        if (!TextUtils.isEmpty(preferencesString) && !foundDefault) {
+            try {
+                RingtoneSettings ringtoneSettings = LoganSquare.parse(preferencesString, RingtoneSettings.class);
+                if (ringtoneSettings.getRingtoneUri() == null) {
+                    adapter.toggleSelection(0);
+                } else if (ringtoneSettings.getRingtoneUri().toString().equals(getRingtoneString())) {
+                    adapter.toggleSelection(1);
+                } else {
+                    NotificationSoundItem notificationSoundItem;
+                    for (int i = 2; i < adapter.getItemCount(); i++) {
+                        notificationSoundItem = (NotificationSoundItem) adapter.getItem(i);
+                        if (notificationSoundItem.getNotificationSoundUri().equals(ringtoneSettings.getRingtoneUri().toString())) {
+                            adapter.toggleSelection(i);
+                            break;
+                        }
+                    }
+                }
+            } catch (IOException e) {
+                Log.e(TAG, "Failed to parse ringtone settings");
+            }
+        }
+
+        adapter.unregisterAdapterDataObserver(adapterDataObserver);
+        adapterDataObserver = null;
+    }
+
+    private String getRingtoneString() {
+        if (callNotificationSounds) {
+            return ("android.resource://" + context.getPackageName() +
+                    "/raw/librem_by_feandesign_call");
+        } else {
+            return ("android.resource://" + context.getPackageName() + "/raw" +
+                    "/librem_by_feandesign_message");
+        }
+
+    }
+
+    private void fetchNotificationSounds() {
+        abstractFlexibleItemList.add(new NotificationSoundItem(getResources().getString(R.string.nc_settings_no_ringtone), null));
+        abstractFlexibleItemList.add(new NotificationSoundItem(getResources()
+                .getString(R.string.nc_settings_default_ringtone), getRingtoneString()));
+
 
         if (getActivity() != null) {
             RingtoneManager manager = new RingtoneManager(getActivity());
@@ -181,29 +219,10 @@ public class RingtoneSelectionController extends BaseController implements Flexi
                 notificationSoundItem = new NotificationSoundItem(notificationTitle, completeNotificationUri);
 
                 abstractFlexibleItemList.add(notificationSoundItem);
-
-                if (!TextUtils.isEmpty(preferencesString) && !foundDefault) {
-                    try {
-                        RingtoneSettings ringtoneSettings = LoganSquare.parse(preferencesString, RingtoneSettings.class);
-                        if (ringtoneSettings.getRingtoneUri() == null) {
-                            ((NotificationSoundItem) abstractFlexibleItemList.get(0)).setSelected(true);
-                            foundDefault = true;
-                        } else if (completeNotificationUri.equals(ringtoneSettings.getRingtoneUri().toString())) {
-                            notificationSoundItem.setSelected(true);
-                            foundDefault = true;
-                        } else if (ringtoneSettings.getRingtoneUri().toString().equals(ringtoneString)) {
-                            ((NotificationSoundItem) abstractFlexibleItemList.get(1)).setSelected(true);
-                            foundDefault = true;
-                        }
-                    } catch (IOException e) {
-                        Log.e(TAG, "Failed to parse ringtone settings");
-                    }
-                }
             }
-
         }
 
-        adapter.updateDataSet(abstractFlexibleItemList, true);
+        adapter.updateDataSet(abstractFlexibleItemList, false);
     }
 
     @Override
@@ -242,14 +261,16 @@ public class RingtoneSelectionController extends BaseController implements Flexi
             if (callNotificationSounds) {
                 try {
                     appPreferences.setCallRingtoneUri(LoganSquare.serialize(ringtoneSettings));
-                    toggleSelection(position);
+                    adapter.toggleSelection(position);
+                    adapter.notifyDataSetChanged();
                 } catch (IOException e) {
                     Log.e(TAG, "Failed to store selected ringtone for calls");
                 }
             } else {
                 try {
                     appPreferences.setMessageRingtoneUri(LoganSquare.serialize(ringtoneSettings));
-                    toggleSelection(position);
+                    adapter.toggleSelection(position);
+                    adapter.notifyDataSetChanged();
                 } catch (IOException e) {
                     Log.e(TAG, "Failed to store selected ringtone for calls");
                 }
@@ -259,19 +280,6 @@ public class RingtoneSelectionController extends BaseController implements Flexi
         return true;
     }
 
-    private void toggleSelection(int position) {
-        adapter.toggleSelection(position);
-        ((NotificationSoundItem) adapter.getItem(position)).flipItemSelection();
-
-        NotificationSoundItem notificationSoundItem;
-        for (int i = 0; i < adapter.getItemCount(); i++) {
-            if (i != position) {
-                notificationSoundItem = (NotificationSoundItem) adapter.getItem(i);
-                notificationSoundItem.flipToFront();
-            }
-        }
-    }
-
     private void endMediaPlayer() {
         if (cancelMediaPlayerHandler != null) {
             cancelMediaPlayerHandler.removeCallbacksAndMessages(null);

+ 12 - 54
app/src/main/java/com/nextcloud/talk/controllers/SettingsController.java

@@ -36,7 +36,6 @@ import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
 import android.widget.Checkable;
-import android.widget.ImageView;
 import android.widget.TextView;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -49,10 +48,9 @@ import com.bluelinelabs.conductor.RouterTransaction;
 import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
 import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler;
 import com.bluelinelabs.logansquare.LoganSquare;
-import com.bumptech.glide.load.model.GlideUrl;
-import com.bumptech.glide.load.model.LazyHeaders;
-import com.bumptech.glide.load.resource.bitmap.CircleCrop;
-import com.bumptech.glide.request.RequestOptions;
+import com.facebook.drawee.backends.pipeline.Fresco;
+import com.facebook.drawee.interfaces.DraweeController;
+import com.facebook.drawee.view.SimpleDraweeView;
 import com.nextcloud.talk.BuildConfig;
 import com.nextcloud.talk.R;
 import com.nextcloud.talk.api.NcApi;
@@ -67,7 +65,6 @@ import com.nextcloud.talk.utils.DoNotDisturbUtils;
 import com.nextcloud.talk.utils.SecurityUtils;
 import com.nextcloud.talk.utils.bundle.BundleKeys;
 import com.nextcloud.talk.utils.database.user.UserUtils;
-import com.nextcloud.talk.utils.glide.GlideApp;
 import com.nextcloud.talk.utils.preferences.AppPreferences;
 import com.nextcloud.talk.utils.preferences.MagicUserInputModule;
 import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder;
@@ -90,113 +87,78 @@ import java.util.*;
 public class SettingsController extends BaseController {
 
     public static final String TAG = "SettingsController";
-
+    private static final int ID_REMOVE_ACCOUNT_WARNING_DIALOG = 0;
     @BindView(R.id.settings_screen)
     MaterialPreferenceScreen settingsScreen;
-
     @BindView(R.id.settings_proxy_choice)
     MaterialChoicePreference proxyChoice;
-
     @BindView(R.id.settings_proxy_port_edit)
     MaterialEditTextPreference proxyPortEditText;
-
     @BindView(R.id.settings_licence)
     MaterialStandardPreference licenceButton;
-
     @BindView(R.id.settings_privacy)
     MaterialStandardPreference privacyButton;
-
     @BindView(R.id.settings_source_code)
     MaterialStandardPreference sourceCodeButton;
-
     @BindView(R.id.settings_version)
     MaterialStandardPreference versionInfo;
-
     @BindView(R.id.avatar_image)
-    ImageView avatarImageView;
-
+    SimpleDraweeView avatarImageView;
     @BindView(R.id.display_name_text)
     TextView displayNameTextView;
-
     @BindView(R.id.base_url_text)
     TextView baseUrlTextView;
-
     @BindView(R.id.settings_call_sound)
     MaterialStandardPreference settingsCallSound;
-
     @BindView(R.id.settings_message_sound)
     MaterialStandardPreference settingsMessageSound;
-
     @BindView(R.id.settings_remove_account)
     MaterialStandardPreference removeAccountButton;
-
     @BindView(R.id.settings_switch)
     MaterialStandardPreference switchAccountButton;
-
     @BindView(R.id.settings_reauthorize)
     MaterialStandardPreference reauthorizeButton;
-
     @BindView(R.id.settings_add_account)
     MaterialStandardPreference addAccountButton;
-
     @BindView(R.id.message_view)
     MaterialPreferenceCategory messageView;
-
     @BindView(R.id.settings_client_cert)
     MaterialStandardPreference certificateSetup;
-
     @BindView(R.id.settings_always_vibrate)
     MaterialSwitchPreference shouldVibrateSwitchPreference;
-
     @BindView(R.id.settings_incognito_keyboard)
     MaterialSwitchPreference incognitoKeyboardSwitchPreference;
-
     @BindView(R.id.settings_screen_security)
     MaterialSwitchPreference screenSecuritySwitchPreference;
-
     @BindView(R.id.settings_link_previews)
     MaterialSwitchPreference linkPreviewsSwitchPreference;
-
     @BindView(R.id.settings_screen_lock)
     MaterialSwitchPreference screenLockSwitchPreference;
-
     @BindView(R.id.settings_screen_lock_timeout)
     MaterialChoicePreference screenLockTimeoutChoicePreference;
-
     @BindView(R.id.message_text)
     TextView messageText;
-
     @Inject
     EventBus eventBus;
-
     @Inject
     AppPreferences appPreferences;
-
     @Inject
     NcApi ncApi;
-
     @Inject
     UserUtils userUtils;
-
     @Inject
     Context context;
-
     private LovelySaveStateHandler saveStateHandler;
-
     private UserEntity currentUser;
     private String credentials;
-
     private OnPreferenceValueChangedListener<String> proxyTypeChangeListener;
     private OnPreferenceValueChangedListener<Boolean> proxyCredentialsChangeListener;
     private OnPreferenceValueChangedListener<Boolean> screenSecurityChangeListener;
     private OnPreferenceValueChangedListener<Boolean> screenLockChangeListener;
     private OnPreferenceValueChangedListener<String> screenLockTimeoutChangeListener;
-
     private Disposable profileQueryDisposable;
     private Disposable dbQueryDisposable;
 
-    private static final int ID_REMOVE_ACCOUNT_WARNING_DIALOG = 0;
-
     @Override
     protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
         return inflater.inflate(R.layout.controller_settings, container, false);
@@ -636,17 +598,13 @@ public class SettingsController extends BaseController {
             avatarId = currentUser.getUsername();
         }
 
-        GlideUrl glideUrl = new GlideUrl(ApiUtils.getUrlForAvatarWithName(currentUser.getBaseUrl(),
-                avatarId, R.dimen.avatar_size_big), new LazyHeaders.Builder()
-                .setHeader("Accept", "image/*")
-                .setHeader("User-Agent", ApiUtils.getUserAgent())
-                .build());
-
-        GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext())
-                .load(glideUrl)
-                .centerInside()
-                .apply(RequestOptions.bitmapTransform(new CircleCrop()))
-                .into(avatarImageView);
+        DraweeController draweeController = Fresco.newDraweeControllerBuilder()
+                .setOldController(avatarImageView.getController())
+                .setAutoPlayAnimations(true)
+                .setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(currentUser.getBaseUrl(),
+                        avatarId, R.dimen.avatar_size_big), null))
+                .build();
+        avatarImageView.setController(draweeController);
     }
 
     @Override

+ 0 - 6
app/src/main/java/com/nextcloud/talk/controllers/SwitchAccountController.java

@@ -30,7 +30,6 @@ import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
 import androidx.annotation.NonNull;
-import androidx.recyclerview.widget.DividerItemDecoration;
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
 import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
@@ -227,11 +226,6 @@ public class SwitchAccountController extends BaseController {
         recyclerView.setHasFixedSize(true);
         recyclerView.setAdapter(adapter);
 
-        recyclerView.addItemDecoration(new DividerItemDecoration(
-                recyclerView.getContext(),
-                layoutManager.getOrientation()
-        ));
-
         swipeRefreshLayout.setEnabled(false);
     }
 

+ 18 - 18
app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/CallMenuController.java

@@ -231,20 +231,20 @@ public class CallMenuController extends BaseController implements FlexibleAdapte
 
                 if (tag > 0) {
                     if (tag == 1 || tag == 9) {
-                            if (tag == 1) {
-                                Data data;
-                                if ((data = getWorkerData()) != null) {
-                                    OneTimeWorkRequest leaveConversationWorker =
-                                            new OneTimeWorkRequest.Builder(LeaveConversationWorker.class).setInputData(data).build();
-                                    WorkManager.getInstance().enqueue(leaveConversationWorker);
-                                }
-                            } else {
-                                Bundle deleteConversationBundle;
-                                if ((deleteConversationBundle = getDeleteConversationBundle()) != null) {
-                                    conversationMenuInterface.openLovelyDialogWithIdAndBundle(ConversationsListController.ID_DELETE_CONVERSATION_DIALOG, deleteConversationBundle);
-                                }
+                        if (tag == 1) {
+                            Data data;
+                            if ((data = getWorkerData()) != null) {
+                                OneTimeWorkRequest leaveConversationWorker =
+                                        new OneTimeWorkRequest.Builder(LeaveConversationWorker.class).setInputData(data).build();
+                                WorkManager.getInstance().enqueue(leaveConversationWorker);
                             }
-                            eventBus.post(new BottomSheetLockEvent(true, 0, false, true));
+                        } else {
+                            Bundle deleteConversationBundle;
+                            if ((deleteConversationBundle = getDeleteConversationBundle()) != null) {
+                                conversationMenuInterface.openLovelyDialogWithIdAndBundle(ConversationsListController.ID_DELETE_CONVERSATION_DIALOG, deleteConversationBundle);
+                            }
+                        }
+                        eventBus.post(new BottomSheetLockEvent(true, 0, false, true));
                     } else {
                         bundle.putInt(BundleKeys.KEY_OPERATION_CODE, tag);
                         if (tag != 2 && tag != 4 && tag != 6 && tag != 7) {
@@ -291,11 +291,6 @@ public class CallMenuController extends BaseController implements FlexibleAdapte
         return true;
     }
 
-    @Parcel
-    public enum MenuType {
-        REGULAR, SHARE
-    }
-
     private Data getWorkerData() {
         if (!TextUtils.isEmpty(conversation.getToken())) {
             Data.Builder data = new Data.Builder();
@@ -318,4 +313,9 @@ public class CallMenuController extends BaseController implements FlexibleAdapte
         return null;
 
     }
+
+    @Parcel
+    public enum MenuType {
+        REGULAR, SHARE
+    }
 }

+ 12 - 9
app/src/main/java/com/nextcloud/talk/dagger/modules/RestModule.java

@@ -197,9 +197,9 @@ public class RestModule {
             if (appPreferences.getProxyCredentials() &&
                     !TextUtils.isEmpty(appPreferences.getProxyUsername()) &&
                     !TextUtils.isEmpty(appPreferences.getProxyPassword())) {
-                httpClient.proxyAuthenticator(new ProxyAuthenticator(Credentials.basic(
+                httpClient.proxyAuthenticator(new MagicAuthenticator(Credentials.basic(
                         appPreferences.getProxyUsername(),
-                        appPreferences.getProxyPassword())));
+                        appPreferences.getProxyPassword()), "Proxy-Authorization"));
             }
         }
 
@@ -210,10 +210,10 @@ public class RestModule {
 
     public static class HeadersInterceptor implements Interceptor {
 
+        @NonNull
         @Override
         public Response intercept(@NonNull Chain chain) throws IOException {
             Request original = chain.request();
-
             Request request = original.newBuilder()
                     .header("User-Agent", ApiUtils.getUserAgent())
                     .header("Accept", "application/json")
@@ -231,24 +231,27 @@ public class RestModule {
         }
     }
 
-    private class ProxyAuthenticator implements Authenticator {
+    public static class MagicAuthenticator implements Authenticator {
 
         private String credentials;
+        private String authenticatorType;
 
-        private ProxyAuthenticator(String credentials) {
+        public MagicAuthenticator(@NonNull String credentials, @NonNull String authenticatorType) {
             this.credentials = credentials;
+            this.authenticatorType = authenticatorType;
         }
 
         @Nullable
         @Override
-        public Request authenticate(@NonNull Route route, @NonNull Response response) throws IOException {
-            if (credentials.equals(response.request().header("Proxy-Authorization"))) {
+        public Request authenticate(@Nullable Route route, @NonNull Response response) {
+            if (response.request().header(authenticatorType) != null) {
                 return null;
             }
 
-            int attemptsCount = 0;
             Response countedResponse = response;
 
+            int attemptsCount = 0;
+
             while ((countedResponse = countedResponse.priorResponse()) != null) {
                 attemptsCount++;
                 if (attemptsCount == 3) {
@@ -257,7 +260,7 @@ public class RestModule {
             }
 
             return response.request().newBuilder()
-                    .header("Proxy-Authorization", credentials)
+                    .header(authenticatorType, credentials)
                     .build();
         }
     }

+ 27 - 0
app/src/main/java/com/nextcloud/talk/interfaces/SelectionInterface.java

@@ -0,0 +1,27 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 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.nextcloud.talk.interfaces;
+
+public interface SelectionInterface {
+    void toggleBrowserItemSelection(String path);
+
+    boolean isPathSelected(String path);
+}

+ 1 - 0
app/src/main/java/com/nextcloud/talk/jobs/DeleteConversationWorker.java

@@ -86,6 +86,7 @@ public class DeleteConversationWorker extends Worker {
                     .subscribeOn(Schedulers.newThread())
                     .blockingSubscribe(new Observer<GenericOverall>() {
                         Disposable disposable;
+
                         @Override
                         public void onSubscribe(Disposable d) {
                             disposable = d;

+ 1 - 0
app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.java

@@ -86,6 +86,7 @@ public class LeaveConversationWorker extends Worker {
                     .subscribeOn(Schedulers.newThread())
                     .blockingSubscribe(new Observer<GenericOverall>() {
                         Disposable disposable;
+
                         @Override
                         public void onSubscribe(Disposable d) {
                             disposable = d;

+ 105 - 0
app/src/main/java/com/nextcloud/talk/jobs/ShareOperationWorker.java

@@ -0,0 +1,105 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 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.nextcloud.talk.jobs;
+
+import android.content.Context;
+import androidx.annotation.NonNull;
+import androidx.work.Data;
+import androidx.work.Worker;
+import androidx.work.WorkerParameters;
+import autodagger.AutoInjector;
+import com.nextcloud.talk.api.NcApi;
+import com.nextcloud.talk.application.NextcloudTalkApplication;
+import com.nextcloud.talk.models.database.UserEntity;
+import com.nextcloud.talk.utils.ApiUtils;
+import com.nextcloud.talk.utils.bundle.BundleKeys;
+import com.nextcloud.talk.utils.database.user.UserUtils;
+import io.reactivex.Observer;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
+
+import javax.inject.Inject;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@AutoInjector(NextcloudTalkApplication.class)
+public class ShareOperationWorker extends Worker {
+    @Inject
+    UserUtils userUtils;
+    @Inject
+    NcApi ncApi;
+    private long userId;
+    private UserEntity operationsUser;
+    private String roomToken;
+    private List<String> filesArray = new ArrayList<>();
+    private String credentials;
+    private String baseUrl;
+
+    public ShareOperationWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
+        super(context, workerParams);
+        NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
+        Data data = workerParams.getInputData();
+        userId = data.getLong(BundleKeys.KEY_INTERNAL_USER_ID, 0);
+        roomToken = data.getString(BundleKeys.KEY_ROOM_TOKEN);
+        Collections.addAll(filesArray, data.getStringArray(BundleKeys.KEY_FILE_PATHS));
+        operationsUser = userUtils.getUserWithId(userId);
+        credentials = ApiUtils.getCredentials(operationsUser.getUsername(), operationsUser.getToken());
+        baseUrl = operationsUser.getBaseUrl();
+    }
+
+
+    @NonNull
+    @Override
+    public Result doWork() {
+        for (int i = 0; i < filesArray.size(); i++) {
+            ncApi.createRemoteShare(credentials,
+                    ApiUtils.getSharingUrl(baseUrl),
+                    filesArray.get(i),
+                    roomToken,
+                    "10")
+                    .subscribeOn(Schedulers.newThread())
+                    .blockingSubscribe(new Observer<Void>() {
+                        @Override
+                        public void onSubscribe(Disposable d) {
+
+                        }
+
+                        @Override
+                        public void onNext(Void aVoid) {
+
+                        }
+
+                        @Override
+                        public void onError(Throwable e) {
+
+                        }
+
+                        @Override
+                        public void onComplete() {
+
+                        }
+                    });
+        }
+
+        return Result.success();
+    }
+}

+ 14 - 0
app/src/main/java/com/nextcloud/talk/models/database/User.java

@@ -75,6 +75,20 @@ public interface User extends Parcelable, Persistable, Serializable {
         return false;
     }
 
+    default boolean hasExternalCapability(String capabilityName) {
+        if (getCapabilities() != null) {
+            try {
+                Capabilities capabilities = LoganSquare.parse(getCapabilities(), Capabilities.class);
+                if (capabilities.getExternalCapability() != null && capabilities.getExternalCapability().containsKey("v1")) {
+                    return capabilities.getExternalCapability().get("v1").contains("capabilityName");
+                }
+            } catch (IOException e) {
+                Log.e(TAG, "Failed to get capabilities for the user");
+            }
+        }
+        return false;
+    }
+
     default boolean hasSpreedCapabilityWithName(String capabilityName) {
         if (getCapabilities() != null) {
             try {

+ 9 - 0
app/src/main/java/com/nextcloud/talk/models/json/capabilities/Capabilities.java

@@ -25,6 +25,9 @@ import com.bluelinelabs.logansquare.annotation.JsonObject;
 import lombok.Data;
 import org.parceler.Parcel;
 
+import java.util.HashMap;
+import java.util.List;
+
 @Parcel
 @Data
 @JsonObject
@@ -34,4 +37,10 @@ public class Capabilities {
 
     @JsonField(name = "notifications")
     NotificationsCapability notificationsCapability;
+
+    @JsonField(name = "theming")
+    ThemingCapability themingCapability;
+
+    @JsonField(name = "external")
+    HashMap<String, List<String>> externalCapability;
 }

+ 61 - 0
app/src/main/java/com/nextcloud/talk/models/json/capabilities/ThemingCapability.java

@@ -0,0 +1,61 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 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.nextcloud.talk.models.json.capabilities;
+
+import com.bluelinelabs.logansquare.annotation.JsonField;
+import com.bluelinelabs.logansquare.annotation.JsonObject;
+import lombok.Data;
+import org.parceler.Parcel;
+
+@Parcel
+@Data
+@JsonObject
+class ThemingCapability {
+    @JsonField(name = "name")
+    String name;
+
+    @JsonField(name = "url")
+    String url;
+
+    @JsonField(name = "slogan")
+    String slogan;
+
+    @JsonField(name = "color")
+    String color;
+
+    @JsonField(name = "color-text")
+    String colorText;
+
+    @JsonField(name = "color-element")
+    String colorElement;
+
+    @JsonField(name = "logo")
+    String logo;
+
+    @JsonField(name = "background")
+    String background;
+
+    @JsonField(name = "background-plain")
+    boolean backgroundPlain;
+
+    @JsonField(name = "background-default")
+    boolean backgroundDefault;
+}

+ 11 - 20
app/src/main/java/com/nextcloud/talk/models/json/chat/ChatMessage.java

@@ -26,6 +26,7 @@ import com.bluelinelabs.logansquare.annotation.JsonIgnore;
 import com.bluelinelabs.logansquare.annotation.JsonObject;
 import com.nextcloud.talk.R;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
+import com.nextcloud.talk.models.database.UserEntity;
 import com.nextcloud.talk.models.json.converters.EnumSystemMessageTypeConverter;
 import com.nextcloud.talk.utils.ApiUtils;
 import com.nextcloud.talk.utils.TextMatchers;
@@ -44,7 +45,7 @@ public class ChatMessage implements IMessage, MessageContentType, MessageContent
     @JsonIgnore
     public boolean isGrouped;
     @JsonIgnore
-    public String activeUserId;
+    public UserEntity activeUser;
     @JsonIgnore
     public Map<String, String> selectedIndividualHashMap;
     @JsonIgnore
@@ -52,7 +53,6 @@ public class ChatMessage implements IMessage, MessageContentType, MessageContent
     List<MessageType> messageTypesToIgnore = Arrays.asList(MessageType.REGULAR_TEXT_MESSAGE,
             MessageType.SYSTEM_MESSAGE, MessageType.SINGLE_LINK_VIDEO_MESSAGE,
             MessageType.SINGLE_LINK_AUDIO_MESSAGE, MessageType.SINGLE_LINK_MESSAGE);
-    String baseUrl;
     @JsonField(name = "id")
     int jsonMessageId;
     @JsonField(name = "token")
@@ -96,9 +96,8 @@ public class ChatMessage implements IMessage, MessageContentType, MessageContent
                 Map<String, String> individualHashMap = messageParameters.get(key);
                 if (individualHashMap.get("type").equals("file")) {
                     selectedIndividualHashMap = individualHashMap;
-                    return String.format(Locale.getDefault(),
-                            "%s/index.php/core/preview?fileId=%s&x=%d&y=%d&forceIcon=1",
-                            baseUrl, individualHashMap.get("id"), 480, 480);
+                    return (ApiUtils.getUrlForFilePreviewWithFileId(getActiveUser().getBaseUrl(),
+                            individualHashMap.get("id"), NextcloudTalkApplication.getSharedApplication().getResources().getDimensionPixelSize(R.dimen.maximum_file_preview_size)));
                 }
             }
         }
@@ -130,14 +129,6 @@ public class ChatMessage implements IMessage, MessageContentType, MessageContent
         this.selectedIndividualHashMap = selectedIndividualHashMap;
     }
 
-    public String getBaseUrl() {
-        return baseUrl;
-    }
-
-    public void setBaseUrl(String baseUrl) {
-        this.baseUrl = baseUrl;
-    }
-
     @Override
     public String getId() {
         return Integer.toString(jsonMessageId);
@@ -155,42 +146,42 @@ public class ChatMessage implements IMessage, MessageContentType, MessageContent
             if (getMessageType().equals(MessageType.SINGLE_LINK_GIPHY_MESSAGE)
                     || getMessageType().equals(MessageType.SINGLE_LINK_TENOR_MESSAGE)
                     || getMessageType().equals(MessageType.SINGLE_LINK_GIF_MESSAGE)) {
-                if (getActorId().equals(getActiveUserId())) {
+                if (getActorId().equals(getActiveUser().getUserId())) {
                     return (NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_sent_a_gif_you));
                 } else {
                     return (String.format(NextcloudTalkApplication.getSharedApplication().getResources().getString(R.string.nc_sent_a_gif),
                             !TextUtils.isEmpty(getActorDisplayName()) ? getActorDisplayName() : NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_guest)));
                 }
             } else if (getMessageType().equals(MessageType.SINGLE_NC_ATTACHMENT_MESSAGE)) {
-                if (getActorId().equals(getActiveUserId())) {
+                if (getActorId().equals(getActiveUser().getUserId())) {
                     return (NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_sent_an_attachment_you));
                 } else {
                     return (String.format(NextcloudTalkApplication.getSharedApplication().getResources().getString(R.string.nc_sent_an_attachment),
                             !TextUtils.isEmpty(getActorDisplayName()) ? getActorDisplayName() : NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_guest)));
                 }
             } else if (getMessageType().equals(MessageType.SINGLE_LINK_MESSAGE)) {
-                if (getActorId().equals(getActiveUserId())) {
+                if (getActorId().equals(getActiveUser().getUserId())) {
                     return (NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_sent_a_link_you));
                 } else {
                     return (String.format(NextcloudTalkApplication.getSharedApplication().getResources().getString(R.string.nc_sent_a_link),
                             !TextUtils.isEmpty(getActorDisplayName()) ? getActorDisplayName() : NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_guest)));
                 }
             } else if (getMessageType().equals(MessageType.SINGLE_LINK_AUDIO_MESSAGE)) {
-                if (getActorId().equals(getActiveUserId())) {
+                if (getActorId().equals(getActiveUser().getUserId())) {
                     return (NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_sent_an_audio_you));
                 } else {
                     return (String.format(NextcloudTalkApplication.getSharedApplication().getResources().getString(R.string.nc_sent_an_audio),
                             !TextUtils.isEmpty(getActorDisplayName()) ? getActorDisplayName() : NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_guest)));
                 }
             } else if (getMessageType().equals(MessageType.SINGLE_LINK_VIDEO_MESSAGE)) {
-                if (getActorId().equals(getActiveUserId())) {
+                if (getActorId().equals(getActiveUser().getUserId())) {
                     return (NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_sent_a_video_you));
                 } else {
                     return (String.format(NextcloudTalkApplication.getSharedApplication().getResources().getString(R.string.nc_sent_a_video),
                             !TextUtils.isEmpty(getActorDisplayName()) ? getActorDisplayName() : NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_guest)));
                 }
             } else if (getMessageType().equals(MessageType.SINGLE_LINK_IMAGE_MESSAGE)) {
-                if (getActorId().equals(getActiveUserId())) {
+                if (getActorId().equals(getActiveUser().getUserId())) {
                     return (NextcloudTalkApplication.getSharedApplication().getString(R.string.nc_sent_an_image_you));
                 } else {
                     return (String.format(NextcloudTalkApplication.getSharedApplication().getResources().getString(R.string.nc_sent_an_image),
@@ -218,7 +209,7 @@ public class ChatMessage implements IMessage, MessageContentType, MessageContent
             @Override
             public String getAvatar() {
                 if (getActorType().equals("users")) {
-                    return ApiUtils.getUrlForAvatarWithName(getBaseUrl(), actorId, R.dimen.avatar_size);
+                    return ApiUtils.getUrlForAvatarWithName(getActiveUser().getBaseUrl(), actorId, R.dimen.avatar_size);
                 } else {
                     return null;
                 }

+ 0 - 1
app/src/main/java/com/nextcloud/talk/models/json/mention/Mention.java

@@ -20,7 +20,6 @@
 package com.nextcloud.talk.models.json.mention;
 
 import com.bluelinelabs.logansquare.annotation.JsonField;
-import com.bluelinelabs.logansquare.annotation.JsonIgnore;
 import com.bluelinelabs.logansquare.annotation.JsonObject;
 import lombok.Data;
 import org.parceler.Parcel;

+ 21 - 0
app/src/main/java/com/nextcloud/talk/utils/AccountUtils.java

@@ -26,6 +26,7 @@ package com.nextcloud.talk.utils;
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.content.Context;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.util.Log;
 import com.nextcloud.talk.R;
@@ -101,6 +102,26 @@ public class AccountUtils {
         return appName;
     }
 
+    public static boolean canWeOpenFilesApp(Context context, String accountName) {
+        PackageManager pm = context.getPackageManager();
+        try {
+            PackageInfo packageInfo =
+                    pm.getPackageInfo(context.getString(R.string.nc_import_accounts_from), 0);
+            if (packageInfo.versionCode < 1) {
+                final AccountManager accMgr = AccountManager.get(context);
+                final Account[] accounts = accMgr.getAccountsByType(context.getString(R.string.nc_import_account_type));
+                for (Account account : accounts) {
+                    if (account.name.equals(accountName)) {
+                        return true;
+                    }
+                }
+            }
+        } catch (PackageManager.NameNotFoundException appNotFoundException) {
+
+        }
+        return false;
+    }
+
     public static ImportAccount getInformationFromAccount(Account account) {
         int lastAtPos = account.name.lastIndexOf("@");
         String urlString = account.name.substring(lastAtPos + 1);

+ 15 - 0
app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java

@@ -60,6 +60,21 @@ public class ApiUtils {
         return retrofitBucket;
     }
 
+    public static String getUrlForFilePreviewWithRemotePath(String baseUrl, String remotePath, int px) {
+        return baseUrl + "/index.php/core/preview.png?file="
+                + Uri.encode(remotePath, "UTF-8")
+                + "&x=" + px + "&y=" + px + "&a=1&mode=cover&forceIcon=1";
+    }
+
+    public static String getUrlForFilePreviewWithFileId(String baseUrl, String fileId, int px) {
+        return baseUrl + "/index.php/core/preview?fileId="
+                + fileId + "&x=" + px + "&y=" + px + "&a=1&mode=cover&forceIcon=1";
+    }
+
+    public static String getSharingUrl(String baseUrl) {
+        return baseUrl + ocsApiVersion + "/apps/files_sharing/api/v1/shares";
+    }
+
     public static RetrofitBucket getRetrofitBucketForContactsSearchFor14(String baseUrl, @Nullable String searchQuery) {
         RetrofitBucket retrofitBucket = getRetrofitBucketForContactsSearch(baseUrl, searchQuery);
         retrofitBucket.setUrl(baseUrl + ocsApiVersion + "/core/autocomplete/get");

+ 43 - 0
app/src/main/java/com/nextcloud/talk/utils/DateUtils.java

@@ -0,0 +1,43 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 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.nextcloud.talk.utils;
+
+import android.content.Context;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+public class DateUtils {
+    public static String getLocalDateTimeStringFromTimestamp(Context context, long timestamp) {
+        Calendar cal = Calendar.getInstance();
+        TimeZone tz = cal.getTimeZone();
+
+        /* date formatter in local timezone */
+        Locale currentLocale = context.getResources().getConfiguration().locale;
+        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss", currentLocale);
+        sdf.setTimeZone(tz);
+
+        return sdf.format(new Date(timestamp));
+    }
+}

+ 19 - 6
app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.java

@@ -60,6 +60,7 @@ import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber;
 import com.facebook.imagepipeline.image.CloseableImage;
 import com.facebook.imagepipeline.image.ImageInfo;
 import com.facebook.imagepipeline.postprocessors.RoundAsCirclePostprocessor;
+import com.facebook.imagepipeline.postprocessors.RoundPostprocessor;
 import com.facebook.imagepipeline.request.ImageRequest;
 import com.facebook.imagepipeline.request.ImageRequestBuilder;
 import com.google.android.material.chip.ChipDrawable;
@@ -72,9 +73,13 @@ import com.vanniktech.emoji.EmojiEditText;
 import com.vanniktech.emoji.EmojiTextView;
 import org.greenrobot.eventbus.EventBus;
 
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -86,14 +91,14 @@ public class DisplayUtils {
         SpannableString spannableString = new SpannableString(string);
         spannableString.setSpan(new ClickableSpan() {
             @Override
-            public void onClick(@NonNull View widget) {
+            public void onClick(@Nonnull View widget) {
                 Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
                 browserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                 NextcloudTalkApplication.getSharedApplication().getApplicationContext().startActivity(browserIntent);
             }
 
             @Override
-            public void updateDrawState(TextPaint ds) {
+            public void updateDrawState(@NonNull TextPaint ds) {
                 super.updateDrawState(ds);
                 ds.setUnderlineText(false);
             }
@@ -104,7 +109,8 @@ public class DisplayUtils {
 
     private static void updateViewSize(@Nullable ImageInfo imageInfo, SimpleDraweeView draweeView) {
         if (imageInfo != null) {
-            draweeView.getLayoutParams().width = imageInfo.getWidth() > 480 ? 480 : imageInfo.getWidth();
+            int maxSize = draweeView.getContext().getResources().getDimensionPixelSize(R.dimen.maximum_file_preview_size);
+            draweeView.getLayoutParams().width = imageInfo.getWidth() > maxSize ? maxSize : imageInfo.getWidth();
             draweeView.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
             draweeView.setAspectRatio((float) imageInfo.getWidth() / imageInfo.getHeight());
             draweeView.requestLayout();
@@ -120,7 +126,7 @@ public class DisplayUtils {
     public static Bitmap getRoundedBitmapFromVectorDrawableResource(Resources resources, int resource) {
         VectorDrawable vectorDrawable = (VectorDrawable) resources.getDrawable(resource);
         Bitmap bitmap = getBitmap(vectorDrawable);
-        new RoundAsCirclePostprocessor(true).process(bitmap);
+        new RoundPostprocessor(true).process(bitmap);
         return bitmap;
     }
 
@@ -142,11 +148,18 @@ public class DisplayUtils {
         return bitmap;
     }
 
-    public static ImageRequest getImageRequestForUrl(String url) {
+    public static ImageRequest getImageRequestForUrl(String url, @Nullable UserEntity userEntity) {
+        Map<String, String> headers = new HashMap<>();
+        if (userEntity != null && url.startsWith(userEntity.getBaseUrl()) && url.contains("index.php/core/preview?fileId=")) {
+            headers.put("Authorization", ApiUtils.getCredentials(userEntity.getUsername(),
+                    userEntity.getToken()));
+        }
+
         return ImageRequestBuilder.newBuilderWithSource(Uri.parse(url))
                 .setProgressiveRenderingEnabled(true)
                 .setRotationOptions(RotationOptions.autoRotate())
                 .disableDiskCache()
+                .setHeaders(headers)
                 .build();
     }
 
@@ -252,7 +265,7 @@ public class DisplayUtils {
 
         if (!isCall) {
             ImageRequest imageRequest =
-                    getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(conversationUser.getBaseUrl(), id, R.dimen.avatar_size_big));
+                    getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(conversationUser.getBaseUrl(), id, R.dimen.avatar_size_big), null);
             ImagePipeline imagePipeline = Fresco.getImagePipeline();
             DataSource<CloseableReference<CloseableImage>> dataSource = imagePipeline.fetchDecodedImage(imageRequest, context);
 

+ 161 - 0
app/src/main/java/com/nextcloud/talk/utils/DrawableUtils.java

@@ -0,0 +1,161 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017/2018 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 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.nextcloud.talk.utils;
+
+import com.nextcloud.talk.R;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class DrawableUtils {
+
+
+    public static int getDrawableResourceIdForMimeType(String mimetype) {
+        Map<String, Integer> drawableMap = new HashMap<>();
+
+        // Initial list of mimetypes was acquired from https://github.com/nextcloud/server/blob/694ba5435b2963e201f6a6d2c775836bde07aaef/core/js/mimetypelist.js
+        drawableMap.put("application/coreldraw", R.drawable.ic_mimetype_image);
+        drawableMap.put("application/epub+zip", R.drawable.ic_mimetype_text);
+        drawableMap.put("application/font-sfnt", R.drawable.ic_mimetype_image);
+        drawableMap.put("application/font-woff", R.drawable.ic_mimetype_image);
+        drawableMap.put("application/gpx+xml", R.drawable.ic_mimetype_location);
+        drawableMap.put("application/illustrator", R.drawable.ic_mimetype_image);
+        drawableMap.put("application/javascript", R.drawable.ic_mimetype_text_code);
+        drawableMap.put("application/json", R.drawable.ic_mimetype_text_code);
+        drawableMap.put("application/msaccess", R.drawable.ic_mimetype_file);
+        drawableMap.put("application/msexcel", R.drawable.ic_mimetype_x_office_spreadsheet);
+        drawableMap.put("application/msonenote", R.drawable.ic_mimetype_x_office_document);
+        drawableMap.put("application/mspowerpoint", R.drawable.ic_mimetype_x_office_presentation);
+        drawableMap.put("application/msword", R.drawable.ic_mimetype_x_office_document);
+        drawableMap.put("application/octet-stream", R.drawable.ic_mimetype_file);
+        drawableMap.put("application/postscript", R.drawable.ic_mimetype_image);
+        drawableMap.put("application/rss+xml", R.drawable.ic_mimetype_text_code);
+        drawableMap.put("application/vnd.android.package-archive", R.drawable.ic_mimetype_package_x_generic);
+        drawableMap.put("application/vnd.lotus-wordpro", R.drawable.ic_mimetype_x_office_document);
+        drawableMap.put("application/vnd.garmin.tcx+xml", R.drawable.ic_mimetype_location);
+        drawableMap.put("application/vnd.google-earth.kml+xml", R.drawable.ic_mimetype_location);
+        drawableMap.put("application/vnd.google-earth.kmz", R.drawable.ic_mimetype_location);
+        drawableMap.put("application/vnd.ms-excel", R.drawable.ic_mimetype_x_office_spreadsheet);
+        drawableMap.put("application/vnd.ms-excel.addin.macroEnabled.12", R.drawable.ic_mimetype_x_office_spreadsheet);
+        drawableMap.put("application/vnd.ms-excel.sheet.binary.macroEnabled.12", R.drawable.ic_mimetype_x_office_spreadsheet);
+        drawableMap.put("application/vnd.ms-excel.sheet.macroEnabled.12", R.drawable.ic_mimetype_x_office_spreadsheet);
+        drawableMap.put("application/vnd.ms-excel.template.macroEnabled.12", R.drawable.ic_mimetype_x_office_spreadsheet);
+        drawableMap.put("application/vnd.ms-fontobject", R.drawable.ic_mimetype_image);
+        drawableMap.put("application/vnd.ms-powerpoint", R.drawable.ic_mimetype_x_office_presentation);
+        drawableMap.put("application/vnd.ms-powerpoint.addin.macroEnabled.12", R.drawable.ic_mimetype_x_office_presentation);
+        drawableMap.put("application/vnd.ms-powerpoint.presentation.macroEnabled.12", R.drawable.ic_mimetype_x_office_presentation);
+        drawableMap.put("application/vnd.ms-powerpoint.slideshow.macroEnabled.12", R.drawable.ic_mimetype_x_office_presentation);
+        drawableMap.put("application/vnd.ms-powerpoint.template.macroEnabled.12", R.drawable.ic_mimetype_x_office_presentation);
+        drawableMap.put("application/vnd.ms-visio.drawing.macroEnabled.12", R.drawable.ic_mimetype_x_office_document);
+        drawableMap.put("application/vnd.ms-visio.drawing", R.drawable.ic_mimetype_x_office_document);
+        drawableMap.put("application/vnd.ms-visio.stencil.macroEnabled.12", R.drawable.ic_mimetype_x_office_document);
+        drawableMap.put("application/vnd.ms-visio.stencil", R.drawable.ic_mimetype_x_office_document);
+        drawableMap.put("application/vnd.ms-visio.template.macroEnabled.12", R.drawable.ic_mimetype_x_office_document);
+        drawableMap.put("application/vnd.ms-visio.template", R.drawable.ic_mimetype_x_office_document);
+        drawableMap.put("application/vnd.ms-word.template.macroEnabled.12", R.drawable.ic_mimetype_x_office_document);
+        drawableMap.put("application/vnd.oasis.opendocument.presentation", R.drawable.ic_mimetype_x_office_presentation);
+        drawableMap.put("application/vnd.oasis.opendocument.presentation-template", R.drawable.ic_mimetype_x_office_presentation);
+        drawableMap.put("application/vnd.oasis.opendocument.spreadsheet", R.drawable.ic_mimetype_x_office_spreadsheet);
+        drawableMap.put("application/vnd.oasis.opendocument.spreadsheet-template", R.drawable.ic_mimetype_x_office_spreadsheet);
+        drawableMap.put("application/vnd.oasis.opendocument.text", R.drawable.ic_mimetype_x_office_document);
+        drawableMap.put("application/vnd.oasis.opendocument.text-master", R.drawable.ic_mimetype_x_office_document);
+        drawableMap.put("application/vnd.oasis.opendocument.text-template", R.drawable.ic_mimetype_x_office_document);
+        drawableMap.put("application/vnd.oasis.opendocument.text-web", R.drawable.ic_mimetype_x_office_document);
+        drawableMap.put("application/vnd.openxmlformats-officedocument.presentationml.presentation", R.drawable.ic_mimetype_x_office_presentation);
+        drawableMap.put("application/vnd.openxmlformats-officedocument.presentationml.slideshow", R.drawable.ic_mimetype_x_office_presentation);
+        drawableMap.put("application/vnd.openxmlformats-officedocument.presentationml.template", R.drawable.ic_mimetype_x_office_presentation);
+        drawableMap.put("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", R.drawable.ic_mimetype_x_office_spreadsheet);
+        drawableMap.put("application/vnd.openxmlformats-officedocument.spreadsheetml.template", R.drawable.ic_mimetype_x_office_spreadsheet);
+        drawableMap.put("application/vnd.openxmlformats-officedocument.wordprocessingml.document", R.drawable.ic_mimetype_x_office_document);
+        drawableMap.put("application/vnd.openxmlformats-officedocument.wordprocessingml.template", R.drawable.ic_mimetype_x_office_document);
+        drawableMap.put("application/vnd.visio", R.drawable.ic_mimetype_x_office_document);
+        drawableMap.put("application/vnd.wordperfect", R.drawable.ic_mimetype_x_office_document);
+        drawableMap.put("application/x-7z-compressed", R.drawable.ic_mimetype_package_x_generic);
+        drawableMap.put("application/x-bzip2", R.drawable.ic_mimetype_package_x_generic);
+        drawableMap.put("application/x-cbr", R.drawable.ic_mimetype_text);
+        drawableMap.put("application/x-compressed", R.drawable.ic_mimetype_package_x_generic);
+        drawableMap.put("application/x-dcraw", R.drawable.ic_mimetype_image);
+        drawableMap.put("application/x-deb", R.drawable.ic_mimetype_package_x_generic);
+        drawableMap.put("application/x-fictionbook+xml", R.drawable.ic_mimetype_text);
+        drawableMap.put("application/x-font", R.drawable.ic_mimetype_image);
+        drawableMap.put("application/x-gimp", R.drawable.ic_mimetype_image);
+        drawableMap.put("application/x-gzip", R.drawable.ic_mimetype_package_x_generic);
+        drawableMap.put("application/x-iwork-keynote-sffkey", R.drawable.ic_mimetype_x_office_presentation);
+        drawableMap.put("application/x-iwork-numbers-sffnumbers", R.drawable.ic_mimetype_x_office_spreadsheet);
+        drawableMap.put("application/x-iwork-pages-sffpages", R.drawable.ic_mimetype_x_office_document);
+        drawableMap.put("application/x-mobipocket-ebook", R.drawable.ic_mimetype_text);
+        drawableMap.put("application/x-perl", R.drawable.ic_mimetype_text_code);
+        drawableMap.put("application/x-photoshop", R.drawable.ic_mimetype_image);
+        drawableMap.put("application/x-php", R.drawable.ic_mimetype_text_code);
+        drawableMap.put("application/x-rar-compressed", R.drawable.ic_mimetype_package_x_generic);
+        drawableMap.put("application/x-tar", R.drawable.ic_mimetype_package_x_generic);
+        drawableMap.put("application/x-tex", R.drawable.ic_mimetype_text);
+        drawableMap.put("application/xml", R.drawable.ic_mimetype_text_code);
+        drawableMap.put("application/yaml", R.drawable.ic_mimetype_text_code);
+        drawableMap.put("application/zip", R.drawable.ic_mimetype_package_x_generic);
+        drawableMap.put("database", R.drawable.ic_mimetype_file);
+        drawableMap.put("httpd/unix-directory", R.drawable.ic_mimetype_folder);
+        drawableMap.put("text/css", R.drawable.ic_mimetype_text_code);
+        drawableMap.put("text/csv", R.drawable.ic_mimetype_x_office_spreadsheet);
+        drawableMap.put("text/html", R.drawable.ic_mimetype_text_code);
+        drawableMap.put("text/x-c", R.drawable.ic_mimetype_text_code);
+        drawableMap.put("text/x-c++src", R.drawable.ic_mimetype_text_code);
+        drawableMap.put("text/x-h", R.drawable.ic_mimetype_text_code);
+        drawableMap.put("text/x-java-source", R.drawable.ic_mimetype_text_code);
+        drawableMap.put("text/x-ldif", R.drawable.ic_mimetype_text_code);
+        drawableMap.put("text/x-python", R.drawable.ic_mimetype_text_code);
+        drawableMap.put("text/x-shellscript", R.drawable.ic_mimetype_text_code);
+        drawableMap.put("web", R.drawable.ic_mimetype_text_code);
+        drawableMap.put("application/internet-shortcut", R.drawable.ic_mimetype_link);
+
+        drawableMap.put("inode/directory", R.drawable.ic_mimetype_folder);
+        drawableMap.put("unknown", R.drawable.ic_mimetype_file);
+        drawableMap.put("application/pdf", R.drawable.ic_mimetype_application_pdf);
+
+        if ("DIR".equals(mimetype)) {
+            mimetype = "inode/directory";
+            return drawableMap.get(mimetype);
+        }
+
+        if (drawableMap.containsKey(mimetype)) {
+            return drawableMap.get(mimetype);
+        }
+
+        if (mimetype.startsWith("image/")) {
+            return R.drawable.ic_mimetype_image;
+        }
+
+        if (mimetype.startsWith("video/")) {
+            return R.drawable.ic_mimetype_video;
+        }
+
+        if (mimetype.startsWith("text/")) {
+            return R.drawable.ic_mimetype_text;
+        }
+
+        if (mimetype.startsWith("audio")) {
+            return R.drawable.ic_mimetype_audio;
+        }
+
+        return drawableMap.get("unknown");
+    }
+
+}

+ 0 - 5
app/src/main/java/com/nextcloud/talk/utils/PushUtils.java

@@ -24,9 +24,7 @@ import android.content.Context;
 import android.text.TextUtils;
 import android.util.Base64;
 import android.util.Log;
-
 import autodagger.AutoInjector;
-
 import com.bluelinelabs.logansquare.LoganSquare;
 import com.nextcloud.talk.R;
 import com.nextcloud.talk.api.NcApi;
@@ -38,15 +36,12 @@ import com.nextcloud.talk.models.json.push.PushConfigurationState;
 import com.nextcloud.talk.models.json.push.PushRegistrationOverall;
 import com.nextcloud.talk.utils.database.user.UserUtils;
 import com.nextcloud.talk.utils.preferences.AppPreferences;
-
 import io.reactivex.Observer;
 import io.reactivex.disposables.Disposable;
 import io.reactivex.schedulers.Schedulers;
-
 import org.greenrobot.eventbus.EventBus;
 
 import javax.inject.Inject;
-
 import java.io.*;
 import java.security.*;
 import java.security.spec.InvalidKeySpecException;

+ 1 - 2
app/src/main/java/com/nextcloud/talk/utils/TextMatchers.java

@@ -24,11 +24,10 @@ package com.nextcloud.talk.utils;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.core.util.PatternsCompat;
 import com.nextcloud.talk.models.json.chat.ChatMessage;
 import com.vanniktech.emoji.EmojiInformation;
 import com.vanniktech.emoji.EmojiUtils;
-
-import androidx.core.util.PatternsCompat;
 import eu.medsea.mimeutil.MimeUtil;
 import eu.medsea.mimeutil.detector.ExtensionMimeDetector;
 import eu.medsea.mimeutil.detector.MagicMimeMimeDetector;

+ 4 - 0
app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.java

@@ -51,4 +51,8 @@ public class BundleKeys {
     public static final String KEY_FROM_NOTIFICATION_START_CALL = "KEY_FROM_NOTIFICATION_START_CALL";
     public static final String KEY_ROOM_ID = "KEY_ROOM_ID";
     public static final String KEY_ARE_CALL_SOUNDS = "KEY_ARE_CALL_SOUNDS";
+    public static final String KEY_BROWSER_TYPE = "KEY_BROWSER_TYPE";
+    public static final String KEY_FILE_PATHS = "KEY_FILE_PATHS";
+    public static final String KEY_ACCOUNT = "KEY_ACCOUNT";
+    public static final String KEY_FILE_PATH = "KEY_FILE_PATH";
 }

+ 0 - 54
app/src/main/java/com/nextcloud/talk/utils/glide/CachingGlideModule.java

@@ -1,54 +0,0 @@
-/*
- * Nextcloud Talk application
- *
- * @author Mario Danic
- * Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU 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 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.nextcloud.talk.utils.glide;
-
-
-import android.content.Context;
-import autodagger.AutoInjector;
-import com.bumptech.glide.Glide;
-import com.bumptech.glide.GlideBuilder;
-import com.bumptech.glide.Registry;
-import com.bumptech.glide.annotation.GlideModule;
-import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader;
-import com.bumptech.glide.load.model.GlideUrl;
-import com.bumptech.glide.module.AppGlideModule;
-import com.nextcloud.talk.application.NextcloudTalkApplication;
-import okhttp3.OkHttpClient;
-
-import javax.inject.Inject;
-import java.io.InputStream;
-
-@AutoInjector(NextcloudTalkApplication.class)
-@GlideModule
-public class CachingGlideModule extends AppGlideModule {
-    @Inject
-    OkHttpClient okHttpClient;
-
-    @Override
-    public void registerComponents(Context context, Glide glide, Registry registry) {
-        NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
-        registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory(okHttpClient));
-    }
-
-    @Override
-    public void applyOptions(Context context, GlideBuilder builder) {
-    }
-}

+ 26 - 29
app/src/main/java/com/nextcloud/talk/utils/power/PowerManagerUtils.java

@@ -39,40 +39,17 @@ import javax.inject.Inject;
 
 public class PowerManagerUtils {
     private static final String TAG = "PowerManagerUtils";
-
-    @Inject
-    Context context;
-
     private final PowerManager.WakeLock fullLock;
     private final PowerManager.WakeLock partialLock;
     private final WifiManager.WifiLock wifiLock;
-    private ProximityLock proximityLock;
-
     private final boolean wifiLockEnforced;
+    @Inject
+    Context context;
+    private ProximityLock proximityLock;
     private boolean proximityDisabled = false;
 
     private int orientation;
 
-    public enum PhoneState {
-        IDLE,
-        PROCESSING,  //used when the phone is active but before the user should be alerted.
-        INTERACTIVE,
-        WITHOUT_PROXIMITY_SENSOR_LOCK,
-        WITH_PROXIMITY_SENSOR_LOCK
-    }
-
-    public enum WakeLockState {
-        FULL,
-        PARTIAL,
-        SLEEP,
-        PROXIMITY
-    }
-
-    public void setOrientation(int newOrientation) {
-        orientation = newOrientation;
-        updateInCallWakeLockState();
-    }
-
     public PowerManagerUtils() {
         NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
 
@@ -95,8 +72,13 @@ public class PowerManagerUtils {
         orientation = context.getResources().getConfiguration().orientation;
     }
 
+    public void setOrientation(int newOrientation) {
+        orientation = newOrientation;
+        updateInCallWakeLockState();
+    }
+
     public void updatePhoneState(PhoneState state) {
-        switch(state) {
+        switch (state) {
             case IDLE:
                 setWakeLockState(WakeLockState.SLEEP);
                 break;
@@ -132,7 +114,7 @@ public class PowerManagerUtils {
 
     @SuppressLint("WakelockTimeout")
     private synchronized void setWakeLockState(WakeLockState newState) {
-        switch(newState) {
+        switch (newState) {
             case FULL:
                 if (!fullLock.isHeld()) {
                     fullLock.acquire();
@@ -183,7 +165,7 @@ public class PowerManagerUtils {
                 }
 
                 fullLock.release(
-                        
+
                 );
                 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                     proximityLock.acquire();
@@ -193,4 +175,19 @@ public class PowerManagerUtils {
                 // something went very very wrong
         }
     }
+
+    public enum PhoneState {
+        IDLE,
+        PROCESSING,  //used when the phone is active but before the user should be alerted.
+        INTERACTIVE,
+        WITHOUT_PROXIMITY_SENSOR_LOCK,
+        WITH_PROXIMITY_SENSOR_LOCK
+    }
+
+    public enum WakeLockState {
+        FULL,
+        PARTIAL,
+        SLEEP,
+        PROXIMITY
+    }
 }

+ 25 - 0
app/src/main/res/drawable/ic_arrow_back_black_24dp.xml

@@ -0,0 +1,25 @@
+<!--
+  ~ Nextcloud Talk application
+  ~
+  ~ @author Mario Danic
+  ~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
+  ~
+  ~ This program is free software: you can redistribute it and/or modify
+  ~ it under the terms of the GNU 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 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/>.
+  -->
+
+<vector android:autoMirrored="true" android:height="24dp"
+    android:viewportHeight="24.0" android:viewportWidth="24.0"
+    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="#FF000000" android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
+</vector>

+ 25 - 0
app/src/main/res/drawable/ic_check_black_24dp.xml

@@ -0,0 +1,25 @@
+<!--
+  ~ Nextcloud Talk application
+  ~
+  ~ @author Mario Danic
+  ~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
+  ~
+  ~ This program is free software: you can redistribute it and/or modify
+  ~ it under the terms of the GNU 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 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/>.
+  -->
+
+<vector android:autoMirrored="true" android:height="24dp"
+    android:viewportHeight="24.0" android:viewportWidth="24.0"
+    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="#FF000000" android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
+</vector>

+ 20 - 0
app/src/main/res/drawable/ic_close_grey600_24dp.xml

@@ -1,3 +1,23 @@
+<!--
+  ~ Nextcloud Talk application
+  ~
+  ~ @author Mario Danic
+  ~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
+  ~
+  ~ This program is free software: you can redistribute it and/or modify
+  ~ it under the terms of the GNU 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 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/>.
+  -->
+
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
     android:width="24dp"

+ 20 - 0
app/src/main/res/drawable/ic_delete_grey600_24dp.xml

@@ -1,3 +1,23 @@
+<!--
+  ~ Nextcloud Talk application
+  ~
+  ~ @author Mario Danic
+  ~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
+  ~
+  ~ This program is free software: you can redistribute it and/or modify
+  ~ it under the terms of the GNU 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 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/>.
+  -->
+
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
     android:width="24dp"

+ 27 - 0
app/src/main/res/drawable/ic_file_icon_black_24h.xml

@@ -0,0 +1,27 @@
+<!--
+  ~ Nextcloud Talk application
+  ~
+  ~ @author Mario Danic
+  ~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
+  ~
+  ~ This program is free software: you can redistribute it and/or modify
+  ~ it under the terms of the GNU 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 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/>.
+  -->
+
+<vector android:autoMirrored="true" android:height="24dp"
+    android:viewportHeight="24" android:viewportWidth="24"
+    android:width="20.57dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="#000000" android:fillType="nonZero"
+        android:pathData="M0.8571,0C0.3771,0 0,0.3771 0,0.8571L0,23.1429C0,23.6229 0.3771,24 0.8571,24L19.7143,24C20.1943,24 20.5714,23.6229 20.5714,23.1429L20.5714,5.1429L15.4286,0L0.8571,0ZM3.4286,3.4286L13.7143,3.4286L13.7143,5.1429L3.4286,5.1429L3.4286,3.4286ZM3.4286,8.5714L12,8.5714L12,10.2857L3.4286,10.2857L3.4286,8.5714ZM3.4286,13.7143L17.1429,13.7143L17.1429,15.4286L3.4286,15.4286L3.4286,13.7143ZM3.4286,18.8571L10.2857,18.8571L10.2857,20.5714L3.4286,20.5714L3.4286,18.8571Z"
+        android:strokeColor="#00000000" android:strokeWidth="1"/>
+</vector>

+ 20 - 0
app/src/main/res/drawable/ic_group_grey600_24px.xml

@@ -1,3 +1,23 @@
+<!--
+  ~ Nextcloud Talk application
+  ~
+  ~ @author Mario Danic
+  ~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
+  ~
+  ~ This program is free software: you can redistribute it and/or modify
+  ~ it under the terms of the GNU 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 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/>.
+  -->
+
 <vector xmlns:tools="http://schemas.android.com/tools"
     android:autoMirrored="true" android:height="24dp"
     android:viewportHeight="24.0" android:viewportWidth="24.0"

+ 25 - 0
app/src/main/res/drawable/ic_insert_emoticon_black_24dp.xml

@@ -0,0 +1,25 @@
+<!--
+  ~ Nextcloud Talk application
+  ~
+  ~ @author Mario Danic
+  ~ Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
+  ~
+  ~ This program is free software: you can redistribute it and/or modify
+  ~ it under the terms of the GNU 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 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/>.
+  -->
+
+<vector android:autoMirrored="true" android:height="24dp"
+    android:viewportHeight="24.0" android:viewportWidth="24.0"
+    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="#FF000000" android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM15.5,11c0.83,0 1.5,-0.67 1.5,-1.5S16.33,8 15.5,8 14,8.67 14,9.5s0.67,1.5 1.5,1.5zM8.5,11c0.83,0 1.5,-0.67 1.5,-1.5S9.33,8 8.5,8 7,8.67 7,9.5 7.67,11 8.5,11zM12,17.5c2.33,0 4.31,-1.46 5.11,-3.5L6.89,14c0.8,2.04 2.78,3.5 5.11,3.5z"/>
+</vector>

+ 20 - 0
app/src/main/res/drawable/ic_launcher_background.xml

@@ -1,3 +1,23 @@
+<!--
+  ~ Nextcloud Talk application
+  ~
+  ~ @author Mario Danic
+  ~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
+  ~
+  ~ This program is free software: you can redistribute it and/or modify
+  ~ it under the terms of the GNU 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 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/>.
+  -->
+
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="108dp"
         android:height="108dp"

+ 20 - 0
app/src/main/res/drawable/ic_launcher_foreground.xml

@@ -1,3 +1,23 @@
+<!--
+  ~ Nextcloud Talk application
+  ~
+  ~ @author Mario Danic
+  ~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
+  ~
+  ~ This program is free software: you can redistribute it and/or modify
+  ~ it under the terms of the GNU 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 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/>.
+  -->
+
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="108dp"
         android:height="108dp"

+ 20 - 0
app/src/main/res/drawable/ic_link_grey600_24px.xml

@@ -1,3 +1,23 @@
+<!--
+  ~ Nextcloud Talk application
+  ~
+  ~ @author Mario Danic
+  ~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
+  ~
+  ~ This program is free software: you can redistribute it and/or modify
+  ~ it under the terms of the GNU 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 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/>.
+  -->
+
 <vector xmlns:tools="http://schemas.android.com/tools"
     android:autoMirrored="true" android:height="24dp"
     android:viewportHeight="24.0" android:viewportWidth="24.0"

+ 20 - 0
app/src/main/res/drawable/ic_link_white_24px.xml

@@ -1,3 +1,23 @@
+<!--
+  ~ Nextcloud Talk application
+  ~
+  ~ @author Mario Danic
+  ~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
+  ~
+  ~ This program is free software: you can redistribute it and/or modify
+  ~ it under the terms of the GNU 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 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/>.
+  -->
+
 <vector xmlns:tools="http://schemas.android.com/tools"
     android:autoMirrored="true" android:height="24dp"
     android:viewportHeight="24.0" android:viewportWidth="24.0"

+ 20 - 0
app/src/main/res/drawable/ic_lock_open_grey600_24dp.xml

@@ -1,3 +1,23 @@
+<!--
+  ~ Nextcloud Talk application
+  ~
+  ~ @author Mario Danic
+  ~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
+  ~
+  ~ This program is free software: you can redistribute it and/or modify
+  ~ it under the terms of the GNU 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 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/>.
+  -->
+
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
     android:width="24dp"

+ 20 - 0
app/src/main/res/drawable/ic_lock_plus_grey600_24dp.xml

@@ -1,3 +1,23 @@
+<!--
+  ~ Nextcloud Talk application
+  ~
+  ~ @author Mario Danic
+  ~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
+  ~
+  ~ This program is free software: you can redistribute it and/or modify
+  ~ it under the terms of the GNU 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 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/>.
+  -->
+
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="24dp"
     android:width="24dp"

+ 20 - 0
app/src/main/res/drawable/ic_logo.xml

@@ -1,3 +1,23 @@
+<!--
+  ~ Nextcloud Talk application
+  ~
+  ~ @author Mario Danic
+  ~ Copyright (C) 2017-2019 Mario Danic <mario@lovelyhq.com>
+  ~
+  ~ This program is free software: you can redistribute it and/or modify
+  ~ it under the terms of the GNU 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 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/>.
+  -->
+
 <vector android:autoMirrored="true" android:height="24dp"
     android:viewportHeight="128" android:viewportWidth="128"
     android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">

+ 27 - 0
app/src/main/res/drawable/ic_mimetype_application.xml

@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="16dp"
+    android:height="16dp"
+    android:viewportWidth="16"
+    android:viewportHeight="16">
+
+    <path
+        android:fillColor="#969696"
+        android:pathData="M6.94,0.5 C6.7,0.5,6.5,0.7,6.5,0.94 L6.5,2.2 C6,2.34,5.45,2.55,4.97,2.85
+L4.06,1.94 C3.9,1.76,3.6,1.75,3.44,1.94 L1.94,3.44 C1.76,3.61,1.76,3.9,1.94,4.06
+L2.85,4.97 C2.566,5.45,2.35,5.97,2.2,6.5 L0.94,6.5 C0.7,6.5,0.5,6.7,0.5,6.94
+L0.5,9.06 C0.5,9.31,0.69,9.5,0.94,9.5 L2.2,9.5 C2.34,10.04,2.56,10.55,2.85,11.03
+L1.94,11.94 C1.76,12.11,1.76,12.39,1.94,12.56 L3.44,14.06
+C3.62,14.24,3.9,14.24,4.06,14.06 L4.97,13.15 C5.45,13.435,5.97,13.65,6.5,13.8
+L6.5,15.06 C6.5,15.31,6.7,15.5,6.94,15.5 L9.06,15.5
+C9.3,15.5,9.51,15.3,9.5,15.06 L9.5,13.8 C10.04,13.66,10.55,13.44,11.03,13.15
+L11.94,14.06 C12.11,14.24,12.39,14.24,12.56,14.06 L14.06,12.56
+C14.24,12.39,14.24,12.11,14.06,11.94 L13.15,11.03
+C13.44,10.55,13.65,10.03,13.8,9.5 L15.06,9.5 C15.3,9.5,15.51,9.3,15.5,9.06
+L15.5,6.94 C15.5,6.7,15.3,6.5,15.06,6.5 L13.8,6.5
+C13.66,5.96,13.44,5.45,13.15,4.97 L14.06,4.06 C14.24,3.89,14.24,3.61,14.06,3.44
+L12.56,1.94 C12.39,1.76,12.11,1.76,11.94,1.94 L11.03,2.85
+C10.55,2.56,10.03,2.35,9.5,2.2 L9.5,0.94 C9.5,0.7,9.3,0.5,9.06,0.5 L6.94,0.5 Z
+M8,4.5 A3.5,3.5,0,0,1,11.5,8 A3.5,3.5,0,0,1,8,11.5 A3.5,3.5,0,0,1,4.5,8
+A3.5,3.5,0,0,1,8,4.5 Z" />
+</vector>

+ 19 - 0
app/src/main/res/drawable/ic_mimetype_application_pdf.xml

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="16dp"
+    android:height="16dp"
+    android:viewportWidth="16"
+    android:viewportHeight="16">
+
+    <path
+        android:fillColor="#dc5047"
+        android:pathData="M2.5,1 C2.22,1,2,1.22,2,1.5 L2,14.5 C2,14.78,2.22,15,2.5,15 L13.5,15
+C13.78,15,14,14.78,14,14.5 L14,4 L11,1 Z M8.3,4.9 S8.37,5.85,8.15,7.2
+C8.865,9.253,9.65,9.53,10,9.7 C10.74,9.64,11.565,9.6,12.3,10
+C12.8,10.286,13.194,11.5,12,11.5 C11.46,11.466,10.463,11.154,9.75,10.8
+C8.684,10.92,7.36,11.12,6.25,11.6 C5,13.7,4.44,14,4,14
+C2.785,13.68,3.44,12.07,3.9,11.8 C4.45,11.33,5.095,11.06,5.3,11
+C5.39,10.85,6.684,8.31,7,7.25 C6.7,6.226,6.63,5.144,6.8,4.5
+C7.58,3.482,8.3,4.15,8.3,4.9 Z M7.6,8 C7.33,9.057,6.252,11.084,6.3,11
+C7.405,10.515,8.4,10.37,9.5,10.2 C8.974,9.965,8.354,9.95,7.6,8 Z" />
+</vector>

+ 16 - 0
app/src/main/res/drawable/ic_mimetype_audio.xml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="16dp"
+    android:height="16dp"
+    android:viewportWidth="16"
+    android:viewportHeight="16">
+
+    <path
+        android:fillColor="#969696"
+        android:pathData="M12.97,0.5 C12.71,0.5,8.175,1.5,5.8,2 C5.33,2.1,5,2.53,5,3 L5,11
+C4.44,10.94,3.856,11.0625,3.35,11.34 C2.124,12.01,1.65,13.4,2.284,14.45
+C2.924,15.5,4.434,15.8,5.654,15.13 C6.5,14.68,7,13.85,7,13 L7,5 L12,4 L12,10.016
+C11.44,9.958,10.856,10.0785,10.35,10.356 C9.124,11.026,8.65,12.416,9.284,13.466
+C9.924,14.512,11.434,14.816,12.654,14.146 C13.5,13.68,14,12.85,14,12 L14,1.475
+C14,0.91,13.534,0.5,12.97,0.5 Z" />
+</vector>

+ 12 - 0
app/src/main/res/drawable/ic_mimetype_file.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="16dp"
+    android:height="16dp"
+    android:viewportWidth="16"
+    android:viewportHeight="16">
+
+    <path
+        android:fillColor="#969696"
+        android:pathData="M2.5,1 C2.22,1,2,1.22,2,1.5 L2,14.5 C2,14.78,2.22,15,2.5,15 L13.5,15
+C13.78,15,14,14.78,14,14.5 L14,4 L11,1 Z" />
+</vector>

+ 12 - 0
app/src/main/res/drawable/ic_mimetype_folder.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="16dp"
+    android:height="16dp"
+    android:viewportWidth="16"
+    android:viewportHeight="16">
+
+    <path
+        android:fillColor="#0082c9"
+        android:pathData="M1.5,2 C1.25,2,1,2.25,1,2.5 L1,13.5 C1,13.76,1.24,14,1.5,14 L14.5,14
+C14.76,14,15,13.759,15,13.5 L15,4.5 C15,4.25,14.75,4,14.5,4 L8,4 L6,2 Z" />
+</vector>

+ 13 - 0
app/src/main/res/drawable/ic_mimetype_folder_drag_accept.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="16dp"
+    android:height="16dp"
+    android:viewportWidth="16"
+    android:viewportHeight="16">
+
+    <path
+        android:fillColor="#0082c9"
+        android:pathData="M1.46,2 C1.21,2,1,2.21,1,2.46 L1,13.54 C1,13.798,1.202,14,1.46,14 L14.54,14
+C14.798,14,15,13.798,15,13.54 L15,4.462 C15,4.212,14.79,3.999,14.54,3.999
+L8,3.999 L6,2 L1.46,2 Z M2,5 L14,5 L14,13 L2,13 L2,5 Z" />
+</vector>

+ 20 - 0
app/src/main/res/drawable/ic_mimetype_folder_encrypted.xml

@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="16dp"
+    android:height="16dp"
+    android:viewportWidth="16"
+    android:viewportHeight="16">
+
+    <path
+        android:fillColor="#0082c9"
+        android:fillType="evenOdd"
+        android:pathData="M1.4609,2 C1.2109,2,1,2.2109,1,2.4609 L1,13.5389
+C1,13.7969,1.2029,13.9999,1.4609,13.9999 L14.5389,13.9999
+C14.7969,13.9999,14.9999,13.7969,14.9999,13.5389 L14.9999,4.4628
+C14.9999,4.2128,14.7889,3.9979,14.5389,3.9979 L7.9999,3.9979 L5.9999,1.9999
+L1.4608,1.9999 Z M8,5.8008 C8.8836,5.8008,9.5996,6.5167,9.5996,7.4004
+L9.5996,8.1992 L10,8.1992 L10,11 L6,11 L6,8.1992 L6.4004,8.1992 L6.4004,7.4004
+C6.4004,6.5167,7.1164,5.8008,8,5.8008 Z M8,6.5996
+C7.5581,6.5996,7.1992,6.9585,7.1992,7.4004 L7.1992,8.1992 L8.8008,8.1992
+L8.8008,7.4004 C8.8008,6.9585,8.4419,6.5996,8,6.5996 Z" />
+</vector>

+ 19 - 0
app/src/main/res/drawable/ic_mimetype_folder_external.xml

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="16dp"
+    android:height="16dp"
+    android:viewportWidth="16"
+    android:viewportHeight="16">
+
+    <path
+        android:fillColor="#0082c9"
+        android:fillType="evenOdd"
+        android:pathData="M1.46,2 C1.21,2,1,2.21,1,2.46 L1,13.54 C1,13.798,1.202,14,1.46,14 L14.54,14
+C14.798,14,15,13.798,15,13.54 L15,4.462 C15,4.212,14.79,3.999,14.54,3.999
+L8,3.999 L6,2 L1.46,2 Z M7.977,5.793 L11.547,5.793 L11.547,9.178 L10.355,8.05
+L8.57,9.743 L7.38,8.613 L9.166,6.923 L7.976,5.793 Z M5.597,6.357 L7.38,6.357
+L7.977,6.922 L5.597,6.922 L5.597,11.436 L10.355,11.436 L10.355,9.178
+L10.951,9.742 L10.951,11.436 C10.951,11.748,10.686,12,10.356,12 L5.596,12
+C5.266,12,5.001,11.748,5.001,11.436 L5.001,6.922
+C5.001,6.609,5.267,6.357,5.597,6.357 Z" />
+</vector>

+ 29 - 0
app/src/main/res/drawable/ic_mimetype_folder_public.xml

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="16dp"
+    android:height="16dp"
+    android:viewportWidth="16"
+    android:viewportHeight="16">
+
+    <path
+        android:fillColor="#0082c9"
+        android:pathData="M1.5,2 C1.25,2,1,2.25,1,2.5 L1,13.5 C1,13.76,1.24,14,1.5,14 L14.5,14
+C14.76,14,15,13.759,15,13.5 L15,4.5 C15,4.25,14.75,4,14.5,4 L8,4 L6,2 L1.5,2 Z
+M9.834,5.5 C10.268,5.4981,10.7,5.6545,11.02,5.9746
+C11.66,6.6153,11.66,7.7166,11.02,8.3574 L10.17,9.207
+C10.197,8.7574,10.151,8.4573,9.8633,8.0508 L10.287,7.625
+C10.562,7.3498,10.539,6.9967,10.289,6.709
+C10.019,6.4391,9.645,6.4388,9.373,6.7109 L7.7266,8.3574
+C7.4437,8.6404,7.431,8.9797,7.7246,9.2734 L6.9941,10.006
+C6.7069,9.7186,6.5083,9.3329,6.4824,8.8984
+C6.4568,8.464,6.6281,7.9913,6.9941,7.625 L8.6406,5.9766
+C8.9651,5.6619,9.4004,5.5019,9.834,5.5 Z M9.0078,7.9902
+C9.296,8.2773,9.4947,8.6645,9.5195,9.0996
+C9.5449,9.5348,9.3746,10.006,9.0078,10.373 L7.3594,12.02
+C6.7198,12.659,5.6199,12.659,4.9805,12.02
+C4.3409,11.38,4.339,10.282,4.9805,9.6406 L5.8418,8.7773
+C5.8155,9.2266,5.8645,9.5278,6.1523,9.9336 L5.7129,10.373
+C5.4541,10.632,5.3887,10.963,5.7129,11.287
+C5.9567,11.531,6.2686,11.594,6.6289,11.287 L8.2754,9.6406
+C8.5401,9.3758,8.562,9.0075,8.2773,8.7227 L9.0078,7.9902 Z" />
+</vector>

+ 19 - 0
app/src/main/res/drawable/ic_mimetype_folder_shared.xml

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="16dp"
+    android:height="16dp"
+    android:viewportWidth="16"
+    android:viewportHeight="16">
+
+    <path
+        android:fillColor="#0082c9"
+        android:pathData="M1.5,2 C1.25,2,1,2.25,1,2.5 L1,13.5 C1,13.76,1.24,14,1.5,14 L14.5,14
+C14.76,14,15,13.759,15,13.5 L15,4.5 C15,4.25,14.75,4,14.5,4 L8,4 L6,2 L1.5,2 Z
+M10.25,5.5 A1.25,1.25,0,0,1,11.5,6.75 A1.25,1.25,0,0,1,10.25,8
+A1.25,1.25,0,0,1,9.4492,7.709 L6.998,8.9355 A1.25,1.25,0,0,1,7,9
+A1.25,1.25,0,0,1,6.9961,9.0645 L9.4492,10.291 A1.25,1.25,0,0,1,10.25,10
+A1.25,1.25,0,0,1,11.5,11.25 A1.25,1.25,0,0,1,10.25,12.5 A1.25,1.25,0,0,1,9,11.25
+A1.25,1.25,0,0,1,9.0039,11.186 L6.5508,9.959 A1.25,1.25,0,0,1,5.75,10.25
+A1.25,1.25,0,0,1,4.5,9 A1.25,1.25,0,0,1,5.75,7.75 A1.25,1.25,0,0,1,6.5508,8.041
+L9.002,6.8145 A1.25,1.25,0,0,1,9,6.75 A1.25,1.25,0,0,1,10.25,5.5 Z" />
+</vector>

+ 14 - 0
app/src/main/res/drawable/ic_mimetype_folder_starred.xml

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="16dp"
+    android:height="16dp"
+    android:viewportWidth="16"
+    android:viewportHeight="16">
+
+    <path
+        android:fillColor="#0082c9"
+        android:pathData="M1.5,2 C1.25,2,1,2.25,1,2.5 L1,13.5 C1,13.76,1.24,14,1.5,14 L14.5,14
+C14.76,14,15,13.759,15,13.5 L15,4.5 C15,4.25,14.75,4,14.5,4 L8,4 L6,2 L1.5,2 Z
+M8,5.25 L9.1,7.9004 L12,8.125 L9.75,10 L10.5,12.75 L8,11.199 L5.5,12.75 L6.25,10
+L4,8.125 L6.9,7.9004 L8,5.25 Z" />
+</vector>

+ 14 - 0
app/src/main/res/drawable/ic_mimetype_image.xml

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="16dp"
+    android:height="16dp"
+    android:viewportWidth="16"
+    android:viewportHeight="16">
+
+    <path
+        android:fillColor="#969696"
+        android:pathData="M1.5,2 C1.3,2,1,2.3,1,2.5 L1,13.5 C1,13.7,1.3,14,1.5,14 L14.5,14
+C14.7,14,15,13.7,15,13.5 L15,2.5 C15,2.3,14.7,2,14.5,2 Z M2,3 L14,3 L14,8 L13,7
+L10,11 L7,8 L3,12 L2,12 Z M4.5,4 C3.67,4,3,4.67,3,5.5 S3.67,7,4.5,7
+S6,6.33,6,5.5 S5.33,4,4.5,4 Z" />
+</vector>

+ 32 - 0
app/src/main/res/drawable/ic_mimetype_link.xml

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="16dp"
+    android:height="16dp"
+    android:viewportWidth="16"
+    android:viewportHeight="16">
+
+    <path
+        android:fillColor="#969696"
+        android:pathData="M7.95,0.65 C3.85,0.65,0.55,3.95,0.55,8.05 S3.85,15.45,7.95,15.45
+S15.35,12.15,15.35,8.05 S12.05,0.65,7.95,0.65 Z M8.75,1.55
+C10.05,1.55,11.15,2.35,12.25,2.85 L14.05,5.35 L13.75,6.45 L14.35,6.75
+L14.35,9.15 C14.15,9.85,13.75,10.45,13.45,11.15
+C13.25,11.25,13.45,10.35,13.35,10.15 C13.35,9.55,12.85,9.55,12.45,9.95
+C12.05,10.25,11.05,10.25,10.95,9.55 C10.65,8.75,10.95,7.85,11.25,7.05
+L10.65,6.35 L10.85,4.55 L10.05,3.65 L10.25,2.65 L9.25,2.05
+C9.05,1.85,8.65,1.85,8.55,1.65 C8.65,1.65,8.75,1.55,8.75,1.55 Z M6.15,1.65
+S6.25,1.65,6.25,1.75 C6.65,1.95,6.15,2.15,6.05,2.35
+C5.55,2.65,6.35,3.05,6.55,3.35 C6.95,3.25,7.35,2.65,7.95,2.85
+C8.65,2.65,8.55,3.45,9.05,3.85 C9.15,4.05,9.95,4.65,9.45,4.45
+C8.95,4.05,8.45,4.05,8.15,4.55 C7.35,5.05,7.85,3.65,7.45,3.35
+C6.85,2.65,7.05,3.85,7.05,4.25 C6.65,4.25,5.95,3.95,5.55,4.45 L5.95,5.05
+L6.45,4.35 C6.45,4.05,6.55,4.55,6.75,4.65 C6.85,4.85,7.55,5.35,7.05,5.55
+C6.25,5.95,5.65,6.65,4.95,7.25 C4.75,7.75,4.25,7.65,3.95,7.25
+C3.25,6.85,3.25,7.95,3.35,8.35 L3.95,7.95 L3.95,9.05
+C3.55,9.45,3.05,8.35,2.65,8.15 L2.65,6.55 C2.65,6.15,2.55,5.65,2.65,5.25
+C3.45,4.35,4.35,3.35,4.85,2.25 L5.65,2.25 C6.25,2.45,5.95,1.55,6.15,1.65 Z
+M4.95,9.85 C5.05,9.85,5.15,9.85,5.25,9.95 C6.05,10.05,6.65,10.65,7.25,11.05
+C7.75,11.55,8.85,11.35,8.95,12.25 C8.75,13.15,7.85,13.65,7.15,13.95
+C6.95,14.05,6.75,14.15,6.55,14.15 C5.85,14.35,5.55,13.55,5.35,13.05
+C5.05,12.35,4.25,11.85,4.35,10.95 C4.35,10.55,4.55,9.95,4.95,9.85 Z" />
+</vector>

+ 16 - 0
app/src/main/res/drawable/ic_mimetype_location.xml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="16dp"
+    android:height="16dp"
+    android:viewportWidth="16"
+    android:viewportHeight="16">
+
+    <path
+        android:strokeColor="#969696"
+        android:strokeWidth="2"
+        android:pathData="M8,2 C10.2091,2,12,3.79086,12,6 C12,8.20914,10.2091,10,8,10
+C5.79086,10,4,8.20914,4,6 C4,3.79086,5.79086,2,8,2 Z" />
+    <path
+        android:fillColor="#969696"
+        android:pathData="M4,9 L12,9 L8,15 Z" />
+</vector>

+ 12 - 0
app/src/main/res/drawable/ic_mimetype_package_x_generic.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="16dp"
+    android:height="16dp"
+    android:viewportWidth="16"
+    android:viewportHeight="16">
+
+    <path
+        android:fillColor="#0082c9"
+        android:pathData="M4,3 L2,5 L2,12.5 C2,12.76,2.24,13,2.5,13 L13.5,13 C13.76,13,14,12.76,14,12.5
+L14,5 L12,3 Z M5,4 L11,4 L12,5 L4,5 Z" />
+</vector>

+ 14 - 0
app/src/main/res/drawable/ic_mimetype_text.xml

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="16dp"
+    android:height="16dp"
+    android:viewportWidth="16"
+    android:viewportHeight="16">
+
+    <path
+        android:fillColor="#969696"
+        android:pathData="M2.5,1 C2.22,1,2,1.22,2,1.5 L2,14.5 C2,14.78,2.22,15,2.5,15 L13.5,15
+C13.78,15,14,14.78,14,14.5 L14,4 L11,1 L2.5,1 Z M4,3 L10,3 L10,4 L4,4 L4,3 Z
+M4,6 L9,6 L9,7 L4,7 L4,6 Z M4,9 L12,9 L12,10 L4,10 L4,9 Z M4,12 L8,12 L8,13
+L4,13 L4,12 Z" />
+</vector>

+ 16 - 0
app/src/main/res/drawable/ic_mimetype_text_calendar.xml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="16dp"
+    android:height="16dp"
+    android:viewportWidth="16"
+    android:viewportHeight="16">
+
+    <path
+        android:fillColor="#969696"
+        android:pathData="M4,1 C3.5,1,3,1.5,3,2 L3,4 C3,4.5,3.5,5,4,5 S5,4.5,5,4 L5,2 C5,1.5,4.5,1,4,1 Z
+M12,1 C11.5,1,11,1.5,11,2 L11,4 C11,4.5,11.5,5,12,5 S13,4.5,13,4 L13,2
+C13,1.5,12.5,1,12,1 Z M5.5,3 L5.5,4 C5.5,4.831,5,5.5,4,5.5 S2.5,5,2.5,4
+L2.5,3.0625 C1.6159,3.2895,1,4.0872,1,5 L1,13 C1,14.108,1.892,15,3,15 L13,15
+C14.108,15,15,14.108,15,13 L15,5 C15,4.0872,14.3841,3.2895,13.5,3.0625 L13.5,4
+C13.5,4.831,13,5.5,12,5.5 S10.5,5,10.5,4 L10.5,3 Z M13,8 L13,13 L3,13 L3,8 Z" />
+</vector>

+ 16 - 0
app/src/main/res/drawable/ic_mimetype_text_code.xml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="16dp"
+    android:height="16dp"
+    android:viewportWidth="16"
+    android:viewportHeight="16">
+
+    <path
+        android:strokeColor="#969696"
+        android:strokeWidth="2"
+        android:pathData="M6.3,3.714 L1.9284,8 L6.3,12.286" />
+    <path
+        android:strokeColor="#969696"
+        android:strokeWidth="2"
+        android:pathData="M9.7,12.286 L14.072,8 L9.7,3.714" />
+</vector>

+ 23 - 0
app/src/main/res/drawable/ic_mimetype_text_vcard.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="16dp"
+    android:height="16dp"
+    android:viewportWidth="16"
+    android:viewportHeight="16">
+
+    <path
+        android:fillColor="#969696"
+        android:pathData="M10,1 C8.25,1,7,2.43,7,3.8 C7,5.2,7.1,6.2,7.8,7.3 C8,7.59,8.3,7.65,8.5,7.9
+C8.635,8.4,8.74,8.9,8.6,9.4 C8.32,9.5,8.075,9.62,7.8,9.73
+C7.715,9.58,7.57,9.53,7.33,9.33 C6.6,8.89,5.77,8.58,5,8.29
+C4.9,7.92,4.9,7.64,5,7.29 C5.156,7.124,5.37,7.02,5.5,6.86
+C5.96,6.26,6,5.206,6,4.49 C6,3.43,5.046,2.59,4,2.59 C2.83,2.59,2,3.59,2,4.49
+C2,5.42,2.034,6.13,2.5,6.86 C2.63,7.06,2.867,7.12,3,7.29
+C3.1,7.62,3.1,7.944,3,8.29 C2.15,8.59,1.4,8.93,0.66,9.33
+C0.09,9.73,0.14,9.535,0,10.86 C-0.11,11.92,2.335,11.99,4,11.99
+C4.06,11.99,4.11,11.99,4.17,11.99 C4.116,12.264,4.07,12.62,4,13.29
+C3.84,14.88,7.5,14.99,10,14.99 S16.16,14.89,16,13.29
+C15.785,11.29,15.77,11.58,15,10.99 C13.9,10.336,12.55,9.82,11.4,9.39
+C11.25,8.83,11.36,8.42,11.5,7.89 C11.735,7.64,12,7.53,12.2,7.29
+C12.9,6.405,13,4.865,13,3.79 C13,2.19,11.57,0.99,10,0.99 Z" />
+</vector>

+ 13 - 0
app/src/main/res/drawable/ic_mimetype_video.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="16dp"
+    android:height="16dp"
+    android:viewportWidth="16"
+    android:viewportHeight="16">
+
+    <path
+        android:fillColor="#969696"
+        android:pathData="M1.5,2 C1.3,2.05,1,2.29,1,2.5 L1,13.5 C1,13.73,1.274,14,1.5,14 L14.5,14
+C14.84,14,15,13.74,15,13.5 L15,2.5 C15,2.16,14.751,2,14.5,2 Z M2,3 L14,3 L14,13
+L2,13 Z M5,5 L5,11 L11,8 Z" />
+</vector>

+ 14 - 0
app/src/main/res/drawable/ic_mimetype_x_office_document.xml

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="16dp"
+    android:height="16dp"
+    android:viewportWidth="16"
+    android:viewportHeight="16">
+
+    <path
+        android:fillColor="#49abea"
+        android:pathData="M2.5,1 C2.22,1,2,1.22,2,1.5 L2,14.5 C2,14.78,2.22,15,2.5,15 L13.5,15
+C13.78,15,14,14.78,14,14.5 L14,4 L11,1 L2.5,1 Z M4,3 L10,3 L10,4 L4,4 L4,3 Z
+M4,6 L9,6 L9,7 L4,7 L4,6 Z M4,9 L12,9 L12,10 L4,10 L4,9 Z M4,12 L8,12 L8,13
+L4,13 L4,12 Z" />
+</vector>

+ 13 - 0
app/src/main/res/drawable/ic_mimetype_x_office_presentation.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="16dp"
+    android:height="16dp"
+    android:viewportWidth="16"
+    android:viewportHeight="16">
+
+    <path
+        android:fillColor="#f0965f"
+        android:pathData="M1.5,2 C1.25,2,1,2.25,1,2.5 L1,13.5 C1,13.75,1.25,14,1.5,14 L14.5,14
+C14.75,14,15,13.75,15,13.5 L15,2.5 C15,2.25,14.75,2,14.5,2 Z M2,5 L14,5 L14,11
+L2,11 Z" />
+</vector>

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff