diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a53f267fcbafc8aa9c17f611bcf5e244f9b19c79..0a7df83a40f7ff15b59d8f1e18827da6797b5d7d 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -126,6 +126,7 @@ dependencies { } // Utility + implementation("io.reactivex.rxjava2", "rxandroid", "2.0.2") implementation("io.reactivex.rxjava2", "rxjava", "2.1.9") implementation("org.threeten", "threetenbp", "1.3.6", classifier = "no-tzdb") implementation("org.jetbrains", "annotations", "16.0.1") diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/ChatActivity.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/ChatActivity.kt index 5928f4594fa911d96c894bd96be43e0b0a815997..07a553b5cd7cb65f845c556cba8e586cf2ed0a0a 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/ChatActivity.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/ChatActivity.kt @@ -106,7 +106,7 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc setSupportActionBar(toolbar) - viewModel.buffer_liveData.observe(this, Observer { + viewModel.buffer.toLiveData().observe(this, Observer { if (it != null && drawerLayout.isDrawerOpen(Gravity.START)) { drawerLayout.closeDrawer(Gravity.START, true) } @@ -151,8 +151,8 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc } } - viewModel.errors.observe(this, Observer { error -> - error?.let { + viewModel.errors.toLiveData().observe(this, Observer { error -> + error?.orNull()?.let { when (it) { is HandshakeMessage.ClientInitReject -> MaterialDialog.Builder(this) @@ -232,7 +232,7 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc } }) - viewModel.connectionProgress_liveData.observe(this, Observer { + viewModel.connectionProgress.toLiveData().observe(this, Observer { val (state, progress, max) = it ?: Triple(ConnectionState.DISCONNECTED, 0, 0) when (state) { ConnectionState.CONNECTED -> { diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferViewConfigFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferViewConfigFragment.kt index cc52089d3702bcd205a59f358b382cf7aa8bc021..63fbb4182388ac65dcd0b74b27fc12a66eb4fd89 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferViewConfigFragment.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferViewConfigFragment.kt @@ -230,7 +230,7 @@ class BufferViewConfigFragment : ServiceBoundFragment() { ) chatList.adapter = listAdapter - viewModel.selectedBuffer_liveData.observe(this, Observer { buffer -> + viewModel.selectedBuffer.toLiveData().observe(this, Observer { buffer -> if (buffer != null) { val menu = actionMode?.menu if (menu != null) { diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/ChatlineFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/ChatlineFragment.kt index 98c1dbe6999916354d61afa5b0467e0b15abb7f7..255e89229bc0da9f5e763613f9743eb0b96eeb12 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/ChatlineFragment.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/ChatlineFragment.kt @@ -19,10 +19,7 @@ import de.kuschku.quasseldroid.R import de.kuschku.quasseldroid.settings.AppearanceSettings import de.kuschku.quasseldroid.settings.AutoCompleteSettings import de.kuschku.quasseldroid.settings.MessageSettings -import de.kuschku.quasseldroid.util.helper.invoke -import de.kuschku.quasseldroid.util.helper.lineSequence -import de.kuschku.quasseldroid.util.helper.retint -import de.kuschku.quasseldroid.util.helper.visibleIf +import de.kuschku.quasseldroid.util.helper.* import de.kuschku.quasseldroid.util.irc.format.IrcFormatDeserializer import de.kuschku.quasseldroid.util.irc.format.IrcFormatSerializer import de.kuschku.quasseldroid.util.service.ServiceBoundFragment @@ -126,9 +123,8 @@ class ChatlineFragment : ServiceBoundFragment() { historyPanel.panelState = SlidingUpPanelLayout.PanelState.COLLAPSED } messageHistory.adapter = messageHistoryAdapter - viewModel.recentlySentMessages_liveData.observe( - this, Observer(messageHistoryAdapter::submitList) - ) + viewModel.recentlySentMessages.toLiveData() + .observe(this, Observer(messageHistoryAdapter::submitList)) fun send() { if (chatline.text.isNotBlank()) { diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageListFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageListFragment.kt index 28dc3c523da437a956493499d85d6d2437305d53..68bafbb81bb30fccc5789678ad5731def5beda1e 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageListFragment.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageListFragment.kt @@ -274,7 +274,7 @@ class MessageListFragment : ServiceBoundFragment() { } } - val lastMessageId = viewModel.buffer_liveData.switchMapNotNull { + val lastMessageId = viewModel.buffer.toLiveData().switchMapNotNull { database.message().lastMsgId(it) } diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/AvatarHelper.kt b/app/src/main/java/de/kuschku/quasseldroid/util/AvatarHelper.kt deleted file mode 100644 index 60a5af7308f1eb72d7a6ac9a19fd53c1a4b61a8f..0000000000000000000000000000000000000000 --- a/app/src/main/java/de/kuschku/quasseldroid/util/AvatarHelper.kt +++ /dev/null @@ -1,18 +0,0 @@ -package de.kuschku.quasseldroid.util - -import de.kuschku.libquassel.quassel.syncables.IrcUser -import de.kuschku.libquassel.util.irc.HostmaskHelper -import de.kuschku.quasseldroid.persistence.QuasselDatabase - -object AvatarHelper { - fun avatar(message: QuasselDatabase.DatabaseMessage? = null, user: IrcUser? = null): String? { - val ident = message?.sender?.let(HostmaskHelper::user) - ?: user?.user() - ?: return null - - val userId = Regex("[us]id(\\d+)").matchEntire(ident)?.groupValues?.lastOrNull() - ?: return null - - return "https://static.irccloud-cdn.com/avatar-redirect/$userId" - } -} diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/compatibility/AndroidHandlerService.kt b/app/src/main/java/de/kuschku/quasseldroid/util/compatibility/AndroidHandlerService.kt index b61c3b793ca4fb4a1d0af66a2ce69cd0e9983f02..3da80f703d0f14d896a2239580330c50d760eff8 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/util/compatibility/AndroidHandlerService.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/util/compatibility/AndroidHandlerService.kt @@ -2,10 +2,18 @@ package de.kuschku.quasseldroid.util.compatibility import android.os.Handler import android.os.HandlerThread +import android.os.Message import android.os.Process import de.kuschku.libquassel.util.compatibility.HandlerService +import io.reactivex.Scheduler +import io.reactivex.disposables.Disposable +import io.reactivex.disposables.Disposables +import io.reactivex.plugins.RxJavaPlugins +import java.util.concurrent.TimeUnit class AndroidHandlerService : HandlerService { + override lateinit var scheduler: Scheduler + override fun serialize(f: () -> Unit) { serializeHandler.post(f) } @@ -56,6 +64,8 @@ class AndroidHandlerService : HandlerService { deserializeHandler = Handler(deserializeThread.looper) writeHandler = Handler(writeThread.looper) backendHandler = Handler(backendThread.looper) + + scheduler = HandlerScheduler(backendHandler) } override var exceptionHandler: Thread.UncaughtExceptionHandler? = null @@ -67,4 +77,77 @@ class AndroidHandlerService : HandlerService { writeThread.quit() backendThread.quit() } + + internal class HandlerScheduler(private val handler: Handler) : Scheduler() { + override fun scheduleDirect(run: Runnable, delay: Long, unit: TimeUnit): Disposable { + val scheduled = ScheduledRunnable(handler, RxJavaPlugins.onSchedule(run)) + handler.postDelayed(scheduled, unit.toMillis(delay)) + return scheduled + } + + override fun createWorker(): Scheduler.Worker { + return HandlerWorker(handler) + } + + private class HandlerWorker constructor(private val handler: Handler) : Scheduler.Worker() { + @Volatile + private var disposed: Boolean = false + + override fun schedule(run: Runnable, delay: Long, unit: TimeUnit): Disposable { + if (disposed) { + return Disposables.disposed() + } + + val scheduled = ScheduledRunnable(handler, RxJavaPlugins.onSchedule(run)) + + val message = Message.obtain(handler, scheduled) + message.obj = this // Used as token for batch disposal of this worker's runnables. + + handler.sendMessageDelayed(message, unit.toMillis(delay)) + + // Re-check disposed state for removing in case we were racing a call to dispose(). + if (disposed) { + handler.removeCallbacks(scheduled) + return Disposables.disposed() + } + + return scheduled + } + + override fun dispose() { + disposed = true + handler.removeCallbacksAndMessages(this /* token */) + } + + override fun isDisposed(): Boolean { + return disposed + } + } + + private class ScheduledRunnable internal constructor(private val handler: Handler, + private val delegate: Runnable) : Runnable, + Disposable { + + @Volatile + private var disposed: Boolean = false + + override fun run() { + try { + delegate.run() + } catch (t: Throwable) { + RxJavaPlugins.onError(t) + } + + } + + override fun dispose() { + disposed = true + handler.removeCallbacks(this) + } + + override fun isDisposed(): Boolean { + return disposed + } + } + } }