Browse Source

reformat kotlin code to comply with ktlint

Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
Andy Scherzinger 4 years ago
parent
commit
e82808080d
35 changed files with 1618 additions and 1087 deletions
  1. 105 57
      app/src/gplay/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.kt
  2. 23 20
      app/src/main/java/com/nextcloud/talk/activities/BaseActivity.kt
  3. 22 17
      app/src/main/java/com/nextcloud/talk/activities/FullScreenImageActivity.kt
  4. 16 12
      app/src/main/java/com/nextcloud/talk/activities/FullScreenMediaActivity.kt
  5. 8 9
      app/src/main/java/com/nextcloud/talk/activities/FullScreenTextViewerActivity.kt
  6. 19 11
      app/src/main/java/com/nextcloud/talk/activities/MagicCallActivity.kt
  7. 111 67
      app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt
  8. 32 31
      app/src/main/java/com/nextcloud/talk/adapters/messages/MagicIncomingTextMessageViewHolder.kt
  9. 36 26
      app/src/main/java/com/nextcloud/talk/adapters/messages/MagicOutcomingTextMessageViewHolder.kt
  10. 44 33
      app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt
  11. 16 18
      app/src/main/java/com/nextcloud/talk/controllers/CallNotificationController.java
  12. 386 268
      app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt
  13. 270 175
      app/src/main/java/com/nextcloud/talk/controllers/ConversationInfoController.kt
  14. 0 1
      app/src/main/java/com/nextcloud/talk/controllers/base/ButterKnifeController.kt
  15. 4 3
      app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/items/BasicListItemWithImage.kt
  16. 20 17
      app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/items/ListIconDialogAdapter.kt
  17. 21 18
      app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/items/MagicBottomSheets.kt
  18. 1 3
      app/src/main/java/com/nextcloud/talk/events/CallNotificationClick.kt
  19. 208 133
      app/src/main/java/com/nextcloud/talk/jobs/ContactAddressBookWorker.kt
  20. 9 6
      app/src/main/java/com/nextcloud/talk/jobs/DownloadFileToCacheWorker.kt
  21. 43 34
      app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt
  22. 1 2
      app/src/main/java/com/nextcloud/talk/models/json/chat/ChatUtils.kt
  23. 20 4
      app/src/main/java/com/nextcloud/talk/models/json/converters/EnumSystemMessageTypeConverter.kt
  24. 9 9
      app/src/main/java/com/nextcloud/talk/receivers/PackageReplacedReceiver.kt
  25. 1 2
      app/src/main/java/com/nextcloud/talk/ui/dialog/AttachmentDialog.kt
  26. 7 6
      app/src/main/java/com/nextcloud/talk/ui/dialog/ScopeDialog.kt
  27. 19 11
      app/src/main/java/com/nextcloud/talk/utils/AccountUtils.kt
  28. 15 5
      app/src/main/java/com/nextcloud/talk/utils/ConductorRemapping.kt
  29. 8 5
      app/src/main/java/com/nextcloud/talk/utils/DateUtils.kt
  30. 28 16
      app/src/main/java/com/nextcloud/talk/utils/DrawableUtils.kt
  31. 6 5
      app/src/main/java/com/nextcloud/talk/utils/LoggingUtils.kt
  32. 71 26
      app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt
  33. 0 2
      app/src/main/java/com/nextcloud/talk/utils/UriUtils.kt
  34. 2 2
      app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt
  35. 37 33
      app/src/main/java/com/nextcloud/talk/utils/ssl/SSLSocketFactoryCompat.kt

+ 105 - 57
app/src/gplay/java/com/nextcloud/talk/services/firebase/MagicFirebaseMessagingService.kt

