Fixes crash cluster a62ffe4d

parent b242be99
Pipeline #481 passed with stages
in 45 minutes and 16 seconds
......@@ -37,6 +37,7 @@ import de.kuschku.libquassel.quassel.syncables.IrcChannel
import de.kuschku.libquassel.quassel.syncables.Network
import de.kuschku.libquassel.util.helper.combineLatest
import de.kuschku.libquassel.util.helper.nullIf
import de.kuschku.libquassel.util.helper.safeSwitchMap
import de.kuschku.libquassel.util.helper.value
import de.kuschku.quasseldroid.R
import de.kuschku.quasseldroid.ui.chat.ChatActivity
......@@ -107,7 +108,7 @@ class ChannelCreateFragment : ServiceBoundSettingsFragment() {
}
var hasSetNetwork = false
modelHelper.networks.switchMap {
modelHelper.networks.safeSwitchMap {
combineLatest(it.values.map(Network::liveNetworkInfo)).map {
it.map {
NetworkItem(it.networkId, it.networkName)
......@@ -177,7 +178,7 @@ class ChannelCreateFragment : ServiceBoundSettingsFragment() {
)?.let { statusBuffer ->
modelHelper.connectedSession.value?.orNull()?.rpcHandler?.apply {
sendInput(statusBuffer, "/join $channelName")
modelHelper.networks.switchMap {
modelHelper.networks.safeSwitchMap {
it[selectedNetworkId]?.liveIrcChannel(channelName)
?: Observable.empty()
}.subscribe {
......
......@@ -33,6 +33,7 @@ import butterknife.ButterKnife
import de.kuschku.libquassel.protocol.NetworkId
import de.kuschku.libquassel.quassel.syncables.Network
import de.kuschku.libquassel.util.helper.combineLatest
import de.kuschku.libquassel.util.helper.safeSwitchMap
import de.kuschku.quasseldroid.R
import de.kuschku.quasseldroid.ui.chat.ChatActivity
import de.kuschku.quasseldroid.ui.chat.add.NetworkAdapter
......@@ -85,7 +86,7 @@ class ChannelJoinFragment : ServiceBoundFragment() {
}
var hasSetNetwork = false
modelHelper.networks.switchMap {
modelHelper.networks.safeSwitchMap {
combineLatest(it.values.map(Network::liveNetworkInfo)).map {
it.map {
NetworkItem(it.networkId, it.networkName)
......
......@@ -50,6 +50,7 @@ import de.kuschku.libquassel.util.Optional
import de.kuschku.libquassel.util.helper.combineLatest
import de.kuschku.libquassel.util.helper.mapOrElse
import de.kuschku.libquassel.util.helper.mapSwitchMap
import de.kuschku.libquassel.util.helper.safeSwitchMap
import de.kuschku.libquassel.util.irc.IrcCaseMappers
import de.kuschku.libquassel.util.irc.SenderColorUtil
import de.kuschku.quasseldroid.GlideApp
......@@ -129,7 +130,7 @@ class QueryCreateFragment : ServiceBoundFragment() {
}
var hasSetNetwork = false
modelHelper.networks.switchMap {
modelHelper.networks.safeSwitchMap {
combineLatest(it.values.map(Network::liveNetworkInfo)).map {
it.map {
NetworkItem(it.networkId, it.networkName)
......@@ -206,7 +207,7 @@ class QueryCreateFragment : ServiceBoundFragment() {
Optional.ofNullable(networks[networkId])
}.mapSwitchMap {
it.liveIrcUsers()
}.mapOrElse(emptyList()).switchMap {
}.mapOrElse(emptyList()).safeSwitchMap {
combineLatest<IrcUserItem>(
it.map<IrcUser, Observable<IrcUserItem>?> {
it.updates().map { user ->
......
......@@ -263,7 +263,7 @@ class BufferViewConfigFragment : ServiceBoundFragment() {
ButterKnife.bind(this, view)
val adapter = BufferViewConfigAdapter()
modelHelper.bufferViewConfigs.switchMap {
modelHelper.bufferViewConfigs.safeSwitchMap {
combineLatest(it.map(BufferViewConfig::liveUpdates))
}.toLiveData().observe(this, Observer {
if (it != null) {
......
......@@ -34,6 +34,7 @@ import de.kuschku.libquassel.session.ISession
import de.kuschku.libquassel.util.Optional
import de.kuschku.libquassel.util.flag.hasFlag
import de.kuschku.libquassel.util.helper.nullIf
import de.kuschku.libquassel.util.helper.safeSwitchMap
import de.kuschku.libquassel.util.helper.value
import de.kuschku.libquassel.util.irc.SenderColorUtil
import de.kuschku.quasseldroid.R
......@@ -260,7 +261,7 @@ class AutoCompleteHelper(
}
fun autoComplete(reverse: Boolean = false) {
helper.editor.lastWord.switchMap { it }.value?.let { originalWord ->
helper.editor.lastWord.safeSwitchMap { it }.value?.let { originalWord ->
val previous = autoCompletionState
if (!originalWord.second.isEmpty()) {
val autoCompletedWords = helper.rawAutoCompleteData.value?.let { (sessionOptional, id, lastWord) ->
......
......@@ -372,7 +372,7 @@ class MessageListFragment : ServiceBoundFragment() {
modelHelper.chat.expandedMessages,
modelHelper.markerLine)
.toLiveData().switchMapNotNull { (buffer, selected, expanded, markerLine) ->
accountDatabase.accounts().listen(accountId).switchMap {
accountDatabase.accounts().listen(accountId).safeSwitchMap {
database.filtered().listen(accountId,
buffer,
it.defaultFiltered).switchMapNotNull { filtered ->
......
......@@ -37,6 +37,7 @@ import de.kuschku.libquassel.quassel.syncables.BufferViewConfig
import de.kuschku.libquassel.quassel.syncables.Identity
import de.kuschku.libquassel.quassel.syncables.Network
import de.kuschku.libquassel.util.helper.combineLatest
import de.kuschku.libquassel.util.helper.safeSwitchMap
import de.kuschku.quasseldroid.R
import de.kuschku.quasseldroid.ui.coresettings.aliaslist.AliasListActivity
import de.kuschku.quasseldroid.ui.coresettings.chatlist.ChatlistCreateActivity
......@@ -136,7 +137,7 @@ class CoreSettingsFragment : ServiceBoundFragment() {
networks.addItemDecoration(itemDecoration)
ViewCompat.setNestedScrollingEnabled(networks, false)
modelHelper.networks.switchMap {
modelHelper.networks.safeSwitchMap {
if (it.isEmpty()) {
Observable.just(emptyList())
} else {
......@@ -155,7 +156,7 @@ class CoreSettingsFragment : ServiceBoundFragment() {
identities.addItemDecoration(itemDecoration)
ViewCompat.setNestedScrollingEnabled(identities, false)
modelHelper.identities.switchMap {
modelHelper.identities.safeSwitchMap {
if (it.isEmpty()) {
Observable.just(emptyList())
} else {
......@@ -174,7 +175,7 @@ class CoreSettingsFragment : ServiceBoundFragment() {
chatlists.addItemDecoration(itemDecoration)
ViewCompat.setNestedScrollingEnabled(chatlists, false)
modelHelper.bufferViewConfigMap.switchMap {
modelHelper.bufferViewConfigMap.safeSwitchMap {
combineLatest(it.values.map(BufferViewConfig::liveUpdates)).map {
it.map {
SettingsItem(it.bufferViewId(), it.bufferViewName())
......
......@@ -42,6 +42,7 @@ import de.kuschku.libquassel.util.flag.hasFlag
import de.kuschku.libquassel.util.flag.minus
import de.kuschku.libquassel.util.flag.plus
import de.kuschku.libquassel.util.helper.combineLatest
import de.kuschku.libquassel.util.helper.safeSwitchMap
import de.kuschku.quasseldroid.R
import de.kuschku.quasseldroid.defaults.Defaults
import de.kuschku.quasseldroid.util.helper.toLiveData
......@@ -121,7 +122,7 @@ abstract class ChatListBaseFragment(private val initDefault: Boolean) :
val networkAdapter = NetworkAdapter(R.string.settings_chatlist_network_all)
networkId.adapter = networkAdapter
modelHelper.networks.switchMap {
modelHelper.networks.safeSwitchMap {
combineLatest(it.values.map(Network::liveNetworkInfo)).map {
it.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER, INetwork.NetworkInfo::networkName))
}
......
......@@ -45,6 +45,7 @@ import de.kuschku.libquassel.session.ISession
import de.kuschku.libquassel.util.Optional
import de.kuschku.libquassel.util.helper.combineLatest
import de.kuschku.libquassel.util.helper.nullIf
import de.kuschku.libquassel.util.helper.safeSwitchMap
import de.kuschku.libquassel.util.helper.value
import de.kuschku.quasseldroid.R
import de.kuschku.quasseldroid.defaults.Defaults
......@@ -171,7 +172,7 @@ abstract class NetworkBaseFragment(private val initDefault: Boolean) :
val identityAdapter = IdentityAdapter()
identity.adapter = identityAdapter
modelHelper.identities.switchMap {
modelHelper.identities.safeSwitchMap {
combineLatest(it.values.map(Identity::liveUpdates)).map {
it.sortedBy(Identity::identityName)
}
......@@ -211,7 +212,7 @@ abstract class NetworkBaseFragment(private val initDefault: Boolean) :
modelHelper.networks.map { Optional.ofNullable(it[networkId]) }
.filter(Optional<Network>::isPresent)
.map(Optional<Network>::get)
.switchMap(Network::liveCaps)
.safeSwitchMap(Network::liveCaps)
.toLiveData()
.observe(this, Observer {
autoidentifyWarning.visibleIf(it.contains("sasl"))
......
......@@ -35,6 +35,7 @@ import de.kuschku.libquassel.protocol.NetworkId
import de.kuschku.libquassel.quassel.BufferInfo
import de.kuschku.libquassel.quassel.syncables.IrcChannel
import de.kuschku.libquassel.util.helper.combineLatest
import de.kuschku.libquassel.util.helper.safeSwitchMap
import de.kuschku.libquassel.util.helper.value
import de.kuschku.quasseldroid.R
import de.kuschku.quasseldroid.settings.MessageSettings
......@@ -109,7 +110,7 @@ class ChannelInfoFragment : ServiceBoundFragment() {
} ?: Pair(null, IrcChannel.NULL)
}.filter {
it.second != IrcChannel.NULL
}.switchMap { (info, channel) ->
}.safeSwitchMap { (info, channel) ->
channel.updates().map {
Pair(info, it)
}
......
......@@ -47,10 +47,7 @@ import de.kuschku.libquassel.quassel.syncables.IgnoreListManager
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.helper.combineLatest
import de.kuschku.libquassel.util.helper.invoke
import de.kuschku.libquassel.util.helper.nullIf
import de.kuschku.libquassel.util.helper.value
import de.kuschku.libquassel.util.helper.*
import de.kuschku.libquassel.util.irc.HostmaskHelper
import de.kuschku.libquassel.util.irc.IrcCaseMappers
import de.kuschku.quasseldroid.R
......@@ -182,7 +179,7 @@ class UserInfoFragment : ServiceBoundFragment() {
}
combineLatest(modelHelper.connectedSession,
modelHelper.networks).switchMap { (sessionOptional, networks) ->
modelHelper.networks).safeSwitchMap { (sessionOptional, networks) ->
fun processUser(user: IrcUser, bufferSyncer: BufferSyncer? = null, info: BufferInfo? = null,
ignoreItems: List<IgnoreListManager.IgnoreListItem>? = null): Observable<Optional<IrcUserInfo>> {
actionShortcut.post(::updateShortcutVisibility)
......@@ -223,7 +220,7 @@ class UserInfoFragment : ServiceBoundFragment() {
combineLatest(user.channels().map { channelName ->
user.network().liveIrcChannel(
channelName
).switchMap { channel ->
).safeSwitchMap { channel ->
channel.updates().map {
Optional.ofNullable(
bufferSyncer?.find(
......@@ -267,7 +264,7 @@ class UserInfoFragment : ServiceBoundFragment() {
val bufferSyncer = session?.bufferSyncer
val bufferInfo = bufferSyncer?.bufferInfo(bufferId)
bufferInfo?.let {
networks[it.networkId]?.liveIrcUser(it.bufferName)?.switchMap(IrcUser::updates)?.switchMap {
networks[it.networkId]?.liveIrcUser(it.bufferName)?.safeSwitchMap(IrcUser::updates)?.safeSwitchMap {
processUser(it, bufferSyncer, bufferInfo)
}
}
......@@ -276,17 +273,17 @@ class UserInfoFragment : ServiceBoundFragment() {
networks[networkId]
?.liveIrcUser(nickName)
?.switchMap(IrcUser::updates)
?.switchMap { user ->
?.safeSwitchMap(IrcUser::updates)
?.safeSwitchMap { user ->
ignoreListManager?.liveMatchingRules(user.hostMask())?.map {
Pair(user, it)
} ?: Observable.just(Pair(user, emptyList()))
}?.switchMap { (user, ignoreItems) ->
}?.safeSwitchMap { (user, ignoreItems) ->
processUser(user,
sessionOptional?.orNull()?.bufferSyncer,
ignoreItems = ignoreItems)
}
} ?: Observable.just(IrcUser.NULL).switchMap { user -> processUser(user, null, null) }
} ?: Observable.just(IrcUser.NULL).safeSwitchMap { user -> processUser(user, null, null) }
}.toLiveData().observe(this, Observer {
val user = it.orNull()
if (user != null) {
......
......@@ -68,7 +68,7 @@ abstract class ServiceBoundSetupActivity :
protected abstract val fragments: List<SlideFragment>
private val currentPage = MutableLiveData<SlideFragment?>()
private val isValid = currentPage.switchMap(SlideFragment::valid).or(false)
private val isValid = currentPage.safeSwitchMap(SlideFragment::valid).or(false)
@DrawableRes
protected val icon: Int = R.mipmap.ic_launcher_recents
......
......@@ -57,7 +57,7 @@ abstract class SetupActivity : DaggerAppCompatActivity() {
protected abstract val fragments: List<SlideFragment>
private val currentPage = MutableLiveData<SlideFragment?>()
private val isValid = currentPage.switchMap(SlideFragment::valid).or(false)
private val isValid = currentPage.safeSwitchMap(SlideFragment::valid).or(false)
@DrawableRes
protected val icon: Int = R.mipmap.ic_launcher_recents
......
......@@ -40,6 +40,7 @@ import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork
import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork.PortDefaults.PORT_PLAINTEXT
import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork.PortDefaults.PORT_SSL
import de.kuschku.libquassel.util.helper.combineLatest
import de.kuschku.libquassel.util.helper.safeSwitchMap
import de.kuschku.quasseldroid.R
import de.kuschku.quasseldroid.defaults.DefaultNetworkServer
import de.kuschku.quasseldroid.ui.coresettings.chatlist.NetworkAdapter
......@@ -187,7 +188,7 @@ class NetworkSetupNetworkSlide : ServiceBoundSlideFragment() {
identity.adapter = identityAdapter
modelHelper.identities.switchMap {
modelHelper.identities.safeSwitchMap {
combineLatest(it.values.map(Identity::liveUpdates)).map {
it.sortedBy(Identity::identityName)
}
......@@ -197,7 +198,7 @@ class NetworkSetupNetworkSlide : ServiceBoundSlideFragment() {
}
})
modelHelper.networks.switchMap {
modelHelper.networks.safeSwitchMap {
combineLatest(it.values.map(Network::liveNetworkInfo)).map {
it.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER, INetwork.NetworkInfo::networkName))
}
......
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
/*
* Quasseldroid - Quassel client for Android
*
......
......@@ -29,6 +29,7 @@ import de.kuschku.libquassel.util.compatibility.LoggingHandler.Companion.log
import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.*
import de.kuschku.libquassel.util.helper.combineLatest
import de.kuschku.libquassel.util.helper.or
import de.kuschku.libquassel.util.helper.safeSwitchMap
import de.kuschku.libquassel.util.helper.value
import io.reactivex.Observable
import io.reactivex.disposables.Disposable
......@@ -48,7 +49,7 @@ class SessionManager(
private val disposables = mutableListOf<Disposable>()
// Helping Rx Mappers
val connectionProgress: Observable<Triple<ConnectionState, Int, Int>> = progressData.switchMap {
val connectionProgress: Observable<Triple<ConnectionState, Int, Int>> = progressData.safeSwitchMap {
combineLatest(it.state, it.progress).map { (state, progress) ->
Triple(state, progress.first, progress.second)
}
......@@ -69,8 +70,8 @@ class SessionManager(
init {
log(INFO, "Session", "Session created")
disposables.add(state.distinctUntilChanged().subscribe {
if (it == ConnectionState.CONNECTED) {
disposables.add(state.distinctUntilChanged().subscribe { state: ConnectionState ->
if (state == ConnectionState.CONNECTED) {
updateStateConnected()
}
})
......
......@@ -20,6 +20,7 @@
package de.kuschku.libquassel.session
import de.kuschku.libquassel.session.manager.SessionState
import de.kuschku.libquassel.util.helper.safeSwitchMap
import io.reactivex.subjects.BehaviorSubject
open class SessionStateHandler constructor(
......@@ -42,15 +43,15 @@ open class SessionStateHandler constructor(
it.progress
}
val errors = progressData.switchMap {
val errors = progressData.safeSwitchMap {
it.error
}
val progress = progressData.switchMap {
val progress = progressData.safeSwitchMap {
it.progress
}
val state = progressData.switchMap {
val state = progressData.safeSwitchMap {
it.state
}
......
......@@ -43,6 +43,10 @@ fun <T : Any, U : Any> Observable<Optional<T>>.mapMapNullable(
}
}
inline fun <T : Any, R : Any> Observable<T>.safeSwitchMap(
noinline mapper: (T) -> ObservableSource<R>): Observable<R> =
switchMap(mapper)
fun <T : Any, U : Any> Observable<T>.mapNullable(
nullableValue: T,
mapper: (T?) -> U): Observable<U> = map {
......
......@@ -25,7 +25,7 @@ import androidx.lifecycle.*
import io.reactivex.Observable
@MainThread
inline fun <X, Y> LiveData<X?>.switchMap(
inline fun <X, Y> LiveData<X?>.safeSwitchMap(
crossinline func: (X) -> LiveData<Y>?
): LiveData<Y> {
val result = MediatorLiveData<Y>()
......
......@@ -60,19 +60,19 @@ open class ChatViewModelHelper @Inject constructor(
* An observable of the changes of the markerline, as pairs of `(old, new)`
*/
val markerLine = connectedSession.mapSwitchMap { currentSession ->
chat.bufferId.switchMap { currentBuffer ->
chat.bufferId.safeSwitchMap { currentBuffer ->
// Get a stream of the latest marker line
currentSession.bufferSyncer.liveMarkerLine(currentBuffer)
}
}
val bufferData = combineLatest(connectedSession, chat.bufferId)
.switchMap { (sessionOptional, id) ->
.safeSwitchMap { (sessionOptional, id) ->
val session = sessionOptional.orNull()
val bufferSyncer = session?.bufferSyncer
if (bufferSyncer != null) {
session.liveNetworks().switchMap { networks ->
bufferSyncer.liveBufferInfos().switchMap {
session.liveNetworks().safeSwitchMap { networks ->
bufferSyncer.liveBufferInfos().safeSwitchMap {
val info = bufferSyncer.bufferInfo(id)
val network = networks[info?.networkId]
if (info == null || network == null) {
......@@ -80,7 +80,7 @@ open class ChatViewModelHelper @Inject constructor(
} else {
when (info.type.toInt()) {
BufferInfo.Type.QueryBuffer.toInt() -> {
network.liveIrcUser(info.bufferName).switchMap {
network.liveIrcUser(info.bufferName).safeSwitchMap {
it.updates().map { user ->
BufferData(
info = info,
......@@ -96,7 +96,7 @@ open class ChatViewModelHelper @Inject constructor(
BufferInfo.Type.ChannelBuffer.toInt() -> {
network.liveIrcChannel(
info.bufferName
).switchMap { channel ->
).safeSwitchMap { channel ->
channel.updates().map {
BufferData(
info = info,
......@@ -132,15 +132,15 @@ open class ChatViewModelHelper @Inject constructor(
bufferData.distinctUntilChanged().throttleLast(100, TimeUnit.MILLISECONDS)
val nickData: Observable<List<IrcUserItem>> = combineLatest(connectedSession, chat.bufferId)
.switchMap { (sessionOptional, buffer) ->
.safeSwitchMap { (sessionOptional, buffer) ->
val session = sessionOptional.orNull()
val bufferSyncer = session?.bufferSyncer
val bufferInfo = bufferSyncer?.bufferInfo(buffer)
if (bufferInfo?.type?.hasFlag(Buffer_Type.ChannelBuffer) == true) {
session.liveNetworks().switchMap { networks ->
session.liveNetworks().safeSwitchMap { networks ->
val network = networks[bufferInfo.networkId]
network?.liveIrcChannel(bufferInfo.bufferName)?.switchMapNullable(IrcChannel.NULL) { ircChannel ->
ircChannel?.liveIrcUsers()?.switchMap { users ->
ircChannel?.liveIrcUsers()?.safeSwitchMap { users ->
combineLatest<IrcUserItem>(
users.map<IrcUser, Observable<IrcUserItem>?> {
it.updates().map { user ->
......@@ -166,7 +166,7 @@ open class ChatViewModelHelper @Inject constructor(
}
)
} ?: Observable.just(emptyList())
}
} ?: Observable.just(emptyList())
}
} else {
Observable.just(emptyList())
......@@ -176,12 +176,12 @@ open class ChatViewModelHelper @Inject constructor(
nickData.distinctUntilChanged().throttleLast(100, TimeUnit.MILLISECONDS)
val selectedBuffer = combineLatest(connectedSession, chat.selectedBufferId, bufferViewConfig)
.switchMap { (sessionOptional, buffer, bufferViewConfigOptional) ->
.safeSwitchMap { (sessionOptional, buffer, bufferViewConfigOptional) ->
val session = sessionOptional.orNull()
val bufferSyncer = session?.bufferSyncer
val bufferViewConfig = bufferViewConfigOptional.orNull()
if (bufferSyncer != null && bufferViewConfig != null) {
session.liveNetworks().switchMap { networks ->
session.liveNetworks().safeSwitchMap { networks ->
val hiddenState = when {
bufferViewConfig.removedBuffers().contains(buffer) ->
BufferHiddenState.HIDDEN_PERMANENT
......@@ -235,22 +235,22 @@ open class ChatViewModelHelper @Inject constructor(
val bufferList: Observable<Pair<BufferViewConfig?, List<BufferProps>>> =
combineLatest(connectedSession, bufferViewConfig, chat.showHidden, chat.bufferSearch)
.switchMap { (sessionOptional, configOptional, showHiddenRaw, bufferSearch) ->
.safeSwitchMap { (sessionOptional, configOptional, showHiddenRaw, bufferSearch) ->
val session = sessionOptional.orNull()
val bufferSyncer = session?.bufferSyncer
val showHidden = showHiddenRaw ?: false
val config = configOptional.orNull()
if (bufferSyncer != null && config != null) {
session.liveNetworks().switchMap { networks ->
session.liveNetworks().safeSwitchMap { networks ->
config.liveUpdates()
.switchMap { currentConfig ->
.safeSwitchMap { currentConfig ->
combineLatest<Collection<BufferId>>(
listOf(
config.liveBuffers(),
config.liveTemporarilyRemovedBuffers(),
config.liveRemovedBuffers()
)
).switchMap { (ids, temp, perm) ->
).safeSwitchMap { (ids, temp, perm) ->
fun transformIds(ids: Collection<BufferId>, state: BufferHiddenState) =
ids.asSequence().mapNotNull { id ->
bufferSyncer.bufferInfo(id)
......@@ -271,11 +271,11 @@ open class ChatViewModelHelper @Inject constructor(
it to network
}
}.map<Pair<BufferInfo, Network>, Observable<BufferProps>?> { (info, network) ->
bufferSyncer.liveActivity(info.bufferId).switchMap { activity ->
bufferSyncer.liveActivity(info.bufferId).safeSwitchMap { activity ->
bufferSyncer.liveHighlightCount(info.bufferId).map { highlights ->
activity to highlights
}
}.switchMap { (activity, highlights) ->
}.safeSwitchMap { (activity, highlights) ->
val name = info.bufferName?.trim() ?: ""
val search = bufferSearch.trim()
val matchMode = when {
......@@ -285,9 +285,9 @@ open class ChatViewModelHelper @Inject constructor(
}
when (info.type.toInt()) {
BufferInfo.Type.QueryBuffer.toInt() -> {
network.liveNetworkInfo().switchMap { networkInfo ->
network.liveConnectionState().switchMap { connectionState ->
network.liveIrcUser(info.bufferName).switchMap {
network.liveNetworkInfo().safeSwitchMap { networkInfo ->
network.liveConnectionState().safeSwitchMap { connectionState ->
network.liveIrcUser(info.bufferName).safeSwitchMap {
it.updates().mapNullable(IrcUser.NULL) { user ->
BufferProps(
info = info,
......@@ -311,9 +311,9 @@ open class ChatViewModelHelper @Inject constructor(
}
}
BufferInfo.Type.ChannelBuffer.toInt() -> {
network.liveNetworkInfo().switchMap { networkInfo ->
network.liveConnectionState().switchMap { connectionState ->
network.liveIrcChannel(info.bufferName).switchMap { channel ->
network.liveNetworkInfo().safeSwitchMap { networkInfo ->
network.liveConnectionState().safeSwitchMap { connectionState ->
network.liveIrcChannel(info.bufferName).safeSwitchMap { channel ->
channel.updates().mapNullable(IrcChannel.NULL) {
BufferProps(
info = info,
......@@ -335,7 +335,7 @@ open class ChatViewModelHelper @Inject constructor(
}
}
BufferInfo.Type.StatusBuffer.toInt() -> {
network.liveNetworkInfo().switchMap { networkInfo ->
network.liveNetworkInfo().safeSwitchMap { networkInfo ->
network.liveConnectionState().map { connectionState ->
BufferProps(
info = info,
......@@ -381,7 +381,7 @@ open class ChatViewModelHelper @Inject constructor(
}.filter {
!config.hideInactiveNetworks() || it.isConnected()
}.map<Network, Observable<BufferProps>?> { network ->
network.liveNetworkInfo().switchMap { networkInfo ->
network.liveNetworkInfo().safeSwitchMap { networkInfo ->
network.liveConnectionState().map { connectionState ->
BufferProps(
info = BufferInfo(
......@@ -404,7 +404,7 @@ open class ChatViewModelHelper @Inject constructor(
}
}
bufferSyncer.liveBufferInfos().switchMap {
bufferSyncer.liveBufferInfos().safeSwitchMap {
val buffers = if (showHidden || bufferSearch.isNotBlank()) {
transformIds(ids, BufferHiddenState.VISIBLE) +
transformIds(temp - ids, BufferHiddenState.HIDDEN_TEMPORARY) +
......
......@@ -31,6 +31,7 @@ import de.kuschku.libquassel.util.flag.hasFlag
import de.kuschku.libquassel.util.helper.combineLatest
import de.kuschku.libquassel.util.helper.mapNullable
import de.kuschku.libquassel.util.helper.nullIf
import de.kuschku.libquassel.util.helper.safeSwitchMap
import de.kuschku.quasseldroid.viewmodel.ChatViewModel
import de.kuschku.quasseldroid.viewmodel.EditorViewModel
import de.kuschku.quasseldroid.viewmodel.QuasselViewModel
......@@ -47,7 +48,7 @@ open class EditorViewModelHelper @Inject constructor(
) : ChatViewModelHelper(chat, quassel) {
val rawAutoCompleteData: Observable<Triple<Optional<ISession>, BufferId, Pair<String, IntRange>>> =
combineLatest(connectedSession, chat.bufferId, editor.lastWord)
.switchMap { (sessionOptional, id, lastWordWrapper) ->
.safeSwitchMap { (sessionOptional, id, lastWordWrapper) ->
lastWordWrapper
.distinctUntilChanged()
.map { lastWord ->
......@@ -58,19 +59,19 @@ open class EditorViewModelHelper @Inject constructor(
val autoCompleteData: Observable<Pair<String, List<AutoCompleteItem>>> = rawAutoCompleteData
.distinctUntilChanged()
.debounce(300, TimeUnit.MILLISECONDS)
.switchMap { (sessionOptional, id, lastWord) ->
.safeSwitchMap { (sessionOptional, id, lastWord) ->
val session = sessionOptional.orNull()
val bufferSyncer = session?.bufferSyncer
val bufferInfo = bufferSyncer?.bufferInfo(id)
if (bufferSyncer != null) {
session.liveNetworks().switchMap { networks ->
bufferSyncer.liveBufferInfos().switchMap { infos ->
session.aliasManager.updates().map(AliasManager::aliasList).switchMap { aliases ->
session.liveNetworks().safeSwitchMap { networks ->
bufferSyncer.liveBufferInfos().safeSwitchMap { infos ->
session.aliasManager.updates().map(AliasManager::aliasList).safeSwitchMap { aliases ->
val network = networks[bufferInfo?.networkId] ?: Network.NULL
val ircChannel = if (bufferInfo?.type?.hasFlag(Buffer_Type.ChannelBuffer) == true) {
network.ircChannel(bufferInfo.bufferName) ?: IrcChannel.NULL
} else IrcChannel.NULL
ircChannel.liveIrcUsers().switchMap { users ->
ircChannel.liveIrcUsers().safeSwitchMap { users ->
fun processResults(results: List<Observable<out AutoCompleteItem>>) =
combineLatest<AutoCompleteItem>(results)
.map { list ->
......@@ -102,7 +103,7 @@ open class EditorViewModelHelper @Inject constructor(
}.map { (info, network) ->
network.liveIrcChannel(
info.bufferName
).switchMap { channel ->
).safeSwitchMap { channel ->
channel.updates().mapNullable(IrcChannel.NULL) {
AutoCompleteItem.ChannelItem(
info = info,
......
......@@ -39,13 +39,13 @@ import javax.net.ssl.SSLSession
open class QuasselViewModelHelper @Inject constructor(
val quassel: QuasselViewModel
) {
val backend = quassel.backendWrapper.switchMap { it }
val backend = quassel.backendWrapper.safeSwitchMap { it }
val sessionManager = backend.mapMapNullable(Backend::sessionManager)
val connectedSession = sessionManager.mapSwitchMap(SessionManager::connectedSession)
val rpcHandler = connectedSession.mapMap(ISession::rpcHandler)
val ircListHelper = connectedSession.mapMap(ISession::ircListHelper)
val features = sessionManager.mapSwitchMap { manager ->
manager.state.switchMap { state ->
manager.state.safeSwitchMap { state ->
if (state != ConnectionState.CONNECTED) {
Observable.just(Pair(false, Features.empty()))
} else {
......@@ -70,7 +70,7 @@ open class QuasselViewModelHelper @Inject constructor(
val bufferViewManager = connectedSession.mapMap(ISession::bufferViewManager)
val errors = sessionManager.switchMap {
val errors = sessionManager.safeSwitchMap {
it.orNull()?.errors ?: Observable.empty()
}
......@@ -92,11 +92,11 @@ open class QuasselViewModelHelper @Inject constructor(
val aliasManager = connectedSession.mapMap(ISession::aliasManager)
val networks = connectedSession.switchMap {
val networks = connectedSession.safeSwitchMap {
it.map(ISession::liveNetworks).orElse(Observable.just(emptyMap()))
}
val identities = connectedSession.switchMap {
val identities = connectedSession.safeSwitchMap {
it.map(ISession::liveIdentities).orElse(Observable.just(emptyMap()))
}
......@@ -115,7 +115,7 @@ open class QuasselViewModelHelper @Inject constructor(