diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/info/user/IrcUserInfo.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/info/user/IrcUserInfo.kt index 32362da4685fa82be0f2532a13ff31c4a0c09d09..efcc94e507423b1f01a62f9320b93ccd37e6be2f 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/info/user/IrcUserInfo.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/info/user/IrcUserInfo.kt @@ -21,6 +21,7 @@ package de.kuschku.quasseldroid.ui.info.user import de.kuschku.libquassel.protocol.NetworkId import de.kuschku.libquassel.quassel.BufferInfo +import de.kuschku.libquassel.quassel.syncables.IgnoreListManager import de.kuschku.libquassel.quassel.syncables.IrcUser import de.kuschku.libquassel.quassel.syncables.Network import de.kuschku.quasseldroid.viewmodel.data.BufferProps @@ -39,5 +40,6 @@ data class IrcUserInfo( val knownToCore: Boolean = false, val info: BufferInfo? = null, val ircUser: IrcUser? = null, - val channels: List<BufferProps> = emptyList() + val channels: List<BufferProps> = emptyList(), + val ignoreListItems: List<IgnoreListManager.IgnoreListItem> = emptyList() ) diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/info/user/UserInfoFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/info/user/UserInfoFragment.kt index adb6a8c3cb5a8d05822b7fc39da6a291fdbd18c2..08c0a7ad0d7e061d52f5e6ebc7d636e2e5705b0b 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/info/user/UserInfoFragment.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/info/user/UserInfoFragment.kt @@ -30,6 +30,7 @@ import android.view.ViewGroup import android.widget.Button import android.widget.ImageView import android.widget.TextView +import androidx.appcompat.widget.PopupMenu import androidx.lifecycle.Observer import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.LinearLayoutManager @@ -42,6 +43,7 @@ import de.kuschku.libquassel.protocol.Message_Type import de.kuschku.libquassel.protocol.NetworkId import de.kuschku.libquassel.quassel.BufferInfo import de.kuschku.libquassel.quassel.syncables.BufferSyncer +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 @@ -174,8 +176,8 @@ class UserInfoFragment : ServiceBoundFragment() { } combineLatest(viewModel.session, viewModel.networks).switchMap { (sessionOptional, networks) -> - fun processUser(user: IrcUser, bufferSyncer: BufferSyncer? = null, - info: BufferInfo? = null): Observable<Optional<IrcUserInfo>> { + fun processUser(user: IrcUser, bufferSyncer: BufferSyncer? = null, info: BufferInfo? = null, + ignoreItems: List<IgnoreListManager.IgnoreListItem>? = null): Observable<Optional<IrcUserInfo>> { actionShortcut.post(::updateShortcutVisibility) return when { user == IrcUser.NULL && info != null -> Observable.just(Optional.of(IrcUserInfo( @@ -202,7 +204,8 @@ class UserInfoFragment : ServiceBoundFragment() { ircUser = user, channels = channels.sortedBy { IrcCaseMappers.unicode.toLowerCaseNullable(it.info.bufferName) - } + }, + ignoreListItems = ignoreItems.orEmpty() ) if (user.channels().isEmpty()) { @@ -252,8 +255,8 @@ class UserInfoFragment : ServiceBoundFragment() { } } + val session = sessionOptional?.orNull() if (openBuffer == true) { - val session = sessionOptional?.orNull() val bufferSyncer = session?.bufferSyncer val bufferInfo = bufferSyncer?.bufferInfo(bufferId) bufferInfo?.let { @@ -262,10 +265,20 @@ class UserInfoFragment : ServiceBoundFragment() { } } } else { + val ignoreListManager = session?.ignoreListManager + networks[networkId] ?.liveIrcUser(nickName) ?.switchMap(IrcUser::updates) - ?.switchMap { user -> processUser(user, sessionOptional?.orNull()?.bufferSyncer) } + ?.switchMap { user -> + ignoreListManager?.liveMatchingRules(user.hostMask())?.map { + Pair(user, it) + } ?: Observable.just(Pair(user, emptyList())) + }?.switchMap { (user, ignoreItems) -> + processUser(user, + sessionOptional?.orNull()?.bufferSyncer, + ignoreItems = ignoreItems) + } } ?: Observable.just(IrcUser.NULL).switchMap { user -> processUser(user, null, null) } }.toLiveData().observe(this, Observer { val user = it.orNull() @@ -366,9 +379,48 @@ class UserInfoFragment : ServiceBoundFragment() { } } + var ignoreMenu: PopupMenu? = null actionIgnore.setOnClickListener { view -> - IgnoreListActivity.launch(view.context, - addRule = HostmaskHelper.build(user.nick, user.user, user.host)) + PopupMenu(actionIgnore.context, actionIgnore).also { menu -> + ignoreMenu?.dismiss() + menu.menuInflater.inflate(R.menu.context_ignore, menu.menu) + for (ignoreItem in user.ignoreListItems) { + menu.menu.add(ignoreItem.ignoreRule).apply { + isCheckable = true + isChecked = ignoreItem.isActive + } + } + menu.setOnMenuItemClickListener { + when { + it.itemId == R.id.action_create -> { + IgnoreListActivity.launch( + view.context, + addRule = HostmaskHelper.build(user.nick, user.user, user.host) + ) + menu.dismiss() + ignoreMenu = null + true + } + it.itemId == R.id.action_show -> { + IgnoreListActivity.launch( + view.context + ) + menu.dismiss() + ignoreMenu = null + true + } + it.isCheckable -> { + viewModel.ignoreListManager.value?.orNull()?.requestToggleIgnoreRule(it.title.toString()) + true + } + else -> false + } + } + menu.setOnDismissListener { + ignoreMenu = null + } + menu.show() + } } actionMention.setOnClickListener { view -> diff --git a/app/src/main/res/menu/context_ignore.xml b/app/src/main/res/menu/context_ignore.xml new file mode 100644 index 0000000000000000000000000000000000000000..53b55589c77acf325b12243a1d951ee8b06bcf9f --- /dev/null +++ b/app/src/main/res/menu/context_ignore.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + Quasseldroid - Quassel client for Android + + Copyright (c) 2019 Janne Koschinski + Copyright (c) 2019 The Quassel Project + + This program is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License version 3 as published + by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program. If not, see <http://www.gnu.org/licenses/>. + --> + +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:id="@+id/action_create" + android:title="@string/label_new_ignore_rule" /> + <item + android:id="@+id/action_show" + android:title="@string/settings_ignorelist_title" /> +</menu> diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/IgnoreListManager.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/IgnoreListManager.kt index b0f464451aeea3d173503a6601f6c7d471189732..2371bd2e186f2d1b29bf7c5e355c0b329dddcb21 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/IgnoreListManager.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/IgnoreListManager.kt @@ -122,6 +122,15 @@ class IgnoreListManager constructor( _ignoreList = list } + fun matchingRules(sender: String) = _ignoreList.filter { + it.type == IgnoreType.SenderIgnore && + it.regEx.match(sender) + } + + fun liveMatchingRules(sender: String) = live_updates.map { + matchingRules(sender) + } + fun updates() = live_updates.map { this } fun copy() = IgnoreListManager(session).also {