From 762cebb093e68af4731d1b7d08bb7e69c4dad2e9 Mon Sep 17 00:00:00 2001
From: Janne Koschinski <janne@kuschku.de>
Date: Wed, 16 May 2018 23:41:35 +0200
Subject: [PATCH] Fixes additional issues with WHOIS functionality

---
 .../ui/chat/info/user/IrcUserInfo.kt          |  36 ++++
 .../ui/chat/info/user/UserInfoFragment.kt     | 187 ++++++++++--------
 .../quasseldroid/util/avatars/AvatarHelper.kt |  28 ++-
 3 files changed, 164 insertions(+), 87 deletions(-)
 create mode 100644 app/src/main/java/de/kuschku/quasseldroid/ui/chat/info/user/IrcUserInfo.kt

diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/info/user/IrcUserInfo.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/info/user/IrcUserInfo.kt
new file mode 100644
index 000000000..05fbf8d6a
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/info/user/IrcUserInfo.kt
@@ -0,0 +1,36 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2018 Janne Koschinski
+ * Copyright (c) 2018 The Quassel Project
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package de.kuschku.quasseldroid.ui.chat.info.user
+
+import de.kuschku.libquassel.quassel.syncables.Network
+
+data class IrcUserInfo(
+  val networkId: Int,
+  val nick: String,
+  val user: String? = null,
+  val host: String? = null,
+  val account: String? = null,
+  val server: String? = null,
+  val realName: String? = null,
+  val isAway: Boolean? = false,
+  val awayMessage: String? = null,
+  val network: Network? = null,
+  val knownToCore: Boolean = false
+)
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/info/user/UserInfoFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/info/user/UserInfoFragment.kt
index c5f7f7450..3f33ead50 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/info/user/UserInfoFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/info/user/UserInfoFragment.kt
@@ -32,9 +32,12 @@ import android.widget.Toast
 import butterknife.BindView
 import butterknife.ButterKnife
 import de.kuschku.libquassel.protocol.Buffer_Type
+import de.kuschku.libquassel.quassel.BufferInfo
 import de.kuschku.libquassel.quassel.syncables.IrcUser
 import de.kuschku.libquassel.util.IrcUserUtils
+import de.kuschku.libquassel.util.Optional
 import de.kuschku.libquassel.util.helpers.nullIf
+import de.kuschku.libquassel.util.helpers.value
 import de.kuschku.quasseldroid.R
 import de.kuschku.quasseldroid.settings.MessageSettings
 import de.kuschku.quasseldroid.ui.chat.ChatActivity
@@ -130,31 +133,55 @@ class UserInfoFragment : ServiceBoundFragment() {
       getColor(0, 0)
     }
 
-    val networkId = arguments?.getInt("networkId")
-    val nickName = arguments?.getString("nick")
+    val networkId2 = arguments?.getInt("networkId")
+    val nickName2 = arguments?.getString("nick")
     combineLatest(viewModel.session, viewModel.networks).switchMap { (sessionOptional, networks) ->
+      fun processUser(user: IrcUser, info: BufferInfo? = null) = when {
+        user == IrcUser.NULL && info != null -> Optional.of(IrcUserInfo(
+          info.networkId,
+          info.bufferName ?: ""
+        ))
+        user == IrcUser.NULL                 -> Optional.empty()
+        else                                 -> Optional.of(IrcUserInfo(
+          networkId = user.network().networkId(),
+          nick = user.nick(),
+          user = user.user(),
+          host = user.host(),
+          account = user.account(),
+          server = user.server(),
+          realName = user.realName(),
+          isAway = user.isAway(),
+          awayMessage = user.awayMessage(),
+          network = user.network(),
+          knownToCore = true
+        ))
+      }
+
       if (openBuffer == true) {
         val session = sessionOptional?.orNull()
         val bufferSyncer = session?.bufferSyncer
         val bufferInfo = bufferSyncer?.bufferInfo(arguments?.getInt("bufferId") ?: -1)
         bufferInfo?.let {
-          networks[it.networkId]?.liveIrcUser(it.bufferName)
+          networks[it.networkId]?.liveIrcUser(it.bufferName)?.switchMap(IrcUser::updates)?.map {
+            processUser(it, bufferInfo)
+          }
         }
       } else {
-        networks[networkId]?.liveIrcUser(nickName)
-      } ?: Observable.just(IrcUser.NULL)
-    }.filter {
-      it != IrcUser.NULL
-    }.switchMap(IrcUser::updates).toLiveData().observe(this, Observer { user ->
-      if (user != null) {
-        val senderColorIndex = IrcUserUtils.senderColor(user.nick())
-        val rawInitial = user.nick().trimStart(*IGNORED_CHARS).firstOrNull()
-                         ?: user.nick().firstOrNull()
+        networks[networkId2]
+          ?.liveIrcUser(nickName2)
+          ?.switchMap(IrcUser::updates)
+          ?.map { user -> processUser(user) }
+      } ?: Observable.just(IrcUser.NULL).map { user -> processUser(user) }
+    }.toLiveData().observe(this, Observer {
+      val processUser = { user: IrcUserInfo ->
+        val senderColorIndex = IrcUserUtils.senderColor(user.nick)
+        val rawInitial = user.nick.trimStart(*IGNORED_CHARS).firstOrNull()
+                         ?: user.nick.firstOrNull()
         val initial = rawInitial?.toUpperCase().toString()
         val senderColor = when (messageSettings.colorizeNicknames) {
           MessageSettings.ColorizeNicknamesMode.ALL          -> senderColors[senderColorIndex]
           MessageSettings.ColorizeNicknamesMode.ALL_BUT_MINE ->
-            if (user.network().isMyNick(user.nick())) selfColor
+            if (user.network?.isMyNick(user.nick) == true) selfColor
             else senderColors[senderColorIndex]
           MessageSettings.ColorizeNicknamesMode.NONE         -> selfColor
         }
@@ -165,84 +192,90 @@ class UserInfoFragment : ServiceBoundFragment() {
           crop = false
         )
 
-        nick.text = user.nick()
-        realName.text = contentFormatter.formatContent(user.realName())
-        realName.visibleIf(user.realName().isNotBlank() && user.realName() != user.nick())
+        nick.text = user.nick
+        realName.text = contentFormatter.formatContent(user.realName ?: "")
+        realName.visibleIf(!user.realName.isNullOrBlank() && user.realName != user.nick)
 
-        awayMessage.text = user.awayMessage().nullIf { it.isBlank() } ?: SpannableString(getString(R.string.label_no_away_message)).apply {
+        awayMessage.text = user.awayMessage.nullIf { it.isNullOrBlank() } ?: SpannableString(
+          getString(
+            R.string.label_no_away_message)).apply {
           setSpan(IrcItalicSpan(), 0, length, 0)
         }
-        awayContainer.visibleIf(user.isAway())
-
-        account.text = user.account()
-        accountContainer.visibleIf(user.account().isNotBlank())
-
-        ident.text = user.user()
-        identContainer.visibleIf(user.user().isNotBlank())
-
-        host.text = user.host()
-        hostContainer.visibleIf(user.host().isNotBlank())
-
-        server.text = user.server()
-        serverContainer.visibleIf(user.server().isNotBlank())
-      }
-    })
-
-    actionQuery.setOnClickListener {
-      viewModel.session {
-        it.orNull()?.let { session ->
-          val info = session.bufferSyncer?.find(
-            bufferName = nickName,
-            networkId = networkId,
-            type = Buffer_Type.of(Buffer_Type.QueryBuffer)
-          )
-
-          if (info != null) {
-            ChatActivity.launch(requireContext(), bufferId = info.bufferId)
-          } else {
-            viewModel.allBuffers.map {
-              listOfNotNull(it.find {
-                it.networkId == networkId && it.bufferName == nickName
+        awayContainer.visibleIf(user.isAway == true)
+
+        account.text = user.account
+        accountContainer.visibleIf(!user.account.isNullOrBlank())
+
+        ident.text = user.user
+        identContainer.visibleIf(!user.user.isNullOrBlank())
+
+        host.text = user.host
+        hostContainer.visibleIf(!user.host.isNullOrBlank())
+
+        server.text = user.server
+        serverContainer.visibleIf(!user.server.isNullOrBlank())
+
+        actionWhois.visibleIf(user.knownToCore)
+
+        actionQuery.setOnClickListener {
+          viewModel.session.value?.orNull()?.let { session ->
+            val info = session.bufferSyncer?.find(
+              bufferName = user.nick,
+              networkId = user.networkId,
+              type = Buffer_Type.of(Buffer_Type.QueryBuffer)
+            )
+
+            if (info != null) {
+              ChatActivity.launch(requireContext(),
+                                  bufferId = info.bufferId)
+            } else {
+              viewModel.allBuffers.map {
+                listOfNotNull(it.find {
+                  it.networkId == user.networkId && it.bufferName == user.nick
+                })
+              }.filter {
+                it.isNotEmpty()
+              }.firstElement().toLiveData().observe(this, Observer {
+                it?.firstOrNull()?.let { info ->
+                  ChatActivity.launch(requireContext(),
+                                      bufferId = info.bufferId)
+                }
               })
-            }.filter {
-              it.isNotEmpty()
-            }.firstElement().toLiveData().observe(this, Observer {
-              it?.firstOrNull()?.let { info ->
-                ChatActivity.launch(requireContext(), bufferId = info.bufferId)
-              }
-            })
 
-            session.bufferSyncer?.find(
-              networkId = networkId,
-              type = Buffer_Type.of(Buffer_Type.StatusBuffer)
-            )?.let { statusInfo ->
-              session.rpcHandler?.sendInput(statusInfo, "/query $nickName")
+              session.bufferSyncer?.find(
+                networkId = user.networkId,
+                type = Buffer_Type.of(Buffer_Type.StatusBuffer)
+              )?.let { statusInfo ->
+                session.rpcHandler?.sendInput(statusInfo,
+                                              "/query ${user.nick}")
+              }
             }
           }
         }
-      }
-    }
 
-    actionIgnore.setOnClickListener {
-      Toast.makeText(requireContext(), "Not Implemented", Toast.LENGTH_SHORT).show()
-    }
+        actionIgnore.setOnClickListener {
+          Toast.makeText(requireContext(), "Not Implemented", Toast.LENGTH_SHORT).show()
+        }
 
-    actionMention.setOnClickListener {
-      ChatActivity.launch(requireContext(), sharedText = "$nickName: ")
-    }
+        actionMention.setOnClickListener {
+          ChatActivity.launch(requireContext(), sharedText = "${user.nick}: ")
+        }
 
-    actionWhois.setOnClickListener {
-      viewModel.session {
-        it.orNull()?.let { session ->
-          session.bufferSyncer?.find(
-            networkId = networkId,
-            type = Buffer_Type.of(Buffer_Type.StatusBuffer)
-          )?.let { statusInfo ->
-            session.rpcHandler?.sendInput(statusInfo, "/whois $nickName $nickName")
+        actionWhois.setOnClickListener {
+          viewModel.session {
+            it.orNull()?.let { session ->
+              session.bufferSyncer?.find(
+                networkId = user.networkId,
+                type = Buffer_Type.of(Buffer_Type.StatusBuffer)
+              )?.let { statusInfo ->
+                session.rpcHandler?.sendInput(statusInfo, "/whois ${user.nick} ${user.nick}")
+              }
+            }
           }
         }
       }
-    }
+      it?.orNull()?.let(processUser)
+    })
 
     actionMention.visibleIf(arguments?.getBoolean("openBuffer") == false)
 
diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/avatars/AvatarHelper.kt b/app/src/main/java/de/kuschku/quasseldroid/util/avatars/AvatarHelper.kt
index 79edf1367..78d0b6c87 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/util/avatars/AvatarHelper.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/util/avatars/AvatarHelper.kt
@@ -24,6 +24,7 @@ import de.kuschku.libquassel.util.irc.HostmaskHelper
 import de.kuschku.libquassel.util.irc.IrcCaseMappers
 import de.kuschku.quasseldroid.persistence.QuasselDatabase
 import de.kuschku.quasseldroid.settings.MessageSettings
+import de.kuschku.quasseldroid.ui.chat.info.user.IrcUserInfo
 import de.kuschku.quasseldroid.util.Patterns
 import de.kuschku.quasseldroid.util.backport.codec.Hex
 import de.kuschku.quasseldroid.util.helper.letIf
@@ -37,8 +38,7 @@ object AvatarHelper {
              size: Int? = null) = listOfNotNull(
     message.avatarUrl.notBlank()?.let { listOf(Avatar.NativeAvatar(it)) },
     settings.showIRCCloudAvatars.letIf {
-      ircCloudFallback(HostmaskHelper.user(message.sender),
-                       size)
+      ircCloudFallback(HostmaskHelper.user(message.sender), size)
     },
     settings.showGravatarAvatars.letIf {
       gravatarFallback(message.realName, size)
@@ -52,8 +52,7 @@ object AvatarHelper {
              size: Int? = null) = listOfNotNull(
     message.avatarUrl.notBlank()?.let { listOf(Avatar.NativeAvatar(it)) },
     settings.showIRCCloudAvatars.letIf {
-      ircCloudFallback(HostmaskHelper.user(message.sender),
-                       size)
+      ircCloudFallback(HostmaskHelper.user(message.sender), size)
     },
     settings.showGravatarAvatars.letIf {
       gravatarFallback(message.realName, size)
@@ -65,16 +64,25 @@ object AvatarHelper {
 
   fun avatar(settings: MessageSettings, user: IrcUserItem, size: Int? = null) = listOfNotNull(
     settings.showIRCCloudAvatars.letIf {
-      ircCloudFallback(HostmaskHelper.user(user.hostmask),
-                       size)
+      ircCloudFallback(HostmaskHelper.user(user.hostmask), size)
     },
     settings.showGravatarAvatars.letIf {
-      gravatarFallback(user.realname.toString(),
-                       size)
+      gravatarFallback(user.realname.toString(), size)
     },
     settings.showMatrixAvatars.letIf {
-      matrixFallback(user.realname.toString(),
-                     size)
+      matrixFallback(user.realname.toString(), size)
+    }
+  ).flatten()
+
+  fun avatar(settings: MessageSettings, user: IrcUserInfo, size: Int? = null) = listOfNotNull(
+    settings.showIRCCloudAvatars.letIf {
+      ircCloudFallback(user.user ?: "", size)
+    },
+    settings.showGravatarAvatars.letIf {
+      gravatarFallback(user.realName ?: "", size)
+    },
+    settings.showMatrixAvatars.letIf {
+      matrixFallback(user.realName ?: "", size)
     }
   ).flatten()
 
-- 
GitLab