diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/info/user/ChannelAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/info/user/ChannelAdapter.kt
new file mode 100644
index 0000000000000000000000000000000000000000..42ada913cdeddfd996029801c4ef864f2bd4d06f
--- /dev/null
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/info/user/ChannelAdapter.kt
@@ -0,0 +1,103 @@
+/*
+ * Quasseldroid - Quassel client for Android
+ *
+ * Copyright (c) 2019 Janne Koschinski
+ * Copyright (c) 2019 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.info.user
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.recyclerview.widget.DiffUtil
+import androidx.recyclerview.widget.RecyclerView
+import butterknife.BindView
+import butterknife.ButterKnife
+import de.kuschku.libquassel.protocol.NetworkId
+import de.kuschku.libquassel.quassel.BufferInfo
+import de.kuschku.quasseldroid.R
+import de.kuschku.quasseldroid.ui.chat.ChatActivity
+import de.kuschku.quasseldroid.util.helper.visibleIf
+import de.kuschku.quasseldroid.util.lists.ListAdapter
+import de.kuschku.quasseldroid.viewmodel.data.BufferProps
+
+class ChannelAdapter : ListAdapter<BufferProps, ChannelAdapter.ChannelViewHolder>(
+  object : DiffUtil.ItemCallback<BufferProps>() {
+    override fun areItemsTheSame(oldItem: BufferProps, newItem: BufferProps) =
+      oldItem.info.bufferId == newItem.info.bufferId
+
+    override fun areContentsTheSame(oldItem: BufferProps, newItem: BufferProps) =
+      oldItem == newItem
+  }
+) {
+  private var clickListener: ((NetworkId, String) -> Unit)? = null
+  fun setOnClickListener(listener: ((NetworkId, String) -> Unit)?) {
+    this.clickListener = listener
+  }
+
+  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ChannelViewHolder(
+    LayoutInflater.from(parent.context).inflate(
+      R.layout.widget_buffer, parent, false
+    ),
+    clickListener = clickListener
+  )
+
+  override fun onBindViewHolder(holder: ChannelViewHolder, position: Int) =
+    holder.bind(getItem(position))
+
+  class ChannelViewHolder(
+    itemView: View,
+    private val clickListener: ((NetworkId, String) -> Unit)? = null
+  ) : RecyclerView.ViewHolder(itemView) {
+    @BindView(R.id.status)
+    lateinit var status: ImageView
+
+    @BindView(R.id.name)
+    lateinit var name: TextView
+
+    @BindView(R.id.description)
+    lateinit var description: TextView
+
+    var info: BufferInfo? = null
+
+    init {
+      ButterKnife.bind(this, itemView)
+      itemView.setOnClickListener {
+        info?.let {
+          ChatActivity.launch(
+            itemView.context,
+            networkId = it.networkId,
+            channel = it.bufferName
+          )
+        }
+      }
+    }
+
+    fun bind(props: BufferProps) {
+      info = props.info
+
+      name.text = props.info.bufferName
+      description.text = props.description
+
+      description.visibleIf(props.description.isNotBlank())
+
+      status.setImageDrawable(props.fallbackDrawable)
+    }
+  }
+}
+
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/info/user/IrcUserInfo.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/info/user/IrcUserInfo.kt
index 98adeadaecc6eb5c0e1b5def9b8f48d535f49fae..32362da4685fa82be0f2532a13ff31c4a0c09d09 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/info/user/IrcUserInfo.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/info/user/IrcUserInfo.kt
@@ -23,6 +23,7 @@ import de.kuschku.libquassel.protocol.NetworkId
 import de.kuschku.libquassel.quassel.BufferInfo
 import de.kuschku.libquassel.quassel.syncables.IrcUser
 import de.kuschku.libquassel.quassel.syncables.Network
+import de.kuschku.quasseldroid.viewmodel.data.BufferProps
 
 data class IrcUserInfo(
   val networkId: NetworkId,
@@ -37,5 +38,6 @@ data class IrcUserInfo(
   val network: Network? = null,
   val knownToCore: Boolean = false,
   val info: BufferInfo? = null,
-  val ircUser: IrcUser? = null
+  val ircUser: IrcUser? = null,
+  val channels: List<BufferProps> = emptyList()
 )
diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/info/user/UserInfoFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/info/user/UserInfoFragment.kt
index 05b9a2bcc09818d820f2ea869c6a7d7669e886a8..1b6ed5b76849fd30a009adc1f107964efb695dc8 100644
--- a/app/src/main/java/de/kuschku/quasseldroid/ui/info/user/UserInfoFragment.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid/ui/info/user/UserInfoFragment.kt
@@ -31,12 +31,18 @@ import android.widget.Button
 import android.widget.ImageView
 import android.widget.TextView
 import androidx.lifecycle.Observer
+import androidx.recyclerview.widget.DefaultItemAnimator
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
 import butterknife.BindView
 import butterknife.ButterKnife
 import de.kuschku.libquassel.protocol.BufferId
 import de.kuschku.libquassel.protocol.Buffer_Type
+import de.kuschku.libquassel.protocol.Message_Type
 import de.kuschku.libquassel.protocol.NetworkId
 import de.kuschku.libquassel.quassel.BufferInfo
+import de.kuschku.libquassel.quassel.syncables.BufferSyncer
+import de.kuschku.libquassel.quassel.syncables.IrcChannel
 import de.kuschku.libquassel.quassel.syncables.IrcUser
 import de.kuschku.libquassel.util.Optional
 import de.kuschku.libquassel.util.helpers.nullIf
@@ -46,6 +52,7 @@ import de.kuschku.quasseldroid.R
 import de.kuschku.quasseldroid.settings.MessageSettings
 import de.kuschku.quasseldroid.ui.chat.ChatActivity
 import de.kuschku.quasseldroid.ui.coresettings.ignorelist.IgnoreListActivity
+import de.kuschku.quasseldroid.util.ColorContext
 import de.kuschku.quasseldroid.util.ShortcutCreationHelper
 import de.kuschku.quasseldroid.util.avatars.AvatarHelper
 import de.kuschku.quasseldroid.util.avatars.MatrixApi
@@ -57,6 +64,9 @@ import de.kuschku.quasseldroid.util.service.ServiceBoundFragment
 import de.kuschku.quasseldroid.util.ui.BetterLinkMovementMethod
 import de.kuschku.quasseldroid.util.ui.LinkLongClickMenuHelper
 import de.kuschku.quasseldroid.viewmodel.data.Avatar
+import de.kuschku.quasseldroid.viewmodel.data.BufferHiddenState
+import de.kuschku.quasseldroid.viewmodel.data.BufferProps
+import de.kuschku.quasseldroid.viewmodel.data.BufferStatus
 import io.reactivex.Observable
 import javax.inject.Inject
 
@@ -115,6 +125,9 @@ class UserInfoFragment : ServiceBoundFragment() {
   @BindView(R.id.server)
   lateinit var server: TextView
 
+  @BindView(R.id.common_channels)
+  lateinit var commonChannels: RecyclerView
+
   @Inject
   lateinit var contentFormatter: ContentFormatter
 
@@ -144,32 +157,83 @@ class UserInfoFragment : ServiceBoundFragment() {
       actionShortcut.visibleIf(currentBufferInfo != null)
     }
 
+    val commonChannelsAdapter = ChannelAdapter()
+    commonChannels.layoutManager = LinearLayoutManager(context)
+    commonChannels.itemAnimator = DefaultItemAnimator()
+    commonChannels.adapter = commonChannelsAdapter
+
+    val colorContext = ColorContext(requireContext(), messageSettings)
+
+    val colorAccent = requireContext().theme.styledAttributes(R.attr.colorAccent) {
+      getColor(0, 0)
+    }
+
+    val colorAway = requireContext().theme.styledAttributes(R.attr.colorAway) {
+      getColor(0, 0)
+    }
+
     combineLatest(viewModel.session, viewModel.networks).switchMap { (sessionOptional, networks) ->
-      fun processUser(user: IrcUser, info: BufferInfo? = null): Optional<IrcUserInfo> {
+      fun processUser(user: IrcUser, bufferSyncer: BufferSyncer? = null,
+                      info: BufferInfo? = null): Observable<Optional<IrcUserInfo>> {
         actionShortcut.post(::updateShortcutVisibility)
         return when {
-          user == IrcUser.NULL && info != null -> Optional.of(IrcUserInfo(
+          user == IrcUser.NULL && info != null -> Observable.just(Optional.of(IrcUserInfo(
             networkId = info.networkId,
             nick = info.bufferName ?: "",
             knownToCore = true,
             info = info
-          ))
-          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,
-            info = info,
-            ircUser = user
-          ))
+          )))
+          user == IrcUser.NULL                 -> Observable.just(Optional.empty())
+          else                                 -> {
+            combineLatest(user.channels().map { channelName ->
+              user.network().liveIrcChannel(
+                channelName
+              ).switchMap { channel ->
+                channel.updates().map {
+                  bufferSyncer?.find(
+                    bufferName = channelName,
+                    networkId = user.network().networkId()
+                  )?.let { info ->
+                    val bufferStatus =
+                      if (it == IrcChannel.NULL) BufferStatus.OFFLINE
+                      else BufferStatus.ONLINE
+                    val color =
+                      if (bufferStatus == BufferStatus.ONLINE) colorAccent
+                      else colorAway
+                    val fallbackDrawable = colorContext.buildTextDrawable("#", color)
+
+                    BufferProps(
+                      info = info,
+                      network = user.network().networkInfo(),
+                      description = it.topic(),
+                      activity = Message_Type.of(),
+                      bufferStatus = bufferStatus,
+                      hiddenState = BufferHiddenState.VISIBLE,
+                      networkConnectionState = user.network().connectionState(),
+                      fallbackDrawable = fallbackDrawable
+                    )
+                  }
+                }
+              }
+            }).map {
+              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,
+                info = info,
+                ircUser = user,
+                channels = it.filterNotNull()
+              ))
+            }
+          }
         }
       }
 
@@ -178,16 +242,16 @@ class UserInfoFragment : ServiceBoundFragment() {
         val bufferSyncer = session?.bufferSyncer
         val bufferInfo = bufferSyncer?.bufferInfo(bufferId)
         bufferInfo?.let {
-          networks[it.networkId]?.liveIrcUser(it.bufferName)?.switchMap(IrcUser::updates)?.map {
-            processUser(it, bufferInfo)
+          networks[it.networkId]?.liveIrcUser(it.bufferName)?.switchMap(IrcUser::updates)?.switchMap {
+            processUser(it, bufferSyncer, bufferInfo)
           }
         }
       } else {
         networks[networkId]
           ?.liveIrcUser(nickName)
           ?.switchMap(IrcUser::updates)
-          ?.map { user -> processUser(user) }
-      } ?: Observable.just(IrcUser.NULL).map { user -> processUser(user) }
+          ?.switchMap { user -> processUser(user, sessionOptional?.orNull()?.bufferSyncer) }
+      } ?: Observable.just(IrcUser.NULL).switchMap { user -> processUser(user, null, null) }
     }.toLiveData().observe(this, Observer {
       val user = it.orNull()
       if (user != null) {
@@ -322,6 +386,8 @@ class UserInfoFragment : ServiceBoundFragment() {
             }
           }
         }
+
+        commonChannelsAdapter.submitList(user.channels)
       }
     })
 
diff --git a/app/src/main/res/layout/info_user.xml b/app/src/main/res/layout/info_user.xml
index b33d185d3eb454ae40e2720826235e40d33c3bcc..3025db19a4a4a6e76828f0195c5aabeca517917c 100644
--- a/app/src/main/res/layout/info_user.xml
+++ b/app/src/main/res/layout/info_user.xml
@@ -251,6 +251,15 @@
           style="@style/Widget.Info.Item.Description"
           android:text="@string/label_user_server" />
       </LinearLayout>
+
+      <TextView
+        style="@style/Widget.Info.Section"
+        android:text="@string/label_user_common_channels" />
+
+      <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/common_channels"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
     </LinearLayout>
   </androidx.core.widget.NestedScrollView>
 </androidx.coordinatorlayout.widget.CoordinatorLayout>
diff --git a/app/src/main/res/values/strings_info.xml b/app/src/main/res/values/strings_info.xml
index 769aa50471cf87e2d1e294e73aa90fbd2c87549a..e0e2fff6b873b8ba7d12d9466036de9f8ca2b8c5 100644
--- a/app/src/main/res/values/strings_info.xml
+++ b/app/src/main/res/values/strings_info.xml
@@ -25,6 +25,7 @@
   <string name="label_user_ident">Ident</string>
   <string name="label_user_host">Host</string>
   <string name="label_user_server">Server</string>
+  <string name="label_user_common_channels">Common Channels</string>
 
   <string name="label_core_version">Version</string>
   <string name="label_core_uptime">Uptime</string>