Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • libquassel-migration
  • main
  • wip
  • ChenZhangg-Modify_GRADLE_1
  • jetpack-compose-rewrite
  • demo-jump-in-history
  • attachments
  • 1.4.0
  • 1.4.1
  • 1.4.2
  • 1.4.3
  • 1.4.4
  • 1.5.0
  • 1.5.1
  • 1.5.2
  • 1.5.3
  • 1.6.0
  • 1.6.1
  • 1.6.2
  • 1.7.0
  • v0.2.0
  • v0.3.0
  • v0.4.0
  • v0.5.0
  • v1.0.0
  • v1.0.1
  • v1.0.10
  • v1.0.11
  • v1.0.12
  • v1.0.13
  • v1.0.14
  • v1.0.15
  • v1.0.16
  • v1.0.17
  • v1.0.18
  • v1.0.19
  • v1.0.2
  • v1.0.20
  • v1.0.21
  • v1.0.22
  • v1.0.23
  • v1.0.25
  • v1.0.26
  • v1.0.27
  • v1.0.28
  • v1.0.29
  • v1.0.3
  • v1.0.31
  • v1.0.35
  • v1.0.36
  • v1.0.37
  • v1.0.38
  • v1.0.39
  • v1.0.4
  • v1.0.40
  • v1.0.41
  • v1.0.42
  • v1.0.43
  • v1.0.44
  • v1.0.45
  • v1.0.5
  • v1.0.6
  • v1.0.7
  • v1.0.8
  • v1.0.9
  • v1.1.0
  • v1.1.1
  • v1.1.2
  • v1.1.3
  • v1.1.4
  • v1.2.1
  • v1.2.10
  • v1.2.11
  • v1.2.12
  • v1.2.13
  • v1.2.14
  • v1.2.15
  • v1.2.16
  • v1.2.17
  • v1.2.18
  • v1.2.19
  • v1.2.2
  • v1.2.20
  • v1.2.21
  • v1.2.22
  • v1.2.23
  • v1.2.24
  • v1.2.25
  • v1.2.26
  • v1.2.27
  • v1.2.28
  • v1.2.3
  • v1.2.4
  • v1.2.5
  • v1.2.6
  • v1.2.7
  • v1.2.9
  • v1.3.0
  • v1.3.1
  • v1.3.2
  • v1.3.3
101 results

Target

Select target project
  • Janne Mareike Koschinski / QuasselDroid-ng
1 result
Select Git revision
  • libquassel-migration
  • main
  • wip
  • ChenZhangg-Modify_GRADLE_1
  • jetpack-compose-rewrite
  • demo-jump-in-history
  • attachments
  • 1.4.0
  • 1.4.1
  • 1.4.2
  • 1.4.3
  • 1.4.4
  • 1.5.0
  • 1.5.1
  • 1.5.2
  • 1.5.3
  • 1.6.0
  • 1.6.1
  • 1.6.2
  • 1.7.0
  • v0.2.0
  • v0.3.0
  • v0.4.0
  • v0.5.0
  • v1.0.0
  • v1.0.1
  • v1.0.10
  • v1.0.11
  • v1.0.12
  • v1.0.13
  • v1.0.14
  • v1.0.15
  • v1.0.16
  • v1.0.17
  • v1.0.18
  • v1.0.19
  • v1.0.2
  • v1.0.20
  • v1.0.21
  • v1.0.22
  • v1.0.23
  • v1.0.25
  • v1.0.26
  • v1.0.27
  • v1.0.28
  • v1.0.29
  • v1.0.3
  • v1.0.31
  • v1.0.35
  • v1.0.36
  • v1.0.37
  • v1.0.38
  • v1.0.39
  • v1.0.4
  • v1.0.40
  • v1.0.41
  • v1.0.42
  • v1.0.43
  • v1.0.44
  • v1.0.45
  • v1.0.5
  • v1.0.6
  • v1.0.7
  • v1.0.8
  • v1.0.9
  • v1.1.0
  • v1.1.1
  • v1.1.2
  • v1.1.3
  • v1.1.4
  • v1.2.1
  • v1.2.10
  • v1.2.11
  • v1.2.12
  • v1.2.13
  • v1.2.14
  • v1.2.15
  • v1.2.16
  • v1.2.17
  • v1.2.18
  • v1.2.19
  • v1.2.2
  • v1.2.20
  • v1.2.21
  • v1.2.22
  • v1.2.23
  • v1.2.24
  • v1.2.25
  • v1.2.26
  • v1.2.27
  • v1.2.28
  • v1.2.3
  • v1.2.4
  • v1.2.5
  • v1.2.6
  • v1.2.7
  • v1.2.9
  • v1.3.0
  • v1.3.1
  • v1.3.2
  • v1.3.3
