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

Minor bugfixes

parent 34335962
Branches
Tags
No related merge requests found
Showing
with 198 additions and 63 deletions
......@@ -26,9 +26,7 @@ import de.kuschku.quasseldroid.util.helper.editApply
import de.kuschku.quasseldroid.util.helper.editCommit
import de.kuschku.quasseldroid.util.helper.sharedPreferences
import de.kuschku.quasseldroid.util.helper.toLiveData
import io.reactivex.Observable
import io.reactivex.functions.BiFunction
import io.reactivex.subjects.BehaviorSubject
import io.reactivex.subjects.PublishSubject
import org.threeten.bp.Instant
import java.security.cert.X509Certificate
import java.util.concurrent.TimeUnit
......@@ -220,7 +218,7 @@ class QuasselService : DaggerLifecycleService(),
}
}
}
private val connectivity = BehaviorSubject.createDefault(Unit)
private val connectivity = PublishSubject.create<Unit>()
private fun disconnectFromCore() {
getSharedPreferences(Keys.Status.NAME, Context.MODE_PRIVATE).editCommit {
......@@ -264,18 +262,27 @@ class QuasselService : DaggerLifecycleService(),
}
})
Observable.combineLatest(
sessionManager.state.filter { it == ConnectionState.DISCONNECTED || it == ConnectionState.CLOSED },
connectivity,
BiFunction { a: ConnectionState, _: Unit -> a })
var wasEverConnected = false
connectivity
.delay(200, TimeUnit.MILLISECONDS)
.throttleFirst(1, TimeUnit.SECONDS)
.toLiveData()
.observe(this, Observer {
if (wasEverConnected) sessionManager.reconnect(true)
})
sessionManager.state
.distinctUntilChanged()
.delay(200, TimeUnit.MILLISECONDS)
.throttleFirst(1, TimeUnit.SECONDS)
.toLiveData()
.observe(
this, Observer {
if (it == ConnectionState.DISCONNECTED || it == ConnectionState.CLOSED)
sessionManager.reconnect(true)
if (it == ConnectionState.DISCONNECTED || it == ConnectionState.CLOSED) {
if (wasEverConnected) sessionManager.reconnect()
} else {
wasEverConnected = true
}
})
sharedPreferences(Keys.Status.NAME, Context.MODE_PRIVATE) {
......
......@@ -388,6 +388,7 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
val selected = dialog.selectedIndices ?: emptyArray()
runInBackground {
val newlyFiltered = selected
.asSequence()
.map { flags[it] }
.fold(Message_Type.of()) { acc, i -> acc or i }
......
......@@ -210,28 +210,24 @@ class BufferViewConfigFragment : ServiceBoundFragment() {
val (config, list) = info ?: Pair(null, emptyList())
val minimumActivity = config?.minimumActivity() ?: Buffer_Activity.NONE
val activities = activityList.associate { it.bufferId to it.filtered }
listAdapter.submitList(list.sortedBy { props ->
activity?.runOnUiThread {
listAdapter.submitList(list.asSequence().sortedBy { props ->
!props.info.type.hasFlag(Buffer_Type.StatusBuffer)
}.sortedBy { props ->
props.network.networkName
}.map { props ->
val activity = props.activity - (activities[props.info.bufferId] ?: 0)
BufferListItem(
props,
BufferState(
networkExpanded = !collapsedNetworks.contains(props.network.networkId),
selected = selected.info?.bufferId == props.info.bufferId
)
)
}.filter { (props, state) ->
props.info.type.hasFlag(BufferInfo.Type.StatusBuffer) || state.networkExpanded
}.map {
val activity = it.props.activity - (activities[it.props.info.bufferId] ?: 0)
it.copy(
props = it.props.copy(
props.copy(
activity = activity,
description = ircFormatDeserializer.formatString(
requireContext(),
props.description.toString(),
colorize = messageSettings.colorizeMirc
),
bufferActivity = Buffer_Activity.of(
when {
it.props.highlights > 0 -> Buffer_Activity.Highlight
props.highlights > 0 -> Buffer_Activity.Highlight
activity.hasFlag(Message_Type.Plain) ||
activity.hasFlag(Message_Type.Notice) ||
activity.hasFlag(Message_Type.Action) -> Buffer_Activity.NewMessage
......@@ -239,12 +235,19 @@ class BufferViewConfigFragment : ServiceBoundFragment() {
else -> Buffer_Activity.NoActivity
}
)
),
BufferState(
networkExpanded = !collapsedNetworks.contains(props.network.networkId),
selected = selected.info?.bufferId == props.info.bufferId
)
)
}.filter { (props, state) ->
props.info.type.hasFlag(BufferInfo.Type.StatusBuffer) || state.networkExpanded
}.filter {
minimumActivity.toInt() <= it.props.bufferActivity.toInt() ||
it.props.info.type.hasFlag(Buffer_Type.StatusBuffer)
})
}.toList())
}
}
}
})
......
......@@ -120,6 +120,7 @@ class AutoCompleteHelper(
)?.let { ircChannel ->
val users = ircChannel.ircUsers()
val buffers = infos
.asSequence()
.filter {
it.type.toInt() == Buffer_Type.ChannelBuffer.toInt()
}.mapNotNull { info ->
......@@ -136,7 +137,7 @@ class AutoCompleteHelper(
description = channel.topic()
)
}
val nicks = users.map { user ->
val nicks = users.asSequence().map { user ->
val userModes = ircChannel.userModes(user)
val prefixModes = network.prefixModes()
......@@ -160,7 +161,7 @@ class AutoCompleteHelper(
lastWord.first.trimStart(*IGNORED_CHARS),
ignoreCase = true
)
}.sorted()
}.sorted().toList()
}
} else null
}
......
......@@ -85,7 +85,7 @@ class MessageListFragment : ServiceBoundFragment() {
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?) = when (item?.itemId) {
R.id.action_copy -> {
val builder = SpannableStringBuilder()
viewModel.selectedMessages.value.values.sortedBy {
viewModel.selectedMessages.value.values.asSequence().sortedBy {
it.id
}.map {
if (it.name != null && it.content != null) {
......@@ -114,7 +114,7 @@ class MessageListFragment : ServiceBoundFragment() {
}
R.id.action_share -> {
val builder = SpannableStringBuilder()
viewModel.selectedMessages.value.values.sortedBy {
viewModel.selectedMessages.value.values.asSequence().sortedBy {
it.id
}.map {
if (it.name != null && it.content != null) {
......
......@@ -77,7 +77,7 @@ class NickListFragment : ServiceBoundFragment() {
val avatarSize = resources.getDimensionPixelSize(R.dimen.avatar_size)
viewModel.nickData.toLiveData().observe(this, Observer {
runInBackground {
it?.map {
it?.asSequence()?.map {
val nickName = it.nick
val senderColorIndex = IrcUserUtils.senderColor(nickName)
val rawInitial = nickName.trimStart('-',
......@@ -129,7 +129,11 @@ class NickListFragment : ServiceBoundFragment() {
.trimStart(*IGNORED_CHARS)
}?.sortedBy {
it.lowestMode
}?.let(nickListAdapter::submitList)
}?.toList()?.let {
activity?.runOnUiThread {
nickListAdapter.submitList(it)
}
}
}
})
savedInstanceState?.run {
......
......@@ -46,7 +46,7 @@ class AppSettingsFragment : DaggerPreferenceFragmentCompat(),
fun initSummary(preference: Preference) {
if (preference is PreferenceGroup) {
(0 until preference.preferenceCount).map(preference::getPreference).forEach(::initSummary)
(0 until preference.preferenceCount).asSequence().map(preference::getPreference).forEach(::initSummary)
} else {
updateSummary(preference)
}
......
......@@ -61,7 +61,7 @@ object AvatarHelper {
?: return emptyList()
if (size != null) {
return listOf("https://static.irccloud-cdn.com/avatar-redirect/w${truncateSize(size)}/$userId")
return listOf("https://static.irccloud-cdn.com/avatar-redirect/s${truncateSize(size)}/$userId")
}
return listOf("https://static.irccloud-cdn.com/avatar-redirect/$userId")
......
......@@ -48,9 +48,7 @@ object Patterns {
@Language("RegExp")
const val LOCAL_HOST_NAME = """(?:$IRI_LABEL\.)*$IRI_LABEL"""
@Language("RegExp")
const val DOMAIN_NAME_STR = """(?:$LOCAL_HOST_NAME|$HOST_NAME|$IP_ADDRESS_STRING)"""
val DOMAIN_NAME = Regex(DOMAIN_NAME_STR)
val DOMAIN_NAME = Regex("""(?:$LOCAL_HOST_NAME|$HOST_NAME|$IP_ADDRESS_STRING)""")
/**
* Regular expression for valid email characters. Does not include some of the valid characters
* defined in RFC5321: #&~!^`{}/=$*?|
......@@ -72,12 +70,12 @@ object Patterns {
@Language("RegExp")
const val EMAIL_ADDRESS_DOMAIN = """(?=.{1,255}(?:\s|$|^))$HOST_NAME"""
/**
* Regular expression pattern to match email addresses. It excludes double quoted local parts
* and the special characters #&~!^`{}/=$*?| that are included in RFC5321.
*/
const val AUTOLINK_EMAIL_ADDRESS_STR = """($WORD_BOUNDARY(?:$EMAIL_ADDRESS_LOCAL_PART@$EMAIL_ADDRESS_DOMAIN)$WORD_BOUNDARY)"""
val AUTOLINK_EMAIL_ADDRESS = Regex(AUTOLINK_EMAIL_ADDRESS_STR)
val AUTOLINK_EMAIL_ADDRESS = Regex("""($WORD_BOUNDARY(?:$EMAIL_ADDRESS_LOCAL_PART@$EMAIL_ADDRESS_DOMAIN)$WORD_BOUNDARY)""")
/**
* Regular expression pattern to match IRCCloud user idents.
......
package de.kuschku.quasseldroid.util
import de.kuschku.libquassel.protocol.Message_Flag
import de.kuschku.libquassel.protocol.Message_Type
import de.kuschku.quasseldroid.persistence.QuasselDatabase
import de.kuschku.quasseldroid.settings.MessageSettings
import org.junit.Test
import org.threeten.bp.Instant
class AvatarHelperTest {
@Test
fun testGravatar() {
val message = QuasselDatabase.DatabaseMessage(
messageId = 1,
time = Instant.now(),
type = Message_Type.of(Message_Type.Plain).toInt(),
flag = Message_Flag.of().toInt(),
bufferId = 0,
sender = "justJanne",
senderPrefixes = "",
realName = "Janne Koschinski <janne@kuschku.de>",
avatarUrl = "",
content = "Lorem Ipsum I Dolor Sit Amet",
ignored = false
)
assert(
AvatarHelper.avatar(
MessageSettings(
showGravatarAvatars = true,
showIRCCloudAvatars = true
),
message
).contains("https://www.gravatar.com/avatar/81128f11cae692bc486e3f88b854ddf1?d=404")
)
assert(
AvatarHelper.avatar(
MessageSettings(
showGravatarAvatars = false,
showIRCCloudAvatars = false
),
message
).isEmpty()
)
}
@Test
fun testIrcCloud() {
val message = QuasselDatabase.DatabaseMessage(
messageId = 1,
time = Instant.now(),
type = Message_Type.of(Message_Type.Plain).toInt(),
flag = Message_Flag.of().toInt(),
bufferId = 0,
sender = "jwheare!sid2@irccloud.com",
senderPrefixes = "",
realName = "James Wheare",
avatarUrl = "",
content = "Lorem Ipsum I Dolor Sit Amet",
ignored = false
)
assert(
AvatarHelper.avatar(
MessageSettings(
showGravatarAvatars = true,
showIRCCloudAvatars = true
),
message
).contains("https://static.irccloud-cdn.com/avatar-redirect/2")
)
assert(
AvatarHelper.avatar(
MessageSettings(
showGravatarAvatars = false,
showIRCCloudAvatars = false
),
message
).isEmpty()
)
}
@Test
fun testActualAvatars() {
val message = QuasselDatabase.DatabaseMessage(
messageId = 1,
time = Instant.now(),
type = Message_Type.of(Message_Type.Plain).toInt(),
flag = Message_Flag.of().toInt(),
bufferId = 0,
sender = "jwheare!sid2@irccloud.com",
senderPrefixes = "",
realName = "James Wheare",
avatarUrl = "https://quasseldroid.info/favicon.png",
content = "Lorem Ipsum I Dolor Sit Amet",
ignored = false
)
assert(
AvatarHelper.avatar(
MessageSettings(
showGravatarAvatars = true,
showIRCCloudAvatars = true
),
message
).contains("https://quasseldroid.info/favicon.png")
)
assert(
AvatarHelper.avatar(
MessageSettings(
showGravatarAvatars = false,
showIRCCloudAvatars = false
),
message
) == listOf("https://quasseldroid.info/favicon.png")
)
}
}
......@@ -64,10 +64,10 @@ class SessionManager(
Invokers
}
fun ifDisconnected(closure: () -> Unit) {
fun ifDisconnected(closure: (ISession) -> Unit) {
state.or(ConnectionState.DISCONNECTED).let {
if (it == ConnectionState.DISCONNECTED || it == ConnectionState.CLOSED) {
closure()
closure(inProgressSession.value)
}
}
}
......
......@@ -185,7 +185,7 @@ class QuasselViewModel : ViewModel() {
val userModes = ircChannel.userModes(user)
val prefixModes = network.prefixModes()
val lowestMode = userModes.mapNotNull {
val lowestMode = userModes.asSequence().mapNotNull {
prefixModes.indexOf(it)
}.min() ?: prefixModes.size
......@@ -300,7 +300,7 @@ class QuasselViewModel : ViewModel() {
)
).switchMap { (ids, temp, perm) ->
fun transformIds(ids: Collection<BufferId>, state: BufferHiddenState) =
ids.mapNotNull { id ->
ids.asSequence().mapNotNull { id ->
bufferSyncer.bufferInfo(id)
}.filter {
currentConfig.networkId() <= 0 || currentConfig.networkId() == it.networkId
......@@ -403,10 +403,10 @@ class QuasselViewModel : ViewModel() {
transformIds(ids.distinct(), BufferHiddenState.VISIBLE)
}
combineLatest<BufferProps>(buffers).map { list ->
combineLatest<BufferProps>(buffers.toList()).map { list ->
Pair<BufferViewConfig?, List<BufferProps>>(
config,
list.filter {
list.asSequence().filter {
(!config.hideInactiveBuffers()) ||
it.bufferStatus != BufferStatus.OFFLINE ||
it.info.type.hasFlag(Buffer_Type.StatusBuffer)
......@@ -415,7 +415,7 @@ class QuasselViewModel : ViewModel() {
it.sortedBy { IrcCaseMappers.unicode.toLowerCaseNullable(it.info.bufferName) }
.sortedByDescending { it.hiddenState == BufferHiddenState.VISIBLE }
else it
}.distinctBy { it.info.bufferId }
}.distinctBy { it.info.bufferId }.toList()
)
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment