Skip to content
Snippets Groups Projects
Commit 49168dd3 authored by Janne Mareike Koschinski's avatar Janne Mareike Koschinski
Browse files

Redesigned app architecture for significant performance improvements

parent 73ec3d12
No related branches found
No related tags found
No related merge requests found
......@@ -292,6 +292,7 @@ class QuasselService : DaggerLifecycleService(),
notificationManager.init()
update()
updateNotificationStatus()
}
override fun onDestroy() {
......
......@@ -117,9 +117,10 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
findViewById(R.id.formatting_toolbar),
appearanceSettings,
{ lines ->
viewModel.session { session ->
viewModel.session { sessionOptional ->
val session = sessionOptional.orNull()
viewModel.buffer { bufferId ->
session.bufferSyncer?.bufferInfo(bufferId)?.also { bufferInfo ->
session?.bufferSyncer?.bufferInfo(bufferId)?.also { bufferInfo ->
val output = mutableListOf<IAliasManager.Command>()
for ((stripped, formatted) in lines) {
viewModel.addRecentlySentMessage(stripped)
......@@ -205,12 +206,14 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
progressBar.hide()
}
ConnectionState.INIT -> {
progressBar.show()
// Show indeterminate when no progress has been made yet
progressBar.isIndeterminate = progress == 0 || max == 0
progressBar.progress = progress
progressBar.max = max
}
else -> {
progressBar.show()
progressBar.isIndeterminate = true
}
}
......
......@@ -57,7 +57,7 @@ class BufferViewConfigFragment : ServiceBoundFragment() {
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
val selected = viewModel.selectedBuffer.value
val info = selected?.info
val session = viewModel.session.value
val session = viewModel.session.value?.orNull()
val bufferSyncer = session?.bufferSyncer
val network = session?.networks?.get(selected?.info?.networkId)
val bufferViewConfig = viewModel.bufferViewConfig.value
......
......@@ -114,7 +114,7 @@ class MessageListFragment : ServiceBoundFragment() {
viewModel.sessionManager_liveData.zip(lastMessageId).observe(
this, Observer {
runInBackground {
val session = it?.first
val session = it?.first?.orNull()
val message = it?.second
val bufferSyncer = session?.bufferSyncer
if (message != null && bufferSyncer != null && previousMessageId != message.messageId) {
......@@ -125,8 +125,10 @@ class MessageListFragment : ServiceBoundFragment() {
})
viewModel.markerLine_liveData.observe(this, Observer {
it?.ifPresent {
adapter.markerLinePosition = it
adapter.notifyDataSetChanged()
}
})
var lastBuffer = -1
......@@ -184,7 +186,7 @@ class MessageListFragment : ServiceBoundFragment() {
val previous = lastBuffer
val firstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition()
val messageId = adapter[firstVisibleItemPosition]?.messageId
val bufferSyncer = viewModel.sessionManager.value?.bufferSyncer
val bufferSyncer = viewModel.session.value?.orNull()?.bufferSyncer
if (previous != null && messageId != null) {
bufferSyncer?.requestSetMarkerLine(previous, messageId)
}
......@@ -194,8 +196,8 @@ class MessageListFragment : ServiceBoundFragment() {
private fun loadMore() {
runInBackground {
viewModel.buffer { bufferId ->
viewModel.sessionManager {
it.backlogManager?.requestBacklog(
viewModel.session {
it.orNull()?.backlogManager?.requestBacklog(
bufferId = bufferId,
last = database.message().findFirstByBufferId(
bufferId
......
......@@ -132,15 +132,9 @@ abstract class ServiceBoundActivity : AppCompatActivity(),
}
val accountIdValid = accountId != -1L
log(
LoggingHandler.LogLevel.ERROR, "DEBUG",
"reconnect: $reconnect, accountIdValid: $accountIdValid"
)
if (!reconnect || !accountIdValid) {
if (!startedSelection) {
log(LoggingHandler.LogLevel.ERROR, "DEBUG", "started: $REQUEST_SELECT_ACCOUNT")
startActivityForResult(
Intent(this, AccountSelectionActivity::class.java), REQUEST_SELECT_ACCOUNT
)
......
......@@ -7,7 +7,8 @@ import de.kuschku.libquassel.quassel.QuasselFeature
import de.kuschku.libquassel.quassel.syncables.*
import de.kuschku.libquassel.util.compatibility.HandlerService
import de.kuschku.libquassel.util.compatibility.LoggingHandler.Companion.log
import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.*
import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.DEBUG
import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.INFO
import de.kuschku.libquassel.util.hasFlag
import io.reactivex.subjects.BehaviorSubject
import org.threeten.bp.Instant
......@@ -53,7 +54,6 @@ class Session(
override val lag = BehaviorSubject.createDefault(0L)
init {
log(ERROR, "DEBUG", "created session:", RuntimeException())
coreConnection.start()
}
......
......@@ -11,3 +11,37 @@ fun <T> Observable<T>.or(default: T): T = try {
val <T> Observable<T>.value
get() = this.map { Optional.of(it) }.blockingMostRecent(Optional.empty()).firstOrNull()?.orNull()
fun <T, U> Observable<Optional<T>>.mapMap(mapper: (T) -> U): Observable<Optional<U>> = map {
it.map(mapper)
}
fun <T, U> Observable<Optional<T>>.mapMapNullable(mapper: (T) -> U?): Observable<Optional<U>> = map {
it.flatMap {
Optional.ofNullable(mapper(it))
}
}
fun <T, U> Observable<Optional<T>>.mapSwitchMap(mapper: (T) -> Observable<U>): Observable<Optional<U>> = switchMap {
if (it.isPresent()) {
it.map(mapper).get().map { Optional.of(it) }
} else {
Observable.just(Optional.empty())
}
}
fun <T, U> Observable<Optional<T>>.mapSwitchMapEmpty(mapper: (T) -> Observable<U>): Observable<U> = switchMap {
if (it.isPresent()) {
it.map(mapper).get()
} else {
Observable.empty()
}
}
fun <T, U> Observable<Optional<T>>.flatMapSwitchMap(mapper: (T) -> Observable<Optional<U>>): Observable<Optional<U>> = switchMap {
it.map(mapper).orElse(Observable.just(Optional.empty()))
}
fun <T> Observable<Optional<T>>.mapOrElse(orElse: T): Observable<T> = map {
it.orElse(orElse)
}
\ No newline at end of file
......@@ -5,13 +5,18 @@ import de.kuschku.libquassel.protocol.BufferId
import de.kuschku.libquassel.protocol.Buffer_Type
import de.kuschku.libquassel.protocol.NetworkId
import de.kuschku.libquassel.quassel.BufferInfo
import de.kuschku.libquassel.quassel.syncables.*
import de.kuschku.libquassel.quassel.syncables.BufferViewConfig
import de.kuschku.libquassel.quassel.syncables.IrcChannel
import de.kuschku.libquassel.quassel.syncables.IrcUser
import de.kuschku.libquassel.quassel.syncables.Network
import de.kuschku.libquassel.session.Backend
import de.kuschku.libquassel.session.ConnectionState
import de.kuschku.libquassel.session.ISession
import de.kuschku.libquassel.session.SessionManager
import de.kuschku.libquassel.util.Optional
import de.kuschku.libquassel.util.and
import de.kuschku.libquassel.util.hasFlag
import de.kuschku.libquassel.util.helpers.*
import de.kuschku.quasseldroid.util.helper.combineLatest
import de.kuschku.quasseldroid.util.helper.toLiveData
import de.kuschku.quasseldroid.viewmodel.data.*
......@@ -39,33 +44,29 @@ class QuasselViewModel : ViewModel() {
}
val backend = backendWrapper.switchMap { it }
val sessionManager = backend
.filter(Optional<Backend>::isPresent)
.map(Optional<Backend>::get)
.map(Backend::sessionManager)
val sessionManager = backend.mapMap(Backend::sessionManager)
val sessionManager_liveData = sessionManager.toLiveData()
val session = sessionManager.switchMap(SessionManager::session)
val session = sessionManager.mapSwitchMap(SessionManager::session)
val connectionProgress = sessionManager.switchMap(SessionManager::connectionProgress)
val connectionProgress = sessionManager.mapSwitchMap(SessionManager::connectionProgress)
.mapOrElse(Triple(ConnectionState.DISCONNECTED, 0, 0))
val connectionProgress_liveData = connectionProgress.toLiveData()
val bufferViewManager = session.map { Optional.ofNullable(it.bufferViewManager) }
.filter(Optional<BufferViewManager>::isPresent)
.map(Optional<BufferViewManager>::get)
val bufferViewManager = session.mapMapNullable(ISession::bufferViewManager)
val bufferViewConfig = bufferViewManager.switchMap { manager ->
val bufferViewConfig = bufferViewManager.flatMapSwitchMap { manager ->
bufferViewConfigId.map { id ->
Optional.ofNullable(manager.bufferViewConfig(id))
}
}
val errors = session.switchMap(ISession::error)
val errors = session.mapSwitchMapEmpty(ISession::error)
val errors_liveData = errors.toLiveData()
/**
* An observable of the changes of the markerline, as pairs of `(old, new)`
*/
val markerLine = session.switchMap { currentSession ->
val markerLine = session.mapSwitchMap { currentSession ->
buffer.switchMap { currentBuffer ->
// Get a stream of the latest marker line
val raw = currentSession.bufferSyncer?.liveMarkerLine(currentBuffer) ?: Observable.empty()
......@@ -74,15 +75,17 @@ class QuasselViewModel : ViewModel() {
}
val markerLine_liveData = markerLine.toLiveData()
val lag: Observable<Long> = session.switchMap(ISession::lag)
// Remove orElse
val lag: Observable<Long> = session.mapSwitchMap(ISession::lag).mapOrElse(0)
val isSecure: Observable<Boolean> = session.switchMap { session ->
val isSecure: Observable<Boolean> = session.mapSwitchMap { session ->
session.state.map { _ ->
session.sslSession != null
}
}
}.mapOrElse(false)
val bufferData = combineLatest(session, buffer).switchMap { (session, id) ->
val bufferData = combineLatest(session, buffer).switchMap { (sessionOptional, id) ->
val session = sessionOptional.orNull()
val bufferSyncer = session?.bufferSyncer
if (bufferSyncer != null) {
bufferSyncer.liveBufferInfos().switchMap {
......@@ -138,7 +141,8 @@ class QuasselViewModel : ViewModel() {
}
val nickData: Observable<List<IrcUserItem>> = combineLatest(session, buffer)
.switchMap { (session, buffer) ->
.switchMap { (sessionOptional, buffer) ->
val session = sessionOptional.orNull()
val bufferSyncer = session?.bufferSyncer
val bufferInfo = bufferSyncer?.bufferInfo(buffer)
if (bufferInfo?.type?.hasFlag(Buffer_Type.ChannelBuffer) == true) {
......@@ -179,11 +183,12 @@ class QuasselViewModel : ViewModel() {
val lastWord = BehaviorSubject.create<Observable<Pair<String, IntRange>>>()
val autoCompleteData: Observable<Pair<String, List<AutoCompleteItem>>> =
combineLatest(session, buffer, lastWord).switchMap { (session, id, lastWordWrapper) ->
combineLatest(session, buffer, lastWord).switchMap { (sessionOptional, id, lastWordWrapper) ->
lastWordWrapper
.distinctUntilChanged()
.debounce(300, TimeUnit.MILLISECONDS)
.switchMap { lastWord ->
val session = sessionOptional.orNull()
val bufferSyncer = session?.bufferSyncer
val bufferInfo = bufferSyncer?.bufferInfo(id)
if (bufferSyncer != null) {
......@@ -269,20 +274,21 @@ class QuasselViewModel : ViewModel() {
}
}
val bufferViewConfigs = bufferViewManager.switchMap { manager ->
val bufferViewConfigs = bufferViewManager.mapSwitchMap { manager ->
manager.liveBufferViewConfigs().map { ids ->
ids.mapNotNull { id ->
manager.bufferViewConfig(id)
}.sortedWith(BufferViewConfig.NameComparator)
}
}
}.mapOrElse(emptyList())
val showHidden = BehaviorSubject.createDefault(false)
val collapsedNetworks = BehaviorSubject.createDefault(emptySet<NetworkId>())
val selectedBufferId = BehaviorSubject.createDefault(-1)
val selectedBuffer = combineLatest(session, selectedBufferId, bufferViewConfig)
.switchMap { (session, buffer, bufferViewConfigOptional) ->
val bufferSyncer = session.bufferSyncer
.switchMap { (sessionOptional, buffer, bufferViewConfigOptional) ->
val session = sessionOptional.orNull()
val bufferSyncer = session?.bufferSyncer
val bufferViewConfig = bufferViewConfigOptional.orNull()
if (bufferSyncer != null && bufferViewConfig != null) {
val hiddenState = when {
......@@ -330,7 +336,8 @@ class QuasselViewModel : ViewModel() {
val bufferList: Observable<Pair<BufferViewConfig?, List<BufferProps>>?> =
combineLatest(session, bufferViewConfig, showHidden)
.switchMap { (session, configOptional, showHiddenRaw) ->
.switchMap { (sessionOptional, configOptional, showHiddenRaw) ->
val session = sessionOptional.orNull()
val bufferSyncer = session?.bufferSyncer
val showHidden = showHiddenRaw ?: false
val config = configOptional.orNull()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment