From 4aed197dd537cc55a05d5c572c0d29e4d6a9900b Mon Sep 17 00:00:00 2001 From: Janne Koschinski <janne@kuschku.de> Date: Thu, 8 Mar 2018 15:58:33 +0100 Subject: [PATCH] Implement early version of Autocomplete --- .../quasseldroid_ng/service/QuasselService.kt | 4 +- .../settings/AppearanceSettings.kt | 69 ++++++++++ .../settings/BacklogSettings.kt | 9 ++ .../settings/ConnectionSettings.kt | 9 ++ .../quasseldroid_ng/settings/Settings.kt | 83 ++++++++++++ .../ui/chat/AutoCompleteAdapter.kt | 121 ++++++++++++++++++ .../quasseldroid_ng/ui/chat/ChatActivity.kt | 62 ++++++++- .../quasseldroid_ng/ui/chat/InputEditor.kt | 15 +++ .../ui/chat/NickListFragment.kt | 4 +- .../ui/chat/ToolbarFragment.kt | 4 +- .../chat/buffers/BufferViewConfigFragment.kt | 4 +- .../ui/chat/messages/MessageAdapter.kt | 2 +- .../ui/chat/messages/MessageListFragment.kt | 6 +- .../chat/messages/QuasselMessageRenderer.kt | 6 +- .../ui/settings/SettingsFragment.kt | 4 +- .../util/helper/CharSequenceHelper.kt | 15 +++ .../util/service/ServiceBoundActivity.kt | 6 +- app/src/main/res/layout/layout_editor.xml | 13 +- app/src/main/res/layout/layout_main.xml | 22 +++- .../main/res/values/strings_preferences.xml | 3 + app/src/main/res/xml/preferences.xml | 5 + 21 files changed, 433 insertions(+), 33 deletions(-) create mode 100644 app/src/main/java/de/kuschku/quasseldroid_ng/settings/AppearanceSettings.kt create mode 100644 app/src/main/java/de/kuschku/quasseldroid_ng/settings/BacklogSettings.kt create mode 100644 app/src/main/java/de/kuschku/quasseldroid_ng/settings/ConnectionSettings.kt create mode 100644 app/src/main/java/de/kuschku/quasseldroid_ng/settings/Settings.kt create mode 100644 app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/AutoCompleteAdapter.kt create mode 100644 app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/CharSequenceHelper.kt diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/service/QuasselService.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/service/QuasselService.kt index a8f6b2e67..d270cc5c8 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/service/QuasselService.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/service/QuasselService.kt @@ -14,8 +14,8 @@ import de.kuschku.quasseldroid_ng.R import de.kuschku.quasseldroid_ng.persistence.AccountDatabase import de.kuschku.quasseldroid_ng.persistence.QuasselBacklogStorage import de.kuschku.quasseldroid_ng.persistence.QuasselDatabase -import de.kuschku.quasseldroid_ng.ui.settings.data.ConnectionSettings -import de.kuschku.quasseldroid_ng.ui.settings.data.Settings +import de.kuschku.quasseldroid_ng.settings.ConnectionSettings +import de.kuschku.quasseldroid_ng.settings.Settings import de.kuschku.quasseldroid_ng.util.AndroidHandlerThread import de.kuschku.quasseldroid_ng.util.QuasseldroidNotificationManager import de.kuschku.quasseldroid_ng.util.compatibility.AndroidHandlerService diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/settings/AppearanceSettings.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/settings/AppearanceSettings.kt new file mode 100644 index 000000000..b0b4e5f00 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/settings/AppearanceSettings.kt @@ -0,0 +1,69 @@ +package de.kuschku.quasseldroid_ng.settings + +import android.support.annotation.StyleRes +import de.kuschku.quasseldroid_ng.R + +data class AppearanceSettings( + val showPrefix: ShowPrefixMode = ShowPrefixMode.HIGHEST, + val colorizeNicknames: ColorizeNicknamesMode = ColorizeNicknamesMode.ALL_BUT_MINE, + val inputEnter: InputEnterMode = InputEnterMode.EMOJI, + val colorizeMirc: Boolean = true, + val useMonospace: Boolean = false, + val showSeconds: Boolean = false, + val use24hClock: Boolean = true, + val showAutocomplete: Boolean = true, + val showHostmask: Boolean = false, + val showLag: Boolean = true, + val theme: Theme = Theme.QUASSEL_LIGHT +) { + enum class ColorizeNicknamesMode { + ALL, + ALL_BUT_MINE, + 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 { + ALL, + HIGHEST, + NONE; + + companion object { + private val map = values().associateBy { it.name } + fun of(name: String) = map[name] + } + } + + enum class Theme(@StyleRes val style: Int) { + QUASSEL_LIGHT(R.style.Theme_ChatTheme_Quassel_Light), + QUASSEL_DARK(R.style.Theme_ChatTheme_Quassel_Dark), + AMOLED(R.style.Theme_ChatTheme_Amoled), + SOLARIZED_LIGHT(R.style.Theme_ChatTheme_Solarized_Light), + SOLARIZED_DARK(R.style.Theme_ChatTheme_Solarized_Dark), + GRUVBOX_LIGHT(R.style.Theme_ChatTheme_Gruvbox_Light), + 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 { + val DEFAULT = AppearanceSettings() + } +} \ No newline at end of file diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/settings/BacklogSettings.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/settings/BacklogSettings.kt new file mode 100644 index 000000000..c15f4e463 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/settings/BacklogSettings.kt @@ -0,0 +1,9 @@ +package de.kuschku.quasseldroid_ng.settings + +data class BacklogSettings( + val dynamicAmount: Int = 20 +) { + companion object { + val DEFAULT = BacklogSettings() + } +} \ No newline at end of file diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/settings/ConnectionSettings.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/settings/ConnectionSettings.kt new file mode 100644 index 000000000..ad0e5993b --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/settings/ConnectionSettings.kt @@ -0,0 +1,9 @@ +package de.kuschku.quasseldroid_ng.settings + +data class ConnectionSettings( + val showNotification: Boolean = true +) { + companion object { + val DEFAULT = ConnectionSettings() + } +} \ No newline at end of file diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/settings/Settings.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/settings/Settings.kt new file mode 100644 index 000000000..f78f23cd8 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/settings/Settings.kt @@ -0,0 +1,83 @@ +package de.kuschku.quasseldroid_ng.settings + +import android.content.Context +import de.kuschku.quasseldroid_ng.R +import de.kuschku.quasseldroid_ng.settings.AppearanceSettings.* +import de.kuschku.quasseldroid_ng.util.helper.sharedPreferences + +object Settings { + fun appearance(context: Context) = context.sharedPreferences { + AppearanceSettings( + theme = Theme.of( + getString( + context.getString(R.string.preference_theme_key), + "" + ) + ) ?: AppearanceSettings.DEFAULT.theme, + useMonospace = getBoolean( + context.getString(R.string.preference_monospace_key), + AppearanceSettings.DEFAULT.useMonospace + ), + showSeconds = getBoolean( + context.getString(R.string.preference_show_seconds_key), + AppearanceSettings.DEFAULT.showSeconds + ), + use24hClock = getBoolean( + context.getString(R.string.preference_use_24h_clock_key), + AppearanceSettings.DEFAULT.use24hClock + ), + showPrefix = ShowPrefixMode.of( + getString( + context.getString(R.string.preference_show_prefix_key), + "" + ) + ) ?: AppearanceSettings.DEFAULT.showPrefix, + colorizeNicknames = ColorizeNicknamesMode.of( + getString( + context.getString(R.string.preference_colorize_nicknames_key), + "" + ) + ) ?: AppearanceSettings.DEFAULT.colorizeNicknames, + inputEnter = InputEnterMode.of( + getString( + context.getString(R.string.preference_input_enter_key), + "" + ) + ) ?: AppearanceSettings.DEFAULT.inputEnter, + colorizeMirc = getBoolean( + context.getString(R.string.preference_colorize_mirc_key), + AppearanceSettings.DEFAULT.colorizeMirc + ), + showAutocomplete = getBoolean( + context.getString(R.string.preference_autocomplete_key), + AppearanceSettings.DEFAULT.showAutocomplete + ), + showHostmask = getBoolean( + context.getString(R.string.preference_hostmask_key), + AppearanceSettings.DEFAULT.showHostmask + ), + showLag = getBoolean( + context.getString(R.string.preference_show_lag_key), + AppearanceSettings.DEFAULT.showLag + ) + ) + } + + fun backlog(context: Context) = context.sharedPreferences { + BacklogSettings( + dynamicAmount = getString( + context.getString(R.string.preference_dynamic_fetch_key), + BacklogSettings.DEFAULT.dynamicAmount.toString() + ).toIntOrNull() ?: BacklogSettings.DEFAULT.dynamicAmount + ) + } + + fun connection(context: Context) = context.sharedPreferences { + ConnectionSettings( + showNotification = getBoolean( + context.getString(R.string.preference_show_notification_key), + ConnectionSettings.DEFAULT.showNotification + ) + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/AutoCompleteAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/AutoCompleteAdapter.kt new file mode 100644 index 000000000..7779e26f4 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/AutoCompleteAdapter.kt @@ -0,0 +1,121 @@ +package de.kuschku.quasseldroid_ng.ui.chat + +import android.arch.lifecycle.LifecycleOwner +import android.arch.lifecycle.LiveData +import android.arch.lifecycle.Observer +import android.support.v7.util.DiffUtil +import android.support.v7.widget.RecyclerView +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import butterknife.BindView +import butterknife.ButterKnife +import de.kuschku.quasseldroid_ng.R +import de.kuschku.quasseldroid_ng.util.helper.visibleIf +import de.kuschku.quasseldroid_ng.util.irc.IrcCaseMappers + +class AutoCompleteAdapter( + lifecycleOwner: LifecycleOwner, + liveData: LiveData<List<NickListAdapter.IrcUserItem>?>, + runInBackground: (() -> Unit) -> Any, + runOnUiThread: (Runnable) -> Any, + private val clickListener: ((String) -> Unit)? = null +) : RecyclerView.Adapter<AutoCompleteAdapter.NickViewHolder>() { + var data = mutableListOf<NickListAdapter.IrcUserItem>() + + init { + liveData.observe( + lifecycleOwner, Observer { it: List<NickListAdapter.IrcUserItem>? -> + runInBackground { + val list = it ?: emptyList() + val old: List<NickListAdapter.IrcUserItem> = data + val new: List<NickListAdapter.IrcUserItem> = list + .sortedBy { IrcCaseMappers[it.networkCasemapping].toLowerCase(it.nick) } + .sortedBy { it.lowestMode } + val result = DiffUtil.calculateDiff( + object : DiffUtil.Callback() { + override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) = + old[oldItemPosition].nick == new[newItemPosition].nick + + override fun getOldListSize() = old.size + override fun getNewListSize() = new.size + override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) = + old[oldItemPosition] == new[newItemPosition] + }, true + ) + runOnUiThread( + Runnable { + data.clear() + data.addAll(new) + result.dispatchUpdatesTo(this@AutoCompleteAdapter) + } + ) + } + } + ) + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = NickViewHolder( + LayoutInflater.from(parent.context).inflate( + when (viewType) { + VIEWTYPE_AWAY -> R.layout.widget_nick_away + else -> R.layout.widget_nick + }, parent, false + ), + clickListener = clickListener + ) + + override fun onBindViewHolder(holder: NickViewHolder, position: Int) = holder.bind(data[position]) + + override fun getItemCount() = data.size + + override fun getItemViewType(position: Int) = if (data[position].away) { + VIEWTYPE_AWAY + } else { + VIEWTYPE_ACTIVE + } + + class NickViewHolder( + 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.nick) + lateinit var nick: TextView + + @BindView(R.id.realname) + lateinit var realname: TextView + + var user: String? = null + + init { + ButterKnife.bind(this, itemView) + itemView.setOnClickListener { + val nick = user + if (nick != null) + clickListener?.invoke(nick) + } + } + + fun bind(data: NickListAdapter.IrcUserItem) { + user = data.nick + + nick.text = data.nick + modes.text = data.modes + realname.text = data.realname + + modes.visibleIf(data.modes.isNotBlank()) + } + } + + companion object { + val VIEWTYPE_ACTIVE = 0 + val VIEWTYPE_AWAY = 1 + } +} \ No newline at end of file diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatActivity.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatActivity.kt index af0bf9cb1..76291f6fd 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatActivity.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ChatActivity.kt @@ -14,9 +14,10 @@ import android.support.design.widget.Snackbar import android.support.v4.graphics.drawable.DrawableCompat import android.support.v4.widget.DrawerLayout import android.support.v7.app.ActionBarDrawerToggle -import android.support.v7.widget.ActionMenuView -import android.support.v7.widget.Toolbar +import android.support.v7.widget.* +import android.text.Editable import android.text.InputType +import android.text.TextWatcher import android.view.* import android.view.inputmethod.EditorInfo import android.widget.EditText @@ -34,15 +35,17 @@ import de.kuschku.libquassel.util.or import de.kuschku.quasseldroid_ng.Keys import de.kuschku.quasseldroid_ng.R import de.kuschku.quasseldroid_ng.persistence.QuasselDatabase +import de.kuschku.quasseldroid_ng.settings.AppearanceSettings +import de.kuschku.quasseldroid_ng.settings.BacklogSettings +import de.kuschku.quasseldroid_ng.settings.Settings 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.Settings import de.kuschku.quasseldroid_ng.ui.viewmodel.QuasselViewModel import de.kuschku.quasseldroid_ng.util.AndroidHandlerThread import de.kuschku.quasseldroid_ng.util.helper.* import de.kuschku.quasseldroid_ng.util.service.ServiceBoundActivity import de.kuschku.quasseldroid_ng.util.ui.MaterialContentLoadingProgressBar +import io.reactivex.subjects.BehaviorSubject +import java.util.concurrent.TimeUnit class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenceChangeListener, ActionMenuView.OnMenuItemClickListener { @@ -70,6 +73,12 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc @BindView(R.id.chatline) lateinit var chatline: EditText + @BindView(R.id.autocomplete_list) + lateinit var autocompleteList: RecyclerView + + @BindView(R.id.autocomplete_list2) + lateinit var autocompleteList2: RecyclerView + private lateinit var drawerToggle: ActionBarDrawerToggle private val handler = AndroidHandlerThread("Chat") @@ -105,6 +114,15 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc } } + private val lastWord = BehaviorSubject.createDefault("") + private val textWatcher = object : TextWatcher { + override fun afterTextChanged(s: Editable?) = + lastWord.onNext(s?.lastWord(chatline.selectionStart, onlyBeforeCursor = true).toString()) + + override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit + override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) = Unit + } + override fun onCreate(savedInstanceState: Bundle?) { handler.onCreate() super.onCreate(savedInstanceState) @@ -192,6 +210,40 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc } }) + val autocompleteAdapter = AutoCompleteAdapter( + this, + viewModel.nickData.switchMapRx { nicks -> + lastWord + .filter { it.length >= 3 || it.isEmpty() } + .distinctUntilChanged() + .debounce(100, TimeUnit.MILLISECONDS) + .map { input -> + if (input.isEmpty()) { + emptyList() + } else { + nicks.filter { + it.nick.contains(input, ignoreCase = true) + }.sortedBy(NickListAdapter.IrcUserItem::nick) + } + } + }, + handler::post, + ::runOnUiThread, + inputEditor::autoComplete + ) + + if (appearanceSettings.showAutocomplete) { + autocompleteList.layoutManager = LinearLayoutManager(this) + autocompleteList.itemAnimator = DefaultItemAnimator() + autocompleteList.adapter = autocompleteAdapter + + autocompleteList2.layoutManager = LinearLayoutManager(this) + autocompleteList2.itemAnimator = DefaultItemAnimator() + autocompleteList2.adapter = autocompleteAdapter + } + + chatline.addTextChangedListener(textWatcher) + editorPanel.addPanelSlideListener(panelSlideListener) editorPanel.panelState = SlidingUpPanelLayout.PanelState.COLLAPSED } diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/InputEditor.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/InputEditor.kt index ebf820700..d096c6aa9 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/InputEditor.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/InputEditor.kt @@ -204,4 +204,19 @@ class InputEditor(private val editText: EditText) { return removedAny } + + fun autoComplete(text: CharSequence) { + val beginningOfWord = editText.text.lastIndexOf(' ', editText.selectionStart) + val endOfWord = editText.text.indexOf(' ', editText.selectionEnd) + val start = beginningOfWord + 1 + val end = if (endOfWord != -1) { + endOfWord + } else { + editText.text.length + } + + val replacement = "$text: " + editText.text.replace(start, end, replacement) + editText.setSelection(start + replacement.length) + } } \ No newline at end of file diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/NickListFragment.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/NickListFragment.kt index 0590152f9..5ff1deaa6 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/NickListFragment.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/NickListFragment.kt @@ -11,8 +11,8 @@ import android.view.ViewGroup import butterknife.BindView import butterknife.ButterKnife import de.kuschku.quasseldroid_ng.R -import de.kuschku.quasseldroid_ng.ui.settings.data.AppearanceSettings -import de.kuschku.quasseldroid_ng.ui.settings.data.Settings +import de.kuschku.quasseldroid_ng.settings.AppearanceSettings +import de.kuschku.quasseldroid_ng.settings.Settings import de.kuschku.quasseldroid_ng.ui.viewmodel.QuasselViewModel import de.kuschku.quasseldroid_ng.util.AndroidHandlerThread import de.kuschku.quasseldroid_ng.util.helper.map diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ToolbarFragment.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ToolbarFragment.kt index 57d9802b2..207c933b8 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ToolbarFragment.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ToolbarFragment.kt @@ -14,8 +14,8 @@ import de.kuschku.libquassel.quassel.BufferInfo import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork import de.kuschku.libquassel.util.hasFlag import de.kuschku.quasseldroid_ng.R -import de.kuschku.quasseldroid_ng.ui.settings.data.AppearanceSettings -import de.kuschku.quasseldroid_ng.ui.settings.data.Settings +import de.kuschku.quasseldroid_ng.settings.AppearanceSettings +import de.kuschku.quasseldroid_ng.settings.Settings import de.kuschku.quasseldroid_ng.ui.viewmodel.QuasselViewModel import de.kuschku.quasseldroid_ng.util.helper.visibleIf import de.kuschku.quasseldroid_ng.util.helper.zip diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/buffers/BufferViewConfigFragment.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/buffers/BufferViewConfigFragment.kt index 490fd7b59..70b1a339a 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/buffers/BufferViewConfigFragment.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/buffers/BufferViewConfigFragment.kt @@ -19,8 +19,8 @@ import de.kuschku.libquassel.util.hasFlag import de.kuschku.libquassel.util.minus import de.kuschku.quasseldroid_ng.R import de.kuschku.quasseldroid_ng.persistence.QuasselDatabase -import de.kuschku.quasseldroid_ng.ui.settings.data.AppearanceSettings -import de.kuschku.quasseldroid_ng.ui.settings.data.Settings +import de.kuschku.quasseldroid_ng.settings.AppearanceSettings +import de.kuschku.quasseldroid_ng.settings.Settings import de.kuschku.quasseldroid_ng.ui.viewmodel.QuasselViewModel import de.kuschku.quasseldroid_ng.util.AndroidHandlerThread import de.kuschku.quasseldroid_ng.util.helper.map diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/messages/MessageAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/messages/MessageAdapter.kt index f02013c80..57bbb6fd7 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/messages/MessageAdapter.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/messages/MessageAdapter.kt @@ -10,7 +10,7 @@ import de.kuschku.libquassel.protocol.* import de.kuschku.libquassel.util.hasFlag import de.kuschku.quasseldroid_ng.persistence.QuasselDatabase import de.kuschku.quasseldroid_ng.persistence.QuasselDatabase.DatabaseMessage -import de.kuschku.quasseldroid_ng.ui.settings.data.AppearanceSettings +import de.kuschku.quasseldroid_ng.settings.AppearanceSettings import de.kuschku.quasseldroid_ng.util.helper.getOrPut class MessageAdapter( diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/messages/MessageListFragment.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/messages/MessageListFragment.kt index 4af1ef6d7..b08403f7e 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/messages/MessageListFragment.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/messages/MessageListFragment.kt @@ -18,9 +18,9 @@ import de.kuschku.libquassel.protocol.MsgId import de.kuschku.libquassel.quassel.syncables.BufferSyncer import de.kuschku.quasseldroid_ng.R import de.kuschku.quasseldroid_ng.persistence.QuasselDatabase -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.Settings +import de.kuschku.quasseldroid_ng.settings.AppearanceSettings +import de.kuschku.quasseldroid_ng.settings.BacklogSettings +import de.kuschku.quasseldroid_ng.settings.Settings import de.kuschku.quasseldroid_ng.ui.viewmodel.QuasselViewModel import de.kuschku.quasseldroid_ng.util.AndroidHandlerThread import de.kuschku.quasseldroid_ng.util.helper.* diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/messages/QuasselMessageRenderer.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/messages/QuasselMessageRenderer.kt index c86f30d0d..940ac0579 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/messages/QuasselMessageRenderer.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/messages/QuasselMessageRenderer.kt @@ -15,9 +15,9 @@ import de.kuschku.libquassel.protocol.MsgId import de.kuschku.libquassel.util.hasFlag import de.kuschku.quasseldroid_ng.R import de.kuschku.quasseldroid_ng.persistence.QuasselDatabase -import de.kuschku.quasseldroid_ng.ui.settings.data.AppearanceSettings -import de.kuschku.quasseldroid_ng.ui.settings.data.AppearanceSettings.ColorizeNicknamesMode -import de.kuschku.quasseldroid_ng.ui.settings.data.AppearanceSettings.ShowPrefixMode +import de.kuschku.quasseldroid_ng.settings.AppearanceSettings +import de.kuschku.quasseldroid_ng.settings.AppearanceSettings.ColorizeNicknamesMode +import de.kuschku.quasseldroid_ng.settings.AppearanceSettings.ShowPrefixMode import de.kuschku.quasseldroid_ng.util.helper.styledAttributes import de.kuschku.quasseldroid_ng.util.helper.visibleIf import de.kuschku.quasseldroid_ng.util.irc.format.IrcFormatDeserializer diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/settings/SettingsFragment.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/settings/SettingsFragment.kt index 6762bd534..bea6fb418 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/settings/SettingsFragment.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/settings/SettingsFragment.kt @@ -7,8 +7,8 @@ import android.support.v7.preference.Preference import android.support.v7.preference.PreferenceFragmentCompat import android.support.v7.preference.PreferenceGroup import de.kuschku.quasseldroid_ng.R -import de.kuschku.quasseldroid_ng.ui.settings.data.AppearanceSettings -import de.kuschku.quasseldroid_ng.ui.settings.data.Settings +import de.kuschku.quasseldroid_ng.settings.AppearanceSettings +import de.kuschku.quasseldroid_ng.settings.Settings class SettingsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedPreferenceChangeListener { diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/CharSequenceHelper.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/CharSequenceHelper.kt new file mode 100644 index 000000000..f7ce68880 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/CharSequenceHelper.kt @@ -0,0 +1,15 @@ +package de.kuschku.quasseldroid_ng.util.helper + +fun CharSequence.lastWord(cursor: Int = this.length, + onlyBeforeCursor: Boolean = false): CharSequence { + val beginningOfWord = lastIndexOf(' ', cursor) + val endOfWord = indexOf(' ', cursor) + val start = beginningOfWord + 1 + val end = if (endOfWord != -1) { + endOfWord + } else { + length + } + + return subSequence(start, if (onlyBeforeCursor) cursor else end) +} \ No newline at end of file diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/ServiceBoundActivity.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/ServiceBoundActivity.kt index 7a500a543..b2d194642 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/ServiceBoundActivity.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/service/ServiceBoundActivity.kt @@ -11,9 +11,9 @@ import android.support.v7.app.AppCompatActivity import de.kuschku.libquassel.session.Backend import de.kuschku.quasseldroid_ng.Keys import de.kuschku.quasseldroid_ng.R -import de.kuschku.quasseldroid_ng.ui.settings.data.AppearanceSettings -import de.kuschku.quasseldroid_ng.ui.settings.data.ConnectionSettings -import de.kuschku.quasseldroid_ng.ui.settings.data.Settings +import de.kuschku.quasseldroid_ng.settings.AppearanceSettings +import de.kuschku.quasseldroid_ng.settings.ConnectionSettings +import de.kuschku.quasseldroid_ng.settings.Settings import de.kuschku.quasseldroid_ng.util.helper.sharedPreferences import de.kuschku.quasseldroid_ng.util.helper.updateRecentsHeaderIfExisting diff --git a/app/src/main/res/layout/layout_editor.xml b/app/src/main/res/layout/layout_editor.xml index a8bc035af..401e59074 100644 --- a/app/src/main/res/layout/layout_editor.xml +++ b/app/src/main/res/layout/layout_editor.xml @@ -8,13 +8,11 @@ android:id="@+id/chatline_scroller" android:layout_width="0dp" android:layout_height="0dp" - android:layout_marginBottom="8dp" - app:layout_constraintBottom_toTopOf="@+id/formatting_toolbar_container" + app:layout_constraintBottom_toTopOf="@+id/autocomplete_list2" app:layout_constraintEnd_toStartOf="@+id/send" app:layout_constraintHorizontal_bias="1.0" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintVertical_bias="0.0"> + app:layout_constraintTop_toTopOf="parent"> <android.support.v7.widget.AppCompatEditText android:id="@+id/chatline" @@ -48,6 +46,13 @@ app:layout_constraintEnd_toEndOf="parent" app:srcCompat="@drawable/ic_send" /> + <android.support.v7.widget.RecyclerView + android:id="@+id/autocomplete_list2" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:maxHeight="144dp" + app:layout_constraintBottom_toTopOf="@+id/formatting_toolbar_container" /> + <android.support.design.widget.AppBarLayout android:id="@+id/formatting_toolbar_container" android:layout_width="match_parent" diff --git a/app/src/main/res/layout/layout_main.xml b/app/src/main/res/layout/layout_main.xml index 9ec10cd07..9c856a9a8 100644 --- a/app/src/main/res/layout/layout_main.xml +++ b/app/src/main/res/layout/layout_main.xml @@ -19,12 +19,26 @@ app:umanoScrollableView="@id/chatline_scroller" app:umanoShadowHeight="4dp"> - <fragment - android:id="@+id/fragment_messages" - android:name="de.kuschku.quasseldroid_ng.ui.chat.messages.MessageListFragment" + <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" - tools:layout="@layout/fragment_messages" /> + android:orientation="vertical"> + + <fragment + android:id="@+id/fragment_messages" + android:name="de.kuschku.quasseldroid_ng.ui.chat.messages.MessageListFragment" + android:layout_width="match_parent" + android:layout_height="0dip" + android:layout_weight="1" + tools:layout="@layout/fragment_messages" /> + + <android.support.v7.widget.RecyclerView + android:id="@+id/autocomplete_list" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:maxHeight="144dp" /> + + </LinearLayout> <include layout="@layout/layout_slider" /> diff --git a/app/src/main/res/values/strings_preferences.xml b/app/src/main/res/values/strings_preferences.xml index d68f77ebb..1d111f867 100644 --- a/app/src/main/res/values/strings_preferences.xml +++ b/app/src/main/res/values/strings_preferences.xml @@ -89,6 +89,9 @@ <item>SEND</item> </string-array> + <string name="preference_autocomplete_key" translatable="false">autocomplete</string> + <string name="preference_autocomplete_title">Show AutoComplete UI</string> + <string name="preference_hostmask_key" translatable="false">hostmask</string> <string name="preference_hostmask_title">Show Hostmask</string> <string name="preference_hostmask_summary">Display the full nick!ident@host in messages</string> diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index bffc6e13f..52f4a061c 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -51,6 +51,11 @@ android:key="@string/preference_show_prefix_key" android:title="@string/preference_show_prefix_title" /> + <SwitchPreference + android:defaultValue="true" + android:key="@string/preference_autocomplete_key" + android:title="@string/preference_autocomplete_title" /> + <SwitchPreference android:defaultValue="false" android:key="@string/preference_hostmask_key" -- GitLab