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

Added enter key option, improved hostmask option

parent 89a3a4e9
No related branches found
No related tags found
No related merge requests found
Showing
with 239 additions and 29 deletions
...@@ -15,7 +15,9 @@ import android.support.v4.widget.DrawerLayout ...@@ -15,7 +15,9 @@ import android.support.v4.widget.DrawerLayout
import android.support.v7.app.ActionBarDrawerToggle import android.support.v7.app.ActionBarDrawerToggle
import android.support.v7.widget.Toolbar import android.support.v7.widget.Toolbar
import android.text.InputType import android.text.InputType
import android.text.Spanned
import android.view.* import android.view.*
import android.view.inputmethod.EditorInfo
import android.widget.EditText import android.widget.EditText
import android.widget.ImageButton import android.widget.ImageButton
import butterknife.BindView import butterknife.BindView
...@@ -32,14 +34,12 @@ import de.kuschku.quasseldroid_ng.Keys ...@@ -32,14 +34,12 @@ import de.kuschku.quasseldroid_ng.Keys
import de.kuschku.quasseldroid_ng.R import de.kuschku.quasseldroid_ng.R
import de.kuschku.quasseldroid_ng.persistence.QuasselDatabase import de.kuschku.quasseldroid_ng.persistence.QuasselDatabase
import de.kuschku.quasseldroid_ng.ui.settings.SettingsActivity import de.kuschku.quasseldroid_ng.ui.settings.SettingsActivity
import de.kuschku.quasseldroid_ng.ui.settings.data.AppearanceSettings
import de.kuschku.quasseldroid_ng.ui.settings.data.BacklogSettings import de.kuschku.quasseldroid_ng.ui.settings.data.BacklogSettings
import de.kuschku.quasseldroid_ng.ui.settings.data.Settings import de.kuschku.quasseldroid_ng.ui.settings.data.Settings
import de.kuschku.quasseldroid_ng.ui.viewmodel.QuasselViewModel import de.kuschku.quasseldroid_ng.ui.viewmodel.QuasselViewModel
import de.kuschku.quasseldroid_ng.util.AndroidHandlerThread import de.kuschku.quasseldroid_ng.util.AndroidHandlerThread
import de.kuschku.quasseldroid_ng.util.helper.editApply import de.kuschku.quasseldroid_ng.util.helper.*
import de.kuschku.quasseldroid_ng.util.helper.invoke
import de.kuschku.quasseldroid_ng.util.helper.let
import de.kuschku.quasseldroid_ng.util.helper.sharedPreferences
import de.kuschku.quasseldroid_ng.util.irc.format.IrcFormatSerializer import de.kuschku.quasseldroid_ng.util.irc.format.IrcFormatSerializer
import de.kuschku.quasseldroid_ng.util.service.ServiceBoundActivity import de.kuschku.quasseldroid_ng.util.service.ServiceBoundActivity
import de.kuschku.quasseldroid_ng.util.ui.MaterialContentLoadingProgressBar import de.kuschku.quasseldroid_ng.util.ui.MaterialContentLoadingProgressBar
...@@ -117,6 +117,17 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc ...@@ -117,6 +117,17 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
send() send()
} }
chatline.imeOptions = when (appearanceSettings.inputEnter) {
AppearanceSettings.InputEnterMode.EMOJI -> listOf(
EditorInfo.IME_ACTION_NONE,
EditorInfo.IME_FLAG_NO_EXTRACT_UI
)
AppearanceSettings.InputEnterMode.SEND -> listOf(
EditorInfo.IME_ACTION_SEND,
EditorInfo.IME_FLAG_NO_EXTRACT_UI
)
}.fold(0, Int::or)
chatline.setOnKeyListener { _, keyCode, event -> chatline.setOnKeyListener { _, keyCode, event ->
if (event.hasNoModifiers() && (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_NUMPAD_ENTER)) { if (event.hasNoModifiers() && (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_NUMPAD_ENTER)) {
send() send()
...@@ -171,9 +182,13 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc ...@@ -171,9 +182,13 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc
viewModel.getBuffer().let { bufferId -> viewModel.getBuffer().let { bufferId ->
session.bufferSyncer?.bufferInfo(bufferId)?.also { bufferInfo -> session.bufferSyncer?.bufferInfo(bufferId)?.also { bufferInfo ->
val output = mutableListOf<IAliasManager.Command>() val output = mutableListOf<IAliasManager.Command>()
for (line in text.lineSequence()) {
session.aliasManager?.processInput( session.aliasManager?.processInput(
bufferInfo, ircFormatSerializer.toEscapeCodes(text), output bufferInfo,
if (line is Spanned) ircFormatSerializer.toEscapeCodes(line) else line.toString(),
output
) )
}
for (command in output) { for (command in output) {
session.rpcHandler?.sendInput(command.buffer, command.message) session.rpcHandler?.sendInput(command.buffer, command.message)
} }
......
...@@ -324,28 +324,38 @@ class QuasselMessageRenderer( ...@@ -324,28 +324,38 @@ class QuasselMessageRenderer(
} }
} }
private fun formatNickImpl(sender: String, colorize: Boolean, hostmask: Boolean): CharSequence { private fun formatNickNickImpl(nick: String, colorize: Boolean): CharSequence {
val nick = IrcUserUtils.nick(sender) val spannableString = SpannableString(nick)
val content = if (hostmask) sender else nick
val spannableString = SpannableString(content)
if (colorize) { if (colorize) {
val senderColor = IrcUserUtils.senderColor(nick) val senderColor = IrcUserUtils.senderColor(nick)
spannableString.setSpan( spannableString.setSpan(
ForegroundColorSpan(senderColors[senderColor % senderColors.size]), ForegroundColorSpan(senderColors[senderColor % senderColors.size]),
0, 0,
content.length, nick.length,
SpannableString.SPAN_INCLUSIVE_EXCLUSIVE SpannableString.SPAN_INCLUSIVE_EXCLUSIVE
) )
} }
spannableString.setSpan( spannableString.setSpan(
StyleSpan(Typeface.BOLD), StyleSpan(Typeface.BOLD),
0, 0,
content.length, nick.length,
SpannableString.SPAN_INCLUSIVE_EXCLUSIVE SpannableString.SPAN_INCLUSIVE_EXCLUSIVE
) )
return spannableString return spannableString
} }
private fun formatNickImpl(sender: String, colorize: Boolean, hostmask: Boolean): CharSequence {
val nick = IrcUserUtils.nick(sender)
val mask = IrcUserUtils.mask(sender)
val formattedNick = formatNickNickImpl(nick, colorize)
return if (hostmask) {
SpanFormatter.format("%s (%s)", formattedNick, mask)
} else {
formattedNick
}
}
private fun formatNick(sender: String, self: Boolean, private fun formatNick(sender: String, self: Boolean,
highlight: Boolean, showHostmask: Boolean) = highlight: Boolean, showHostmask: Boolean) =
when (appearanceSettings.colorizeNicknames) { when (appearanceSettings.colorizeNicknames) {
......
...@@ -6,6 +6,7 @@ import de.kuschku.quasseldroid_ng.R ...@@ -6,6 +6,7 @@ import de.kuschku.quasseldroid_ng.R
data class AppearanceSettings( data class AppearanceSettings(
val showPrefix: ShowPrefixMode = ShowPrefixMode.HIGHEST, val showPrefix: ShowPrefixMode = ShowPrefixMode.HIGHEST,
val colorizeNicknames: ColorizeNicknamesMode = ColorizeNicknamesMode.ALL_BUT_MINE, val colorizeNicknames: ColorizeNicknamesMode = ColorizeNicknamesMode.ALL_BUT_MINE,
val inputEnter: InputEnterMode = InputEnterMode.EMOJI,
val colorizeMirc: Boolean = true, val colorizeMirc: Boolean = true,
val useMonospace: Boolean = false, val useMonospace: Boolean = false,
val showSeconds: Boolean = false, val showSeconds: Boolean = false,
...@@ -17,13 +18,33 @@ data class AppearanceSettings( ...@@ -17,13 +18,33 @@ data class AppearanceSettings(
enum class ColorizeNicknamesMode { enum class ColorizeNicknamesMode {
ALL, ALL,
ALL_BUT_MINE, ALL_BUT_MINE,
NONE NONE;
companion object {
private val map = values().associateBy { it.name }
fun of(name: String) = map[name]
}
}
enum class InputEnterMode {
EMOJI,
SEND;
companion object {
private val map = values().associateBy { it.name }
fun of(name: String) = map[name]
}
} }
enum class ShowPrefixMode { enum class ShowPrefixMode {
ALL, ALL,
HIGHEST, HIGHEST,
NONE NONE;
companion object {
private val map = values().associateBy { it.name }
fun of(name: String) = map[name]
}
} }
enum class Theme(@StyleRes val style: Int) { enum class Theme(@StyleRes val style: Int) {
...@@ -33,7 +54,12 @@ data class AppearanceSettings( ...@@ -33,7 +54,12 @@ data class AppearanceSettings(
SOLARIZED_LIGHT(R.style.Theme_ChatTheme_Solarized_Light), SOLARIZED_LIGHT(R.style.Theme_ChatTheme_Solarized_Light),
SOLARIZED_DARK(R.style.Theme_ChatTheme_Solarized_Dark), SOLARIZED_DARK(R.style.Theme_ChatTheme_Solarized_Dark),
GRUVBOX_LIGHT(R.style.Theme_ChatTheme_Gruvbox_Light), GRUVBOX_LIGHT(R.style.Theme_ChatTheme_Gruvbox_Light),
GRUVBOX_DARK(R.style.Theme_ChatTheme_Gruvbox_Dark) GRUVBOX_DARK(R.style.Theme_ChatTheme_Gruvbox_Dark);
companion object {
private val map = values().associateBy { it.name }
fun of(name: String) = map[name]
}
} }
companion object { companion object {
......
...@@ -8,12 +8,12 @@ import de.kuschku.quasseldroid_ng.util.helper.sharedPreferences ...@@ -8,12 +8,12 @@ import de.kuschku.quasseldroid_ng.util.helper.sharedPreferences
object Settings { object Settings {
fun appearance(context: Context) = context.sharedPreferences { fun appearance(context: Context) = context.sharedPreferences {
AppearanceSettings( AppearanceSettings(
theme = Theme.valueOf( theme = Theme.of(
getString( getString(
context.getString(R.string.preference_theme_key), context.getString(R.string.preference_theme_key),
AppearanceSettings.DEFAULT.theme.name null
) )
), ) ?: AppearanceSettings.DEFAULT.theme,
useMonospace = getBoolean( useMonospace = getBoolean(
context.getString(R.string.preference_monospace_key), context.getString(R.string.preference_monospace_key),
AppearanceSettings.DEFAULT.useMonospace AppearanceSettings.DEFAULT.useMonospace
...@@ -26,18 +26,24 @@ object Settings { ...@@ -26,18 +26,24 @@ object Settings {
context.getString(R.string.preference_use_24h_clock_key), context.getString(R.string.preference_use_24h_clock_key),
AppearanceSettings.DEFAULT.use24hClock AppearanceSettings.DEFAULT.use24hClock
), ),
showPrefix = ShowPrefixMode.valueOf( showPrefix = ShowPrefixMode.of(
getString( getString(
context.getString(R.string.preference_show_prefix_key), context.getString(R.string.preference_show_prefix_key),
AppearanceSettings.DEFAULT.showPrefix.name null
) )
), ) ?: AppearanceSettings.DEFAULT.showPrefix,
colorizeNicknames = ColorizeNicknamesMode.valueOf( colorizeNicknames = ColorizeNicknamesMode.of(
getString( getString(
context.getString(R.string.preference_colorize_nicknames_key), context.getString(R.string.preference_colorize_nicknames_key),
AppearanceSettings.DEFAULT.colorizeNicknames.name null
) )
), ) ?: AppearanceSettings.DEFAULT.colorizeNicknames,
inputEnter = InputEnterMode.of(
getString(
context.getString(R.string.preference_input_enter_key),
null
)
) ?: AppearanceSettings.DEFAULT.inputEnter,
colorizeMirc = getBoolean( colorizeMirc = getBoolean(
context.getString(R.string.preference_colorize_mirc_key), context.getString(R.string.preference_colorize_mirc_key),
AppearanceSettings.DEFAULT.colorizeMirc AppearanceSettings.DEFAULT.colorizeMirc
......
package de.kuschku.quasseldroid_ng.util.helper
private class DelimitedRangesSequence(
private val input: CharSequence,
private val startIndex: Int,
private val limit: Int,
private val getNextMatch: CharSequence.(Int) -> Pair<Int, Int>?
) : Sequence<IntRange> {
override fun iterator(): Iterator<IntRange> = object : Iterator<IntRange> {
var nextState: Int = -1 // -1 for unknown, 0 for done, 1 for continue
var currentStartIndex: Int = startIndex.coerceIn(0, input.length)
var nextSearchIndex: Int = currentStartIndex
var nextItem: IntRange? = null
var counter: Int = 0
private fun calcNext() {
if (nextSearchIndex < 0) {
nextState = 0
nextItem = null
} else {
if (limit > 0 && ++counter >= limit || nextSearchIndex > input.length) {
nextItem = currentStartIndex..input.lastIndex
nextSearchIndex = -1
} else {
val match = input.getNextMatch(nextSearchIndex)
if (match == null) {
nextItem = currentStartIndex..input.lastIndex
nextSearchIndex = -1
} else {
val (index, length) = match
nextItem = currentStartIndex..index - 1
currentStartIndex = index + length
nextSearchIndex = currentStartIndex + if (length == 0) 1 else 0
}
}
nextState = 1
}
}
override fun next(): IntRange {
if (nextState == -1)
calcNext()
if (nextState == 0)
throw NoSuchElementException()
val result = nextItem as IntRange
// Clean next to avoid keeping reference on yielded instance
nextItem = null
nextState = -1
return result
}
override fun hasNext(): Boolean {
if (nextState == -1)
calcNext()
return nextState == 1
}
}
}
internal fun CharSequence.regionMatchesImpl(thisOffset: Int, other: CharSequence, otherOffset: Int,
length: Int, ignoreCase: Boolean): Boolean {
if ((otherOffset < 0) || (thisOffset < 0) || (thisOffset > this.length - length)
|| (otherOffset > other.length - length)) {
return false
}
for (index in 0 until length) {
if (!this[thisOffset + index].equals(other[otherOffset + index], ignoreCase))
return false
}
return true
}
private fun CharSequence.findAnyOf(strings: Collection<String>, startIndex: Int,
ignoreCase: Boolean, last: Boolean): Pair<Int, String>? {
if (!ignoreCase && strings.size == 1) {
val string = strings.single()
val index = if (!last) indexOf(string, startIndex) else lastIndexOf(string, startIndex)
return if (index < 0) null else index to string
}
val indices = if (!last) startIndex.coerceAtLeast(0)..length else startIndex.coerceAtMost(
lastIndex
) downTo 0
if (this is String) {
for (index in indices) {
val matchingString = strings.firstOrNull {
it.regionMatches(
0, this, index, it.length, ignoreCase
)
}
if (matchingString != null)
return index to matchingString
}
} else {
for (index in indices) {
val matchingString = strings.firstOrNull {
it.regionMatchesImpl(
0, this, index, it.length, ignoreCase
)
}
if (matchingString != null)
return index to matchingString
}
}
return null
}
private fun CharSequence.rangesDelimitedBy(delimiters: Array<out String>, startIndex: Int = 0,
ignoreCase: Boolean = false,
limit: Int = 0): Sequence<IntRange> {
require(limit >= 0, { "Limit must be non-negative, but was $limit." })
val delimitersList = delimiters.asList()
return DelimitedRangesSequence(
this, startIndex, limit, { startIndex ->
findAnyOf(
delimitersList, startIndex, ignoreCase = ignoreCase, last = false
)?.let { it.first to it.second.length }
})
}
fun CharSequence.splitToSequence(vararg delimiters: String, ignoreCase: Boolean = false,
limit: Int = 0): Sequence<CharSequence> =
rangesDelimitedBy(delimiters, ignoreCase = ignoreCase, limit = limit).map { subSequence(it) }
fun CharSequence.lineSequence(): Sequence<CharSequence> = splitToSequence("\r\n", "\n", "\r")
\ No newline at end of file
...@@ -251,6 +251,10 @@ class IrcFormatDeserializer(private val context: Context) { ...@@ -251,6 +251,10 @@ class IrcFormatDeserializer(private val context: Context) {
if (colorize) color.apply(plainText, plainText.length) if (colorize) color.apply(plainText, plainText.length)
color = null color = null
} }
if (hexColor != null) {
if (colorize) hexColor.apply(plainText, plainText.length)
hexColor = null
}
} }
else -> { else -> {
// Just append it, if it’s not special // Just append it, if it’s not special
......
...@@ -18,20 +18,20 @@ object IrcUserUtils { ...@@ -18,20 +18,20 @@ object IrcUserUtils {
fun user(hostmask: String): String { fun user(hostmask: String): String {
return hostmask.substring( return hostmask.substring(
hostmask.lastIndex('!', hostmask.lastIndex('@')) ?: 0, (hostmask.lastIndex('!', hostmask.lastIndex('@')) ?: -1) + 1,
hostmask.lastIndex('@') ?: hostmask.length hostmask.lastIndex('@') ?: hostmask.length
) )
} }
fun host(hostmask: String): String { fun host(hostmask: String): String {
return hostmask.substring( return hostmask.substring(
hostmask.lastIndex('@') ?: 0 (hostmask.lastIndex('@') ?: -1) + 1
) )
} }
fun mask(hostmask: String): String { fun mask(hostmask: String): String {
return hostmask.substring( return hostmask.substring(
hostmask.lastIndex('!', hostmask.lastIndex('@')) ?: 0 (hostmask.lastIndex('!', hostmask.lastIndex('@')) ?: -1) + 1
) )
} }
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
android:background="@android:color/transparent" android:background="@android:color/transparent"
android:gravity="center_vertical" android:gravity="center_vertical"
android:hint="@string/label_placeholder" android:hint="@string/label_placeholder"
android:imeOptions="actionSend|flagNoEnterAction|flagNoExtractUi" android:imeOptions="flagNoExtractUi"
android:inputType="textCapSentences|textAutoCorrect|textShortMessage" android:inputType="textCapSentences|textAutoCorrect|textShortMessage"
android:minHeight="?actionBarSize" android:minHeight="?actionBarSize"
android:paddingBottom="8dp" android:paddingBottom="8dp"
......
...@@ -76,6 +76,19 @@ ...@@ -76,6 +76,19 @@
<item>NONE</item> <item>NONE</item>
</string-array> </string-array>
<string name="preference_input_enter_key" translatable="false">input_enter</string>
<string name="preference_input_enter_title">Enter key on keyboard</string>
<string name="preference_input_enter_entry_emoji">Emoji</string>
<string name="preference_input_enter_entry_send">Send</string>
<string-array name="preference_input_enter_entries">
<item>@string/preference_input_enter_entry_emoji</item>
<item>@string/preference_input_enter_entry_send</item>
</string-array>
<string-array name="preference_input_enter_entryvalues">
<item>EMOJI</item>
<item>SEND</item>
</string-array>
<string name="preference_hostmask_key" translatable="false">hostmask</string> <string name="preference_hostmask_key" translatable="false">hostmask</string>
<string name="preference_hostmask_title">Show Hostmask</string> <string name="preference_hostmask_title">Show Hostmask</string>
<string name="preference_hostmask_summary">Display the full nick!ident@host in messages</string> <string name="preference_hostmask_summary">Display the full nick!ident@host in messages</string>
......
...@@ -37,6 +37,13 @@ ...@@ -37,6 +37,13 @@
android:key="@string/preference_colorize_nicknames_key" android:key="@string/preference_colorize_nicknames_key"
android:title="@string/preference_colorize_nicknames_title" /> android:title="@string/preference_colorize_nicknames_title" />
<DropDownPreference
android:defaultValue="EMOJI"
android:entries="@array/preference_input_enter_entries"
android:entryValues="@array/preference_input_enter_entryvalues"
android:key="@string/preference_input_enter_key"
android:title="@string/preference_input_enter_title" />
<DropDownPreference <DropDownPreference
android:defaultValue="HIGHEST" android:defaultValue="HIGHEST"
android:entries="@array/preference_show_prefix_entries" android:entries="@array/preference_show_prefix_entries"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment