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 ceb44aee9782475983ddb86f5c593ebd5520efe7..8552ed8d6a65e920bd23f536ef9e015854b5423b 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 @@ -26,8 +26,8 @@ import de.kuschku.libquassel.protocol.Message_Type import de.kuschku.libquassel.protocol.message.HandshakeMessage import de.kuschku.libquassel.quassel.syncables.interfaces.IAliasManager import de.kuschku.libquassel.session.ConnectionState -import de.kuschku.libquassel.util.and -import de.kuschku.libquassel.util.or +import de.kuschku.libquassel.util.flag.and +import de.kuschku.libquassel.util.flag.or import de.kuschku.quasseldroid.Keys import de.kuschku.quasseldroid.R import de.kuschku.quasseldroid.persistence.AccountDatabase @@ -41,6 +41,7 @@ import de.kuschku.quasseldroid.util.helper.editCommit import de.kuschku.quasseldroid.util.helper.invoke import de.kuschku.quasseldroid.util.helper.retint import de.kuschku.quasseldroid.util.helper.toLiveData +import de.kuschku.quasseldroid.util.irc.format.IrcFormatDeserializer import de.kuschku.quasseldroid.util.service.ServiceBoundActivity import de.kuschku.quasseldroid.util.ui.MaterialContentLoadingProgressBar import de.kuschku.quasseldroid.viewmodel.data.AutoCompleteItem @@ -76,6 +77,9 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc @Inject lateinit var messageSettings: MessageSettings + @Inject + lateinit var ircFormatDeserializer: IrcFormatDeserializer + private lateinit var editor: Editor private val panelSlideListener: SlidingUpPanelLayout.PanelSlideListener = object : @@ -117,8 +121,10 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc findViewById(R.id.autocomplete_list_expanded) ), findViewById(R.id.formatting_toolbar), + ircFormatDeserializer, appearanceSettings, autoCompleteSettings, + messageSettings, { lines -> viewModel.session { sessionOptional -> val session = sessionOptional.orNull() diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/ToolbarFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/ToolbarFragment.kt index 6c205aea3ff7980520a38d18def36be1934ea705..ca7cd350eb3054c8c73b8bfcbefe4f66929c440e 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/ToolbarFragment.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/ToolbarFragment.kt @@ -11,7 +11,7 @@ import butterknife.BindView import butterknife.ButterKnife import de.kuschku.libquassel.protocol.Buffer_Type import de.kuschku.libquassel.quassel.BufferInfo -import de.kuschku.libquassel.util.hasFlag +import de.kuschku.libquassel.util.flag.hasFlag import de.kuschku.libquassel.util.helpers.value import de.kuschku.quasseldroid.R import de.kuschku.quasseldroid.settings.AppearanceSettings diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferListAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferListAdapter.kt index cd6b7773e57ddd3ded7056b25e3c317d08aa9565..271f9c5cf8b71b0310eb94bd3ddcdf6d70805d6e 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferListAdapter.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/buffers/BufferListAdapter.kt @@ -18,7 +18,7 @@ import de.kuschku.libquassel.protocol.Buffer_Activity import de.kuschku.libquassel.protocol.Buffer_Type import de.kuschku.libquassel.protocol.NetworkId import de.kuschku.libquassel.quassel.BufferInfo -import de.kuschku.libquassel.util.hasFlag +import de.kuschku.libquassel.util.flag.hasFlag import de.kuschku.quasseldroid.R import de.kuschku.quasseldroid.util.helper.* import de.kuschku.quasseldroid.viewmodel.data.BufferListItem 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 857ca41fb3ae0285a9e9c3ce39b6734793a1976b..a568631db3821244daf3375d9288d6c447004bb1 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 @@ -13,9 +13,9 @@ import de.kuschku.libquassel.protocol.Buffer_Activity import de.kuschku.libquassel.protocol.Buffer_Type import de.kuschku.libquassel.protocol.Message_Type import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork -import de.kuschku.libquassel.util.hasFlag +import de.kuschku.libquassel.util.flag.hasFlag +import de.kuschku.libquassel.util.flag.minus import de.kuschku.libquassel.util.helpers.value -import de.kuschku.libquassel.util.minus import de.kuschku.quasseldroid.R import de.kuschku.quasseldroid.persistence.QuasselDatabase import de.kuschku.quasseldroid.settings.AppearanceSettings diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/AutoCompleteAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/AutoCompleteAdapter.kt index 0f1903e0098b6fffe171b6d3ec47bb86d9711d38..0b030e7193dae2f660c127db1507dcaaa683d79f 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/AutoCompleteAdapter.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/AutoCompleteAdapter.kt @@ -11,16 +11,21 @@ import android.widget.ImageView import android.widget.TextView import butterknife.BindView import butterknife.ButterKnife +import com.bumptech.glide.request.RequestOptions +import de.kuschku.quasseldroid.GlideApp import de.kuschku.quasseldroid.R +import de.kuschku.quasseldroid.settings.MessageSettings import de.kuschku.quasseldroid.ui.chat.nicks.NickListAdapter.Companion.VIEWTYPE_AWAY import de.kuschku.quasseldroid.util.helper.getDrawableCompat import de.kuschku.quasseldroid.util.helper.styledAttributes import de.kuschku.quasseldroid.util.helper.tint import de.kuschku.quasseldroid.util.helper.visibleIf +import de.kuschku.quasseldroid.util.ui.SpanFormatter import de.kuschku.quasseldroid.viewmodel.data.AutoCompleteItem import de.kuschku.quasseldroid.viewmodel.data.BufferStatus class AutoCompleteAdapter( + private val messageSettings: MessageSettings, private val clickListener: ((String) -> Unit)? = null ) : ListAdapter<AutoCompleteItem, AutoCompleteAdapter.AutoCompleteViewHolder>( object : DiffUtil.ItemCallback<AutoCompleteItem>() { @@ -37,15 +42,21 @@ class AutoCompleteAdapter( .inflate(R.layout.widget_buffer, parent, false), clickListener = clickListener ) - VIEWTYPE_NICK_ACTIVE, VIEWTYPE_NICK_AWAY -> AutoCompleteViewHolder.NickViewHolder( - LayoutInflater.from(parent.context).inflate( - when (viewType) { - VIEWTYPE_AWAY -> R.layout.widget_nick_away - else -> R.layout.widget_nick - }, parent, false - ), - clickListener = clickListener - ) + VIEWTYPE_NICK_ACTIVE, VIEWTYPE_NICK_AWAY -> { + val holder = AutoCompleteViewHolder.NickViewHolder( + LayoutInflater.from(parent.context).inflate( + when (viewType) { + VIEWTYPE_AWAY -> R.layout.widget_nick_away + else -> R.layout.widget_nick + }, parent, false + ), + clickListener = clickListener + ) + + holder.avatar.visibleIf(messageSettings.showAvatars) + + holder + } else -> throw IllegalArgumentException( "Invoked with wrong item type" ) @@ -75,11 +86,8 @@ class AutoCompleteAdapter( itemView: View, private val clickListener: ((String) -> Unit)? = null ) : AutoCompleteViewHolder(itemView) { - @BindView(R.id.modesContainer) - lateinit var modesContainer: View - - @BindView(R.id.modes) - lateinit var modes: TextView + @BindView(R.id.avatar) + lateinit var avatar: ImageView @BindView(R.id.nick) lateinit var nick: TextView @@ -101,11 +109,14 @@ class AutoCompleteAdapter( fun bindImpl(data: AutoCompleteItem.UserItem) { value = data.name - nick.text = data.nick - modes.text = data.modes + nick.text = SpanFormatter.format("%s%s", data.modes, data.displayNick ?: data.nick) realname.text = data.realname - modes.visibleIf(data.modes.isNotBlank()) + GlideApp.with(itemView) + .load(data.avatarUrl) + .apply(RequestOptions.circleCropTransform()) + .placeholder(data.fallbackDrawable) + .into(avatar) } } diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/Editor.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/Editor.kt index 2a938902e02adf613104372eaaba6ca99a45dc73..40034a1b2fef3d7d06602180a3ffd3373127ccf0 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/Editor.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/input/Editor.kt @@ -2,6 +2,7 @@ package de.kuschku.quasseldroid.ui.chat.input import android.arch.lifecycle.LiveData import android.arch.lifecycle.Observer +import android.graphics.Typeface import android.support.annotation.ColorInt import android.support.annotation.StringRes import android.support.v4.app.FragmentActivity @@ -9,18 +10,25 @@ import android.support.v7.app.AppCompatActivity import android.support.v7.widget.* import android.text.Editable import android.text.InputType +import android.text.SpannableString import android.text.TextWatcher +import android.text.style.ForegroundColorSpan +import android.text.style.StyleSpan import android.view.* import android.view.inputmethod.EditorInfo import butterknife.BindView import butterknife.ButterKnife +import de.kuschku.libquassel.util.IrcUserUtils 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.ui.chat.ChatActivity import de.kuschku.quasseldroid.util.helper.* +import de.kuschku.quasseldroid.util.irc.format.IrcFormatDeserializer import de.kuschku.quasseldroid.util.ui.ColorChooserDialog import de.kuschku.quasseldroid.util.ui.EditTextSelectionChange +import de.kuschku.quasseldroid.util.ui.TextDrawable import de.kuschku.quasseldroid.viewmodel.data.AutoCompleteItem import io.reactivex.Observable import io.reactivex.subjects.BehaviorSubject @@ -37,9 +45,12 @@ class Editor( tabComplete: AppCompatImageButton, autoCompleteLists: List<RecyclerView>, formattingToolbar: Toolbar, + // Helpers + private val ircFormatDeserializer: IrcFormatDeserializer, // Settings private val appearanceSettings: AppearanceSettings, private val autoCompleteSettings: AutoCompleteSettings, + private val messageSettings: MessageSettings, // Listeners private val sendCallback: (Sequence<Pair<CharSequence, String>>) -> Unit, private val panelStateCallback: (Boolean) -> Unit @@ -52,6 +63,17 @@ class Editor( else -> false } + private val senderColors = activity.theme.styledAttributes( + R.attr.senderColor0, R.attr.senderColor1, R.attr.senderColor2, R.attr.senderColor3, + R.attr.senderColor4, R.attr.senderColor5, R.attr.senderColor6, R.attr.senderColor7, + R.attr.senderColor8, R.attr.senderColor9, R.attr.senderColorA, R.attr.senderColorB, + R.attr.senderColorC, R.attr.senderColorD, R.attr.senderColorE, R.attr.senderColorF + ) { + IntArray(16) { + getColor(it, 0) + } + } + private val lastWord = BehaviorSubject.createDefault(Pair("", IntRange.EMPTY)) private val textWatcher = object : TextWatcher { override fun afterTextChanged(s: Editable?) { @@ -137,6 +159,7 @@ class Editor( }.fold(0, Int::or) val autocompleteAdapter = AutoCompleteAdapter( + messageSettings, // This is still broken when mixing tab complete and UI auto complete formatHandler::autoComplete ) @@ -146,7 +169,49 @@ class Editor( val shouldShowResults = (autoCompleteSettings.auto && query.length >= 3) || (autoCompleteSettings.prefix && query.startsWith('@')) || (autoCompleteSettings.prefix && query.startsWith('#')) - autocompleteAdapter.submitList(if (shouldShowResults) it?.second.orEmpty() else emptyList()) + val list = if (shouldShowResults) it?.second.orEmpty() else emptyList() + autocompleteAdapter.submitList(list.map { + if (it is AutoCompleteItem.UserItem) { + val nickName = it.nick + val senderColorIndex = IrcUserUtils.senderColor(nickName) + val initial = nickName.trimStart('-', '_', '[', ']', '{', '}', '|', '`', '^', '.', '\\') + .firstOrNull()?.toUpperCase().toString() + val senderColor = senderColors[senderColorIndex] + + fun formatNick(nick: CharSequence): CharSequence { + val spannableString = SpannableString(nick) + spannableString.setSpan( + ForegroundColorSpan(senderColor), + 0, + nick.length, + SpannableString.SPAN_INCLUSIVE_EXCLUSIVE + ) + spannableString.setSpan( + StyleSpan(Typeface.BOLD), + 0, + nick.length, + SpannableString.SPAN_INCLUSIVE_EXCLUSIVE + ) + return spannableString + } + + it.copy( + displayNick = formatNick(it.nick), + fallbackDrawable = TextDrawable.builder().buildRound(initial, senderColor), + modes = when (messageSettings.showPrefix) { + MessageSettings.ShowPrefixMode.ALL -> + it.modes + else -> + it.modes.substring(0, Math.min(it.modes.length, 1)) + }, + realname = ircFormatDeserializer.formatString( + activity, it.realname.toString(), messageSettings.colorizeMirc + ) + ) + } else { + it + } + }) }) if (autoCompleteSettings.prefix || autoCompleteSettings.auto) { diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageAdapter.kt index a336d0f2506e654d6dc1028362304d215ee9639e..191abda65561250227084ce21d69f34b6c33dc9e 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageAdapter.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/MessageAdapter.kt @@ -17,7 +17,7 @@ import de.kuschku.libquassel.protocol.Message_Flag import de.kuschku.libquassel.protocol.Message_Flags import de.kuschku.libquassel.protocol.Message_Type import de.kuschku.libquassel.protocol.Message_Types -import de.kuschku.libquassel.util.hasFlag +import de.kuschku.libquassel.util.flag.hasFlag import de.kuschku.quasseldroid.GlideApp import de.kuschku.quasseldroid.R import de.kuschku.quasseldroid.persistence.QuasselDatabase diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/QuasselMessageRenderer.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/QuasselMessageRenderer.kt index b735422fcaf8c42cb0779d7ef3746d30b81a7cc6..53a8f9e2a9bcb8bdfb53449477200931d9d7aa6a 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/QuasselMessageRenderer.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/messages/QuasselMessageRenderer.kt @@ -11,7 +11,8 @@ import android.util.TypedValue import de.kuschku.libquassel.protocol.Message.MessageType.* import de.kuschku.libquassel.protocol.Message_Flag import de.kuschku.libquassel.protocol.Message_Type -import de.kuschku.libquassel.util.hasFlag +import de.kuschku.libquassel.util.IrcUserUtils +import de.kuschku.libquassel.util.flag.hasFlag import de.kuschku.libquassel.util.irc.HostmaskHelper import de.kuschku.quasseldroid.R import de.kuschku.quasseldroid.persistence.QuasselDatabase @@ -21,7 +22,6 @@ import de.kuschku.quasseldroid.settings.MessageSettings.ShowPrefixMode import de.kuschku.quasseldroid.util.helper.styledAttributes import de.kuschku.quasseldroid.util.helper.visibleIf import de.kuschku.quasseldroid.util.irc.format.ContentFormatter -import de.kuschku.quasseldroid.util.quassel.IrcUserUtils import de.kuschku.quasseldroid.util.ui.SpanFormatter import de.kuschku.quasseldroid.util.ui.TextDrawable import de.kuschku.quasseldroid.viewmodel.data.FormattedMessage @@ -420,7 +420,7 @@ class QuasselMessageRenderer @Inject constructor( if (colorize) { val senderColor = IrcUserUtils.senderColor(nick) spannableString.setSpan( - ForegroundColorSpan(senderColors[senderColor % senderColors.size]), + ForegroundColorSpan(senderColors[(senderColor + senderColors.size) % senderColors.size]), 0, nick.length, SpannableString.SPAN_INCLUSIVE_EXCLUSIVE diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/nicks/NickListAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/nicks/NickListAdapter.kt index 4090fe00aa826849d638ef483ee87e81edd463e5..4f07b965b39b47b1f6a5e5ea785b1e52456c9272 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/nicks/NickListAdapter.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/nicks/NickListAdapter.kt @@ -6,14 +6,20 @@ import android.support.v7.widget.RecyclerView import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.ImageView import android.widget.TextView import butterknife.BindView import butterknife.ButterKnife +import com.bumptech.glide.request.RequestOptions +import de.kuschku.quasseldroid.GlideApp import de.kuschku.quasseldroid.R +import de.kuschku.quasseldroid.settings.MessageSettings import de.kuschku.quasseldroid.util.helper.visibleIf +import de.kuschku.quasseldroid.util.ui.SpanFormatter import de.kuschku.quasseldroid.viewmodel.data.IrcUserItem class NickListAdapter( + private val messageSettings: MessageSettings, private val clickListener: ((String) -> Unit)? = null ) : ListAdapter<IrcUserItem, NickListAdapter.NickViewHolder>( object : DiffUtil.ItemCallback<IrcUserItem>() { @@ -23,8 +29,8 @@ class NickListAdapter( override fun areContentsTheSame(oldItem: IrcUserItem?, newItem: IrcUserItem?) = oldItem == newItem }) { - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = - NickViewHolder( + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NickViewHolder { + val holder = NickViewHolder( LayoutInflater.from(parent.context).inflate( when (viewType) { VIEWTYPE_AWAY -> R.layout.widget_nick_away @@ -34,6 +40,13 @@ class NickListAdapter( clickListener = clickListener ) + holder.avatar.visibleIf(messageSettings.showAvatars) + + return holder + } + + operator fun get(position: Int): IrcUserItem? = super.getItem(position) + override fun onBindViewHolder(holder: NickViewHolder, position: Int) = holder.bind(getItem(position)) @@ -47,11 +60,8 @@ class NickListAdapter( itemView: View, private val clickListener: ((String) -> Unit)? = null ) : RecyclerView.ViewHolder(itemView) { - @BindView(R.id.modesContainer) - lateinit var modesContainer: View - - @BindView(R.id.modes) - lateinit var modes: TextView + @BindView(R.id.avatar) + lateinit var avatar: ImageView @BindView(R.id.nick) lateinit var nick: TextView @@ -73,11 +83,15 @@ class NickListAdapter( fun bind(data: IrcUserItem) { user = data.nick - nick.text = data.nick - modes.text = data.modes + nick.text = SpanFormatter.format("%s%s", data.modes, data.displayNick ?: data.nick) realname.text = data.realname - modes.visibleIf(data.modes.isNotBlank()) + + GlideApp.with(itemView) + .load(data.avatarUrl) + .apply(RequestOptions.circleCropTransform()) + .placeholder(data.fallbackDrawable) + .into(avatar) } } diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/nicks/NickListFragment.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/nicks/NickListFragment.kt index bcbef6f3986fc551c6f0c574c34cf9d009b3156d..4b399d4782f59867fd29f8374542d3767429911a 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/chat/nicks/NickListFragment.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/chat/nicks/NickListFragment.kt @@ -2,27 +2,39 @@ package de.kuschku.quasseldroid.ui.chat.nicks import android.arch.lifecycle.Observer import android.content.Intent +import android.graphics.Typeface import android.os.Bundle import android.support.v7.widget.DefaultItemAnimator import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.RecyclerView +import android.text.SpannableString +import android.text.style.ForegroundColorSpan +import android.text.style.StyleSpan import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import butterknife.BindView import butterknife.ButterKnife +import com.bumptech.glide.Glide +import com.bumptech.glide.ListPreloader +import com.bumptech.glide.integration.recyclerview.RecyclerViewPreloader +import com.bumptech.glide.util.FixedPreloadSizeProvider import de.kuschku.libquassel.quassel.BufferInfo +import de.kuschku.libquassel.util.IrcUserUtils import de.kuschku.libquassel.util.helpers.value import de.kuschku.libquassel.util.irc.IrcCaseMappers +import de.kuschku.quasseldroid.GlideApp import de.kuschku.quasseldroid.R import de.kuschku.quasseldroid.settings.AppearanceSettings import de.kuschku.quasseldroid.settings.MessageSettings import de.kuschku.quasseldroid.ui.chat.info.InfoActivity import de.kuschku.quasseldroid.ui.chat.info.InfoDescriptor import de.kuschku.quasseldroid.ui.chat.info.InfoType +import de.kuschku.quasseldroid.util.helper.styledAttributes import de.kuschku.quasseldroid.util.helper.toLiveData import de.kuschku.quasseldroid.util.irc.format.IrcFormatDeserializer import de.kuschku.quasseldroid.util.service.ServiceBoundFragment +import de.kuschku.quasseldroid.util.ui.TextDrawable import javax.inject.Inject class NickListFragment : ServiceBoundFragment() { @@ -43,15 +55,54 @@ class NickListFragment : ServiceBoundFragment() { val view = inflater.inflate(R.layout.fragment_nick_list, container, false) ButterKnife.bind(this, view) - val nickListAdapter = NickListAdapter(clickListener) + val nickListAdapter = NickListAdapter(messageSettings, clickListener) nickList.adapter = nickListAdapter nickList.layoutManager = object : LinearLayoutManager(context) { override fun supportsPredictiveItemAnimations() = false } nickList.itemAnimator = DefaultItemAnimator() + + + val senderColors = requireContext().theme.styledAttributes( + R.attr.senderColor0, R.attr.senderColor1, R.attr.senderColor2, R.attr.senderColor3, + R.attr.senderColor4, R.attr.senderColor5, R.attr.senderColor6, R.attr.senderColor7, + R.attr.senderColor8, R.attr.senderColor9, R.attr.senderColorA, R.attr.senderColorB, + R.attr.senderColorC, R.attr.senderColorD, R.attr.senderColorE, R.attr.senderColorF + ) { + IntArray(16) { + getColor(it, 0) + } + } + viewModel.nickData.map { it.map { + val nickName = it.nick + val senderColorIndex = IrcUserUtils.senderColor(nickName) + val initial = nickName.trimStart('-', '_', '[', ']', '{', '}', '|', '`', '^', '.', '\\') + .firstOrNull()?.toUpperCase().toString() + val senderColor = senderColors[senderColorIndex] + + + fun formatNick(nick: CharSequence): CharSequence { + val spannableString = SpannableString(nick) + spannableString.setSpan( + ForegroundColorSpan(senderColor), + 0, + nick.length, + SpannableString.SPAN_INCLUSIVE_EXCLUSIVE + ) + spannableString.setSpan( + StyleSpan(Typeface.BOLD), + 0, + nick.length, + SpannableString.SPAN_INCLUSIVE_EXCLUSIVE + ) + return spannableString + } + it.copy( + displayNick = formatNick(it.nick), + fallbackDrawable = TextDrawable.builder().buildRound(initial, senderColor), modes = when (messageSettings.showPrefix) { MessageSettings.ShowPrefixMode.ALL -> it.modes @@ -73,6 +124,23 @@ class NickListFragment : ServiceBoundFragment() { nickList.layoutManager.onRestoreInstanceState(getParcelable(KEY_STATE_LIST)) } + val avatar_size = resources.getDimensionPixelSize(R.dimen.avatar_size) + + val sizeProvider = FixedPreloadSizeProvider<String>(avatar_size, avatar_size) + + val preloadModelProvider = object : ListPreloader.PreloadModelProvider<String> { + override fun getPreloadItems(position: Int) = nickListAdapter[position]?.avatarUrl?.let { + mutableListOf(it) + } ?: mutableListOf() + + override fun getPreloadRequestBuilder(item: String) = + GlideApp.with(this@NickListFragment).load(item).override(avatar_size) + } + + val preloader = RecyclerViewPreloader(Glide.with(this), preloadModelProvider, sizeProvider, 10) + + nickList.addOnScrollListener(preloader) + return view } diff --git a/app/src/main/res/layout/fragment_nick_list.xml b/app/src/main/res/layout/fragment_nick_list.xml index d1e0c34a75b97d59d1b65b192172eebf443689b6..58f05b5ebfe6d9f5875126ab19fabadde6cee2c8 100644 --- a/app/src/main/res/layout/fragment_nick_list.xml +++ b/app/src/main/res/layout/fragment_nick_list.xml @@ -6,4 +6,5 @@ android:background="?attr/colorBackground" android:clipToPadding="false" android:fitsSystemWindows="true" + tools:listitem="@layout/widget_nick" tools:showIn="@layout/activity_main" /> diff --git a/app/src/main/res/layout/widget_chatmessage_plain.xml b/app/src/main/res/layout/widget_chatmessage_plain.xml index 38c87d96b3016e89190f5018f4ad0d8d79782670..85bf7eeb2127a4808cfde220b1e8acb39e9087f5 100644 --- a/app/src/main/res/layout/widget_chatmessage_plain.xml +++ b/app/src/main/res/layout/widget_chatmessage_plain.xml @@ -5,7 +5,8 @@ android:layout_height="wrap_content" android:background="?attr/backgroundMenuItem" android:orientation="vertical" - android:textAppearance="?android:attr/textAppearanceListItemSmall"> + android:textAppearance="?android:attr/textAppearanceListItemSmall" + tools:showIn="@layout/fragment_messages"> <LinearLayout android:layout_width="match_parent" @@ -45,6 +46,7 @@ android:layout_height="@dimen/avatar_size" android:contentDescription="@string/label_avatar" android:visibility="gone" + tools:src="@tools:sample/avatars" tools:visibility="visible" /> </FrameLayout> @@ -105,8 +107,8 @@ android:textColor="?attr/colorForegroundSecondary" android:textStyle="italic" android:visibility="gone" - tools:textSize="11.9sp" tools:text="@sample/messages.json/data/time" + tools:textSize="11.9sp" tools:visibility="visible" /> </LinearLayout> </LinearLayout> diff --git a/app/src/main/res/layout/widget_nick.xml b/app/src/main/res/layout/widget_nick.xml index b54a3aeda52d5552f74b600f590fa7ffd4cd0497..054915a7e9b30cb69d09bd42428817a47d48b5b8 100644 --- a/app/src/main/res/layout/widget_nick.xml +++ b/app/src/main/res/layout/widget_nick.xml @@ -1,72 +1,48 @@ +<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" - android:layout_height="56dp" - android:background="?selectableItemBackground" - android:clickable="true" - android:focusable="true" + android:layout_height="wrap_content" + android:background="?attr/backgroundMenuItem" android:orientation="horizontal" - android:paddingEnd="?listPreferredItemPaddingRight" - android:paddingLeft="?listPreferredItemPaddingLeft" - android:paddingRight="?listPreferredItemPaddingRight" - android:baselineAligned="false" - android:paddingStart="?listPreferredItemPaddingLeft"> + android:paddingBottom="4dp" + android:paddingLeft="16dp" + android:paddingRight="16dp" + android:paddingTop="4dp" + android:textAppearance="?android:attr/textAppearanceListItemSmall" + tools:showIn="@layout/fragment_nick_list"> - <FrameLayout - android:id="@+id/modesContainer" - android:layout_width="wrap_content" - android:layout_height="match_parent" + <ImageView + android:id="@+id/avatar" + android:layout_width="@dimen/avatar_size" + android:layout_height="@dimen/avatar_size" + android:layout_gravity="center_vertical" android:layout_marginEnd="16dp" android:layout_marginRight="16dp" - android:minWidth="40dp"> - - <android.support.v7.widget.AppCompatTextView - android:id="@+id/modes" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - android:layout_marginBottom="8dp" - android:layout_marginTop="8dp" - android:background="@drawable/bg_badge" - android:fontFamily="monospace" - android:gravity="center" - android:minHeight="24dp" - android:minWidth="24dp" - android:textColor="?colorBackground" - android:textSize="12sp" - android:textStyle="bold" - app:backgroundTint="@color/colorAccent" - tools:text="\@" /> - </FrameLayout> + android:contentDescription="@string/label_avatar" + tools:src="@tools:sample/avatars" /> <LinearLayout - android:layout_width="0dp" - android:layout_height="match_parent" - android:layout_weight="1" - android:gravity="center_vertical|start" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" android:orientation="vertical"> <TextView android:id="@+id/nick" android:layout_width="match_parent" android:layout_height="wrap_content" - android:fontFamily="sans-serif-medium" - android:gravity="center_vertical|start" - android:singleLine="true" - android:textColor="?colorTextPrimary" + android:textColor="?attr/colorTextPrimary" android:textSize="13sp" - tools:text="justJanne" /> + tools:text="@sample/messages.json/data/sender" /> <TextView android:id="@+id/realname" android:layout_width="match_parent" android:layout_height="wrap_content" - android:fontFamily="sans-serif" - android:gravity="center_vertical|start" - android:singleLine="true" - android:textColor="?colorTextSecondary" + android:textColor="?attr/colorTextSecondary" android:textSize="12sp" - tools:text="Janne Koschinski: https://kuschku.de/" /> + tools:text="@sample/messages.json/data/sender" + tools:visibility="visible" /> </LinearLayout> </LinearLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/widget_nick_away.xml b/app/src/main/res/layout/widget_nick_away.xml index 276583648b3a4498ed549a67fd6d1c2414d03a7d..8d4c1a90ffbf542cedb1d10e0cea6b152de6d9a0 100644 --- a/app/src/main/res/layout/widget_nick_away.xml +++ b/app/src/main/res/layout/widget_nick_away.xml @@ -1,74 +1,50 @@ +<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" - android:layout_height="56dp" - android:background="?selectableItemBackground" - android:clickable="true" - android:focusable="true" + android:layout_height="wrap_content" + android:background="?attr/backgroundMenuItem" android:orientation="horizontal" - android:paddingEnd="?listPreferredItemPaddingRight" - android:paddingLeft="?listPreferredItemPaddingLeft" - android:paddingRight="?listPreferredItemPaddingRight" - android:baselineAligned="false" - android:paddingStart="?listPreferredItemPaddingLeft"> + android:paddingBottom="4dp" + android:paddingLeft="16dp" + android:paddingRight="16dp" + android:paddingTop="4dp" + android:textAppearance="?android:attr/textAppearanceListItemSmall" + tools:showIn="@layout/fragment_nick_list"> - <FrameLayout - android:id="@+id/modesContainer" - android:layout_width="wrap_content" - android:layout_height="match_parent" + <ImageView + android:id="@+id/avatar" + android:layout_width="@dimen/avatar_size" + android:layout_height="@dimen/avatar_size" + android:layout_gravity="center_vertical" android:layout_marginEnd="16dp" android:layout_marginRight="16dp" - android:minWidth="40dp"> - - <android.support.v7.widget.AppCompatTextView - android:id="@+id/modes" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - android:layout_marginBottom="8dp" - android:layout_marginTop="8dp" - android:background="@drawable/bg_badge" - android:fontFamily="monospace" - android:gravity="center" - android:minHeight="24dp" - android:minWidth="24dp" - android:textColor="?colorBackground" - android:textSize="12sp" - android:textStyle="bold" - app:backgroundTint="@color/colorAccent" - tools:text="\@" /> - </FrameLayout> + android:contentDescription="@string/label_avatar" + tools:src="@tools:sample/avatars" /> <LinearLayout - android:layout_width="0dp" - android:layout_height="match_parent" - android:layout_weight="1" - android:gravity="center_vertical|start" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" android:orientation="vertical"> <TextView android:id="@+id/nick" android:layout_width="match_parent" android:layout_height="wrap_content" - android:fontFamily="sans-serif-medium" - android:gravity="center_vertical|start" - android:singleLine="true" - android:textColor="?colorTextSecondary" + android:textColor="?attr/colorTextSecondary" android:textSize="13sp" android:textStyle="italic" - tools:text="justJanne" /> + tools:text="@sample/messages.json/data/sender" /> <TextView android:id="@+id/realname" android:layout_width="match_parent" android:layout_height="wrap_content" - android:fontFamily="sans-serif" - android:gravity="center_vertical|start" - android:singleLine="true" - android:textColor="?colorTextSecondary" + android:textColor="?attr/colorTextSecondary" android:textSize="12sp" android:textStyle="italic" - tools:text="Janne Koschinski: https://kuschku.de/" /> + tools:text="@sample/messages.json/data/sender" + tools:visibility="visible" /> </LinearLayout> </LinearLayout> \ No newline at end of file diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/Message.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/Message.kt index 6853dc8b464a5f5d2a9ab23fbd8912d2c97fcabd..f628ca91486060038bf3a5f005e110390d63fd07 100644 --- a/lib/src/main/java/de/kuschku/libquassel/protocol/Message.kt +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/Message.kt @@ -1,8 +1,8 @@ package de.kuschku.libquassel.protocol import de.kuschku.libquassel.quassel.BufferInfo -import de.kuschku.libquassel.util.Flag -import de.kuschku.libquassel.util.Flags +import de.kuschku.libquassel.util.flag.Flag +import de.kuschku.libquassel.util.flag.Flags import org.threeten.bp.Instant class Message( @@ -15,7 +15,8 @@ class Message( val senderPrefixes: String, val content: String ) { - enum class MessageType(override val bit: Int) : Flag<MessageType> { + enum class MessageType(override val bit: Int) : + Flag<MessageType> { Plain(0x00001), Notice(0x00002), Action(0x00004), @@ -44,7 +45,8 @@ class Message( } } - enum class MessageFlag(override val bit: Int) : Flag<MessageFlag> { + enum class MessageFlag(override val bit: Int) : + Flag<MessageFlag> { Self(0x01), Highlight(0x02), Redirected(0x04), diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/QTypes.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/QTypes.kt index dd3ec4116f1d21d627df3b501e32fcb0fdff17cd..02865205d0df028af4b2bde1f96d79e87baf11b2 100644 --- a/lib/src/main/java/de/kuschku/libquassel/protocol/QTypes.kt +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/QTypes.kt @@ -5,8 +5,8 @@ import de.kuschku.libquassel.quassel.BufferInfo import de.kuschku.libquassel.quassel.LegacyFeature import de.kuschku.libquassel.quassel.ProtocolFeature import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork -import de.kuschku.libquassel.util.Flags -import de.kuschku.libquassel.util.ShortFlags +import de.kuschku.libquassel.util.flag.Flags +import de.kuschku.libquassel.util.flag.ShortFlags import de.kuschku.libquassel.util.helpers.deserializeString import java.nio.ByteBuffer diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitAckSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitAckSerializer.kt index 69aade656d54d8548ac81f5f9fbf2d6f2666ad58..22e7ee81029abd85c05f77287fbcc033febcc8fe 100644 --- a/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitAckSerializer.kt +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitAckSerializer.kt @@ -1,7 +1,7 @@ package de.kuschku.libquassel.protocol.message import de.kuschku.libquassel.protocol.* -import de.kuschku.libquassel.util.Flags +import de.kuschku.libquassel.util.flag.Flags object ClientInitAckSerializer : HandshakeMessageSerializer<HandshakeMessage.ClientInitAck> { override fun serialize(data: HandshakeMessage.ClientInitAck) = mapOf( diff --git a/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitSerializer.kt b/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitSerializer.kt index 9050cc75055c14ab9492b5c30b274569f6a97e2c..0de96e42721d3afb064dde984978bcbf59ef4eaa 100644 --- a/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitSerializer.kt +++ b/lib/src/main/java/de/kuschku/libquassel/protocol/message/ClientInitSerializer.kt @@ -4,7 +4,7 @@ import de.kuschku.libquassel.protocol.QVariant import de.kuschku.libquassel.protocol.QVariantMap import de.kuschku.libquassel.protocol.Type import de.kuschku.libquassel.protocol.value -import de.kuschku.libquassel.util.Flags +import de.kuschku.libquassel.util.flag.Flags object ClientInitSerializer : HandshakeMessageSerializer<HandshakeMessage.ClientInit> { override fun serialize(data: HandshakeMessage.ClientInit) = mapOf( diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/BufferInfo.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/BufferInfo.kt index b85e7ac3a76452d44c0510e2b9fe47e5320e47a6..c5fcf18b33bcd161a53c8f756f65ee96ddbf82c7 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/BufferInfo.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/BufferInfo.kt @@ -1,10 +1,10 @@ package de.kuschku.libquassel.quassel import de.kuschku.libquassel.protocol.Buffer_Types -import de.kuschku.libquassel.util.Flag -import de.kuschku.libquassel.util.Flags -import de.kuschku.libquassel.util.ShortFlag -import de.kuschku.libquassel.util.ShortFlags +import de.kuschku.libquassel.util.flag.Flag +import de.kuschku.libquassel.util.flag.Flags +import de.kuschku.libquassel.util.flag.ShortFlag +import de.kuschku.libquassel.util.flag.ShortFlags data class BufferInfo( var bufferId: Int, diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/LegacyFeature.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/LegacyFeature.kt index dd026c7569dcb7f12a6ae6c262453d5f2e0a8415..9243d109fefcd94a1ed43f0193affaa744063508 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/LegacyFeature.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/LegacyFeature.kt @@ -1,7 +1,7 @@ package de.kuschku.libquassel.quassel -import de.kuschku.libquassel.util.Flag -import de.kuschku.libquassel.util.Flags +import de.kuschku.libquassel.util.flag.Flag +import de.kuschku.libquassel.util.flag.Flags /** * A list of features that are optional in core and/or client, but need runtime checking @@ -12,7 +12,8 @@ import de.kuschku.libquassel.util.Flags * * This list should be cleaned up after every protocol break, as we can assume them to be present then. */ -enum class LegacyFeature(override val bit: Int) : Flag<LegacyFeature> { +enum class LegacyFeature(override val bit: Int) : + Flag<LegacyFeature> { SynchronizedMarkerLine(0x0001), SaslAuthentication(0x0002), SaslExternal(0x0004), diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/ProtocolFeature.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/ProtocolFeature.kt index cadce1dd0c4e6cc1f797aad9ed315de73d459718..f3b7a22e203ceafe5df12e2e3c8db96d473073a7 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/ProtocolFeature.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/ProtocolFeature.kt @@ -1,9 +1,10 @@ package de.kuschku.libquassel.quassel -import de.kuschku.libquassel.util.Flag -import de.kuschku.libquassel.util.Flags +import de.kuschku.libquassel.util.flag.Flag +import de.kuschku.libquassel.util.flag.Flags -enum class ProtocolFeature(override val bit: Int) : Flag<ProtocolFeature> { +enum class ProtocolFeature(override val bit: Int) : + Flag<ProtocolFeature> { None(0x00), TLS(0x01), Compression(0x02); diff --git a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/INetwork.kt b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/INetwork.kt index 03d07e2ddfb2dd5e7979af7fa99bb988f54c06c2..cc015a74d48cd9ef1374f2aac9c1cc04c2943cca 100644 --- a/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/INetwork.kt +++ b/lib/src/main/java/de/kuschku/libquassel/quassel/syncables/interfaces/INetwork.kt @@ -3,8 +3,8 @@ package de.kuschku.libquassel.quassel.syncables.interfaces import de.kuschku.libquassel.annotations.Slot import de.kuschku.libquassel.annotations.Syncable import de.kuschku.libquassel.protocol.* -import de.kuschku.libquassel.util.Flag -import de.kuschku.libquassel.util.Flags +import de.kuschku.libquassel.util.flag.Flag +import de.kuschku.libquassel.util.flag.Flags import java.nio.ByteBuffer @Syncable(name = "Network") @@ -255,7 +255,8 @@ interface INetwork : ISyncableObject { * {@see http://www.irc.org/tech_docs/005.html} * {@see http://www.irc.org/tech_docs/draft-brocklesby-irc-isupport-03.txt} */ - enum class ChannelModeType(override val bit: Int) : Flag<ChannelModeType> { + enum class ChannelModeType(override val bit: Int) : + Flag<ChannelModeType> { NOT_A_CHANMODE(0x00), A_CHANMODE(0x01), B_CHANMODE(0x02), diff --git a/lib/src/main/java/de/kuschku/libquassel/session/CoreConnection.kt b/lib/src/main/java/de/kuschku/libquassel/session/CoreConnection.kt index 9a0de43cf0d3451e69c3c816367db3e18f7dfdfd..5b22f88e98f9a5e55ea12dc23eafb69855898c7b 100644 --- a/lib/src/main/java/de/kuschku/libquassel/session/CoreConnection.kt +++ b/lib/src/main/java/de/kuschku/libquassel/session/CoreConnection.kt @@ -13,7 +13,7 @@ import de.kuschku.libquassel.util.compatibility.HandlerService import de.kuschku.libquassel.util.compatibility.LoggingHandler.Companion.log import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.DEBUG import de.kuschku.libquassel.util.compatibility.LoggingHandler.LogLevel.WARN -import de.kuschku.libquassel.util.hasFlag +import de.kuschku.libquassel.util.flag.hasFlag import de.kuschku.libquassel.util.helpers.hexDump import de.kuschku.libquassel.util.helpers.write import de.kuschku.libquassel.util.nio.ChainedByteBuffer diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/quassel/CRCUtils.kt b/lib/src/main/java/de/kuschku/libquassel/util/CRCUtils.kt similarity index 94% rename from app/src/main/java/de/kuschku/quasseldroid/util/quassel/CRCUtils.kt rename to lib/src/main/java/de/kuschku/libquassel/util/CRCUtils.kt index b9fb401ab6228a460cb11de3851d23b3341f2ac0..998c248ad26569b0bbee84f096afd0c547257bdc 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/util/quassel/CRCUtils.kt +++ b/lib/src/main/java/de/kuschku/libquassel/util/CRCUtils.kt @@ -1,4 +1,4 @@ -package de.kuschku.quasseldroid.util.quassel +package de.kuschku.libquassel.util object CRCUtils { fun qChecksum(data: ByteArray): Int { diff --git a/app/src/main/java/de/kuschku/quasseldroid/util/quassel/IrcUserUtils.kt b/lib/src/main/java/de/kuschku/libquassel/util/IrcUserUtils.kt similarity index 97% rename from app/src/main/java/de/kuschku/quasseldroid/util/quassel/IrcUserUtils.kt rename to lib/src/main/java/de/kuschku/libquassel/util/IrcUserUtils.kt index 403c63523edd4c9183e7392e6032fb02134d219b..a2bf8f95035ed4afdec901728878974b4c6fb422 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/util/quassel/IrcUserUtils.kt +++ b/lib/src/main/java/de/kuschku/libquassel/util/IrcUserUtils.kt @@ -1,4 +1,4 @@ -package de.kuschku.quasseldroid.util.quassel +package de.kuschku.libquassel.util import java.util.* diff --git a/lib/src/main/java/de/kuschku/libquassel/util/Flag.kt b/lib/src/main/java/de/kuschku/libquassel/util/flag/Flag.kt similarity index 69% rename from lib/src/main/java/de/kuschku/libquassel/util/Flag.kt rename to lib/src/main/java/de/kuschku/libquassel/util/flag/Flag.kt index 7d0ae2df5d938bf66c7deeab4f02d91b7db9aba6..dd43df5d14688ae22db1afefece90684f9af1cb8 100644 --- a/lib/src/main/java/de/kuschku/libquassel/util/Flag.kt +++ b/lib/src/main/java/de/kuschku/libquassel/util/flag/Flag.kt @@ -1,4 +1,4 @@ -package de.kuschku.libquassel.util +package de.kuschku.libquassel.util.flag interface Flag<T> where T : Enum<T>, T : Flag<T> { val bit: Int @@ -47,15 +47,19 @@ data class Flags<E>( companion object { inline fun <reified T> of(int: Int): Flags<T> - where T : Flag<T>, T : Enum<T> = Flags(int, enumValues()) + where T : Flag<T>, T : Enum<T> = Flags( + int, + enumValues()) inline fun <reified T> of(vararg flags: T): Flags<T> where T : Flag<T>, T : Enum<T> = - Flags(flags.map(Flag<T>::bit).distinct().sum(), enumValues()) + Flags(flags.map(Flag<T>::bit).distinct().sum(), + enumValues()) inline fun <reified T> of(flags: Iterable<T>): Flags<T> where T : Flag<T>, T : Enum<T> = - Flags(flags.map(Flag<T>::bit).distinct().sum(), enumValues()) + Flags(flags.map(Flag<T>::bit).distinct().sum(), + enumValues()) } interface Factory<E> where E : Flag<E>, E : Enum<E> { @@ -74,40 +78,53 @@ infix fun <T> Flags<T>.hasFlag(which: T): Boolean where T : Enum<T>, T : Flag<T> } infix fun <T> Flags<T>.or(other: Int): Flags<T> - where T : kotlin.Enum<T>, T : Flag<T> = Flags(value or other) + where T : kotlin.Enum<T>, T : Flag<T> = Flags( + value or other) infix fun <T> Flags<T>.or(other: Flag<T>): Flags<T> - where T : kotlin.Enum<T>, T : Flag<T> = Flags(value or other.bit) + where T : kotlin.Enum<T>, T : Flag<T> = Flags( + value or other.bit) infix fun <T> Flags<T>.or(other: Flags<T>): Flags<T> - where T : kotlin.Enum<T>, T : Flag<T> = Flags(value or other.value) + where T : kotlin.Enum<T>, T : Flag<T> = Flags( + value or other.value) infix fun <T> Flags<T>.and(other: Int): Flags<T> - where T : kotlin.Enum<T>, T : Flag<T> = Flags(value and other) + where T : kotlin.Enum<T>, T : Flag<T> = Flags( + value and other) infix fun <T> Flags<T>.and(other: Flag<T>): Flags<T> - where T : kotlin.Enum<T>, T : Flag<T> = Flags(value and other.bit) + where T : kotlin.Enum<T>, T : Flag<T> = Flags( + value and other.bit) infix fun <T> Flags<T>.and(other: Flags<T>): Flags<T> - where T : kotlin.Enum<T>, T : Flag<T> = Flags(value and other.value) + where T : kotlin.Enum<T>, T : Flag<T> = Flags( + value and other.value) infix operator fun <T> Flags<T>.plus(other: Int): Flags<T> - where T : Enum<T>, T : Flag<T> = Flags(value or other) + where T : Enum<T>, T : Flag<T> = Flags( + value or other) infix operator fun <T> Flags<T>.plus(other: Flag<T>): Flags<T> - where T : Enum<T>, T : Flag<T> = Flags(value or other.bit) + where T : Enum<T>, T : Flag<T> = Flags( + value or other.bit) infix operator fun <T> Flags<T>.plus(other: Flags<T>): Flags<T> - where T : Enum<T>, T : Flag<T> = Flags(value or other.value) + where T : Enum<T>, T : Flag<T> = Flags( + value or other.value) infix operator fun <T> Flags<T>.minus(other: Int): Flags<T> - where T : Enum<T>, T : Flag<T> = Flags(value and other.inv()) + where T : Enum<T>, T : Flag<T> = Flags( + value and other.inv()) infix operator fun <T> Flags<T>.minus(other: Flag<T>): Flags<T> - where T : Enum<T>, T : Flag<T> = Flags(value and other.bit.inv()) + where T : Enum<T>, T : Flag<T> = Flags( + value and other.bit.inv()) infix operator fun <T> Flags<T>.minus(other: Flags<T>): Flags<T> - where T : Enum<T>, T : Flag<T> = Flags(value and other.value.inv()) + where T : Enum<T>, T : Flag<T> = Flags( + value and other.value.inv()) infix fun <T> Flags<T>.unset(which: T): Flags<T> - where T : Enum<T>, T : Flag<T> = Flags(value xor which.bit) + where T : Enum<T>, T : Flag<T> = Flags( + value xor which.bit) diff --git a/lib/src/main/java/de/kuschku/libquassel/util/LongFlag.kt b/lib/src/main/java/de/kuschku/libquassel/util/flag/LongFlag.kt similarity index 69% rename from lib/src/main/java/de/kuschku/libquassel/util/LongFlag.kt rename to lib/src/main/java/de/kuschku/libquassel/util/flag/LongFlag.kt index 7356adebc9ff8150e0a8401d6615f4d7a1e3499f..9081e1eefbf724c16fc46d916edf302467d37ffa 100644 --- a/lib/src/main/java/de/kuschku/libquassel/util/LongFlag.kt +++ b/lib/src/main/java/de/kuschku/libquassel/util/flag/LongFlag.kt @@ -1,4 +1,4 @@ -package de.kuschku.libquassel.util +package de.kuschku.libquassel.util.flag interface LongFlag<T> where T : Enum<T>, T : LongFlag<T> { val bit: Long @@ -47,15 +47,19 @@ data class LongFlags<E>( companion object { inline fun <reified T> of(int: Long): LongFlags<T> - where T : LongFlag<T>, T : Enum<T> = LongFlags(int, enumValues()) + where T : LongFlag<T>, T : Enum<T> = LongFlags( + int, + enumValues()) inline fun <reified T> of(vararg flags: LongFlag<T>): LongFlags<T> where T : LongFlag<T>, T : Enum<T> = - LongFlags(flags.map(LongFlag<T>::bit).distinct().sum(), enumValues()) + LongFlags(flags.map(LongFlag<T>::bit).distinct().sum(), + enumValues()) inline fun <reified T> of(flags: Iterable<T>): LongFlags<T> where T : LongFlag<T>, T : Enum<T> = - LongFlags(flags.map(LongFlag<T>::bit).distinct().sum(), enumValues()) + LongFlags(flags.map(LongFlag<T>::bit).distinct().sum(), + enumValues()) } interface Factory<E> where E : LongFlag<E>, E : Enum<E> { @@ -73,40 +77,53 @@ infix fun <T> LongFlags<T>.hasFlag(which: T): Boolean where T : Enum<T>, T : Lon } infix fun <T> LongFlags<T>.or(other: Long): LongFlags<T> - where T : kotlin.Enum<T>, T : LongFlag<T> = LongFlags(value or other) + where T : kotlin.Enum<T>, T : LongFlag<T> = LongFlags( + value or other) infix fun <T> LongFlags<T>.or(other: LongFlag<T>): LongFlags<T> - where T : kotlin.Enum<T>, T : LongFlag<T> = LongFlags(value or other.bit) + where T : kotlin.Enum<T>, T : LongFlag<T> = LongFlags( + value or other.bit) infix fun <T> LongFlags<T>.or(other: LongFlags<T>): LongFlags<T> - where T : kotlin.Enum<T>, T : LongFlag<T> = LongFlags(value or other.value) + where T : kotlin.Enum<T>, T : LongFlag<T> = LongFlags( + value or other.value) infix fun <T> LongFlags<T>.and(other: Long): LongFlags<T> - where T : kotlin.Enum<T>, T : LongFlag<T> = LongFlags(value and other) + where T : kotlin.Enum<T>, T : LongFlag<T> = LongFlags( + value and other) infix fun <T> LongFlags<T>.and(other: LongFlag<T>): LongFlags<T> - where T : kotlin.Enum<T>, T : LongFlag<T> = LongFlags(value and other.bit) + where T : kotlin.Enum<T>, T : LongFlag<T> = LongFlags( + value and other.bit) infix fun <T> LongFlags<T>.and(other: LongFlags<T>): LongFlags<T> - where T : kotlin.Enum<T>, T : LongFlag<T> = LongFlags(value and other.value) + where T : kotlin.Enum<T>, T : LongFlag<T> = LongFlags( + value and other.value) infix operator fun <T> LongFlags<T>.plus(other: Long): LongFlags<T> - where T : Enum<T>, T : LongFlag<T> = LongFlags(value or other) + where T : Enum<T>, T : LongFlag<T> = LongFlags( + value or other) infix operator fun <T> LongFlags<T>.plus(other: LongFlag<T>): LongFlags<T> - where T : Enum<T>, T : LongFlag<T> = LongFlags(value or other.bit) + where T : Enum<T>, T : LongFlag<T> = LongFlags( + value or other.bit) infix operator fun <T> LongFlags<T>.plus(other: LongFlags<T>): LongFlags<T> - where T : Enum<T>, T : LongFlag<T> = LongFlags(value or other.value) + where T : Enum<T>, T : LongFlag<T> = LongFlags( + value or other.value) infix operator fun <T> LongFlags<T>.minus(other: Long): LongFlags<T> - where T : Enum<T>, T : LongFlag<T> = LongFlags(value and other.inv()) + where T : Enum<T>, T : LongFlag<T> = LongFlags( + value and other.inv()) infix operator fun <T> LongFlags<T>.minus(other: LongFlag<T>): LongFlags<T> - where T : Enum<T>, T : LongFlag<T> = LongFlags(value and other.bit.inv()) + where T : Enum<T>, T : LongFlag<T> = LongFlags( + value and other.bit.inv()) infix operator fun <T> LongFlags<T>.minus(other: LongFlags<T>): LongFlags<T> - where T : Enum<T>, T : LongFlag<T> = LongFlags(value and other.value.inv()) + where T : Enum<T>, T : LongFlag<T> = LongFlags( + value and other.value.inv()) infix fun <T> LongFlags<T>.unset(which: T): LongFlags<T> - where T : Enum<T>, T : LongFlag<T> = LongFlags(value xor which.bit) \ No newline at end of file + where T : Enum<T>, T : LongFlag<T> = LongFlags( + value xor which.bit) \ No newline at end of file diff --git a/lib/src/main/java/de/kuschku/libquassel/util/ShortFlag.kt b/lib/src/main/java/de/kuschku/libquassel/util/flag/ShortFlag.kt similarity index 72% rename from lib/src/main/java/de/kuschku/libquassel/util/ShortFlag.kt rename to lib/src/main/java/de/kuschku/libquassel/util/flag/ShortFlag.kt index c7271d11100c2459e41c0e9c9568dc3c0d44e8da..2ef747380e153b7c484b906dd7dbb518db8fd221 100644 --- a/lib/src/main/java/de/kuschku/libquassel/util/ShortFlag.kt +++ b/lib/src/main/java/de/kuschku/libquassel/util/flag/ShortFlag.kt @@ -1,4 +1,4 @@ -package de.kuschku.libquassel.util +package de.kuschku.libquassel.util.flag import kotlin.experimental.and import kotlin.experimental.inv @@ -52,15 +52,19 @@ data class ShortFlags<E>( companion object { inline fun <reified T> of(int: Short): ShortFlags<T> - where T : ShortFlag<T>, T : Enum<T> = ShortFlags(int, enumValues()) + where T : ShortFlag<T>, T : Enum<T> = ShortFlags( + int, + enumValues()) inline fun <reified T> of(vararg flags: ShortFlag<T>): ShortFlags<T> where T : ShortFlag<T>, T : Enum<T> = - ShortFlags(flags.map(ShortFlag<T>::bit).distinct().sum().toShort(), enumValues()) + ShortFlags(flags.map(ShortFlag<T>::bit).distinct().sum().toShort(), + enumValues()) inline fun <reified T> of(flags: Iterable<T>): ShortFlags<T> where T : ShortFlag<T>, T : Enum<T> = - ShortFlags(flags.map(ShortFlag<T>::bit).distinct().sum().toShort(), enumValues()) + ShortFlags(flags.map(ShortFlag<T>::bit).distinct().sum().toShort(), + enumValues()) } interface Factory<E> where E : ShortFlag<E>, E : Enum<E> { @@ -78,40 +82,53 @@ infix fun <T> ShortFlags<T>.hasFlag(which: T): Boolean where T : Enum<T>, T : Sh } infix fun <T> ShortFlags<T>.or(other: Short): ShortFlags<T> - where T : kotlin.Enum<T>, T : ShortFlag<T> = ShortFlags(value or other) + where T : kotlin.Enum<T>, T : ShortFlag<T> = ShortFlags( + value or other) infix fun <T> ShortFlags<T>.or(other: ShortFlag<T>): ShortFlags<T> - where T : kotlin.Enum<T>, T : ShortFlag<T> = ShortFlags(value or other.bit) + where T : kotlin.Enum<T>, T : ShortFlag<T> = ShortFlags( + value or other.bit) infix fun <T> ShortFlags<T>.or(other: ShortFlags<T>): ShortFlags<T> - where T : kotlin.Enum<T>, T : ShortFlag<T> = ShortFlags(value or other.value) + where T : kotlin.Enum<T>, T : ShortFlag<T> = ShortFlags( + value or other.value) infix fun <T> ShortFlags<T>.and(other: Short): ShortFlags<T> - where T : kotlin.Enum<T>, T : ShortFlag<T> = ShortFlags(value and other) + where T : kotlin.Enum<T>, T : ShortFlag<T> = ShortFlags( + value and other) infix fun <T> ShortFlags<T>.and(other: ShortFlag<T>): ShortFlags<T> - where T : kotlin.Enum<T>, T : ShortFlag<T> = ShortFlags(value and other.bit) + where T : kotlin.Enum<T>, T : ShortFlag<T> = ShortFlags( + value and other.bit) infix fun <T> ShortFlags<T>.and(other: ShortFlags<T>): ShortFlags<T> - where T : kotlin.Enum<T>, T : ShortFlag<T> = ShortFlags(value and other.value) + where T : kotlin.Enum<T>, T : ShortFlag<T> = ShortFlags( + value and other.value) infix operator fun <T> ShortFlags<T>.plus(other: Short): ShortFlags<T> - where T : Enum<T>, T : ShortFlag<T> = ShortFlags(value or other) + where T : Enum<T>, T : ShortFlag<T> = ShortFlags( + value or other) infix operator fun <T> ShortFlags<T>.plus(other: ShortFlag<T>): ShortFlags<T> - where T : Enum<T>, T : ShortFlag<T> = ShortFlags(value or other.bit) + where T : Enum<T>, T : ShortFlag<T> = ShortFlags( + value or other.bit) infix operator fun <T> ShortFlags<T>.plus(other: ShortFlags<T>): ShortFlags<T> - where T : Enum<T>, T : ShortFlag<T> = ShortFlags(value or other.value) + where T : Enum<T>, T : ShortFlag<T> = ShortFlags( + value or other.value) infix operator fun <T> ShortFlags<T>.minus(other: Short): ShortFlags<T> - where T : Enum<T>, T : ShortFlag<T> = ShortFlags(value and other.inv()) + where T : Enum<T>, T : ShortFlag<T> = ShortFlags( + value and other.inv()) infix operator fun <T> ShortFlags<T>.minus(other: ShortFlag<T>): ShortFlags<T> - where T : Enum<T>, T : ShortFlag<T> = ShortFlags(value and other.bit.inv()) + where T : Enum<T>, T : ShortFlag<T> = ShortFlags( + value and other.bit.inv()) infix operator fun <T> ShortFlags<T>.minus(other: ShortFlags<T>): ShortFlags<T> - where T : Enum<T>, T : ShortFlag<T> = ShortFlags(value and other.value.inv()) + where T : Enum<T>, T : ShortFlag<T> = ShortFlags( + value and other.value.inv()) infix fun <T> ShortFlags<T>.unset(which: T): ShortFlags<T> - where T : Enum<T>, T : ShortFlag<T> = ShortFlags(value xor which.bit) \ No newline at end of file + where T : Enum<T>, T : ShortFlag<T> = ShortFlags( + value xor which.bit) \ No newline at end of file diff --git a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/QuasselViewModel.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/QuasselViewModel.kt index 4ba1fec689567256a681d11a2a54327c26d11180..d65e285164ef14ad2b59c964e9f6755a7fa6986f 100644 --- a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/QuasselViewModel.kt +++ b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/QuasselViewModel.kt @@ -15,8 +15,8 @@ import de.kuschku.libquassel.session.ConnectionState import de.kuschku.libquassel.session.ISession import de.kuschku.libquassel.session.SessionManager import de.kuschku.libquassel.util.Optional -import de.kuschku.libquassel.util.and -import de.kuschku.libquassel.util.hasFlag +import de.kuschku.libquassel.util.flag.and +import de.kuschku.libquassel.util.flag.hasFlag import de.kuschku.libquassel.util.helpers.* import de.kuschku.quasseldroid.util.helper.combineLatest import de.kuschku.quasseldroid.util.helper.switchMapNotNull @@ -181,7 +181,10 @@ class QuasselViewModel : ViewModel() { lowestMode, user.realName(), user.isAway(), - network.support("CASEMAPPING") + network.support("CASEMAPPING"), + Regex("[us]id(\\d+)").matchEntire(user.user())?.groupValues?.lastOrNull()?.let { + "https://www.irccloud.com/avatar-redirect/$it" + } ) } } @@ -255,7 +258,10 @@ class QuasselViewModel : ViewModel() { lowestMode, user.realName(), user.isAway(), - network.support("CASEMAPPING") + network.support("CASEMAPPING"), + Regex("[us]id(\\d+)").matchEntire(user.user())?.groupValues?.lastOrNull()?.let { + "https://www.irccloud.com/avatar-redirect/$it" + } ) } } diff --git a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/AutoCompleteItem.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/AutoCompleteItem.kt index 0aea3b45e49fdaa5e26e0644d92d92276b69d256..0b452a55b8b6999c10e70a37cf0879e4859dda60 100644 --- a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/AutoCompleteItem.kt +++ b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/AutoCompleteItem.kt @@ -1,5 +1,6 @@ package de.kuschku.quasseldroid.viewmodel.data +import android.graphics.drawable.Drawable import de.kuschku.libquassel.quassel.BufferInfo import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork @@ -20,7 +21,10 @@ sealed class AutoCompleteItem(open val name: String) : Comparable<AutoCompleteIt val lowestMode: Int, val realname: CharSequence, val away: Boolean, - val networkCasemapping: String? + val networkCasemapping: String?, + val displayNick: CharSequence? = null, + val avatarUrl: String? = null, + val fallbackDrawable: Drawable? = null ) : AutoCompleteItem(nick) data class ChannelItem( diff --git a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/IrcUserItem.kt b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/IrcUserItem.kt index 651699812d34bf2bc96b00584ff494759c601eae..de3ec6672def2a3d39cba4b9880905ff2823fa19 100644 --- a/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/IrcUserItem.kt +++ b/viewmodel/src/main/java/de/kuschku/quasseldroid/viewmodel/data/IrcUserItem.kt @@ -1,10 +1,15 @@ package de.kuschku.quasseldroid.viewmodel.data +import android.graphics.drawable.Drawable + data class IrcUserItem( val nick: String, val modes: String, val lowestMode: Int, val realname: CharSequence, val away: Boolean, - val networkCasemapping: String? + val networkCasemapping: String?, + val avatarUrl: String? = null, + val fallbackDrawable: Drawable? = null, + val displayNick: CharSequence? = null ) \ No newline at end of file