101 results
Show changes

Commits on Source 6

15 files
+ 218
81
Compare changes
  • Side-by-side
  • Inline

Files

+1 −1
Original line number Diff line number Diff line
image: "k8r.eu/justjanne/android-sdk:28-28.0.3-26.1.1"
image: "k8r.eu/justjanne/android-sdk:28-28.0.3"

variables:
  GRADLE_OPTS: "-Dorg.gradle.daemon=false"
+1 −1
Original line number Diff line number Diff line
@@ -497,7 +497,7 @@ class QuasselService : DaggerLifecycleService(),
      session.bufferViewManager.requestCreateBufferView(
        Defaults.bufferViewConfigInitial(translatedLocale).apply {
          for (info in session.bufferSyncer.bufferInfos()) {
            handleBuffer(info, session.bufferSyncer)
            handleBuffer(info, session.bufferSyncer, session.networks)
          }
        }.toVariantMap()
      )
+6 −0
Original line number Diff line number Diff line
@@ -211,6 +211,12 @@ class ChatlineFragment : ServiceBoundFragment() {
    }

    editorHelper.setOnEnterListener(::send)
    editorHelper.setOnDownListener {
      chatline.setText(modelHelper.chat.recentMessagesIndexDown(chatline.safeText))
    }
    editorHelper.setOnUpListener {
      chatline.setText(modelHelper.chat.recentMessagesIndexUp())
    }
    send.setOnClickListener { send() }
    send.setTooltip()

+42 −3
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.text.Editable
import android.text.TextWatcher
import android.view.KeyEvent
import android.view.inputmethod.EditorInfo
import android.widget.Toast
import androidx.annotation.ColorInt
import androidx.annotation.StringRes
import androidx.fragment.app.FragmentActivity
@@ -44,6 +45,8 @@ class EditorHelper(
  appearanceSettings: AppearanceSettings
) {
  private var enterListener: (() -> Unit)? = null
  private var upListener: (() -> Unit)? = null
  private var downListener: (() -> Unit)? = null

  private val mircColors = listOf(
    R.color.mircColor00, R.color.mircColor01, R.color.mircColor02, R.color.mircColor03,
@@ -124,8 +127,28 @@ class EditorHelper(
      )
    }
    editText.addTextChangedListener(textWatcher)
    editText.setOnKeyListener { _, keyCode, event: KeyEvent? ->
      if (event?.action == KeyEvent.ACTION_DOWN) {
    editText.setOnKeyListener { _, keyCode, event: KeyEvent ->
      val action = when (event.action) {
        KeyEvent.ACTION_UP       -> "up"
        KeyEvent.ACTION_DOWN     -> "down"
        KeyEvent.ACTION_MULTIPLE -> "multiple"
        else                     -> "unknown"
      }
      val key = when (keyCode) {
        KeyEvent.KEYCODE_ENTER        -> "enter"
        KeyEvent.KEYCODE_NUMPAD_ENTER -> "numpad_enter"
        KeyEvent.KEYCODE_DPAD_DOWN    -> "down"
        KeyEvent.KEYCODE_DPAD_UP      -> "up"
        else                          -> "#$keyCode"
      }
      val modifiers = listOfNotNull(
        if (event.isCtrlPressed) "ctrl" else null,
        if (event.isAltPressed) "alt" else null,
        if (event.isShiftPressed) "shift" else null
      ).joinToString(", ")

      Toast.makeText(editText.context, "$key $action $modifiers", Toast.LENGTH_SHORT).show()
      if (event.action == KeyEvent.ACTION_DOWN) {
        if (event.isCtrlPressed && !event.isAltPressed) when (keyCode) {
          KeyEvent.KEYCODE_B -> {
            editText.toggleBold()
@@ -148,6 +171,14 @@ class EditorHelper(
            enterListener?.invoke()
            true
          }
          KeyEvent.KEYCODE_DPAD_DOWN    -> {
            downListener?.invoke()
            true
          }
          KeyEvent.KEYCODE_DPAD_UP      -> {
            upListener?.invoke()
            true
          }
          KeyEvent.KEYCODE_TAB          -> {
            if (!event.isAltPressed && !event.isCtrlPressed) {
              autoCompleteHelper.autoComplete(event.isShiftPressed)
@@ -159,7 +190,7 @@ class EditorHelper(
          else                          -> false
        }
      } else if (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_NUMPAD_ENTER) {
        !(event?.isShiftPressed ?: false)
        !event.isShiftPressed
      } else {
        false
      }
@@ -191,6 +222,14 @@ class EditorHelper(
    this.enterListener = listener
  }

  fun setOnUpListener(listener: (() -> Unit)?) {
    this.upListener = listener
  }

  fun setOnDownListener(listener: (() -> Unit)?) {
    this.downListener = listener
  }

  fun setMultiLine(enabled: Boolean) = editText.setMultiLine(enabled)

  fun replaceText(text: CharSequence?) = editText.replaceText(text)
+1 −1
Original line number Diff line number Diff line
@@ -191,7 +191,7 @@ object BufferContextPresenter {
      true
    }
    R.id.action_unhide      -> {
      bufferViewConfig?.insertBufferSorted(info, bufferSyncer)
      bufferViewConfig?.insertBufferSorted(info, bufferSyncer, session.networks)
      actionMode.finish()
      true
    }
+1 −1
Original line number Diff line number Diff line
@@ -25,7 +25,7 @@ buildscript {
    jcenter()
  }
  dependencies {
    classpath("com.android.tools.build:gradle:3.4.1")
    classpath("com.android.tools.build:gradle:3.4.2")
    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.41")
  }
}
+2 −2
Original line number Diff line number Diff line
@@ -245,7 +245,7 @@ class BufferSyncer constructor(
      live_bufferInfos.onNext(Unit)

      if (oldInfo == null) {
        session.bufferViewManager.handleBuffer(info, this)
        session.bufferViewManager.handleBuffer(info, this, session.networks)
      }
    }
  }
@@ -282,7 +282,7 @@ class BufferSyncer constructor(
        activity hasFlag Message_Type.Notice ||
        activity hasFlag Message_Type.Action) {
      bufferInfo(buffer)?.let {
        session.bufferViewManager.handleBuffer(it, this, true)
        session.bufferViewManager.handleBuffer(it, this, session.networks, true)
      }
    }
    _bufferActivities[buffer] = activity
+30 −12
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ import de.kuschku.libquassel.quassel.syncables.interfaces.IBufferViewConfig
import de.kuschku.libquassel.session.SignalProxy
import de.kuschku.libquassel.util.flag.hasFlag
import de.kuschku.libquassel.util.helper.clampOf
import de.kuschku.libquassel.util.irc.IrcCaseMappers
import io.reactivex.Observable
import io.reactivex.subjects.BehaviorSubject

@@ -326,28 +325,33 @@ class BufferViewConfig constructor(
      (a?.bufferViewName() ?: "").compareTo((b?.bufferViewName() ?: ""), true)
  }

  fun insertBufferSorted(info: BufferInfo, bufferSyncer: BufferSyncer) {
  fun insertBufferSorted(info: BufferInfo, bufferSyncer: BufferSyncer,
                         networks: Map<NetworkId, Network>) {
    if (!_buffers.contains(info.bufferId)) {
      val element = IrcCaseMappers.unicode.toLowerCaseNullable(info.bufferName)
      val position =
        if (_sortAlphabetically) -_buffers.mapNotNull {
          IrcCaseMappers.unicode.toLowerCaseNullable(bufferSyncer.bufferInfo(it)?.bufferName)
        }.binarySearch(element) - 1
        else _buffers.size
      requestAddBuffer(info.bufferId, position)
      requestAddBuffer(
        info.bufferId,
        sortBuffers(
          _buffers.mapNotNull { bufferSyncer.bufferInfo(it) } + info,
          sortAlphabetically(),
          { it.bufferName ?: "" },
          { networks[it.networkId]?.networkName() ?: "" },
          { it.type }
        ).indexOf(info)
      )
    }
  }

  fun handleBuffer(info: BufferInfo, bufferSyncer: BufferSyncer, unhide: Boolean = false) {
  fun handleBuffer(info: BufferInfo, bufferSyncer: BufferSyncer, networks: Map<NetworkId, Network>,
                   unhide: Boolean = false) {
    if (_addNewBuffersAutomatically &&
        !_buffers.contains(info.bufferId) &&
        !_temporarilyRemovedBuffers.contains(info.bufferId) &&
        !_removedBuffers.contains(info.bufferId) &&
        !info.type.hasFlag(Buffer_Type.StatusBuffer)) {
      insertBufferSorted(info, bufferSyncer)
      insertBufferSorted(info, bufferSyncer, networks)
    } else if (unhide && !_buffers.contains(info.bufferId) &&
               _temporarilyRemovedBuffers.contains(info.bufferId)) {
      insertBufferSorted(info, bufferSyncer)
      insertBufferSorted(info, bufferSyncer, networks)
    }
  }

@@ -365,4 +369,18 @@ class BufferViewConfig constructor(
  override fun toString(): String {
    return "BufferViewConfig(_bufferViewId=$_bufferViewId, _bufferViewName='$_bufferViewName', _networkId=$_networkId, _addNewBuffersAutomatically=$_addNewBuffersAutomatically, _sortAlphabetically=$_sortAlphabetically, _hideInactiveBuffers=$_hideInactiveBuffers, _hideInactiveNetworks=$_hideInactiveNetworks, _disableDecoration=$_disableDecoration, _allowedBufferTypes=$_allowedBufferTypes, _minimumActivity=$_minimumActivity, _showSearch=$_showSearch)"
  }

  companion object {
    inline fun <T> sortBuffers(list: List<T>, sortAlphabetically: Boolean,
                               crossinline bufferName: (T) -> String,
                               crossinline networkName: (T) -> String,
                               crossinline type: (T) -> Buffer_Types) =
      list.let {
        if (sortAlphabetically) list.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER,
                                                          bufferName))
        else list
      }.sortedBy {
        !type(it).hasFlag(Buffer_Type.StatusBuffer)
      }.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER, networkName))
  }
}
+4 −3
Original line number Diff line number Diff line
@@ -90,12 +90,13 @@ class BufferViewManager constructor(

  private val _bufferViewConfigs: MutableMap<Int, BufferViewConfig> = mutableMapOf()

  private val live_bufferViewConfigs: BehaviorSubject<Set<Int>> = BehaviorSubject.createDefault<Set<Int>>(
  private val live_bufferViewConfigs: BehaviorSubject<Set<Int>> = BehaviorSubject.createDefault(
    emptySet())

  fun handleBuffer(info: BufferInfo, bufferSyncer: BufferSyncer, unhide: Boolean = false) {
  fun handleBuffer(info: BufferInfo, bufferSyncer: BufferSyncer, networks: Map<NetworkId, Network>,
                   unhide: Boolean = false) {
    for (bufferViewConfig in bufferViewConfigs()) {
      bufferViewConfig.handleBuffer(info, bufferSyncer, unhide)
      bufferViewConfig.handleBuffer(info, bufferSyncer, networks, unhide)
    }
  }

+32 −21
Original line number Diff line number Diff line
@@ -85,21 +85,24 @@ class Session(
  override val backlogManager = BacklogManager(this, backlogStorage)
  override val bufferViewManager = BufferViewManager(this)
  override val bufferSyncer = BufferSyncer(this, notificationManager)
  override val certManagers = mutableMapOf<IdentityId, CertManager>()
  override var certManagers = emptyMap<IdentityId, CertManager>()
    private set
  override val coreInfo = CoreInfo(this)
  override val dccConfig = DccConfig(this)

  override val identities = mutableMapOf<IdentityId, Identity>()
  override var identities = emptyMap<IdentityId, Identity>()
    private set
  private val live_identities = BehaviorSubject.createDefault(Unit)
  override fun liveIdentities(): Observable<Map<IdentityId, Identity>> = live_identities.map { identities.toMap() }
  override fun liveIdentities(): Observable<Map<IdentityId, Identity>> = live_identities.map { identities }

  override val ignoreListManager = IgnoreListManager(this)
  override val highlightRuleManager = HighlightRuleManager(this)
  override val ircListHelper = IrcListHelper(this)

  override val networks = mutableMapOf<NetworkId, Network>()
  override var networks = emptyMap<NetworkId, Network>()
    private set
  private val live_networks = BehaviorSubject.createDefault(Unit)
  override fun liveNetworks(): Observable<Map<NetworkId, Network>> = live_networks.map { networks.toMap() }
  override fun liveNetworks(): Observable<Map<NetworkId, Network>> = live_networks.map { networks }

  private val network_added = PublishSubject.create<NetworkId>()
  override fun liveNetworkAdded(): Observable<NetworkId> = network_added
@@ -183,14 +186,15 @@ class Session(

  override fun addNetwork(networkId: NetworkId) {
    val network = Network(networkId, this)
    networks[networkId] = network
    networks = networks + Pair(networkId, network)
    synchronize(network)
    live_networks.onNext(Unit)
    network_added.onNext(networkId)
  }

  override fun removeNetwork(networkId: NetworkId) {
    val network = networks.remove(networkId)
    val network = networks[networkId]
    networks = networks - networkId
    stopSynchronize(network)
    live_networks.onNext(Unit)
  }
@@ -198,13 +202,14 @@ class Session(
  override fun addIdentity(initData: QVariantMap) {
    val identity = Identity(this)
    identity.fromVariantMap(initData)
    identities[identity.id()] = identity
    identities = identities + Pair(identity.id(), identity)
    synchronize(identity)
    live_identities.onNext(Unit)
  }

  override fun removeIdentity(identityId: IdentityId) {
    val identity = identities.remove(identityId)
    val identity = identities[identityId]
    identities = identities - identityId
    stopSynchronize(identity)
    live_identities.onNext(Unit)
  }
@@ -219,23 +224,29 @@ class Session(
    handlerService.backend {
      bufferSyncer.initSetBufferInfos(f.bufferInfos)

      f.networkIds?.forEach {
        val network = Network(it.value(NetworkId(-1)), this)
        networks[network.networkId()] = network
      }
      networks = f.networkIds?.map {
        Pair(it.value(NetworkId(-1)), Network(it.value(NetworkId(-1)), this))
      }?.toMap().orEmpty()
      live_networks.onNext(Unit)

      f.identities?.forEach {
      val identityCertmanagerPairs = f.identities?.map {
        val identity = Identity(this)
        identity.fromVariantMap(it.valueOr(::emptyMap))
        identity.initialized = true
        identity.init()
        identities[identity.id()] = identity
        synchronize(identity)

        val certManager = CertManager(identity.id(), this)
        certManagers[identity.id()] = certManager
      }
        Pair(identity, certManager)
      }?.toMap().orEmpty()

      identities = identityCertmanagerPairs.map { (identity, _) ->
        Pair(identity.id(), identity)
      }.toMap()

      certManagers = identityCertmanagerPairs.map { (identity, certManager) ->
        Pair(identity.id(), certManager)
      }.toMap()

      isInitializing = true
      networks.values.forEach { syncableObject -> this.synchronize(syncableObject, true) }
@@ -269,7 +280,7 @@ class Session(
    initCallback?.invoke(this)
    for (config in bufferViewManager.bufferViewConfigs()) {
      for (info in bufferSyncer.bufferInfos()) {
        config.handleBuffer(info, bufferSyncer)
        config.handleBuffer(info, bufferSyncer, networks)
      }
    }
    notificationManager?.init(this)
@@ -318,10 +329,10 @@ class Session(
    backlogManager.deinit()
    rpcHandler.deinit()

    certManagers.clear()
    identities.clear()
    certManagers = emptyMap()
    identities = emptyMap()
    live_identities.onNext(Unit)
    networks.clear()
    networks = emptyMap()
    live_networks.onNext(Unit)
  }

+1 −1
Original line number Diff line number Diff line
@@ -43,7 +43,7 @@ class BufferViewConfigTest {
    val bufferViewConfig = bufferViewManager.bufferViewConfig(0)!!

    ensure {
      bufferViewConfig.insertBufferSorted(bufferSyncer.bufferInfo(BufferId(4))!!, bufferSyncer)
      bufferViewConfig.insertBufferSorted(bufferSyncer.bufferInfo(BufferId(4))!!, bufferSyncer, networks)
    }.does {
      callSync(bufferViewConfig, "requestAddBuffer", listOf(
        QVariant_.of(BufferId(4), QType.BufferId),
+36 −0
Original line number Diff line number Diff line
@@ -35,6 +35,8 @@ open class ChatViewModel : QuasselViewModel() {
  val bufferId = BehaviorSubject.createDefault(BufferId.MAX_VALUE)
  val bufferViewConfigId = BehaviorSubject.createDefault(-1)
  val recentlySentMessages = BehaviorSubject.createDefault(emptyList<CharSequence>())
  val recentlySentMessageIndex = BehaviorSubject.createDefault(-1)
  val inputCache = BehaviorSubject.createDefault<CharSequence>("")
  val showHidden = BehaviorSubject.createDefault(false)
  val bufferSearchTemporarilyVisible = BehaviorSubject.createDefault(false)
  val expandedNetworks = BehaviorSubject.createDefault(emptyMap<NetworkId, Boolean>())
@@ -145,6 +147,40 @@ open class ChatViewModel : QuasselViewModel() {
    )
  }

  private fun recentMessagesChange(value: Int) {
    val current = recentlySentMessageIndex.safeValue
    val size = recentlySentMessages.safeValue.size
    val nextValue = current + value
    recentlySentMessageIndex.onNext(
      if (nextValue < 0) -1
      else (size + current + value) % size
    )
  }

  fun recentMessagesValue() =
    if (recentlySentMessageIndex.safeValue == -1) inputCache.safeValue
    else recentlySentMessages.safeValue[recentlySentMessageIndex.safeValue]

  fun recentMessagesIndexDown(content: CharSequence): CharSequence {
    if (recentlySentMessageIndex.safeValue == -1) {
      inputCache.onNext(content)
    }
    recentMessagesChange(+1)
    return recentMessagesValue()
  }

  fun recentMessagesIndexUp(): CharSequence? {
    if (recentlySentMessageIndex.safeValue > -1) {
      recentMessagesChange(-1)
    }
    return recentMessagesValue()
  }

  fun recentMessagesIndexReset(): CharSequence? {
    recentlySentMessageIndex.onNext(-1)
    return recentMessagesValue()
  }

  companion object {
    const val KEY_SELECTED_MESSAGES = "model_chat_selectedMessages"
    const val KEY_BUFFER_SEARCH = "model_chat_bufferSearch"
+1 −1
Original line number Diff line number Diff line
@@ -60,5 +60,5 @@ open class ArchiveViewModelHelper @Inject constructor(
    showHandle
  )

  val selectedBuffer = processSelectedBuffer(archive.selectedBufferId)
  val selectedBuffer = processSelectedBuffer(bufferViewConfig, archive.selectedBufferId)
}
+1 −1
Original line number Diff line number Diff line
@@ -170,7 +170,7 @@ open class ChatViewModelHelper @Inject constructor(
  val nickDataThrottled =
    nickData.distinctUntilChanged().throttleLast(100, TimeUnit.MILLISECONDS)

  val selectedBuffer = processSelectedBuffer(chat.selectedBufferId)
  val selectedBuffer = processSelectedBuffer(bufferViewConfig, chat.selectedBufferId)

  fun processChatBufferList(
    filtered: Observable<Pair<Map<BufferId, Int>, Int>>
+59 −33
Original line number Diff line number Diff line
@@ -456,12 +456,15 @@ open class QuasselViewModelHelper @Inject constructor(
    }

  fun processSelectedBuffer(
    bufferViewConfigObservable: Observable<Optional<BufferViewConfig>>,
    selectedBufferId: Observable<BufferId>
  ) = combineLatest(connectedSession, selectedBufferId)
    .safeSwitchMap { (sessionOptional, buffer) ->
  ) = combineLatest(connectedSession, selectedBufferId, bufferViewConfigObservable)
    .safeSwitchMap { (sessionOptional, buffer, bufferViewConfigOptional) ->
      val session = sessionOptional.orNull()
      val bufferViewConfig = bufferViewConfigOptional.orNull()
      val bufferSyncer = session?.bufferSyncer
      if (bufferSyncer != null) {
      if (bufferSyncer != null && bufferViewConfig != null) {
        bufferHiddenState(bufferViewConfig, buffer).safeSwitchMap { bufferHiddenState ->
          session.liveNetworks().safeSwitchMap { networks ->
            val info = if (!buffer.isValidId()) networks[NetworkId(-buffer.id)]?.let {
              BufferInfo(
@@ -479,7 +482,8 @@ open class QuasselViewModelHelper @Inject constructor(
                  network?.liveConnectionState()?.map {
                    SelectedBufferItem(
                      info,
                    connectionState = it
                      connectionState = it,
                      hiddenState = bufferHiddenState
                    )
                  } ?: Observable.just(SelectedBufferItem(info))
                }
@@ -487,19 +491,41 @@ open class QuasselViewModelHelper @Inject constructor(
                  network?.liveIrcChannel(info.bufferName)?.mapNullable(IrcChannel.NULL) {
                    SelectedBufferItem(
                      info,
                    joined = it != null
                      joined = it != null,
                      hiddenState = bufferHiddenState
                    )
                } ?: Observable.just(SelectedBufferItem(info))
                  } ?: Observable.just(SelectedBufferItem(
                    info,
                    hiddenState = bufferHiddenState
                  ))
                }
                else                      ->
                Observable.just(SelectedBufferItem(info))
                  Observable.just(SelectedBufferItem(
                    info,
                    hiddenState = bufferHiddenState
                  ))
              }
            } else {
              Observable.just(SelectedBufferItem())
            }
          }
        }
      } else {
        Observable.just(SelectedBufferItem())
      }
    }

  fun bufferHiddenState(bufferViewConfig: BufferViewConfig,
                        bufferId: BufferId): Observable<BufferHiddenState> =
    combineLatest(bufferViewConfig.liveBuffers(),
                  bufferViewConfig.liveTemporarilyRemovedBuffers(),
                  bufferViewConfig.liveRemovedBuffers())
      .map { (visible, temp, perm) ->
        when (bufferId) {
          in visible -> BufferHiddenState.VISIBLE
          in temp    -> BufferHiddenState.HIDDEN_TEMPORARY
          in perm    -> BufferHiddenState.HIDDEN_PERMANENT
          else       -> BufferHiddenState.HIDDEN_PERMANENT
        }
      }
}