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

Fixes concurrency bugs

parent 1c6ec321
Branches
Tags
No related merge requests found
...@@ -22,6 +22,8 @@ package de.kuschku.quasseldroid.ui.clientsettings.client ...@@ -22,6 +22,8 @@ package de.kuschku.quasseldroid.ui.clientsettings.client
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Handler
import android.os.HandlerThread
import android.view.Menu import android.view.Menu
import android.view.MenuInflater import android.view.MenuInflater
import android.view.MenuItem import android.view.MenuItem
...@@ -29,6 +31,7 @@ import androidx.preference.ListPreference ...@@ -29,6 +31,7 @@ import androidx.preference.ListPreference
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceGroup import androidx.preference.PreferenceGroup
import de.kuschku.quasseldroid.R import de.kuschku.quasseldroid.R
import de.kuschku.quasseldroid.persistence.db.QuasselDatabase
import de.kuschku.quasseldroid.settings.AppearanceSettings import de.kuschku.quasseldroid.settings.AppearanceSettings
import de.kuschku.quasseldroid.settings.Settings import de.kuschku.quasseldroid.settings.Settings
import de.kuschku.quasseldroid.ui.clientsettings.about.AboutActivity import de.kuschku.quasseldroid.ui.clientsettings.about.AboutActivity
...@@ -43,9 +46,21 @@ class ClientSettingsFragment : DaggerPreferenceFragmentCompat(), ...@@ -43,9 +46,21 @@ class ClientSettingsFragment : DaggerPreferenceFragmentCompat(),
@Inject @Inject
lateinit var appearanceSettings: AppearanceSettings lateinit var appearanceSettings: AppearanceSettings
private lateinit var handlerThread: HandlerThread
private lateinit var handler: Handler
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setHasOptionsMenu(true) setHasOptionsMenu(true)
handlerThread = HandlerThread("ClientSettings")
handlerThread.start()
handler = Handler(handlerThread.looper)
}
override fun onDestroy() {
super.onDestroy()
handlerThread.quit()
} }
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
...@@ -57,6 +72,14 @@ class ClientSettingsFragment : DaggerPreferenceFragmentCompat(), ...@@ -57,6 +72,14 @@ class ClientSettingsFragment : DaggerPreferenceFragmentCompat(),
} else { } else {
findPreference(getString(R.string.preference_notification_configure_key)).isVisible = false findPreference(getString(R.string.preference_notification_configure_key)).isVisible = false
} }
findPreference(getString(R.string.preference_clear_cache_key)).setOnPreferenceClickListener {
activity?.let {
handler.post {
QuasselDatabase.Creator.init(it).message().clearMessages()
}
}
true
}
} }
override fun onStart() { override fun onStart() {
......
...@@ -299,6 +299,8 @@ ...@@ -299,6 +299,8 @@
<string name="preference_initial_amount_title">Initial Amount</string> <string name="preference_initial_amount_title">Initial Amount</string>
<string name="preference_initial_amount_summary">Number of messages to load when opening a buffer for the first time</string> <string name="preference_initial_amount_summary">Number of messages to load when opening a buffer for the first time</string>
<string name="preference_clear_cache_key" translatable="false">clear_cache_key</string>
<string name="preference_clear_cache_title">Clear Backlog Cache</string>
<string name="preference_connection_title">Connection</string> <string name="preference_connection_title">Connection</string>
......
...@@ -306,6 +306,9 @@ ...@@ -306,6 +306,9 @@
android:key="@string/preference_initial_amount_key" android:key="@string/preference_initial_amount_key"
android:summary="@string/preference_initial_amount_summary" android:summary="@string/preference_initial_amount_summary"
android:title="@string/preference_initial_amount_title" /> android:title="@string/preference_initial_amount_title" />
<PreferenceScreen
android:key="@string/preference_clear_cache_key"
android:title="@string/preference_clear_cache_title" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory android:layout="@layout/widget_preference_divider" /> <PreferenceCategory android:layout="@layout/widget_preference_divider" />
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>. * with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
@file:Suppress("NOTHING_TO_INLINE") @file:Suppress("NOTHING_TO_INLINE")
package de.kuschku.libquassel.quassel.syncables package de.kuschku.libquassel.quassel.syncables
import de.kuschku.libquassel.protocol.* import de.kuschku.libquassel.protocol.*
...@@ -79,9 +80,11 @@ class IrcChannel( ...@@ -79,9 +80,11 @@ class IrcChannel(
"D" to QVariant.of(_D_channelModes.joinToString(), Type.QString) "D" to QVariant.of(_D_channelModes.joinToString(), Type.QString)
) )
override fun initUserModes(): QVariantMap = _userModes.entries.map { (key, value) -> override fun initUserModes(): QVariantMap = synchronized(_userModes) {
_userModes.entries.map { (key, value) ->
key.nick() to QVariant.of(value, Type.QString) key.nick() to QVariant.of(value, Type.QString)
}.toMap() }.toMap()
}
override fun initProperties(): QVariantMap = mapOf( override fun initProperties(): QVariantMap = mapOf(
"name" to QVariant.of(name(), Type.QString), "name" to QVariant.of(name(), Type.QString),
...@@ -120,8 +123,8 @@ class IrcChannel( ...@@ -120,8 +123,8 @@ class IrcChannel(
setEncrypted(properties["encrypted"].indexed(i).valueOr(this::encrypted)) setEncrypted(properties["encrypted"].indexed(i).valueOr(this::encrypted))
} }
fun isKnownUser(ircUser: IrcUser): Boolean { fun isKnownUser(ircUser: IrcUser) = synchronized(_userModes) {
return _userModes.contains(ircUser) _userModes.contains(ircUser)
} }
fun isValidChannelUserMode(mode: String): Boolean { fun isValidChannelUserMode(mode: String): Boolean {
...@@ -133,14 +136,22 @@ class IrcChannel( ...@@ -133,14 +136,22 @@ class IrcChannel(
fun password() = _password fun password() = _password
fun encrypted() = _encrypted fun encrypted() = _encrypted
fun network() = _network fun network() = _network
fun ircUsers() = _userModes.keys fun ircUsers() = synchronized(_userModes) {
fun liveIrcUsers(): Observable<MutableSet<IrcUser>> = _userModes.keys.toSet()
live_userModes.map { _userModes }.map(MutableMap<IrcUser, String>::keys) }
fun liveIrcUsers(): Observable<Set<IrcUser>> =
live_userModes.map { ircUsers() }
fun userModes(ircUser: IrcUser) = synchronized(_userModes) {
_userModes.getOr(ircUser, "")
}
fun userModes(ircUser: IrcUser) = _userModes.getOr(ircUser, "")
fun liveUserModes(ircUser: IrcUser) = live_userModes.map { fun liveUserModes(ircUser: IrcUser) = live_userModes.map {
synchronized(_userModes) {
_userModes.getOr(ircUser, "") _userModes.getOr(ircUser, "")
} }
}
fun userCount() = _userCount fun userCount() = _userCount
...@@ -248,6 +259,7 @@ class IrcChannel( ...@@ -248,6 +259,7 @@ class IrcChannel(
} }
private fun joinIrcUsersInternal(rawUsers: List<IrcUser>, rawModes: List<String>) { private fun joinIrcUsersInternal(rawUsers: List<IrcUser>, rawModes: List<String>) {
synchronized(_userModes) {
val users = rawUsers.zip(rawModes) val users = rawUsers.zip(rawModes)
val newNicks = users.filter { !_userModes.contains(it.first) } val newNicks = users.filter { !_userModes.contains(it.first) }
val oldNicks = users.filter { _userModes.contains(it.first) } val oldNicks = users.filter { _userModes.contains(it.first) }
...@@ -262,12 +274,14 @@ class IrcChannel( ...@@ -262,12 +274,14 @@ class IrcChannel(
} }
updateUsers() updateUsers()
} }
}
override fun joinIrcUser(ircuser: IrcUser) { override fun joinIrcUser(ircuser: IrcUser) {
joinIrcUsersInternal(listOf(ircuser), listOf("")) joinIrcUsersInternal(listOf(ircuser), listOf(""))
} }
override fun part(ircuser: IrcUser?) { override fun part(ircuser: IrcUser?) {
synchronized(_userModes) {
if (ircuser == null) if (ircuser == null)
return return
if (!isKnownUser(ircuser)) if (!isKnownUser(ircuser))
...@@ -284,17 +298,20 @@ class IrcChannel( ...@@ -284,17 +298,20 @@ class IrcChannel(
} }
updateUsers() updateUsers()
} }
}
override fun part(nick: String?) { override fun part(nick: String?) {
part(network().ircUser(nick)) part(network().ircUser(nick))
} }
override fun setUserModes(ircuser: IrcUser?, modes: String?) { override fun setUserModes(ircuser: IrcUser?, modes: String?) {
synchronized(_userModes) {
if (ircuser == null || !isKnownUser(ircuser)) if (ircuser == null || !isKnownUser(ircuser))
return return
_userModes[ircuser] = modes ?: "" _userModes[ircuser] = modes ?: ""
updateUsers() updateUsers()
} }
}
override fun setUserModes(nick: String?, modes: String?) { override fun setUserModes(nick: String?, modes: String?) {
setUserModes(network().ircUser(nick), modes ?: "") setUserModes(network().ircUser(nick), modes ?: "")
...@@ -305,6 +322,7 @@ class IrcChannel( ...@@ -305,6 +322,7 @@ class IrcChannel(
} }
override fun addUserMode(ircuser: IrcUser?, mode: String?) { override fun addUserMode(ircuser: IrcUser?, mode: String?) {
synchronized(_userModes) {
val userMode = mode ?: "" val userMode = mode ?: ""
if (ircuser == null || !isKnownUser(ircuser) || !isValidChannelUserMode(userMode)) if (ircuser == null || !isKnownUser(ircuser) || !isValidChannelUserMode(userMode))
return return
...@@ -313,12 +331,14 @@ class IrcChannel( ...@@ -313,12 +331,14 @@ class IrcChannel(
_userModes[ircuser] = _userModes.getOr(ircuser, "") + userMode _userModes[ircuser] = _userModes.getOr(ircuser, "") + userMode
updateUsers() updateUsers()
} }
}
override fun addUserMode(nick: String?, mode: String?) { override fun addUserMode(nick: String?, mode: String?) {
addUserMode(network().ircUser(nick), mode ?: "") addUserMode(network().ircUser(nick), mode ?: "")
} }
override fun removeUserMode(ircuser: IrcUser?, mode: String?) { override fun removeUserMode(ircuser: IrcUser?, mode: String?) {
synchronized(_userModes) {
val userMode = mode ?: "" val userMode = mode ?: ""
if (ircuser == null || !isKnownUser(ircuser) || !isValidChannelUserMode(userMode)) if (ircuser == null || !isKnownUser(ircuser) || !isValidChannelUserMode(userMode))
return return
...@@ -328,6 +348,7 @@ class IrcChannel( ...@@ -328,6 +348,7 @@ class IrcChannel(
.replace(userMode, "", ignoreCase = true) .replace(userMode, "", ignoreCase = true)
updateUsers() updateUsers()
} }
}
override fun removeUserMode(nick: String?, mode: String?) { override fun removeUserMode(nick: String?, mode: String?) {
removeUserMode(network().ircUser(nick), mode ?: "") removeUserMode(network().ircUser(nick), mode ?: "")
...@@ -398,7 +419,7 @@ class IrcChannel( ...@@ -398,7 +419,7 @@ class IrcChannel(
live_updates.onNext(Unit) live_updates.onNext(Unit)
} }
private fun updateUsers() { private fun updateUsers() = synchronized(_userModes) {
_userCount = _userModes.size _userCount = _userModes.size
live_userModes.onNext(Unit) live_userModes.onNext(Unit)
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment