diff --git a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/AutoCompleteItem.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/AutoCompleteItem.kt
index 0c39ad9c73433641514f91fd03c326f8a4adbd27..29c9e39fb91e7e342d0930d2df94e5e40bd29589 100644
--- a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/AutoCompleteItem.kt
+++ b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/AutoCompleteItem.kt
@@ -42,7 +42,41 @@ sealed class AutoCompleteItem(open val name: String, val suffix: String, private
     val avatarUrls: List<Avatar> = emptyList(),
     val fallbackDrawable: Drawable? = null,
     val displayNick: CharSequence? = null
-  ) : AutoCompleteItem(nick, ": ", 0)
+  ) : AutoCompleteItem(nick, ": ", 0) {
+    override fun equals(other: Any?): Boolean {
+      if (this === other) return true
+      if (javaClass != other?.javaClass) return false
+
+      other as UserItem
+
+      if (nick != other.nick) return false
+      if (hostMask != other.hostMask) return false
+      if (modes != other.modes) return false
+      if (lowestMode != other.lowestMode) return false
+      if (realname != other.realname) return false
+      if (away != other.away) return false
+      if (self != other.self) return false
+      if (networkCasemapping != other.networkCasemapping) return false
+      if (avatarUrls != other.avatarUrls) return false
+      if (displayNick != other.displayNick) return false
+
+      return true
+    }
+
+    override fun hashCode(): Int {
+      var result = nick.hashCode()
+      result = 31 * result + hostMask.hashCode()
+      result = 31 * result + modes.hashCode()
+      result = 31 * result + lowestMode
+      result = 31 * result + realname.hashCode()
+      result = 31 * result + away.hashCode()
+      result = 31 * result + self.hashCode()
+      result = 31 * result + (networkCasemapping?.hashCode() ?: 0)
+      result = 31 * result + avatarUrls.hashCode()
+      result = 31 * result + (displayNick?.hashCode() ?: 0)
+      return result
+    }
+  }
 
   data class AliasItem(
     val alias: String,
@@ -55,5 +89,27 @@ sealed class AutoCompleteItem(open val name: String, val suffix: String, private
     val bufferStatus: BufferStatus,
     val description: CharSequence,
     val icon: Drawable? = null
-  ) : AutoCompleteItem(info.bufferName ?: "", " ", 2)
+  ) : AutoCompleteItem(info.bufferName ?: "", " ", 2) {
+    override fun equals(other: Any?): Boolean {
+      if (this === other) return true
+      if (javaClass != other?.javaClass) return false
+
+      other as ChannelItem
+
+      if (info != other.info) return false
+      if (network != other.network) return false
+      if (bufferStatus != other.bufferStatus) return false
+      if (description != other.description) return false
+
+      return true
+    }
+
+    override fun hashCode(): Int {
+      var result = info.hashCode()
+      result = 31 * result + network.hashCode()
+      result = 31 * result + bufferStatus.hashCode()
+      result = 31 * result + description.hashCode()
+      return result
+    }
+  }
 }
diff --git a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/BufferProps.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/BufferProps.kt
index daddbb58092241f7fd04ec83ca6501a8399e319a..be6084b1dfeedcf60e42fa8ad083d0b9839c5345 100644
--- a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/BufferProps.kt
+++ b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/BufferProps.kt
@@ -41,4 +41,40 @@ data class BufferProps(
   val ircUser: IrcUser? = null,
   val avatarUrls: List<Avatar> = emptyList(),
   val fallbackDrawable: Drawable? = null
-)
+) {
+  override fun equals(other: Any?): Boolean {
+    if (this === other) return true
+    if (javaClass != other?.javaClass) return false
+
+    other as BufferProps
+
+    if (info != other.info) return false
+    if (network != other.network) return false
+    if (networkConnectionState != other.networkConnectionState) return false
+    if (bufferStatus != other.bufferStatus) return false
+    if (description != other.description) return false
+    if (activity != other.activity) return false
+    if (highlights != other.highlights) return false
+    if (bufferActivity != other.bufferActivity) return false
+    if (hiddenState != other.hiddenState) return false
+    if (ircUser != other.ircUser) return false
+    if (avatarUrls != other.avatarUrls) return false
+
+    return true
+  }
+
+  override fun hashCode(): Int {
+    var result = info.hashCode()
+    result = 31 * result + network.hashCode()
+    result = 31 * result + networkConnectionState.hashCode()
+    result = 31 * result + bufferStatus.hashCode()
+    result = 31 * result + description.hashCode()
+    result = 31 * result + activity.hashCode()
+    result = 31 * result + highlights
+    result = 31 * result + bufferActivity.hashCode()
+    result = 31 * result + hiddenState.hashCode()
+    result = 31 * result + (ircUser?.hashCode() ?: 0)
+    result = 31 * result + avatarUrls.hashCode()
+    return result
+  }
+}
diff --git a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/FormattedMessage.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/FormattedMessage.kt
index 11f28b43c9ae06416bc7c95f067fad37566d60df..773111d6608c06f3c4e914fe507aa744d4954136 100644
--- a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/FormattedMessage.kt
+++ b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/FormattedMessage.kt
@@ -36,4 +36,42 @@ class FormattedMessage(
   val isSelected: Boolean,
   val isExpanded: Boolean,
   val isMarkerLine: Boolean
-)
+) {
+  override fun equals(other: Any?): Boolean {
+    if (this === other) return true
+    if (javaClass != other?.javaClass) return false
+
+    other as FormattedMessage
+
+    if (id != other.id) return false
+    if (time != other.time) return false
+    if (dayChange != other.dayChange) return false
+    if (name != other.name) return false
+    if (content != other.content) return false
+    if (combined != other.combined) return false
+    if (realName != other.realName) return false
+    if (avatarUrls != other.avatarUrls) return false
+    if (hasDayChange != other.hasDayChange) return false
+    if (isSelected != other.isSelected) return false
+    if (isExpanded != other.isExpanded) return false
+    if (isMarkerLine != other.isMarkerLine) return false
+
+    return true
+  }
+
+  override fun hashCode(): Int {
+    var result = id.hashCode()
+    result = 31 * result + time.hashCode()
+    result = 31 * result + (dayChange?.hashCode() ?: 0)
+    result = 31 * result + (name?.hashCode() ?: 0)
+    result = 31 * result + (content?.hashCode() ?: 0)
+    result = 31 * result + combined.hashCode()
+    result = 31 * result + (realName?.hashCode() ?: 0)
+    result = 31 * result + avatarUrls.hashCode()
+    result = 31 * result + hasDayChange.hashCode()
+    result = 31 * result + isSelected.hashCode()
+    result = 31 * result + isExpanded.hashCode()
+    result = 31 * result + isMarkerLine.hashCode()
+    return result
+  }
+}
diff --git a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/IrcUserItem.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/IrcUserItem.kt
index da69e6f4938a9ba530abd4cdaee6d64ff96e2ed2..8f88b84f3fb05ffb83ccb633e1ab1976851027e6 100644
--- a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/IrcUserItem.kt
+++ b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/IrcUserItem.kt
@@ -34,4 +34,40 @@ data class IrcUserItem(
   val initial: String? = "",
   val fallbackDrawable: Drawable? = null,
   val displayNick: CharSequence? = null
-)
+) {
+  override fun equals(other: Any?): Boolean {
+    if (this === other) return true
+    if (javaClass != other?.javaClass) return false
+
+    other as IrcUserItem
+
+    if (nick != other.nick) return false
+    if (modes != other.modes) return false
+    if (lowestMode != other.lowestMode) return false
+    if (realname != other.realname) return false
+    if (hostmask != other.hostmask) return false
+    if (away != other.away) return false
+    if (self != other.self) return false
+    if (networkCasemapping != other.networkCasemapping) return false
+    if (avatarUrls != other.avatarUrls) return false
+    if (initial != other.initial) return false
+    if (displayNick != other.displayNick) return false
+
+    return true
+  }
+
+  override fun hashCode(): Int {
+    var result = nick.hashCode()
+    result = 31 * result + modes.hashCode()
+    result = 31 * result + lowestMode
+    result = 31 * result + realname.hashCode()
+    result = 31 * result + hostmask.hashCode()
+    result = 31 * result + away.hashCode()
+    result = 31 * result + self.hashCode()
+    result = 31 * result + (networkCasemapping?.hashCode() ?: 0)
+    result = 31 * result + avatarUrls.hashCode()
+    result = 31 * result + (initial?.hashCode() ?: 0)
+    result = 31 * result + (displayNick?.hashCode() ?: 0)
+    return result
+  }
+}