@@ -104,7 +104,6 @@ class MagicFirebaseMessagingService : FirebaseMessagingService() {
     @Inject
     var eventBus: EventBus? = null
 
-
     override fun onCreate() {
         super.onCreate()
         sharedApplication!!.componentApplication.inject(this)
@@ -148,18 +147,26 @@ class MagicFirebaseMessagingService : FirebaseMessagingService() {
             val pushUtils = PushUtils()
             val privateKey = pushUtils.readKeyFromFile(false) as PrivateKey
             try {
-                signatureVerification = pushUtils.verifySignature(base64DecodedSignature,
-                        base64DecodedSubject)
+                signatureVerification = pushUtils.verifySignature(
+                    base64DecodedSignature,
+                    base64DecodedSubject
+                )
                 if (signatureVerification!!.signatureValid) {
                     val cipher = Cipher.getInstance("RSA/None/PKCS1Padding")
                     cipher.init(Cipher.DECRYPT_MODE, privateKey)
                     val decryptedSubject = cipher.doFinal(base64DecodedSubject)
-                    decryptedPushMessage = LoganSquare.parse(String(decryptedSubject),
-                            DecryptedPushMessage::class.java)
+                    decryptedPushMessage = LoganSquare.parse(
+                        String(decryptedSubject),
+                        DecryptedPushMessage::class.java
+                    )
                     decryptedPushMessage?.apply {
                         timestamp = System.currentTimeMillis()
                         if (delete) {
-                            cancelExistingNotificationWithId(applicationContext, signatureVerification!!.userEntity, notificationId)
+                            cancelExistingNotificationWithId(
+                                applicationContext,
+                                signatureVerification!!.userEntity,
+                                notificationId
+                            )
                         } else if (deleteAll) {
                             cancelAllNotificationsForAccount(applicationContext, signatureVerification!!.userEntity)
                         } else if (type == "call") {
@@ -171,39 +178,66 @@ class MagicFirebaseMessagingService : FirebaseMessagingService() {
                             fullScreenIntent.putExtras(bundle)
 
                             fullScreenIntent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_NEW_TASK
-                            val fullScreenPendingIntent = PendingIntent.getActivity(this@MagicFirebaseMessagingService, 0, fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT)
+                            val fullScreenPendingIntent = PendingIntent.getActivity(
+                                this@MagicFirebaseMessagingService,
+                                0,
+                                fullScreenIntent,
+                                PendingIntent.FLAG_UPDATE_CURRENT
+                            )
 
-                            val audioAttributesBuilder = AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+                            val audioAttributesBuilder =
+                                AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                             audioAttributesBuilder.setUsage(AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST)
 
                             val ringtonePreferencesString: String? = appPreferences!!.callRingtoneUri
                             val soundUri = if (TextUtils.isEmpty(ringtonePreferencesString)) {
-                                Uri.parse("android.resource://" + applicationContext.packageName +
-                                        "/raw/librem_by_feandesign_call")
+                                Uri.parse(
+                                    "android.resource://" + applicationContext.packageName +
+                                        "/raw/librem_by_feandesign_call"
+                                )
                             } else {
                                 try {
-                                    val ringtoneSettings = LoganSquare.parse(ringtonePreferencesString, RingtoneSettings::class.java)
+                                    val ringtoneSettings =
+                                        LoganSquare.parse(ringtonePreferencesString, RingtoneSettings::class.java)
                                     ringtoneSettings.ringtoneUri
                                 } catch (exception: IOException) {
                                     Uri.parse("android.resource://" + applicationContext.packageName + "/raw/librem_by_feandesign_call")
                                 }
                             }
 
-                            val notificationChannelId = NotificationUtils.getNotificationChannelId(applicationContext.resources
-                                    .getString(R.string.nc_notification_channel_calls), applicationContext.resources
-                                    .getString(R.string.nc_notification_channel_calls_description), true,
-                                    NotificationManagerCompat.IMPORTANCE_HIGH, soundUri!!, audioAttributesBuilder.build(), null, false)
+                            val notificationChannelId = NotificationUtils.getNotificationChannelId(
+                                applicationContext.resources
+                                    .getString(R.string.nc_notification_channel_calls),
+                                applicationContext.resources
+                                    .getString(R.string.nc_notification_channel_calls_description),
+                                true,
+                                NotificationManagerCompat.IMPORTANCE_HIGH,
+                                soundUri!!,
+                                audioAttributesBuilder.build(),
+                                null,
+                                false
+                            )
 
-                            createNotificationChannel(applicationContext!!,
-                                    notificationChannelId, applicationContext.resources
-                                    .getString(R.string.nc_notification_channel_calls), applicationContext.resources
-                                    .getString(R.string.nc_notification_channel_calls_description), true,
-                                    NotificationManagerCompat.IMPORTANCE_HIGH, soundUri, audioAttributesBuilder.build(), null, false)
+                            createNotificationChannel(
+                                applicationContext!!,
+                                notificationChannelId,
+                                applicationContext.resources
+                                    .getString(R.string.nc_notification_channel_calls),
+                                applicationContext.resources
+                                    .getString(R.string.nc_notification_channel_calls_description),
+                                true,
+                                NotificationManagerCompat.IMPORTANCE_HIGH,
+                                soundUri,
+                                audioAttributesBuilder.build(),
+                                null,
+                                false
+                            )
 
                             val uri = Uri.parse(signatureVerification!!.userEntity.baseUrl)
                             val baseUrl = uri.host
 
-                            val notification = NotificationCompat.Builder(this@MagicFirebaseMessagingService, notificationChannelId)
+                            val notification =
+                                NotificationCompat.Builder(this@MagicFirebaseMessagingService, notificationChannelId)
                                     .setPriority(NotificationCompat.PRIORITY_HIGH)
                                     .setCategory(NotificationCompat.CATEGORY_CALL)
                                     .setSmallIcon(R.drawable.ic_call_black_24dp)
@@ -213,7 +247,7 @@ class MagicFirebaseMessagingService : FirebaseMessagingService() {
                                     .setContentTitle(EmojiCompat.get().process(decryptedPushMessage!!.subject))
                                     .setAutoCancel(true)
                                     .setOngoing(true)
-                                    //.setTimeoutAfter(45000L)
+                                    // .setTimeoutAfter(45000L)
                                     .setContentIntent(fullScreenPendingIntent)
                                     .setFullScreenIntent(fullScreenPendingIntent, true)
                                     .setSound(soundUri)
@@ -224,10 +258,12 @@ class MagicFirebaseMessagingService : FirebaseMessagingService() {
                             startForeground(decryptedPushMessage!!.timestamp.toInt(), notification)
                         } else {
                             val messageData = Data.Builder()
-                                    .putString(BundleKeys.KEY_NOTIFICATION_SUBJECT, subject)
-                                    .putString(BundleKeys.KEY_NOTIFICATION_SIGNATURE, signature)
+                                .putString(BundleKeys.KEY_NOTIFICATION_SUBJECT, subject)
+                                .putString(BundleKeys.KEY_NOTIFICATION_SIGNATURE, signature)
+                                .build()
+                            val pushNotificationWork =
+                                OneTimeWorkRequest.Builder(NotificationWorker::class.java).setInputData(messageData)
                                     .build()
-                            val pushNotificationWork = OneTimeWorkRequest.Builder(NotificationWorker::class.java).setInputData(messageData).build()
                             WorkManager.getInstance().enqueue(pushNotificationWork)
                         }
                     }
@@ -244,47 +280,59 @@ class MagicFirebaseMessagingService : FirebaseMessagingService() {
         }
     }
 
-    private fun checkIfCallIsActive(signatureVerification: SignatureVerification, decryptedPushMessage: DecryptedPushMessage) {
-        val ncApi = retrofit!!.newBuilder().client(okHttpClient!!.newBuilder().cookieJar(JavaNetCookieJar(CookieManager())).build()).build().create(NcApi::class.java)
+    private fun checkIfCallIsActive(
+        signatureVerification: SignatureVerification,
+        decryptedPushMessage: DecryptedPushMessage
+    ) {
+        val ncApi = retrofit!!.newBuilder()
+            .client(okHttpClient!!.newBuilder().cookieJar(JavaNetCookieJar(CookieManager())).build()).build()
+            .create(NcApi::class.java)
         var hasParticipantsInCall = false
         var inCallOnDifferentDevice = false
 
-        ncApi.getPeersForCall(ApiUtils.getCredentials(signatureVerification.userEntity.username, signatureVerification.userEntity.token),
-                ApiUtils.getUrlForCall(signatureVerification.userEntity.baseUrl,
-                        decryptedPushMessage.id))
-                .takeWhile {
-                    isServiceInForeground
+        ncApi.getPeersForCall(
+            ApiUtils.getCredentials(signatureVerification.userEntity.username, signatureVerification.userEntity.token),
+            ApiUtils.getUrlForCall(
+                signatureVerification.userEntity.baseUrl,
+                decryptedPushMessage.id
+            )
+        )
+            .takeWhile {
+                isServiceInForeground
+            }
+            .subscribeOn(Schedulers.io())
+            .subscribe(object : Observer<ParticipantsOverall> {
+                override fun onSubscribe(d: Disposable) {
                 }
-                .subscribeOn(Schedulers.io())
-                .subscribe(object : Observer<ParticipantsOverall> {
-                    override fun onSubscribe(d: Disposable) {
-                    }
 
-                    override fun onNext(participantsOverall: ParticipantsOverall) {
-                        val participantList: List<Participant> = participantsOverall.ocs.data
-                        hasParticipantsInCall = participantList.isNotEmpty()
-                        if (!hasParticipantsInCall) {
-                            for (participant in participantList) {
-                                if (participant.userId == signatureVerification.userEntity.userId) {
-                                    inCallOnDifferentDevice = true
-                                    break
-                                }
+                override fun onNext(participantsOverall: ParticipantsOverall) {
+                    val participantList: List<Participant> = participantsOverall.ocs.data
+                    hasParticipantsInCall = participantList.isNotEmpty()
+                    if (!hasParticipantsInCall) {
+                        for (participant in participantList) {
+                            if (participant.userId == signatureVerification.userEntity.userId) {
+                                inCallOnDifferentDevice = true
+                                break
                             }
                         }
+                    }
 
-                        if (!hasParticipantsInCall || inCallOnDifferentDevice) {
-                            stopForeground(true)
-                            handler.removeCallbacksAndMessages(null)
-                        } else if (isServiceInForeground) {
-                            handler.postDelayed({
+                    if (!hasParticipantsInCall || inCallOnDifferentDevice) {
+                        stopForeground(true)
+                        handler.removeCallbacksAndMessages(null)
+                    } else if (isServiceInForeground) {
+                        handler.postDelayed(
+                            {
                                 checkIfCallIsActive(signatureVerification, decryptedPushMessage)
-                            }, 5000)
-                        }
+                            },
+                            5000
+                        )
                     }
+                }
 
-                    override fun onError(e: Throwable) {}
-                    override fun onComplete() {
-                    }
-                })
+                override fun onError(e: Throwable) {}
+                override fun onComplete() {
+                }
+            })
     }
-}
+}

+ 23 - 20
app/src/main/java/com/nextcloud/talk/activities/BaseActivity.kt

@@ -76,8 +76,11 @@ open class BaseActivity : AppCompatActivity() {
         }
     }
 
-    fun showCertificateDialog(cert: X509Certificate, magicTrustManager: MagicTrustManager,
-                              sslErrorHandler: SslErrorHandler?) {
+    fun showCertificateDialog(
+        cert: X509Certificate,
+        magicTrustManager: MagicTrustManager,
+        sslErrorHandler: SslErrorHandler?
+    ) {
         val formatter = DateFormat.getDateInstance(DateFormat.LONG)
         val validFrom = formatter.format(cert.notBefore)
         val validUntil = formatter.format(cert.notAfter)
@@ -101,30 +104,30 @@ open class BaseActivity : AppCompatActivity() {
                 issuedFor = cert.subjectDN.name
             }
 
-            @SuppressLint("StringFormatMatches") val dialogText = String.format(resources
+            @SuppressLint("StringFormatMatches") val dialogText = String.format(
+                resources
                     .getString(R.string.nc_certificate_dialog_text),
-                    issuedBy, issuedFor, validFrom, validUntil)
+                issuedBy, issuedFor, validFrom, validUntil
+            )
 
             LovelyStandardDialog(this)
-                    .setTopColorRes(R.color.nc_darkRed)
-                    .setNegativeButtonColorRes(R.color.nc_darkRed)
-                    .setPositiveButtonColorRes(R.color.colorPrimary)
-                    .setIcon(R.drawable.ic_security_white_24dp)
-                    .setTitle(R.string.nc_certificate_dialog_title)
-                    .setMessage(dialogText)
-                    .setPositiveButton(R.string.nc_yes) { v ->
-                        magicTrustManager.addCertInTrustStore(cert)
-                        sslErrorHandler?.proceed()
-                    }
-                    .setNegativeButton(R.string.nc_no) { view1 ->
-                        sslErrorHandler?.cancel()
-                    }
-                    .show()
-
+                .setTopColorRes(R.color.nc_darkRed)
+                .setNegativeButtonColorRes(R.color.nc_darkRed)
+                .setPositiveButtonColorRes(R.color.colorPrimary)
+                .setIcon(R.drawable.ic_security_white_24dp)
+                .setTitle(R.string.nc_certificate_dialog_title)
+                .setMessage(dialogText)
+                .setPositiveButton(R.string.nc_yes) { v ->
+                    magicTrustManager.addCertInTrustStore(cert)
+                    sslErrorHandler?.proceed()
+                }
+                .setNegativeButton(R.string.nc_no) { view1 ->
+                    sslErrorHandler?.cancel()
+                }
+                .show()
         } catch (e: CertificateParsingException) {
             Log.d(TAG, "Failed to parse the certificate")
         }
-
     }
 
     @Subscribe(threadMode = ThreadMode.MAIN)

+ 22 - 17
app/src/main/java/com/nextcloud/talk/activities/FullScreenImageActivity.kt

@@ -38,7 +38,6 @@ import pl.droidsonroids.gif.GifDrawable
 import pl.droidsonroids.gif.GifImageView
 import java.io.File
 
-
 class FullScreenImageActivity : AppCompatActivity() {
 
     private lateinit var path: String
@@ -55,9 +54,11 @@ class FullScreenImageActivity : AppCompatActivity() {
 
     override fun onOptionsItemSelected(item: MenuItem): Boolean {
         return if (item.itemId == R.id.share) {
-            val shareUri = FileProvider.getUriForFile(this,
-                    BuildConfig.APPLICATION_ID,
-                    File(path))
+            val shareUri = FileProvider.getUriForFile(
+                this,
+                BuildConfig.APPLICATION_ID,
+                File(path)
+            )
 
             val shareIntent: Intent = Intent().apply {
                 action = Intent.ACTION_SEND
@@ -78,19 +79,19 @@ class FullScreenImageActivity : AppCompatActivity() {
 
         setContentView(R.layout.activity_full_screen_image)
         setSupportActionBar(findViewById(R.id.imageview_toolbar))
-        supportActionBar?.setDisplayShowTitleEnabled(false);
+        supportActionBar?.setDisplayShowTitleEnabled(false)
 
         imageWrapperView = findViewById(R.id.image_wrapper_view)
         photoView = findViewById(R.id.photo_view)
         gifView = findViewById(R.id.gif_view)
 
-        photoView.setOnPhotoTapListener{ view, x, y ->
+        photoView.setOnPhotoTapListener { view, x, y ->
             toggleFullscreen()
         }
-        photoView.setOnOutsidePhotoTapListener{
+        photoView.setOnOutsidePhotoTapListener {
             toggleFullscreen()
         }
-        gifView.setOnClickListener{
+        gifView.setOnClickListener {
             toggleFullscreen()
         }
 
@@ -115,29 +116,33 @@ class FullScreenImageActivity : AppCompatActivity() {
         }
     }
 
-    private fun toggleFullscreen(){
-        showFullscreen = !showFullscreen;
-        if (showFullscreen){
+    private fun toggleFullscreen() {
+        showFullscreen = !showFullscreen
+        if (showFullscreen) {
             hideSystemUI()
             supportActionBar?.hide()
-        } else{
+        } else {
             showSystemUI()
             supportActionBar?.show()
         }
     }
 
     private fun hideSystemUI() {
-        window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE
+        window.decorView.systemUiVisibility = (
+            View.SYSTEM_UI_FLAG_IMMERSIVE
                 or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                 or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                 or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                 or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
-                or View.SYSTEM_UI_FLAG_FULLSCREEN)
+                or View.SYSTEM_UI_FLAG_FULLSCREEN
+            )
     }
 
     private fun showSystemUI() {
-        window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+        window.decorView.systemUiVisibility = (
+            View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                 or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
-                or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
+                or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+            )
     }
-}
+}

+ 16 - 12
app/src/main/java/com/nextcloud/talk/activities/FullScreenMediaActivity.kt

@@ -22,7 +22,6 @@ package com.nextcloud.talk.activities
 
 import android.content.Intent
 import android.os.Bundle
-import android.util.Log
 import android.view.Menu
 import android.view.MenuItem
 import android.view.View
@@ -33,7 +32,6 @@ import autodagger.AutoInjector
 import com.google.android.exoplayer2.MediaItem
 import com.google.android.exoplayer2.Player
 import com.google.android.exoplayer2.SimpleExoPlayer
-import com.google.android.exoplayer2.ui.PlayerControlView
 import com.google.android.exoplayer2.ui.StyledPlayerView
 import com.nextcloud.talk.BuildConfig
 import com.nextcloud.talk.R
@@ -54,9 +52,11 @@ class FullScreenMediaActivity : AppCompatActivity(), Player.EventListener {
 
     override fun onOptionsItemSelected(item: MenuItem): Boolean {
         return if (item.itemId == R.id.share) {
-            val shareUri = FileProvider.getUriForFile(this,
-                    BuildConfig.APPLICATION_ID,
-                    File(path))
+            val shareUri = FileProvider.getUriForFile(
+                this,
+                BuildConfig.APPLICATION_ID,
+                File(path)
+            )
 
             val shareIntent: Intent = Intent().apply {
                 action = Intent.ACTION_SEND
@@ -82,11 +82,11 @@ class FullScreenMediaActivity : AppCompatActivity(), Player.EventListener {
 
         setContentView(R.layout.activity_full_screen_media)
         setSupportActionBar(findViewById(R.id.mediaview_toolbar))
-        supportActionBar?.setDisplayShowTitleEnabled(false);
+        supportActionBar?.setDisplayShowTitleEnabled(false)
 
         playerView = findViewById(R.id.player_view)
 
-        window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+        window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
 
         playerView.showController()
         if (isAudioOnly) {
@@ -121,7 +121,7 @@ class FullScreenMediaActivity : AppCompatActivity(), Player.EventListener {
 
     private fun initializePlayer() {
         player = SimpleExoPlayer.Builder(applicationContext).build()
-        playerView.player = player;
+        playerView.player = player
         player.playWhenReady = true
         player.addListener(this)
     }
@@ -131,17 +131,21 @@ class FullScreenMediaActivity : AppCompatActivity(), Player.EventListener {
     }
 
     private fun hideSystemUI() {
-        window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE
+        window.decorView.systemUiVisibility = (
+            View.SYSTEM_UI_FLAG_IMMERSIVE
                 or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                 or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                 or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                 or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
-                or View.SYSTEM_UI_FLAG_FULLSCREEN)
+                or View.SYSTEM_UI_FLAG_FULLSCREEN
+            )
     }
 
     private fun showSystemUI() {
-        window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+        window.decorView.systemUiVisibility = (
+            View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                 or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
-                or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
+                or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+            )
     }
 }

+ 8 - 9
app/src/main/java/com/nextcloud/talk/activities/FullScreenTextViewerActivity.kt

@@ -34,7 +34,6 @@ import com.nextcloud.talk.application.NextcloudTalkApplication
 import io.noties.markwon.Markwon
 import java.io.File
 
-
 @AutoInjector(NextcloudTalkApplication::class)
 class FullScreenTextViewerActivity : AppCompatActivity() {
 
@@ -48,9 +47,11 @@ class FullScreenTextViewerActivity : AppCompatActivity() {
 
     override fun onOptionsItemSelected(item: MenuItem): Boolean {
         return if (item.itemId == R.id.share) {
-            val shareUri = FileProvider.getUriForFile(this,
-                    BuildConfig.APPLICATION_ID,
-                    File(path))
+            val shareUri = FileProvider.getUriForFile(
+                this,
+                BuildConfig.APPLICATION_ID,
+                File(path)
+            )
 
             val shareIntent: Intent = Intent().apply {
                 action = Intent.ACTION_SEND
@@ -71,8 +72,7 @@ class FullScreenTextViewerActivity : AppCompatActivity() {
 
         setContentView(R.layout.activity_full_screen_text)
         setSupportActionBar(findViewById(R.id.textview_toolbar))
-        supportActionBar?.setDisplayShowTitleEnabled(false);
-
+        supportActionBar?.setDisplayShowTitleEnabled(false)
         textView = findViewById(R.id.text_view)
 
         val fileName = intent.getStringExtra("FILE_NAME")
@@ -81,13 +81,12 @@ class FullScreenTextViewerActivity : AppCompatActivity() {
         var text = readFile(path)
 
         if (isMarkdown) {
-            val markwon = Markwon.create(applicationContext);
-            markwon.setMarkdown(textView, text);
+            val markwon = Markwon.create(applicationContext)
+            markwon.setMarkdown(textView, text)
         } else {
             textView.text = text
         }
     }
 
     private fun readFile(fileName: String) = File(fileName).inputStream().readBytes().toString(Charsets.UTF_8)
-
 }

+ 19 - 11
app/src/main/java/com/nextcloud/talk/activities/MagicCallActivity.kt

@@ -48,7 +48,7 @@ class MagicCallActivity : BaseActivity() {
 
     @BindView(R.id.controller_container)
     lateinit var container: ViewGroup
-    
+
     @BindView(R.id.chatControllerView)
     lateinit var chatContainer: ViewGroup
 
@@ -60,10 +60,12 @@ class MagicCallActivity : BaseActivity() {
         NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
 
         requestWindowFeature(Window.FEATURE_NO_TITLE)
-        window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN or
+        window.addFlags(
+            WindowManager.LayoutParams.FLAG_FULLSCREEN or
                 WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON or
                 WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
-                WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON)
+                WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
+        )
         window.decorView.systemUiVisibility = systemUiVisibility
 
         setContentView(R.layout.activity_magic_call)
@@ -74,26 +76,32 @@ class MagicCallActivity : BaseActivity() {
 
         if (!router!!.hasRootController()) {
             if (intent.getBooleanExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL, false)) {
-                router!!.setRoot(RouterTransaction.with(CallNotificationController(intent.extras))
+                router!!.setRoot(
+                    RouterTransaction.with(CallNotificationController(intent.extras))
                         .pushChangeHandler(HorizontalChangeHandler())
-                        .popChangeHandler(HorizontalChangeHandler()))
+                        .popChangeHandler(HorizontalChangeHandler())
+                )
             } else {
-                router!!.setRoot(RouterTransaction.with(CallController(intent.extras))
+                router!!.setRoot(
+                    RouterTransaction.with(CallController(intent.extras))
                         .pushChangeHandler(HorizontalChangeHandler())
-                        .popChangeHandler(HorizontalChangeHandler()))
+                        .popChangeHandler(HorizontalChangeHandler())
+                )
             }
         }
 
         val extras = intent.extras ?: Bundle()
         extras.putBoolean("showToggleChat", true)
-        
+
         chatController = ChatController(extras)
         chatRouter = Conductor.attachRouter(this, chatContainer, savedInstanceState)
-        chatRouter!!.setRoot(RouterTransaction.with(chatController)
+        chatRouter!!.setRoot(
+            RouterTransaction.with(chatController)
                 .pushChangeHandler(HorizontalChangeHandler())
-                .popChangeHandler(HorizontalChangeHandler()))
+                .popChangeHandler(HorizontalChangeHandler())
+        )
     }
-    
+
     fun showChat() {
         chatContainer.visibility = View.VISIBLE
         container.visibility = View.GONE

+ 111 - 67
app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt

@@ -79,23 +79,31 @@ class MainActivity : BaseActivity(), ActionBarProvider {
 
     @BindView(R.id.appBar)
     lateinit var appBar: AppBarLayout
+
     @BindView(R.id.toolbar)
     lateinit var toolbar: MaterialToolbar
+
     @BindView(R.id.home_toolbar)
     lateinit var searchCardView: MaterialCardView
+
     @BindView(R.id.search_text)
     lateinit var searchInputText: MaterialTextView
+
     @BindView(R.id.switch_account_button)
     lateinit var settingsButton: MaterialButton
+
     @BindView(R.id.controller_container)
     lateinit var container: ViewGroup
 
     @Inject
     lateinit var userUtils: UserUtils
+
     @Inject
     lateinit var dataStore: ReactiveEntityStore<Persistable>
+
     @Inject
     lateinit var sqlCipherDatabaseSource: SqlCipherDatabaseSource
+
     @Inject
     lateinit var ncApi: NcApi
 
@@ -124,39 +132,53 @@ class MainActivity : BaseActivity(), ActionBarProvider {
 
         if (intent.hasExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL)) {
             if (!router!!.hasRootController()) {
-                router!!.setRoot(RouterTransaction.with(ConversationsListController())
+                router!!.setRoot(
+                    RouterTransaction.with(ConversationsListController())
                         .pushChangeHandler(HorizontalChangeHandler())
-                        .popChangeHandler(HorizontalChangeHandler()))
+                        .popChangeHandler(HorizontalChangeHandler())
+                )
             }
             onNewIntent(intent)
         } else if (!router!!.hasRootController()) {
             if (hasDb) {
                 if (userUtils.anyUserExists()) {
-                    router!!.setRoot(RouterTransaction.with(ConversationsListController())
+                    router!!.setRoot(
+                        RouterTransaction.with(ConversationsListController())
                             .pushChangeHandler(HorizontalChangeHandler())
-                            .popChangeHandler(HorizontalChangeHandler()))
+                            .popChangeHandler(HorizontalChangeHandler())
+                    )
                 } else {
                     if (!TextUtils.isEmpty(resources.getString(R.string.weblogin_url))) {
-                        router!!.pushController(RouterTransaction.with(
-                                WebViewLoginController(resources.getString(R.string.weblogin_url), false))
+                        router!!.pushController(
+                            RouterTransaction.with(
+                                WebViewLoginController(resources.getString(R.string.weblogin_url), false)
+                            )
                                 .pushChangeHandler(HorizontalChangeHandler())
-                                .popChangeHandler(HorizontalChangeHandler()))
+                                .popChangeHandler(HorizontalChangeHandler())
+                        )
                     } else {
-                        router!!.setRoot(RouterTransaction.with(ServerSelectionController())
+                        router!!.setRoot(
+                            RouterTransaction.with(ServerSelectionController())
                                 .pushChangeHandler(HorizontalChangeHandler())
-                                .popChangeHandler(HorizontalChangeHandler()))
+                                .popChangeHandler(HorizontalChangeHandler())
+                        )
                     }
                 }
             } else {
                 if (!TextUtils.isEmpty(resources.getString(R.string.weblogin_url))) {
-                    router!!.pushController(RouterTransaction.with(
-                            WebViewLoginController(resources.getString(R.string.weblogin_url), false))
+                    router!!.pushController(
+                        RouterTransaction.with(
+                            WebViewLoginController(resources.getString(R.string.weblogin_url), false)
+                        )
                             .pushChangeHandler(HorizontalChangeHandler())
-                            .popChangeHandler(HorizontalChangeHandler()))
+                            .popChangeHandler(HorizontalChangeHandler())
+                    )
                 } else {
-                    router!!.setRoot(RouterTransaction.with(ServerSelectionController())
+                    router!!.setRoot(
+                        RouterTransaction.with(ServerSelectionController())
                             .pushChangeHandler(HorizontalChangeHandler())
-                            .popChangeHandler(HorizontalChangeHandler()))
+                            .popChangeHandler(HorizontalChangeHandler())
+                    )
                 }
             }
         }
@@ -167,7 +189,7 @@ class MainActivity : BaseActivity(), ActionBarProvider {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
             checkIfWeAreSecure()
         }
-        
+
         handleActionFromContact(intent)
     }
 
@@ -182,7 +204,7 @@ class MainActivity : BaseActivity(), ActionBarProvider {
                     // userId @ server
                     userId = cursor.getString(cursor.getColumnIndex(ContactsContract.Data.DATA1))
                 }
-                
+
                 cursor.close()
             }
 
@@ -193,65 +215,82 @@ class MainActivity : BaseActivity(), ActionBarProvider {
                     if (userUtils.currentUser?.baseUrl?.endsWith(baseUrl) == true) {
                         startConversation(user)
                     } else {
-                        Snackbar.make(container, R.string.nc_phone_book_integration_account_not_found, Snackbar
-                                .LENGTH_LONG).show()
+                        Snackbar.make(
+                            container, R.string.nc_phone_book_integration_account_not_found,
+                            Snackbar.LENGTH_LONG
+                        ).show()
                     }
                 }
             }
         }
     }
-    
+
     private fun startConversation(userId: String) {
         val roomType = "1"
         val currentUser = userUtils.currentUser ?: return
 
         val credentials = ApiUtils.getCredentials(currentUser.username, currentUser.token)
-        val retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(currentUser.baseUrl, roomType,
-                userId, null)
-        ncApi.createRoom(credentials,
-                retrofitBucket.url, retrofitBucket.queryMap)
-                .subscribeOn(Schedulers.io())
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribe(object : Observer<RoomOverall> {
-                    override fun onSubscribe(d: Disposable) {}
-                    override fun onNext(roomOverall: RoomOverall) {
-                        val conversationIntent = Intent(context, MagicCallActivity::class.java)
-                        val bundle = Bundle()
-                        bundle.putParcelable(KEY_USER_ENTITY, currentUser)
-                        bundle.putString(KEY_ROOM_TOKEN, roomOverall.ocs.data.token)
-                        bundle.putString(KEY_ROOM_ID, roomOverall.ocs.data.roomId)
-                        if (currentUser.hasSpreedFeatureCapability("chat-v2")) {
-                            ncApi.getRoom(credentials,
-                                    ApiUtils.getRoom(currentUser.baseUrl,
-                                            roomOverall.ocs.data.token))
-                                    .subscribeOn(Schedulers.io())
-                                    .observeOn(AndroidSchedulers.mainThread())
-                                    .subscribe(object : Observer<RoomOverall> {
-                                        override fun onSubscribe(d: Disposable) {}
-                                        override fun onNext(roomOverall: RoomOverall) {
-                                            bundle.putParcelable(KEY_ACTIVE_CONVERSATION,
-                                                    Parcels.wrap(roomOverall.ocs.data))
-                                            remapChatController(router!!, currentUser.id,
-                                                    roomOverall.ocs.data.token, bundle, true)
-                                        }
-
-                                        override fun onError(e: Throwable) {}
-                                        override fun onComplete() {}
-                                    })
-                        } else {
-                            conversationIntent.putExtras(bundle)
-                            startActivity(conversationIntent)
-                            Handler().postDelayed({
+        val retrofitBucket = ApiUtils.getRetrofitBucketForCreateRoom(
+            currentUser.baseUrl, roomType,
+            userId, null
+        )
+        ncApi.createRoom(
+            credentials,
+            retrofitBucket.url, retrofitBucket.queryMap
+        )
+            .subscribeOn(Schedulers.io())
+            .observeOn(AndroidSchedulers.mainThread())
+            .subscribe(object : Observer<RoomOverall> {
+                override fun onSubscribe(d: Disposable) {}
+                override fun onNext(roomOverall: RoomOverall) {
+                    val conversationIntent = Intent(context, MagicCallActivity::class.java)
+                    val bundle = Bundle()
+                    bundle.putParcelable(KEY_USER_ENTITY, currentUser)
+                    bundle.putString(KEY_ROOM_TOKEN, roomOverall.ocs.data.token)
+                    bundle.putString(KEY_ROOM_ID, roomOverall.ocs.data.roomId)
+                    if (currentUser.hasSpreedFeatureCapability("chat-v2")) {
+                        ncApi.getRoom(
+                            credentials,
+                            ApiUtils.getRoom(
+                                currentUser.baseUrl,
+                                roomOverall.ocs.data.token
+                            )
+                        )
+                            .subscribeOn(Schedulers.io())
+                            .observeOn(AndroidSchedulers.mainThread())
+                            .subscribe(object : Observer<RoomOverall> {
+                                override fun onSubscribe(d: Disposable) {}
+                                override fun onNext(roomOverall: RoomOverall) {
+                                    bundle.putParcelable(
+                                        KEY_ACTIVE_CONVERSATION,
+                                        Parcels.wrap(roomOverall.ocs.data)
+                                    )
+                                    remapChatController(
+                                        router!!, currentUser.id,
+                                        roomOverall.ocs.data.token, bundle, true
+                                    )
+                                }
+
+                                override fun onError(e: Throwable) {}
+                                override fun onComplete() {}
+                            })
+                    } else {
+                        conversationIntent.putExtras(bundle)
+                        startActivity(conversationIntent)
+                        Handler().postDelayed(
+                            {
                                 if (!isDestroyed) {
                                     router!!.popCurrentController()
                                 }
-                            }, 100)
-                        }
+                            },
+                            100
+                        )
                     }
+                }
 
-                    override fun onError(e: Throwable) {}
-                    override fun onComplete() {}
-                })
+                override fun onError(e: Throwable) {}
+                override fun onComplete() {}
+            })
     }
 
     @RequiresApi(api = Build.VERSION_CODES.M)
@@ -260,16 +299,17 @@ class MainActivity : BaseActivity(), ActionBarProvider {
         if (keyguardManager.isKeyguardSecure && appPreferences.isScreenLocked) {
             if (!SecurityUtils.checkIfWeAreAuthenticated(appPreferences.screenLockTimeout)) {
                 if (router != null && router!!.getControllerWithTag(LockedController.TAG) == null) {
-                    router!!.pushController(RouterTransaction.with(LockedController())
+                    router!!.pushController(
+                        RouterTransaction.with(LockedController())
                             .pushChangeHandler(VerticalChangeHandler())
                             .popChangeHandler(VerticalChangeHandler())
-                            .tag(LockedController.TAG))
+                            .tag(LockedController.TAG)
+                    )
                 }
             }
         }
     }
 
-
     override fun onNewIntent(intent: Intent) {
         super.onNewIntent(intent)
 
@@ -277,12 +317,16 @@ class MainActivity : BaseActivity(), ActionBarProvider {
 
         if (intent.hasExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL)) {
             if (intent.getBooleanExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL, false)) {
-                router!!.pushController(RouterTransaction.with(CallNotificationController(intent.extras))
+                router!!.pushController(
+                    RouterTransaction.with(CallNotificationController(intent.extras))
                         .pushChangeHandler(HorizontalChangeHandler())
-                        .popChangeHandler(HorizontalChangeHandler()))
+                        .popChangeHandler(HorizontalChangeHandler())
+                )
             } else {
-                ConductorRemapping.remapChatController(router!!, intent.getLongExtra(BundleKeys.KEY_INTERNAL_USER_ID, -1),
-                        intent.getStringExtra(BundleKeys.KEY_ROOM_TOKEN), intent.extras!!, false)
+                ConductorRemapping.remapChatController(
+                    router!!, intent.getLongExtra(BundleKeys.KEY_INTERNAL_USER_ID, -1),
+                    intent.getStringExtra(BundleKeys.KEY_ROOM_TOKEN), intent.extras!!, false
+                )
             }
         }
     }

+ 32 - 31
app/src/main/java/com/nextcloud/talk/adapters/messages/MagicIncomingTextMessageViewHolder.kt

@@ -39,7 +39,6 @@ import autodagger.AutoInjector
 import butterknife.BindView
 import butterknife.ButterKnife
 import coil.load
-import coil.transform.CircleCropTransformation
 import com.amulyakhare.textdrawable.TextDrawable
 import com.facebook.drawee.view.SimpleDraweeView
 import com.nextcloud.talk.R
@@ -51,7 +50,6 @@ import com.nextcloud.talk.utils.DisplayUtils
 import com.nextcloud.talk.utils.TextMatchers
 import com.nextcloud.talk.utils.preferences.AppPreferences
 import com.stfalcon.chatkit.messages.MessageHolders
-import com.stfalcon.chatkit.utils.DateFormatter
 import javax.inject.Inject
 
 @AutoInjector(NextcloudTalkApplication::class)
@@ -104,8 +102,8 @@ class MagicIncomingTextMessageViewHolder(incomingView: View) : MessageHolders
 
     init {
         ButterKnife.bind(
-                this,
-                itemView
+            this,
+            itemView
         )
     }
 
@@ -131,13 +129,13 @@ class MagicIncomingTextMessageViewHolder(incomingView: View) : MessageHolders
                 messageUserAvatarView?.setImageDrawable(DisplayUtils.getRoundedDrawable(layerDrawable))
             } else if (message.actorType == "bots") {
                 val drawable = TextDrawable.builder()
-                        .beginConfig()
-                        .bold()
-                        .endConfig()
-                        .buildRound(
-                                ">",
-                                context!!.resources.getColor(R.color.black)
-                        )
+                    .beginConfig()
+                    .bold()
+                    .endConfig()
+                    .buildRound(
+                        ">",
+                        context!!.resources.getColor(R.color.black)
+                    )
                 messageUserAvatarView!!.visibility = View.VISIBLE
                 messageUserAvatarView?.setImageDrawable(drawable)
             }
@@ -165,9 +163,9 @@ class MagicIncomingTextMessageViewHolder(incomingView: View) : MessageHolders
         }
 
         val bubbleDrawable = DisplayUtils.getMessageSelector(
-                bgBubbleColor,
-                resources.getColor(R.color.transparent),
-                bgBubbleColor, bubbleResource
+            bgBubbleColor,
+            resources.getColor(R.color.transparent),
+            bgBubbleColor, bubbleResource
         )
         ViewCompat.setBackground(bubble, bubbleDrawable)
 
@@ -187,23 +185,23 @@ class MagicIncomingTextMessageViewHolder(incomingView: View) : MessageHolders
                     if (individualHashMap["type"] == "user" || individualHashMap["type"] == "guest" || individualHashMap["type"] == "call") {
                         if (individualHashMap["id"] == message.activeUser!!.userId) {
                             messageString = DisplayUtils.searchAndReplaceWithMentionSpan(
-                                    messageText!!.context,
-                                    messageString,
-                                    individualHashMap["id"]!!,
-                                    individualHashMap["name"]!!,
-                                    individualHashMap["type"]!!,
-                                    message.activeUser!!,
-                                    R.xml.chip_you
+                                messageText!!.context,
+                                messageString,
+                                individualHashMap["id"]!!,
+                                individualHashMap["name"]!!,
+                                individualHashMap["type"]!!,
+                                message.activeUser!!,
+                                R.xml.chip_you
                             )
                         } else {
                             messageString = DisplayUtils.searchAndReplaceWithMentionSpan(
-                                    messageText!!.context,
-                                    messageString,
-                                    individualHashMap["id"]!!,
-                                    individualHashMap["name"]!!,
-                                    individualHashMap["type"]!!,
-                                    message.activeUser!!,
-                                    R.xml.chip_others
+                                messageText!!.context,
+                                messageString,
+                                individualHashMap["id"]!!,
+                                individualHashMap["name"]!!,
+                                individualHashMap["type"]!!,
+                                message.activeUser!!,
+                                R.xml.chip_others
                             )
                         }
                     } else if (individualHashMap["type"] == "file") {
@@ -231,18 +229,21 @@ class MagicIncomingTextMessageViewHolder(incomingView: View) : MessageHolders
             parentChatMessage.imageUrl?.let {
                 quotedMessagePreview?.visibility = View.VISIBLE
                 quotedMessagePreview?.load(it) {
-                    addHeader("Authorization", ApiUtils.getCredentials(message.activeUser.username, message.activeUser.token))
+                    addHeader(
+                        "Authorization",
+                        ApiUtils.getCredentials(message.activeUser.username, message.activeUser.token)
+                    )
                 }
             } ?: run {
                 quotedMessagePreview?.visibility = View.GONE
             }
             quotedUserName?.text = parentChatMessage.actorDisplayName
-                    ?: context!!.getText(R.string.nc_nick_guest)
+                ?: context!!.getText(R.string.nc_nick_guest)
             quotedMessage?.text = parentChatMessage.text
 
             quotedUserName?.setTextColor(context!!.resources.getColor(R.color.textColorMaxContrast))
 
-            if(parentChatMessage.actorId?.equals(message.activeUser.userId) == true) {
+            if (parentChatMessage.actorId?.equals(message.activeUser.userId) == true) {
                 quoteColoredView?.setBackgroundResource(R.color.colorPrimary)
             } else {
                 quoteColoredView?.setBackgroundResource(R.color.textColorMaxContrast)

+ 36 - 26
app/src/main/java/com/nextcloud/talk/adapters/messages/MagicOutcomingTextMessageViewHolder.kt

@@ -36,7 +36,6 @@ import autodagger.AutoInjector
 import butterknife.BindView
 import butterknife.ButterKnife
 import coil.load
-import coil.transform.CircleCropTransformation
 import com.google.android.flexbox.FlexboxLayout
 import com.nextcloud.talk.R
 import com.nextcloud.talk.application.NextcloudTalkApplication
@@ -48,8 +47,7 @@ import com.nextcloud.talk.utils.DisplayUtils.getMessageSelector
 import com.nextcloud.talk.utils.DisplayUtils.searchAndReplaceWithMentionSpan
 import com.nextcloud.talk.utils.TextMatchers
 import com.stfalcon.chatkit.messages.MessageHolders.OutcomingTextMessageViewHolder
-import com.stfalcon.chatkit.utils.DateFormatter
-import java.util.*
+import java.util.HashMap
 import javax.inject.Inject
 
 @AutoInjector(NextcloudTalkApplication::class)
@@ -57,6 +55,7 @@ class MagicOutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessage
     @JvmField
     @BindView(R.id.messageText)
     var messageText: EmojiTextView? = null
+
     @JvmField
     @BindView(R.id.messageTime)
     var messageTimeView: TextView? = null
@@ -104,20 +103,26 @@ class MagicOutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessage
             for (key in messageParameters.keys) {
                 val individualHashMap: HashMap<String, String>? = message.messageParameters[key]
                 if (individualHashMap != null) {
-                    if (individualHashMap["type"] == "user" || (individualHashMap["type"]
-                                    == "guest") || individualHashMap["type"] == "call") {
-                        messageString = searchAndReplaceWithMentionSpan(messageText!!.context,
-                                messageString,
-                                individualHashMap["id"]!!,
-                                individualHashMap["name"]!!,
-                                individualHashMap["type"]!!,
-                                message.activeUser,
-                                R.xml.chip_others)
+                    if (individualHashMap["type"] == "user" || (
+                        individualHashMap["type"] == "guest"
+                        ) || individualHashMap["type"] == "call"
+                    ) {
+                        messageString = searchAndReplaceWithMentionSpan(
+                            messageText!!.context,
+                            messageString,
+                            individualHashMap["id"]!!,
+                            individualHashMap["name"]!!,
+                            individualHashMap["type"]!!,
+                            message.activeUser,
+                            R.xml.chip_others
+                        )
                     } else if (individualHashMap["type"] == "file") {
-                        realView.setOnClickListener(View.OnClickListener { v: View? ->
-                            val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(individualHashMap["link"]))
-                            context!!.startActivity(browserIntent)
-                        })
+                        realView.setOnClickListener(
+                            View.OnClickListener { v: View? ->
+                                val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(individualHashMap["link"]))
+                                context!!.startActivity(browserIntent)
+                            }
+                        )
                     }
                 }
             }
@@ -135,17 +140,19 @@ class MagicOutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessage
         }
         if (message.isGrouped) {
             val bubbleDrawable = getMessageSelector(
-                    bgBubbleColor,
-                    resources.getColor(R.color.transparent),
-                    bgBubbleColor,
-                    R.drawable.shape_grouped_outcoming_message)
+                bgBubbleColor,
+                resources.getColor(R.color.transparent),
+                bgBubbleColor,
+                R.drawable.shape_grouped_outcoming_message
+            )
             ViewCompat.setBackground(bubble, bubbleDrawable)
         } else {
             val bubbleDrawable = getMessageSelector(
-                    bgBubbleColor,
-                    resources.getColor(R.color.transparent),
-                    bgBubbleColor,
-                    R.drawable.shape_outcoming_message)
+                bgBubbleColor,
+                resources.getColor(R.color.transparent),
+                bgBubbleColor,
+                R.drawable.shape_outcoming_message
+            )
             ViewCompat.setBackground(bubble, bubbleDrawable)
         }
         messageText!!.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
@@ -160,13 +167,16 @@ class MagicOutcomingTextMessageViewHolder(itemView: View) : OutcomingTextMessage
             parentChatMessage.imageUrl?.let {
                 quotedMessagePreview?.visibility = View.VISIBLE
                 quotedMessagePreview?.load(it) {
-                    addHeader("Authorization", ApiUtils.getCredentials(message.activeUser.username, message.activeUser.token))
+                    addHeader(
+                        "Authorization",
+                        ApiUtils.getCredentials(message.activeUser.username, message.activeUser.token)
+                    )
                 }
             } ?: run {
                 quotedMessagePreview?.visibility = View.GONE
             }
             quotedUserName?.text = parentChatMessage.actorDisplayName
-                    ?: context!!.getText(R.string.nc_nick_guest)
+                ?: context!!.getText(R.string.nc_nick_guest)
             quotedMessage?.text = parentChatMessage.text
             quotedMessage?.setTextColor(context!!.resources.getColor(R.color.nc_outcoming_text_default))
             quotedUserName?.setTextColor(context!!.resources.getColor(R.color.nc_grey))

+ 44 - 33
app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt

@@ -90,6 +90,7 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
 
     @Inject
     lateinit var appPreferences: AppPreferences
+
     @Inject
     lateinit var okHttpClient: OkHttpClient
     //endregion
@@ -105,8 +106,10 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
                 WebRtcAudioManager.setBlacklistDeviceForOpenSLESUsage(true)
             }
 
-            PeerConnectionFactory.initialize(PeerConnectionFactory.InitializationOptions.builder(this)
-                    .createInitializationOptions())
+            PeerConnectionFactory.initialize(
+                PeerConnectionFactory.InitializationOptions.builder(this)
+                    .createInitializationOptions()
+            )
         } catch (e: UnsatisfiedLinkError) {
             Log.w(TAG, e)
         }
@@ -120,8 +123,8 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
 
         val securityKeyManager = SecurityKeyManager.getInstance()
         val securityKeyConfig = SecurityKeyManagerConfig.Builder()
-                .setEnableDebugLogging(BuildConfig.DEBUG)
-                .build()
+            .setEnableDebugLogging(BuildConfig.DEBUG)
+            .build()
         securityKeyManager.init(this, securityKeyConfig)
 
         initializeWebRtc()
@@ -136,13 +139,15 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
         super.onCreate()
 
         val imagePipelineConfig = ImagePipelineConfig.newBuilder(this)
-                .setNetworkFetcher(OkHttpNetworkFetcherWithCache(okHttpClient))
-                .setMainDiskCacheConfig(DiskCacheConfig.newBuilder(this)
-                        .setMaxCacheSize(0)
-                        .setMaxCacheSizeOnLowDiskSpace(0)
-                        .setMaxCacheSizeOnVeryLowDiskSpace(0)
-                        .build())
-                .build()
+            .setNetworkFetcher(OkHttpNetworkFetcherWithCache(okHttpClient))
+            .setMainDiskCacheConfig(
+                DiskCacheConfig.newBuilder(this)
+                    .setMaxCacheSize(0)
+                    .setMaxCacheSizeOnLowDiskSpace(0)
+                    .setMaxCacheSizeOnVeryLowDiskSpace(0)
+                    .build()
+            )
+            .build()
 
         Fresco.initialize(this, imagePipelineConfig)
         Security.insertProviderAt(Conscrypt.newProvider(), 1)
@@ -152,8 +157,10 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
 
         val pushRegistrationWork = OneTimeWorkRequest.Builder(PushRegistrationWorker::class.java).build()
         val accountRemovalWork = OneTimeWorkRequest.Builder(AccountRemovalWorker::class.java).build()
-        val periodicCapabilitiesUpdateWork = PeriodicWorkRequest.Builder(CapabilitiesWorker::class.java,
-                12, TimeUnit.HOURS).build()
+        val periodicCapabilitiesUpdateWork = PeriodicWorkRequest.Builder(
+            CapabilitiesWorker::class.java,
+            12, TimeUnit.HOURS
+        ).build()
         val capabilitiesUpdateWork = OneTimeWorkRequest.Builder(CapabilitiesWorker::class.java).build()
         val signalingSettingsWork = OneTimeWorkRequest.Builder(SignalingSettingsWorker::class.java).build()
 
@@ -161,7 +168,11 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
         WorkManager.getInstance().enqueue(accountRemovalWork)
         WorkManager.getInstance().enqueue(capabilitiesUpdateWork)
         WorkManager.getInstance().enqueue(signalingSettingsWork)
-        WorkManager.getInstance().enqueueUniquePeriodicWork("DailyCapabilitiesUpdateWork", ExistingPeriodicWorkPolicy.REPLACE, periodicCapabilitiesUpdateWork)
+        WorkManager.getInstance().enqueueUniquePeriodicWork(
+            "DailyCapabilitiesUpdateWork",
+            ExistingPeriodicWorkPolicy.REPLACE,
+            periodicCapabilitiesUpdateWork
+        )
 
         val config = BundledEmojiCompatConfig(this)
         config.setReplaceAll(true)
@@ -176,17 +187,16 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
     }
     //endregion
 
-
     //region Protected methods
     protected fun buildComponent() {
         componentApplication = DaggerNextcloudTalkApplicationComponent.builder()
-                .busModule(BusModule())
-                .contextModule(ContextModule(applicationContext))
-                .databaseModule(DatabaseModule())
-                .restModule(RestModule(applicationContext))
-                .userModule(UserModule())
-                .arbitraryStorageModule(ArbitraryStorageModule())
-                .build()
+            .busModule(BusModule())
+            .contextModule(ContextModule(applicationContext))
+            .databaseModule(DatabaseModule())
+            .restModule(RestModule(applicationContext))
+            .userModule(UserModule())
+            .arbitraryStorageModule(ArbitraryStorageModule())
+            .build()
     }
 
     override fun attachBaseContext(base: Context) {
@@ -196,19 +206,20 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
 
     private fun buildDefaultImageLoader(): ImageLoader {
         return ImageLoader.Builder(applicationContext)
-                .availableMemoryPercentage(0.5) // Use 50% of the application's available memory.
-                .crossfade(true) // Show a short crossfade when loading images from network or disk into an ImageView.
-                .componentRegistry {
-                    if (SDK_INT >= P) {
-                        add(ImageDecoderDecoder(applicationContext))
-                    } else {
-                        add(GifDecoder())
-                    }
-                    add(SvgDecoder(applicationContext))
+            .availableMemoryPercentage(0.5) // Use 50% of the application's available memory.
+            .crossfade(true) // Show a short crossfade when loading images from network or disk into an ImageView.
+            .componentRegistry {
+                if (SDK_INT >= P) {
+                    add(ImageDecoderDecoder(applicationContext))
+                } else {
+                    add(GifDecoder())
                 }
-                .okHttpClient(okHttpClient)
-                .build()
+                add(SvgDecoder(applicationContext))
+            }
+            .okHttpClient(okHttpClient)
+            .build()
     }
+
     companion object {
         private val TAG = NextcloudTalkApplication::class.java.simpleName
         //region Singleton

+ 16 - 18
app/src/main/java/com/nextcloud/talk/controllers/CallNotificationController.java

@@ -44,10 +44,6 @@ import android.widget.ImageView;
 import android.widget.RelativeLayout;
 import android.widget.TextView;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.constraintlayout.widget.ConstraintLayout;
-
 import com.bluelinelabs.conductor.RouterTransaction;
 import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
 import com.bluelinelabs.logansquare.LoganSquare;
@@ -71,7 +67,6 @@ import com.nextcloud.talk.models.RingtoneSettings;
 import com.nextcloud.talk.models.database.UserEntity;
 import com.nextcloud.talk.models.json.conversations.Conversation;
 import com.nextcloud.talk.models.json.conversations.RoomOverall;
-import com.nextcloud.talk.models.json.conversations.RoomsOverall;
 import com.nextcloud.talk.models.json.participants.Participant;
 import com.nextcloud.talk.models.json.participants.ParticipantsOverall;
 import com.nextcloud.talk.utils.ApiUtils;
@@ -94,6 +89,9 @@ import java.util.List;
 
 import javax.inject.Inject;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.constraintlayout.widget.ConstraintLayout;
 import autodagger.AutoInjector;
 import butterknife.BindView;
 import butterknife.OnClick;
@@ -206,13 +204,13 @@ public class CallNotificationController extends BaseController {
         originalBundle.putString(BundleKeys.INSTANCE.getKEY_CONVERSATION_NAME(), currentConversation.getDisplayName());
 
         getRouter().replaceTopController(RouterTransaction.with(new CallController(originalBundle))
-                .popChangeHandler(new HorizontalChangeHandler())
-                .pushChangeHandler(new HorizontalChangeHandler()));
+                                                 .popChangeHandler(new HorizontalChangeHandler())
+                                                 .pushChangeHandler(new HorizontalChangeHandler()));
     }
 
     private void checkIfAnyParticipantsRemainInRoom() {
         ncApi.getPeersForCall(credentials, ApiUtils.getUrlForCall(userBeingCalled.getBaseUrl(),
-                currentConversation.getToken()))
+                                                                  currentConversation.getToken()))
                 .subscribeOn(Schedulers.io())
                 .takeWhile(observable -> !leavingScreen)
                 .subscribe(new Observer<ParticipantsOverall>() {
@@ -261,7 +259,7 @@ public class CallNotificationController extends BaseController {
 
     private void handleFromNotification() {
         boolean isConversationApiV3 = userBeingCalled.hasSpreedFeatureCapability("conversation-v3");
-        if(isConversationApiV3) {
+        if (isConversationApiV3) {
             ncApi.getRoom(credentials, ApiUtils.getRoomV3(userBeingCalled.getBaseUrl(), roomId))
                     .subscribeOn(Schedulers.io())
                     .retry(3)
@@ -279,12 +277,12 @@ public class CallNotificationController extends BaseController {
 
                             boolean hasCallFlags = userBeingCalled.hasSpreedFeatureCapability("conversation-call-flags");
                             if (hasCallFlags) {
-                                if (isInCallWithVideo(currentConversation.callFlag)){
+                                if (isInCallWithVideo(currentConversation.callFlag)) {
                                     incomingCallVoiceOrVideoTextView.setText(String.format(getResources().getString(R.string.nc_call_video),
-                                            getResources().getString(R.string.nc_app_name)));
+                                                                                           getResources().getString(R.string.nc_app_name)));
                                 } else {
                                     incomingCallVoiceOrVideoTextView.setText(String.format(getResources().getString(R.string.nc_call_voice),
-                                            getResources().getString(R.string.nc_app_name)));
+                                                                                           getResources().getString(R.string.nc_app_name)));
                                 }
                             }
                         }
@@ -412,7 +410,7 @@ public class CallNotificationController extends BaseController {
 
                 ImageRequest imageRequest =
                         DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(userBeingCalled.getBaseUrl(),
-                                currentConversation.getName(), R.dimen.avatar_size_very_big), null);
+                                                                                            currentConversation.getName(), R.dimen.avatar_size_very_big), null);
 
                 ImagePipeline imagePipeline = Fresco.getImagePipeline();
                 DataSource<CloseableReference<CloseableImage>> dataSource = imagePipeline.fetchDecodedImage(imageRequest, null);
@@ -422,11 +420,11 @@ public class CallNotificationController extends BaseController {
                     protected void onNewResultImpl(@Nullable Bitmap bitmap) {
                         if (avatarImageView != null) {
                             avatarImageView.getHierarchy().setImage(new BitmapDrawable(bitmap), 100,
-                                    true);
+                                                                    true);
 
                             if (getResources() != null) {
                                 incomingTextRelativeLayout.setBackground(getResources().getDrawable(R.drawable
-                                        .incoming_gradient));
+                                                                                                            .incoming_gradient));
                             }
 
                             if ((AvatarStatusCodeHolder.getInstance().getStatusCode() == 200 || AvatarStatusCodeHolder.getInstance().getStatusCode() == 0) &&
@@ -512,7 +510,7 @@ public class CallNotificationController extends BaseController {
         if (TextUtils.isEmpty(callRingtonePreferenceString)) {
             // play default sound
             ringtoneUri = Uri.parse("android.resource://" + getApplicationContext().getPackageName() +
-                    "/raw/librem_by_feandesign_call");
+                                            "/raw/librem_by_feandesign_call");
         } else {
             try {
                 RingtoneSettings ringtoneSettings = LoganSquare.parse(callRingtonePreferenceString, RingtoneSettings.class);
@@ -520,7 +518,7 @@ public class CallNotificationController extends BaseController {
             } catch (IOException e) {
                 Log.e(TAG, "Failed to parse ringtone settings");
                 ringtoneUri = Uri.parse("android.resource://" + getApplicationContext().getPackageName() +
-                        "/raw/librem_by_feandesign_call");
+                                                "/raw/librem_by_feandesign_call");
             }
         }
 
@@ -531,7 +529,7 @@ public class CallNotificationController extends BaseController {
 
                 mediaPlayer.setLooping(true);
                 AudioAttributes audioAttributes = new AudioAttributes.Builder().setContentType(AudioAttributes
-                        .CONTENT_TYPE_SONIFICATION).setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE).build();
+                                                                                                       .CONTENT_TYPE_SONIFICATION).setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE).build();
                 mediaPlayer.setAudioAttributes(audioAttributes);
 
                 mediaPlayer.setOnPreparedListener(mp -> mediaPlayer.start());

File diff suppressed because it is too large
+ 386 - 268
app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt


+ 270 - 175
app/src/main/java/com/nextcloud/talk/controllers/ConversationInfoController.kt

@@ -85,50 +85,69 @@ import io.reactivex.schedulers.Schedulers
 import org.greenrobot.eventbus.EventBus
 import org.greenrobot.eventbus.Subscribe
 import org.greenrobot.eventbus.ThreadMode
-import java.util.*
+import java.util.Calendar
+import java.util.Collections
+import java.util.Comparator
+import java.util.Locale
 import javax.inject.Inject
-import kotlin.collections.ArrayList
-
 
 @AutoInjector(NextcloudTalkApplication::class)
 class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleAdapter.OnItemClickListener {
 
     @BindView(R.id.notification_settings)
     lateinit var notificationsPreferenceScreen: MaterialPreferenceScreen
+
     @BindView(R.id.progressBar)
     lateinit var progressBar: ProgressBar
+
     @BindView(R.id.conversation_info_message_notifications)
     lateinit var messageNotificationLevel: MaterialChoicePreference
+
     @BindView(R.id.webinar_settings)
     lateinit var conversationInfoWebinar: MaterialPreferenceScreen
+
     @BindView(R.id.conversation_info_lobby)
     lateinit var conversationInfoLobby: MaterialSwitchPreference
+
     @BindView(R.id.conversation_info_name)
     lateinit var nameCategoryView: MaterialPreferenceCategory
+
     @BindView(R.id.start_time_preferences)
     lateinit var startTimeView: MaterialStandardPreference
+
     @BindView(R.id.avatar_image)
     lateinit var conversationAvatarImageView: SimpleDraweeView
+
     @BindView(R.id.display_name_text)
     lateinit var conversationDisplayName: EmojiTextView
+
     @BindView(R.id.participants_list_category)
     lateinit var participantsListCategory: MaterialPreferenceCategory
+
     @BindView(R.id.addParticipantsAction)
-    lateinit var addParticipantsAction: MaterialStandardPreference;
+    lateinit var addParticipantsAction: MaterialStandardPreference
+
     @BindView(R.id.recycler_view)
     lateinit var recyclerView: RecyclerView
+
     @BindView(R.id.deleteConversationAction)
     lateinit var deleteConversationAction: MaterialStandardPreference
+
     @BindView(R.id.leaveConversationAction)
     lateinit var leaveConversationAction: MaterialStandardPreference
+
     @BindView(R.id.ownOptions)
     lateinit var ownOptionsCategory: MaterialPreferenceCategory
+
     @BindView(R.id.muteCalls)
     lateinit var muteCalls: MaterialSwitchPreference
+
     @set:Inject
     lateinit var ncApi: NcApi
+
     @set:Inject
     lateinit var context: Context
+
     @set:Inject
     lateinit var eventBus: EventBus
 
@@ -164,7 +183,7 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
         NextcloudTalkApplication.sharedApplication?.componentApplication?.inject(this)
         conversationUser = args.getParcelable(BundleKeys.KEY_USER_ENTITY)
         conversationToken = args.getString(BundleKeys.KEY_ROOM_TOKEN)
-        hasAvatarSpacing = args.getBoolean(BundleKeys.KEY_ROOM_ONE_TO_ONE, false);
+        hasAvatarSpacing = args.getBoolean(BundleKeys.KEY_ROOM_ONE_TO_ONE, false)
         credentials = ApiUtils.getCredentials(conversationUser!!.username, conversationUser.token)
     }
 
@@ -207,14 +226,19 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
     }
 
     private fun setupWebinaryView() {
-        if (conversationUser!!.hasSpreedFeatureCapability("webinary-lobby") && (conversation!!.type
-                        == Conversation.ConversationType.ROOM_GROUP_CALL || conversation!!.type ==
-                        Conversation.ConversationType.ROOM_PUBLIC_CALL) && conversation!!.canModerate(conversationUser)) {
+        if (conversationUser!!.hasSpreedFeatureCapability("webinary-lobby") &&
+            (
+                conversation!!.type == Conversation.ConversationType.ROOM_GROUP_CALL ||
+                    conversation!!.type == Conversation.ConversationType.ROOM_PUBLIC_CALL
+                ) &&
+            conversation!!.canModerate(conversationUser)
+        ) {
             conversationInfoWebinar.visibility = View.VISIBLE
 
-            val isLobbyOpenToModeratorsOnly = conversation!!.lobbyState == Conversation.LobbyState.LOBBY_STATE_MODERATORS_ONLY
+            val isLobbyOpenToModeratorsOnly =
+                conversation!!.lobbyState == Conversation.LobbyState.LOBBY_STATE_MODERATORS_ONLY
             (conversationInfoLobby.findViewById<View>(R.id.mp_checkable) as SwitchCompat)
-                    .isChecked = isLobbyOpenToModeratorsOnly
+                .isChecked = isLobbyOpenToModeratorsOnly
 
             reconfigureLobbyTimerView()
 
@@ -225,12 +249,17 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
                         currentTimeCalendar.timeInMillis = conversation!!.lobbyTimer * 1000
                     }
 
-                    dateTimePicker(minDateTime = Calendar.getInstance(), requireFutureDateTime =
-                    true, currentDateTime = currentTimeCalendar, dateTimeCallback = { _,
-                                                                                      dateTime ->
-                        reconfigureLobbyTimerView(dateTime)
-                        submitLobbyChanges()
-                    })
+                    dateTimePicker(
+                        minDateTime = Calendar.getInstance(),
+                        requireFutureDateTime =
+                        true,
+                        currentDateTime = currentTimeCalendar,
+                        dateTimeCallback = { _,
+                            dateTime ->
+                            reconfigureLobbyTimerView(dateTime)
+                            submitLobbyChanges()
+                        }
+                    )
                 }
             }
 
@@ -253,7 +282,7 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
         }
 
         conversation!!.lobbyState = if (isChecked) Conversation.LobbyState
-                .LOBBY_STATE_MODERATORS_ONLY else Conversation.LobbyState.LOBBY_STATE_ALL_PARTICIPANTS
+            .LOBBY_STATE_MODERATORS_ONLY else Conversation.LobbyState.LOBBY_STATE_ALL_PARTICIPANTS
 
         if (conversation!!.lobbyTimer != null && conversation!!.lobbyTimer != java.lang.Long.MIN_VALUE && conversation!!.lobbyTimer != 0L) {
             startTimeView.setSummary(DateUtils.getLocalDateStringFromTimestampForLobby(conversation!!.lobbyTimer))
@@ -269,27 +298,34 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
     }
 
     fun submitLobbyChanges() {
-        val state = if ((conversationInfoLobby.findViewById<View>(R.id
-                        .mp_checkable) as SwitchCompat).isChecked) 1 else 0
-        ncApi.setLobbyForConversation(ApiUtils.getCredentials(conversationUser!!.username,
-                conversationUser.token), ApiUtils.getUrlForLobbyForConversation
-        (conversationUser.baseUrl, conversation!!.token), state, conversation!!.lobbyTimer)
-                .subscribeOn(Schedulers.io())
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribe(object : Observer<GenericOverall> {
-                    override fun onComplete() {
-                    }
-
-                    override fun onSubscribe(d: Disposable) {
-                    }
+        val state = if (
+            (
+                conversationInfoLobby.findViewById<View>(
+                    R.id.mp_checkable
+                ) as SwitchCompat
+                ).isChecked
+        ) 1 else 0
+        ncApi.setLobbyForConversation(
+            ApiUtils.getCredentials(conversationUser!!.username, conversationUser.token),
+            ApiUtils.getUrlForLobbyForConversation(conversationUser.baseUrl, conversation!!.token),
+            state,
+            conversation!!.lobbyTimer
+        )
+            .subscribeOn(Schedulers.io())
+            .observeOn(AndroidSchedulers.mainThread())
+            .subscribe(object : Observer<GenericOverall> {
+                override fun onComplete() {
+                }
 
-                    override fun onNext(t: GenericOverall) {
-                    }
+                override fun onSubscribe(d: Disposable) {
+                }
 
-                    override fun onError(e: Throwable) {
-                    }
+                override fun onNext(t: GenericOverall) {
+                }
 
-                })
+                override fun onError(e: Throwable) {
+                }
+            })
     }
 
     private fun showLovelyDialog(dialogId: Int, savedInstanceState: Bundle) {
@@ -313,17 +349,21 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
     private fun showDeleteConversationDialog(savedInstanceState: Bundle?) {
         if (activity != null) {
             LovelyStandardDialog(activity, LovelyStandardDialog.ButtonLayout.HORIZONTAL)
-                    .setTopColorRes(R.color.nc_darkRed)
-                    .setIcon(DisplayUtils.getTintedDrawable(context!!.resources,
-                            R.drawable.ic_delete_black_24dp, R.color.bg_default))
-                    .setPositiveButtonColor(context!!.resources.getColor(R.color.nc_darkRed))
-                    .setTitle(R.string.nc_delete_call)
-                    .setMessage(conversation!!.deleteWarningMessage)
-                    .setPositiveButton(R.string.nc_delete) { deleteConversation() }
-                    .setNegativeButton(R.string.nc_cancel, null)
-                    .setInstanceStateHandler(ID_DELETE_CONVERSATION_DIALOG, saveStateHandler!!)
-                    .setSavedInstanceState(savedInstanceState)
-                    .show()
+                .setTopColorRes(R.color.nc_darkRed)
+                .setIcon(
+                    DisplayUtils.getTintedDrawable(
+                        context!!.resources,
+                        R.drawable.ic_delete_black_24dp, R.color.bg_default
+                    )
+                )
+                .setPositiveButtonColor(context!!.resources.getColor(R.color.nc_darkRed))
+                .setTitle(R.string.nc_delete_call)
+                .setMessage(conversation!!.deleteWarningMessage)
+                .setPositiveButton(R.string.nc_delete) { deleteConversation() }
+                .setNegativeButton(R.string.nc_cancel, null)
+                .setInstanceStateHandler(ID_DELETE_CONVERSATION_DIALOG, saveStateHandler!!)
+                .setSavedInstanceState(savedInstanceState)
+                .show()
         }
     }
 
@@ -335,8 +375,8 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
     override fun onRestoreViewState(view: View, savedViewState: Bundle) {
         super.onRestoreViewState(view, savedViewState)
         if (LovelySaveStateHandler.wasDialogOnScreen(savedViewState)) {
-            //Dialog won't be restarted automatically, so we need to call this method.
-            //Each dialog knows how to restore its state
+            // Dialog won't be restarted automatically, so we need to call this method.
+            // Each dialog knows how to restore its state
             showLovelyDialog(LovelySaveStateHandler.getSavedDialogId(savedViewState), savedViewState)
         }
     }
@@ -397,27 +437,28 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
     }
 
     private fun getListOfParticipants() {
-        ncApi.getPeersForCall(credentials, ApiUtils.getUrlForParticipants(conversationUser!!.baseUrl, conversationToken))
-                .subscribeOn(Schedulers.io())
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribe(object : Observer<ParticipantsOverall> {
-                    override fun onSubscribe(d: Disposable) {
-                        participantsDisposable = d
-                    }
-
-                    override fun onNext(participantsOverall: ParticipantsOverall) {
-                        handleParticipants(participantsOverall.ocs.data)
-                    }
-
-                    override fun onError(e: Throwable) {
+        ncApi.getPeersForCall(
+            credentials,
+            ApiUtils.getUrlForParticipants(conversationUser!!.baseUrl, conversationToken)
+        )
+            .subscribeOn(Schedulers.io())
+            .observeOn(AndroidSchedulers.mainThread())
+            .subscribe(object : Observer<ParticipantsOverall> {
+                override fun onSubscribe(d: Disposable) {
+                    participantsDisposable = d
+                }
 
-                    }
+                override fun onNext(participantsOverall: ParticipantsOverall) {
+                    handleParticipants(participantsOverall.ocs.data)
+                }
 
-                    override fun onComplete() {
-                        participantsDisposable!!.dispose()
-                    }
-                })
+                override fun onError(e: Throwable) {
+                }
 
+                override fun onComplete() {
+                    participantsDisposable!!.dispose()
+                }
+            })
     }
 
     @OnClick(R.id.addParticipantsAction)
@@ -430,21 +471,33 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
             existingParticipantsId.add(userItem.model.userId)
         }
 
-        bundle.putBoolean(BundleKeys.KEY_ADD_PARTICIPANTS, true);
+        bundle.putBoolean(BundleKeys.KEY_ADD_PARTICIPANTS, true)
         bundle.putStringArrayList(BundleKeys.KEY_EXISTING_PARTICIPANTS, existingParticipantsId)
         bundle.putString(BundleKeys.KEY_TOKEN, conversation!!.token)
 
-        getRouter().pushController((RouterTransaction.with(ContactsController(bundle))
-                .pushChangeHandler(HorizontalChangeHandler())
-                .popChangeHandler(HorizontalChangeHandler())))
+        getRouter().pushController(
+            (
+                RouterTransaction.with(
+                    ContactsController(bundle)
+                )
+                    .pushChangeHandler(
+                        HorizontalChangeHandler()
+                    )
+                    .popChangeHandler(
+                        HorizontalChangeHandler()
+                    )
+                )
+        )
     }
 
     @OnClick(R.id.leaveConversationAction)
     internal fun leaveConversation() {
         workerData?.let {
-            WorkManager.getInstance().enqueue(OneTimeWorkRequest.Builder
-            (LeaveConversationWorker::class
-                    .java).setInputData(it).build()
+            WorkManager.getInstance().enqueue(
+                OneTimeWorkRequest.Builder(
+                    LeaveConversationWorker::class
+                        .java
+                ).setInputData(it).build()
             )
             popTwoLastControllers()
         }
@@ -452,8 +505,11 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
 
     private fun deleteConversation() {
         workerData?.let {
-            WorkManager.getInstance().enqueue(OneTimeWorkRequest.Builder
-            (DeleteConversationWorker::class.java).setInputData(it).build())
+            WorkManager.getInstance().enqueue(
+                OneTimeWorkRequest.Builder(
+                    DeleteConversationWorker::class.java
+                ).setInputData(it).build()
+            )
             popTwoLastControllers()
         }
     }
@@ -471,69 +527,67 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
 
     private fun fetchRoomInfo() {
         ncApi.getRoom(credentials, ApiUtils.getRoom(conversationUser!!.baseUrl, conversationToken))
-                .subscribeOn(Schedulers.io())
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribe(object : Observer<RoomOverall> {
-                    override fun onSubscribe(d: Disposable) {
-                        roomDisposable = d
-                    }
-
-                    override fun onNext(roomOverall: RoomOverall) {
-                        conversation = roomOverall.ocs.data
+            .subscribeOn(Schedulers.io())
+            .observeOn(AndroidSchedulers.mainThread())
+            .subscribe(object : Observer<RoomOverall> {
+                override fun onSubscribe(d: Disposable) {
+                    roomDisposable = d
+                }
 
-                        val conversationCopy = conversation
+                override fun onNext(roomOverall: RoomOverall) {
+                    conversation = roomOverall.ocs.data
 
-                        if (conversationCopy!!.canModerate(conversationUser)) {
-                            addParticipantsAction.visibility = View.VISIBLE
-                        } else {
-                            addParticipantsAction.visibility = View.GONE
-                        }
+                    val conversationCopy = conversation
 
-                        if (isAttached && (!isBeingDestroyed || !isDestroyed)) {
-                            ownOptionsCategory.visibility = View.VISIBLE
+                    if (conversationCopy!!.canModerate(conversationUser)) {
+                        addParticipantsAction.visibility = View.VISIBLE
+                    } else {
+                        addParticipantsAction.visibility = View.GONE
+                    }
 
-                            setupWebinaryView()
+                    if (isAttached && (!isBeingDestroyed || !isDestroyed)) {
+                        ownOptionsCategory.visibility = View.VISIBLE
 
-                            if (!conversation!!.canLeave(conversationUser)) {
-                                leaveConversationAction.visibility = View.GONE
-                            } else {
-                                leaveConversationAction.visibility = View.VISIBLE
-                            }
+                        setupWebinaryView()
 
-                            if (!conversation!!.canModerate(conversationUser)) {
-                                deleteConversationAction.visibility = View.GONE
-                            } else {
-                                deleteConversationAction.visibility = View.VISIBLE
-                            }
+                        if (!conversation!!.canLeave(conversationUser)) {
+                            leaveConversationAction.visibility = View.GONE
+                        } else {
+                            leaveConversationAction.visibility = View.VISIBLE
+                        }
 
-                            if (Conversation.ConversationType.ROOM_SYSTEM == conversation!!.type) {
-                                muteCalls.visibility = View.GONE
-                            }
+                        if (!conversation!!.canModerate(conversationUser)) {
+                            deleteConversationAction.visibility = View.GONE
+                        } else {
+                            deleteConversationAction.visibility = View.VISIBLE
+                        }
 
-                            getListOfParticipants()
+                        if (Conversation.ConversationType.ROOM_SYSTEM == conversation!!.type) {
+                            muteCalls.visibility = View.GONE
+                        }
 
-                            progressBar.visibility = View.GONE
+                        getListOfParticipants()
 
-                            nameCategoryView.visibility = View.VISIBLE
+                        progressBar.visibility = View.GONE
 
-                            conversationDisplayName.text = conversation!!.displayName
+                        nameCategoryView.visibility = View.VISIBLE
 
+                        conversationDisplayName.text = conversation!!.displayName
 
-                            loadConversationAvatar()
-                            adjustNotificationLevelUI()
+                        loadConversationAvatar()
+                        adjustNotificationLevelUI()
 
-                            notificationsPreferenceScreen.visibility = View.VISIBLE
-                        }
+                        notificationsPreferenceScreen.visibility = View.VISIBLE
                     }
+                }
 
-                    override fun onError(e: Throwable) {
-
-                    }
+                override fun onError(e: Throwable) {
+                }
 
-                    override fun onComplete() {
-                        roomDisposable!!.dispose()
-                    }
-                })
+                override fun onComplete() {
+                    roomDisposable!!.dispose()
+                }
+            })
     }
 
     private fun adjustNotificationLevelUI() {
@@ -543,12 +597,13 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
                 messageNotificationLevel.alpha = 1.0f
 
                 if (conversation!!.notificationLevel != Conversation.NotificationLevel.DEFAULT) {
-                    val stringValue: String = when (EnumNotificationLevelConverter().convertToInt(conversation!!.notificationLevel)) {
-                        1 -> "always"
-                        2 -> "mention"
-                        3 -> "never"
-                        else -> "mention"
-                    }
+                    val stringValue: String =
+                        when (EnumNotificationLevelConverter().convertToInt(conversation!!.notificationLevel)) {
+                            1 -> "always"
+                            2 -> "mention"
+                            3 -> "never"
+                            else -> "mention"
+                        }
 
                     messageNotificationLevel.value = stringValue
                 } else {
@@ -577,22 +632,38 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
 
     private fun loadConversationAvatar() {
         when (conversation!!.type) {
-            Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL -> if (!TextUtils.isEmpty
-                    (conversation!!.name)) {
+            Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL -> if (
+                !TextUtils.isEmpty(conversation!!.name)
+            ) {
                 val draweeController = Fresco.newDraweeControllerBuilder()
-                        .setOldController(conversationAvatarImageView.controller)
-                        .setAutoPlayAnimations(true)
-                        .setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(conversationUser!!.baseUrl,
-                                conversation!!.name, R.dimen.avatar_size_big), conversationUser))
-                        .build()
+                    .setOldController(conversationAvatarImageView.controller)
+                    .setAutoPlayAnimations(true)
+                    .setImageRequest(
+                        DisplayUtils.getImageRequestForUrl(
+                            ApiUtils.getUrlForAvatarWithName(
+                                conversationUser!!.baseUrl,
+                                conversation!!.name, R.dimen.avatar_size_big
+                            ),
+                            conversationUser
+                        )
+                    )
+                    .build()
                 conversationAvatarImageView.controller = draweeController
             }
-            Conversation.ConversationType.ROOM_GROUP_CALL -> conversationAvatarImageView.hierarchy.setPlaceholderImage(DisplayUtils
-                    .getRoundedBitmapDrawableFromVectorDrawableResource(resources,
-                            R.drawable.ic_people_group_white_24px))
-            Conversation.ConversationType.ROOM_PUBLIC_CALL -> conversationAvatarImageView.hierarchy.setPlaceholderImage(DisplayUtils
-                    .getRoundedBitmapDrawableFromVectorDrawableResource(resources,
-                            R.drawable.ic_link_white_24px))
+            Conversation.ConversationType.ROOM_GROUP_CALL -> conversationAvatarImageView.hierarchy.setPlaceholderImage(
+                DisplayUtils
+                    .getRoundedBitmapDrawableFromVectorDrawableResource(
+                        resources,
+                        R.drawable.ic_people_group_white_24px
+                    )
+            )
+            Conversation.ConversationType.ROOM_PUBLIC_CALL -> conversationAvatarImageView.hierarchy.setPlaceholderImage(
+                DisplayUtils
+                    .getRoundedBitmapDrawableFromVectorDrawableResource(
+                        resources,
+                        R.drawable.ic_link_white_24px
+                    )
+            )
             Conversation.ConversationType.ROOM_SYSTEM -> {
                 val layers = arrayOfNulls<Drawable>(2)
                 layers[0] = context.getDrawable(R.drawable.ic_launcher_background)
@@ -610,13 +681,14 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
         val userItem = adapter?.getItem(position) as UserItem
         val participant = userItem.model
 
-
         if (participant.userId != conversationUser!!.userId) {
             var items = mutableListOf(
-                    BasicListItemWithImage(R.drawable.ic_pencil_grey600_24dp, context.getString(R.string.nc_promote)),
-                    BasicListItemWithImage(R.drawable.ic_pencil_grey600_24dp, context.getString(R.string.nc_demote)),
-                    BasicListItemWithImage(R.drawable.ic_delete_grey600_24dp,
-                            context.getString(R.string.nc_remove_participant))
+                BasicListItemWithImage(R.drawable.ic_pencil_grey600_24dp, context.getString(R.string.nc_promote)),
+                BasicListItemWithImage(R.drawable.ic_pencil_grey600_24dp, context.getString(R.string.nc_demote)),
+                BasicListItemWithImage(
+                    R.drawable.ic_delete_grey600_24dp,
+                    context.getString(R.string.nc_remove_participant)
+                )
             )
 
             if (!conversation!!.canModerate(conversationUser)) {
@@ -629,7 +701,6 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
                 }
             }
 
-
             if (items.isNotEmpty()) {
                 MaterialDialog(activity!!, BottomSheet(WRAP_CONTENT)).show {
                     cornerRadius(res = R.dimen.corner_radius)
@@ -639,38 +710,62 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
 
                         if (index == 0) {
                             if (participant.type == Participant.ParticipantType.MODERATOR) {
-                                ncApi.demoteModeratorToUser(credentials, ApiUtils.getUrlForModerators(conversationUser.baseUrl, conversation!!.token), participant.userId)
-                                        .subscribeOn(Schedulers.io())
-                                        .observeOn(AndroidSchedulers.mainThread())
-                                        .subscribe {
-                                            getListOfParticipants()
-                                        }
+                                ncApi.demoteModeratorToUser(
+                                    credentials,
+                                    ApiUtils.getUrlForModerators(conversationUser.baseUrl, conversation!!.token),
+                                    participant.userId
+                                )
+                                    .subscribeOn(Schedulers.io())
+                                    .observeOn(AndroidSchedulers.mainThread())
+                                    .subscribe {
+                                        getListOfParticipants()
+                                    }
                             } else if (participant.type == Participant.ParticipantType.USER) {
-                                ncApi.promoteUserToModerator(credentials, ApiUtils.getUrlForModerators(conversationUser.baseUrl, conversation!!.token), participant.userId)
-                                        .subscribeOn(Schedulers.io())
-                                        .observeOn(AndroidSchedulers.mainThread())
-                                        .subscribe {
-                                            getListOfParticipants()
-                                        }
+                                ncApi.promoteUserToModerator(
+                                    credentials,
+                                    ApiUtils.getUrlForModerators(conversationUser.baseUrl, conversation!!.token),
+                                    participant.userId
+                                )
+                                    .subscribeOn(Schedulers.io())
+                                    .observeOn(AndroidSchedulers.mainThread())
+                                    .subscribe {
+                                        getListOfParticipants()
+                                    }
                             }
                         } else if (index == 1) {
                             if (participant.type == Participant.ParticipantType.GUEST ||
-                                    participant.type == Participant.ParticipantType.USER_FOLLOWING_LINK) {
-                                ncApi.removeParticipantFromConversation(credentials, ApiUtils.getUrlForRemovingParticipantFromConversation(conversationUser.baseUrl, conversation!!.token, true), participant.sessionId)
-                                        .subscribeOn(Schedulers.io())
-                                        .observeOn(AndroidSchedulers.mainThread())
-                                        .subscribe {
-                                            getListOfParticipants()
-                                        }
-
+                                participant.type == Participant.ParticipantType.USER_FOLLOWING_LINK
+                            ) {
+                                ncApi.removeParticipantFromConversation(
+                                    credentials,
+                                    ApiUtils.getUrlForRemovingParticipantFromConversation(
+                                        conversationUser.baseUrl,
+                                        conversation!!.token,
+                                        true
+                                    ),
+                                    participant.sessionId
+                                )
+                                    .subscribeOn(Schedulers.io())
+                                    .observeOn(AndroidSchedulers.mainThread())
+                                    .subscribe {
+                                        getListOfParticipants()
+                                    }
                             } else {
-                                ncApi.removeParticipantFromConversation(credentials, ApiUtils.getUrlForRemovingParticipantFromConversation(conversationUser.baseUrl, conversation!!.token, false), participant.userId)
-                                        .subscribeOn(Schedulers.io())
-                                        .observeOn(AndroidSchedulers.mainThread())
-                                        .subscribe {
-                                            getListOfParticipants()
-                                            // get participants again
-                                        }
+                                ncApi.removeParticipantFromConversation(
+                                    credentials,
+                                    ApiUtils.getUrlForRemovingParticipantFromConversation(
+                                        conversationUser.baseUrl,
+                                        conversation!!.token,
+                                        false
+                                    ),
+                                    participant.userId
+                                )
+                                    .subscribeOn(Schedulers.io())
+                                    .observeOn(AndroidSchedulers.mainThread())
+                                    .subscribe {
+                                        getListOfParticipants()
+                                        // get participants again
+                                    }
                             }
                         }
                     }
@@ -678,7 +773,7 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
             }
         }
 
-        return true;
+        return true
     }
 
     companion object {
@@ -709,7 +804,7 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
             }
 
             return left.model.displayName.toLowerCase(Locale.ROOT).compareTo(
-                    right.model.displayName.toLowerCase(Locale.ROOT)
+                right.model.displayName.toLowerCase(Locale.ROOT)
             )
         }
     }

+ 0 - 1
app/src/main/java/com/nextcloud/talk/controllers/base/ButterKnifeController.kt

@@ -53,5 +53,4 @@ abstract class ButterKnifeController : Controller {
         unbinder!!.unbind()
         unbinder = null
     }
-
 }

+ 4 - 3
app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/items/BasicListItemWithImage.kt

@@ -29,10 +29,11 @@ interface ListItemWithImage {
 }
 
 data class BasicListItemWithImage(
-        @DrawableRes val iconRes: Int,
-        override val title: String) : ListItemWithImage {
+    @DrawableRes val iconRes: Int,
+    override val title: String
+) : ListItemWithImage {
 
     override fun populateIcon(imageView: ImageView) {
         imageView.setImageResource(iconRes)
     }
-}
+}

+ 20 - 17
app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/items/ListIconDialogAdapter.kt

@@ -23,7 +23,6 @@ package com.nextcloud.talk.controllers.bottomsheet.items
 import android.view.View
 import android.view.ViewGroup
 import android.widget.ImageView
-import android.widget.TextView
 import androidx.recyclerview.widget.RecyclerView
 import com.afollestad.materialdialogs.MaterialDialog
 import com.afollestad.materialdialogs.WhichButton
@@ -34,14 +33,14 @@ import com.afollestad.materialdialogs.internal.rtl.RtlTextView
 import com.afollestad.materialdialogs.list.getItemSelector
 import com.afollestad.materialdialogs.utils.MDUtil.inflate
 import com.afollestad.materialdialogs.utils.MDUtil.maybeSetTextColor
-import com.google.android.material.textview.MaterialTextView
 import com.nextcloud.talk.R
 
 private const val KEY_ACTIVATED_INDEX = "activated_index"
 
 internal class ListItemViewHolder(
-        itemView: View,
-        private val adapter: ListIconDialogAdapter<*>) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
+    itemView: View,
+    private val adapter: ListIconDialogAdapter<*>
+) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
     init {
         itemView.setOnClickListener(this)
     }
@@ -53,11 +52,12 @@ internal class ListItemViewHolder(
 }
 
 internal class ListIconDialogAdapter<IT : ListItemWithImage>(
-        private var dialog: MaterialDialog,
-        private var items: List<IT>,
-        disabledItems: IntArray?,
-        private var waitForPositiveButton: Boolean,
-        private var selection: ListItemListener<IT>) : RecyclerView.Adapter<ListItemViewHolder>(), DialogAdapter<IT, ListItemListener<IT>> {
+    private var dialog: MaterialDialog,
+    private var items: List<IT>,
+    disabledItems: IntArray?,
+    private var waitForPositiveButton: Boolean,
+    private var selection: ListItemListener<IT>
+) : RecyclerView.Adapter<ListItemViewHolder>(), DialogAdapter<IT, ListItemListener<IT>> {
 
     private var disabledIndices: IntArray = disabledItems ?: IntArray(0)
 
@@ -81,12 +81,13 @@ internal class ListIconDialogAdapter<IT : ListItemWithImage>(
     }
 
     override fun onCreateViewHolder(
-            parent: ViewGroup,
-            viewType: Int): ListItemViewHolder {
+        parent: ViewGroup,
+        viewType: Int
+    ): ListItemViewHolder {
         val listItemView: View = parent.inflate(dialog.windowContext, R.layout.menu_item_sheet)
         val viewHolder = ListItemViewHolder(
-                itemView = listItemView,
-                adapter = this
+            itemView = listItemView,
+            adapter = this
         )
         viewHolder.titleView.maybeSetTextColor(dialog.windowContext, R.attr.md_color_content)
         return viewHolder
@@ -95,8 +96,9 @@ internal class ListIconDialogAdapter<IT : ListItemWithImage>(
     override fun getItemCount() = items.size
 
     override fun onBindViewHolder(
-            holder: ListItemViewHolder,
-            position: Int) {
+        holder: ListItemViewHolder,
+        position: Int
+    ) {
         holder.itemView.isEnabled = !disabledIndices.contains(position)
         val currentItem = items[position]
 
@@ -121,8 +123,9 @@ internal class ListIconDialogAdapter<IT : ListItemWithImage>(
     }
 
     override fun replaceItems(
-            items: List<IT>,
-            listener: ListItemListener<IT>) {
+        items: List<IT>,
+        listener: ListItemListener<IT>
+    ) {
         this.items = items
         if (listener != null) {
             this.selection = listener

+ 21 - 18
app/src/main/java/com/nextcloud/talk/controllers/bottomsheet/items/MagicBottomSheets.kt

@@ -28,37 +28,40 @@ import com.afollestad.materialdialogs.list.customListAdapter
 import com.afollestad.materialdialogs.list.getListAdapter
 
 typealias ListItemListener<IT> =
-        ((dialog: MaterialDialog, index: Int, item: IT) -> Unit)?
+    ((dialog: MaterialDialog, index: Int, item: IT) -> Unit)?
 
-@CheckResult fun <IT : ListItemWithImage> MaterialDialog.listItemsWithImage(
-        items: List<IT>,
-        disabledIndices: IntArray? = null,
-        waitForPositiveButton: Boolean = true,
-        selection: ListItemListener<IT> = null): MaterialDialog {
+@CheckResult
+fun <IT : ListItemWithImage> MaterialDialog.listItemsWithImage(
+    items: List<IT>,
+    disabledIndices: IntArray? = null,
+    waitForPositiveButton: Boolean = true,
+    selection: ListItemListener<IT> = null
+): MaterialDialog {
 
     if (getListAdapter() != null) {
         return updateListItemsWithImage(
-                items = items,
-                disabledIndices = disabledIndices
+            items = items,
+            disabledIndices = disabledIndices
         )
     }
 
     val layoutManager = LinearLayoutManager(windowContext)
     return customListAdapter(
-            adapter = ListIconDialogAdapter(
-                    dialog = this,
-                    items = items,
-                    disabledItems = disabledIndices,
-                    waitForPositiveButton = waitForPositiveButton,
-                    selection = selection
-            ),
-            layoutManager = layoutManager
+        adapter = ListIconDialogAdapter(
+            dialog = this,
+            items = items,
+            disabledItems = disabledIndices,
+            waitForPositiveButton = waitForPositiveButton,
+            selection = selection
+        ),
+        layoutManager = layoutManager
     )
 }
 
 fun MaterialDialog.updateListItemsWithImage(
-        items: List<ListItemWithImage>,
-        disabledIndices: IntArray? = null): MaterialDialog {
+    items: List<ListItemWithImage>,
+    disabledIndices: IntArray? = null
+): MaterialDialog {
     val adapter = getListAdapter()
     check(adapter != null) {
         "updateGridItems(...) can't be used before you've created a bottom sheet grid dialog."

+ 1 - 3
app/src/main/java/com/nextcloud/talk/events/CallNotificationClick.kt

@@ -20,6 +20,4 @@
 
 package com.nextcloud.talk.events
 
-class CallNotificationClick {
-
-}
+class CallNotificationClick

+ 208 - 133
app/src/main/java/com/nextcloud/talk/jobs/ContactAddressBookWorker.kt

@@ -33,7 +33,11 @@ import android.provider.ContactsContract
 import android.util.Log
 import androidx.core.content.ContextCompat
 import androidx.core.os.ConfigurationCompat
-import androidx.work.*
+import androidx.work.Data
+import androidx.work.OneTimeWorkRequest
+import androidx.work.WorkManager
+import androidx.work.Worker
+import androidx.work.WorkerParameters
 import autodagger.AutoInjector
 import com.bluelinelabs.conductor.Controller
 import com.google.gson.Gson
@@ -54,10 +58,9 @@ import okhttp3.MediaType
 import okhttp3.RequestBody
 import javax.inject.Inject
 
-
 @AutoInjector(NextcloudTalkApplication::class)
 class ContactAddressBookWorker(val context: Context, workerParameters: WorkerParameters) :
-        Worker(context, workerParameters) {
+    Worker(context, workerParameters) {
 
     @Inject
     lateinit var ncApi: NcApi
@@ -85,7 +88,7 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
         }
 
         val deleteAll = inputData.getBoolean(DELETE_ALL, false)
-        if(deleteAll){
+        if (deleteAll) {
             deleteAllLinkedAccounts()
             return Result.success()
         }
@@ -99,7 +102,7 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
             }
         }
 
-        if(AccountManager.get(context).getAccountsByType(accountType).isEmpty()){
+        if (AccountManager.get(context).getAccountsByType(accountType).isEmpty()) {
             AccountManager.get(context).addAccountExplicitly(Account(accountName, accountType), "", null)
         } else {
             Log.d(TAG, "Account already exists")
@@ -107,7 +110,7 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
 
         val deviceContactsWithNumbers = collectContactsWithPhoneNumbersFromDevice()
 
-        if(deviceContactsWithNumbers.isNotEmpty()){
+        if (deviceContactsWithNumbers.isNotEmpty()) {
             val currentLocale = ConfigurationCompat.getLocales(context.resources.configuration)[0].country
 
             val map = mutableMapOf<String, Any>()
@@ -117,28 +120,29 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
             val json = Gson().toJson(map)
 
             ncApi.searchContactsByPhoneNumber(
-                    ApiUtils.getCredentials(currentUser.username, currentUser.token),
-                    ApiUtils.getUrlForSearchByNumber(currentUser.baseUrl),
-                    RequestBody.create(MediaType.parse("application/json"), json))
-                    .subscribeOn(Schedulers.io())
-                    .observeOn(AndroidSchedulers.mainThread())
-                    .subscribe(object : Observer<ContactsByNumberOverall> {
-                        override fun onComplete() {
-                        }
-
-                        override fun onSubscribe(d: Disposable) {
-                        }
-
-                        override fun onNext(foundContacts: ContactsByNumberOverall) {
-                            val contactsWithAssociatedPhoneNumbers = foundContacts.ocs.map
-                            deleteLinkedAccounts(contactsWithAssociatedPhoneNumbers)
-                            createLinkedAccounts(contactsWithAssociatedPhoneNumbers)
-                        }
-
-                        override fun onError(e: Throwable) {
-                            Log.e(javaClass.simpleName, "Failed to searchContactsByPhoneNumber", e)
-                        }
-                    })
+                ApiUtils.getCredentials(currentUser.username, currentUser.token),
+                ApiUtils.getUrlForSearchByNumber(currentUser.baseUrl),
+                RequestBody.create(MediaType.parse("application/json"), json)
+            )
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe(object : Observer<ContactsByNumberOverall> {
+                    override fun onComplete() {
+                    }
+
+                    override fun onSubscribe(d: Disposable) {
+                    }
+
+                    override fun onNext(foundContacts: ContactsByNumberOverall) {
+                        val contactsWithAssociatedPhoneNumbers = foundContacts.ocs.map
+                        deleteLinkedAccounts(contactsWithAssociatedPhoneNumbers)
+                        createLinkedAccounts(contactsWithAssociatedPhoneNumbers)
+                    }
+
+                    override fun onError(e: Throwable) {
+                        Log.e(javaClass.simpleName, "Failed to searchContactsByPhoneNumber", e)
+                    }
+                })
         }
 
         // store timestamp 
@@ -151,11 +155,11 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
         val deviceContactsWithNumbers: MutableMap<String, List<String>> = mutableMapOf()
 
         val contactCursor = context.contentResolver.query(
-                ContactsContract.Contacts.CONTENT_URI,
-                null,
-                null,
-                null,
-                null
+            ContactsContract.Contacts.CONTENT_URI,
+            null,
+            null,
+            null,
+            null
         )
 
         if (contactCursor != null) {
@@ -163,7 +167,8 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
                 contactCursor.moveToFirst()
                 for (i in 0 until contactCursor.count) {
                     val id = contactCursor.getString(contactCursor.getColumnIndex(ContactsContract.Contacts._ID))
-                    val lookup = contactCursor.getString(contactCursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY))
+                    val lookup =
+                        contactCursor.getString(contactCursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY))
                     deviceContactsWithNumbers[lookup] = getPhoneNumbersFromDeviceContact(id)
                     contactCursor.moveToNext()
                 }
@@ -178,39 +183,50 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
         Log.d(TAG, "deleteLinkedAccount")
         fun deleteLinkedAccount(id: String) {
             val rawContactUri = ContactsContract.RawContacts.CONTENT_URI
-                    .buildUpon()
-                    .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
-                    .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, accountName)
-                    .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, accountType)
-                    .build()
-            val count = context.contentResolver.delete(rawContactUri, ContactsContract.RawContacts.CONTACT_ID + " " +
-                    "LIKE \"" + id + "\"", null)
-            Log.d(TAG, "deleted $count linked accounts for id $id")
-        }
-
-        val rawContactUri = ContactsContract.Data.CONTENT_URI
                 .buildUpon()
                 .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
                 .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, accountName)
                 .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, accountType)
-                .appendQueryParameter(ContactsContract.Data.MIMETYPE, "vnd.android.cursor.item/vnd.com.nextcloud.talk2.chat")
                 .build()
-
-        val rawContactsCursor = context.contentResolver.query(
+            val count = context.contentResolver.delete(
                 rawContactUri,
-                null,
-                null,
-                null,
+                ContactsContract.RawContacts.CONTACT_ID + " " + "LIKE \"" + id + "\"",
                 null
+            )
+            Log.d(TAG, "deleted $count linked accounts for id $id")
+        }
+
+        val rawContactUri = ContactsContract.Data.CONTENT_URI
+            .buildUpon()
+            .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
+            .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, accountName)
+            .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, accountType)
+            .appendQueryParameter(
+                ContactsContract.Data.MIMETYPE,
+                "vnd.android.cursor.item/vnd.com.nextcloud.talk2.chat"
+            )
+            .build()
+
+        val rawContactsCursor = context.contentResolver.query(
+            rawContactUri,
+            null,
+            null,
+            null,
+            null
         )
 
         if (rawContactsCursor != null) {
             if (rawContactsCursor.count > 0) {
                 while (rawContactsCursor.moveToNext()) {
-                    val lookupKey = rawContactsCursor.getString(rawContactsCursor.getColumnIndex(ContactsContract.Data.LOOKUP_KEY))
-                    val contactId = rawContactsCursor.getString(rawContactsCursor.getColumnIndex(ContactsContract.Data.CONTACT_ID))
-
-                    if (contactsWithAssociatedPhoneNumbers == null || !contactsWithAssociatedPhoneNumbers.containsKey(lookupKey)) {
+                    val lookupKey =
+                        rawContactsCursor.getString(rawContactsCursor.getColumnIndex(ContactsContract.Data.LOOKUP_KEY))
+                    val contactId =
+                        rawContactsCursor.getString(rawContactsCursor.getColumnIndex(ContactsContract.Data.CONTACT_ID))
+
+                    if (contactsWithAssociatedPhoneNumbers == null || !contactsWithAssociatedPhoneNumbers.containsKey(
+                            lookupKey
+                        )
+                    ) {
                         deleteLinkedAccount(contactId)
                     }
                 }
@@ -222,25 +238,29 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
     }
 
     private fun createLinkedAccounts(contactsWithAssociatedPhoneNumbers: Map<String, String>?) {
-        fun hasLinkedAccount(id: String) : Boolean {
+        fun hasLinkedAccount(id: String): Boolean {
             var hasLinkedAccount = false
-            val where = ContactsContract.Data.MIMETYPE + " = ? AND " + ContactsContract.CommonDataKinds.StructuredName.CONTACT_ID + " = ?"
+            val where =
+                ContactsContract.Data.MIMETYPE + " = ? AND " + ContactsContract.CommonDataKinds.StructuredName.CONTACT_ID + " = ?"
             val params = arrayOf(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE, id)
 
             val rawContactUri = ContactsContract.Data.CONTENT_URI
-                    .buildUpon()
-                    .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
-                    .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, accountName)
-                    .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, accountType)
-                    .appendQueryParameter(ContactsContract.Data.MIMETYPE, "vnd.android.cursor.item/vnd.com.nextcloud.talk2.chat")
-                    .build()
+                .buildUpon()
+                .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
+                .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, accountName)
+                .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, accountType)
+                .appendQueryParameter(
+                    ContactsContract.Data.MIMETYPE,
+                    "vnd.android.cursor.item/vnd.com.nextcloud.talk2.chat"
+                )
+                .build()
 
             val rawContactsCursor = context.contentResolver.query(
-                    rawContactUri,
-                    null,
-                    where,
-                    params,
-                    null
+                rawContactUri,
+                null,
+                where,
+                params,
+                null
             )
 
             if (rawContactsCursor != null) {
@@ -259,18 +279,19 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
             val lookupUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookupKey)
             val lookupContactUri = ContactsContract.Contacts.lookupContact(context.contentResolver, lookupUri)
             val contactCursor = context.contentResolver.query(
-                    lookupContactUri,
-                    null,
-                    null,
-                    null,
-                    null)
+                lookupContactUri,
+                null,
+                null,
+                null,
+                null
+            )
 
             if (contactCursor != null) {
                 if (contactCursor.count > 0) {
                     contactCursor.moveToFirst()
 
                     val id = contactCursor.getString(contactCursor.getColumnIndex(ContactsContract.Contacts._ID))
-                    if(hasLinkedAccount(id)){
+                    if (hasLinkedAccount(id)) {
                         return
                     }
 
@@ -285,34 +306,60 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
                     val rawContactsUri = ContactsContract.RawContacts.CONTENT_URI.buildUpon().build()
                     val dataUri = ContactsContract.Data.CONTENT_URI.buildUpon().build()
 
-                    ops.add(ContentProviderOperation
+                    ops.add(
+                        ContentProviderOperation
                             .newInsert(rawContactsUri)
                             .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, accountName)
                             .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, accountType)
-                            .withValue(ContactsContract.RawContacts.AGGREGATION_MODE,
-                                    ContactsContract.RawContacts.AGGREGATION_MODE_DEFAULT)
+                            .withValue(
+                                ContactsContract.RawContacts.AGGREGATION_MODE,
+                                ContactsContract.RawContacts.AGGREGATION_MODE_DEFAULT
+                            )
                             .withValue(ContactsContract.RawContacts.SYNC2, cloudId)
-                            .build())
-                    ops.add(ContentProviderOperation
+                            .build()
+                    )
+                    ops.add(
+                        ContentProviderOperation
                             .newInsert(dataUri)
                             .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
-                            .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
+                            .withValue(
+                                ContactsContract.Data.MIMETYPE,
+                                ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE
+                            )
                             .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, numbers[0])
-                            .build())
-                    ops.add(ContentProviderOperation
+                            .build()
+                    )
+                    ops.add(
+                        ContentProviderOperation
                             .newInsert(dataUri)
                             .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
-                            .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
+                            .withValue(
+                                ContactsContract.Data.MIMETYPE,
+                                ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE
+                            )
                             .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, displayName)
-                            .build())
-                    ops.add(ContentProviderOperation
+                            .build()
+                    )
+                    ops.add(
+                        ContentProviderOperation
                             .newInsert(dataUri)
                             .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
-                            .withValue(ContactsContract.Data.MIMETYPE, "vnd.android.cursor.item/vnd.com.nextcloud.talk2.chat")
+                            .withValue(
+                                ContactsContract.Data.MIMETYPE,
+                                "vnd.android.cursor.item/vnd.com.nextcloud.talk2.chat"
+                            )
                             .withValue(ContactsContract.Data.DATA1, cloudId)
-                            .withValue(ContactsContract.Data.DATA2, String.format(context.resources.getString(R
-                                    .string.nc_phone_book_integration_chat_via), accountName))
-                            .build())
+                            .withValue(
+                                ContactsContract.Data.DATA2,
+                                String.format(
+                                    context.resources.getString(
+                                        R.string.nc_phone_book_integration_chat_via
+                                    ),
+                                    accountName
+                                )
+                            )
+                            .build()
+                    )
 
                     try {
                         context.contentResolver.applyBatch(ContactsContract.AUTHORITY, ops)
@@ -322,8 +369,11 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
                         Log.e(javaClass.simpleName, "", e)
                     }
 
-                    Log.d(TAG, "added new entry for contact $displayName (cloudId: $cloudId | lookupKey: $lookupKey" +
-                            " | id: $id)")
+                    Log.d(
+                        TAG,
+                        "added new entry for contact $displayName (cloudId: $cloudId | lookupKey: $lookupKey" +
+                            " | id: $id)"
+                    )
                 }
                 contactCursor.close()
             }
@@ -341,18 +391,21 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
     }
 
     private fun getDisplayNameFromDeviceContact(id: String?): String? {
-        var displayName:String? = null
-        val whereName = ContactsContract.Data.MIMETYPE + " = ? AND " + ContactsContract.CommonDataKinds.StructuredName.CONTACT_ID + " = ?"
+        var displayName: String? = null
+        val whereName =
+            ContactsContract.Data.MIMETYPE + " = ? AND " + ContactsContract.CommonDataKinds.StructuredName.CONTACT_ID + " = ?"
         val whereNameParams = arrayOf(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE, id)
         val nameCursor = context.contentResolver.query(
-                ContactsContract.Data.CONTENT_URI,
-                null,
-                whereName,
-                whereNameParams,
-                ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME)
+            ContactsContract.Data.CONTENT_URI,
+            null,
+            whereName,
+            whereNameParams,
+            ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME
+        )
         if (nameCursor != null) {
             while (nameCursor.moveToNext()) {
-                displayName = nameCursor.getString(nameCursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME))
+                displayName =
+                    nameCursor.getString(nameCursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME))
             }
             nameCursor.close()
         }
@@ -362,11 +415,12 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
     private fun getPhoneNumbersFromDeviceContact(id: String?): MutableList<String> {
         val numbers = mutableListOf<String>()
         val phonesNumbersCursor = context.contentResolver.query(
-                ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
-                null,
-                ContactsContract.Data.CONTACT_ID + " = " + id,
-                null,
-                null)
+            ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
+            null,
+            ContactsContract.Data.CONTACT_ID + " = " + id,
+            null,
+            null
+        )
 
         if (phonesNumbersCursor != null) {
             while (phonesNumbersCursor.moveToNext()) {
@@ -374,7 +428,7 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
             }
             phonesNumbersCursor.close()
         }
-        if(numbers.size > 0){
+        if (numbers.size > 0) {
             Log.d(TAG, "Found ${numbers.size} phone numbers for contact with id $id")
         }
         return numbers
@@ -382,11 +436,11 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
 
     fun deleteAllLinkedAccounts() {
         val rawContactUri = ContactsContract.RawContacts.CONTENT_URI
-                .buildUpon()
-                .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
-                .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, accountName)
-                .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, accountType)
-                .build()
+            .buildUpon()
+            .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
+            .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, accountName)
+            .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, accountType)
+            .build()
         context.contentResolver.delete(rawContactUri, null, null)
         Log.d(TAG, "deleted all linked accounts")
     }
@@ -398,42 +452,63 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
         const val DELETE_ALL = "DELETE_ALL"
 
         fun run(context: Context) {
-            if (ContextCompat.checkSelfPermission(context,
-                            Manifest.permission.WRITE_CONTACTS) == PackageManager.PERMISSION_GRANTED &&
-                    ContextCompat.checkSelfPermission(context,
-                            Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
+            if (ContextCompat.checkSelfPermission(
+                    context,
+                    Manifest.permission.WRITE_CONTACTS
+                ) == PackageManager.PERMISSION_GRANTED &&
+                ContextCompat.checkSelfPermission(
+                        context,
+                        Manifest.permission.READ_CONTACTS
+                    ) == PackageManager.PERMISSION_GRANTED
+            ) {
                 WorkManager
-                        .getInstance()
-                        .enqueue(OneTimeWorkRequest.Builder(ContactAddressBookWorker::class.java)
-                                .setInputData(Data.Builder().putBoolean(KEY_FORCE, false).build())
-                                .build())
+                    .getInstance()
+                    .enqueue(
+                        OneTimeWorkRequest.Builder(ContactAddressBookWorker::class.java)
+                            .setInputData(Data.Builder().putBoolean(KEY_FORCE, false).build())
+                            .build()
+                    )
             }
         }
 
         fun checkPermission(controller: Controller, context: Context): Boolean {
-            if (ContextCompat.checkSelfPermission(context,
-                            Manifest.permission.WRITE_CONTACTS) != PackageManager.PERMISSION_GRANTED ||
-                    ContextCompat.checkSelfPermission(context,
-                            Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
-                controller.requestPermissions(arrayOf(Manifest.permission.WRITE_CONTACTS,
-                        Manifest.permission.READ_CONTACTS), REQUEST_PERMISSION)
+            if (ContextCompat.checkSelfPermission(
+                    context,
+                    Manifest.permission.WRITE_CONTACTS
+                ) != PackageManager.PERMISSION_GRANTED ||
+                ContextCompat.checkSelfPermission(
+                        context,
+                        Manifest.permission.READ_CONTACTS
+                    ) != PackageManager.PERMISSION_GRANTED
+            ) {
+                controller.requestPermissions(
+                    arrayOf(
+                        Manifest.permission.WRITE_CONTACTS,
+                        Manifest.permission.READ_CONTACTS
+                    ),
+                    REQUEST_PERMISSION
+                )
                 return false
             } else {
                 WorkManager
-                        .getInstance()
-                        .enqueue(OneTimeWorkRequest.Builder(ContactAddressBookWorker::class.java)
-                                .setInputData(Data.Builder().putBoolean(KEY_FORCE, true).build())
-                                .build())
+                    .getInstance()
+                    .enqueue(
+                        OneTimeWorkRequest.Builder(ContactAddressBookWorker::class.java)
+                            .setInputData(Data.Builder().putBoolean(KEY_FORCE, true).build())
+                            .build()
+                    )
                 return true
             }
         }
 
         fun deleteAll() {
-                WorkManager
-                        .getInstance()
-                        .enqueue(OneTimeWorkRequest.Builder(ContactAddressBookWorker::class.java)
-                                .setInputData(Data.Builder().putBoolean(DELETE_ALL, true).build())
-                                .build())
+            WorkManager
+                .getInstance()
+                .enqueue(
+                    OneTimeWorkRequest.Builder(ContactAddressBookWorker::class.java)
+                        .setInputData(Data.Builder().putBoolean(DELETE_ALL, true).build())
+                        .build()
+                )
         }
     }
 }

+ 9 - 6
app/src/main/java/com/nextcloud/talk/jobs/DownloadFileToCacheWorker.kt

@@ -33,13 +33,16 @@ import com.nextcloud.talk.utils.ApiUtils
 import com.nextcloud.talk.utils.database.user.UserUtils
 import com.nextcloud.talk.utils.preferences.AppPreferences
 import okhttp3.ResponseBody
-import java.io.*
+import java.io.BufferedInputStream
+import java.io.File
+import java.io.FileOutputStream
+import java.io.InputStream
+import java.io.OutputStream
 import javax.inject.Inject
 
-
 @AutoInjector(NextcloudTalkApplication::class)
 class DownloadFileToCacheWorker(val context: Context, workerParameters: WorkerParameters) :
-        Worker(context, workerParameters) {
+    Worker(context, workerParameters) {
 
     private var totalFileSize: Int = -1
 
@@ -86,8 +89,9 @@ class DownloadFileToCacheWorker(val context: Context, workerParameters: WorkerPa
 
     private fun downloadFile(currentUser: UserEntity, url: String, fileName: String): Result {
         val downloadCall = ncApi.downloadFile(
-                ApiUtils.getCredentials(currentUser.username, currentUser.token),
-                url)
+            ApiUtils.getCredentials(currentUser.username, currentUser.token),
+            url
+        )
 
         return executeDownload(downloadCall.execute().body(), fileName)
     }
@@ -152,6 +156,5 @@ class DownloadFileToCacheWorker(val context: Context, workerParameters: WorkerPa
         const val KEY_FILE_SIZE = "KEY_FILE_SIZE"
         const val PROGRESS = "PROGRESS"
         const val SUCCESS = "SUCCESS"
-
     }
 }

+ 43 - 34
app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt

@@ -23,7 +23,11 @@ package com.nextcloud.talk.jobs
 import android.content.Context
 import android.net.Uri
 import android.util.Log
-import androidx.work.*
+import androidx.work.Data
+import androidx.work.OneTimeWorkRequest
+import androidx.work.WorkManager
+import androidx.work.Worker
+import androidx.work.WorkerParameters
 import autodagger.AutoInjector
 import com.nextcloud.talk.api.NcApi
 import com.nextcloud.talk.application.NextcloudTalkApplication
@@ -46,13 +50,12 @@ import retrofit2.Response
 import java.io.File
 import java.io.FileOutputStream
 import java.io.InputStream
-import java.util.*
+import java.util.ArrayList
 import javax.inject.Inject
 
-
 @AutoInjector(NextcloudTalkApplication::class)
 class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerParameters) :
-        Worker(context, workerParameters) {
+    Worker(context, workerParameters) {
 
     @Inject
     lateinit var ncApi: NcApi
@@ -107,31 +110,37 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa
         return requestBody
     }
 
-    private fun uploadFile(currentUser: UserEntity, ncTargetpath: String?, filename: String, roomToken: String?,
-                           requestBody: RequestBody?, sourcefileUri: Uri) {
+    private fun uploadFile(
+        currentUser: UserEntity,
+        ncTargetpath: String?,
+        filename: String,
+        roomToken: String?,
+        requestBody: RequestBody?,
+        sourcefileUri: Uri
+    ) {
         ncApi.uploadFile(
-                ApiUtils.getCredentials(currentUser.username, currentUser.token),
-                ApiUtils.getUrlForFileUpload(currentUser.baseUrl, currentUser.userId, ncTargetpath, filename),
-                requestBody
+            ApiUtils.getCredentials(currentUser.username, currentUser.token),
+            ApiUtils.getUrlForFileUpload(currentUser.baseUrl, currentUser.userId, ncTargetpath, filename),
+            requestBody
         )
-                .subscribeOn(Schedulers.io())
-                .observeOn(AndroidSchedulers.mainThread())
-                .subscribe(object : Observer<Response<GenericOverall>> {
-                    override fun onSubscribe(d: Disposable) {
-                    }
-
-                    override fun onNext(t: Response<GenericOverall>) {
-                    }
-
-                    override fun onError(e: Throwable) {
-                        Log.e(TAG, "failed to upload file $filename")
-                    }
-
-                    override fun onComplete() {
-                        shareFile(roomToken, currentUser, ncTargetpath, filename)
-                        copyFileToCache(sourcefileUri, filename)
-                    }
-                })
+            .subscribeOn(Schedulers.io())
+            .observeOn(AndroidSchedulers.mainThread())
+            .subscribe(object : Observer<Response<GenericOverall>> {
+                override fun onSubscribe(d: Disposable) {
+                }
+
+                override fun onNext(t: Response<GenericOverall>) {
+                }
+
+                override fun onError(e: Throwable) {
+                    Log.e(TAG, "failed to upload file $filename")
+                }
+
+                override fun onComplete() {
+                    shareFile(roomToken, currentUser, ncTargetpath, filename)
+                    copyFileToCache(sourcefileUri, filename)
+                }
+            })
     }
 
     private fun copyFileToCache(sourceFileUri: Uri, filename: String) {
@@ -151,13 +160,13 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa
         paths.add("$ncTargetpath/$filename")
 
         val data = Data.Builder()
-                .putLong(KEY_INTERNAL_USER_ID, currentUser.id)
-                .putString(KEY_ROOM_TOKEN, roomToken)
-                .putStringArray(KEY_FILE_PATHS, paths.toTypedArray())
-                .build()
+            .putLong(KEY_INTERNAL_USER_ID, currentUser.id)
+            .putString(KEY_ROOM_TOKEN, roomToken)
+            .putStringArray(KEY_FILE_PATHS, paths.toTypedArray())
+            .build()
         val shareWorker = OneTimeWorkRequest.Builder(ShareOperationWorker::class.java)
-                .setInputData(data)
-                .build()
+            .setInputData(data)
+            .build()
         WorkManager.getInstance().enqueue(shareWorker)
     }
 
@@ -167,4 +176,4 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa
         const val NC_TARGETPATH = "NC_TARGETPATH"
         const val ROOM_TOKEN = "ROOM_TOKEN"
     }
-}
+}

+ 1 - 2
app/src/main/java/com/nextcloud/talk/models/json/chat/ChatUtils.kt

@@ -25,7 +25,7 @@ package com.nextcloud.talk.models.json.chat
 class ChatUtils {
     companion object {
         fun getParsedMessage(message: String?, messageParameters: HashMap<String?, HashMap<String?, String?>>?):
-                String? {
+            String? {
             var resultMessage = message
             if (messageParameters != null && messageParameters.size > 0) {
                 for (key in messageParameters.keys) {
@@ -46,4 +46,3 @@ class ChatUtils {
         }
     }
 }
-

+ 20 - 4
app/src/main/java/com/nextcloud/talk/models/json/converters/EnumSystemMessageTypeConverter.kt

@@ -22,11 +22,28 @@ package com.nextcloud.talk.models.json.converters
 
 import com.bluelinelabs.logansquare.typeconverters.StringBasedTypeConverter
 import com.nextcloud.talk.models.json.chat.ChatMessage
-
-import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.*
+import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.CALL_ENDED
+import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.CALL_JOINED
+import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.CALL_LEFT
+import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.CALL_STARTED
+import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.CONVERSATION_CREATED
+import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.CONVERSATION_RENAMED
+import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.DUMMY
+import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.FILE_SHARED
+import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.GUESTS_ALLOWED
+import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.GUESTS_DISALLOWED
+import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.LOBBY_NONE
+import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.LOBBY_NON_MODERATORS
+import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.LOBBY_OPEN_TO_EVERYONE
+import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.MODERATOR_DEMOTED
+import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.MODERATOR_PROMOTED
+import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.PARENT_MESSAGE_DELETED
+import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.PASSWORD_REMOVED
+import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.PASSWORD_SET
+import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.USER_ADDED
+import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.USER_REMOVED
 
 /*
-
     conversation_created - {actor} created the conversation
     conversation_renamed - {actor} renamed the conversation from "foo" to "bar"
     call_joined - {actor} joined the call
@@ -40,7 +57,6 @@ import com.nextcloud.talk.models.json.chat.ChatMessage.SystemMessageType.*
     user_removed - {actor} removed {user} from the conversation
     moderator_promoted - {actor} promoted {user} to moderator
     moderator_demoted - {actor} demoted {user} from moderator
-
  */
 class EnumSystemMessageTypeConverter : StringBasedTypeConverter<ChatMessage.SystemMessageType>() {
     override fun getFromString(string: String): ChatMessage.SystemMessageType {

+ 9 - 9
app/src/main/java/com/nextcloud/talk/receivers/PackageReplacedReceiver.kt

@@ -20,12 +20,10 @@
 
 package com.nextcloud.talk.receivers
 
-import android.app.NotificationChannelGroup
 import android.app.NotificationManager
 import android.content.BroadcastReceiver
 import android.content.Context
 import android.content.Intent
-import android.content.pm.PackageInfo
 import android.content.pm.PackageManager
 import android.os.Build
 import android.util.Log
@@ -34,7 +32,6 @@ import com.nextcloud.talk.application.NextcloudTalkApplication
 import com.nextcloud.talk.utils.NotificationUtils
 import com.nextcloud.talk.utils.database.user.UserUtils
 import com.nextcloud.talk.utils.preferences.AppPreferences
-
 import javax.inject.Inject
 
 @AutoInjector(NextcloudTalkApplication::class)
@@ -50,16 +47,20 @@ class PackageReplacedReceiver : BroadcastReceiver() {
         NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
 
         if (intent != null && intent.action != null &&
-                intent.action == "android.intent.action.MY_PACKAGE_REPLACED") {
+            intent.action == "android.intent.action.MY_PACKAGE_REPLACED"
+        ) {
             try {
                 val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
                 if (packageInfo.versionCode > 43 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-                    val notificationManager = context.getSystemService(Context
-                            .NOTIFICATION_SERVICE) as NotificationManager
+                    val notificationManager = context.getSystemService(
+                        Context
+                            .NOTIFICATION_SERVICE
+                    ) as NotificationManager
 
                     if (!appPreferences.isNotificationChannelUpgradedToV2) {
-                        for (notificationChannelGroup in notificationManager
-                                .notificationChannelGroups) {
+                        for (
+                            notificationChannelGroup in notificationManager.notificationChannelGroups
+                        ) {
                             notificationManager.deleteNotificationChannelGroup(notificationChannelGroup.id)
                         }
 
@@ -80,7 +81,6 @@ class PackageReplacedReceiver : BroadcastReceiver() {
             } catch (e: PackageManager.NameNotFoundException) {
                 Log.e(TAG, "Failed to fetch package info")
             }
-
         }
     }
 

+ 1 - 2
app/src/main/java/com/nextcloud/talk/ui/dialog/AttachmentDialog.kt

@@ -32,7 +32,6 @@ import com.nextcloud.talk.R
 import com.nextcloud.talk.components.filebrowser.controllers.BrowserController
 import com.nextcloud.talk.controllers.ChatController
 
-
 class AttachmentDialog(val activity: Activity, var chatController: ChatController) : BottomSheetDialog(activity) {
 
     @BindView(R.id.txt_attach_file_from_local)
@@ -54,7 +53,7 @@ class AttachmentDialog(val activity: Activity, var chatController: ChatControlle
 
         var serverName = chatController.conversationUser?.serverName
         attachFromCloud?.text = chatController.resources?.let {
-            if(serverName.isNullOrEmpty()){
+            if (serverName.isNullOrEmpty()) {
                 serverName = it.getString(R.string.nc_server_product_name)
             }
             String.format(it.getString(R.string.nc_upload_from_cloud), serverName)

+ 7 - 6
app/src/main/java/com/nextcloud/talk/ui/dialog/ScopeDialog.kt

@@ -30,12 +30,13 @@ import com.nextcloud.talk.R
 import com.nextcloud.talk.controllers.ProfileController
 import com.nextcloud.talk.models.json.userprofile.Scope
 
-
-class ScopeDialog(con: Context,
-                  private val userInfoAdapter: ProfileController.UserInfoAdapter,
-                  private val field: ProfileController.Field,
-                  private val position: Int) :
-        BottomSheetDialog(con) {
+class ScopeDialog(
+    con: Context,
+    private val userInfoAdapter: ProfileController.UserInfoAdapter,
+    private val field: ProfileController.Field,
+    private val position: Int
+) :
+    BottomSheetDialog(con) {
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         val view = layoutInflater.inflate(R.layout.dialog_scope, null)

+ 19 - 11
app/src/main/java/com/nextcloud/talk/utils/AccountUtils.kt

@@ -32,7 +32,8 @@ import com.nextcloud.talk.R
 import com.nextcloud.talk.application.NextcloudTalkApplication
 import com.nextcloud.talk.models.ImportAccount
 import com.nextcloud.talk.models.database.UserEntity
-import java.util.*
+import java.util.ArrayList
+import java.util.Arrays
 
 object AccountUtils {
 
@@ -60,14 +61,15 @@ object AccountUtils {
                             break
                         }
                     } else {
-                        if (internalUserEntity.username == importAccount.username && (internalUserEntity
-                                        .baseUrl == "http://" + importAccount.baseUrl ||
-                                        internalUserEntity.baseUrl == "https://" + importAccount
-                                        .baseUrl)) {
+                        if (internalUserEntity.username == importAccount.username &&
+                            (
+                                internalUserEntity.baseUrl == "http://" + importAccount.baseUrl ||
+                                    internalUserEntity.baseUrl == "https://" + importAccount.baseUrl
+                                )
+                        ) {
                             accountFound = true
                             break
                         }
-
                     }
                 } else {
                     accountFound = true
@@ -88,8 +90,12 @@ object AccountUtils {
         val packageManager = context.packageManager
         var appName = ""
         try {
-            appName = packageManager.getApplicationLabel(packageManager.getApplicationInfo(packageName,
-                    PackageManager.GET_META_DATA)) as String
+            appName = packageManager.getApplicationLabel(
+                packageManager.getApplicationInfo(
+                    packageName,
+                    PackageManager.GET_META_DATA
+                )
+            ) as String
         } catch (e: PackageManager.NameNotFoundException) {
             Log.e(TAG, "Failed to get app name based on package")
         }
@@ -103,7 +109,10 @@ object AccountUtils {
             val packageInfo = pm.getPackageInfo(context.getString(R.string.nc_import_accounts_from), 0)
             if (packageInfo.versionCode >= 30060151) {
                 val ownSignatures = pm.getPackageInfo(context.packageName, PackageManager.GET_SIGNATURES).signatures
-                val filesAppSignatures = pm.getPackageInfo(context.getString(R.string.nc_import_accounts_from), PackageManager.GET_SIGNATURES).signatures
+                val filesAppSignatures = pm.getPackageInfo(
+                    context.getString(R.string.nc_import_accounts_from),
+                    PackageManager.GET_SIGNATURES
+                ).signatures
 
                 if (Arrays.equals(ownSignatures, filesAppSignatures)) {
                     val accMgr = AccountManager.get(context)
@@ -118,7 +127,7 @@ object AccountUtils {
                 }
             }
         } catch (appNotFoundException: PackageManager.NameNotFoundException) {
-
+            // ignore
         }
 
         return false
@@ -146,4 +155,3 @@ object AccountUtils {
         return ImportAccount(username, password, urlString)
     }
 }
-

+ 15 - 5
app/src/main/java/com/nextcloud/talk/utils/ConductorRemapping.kt

@@ -27,7 +27,13 @@ import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
 import com.nextcloud.talk.controllers.ChatController
 
 object ConductorRemapping {
-    fun remapChatController(router: Router, internalUserId: Long, roomTokenOrId: String, bundle: Bundle, replaceTop: Boolean) {
+    fun remapChatController(
+        router: Router,
+        internalUserId: Long,
+        roomTokenOrId: String,
+        bundle: Bundle,
+        replaceTop: Boolean
+    ) {
         val tag = "$internalUserId@$roomTokenOrId"
         if (router.getControllerWithTag(tag) != null) {
             val backstack = router.backstack
@@ -44,13 +50,17 @@ object ConductorRemapping {
             router.setBackstack(backstack, HorizontalChangeHandler())
         } else {
             if (!replaceTop) {
-                router.pushController(RouterTransaction.with(ChatController(bundle))
+                router.pushController(
+                    RouterTransaction.with(ChatController(bundle))
                         .pushChangeHandler(HorizontalChangeHandler())
-                        .popChangeHandler(HorizontalChangeHandler()).tag(tag))
+                        .popChangeHandler(HorizontalChangeHandler()).tag(tag)
+                )
             } else {
-                router.replaceTopController(RouterTransaction.with(ChatController(bundle))
+                router.replaceTopController(
+                    RouterTransaction.with(ChatController(bundle))
                         .pushChangeHandler(HorizontalChangeHandler())
-                        .popChangeHandler(HorizontalChangeHandler()).tag(tag))
+                        .popChangeHandler(HorizontalChangeHandler()).tag(tag)
+                )
             }
         }
     }

+ 8 - 5
app/src/main/java/com/nextcloud/talk/utils/DateUtils.kt

@@ -21,8 +21,9 @@
 package com.nextcloud.talk.utils
 
 import java.text.DateFormat
-import java.util.*
-
+import java.util.Calendar
+import java.util.Date
+import java.util.Locale
 
 object DateUtils {
     fun getLocalDateTimeStringFromTimestamp(timestamp: Long): String {
@@ -30,14 +31,16 @@ object DateUtils {
         val tz = cal.timeZone
 
         /* date formatter in local timezone */
-        val format = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.SHORT, Locale
-                .getDefault())
+        val format = DateFormat.getDateTimeInstance(
+            DateFormat.DEFAULT, DateFormat.SHORT,
+            Locale.getDefault()
+        )
         format.timeZone = tz
 
         return format.format(Date(timestamp))
     }
 
     fun getLocalDateStringFromTimestampForLobby(timestamp: Long): String {
-        return getLocalDateTimeStringFromTimestamp(timestamp * 1000);
+        return getLocalDateTimeStringFromTimestamp(timestamp * 1000)
     }
 }

+ 28 - 16
app/src/main/java/com/nextcloud/talk/utils/DrawableUtils.kt

@@ -21,12 +21,10 @@
 package com.nextcloud.talk.utils
 
 import com.nextcloud.talk.R
-
 import java.util.HashMap
 
 object DrawableUtils {
 
-
     fun getDrawableResourceIdForMimeType(mimetype: String): Int {
         var localMimetype = mimetype
         val drawableMap = HashMap<String, Int>()
@@ -55,15 +53,20 @@ object DrawableUtils {
         drawableMap["application/vnd.google-earth.kmz"] = R.drawable.ic_mimetype_location
         drawableMap["application/vnd.ms-excel"] = R.drawable.ic_mimetype_x_office_spreadsheet
         drawableMap["application/vnd.ms-excel.addin.macroEnabled.12"] = R.drawable.ic_mimetype_x_office_spreadsheet
-        drawableMap["application/vnd.ms-excel.sheet.binary.macroEnabled.12"] = R.drawable.ic_mimetype_x_office_spreadsheet
+        drawableMap["application/vnd.ms-excel.sheet.binary.macroEnabled.12"] =
+            R.drawable.ic_mimetype_x_office_spreadsheet
         drawableMap["application/vnd.ms-excel.sheet.macroEnabled.12"] = R.drawable.ic_mimetype_x_office_spreadsheet
         drawableMap["application/vnd.ms-excel.template.macroEnabled.12"] = R.drawable.ic_mimetype_x_office_spreadsheet
         drawableMap["application/vnd.ms-fontobject"] = R.drawable.ic_mimetype_image
         drawableMap["application/vnd.ms-powerpoint"] = R.drawable.ic_mimetype_x_office_presentation
-        drawableMap["application/vnd.ms-powerpoint.addin.macroEnabled.12"] = R.drawable.ic_mimetype_x_office_presentation
-        drawableMap["application/vnd.ms-powerpoint.presentation.macroEnabled.12"] = R.drawable.ic_mimetype_x_office_presentation
-        drawableMap["application/vnd.ms-powerpoint.slideshow.macroEnabled.12"] = R.drawable.ic_mimetype_x_office_presentation
-        drawableMap["application/vnd.ms-powerpoint.template.macroEnabled.12"] = R.drawable.ic_mimetype_x_office_presentation
+        drawableMap["application/vnd.ms-powerpoint.addin.macroEnabled.12"] =
+            R.drawable.ic_mimetype_x_office_presentation
+        drawableMap["application/vnd.ms-powerpoint.presentation.macroEnabled.12"] =
+            R.drawable.ic_mimetype_x_office_presentation
+        drawableMap["application/vnd.ms-powerpoint.slideshow.macroEnabled.12"] =
+            R.drawable.ic_mimetype_x_office_presentation
+        drawableMap["application/vnd.ms-powerpoint.template.macroEnabled.12"] =
+            R.drawable.ic_mimetype_x_office_presentation
         drawableMap["application/vnd.ms-visio.drawing.macroEnabled.12"] = R.drawable.ic_mimetype_x_office_document
         drawableMap["application/vnd.ms-visio.drawing"] = R.drawable.ic_mimetype_x_office_document
         drawableMap["application/vnd.ms-visio.stencil.macroEnabled.12"] = R.drawable.ic_mimetype_x_office_document
@@ -72,20 +75,29 @@ object DrawableUtils {
         drawableMap["application/vnd.ms-visio.template"] = R.drawable.ic_mimetype_x_office_document
         drawableMap["application/vnd.ms-word.template.macroEnabled.12"] = R.drawable.ic_mimetype_x_office_document
         drawableMap["application/vnd.oasis.opendocument.presentation"] = R.drawable.ic_mimetype_x_office_presentation
-        drawableMap["application/vnd.oasis.opendocument.presentation-template"] = R.drawable.ic_mimetype_x_office_presentation
+        drawableMap["application/vnd.oasis.opendocument.presentation-template"] =
+            R.drawable.ic_mimetype_x_office_presentation
         drawableMap["application/vnd.oasis.opendocument.spreadsheet"] = R.drawable.ic_mimetype_x_office_spreadsheet
-        drawableMap["application/vnd.oasis.opendocument.spreadsheet-template"] = R.drawable.ic_mimetype_x_office_spreadsheet
+        drawableMap["application/vnd.oasis.opendocument.spreadsheet-template"] =
+            R.drawable.ic_mimetype_x_office_spreadsheet
         drawableMap["application/vnd.oasis.opendocument.text"] = R.drawable.ic_mimetype_x_office_document
         drawableMap["application/vnd.oasis.opendocument.text-master"] = R.drawable.ic_mimetype_x_office_document
         drawableMap["application/vnd.oasis.opendocument.text-template"] = R.drawable.ic_mimetype_x_office_document
         drawableMap["application/vnd.oasis.opendocument.text-web"] = R.drawable.ic_mimetype_x_office_document
-        drawableMap["application/vnd.openxmlformats-officedocument.presentationml.presentation"] = R.drawable.ic_mimetype_x_office_presentation
-        drawableMap["application/vnd.openxmlformats-officedocument.presentationml.slideshow"] = R.drawable.ic_mimetype_x_office_presentation
-        drawableMap["application/vnd.openxmlformats-officedocument.presentationml.template"] = R.drawable.ic_mimetype_x_office_presentation
-        drawableMap["application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"] = R.drawable.ic_mimetype_x_office_spreadsheet
-        drawableMap["application/vnd.openxmlformats-officedocument.spreadsheetml.template"] = R.drawable.ic_mimetype_x_office_spreadsheet
-        drawableMap["application/vnd.openxmlformats-officedocument.wordprocessingml.document"] = R.drawable.ic_mimetype_x_office_document
-        drawableMap["application/vnd.openxmlformats-officedocument.wordprocessingml.template"] = R.drawable.ic_mimetype_x_office_document
+        drawableMap["application/vnd.openxmlformats-officedocument.presentationml.presentation"] =
+            R.drawable.ic_mimetype_x_office_presentation
+        drawableMap["application/vnd.openxmlformats-officedocument.presentationml.slideshow"] =
+            R.drawable.ic_mimetype_x_office_presentation
+        drawableMap["application/vnd.openxmlformats-officedocument.presentationml.template"] =
+            R.drawable.ic_mimetype_x_office_presentation
+        drawableMap["application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"] =
+            R.drawable.ic_mimetype_x_office_spreadsheet
+        drawableMap["application/vnd.openxmlformats-officedocument.spreadsheetml.template"] =
+            R.drawable.ic_mimetype_x_office_spreadsheet
+        drawableMap["application/vnd.openxmlformats-officedocument.wordprocessingml.document"] =
+            R.drawable.ic_mimetype_x_office_document
+        drawableMap["application/vnd.openxmlformats-officedocument.wordprocessingml.template"] =
+            R.drawable.ic_mimetype_x_office_document
         drawableMap["application/vnd.visio"] = R.drawable.ic_mimetype_x_office_document
         drawableMap["application/vnd.wordperfect"] = R.drawable.ic_mimetype_x_office_document
         drawableMap["application/x-7z-compressed"] = R.drawable.ic_mimetype_package_x_generic

+ 6 - 5
app/src/main/java/com/nextcloud/talk/utils/LoggingUtils.kt

@@ -29,7 +29,7 @@ import com.nextcloud.talk.BuildConfig
 import java.io.FileNotFoundException
 import java.io.IOException
 import java.text.SimpleDateFormat
-import java.util.*
+import java.util.Date
 
 object LoggingUtils {
     fun writeLogEntryToFile(context: Context, logEntry: String) {
@@ -38,8 +38,10 @@ object LoggingUtils {
         val logEntryWithDateTime = dateFormat.format(date) + ": " + logEntry + "\n"
 
         try {
-            val outputStream = context.openFileOutput("nc_log.txt",
-                    Context.MODE_PRIVATE or Context.MODE_APPEND)
+            val outputStream = context.openFileOutput(
+                "nc_log.txt",
+                Context.MODE_PRIVATE or Context.MODE_APPEND
+            )
             outputStream.write(logEntryWithDateTime.toByteArray())
             outputStream.flush()
             outputStream.close()
@@ -48,13 +50,12 @@ object LoggingUtils {
         } catch (e: IOException) {
             e.printStackTrace()
         }
-
     }
 
     fun sendMailWithAttachment(context: Context) {
         val logFile = context.getFileStreamPath("nc_log.txt")
         val emailIntent = Intent(Intent.ACTION_SEND)
-        val mailto = "mario@nextcloud.com"
+        val mailto = "android@nextcloud.com"
         emailIntent.putExtra(Intent.EXTRA_EMAIL, arrayOf(mailto))
         emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Talk logs")
         emailIntent.type = "text/plain"

+ 71 - 26
app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt

@@ -33,7 +33,7 @@ import android.service.notification.StatusBarNotification
 import com.nextcloud.talk.R
 import com.nextcloud.talk.models.database.UserEntity
 import com.nextcloud.talk.utils.bundle.BundleKeys
-import java.util.*
+import java.util.Objects
 
 object NotificationUtils {
     val NOTIFICATION_CHANNEL_CALLS = "NOTIFICATION_CHANNEL_CALLS"
@@ -47,25 +47,50 @@ object NotificationUtils {
         return longArrayOf(0L, 400L, 800L, 600L, 800L, 800L, 800L, 1000L)
     }
 
-    fun getNotificationChannelId(channelName: String,
-                                 channelDescription: String, enableLights: Boolean,
-                                 importance: Int, sound: Uri, audioAttributes: AudioAttributes, vibrationPattern: LongArray?, bypassDnd: Boolean): String {
-        return Objects.hash(channelName, channelDescription, enableLights, importance, sound, audioAttributes, vibrationPattern, bypassDnd).toString()
+    fun getNotificationChannelId(
+        channelName: String,
+        channelDescription: String,
+        enableLights: Boolean,
+        importance: Int,
+        sound: Uri,
+        audioAttributes: AudioAttributes,
+        vibrationPattern: LongArray?,
+        bypassDnd: Boolean
+    ): String {
+        return Objects.hash(
+            channelName,
+            channelDescription,
+            enableLights,
+            importance,
+            sound,
+            audioAttributes,
+            vibrationPattern,
+            bypassDnd
+        ).toString()
     }
 
     @TargetApi(Build.VERSION_CODES.O)
-    fun createNotificationChannel(context: Context,
-                                  channelId: String, channelName: String,
-                                  channelDescription: String, enableLights: Boolean,
-                                  importance: Int, sound: Uri, audioAttributes: AudioAttributes,
-                                  vibrationPattern: LongArray?, bypassDnd: Boolean = false) {
+    fun createNotificationChannel(
+        context: Context,
+        channelId: String,
+        channelName: String,
+        channelDescription: String,
+        enableLights: Boolean,
+        importance: Int,
+        sound: Uri,
+        audioAttributes: AudioAttributes,
+        vibrationPattern: LongArray?,
+        bypassDnd: Boolean = false
+    ) {
 
         val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
 
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && notificationManager.getNotificationChannel(channelId) == null) {
 
-            val channel = NotificationChannel(channelId, channelName,
-                    importance)
+            val channel = NotificationChannel(
+                channelId, channelName,
+                importance
+            )
 
             channel.description = channelDescription
             channel.enableLights(enableLights)
@@ -84,8 +109,11 @@ object NotificationUtils {
     }
 
     @TargetApi(Build.VERSION_CODES.O)
-    fun createNotificationChannelGroup(context: Context,
-                                       groupId: String, groupName: CharSequence) {
+    fun createNotificationChannelGroup(
+        context: Context,
+        groupId: String,
+        groupName: CharSequence
+    ) {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
             val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
 
@@ -113,12 +141,12 @@ object NotificationUtils {
                 }
             }
         }
-
     }
 
     fun cancelExistingNotificationWithId(context: Context?, conversationUser: UserEntity, notificationId: Long) {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && conversationUser.id != -1L &&
-                context != null) {
+            context != null
+        ) {
 
             val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
 
@@ -128,7 +156,10 @@ object NotificationUtils {
                 notification = statusBarNotification.notification
 
                 if (notification != null && !notification.extras.isEmpty) {
-                    if (conversationUser.id == notification.extras.getLong(BundleKeys.KEY_INTERNAL_USER_ID) && notificationId == notification.extras.getLong(BundleKeys.KEY_NOTIFICATION_ID)) {
+                    if (conversationUser.id == notification.extras.getLong(BundleKeys.KEY_INTERNAL_USER_ID) && notificationId == notification.extras.getLong(
+                            BundleKeys.KEY_NOTIFICATION_ID
+                        )
+                    ) {
                         notificationManager.cancel(statusBarNotification.id)
                     }
                 }
@@ -136,11 +167,14 @@ object NotificationUtils {
         }
     }
 
-    fun findNotificationForRoom(context: Context?,
-                                conversationUser: UserEntity,
-                                roomTokenOrId: String): StatusBarNotification? {
+    fun findNotificationForRoom(
+        context: Context?,
+        conversationUser: UserEntity,
+        roomTokenOrId: String
+    ): StatusBarNotification? {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && conversationUser.id != -1L &&
-                context != null) {
+            context != null
+        ) {
 
             val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
 
@@ -150,7 +184,10 @@ object NotificationUtils {
                 notification = statusBarNotification.notification
 
                 if (notification != null && !notification.extras.isEmpty) {
-                    if (conversationUser.id == notification.extras.getLong(BundleKeys.KEY_INTERNAL_USER_ID) && roomTokenOrId == statusBarNotification.notification.extras.getString(BundleKeys.KEY_ROOM_TOKEN)) {
+                    if (conversationUser.id == notification.extras.getLong(BundleKeys.KEY_INTERNAL_USER_ID) && roomTokenOrId == statusBarNotification.notification.extras.getString(
+                            BundleKeys.KEY_ROOM_TOKEN
+                        )
+                    ) {
                         return statusBarNotification
                     }
                 }
@@ -160,10 +197,14 @@ object NotificationUtils {
         return null
     }
 
-    fun cancelExistingNotificationsForRoom(context: Context?, conversationUser: UserEntity,
-                                           roomTokenOrId: String) {
+    fun cancelExistingNotificationsForRoom(
+        context: Context?,
+        conversationUser: UserEntity,
+        roomTokenOrId: String
+    ) {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && conversationUser.id != -1L &&
-                context != null) {
+            context != null
+        ) {
 
             val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
 
@@ -173,7 +214,11 @@ object NotificationUtils {
                 notification = statusBarNotification.notification
 
                 if (notification != null && !notification.extras.isEmpty) {
-                    if (conversationUser.id == notification.extras.getLong(BundleKeys.KEY_INTERNAL_USER_ID) && roomTokenOrId == statusBarNotification.notification.extras.getString(BundleKeys.KEY_ROOM_TOKEN)) {
+                    if (conversationUser.id == notification.extras.getLong(BundleKeys.KEY_INTERNAL_USER_ID) &&
+                        roomTokenOrId == statusBarNotification.notification.extras.getString(
+                                BundleKeys.KEY_ROOM_TOKEN
+                            )
+                    ) {
                         notificationManager.cancel(statusBarNotification.id)
                     }
                 }

+ 0 - 2
app/src/main/java/com/nextcloud/talk/utils/UriUtils.kt

@@ -25,7 +25,6 @@ import android.database.Cursor
 import android.net.Uri
 import android.provider.OpenableColumns
 import android.util.Log
-import com.nextcloud.talk.jobs.UploadAndShareFilesWorker
 
 object UriUtils {
 
@@ -51,5 +50,4 @@ object UriUtils {
         }
         return filename
     }
-
 }

+ 2 - 2
app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt

@@ -21,8 +21,8 @@
 package com.nextcloud.talk.utils.bundle
 
 object BundleKeys {
-    val KEY_SELECTED_USERS = "KEY_SELECTED_USERS";
-    val KEY_SELECTED_GROUPS = "KEY_SELECTED_GROUPS";
+    val KEY_SELECTED_USERS = "KEY_SELECTED_USERS"
+    val KEY_SELECTED_GROUPS = "KEY_SELECTED_GROUPS"
     val KEY_USERNAME = "KEY_USERNAME"
     val KEY_TOKEN = "KEY_TOKEN"
     val KEY_BASE_URL = "KEY_BASE_URL"

+ 37 - 33
app/src/main/java/com/nextcloud/talk/utils/ssl/SSLSocketFactoryCompat.kt

@@ -13,11 +13,17 @@ import java.io.IOException
 import java.net.InetAddress
 import java.net.Socket
 import java.security.GeneralSecurityException
-import java.util.*
-import javax.net.ssl.*
-
-class SSLSocketFactoryCompat(keyManager: KeyManager?,
-                             trustManager: X509TrustManager) : SSLSocketFactory() {
+import java.util.LinkedList
+import javax.net.ssl.KeyManager
+import javax.net.ssl.SSLContext
+import javax.net.ssl.SSLSocket
+import javax.net.ssl.SSLSocketFactory
+import javax.net.ssl.X509TrustManager
+
+class SSLSocketFactoryCompat(
+    keyManager: KeyManager?,
+    trustManager: X509TrustManager
+) : SSLSocketFactory() {
 
     private var delegate: SSLSocketFactory
 
@@ -50,24 +56,24 @@ class SSLSocketFactoryCompat(keyManager: KeyManager?,
 
                         /* set up reasonable cipher suites */
                         val knownCiphers = arrayOf<String>(
-                                // TLS 1.2
-                                "TLS_RSA_WITH_AES_256_GCM_SHA384",
-                                "TLS_RSA_WITH_AES_128_GCM_SHA256",
-                                "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
-                                "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
-                                "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
-                                "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
-                                "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
-                                // maximum interoperability
-                                "TLS_RSA_WITH_3DES_EDE_CBC_SHA",
-                                "SSL_RSA_WITH_3DES_EDE_CBC_SHA",
-                                "TLS_RSA_WITH_AES_128_CBC_SHA",
-                                // additionally
-                                "TLS_RSA_WITH_AES_256_CBC_SHA",
-                                "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
-                                "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
-                                "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
-                                "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"
+                            // TLS 1.2
+                            "TLS_RSA_WITH_AES_256_GCM_SHA384",
+                            "TLS_RSA_WITH_AES_128_GCM_SHA256",
+                            "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
+                            "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
+                            "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
+                            "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
+                            "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+                            // maximum interoperability
+                            "TLS_RSA_WITH_3DES_EDE_CBC_SHA",
+                            "SSL_RSA_WITH_3DES_EDE_CBC_SHA",
+                            "TLS_RSA_WITH_AES_128_CBC_SHA",
+                            // additionally
+                            "TLS_RSA_WITH_AES_256_CBC_SHA",
+                            "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
+                            "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
+                            "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
+                            "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"
                         )
                         val availableCiphers = socket.supportedCipherSuites
 
@@ -89,31 +95,31 @@ class SSLSocketFactoryCompat(keyManager: KeyManager?,
                 } catch (e: IOException) {
                     // Exception is to be ignored
                 } finally {
-                    socket?.close()     // doesn't implement Closeable on all supported Android versions
+                    socket?.close() // doesn't implement Closeable on all supported Android versions
                 }
             }
         }
     }
 
-
     init {
         try {
             val sslContext = SSLContext.getInstance("TLS")
             sslContext.init(
-                    if (keyManager != null) arrayOf(keyManager) else null,
-                    arrayOf(trustManager),
-                    null)
+                if (keyManager != null) arrayOf(keyManager) else null,
+                arrayOf(trustManager),
+                null
+            )
             delegate = sslContext.socketFactory
         } catch (e: GeneralSecurityException) {
-            throw IllegalStateException()      // system has no TLS
+            throw IllegalStateException() // system has no TLS
         }
     }
 
     override fun getDefaultCipherSuites(): Array<String>? = cipherSuites
-            ?: delegate.defaultCipherSuites
+        ?: delegate.defaultCipherSuites
 
     override fun getSupportedCipherSuites(): Array<String>? = cipherSuites
-            ?: delegate.supportedCipherSuites
+        ?: delegate.supportedCipherSuites
 
     override fun createSocket(s: Socket, host: String, port: Int, autoClose: Boolean): Socket {
         val ssl = delegate.createSocket(s, host, port, autoClose)
@@ -150,10 +156,8 @@ class SSLSocketFactoryCompat(keyManager: KeyManager?,
         return ssl
     }
 
-
     private fun upgradeTLS(ssl: SSLSocket) {
         protocols?.let { ssl.enabledProtocols = it }
         cipherSuites?.let { ssl.enabledCipherSuites = it }
     }
-
 }

Some files were not shown because too many files changed in this diff