diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 607b9e9330ad5baa38da222d170e584caae17001..50204202560529ea3bf30236e6b6448d782f1c17 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -111,7 +111,7 @@ dependencies { } // App Arch Persistence - withVersion("1.1.0-alpha3") { + withVersion("1.1.0-beta1") { implementation("android.arch.persistence.room", "runtime", version) implementation("android.arch.persistence.room", "rxjava2", version) kapt("android.arch.persistence.room", "compiler", version) @@ -119,7 +119,7 @@ dependencies { } // App Arch Paging - implementation("android.arch.paging", "runtime", "1.0.0-alpha6") { + implementation("android.arch.paging", "runtime", "1.0.0-alpha7") { exclude(group = "junit", module = "junit") } diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/QuasseldroidNG.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/QuasseldroidNG.kt index f5ea01c145ee26071a87ebe3d59c62b638907f74..6cd6dab9ab9143a16ab07ad75fc4c8ca780b8870 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/QuasseldroidNG.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/QuasseldroidNG.kt @@ -77,8 +77,7 @@ class QuasseldroidNG : Application() { } else { it } - } - .let { + }.let { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { it.detectUnbufferedIo() } else { @@ -100,8 +99,7 @@ class QuasseldroidNG : Application() { } else { it } - } - .let { + }.let { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { it.detectContentUriWithoutPermission() } else { diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/persistence/QuasselDatabase.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/persistence/QuasselDatabase.kt index 8d7daca1d983c26728fc99662b396d28ce8e60b3..ca926a7d040891cd7071e06ddf0098eda05694ff 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/persistence/QuasselDatabase.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/persistence/QuasselDatabase.kt @@ -7,7 +7,6 @@ import android.arch.persistence.room.* import android.arch.persistence.room.migration.Migration import android.content.Context import android.support.annotation.IntRange -import android.support.v7.recyclerview.extensions.DiffCallback import de.kuschku.libquassel.protocol.Message_Flag import de.kuschku.libquassel.protocol.Message_Type import de.kuschku.quasseldroid_ng.persistence.QuasselDatabase.DatabaseMessage @@ -46,14 +45,6 @@ abstract class QuasselDatabase : RoomDatabase() { flag )}, bufferId=$bufferId, sender='$sender', senderPrefixes='$senderPrefixes', content='$content')" } - - object MessageDiffCallback : DiffCallback<DatabaseMessage>() { - override fun areContentsTheSame(oldItem: QuasselDatabase.DatabaseMessage, - newItem: QuasselDatabase.DatabaseMessage) = oldItem == newItem - - override fun areItemsTheSame(oldItem: QuasselDatabase.DatabaseMessage, - newItem: QuasselDatabase.DatabaseMessage) = oldItem.messageId == newItem.messageId - } } @Dao @@ -154,8 +145,7 @@ abstract class QuasselDatabase : RoomDatabase() { "CREATE TABLE filtered(bufferId INTEGER, accountId INTEGER, filtered INTEGER, PRIMARY KEY(accountId, bufferId));" ) } - } - ).build() + }).build() } } } 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 d270cc5c8091707720b01fcfaeecfb8af198f8cb..fee16389dbc7ffe988ac99cdd05026ccf5159acd 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 @@ -110,7 +110,8 @@ class QuasselService : LifecycleService(), } ConnectionState.INIT -> { handle.builder.setContentTitle(getString(R.string.label_status_init)) - handle.builder.setProgress(max, progress, false) + // Show indeterminate when no progress has been made yet + handle.builder.setProgress(max, progress, progress == 0 || max == 0) } ConnectionState.CONNECTED -> { handle.builder.setContentTitle(getString(R.string.label_status_connected)) @@ -265,8 +266,7 @@ class QuasselService : LifecycleService(), .observe( this, Observer { sessionManager.reconnect(true) - } - ) + }) sharedPreferences(Keys.Status.NAME, Context.MODE_PRIVATE) { registerOnSharedPreferenceChangeListener(this@QuasselService) 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 index c15f4e463b683e5a69fdfbe222b5bbfb19a724fc..0287243199a02bba066102d474e800eb44ce95b8 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/settings/BacklogSettings.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/settings/BacklogSettings.kt @@ -1,7 +1,7 @@ package de.kuschku.quasseldroid_ng.settings data class BacklogSettings( - val dynamicAmount: Int = 20 + val dynamicAmount: Int = 150 ) { companion object { val DEFAULT = BacklogSettings() 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 index 175afcd6729f78a7c9572fc374c2849629c81435..24de3eb0079b2791bb07e03954855a67cf8d7f3f 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/settings/Settings.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/settings/Settings.kt @@ -70,7 +70,7 @@ object Settings { fun backlog(context: Context) = context.sharedPreferences { BacklogSettings( dynamicAmount = getString( - context.getString(R.string.preference_dynamic_fetch_key), + context.getString(R.string.preference_page_size_key), BacklogSettings.DEFAULT.dynamicAmount.toString() ).toIntOrNull() ?: BacklogSettings.DEFAULT.dynamicAmount ) 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 17c4644fa62e0c22d422a233054ed75528bd054a..4627d3e556189ec66359032deea8efd3cda42be5 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 @@ -9,17 +9,16 @@ import android.content.SharedPreferences import android.os.Build import android.os.Bundle import android.os.PersistableBundle -import android.support.v4.graphics.drawable.DrawableCompat import android.support.v4.widget.DrawerLayout import android.support.v7.app.ActionBarDrawerToggle -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 -import android.widget.ImageButton +import android.support.v7.widget.DefaultItemAnimator +import android.support.v7.widget.LinearLayoutManager +import android.support.v7.widget.RecyclerView +import android.support.v7.widget.Toolbar +import android.view.Gravity +import android.view.Menu +import android.view.MenuItem +import android.view.View import butterknife.BindView import butterknife.ButterKnife import com.afollestad.materialdialogs.MaterialDialog @@ -33,29 +32,29 @@ 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.chat.input.AutoCompleteAdapter +import de.kuschku.quasseldroid_ng.ui.chat.input.Editor +import de.kuschku.quasseldroid_ng.ui.chat.input.MessageHistoryAdapter import de.kuschku.quasseldroid_ng.ui.settings.SettingsActivity import de.kuschku.quasseldroid_ng.ui.setup.accounts.AccountSelectionActivity 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.helper.editApply +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.service.ServiceBoundActivity import de.kuschku.quasseldroid_ng.util.ui.MaterialContentLoadingProgressBar -import io.reactivex.subjects.BehaviorSubject -class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenceChangeListener, - ActionMenuView.OnMenuItemClickListener { +class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenceChangeListener { @BindView(R.id.drawer_layout) lateinit var drawerLayout: DrawerLayout @BindView(R.id.toolbar) lateinit var toolbar: Toolbar - @BindView(R.id.formatting_menu) - lateinit var formattingMenu: ActionMenuView - @BindView(R.id.progress_bar) lateinit var progressBar: MaterialContentLoadingProgressBar @@ -65,18 +64,6 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc @BindView(R.id.history_panel) lateinit var historyPanel: SlidingUpPanelLayout - @BindView(R.id.send) - lateinit var send: ImageButton - - @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 - @BindView(R.id.msg_history) lateinit var msgHistory: RecyclerView @@ -90,7 +77,7 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc private lateinit var backlogSettings: BacklogSettings - private lateinit var inputEditor: InputEditor + private lateinit var editor: Editor private val panelSlideListener: SlidingUpPanelLayout.PanelSlideListener = object : SlidingUpPanelLayout.PanelSlideListener { @@ -99,57 +86,16 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc override fun onPanelStateChanged(panel: View?, previousState: SlidingUpPanelLayout.PanelState?, newState: SlidingUpPanelLayout.PanelState?) { - val selectionStart = chatline.selectionStart - val selectionEnd = chatline.selectionEnd - - when (newState) { - SlidingUpPanelLayout.PanelState.COLLAPSED -> - chatline.inputType = chatline.inputType and InputType.TYPE_TEXT_FLAG_MULTI_LINE.inv() - else -> - chatline.inputType = chatline.inputType or InputType.TYPE_TEXT_FLAG_MULTI_LINE - } - - chatline.setSelection(selectionStart, selectionEnd) + editor.setMultiLine(newState == SlidingUpPanelLayout.PanelState.COLLAPSED) } } - private val lastWord = BehaviorSubject.createDefault(Pair("", IntRange.EMPTY)) - private val textWatcher = object : TextWatcher { - override fun afterTextChanged(s: Editable?) { - val previous = autocompletionState - val next = if (previous != null && s != null) { - val suffix = if (previous.range.start == 0) ": " else " " - val end = Math.min( - s.length, previous.range.start + previous.completion.name.length + suffix.length - ) - val sequence = s.substring(previous.range.start, end) - if (sequence == previous.completion.name + suffix) { - previous.originalWord to (previous.range.start until end) - } else { - autocompletionState = null - s.lastWordIndices(chatline.selectionStart, onlyBeforeCursor = true)?.let { indices -> - s.substring(indices) to indices - } - } - } else { - s?.lastWordIndices(chatline.selectionStart, onlyBeforeCursor = true)?.let { indices -> - s.substring(indices) to indices - } - } - - lastWord.onNext(next ?: Pair("", IntRange.EMPTY)) - } - - 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 onNewIntent(intent: Intent?) { super.onNewIntent(intent) if (intent != null) { when { intent.type == "text/plain" -> { - inputEditor.share(intent.getStringExtra(Intent.EXTRA_TEXT)) + editor.formatHandler.replace(intent.getStringExtra(Intent.EXTRA_TEXT)) } } } @@ -163,90 +109,75 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc viewModel = ViewModelProviders.of(this)[QuasselViewModel::class.java] viewModel.setBackend(this.backend) - viewModel.lastWord.value = lastWord backlogSettings = Settings.backlog(this) - inputEditor = InputEditor(chatline) - menuInflater.inflate(inputEditor.menu, formattingMenu.menu) - menuInflater.inflate(R.menu.input_panel, formattingMenu.menu) - formattingMenu.setOnMenuItemClickListener(this) - - formattingMenu.context.theme.styledAttributes(R.attr.colorControlNormal) { - val color = getColor(0, 0) - - for (item in (0 until formattingMenu.menu.size()).map { formattingMenu.menu.getItem(it) }) { - val drawable = item.icon.mutate() - DrawableCompat.setTint(drawable, color) - item.icon = drawable + editor = Editor( + this, + viewModel.autoCompleteData, + viewModel.lastWord, + findViewById(R.id.chatline), + findViewById(R.id.send), + listOf( + findViewById(R.id.autocomplete_list), + findViewById(R.id.autocomplete_list_expanded) + ), + findViewById(R.id.formatting_menu), + findViewById(R.id.formatting_toolbar), + { lines -> + viewModel.session { session -> + viewModel.getBuffer().let { bufferId -> + session.bufferSyncer?.bufferInfo(bufferId)?.also { bufferInfo -> + val output = mutableListOf<IAliasManager.Command>() + for ((stripped, formatted) in lines) { + viewModel.addRecentlySentMessage(stripped) + session.aliasManager?.processInput(bufferInfo, formatted, output) + } + for (command in output) { + session.rpcHandler?.sendInput(command.buffer, command.message) + } + } + } + } + }, + { expanded -> + historyPanel.panelState = if (expanded) + SlidingUpPanelLayout.PanelState.EXPANDED + else + SlidingUpPanelLayout.PanelState.COLLAPSED } - } + ) msgHistory.itemAnimator = DefaultItemAnimator() msgHistory.layoutManager = LinearLayoutManager(this) - msgHistory.adapter = MessageHistoryAdapter( - this, - viewModel.recentlySentMessages, - handler::post, - ::runOnUiThread, - { text -> - chatline.setText(text) - chatline.setSelection(chatline.length()) - historyPanel.panelState = SlidingUpPanelLayout.PanelState.COLLAPSED - } - ) + val messageHistoryAdapter = MessageHistoryAdapter { text -> + editor.formatHandler.replace(text) + historyPanel.panelState = SlidingUpPanelLayout.PanelState.COLLAPSED + } + msgHistory.adapter = messageHistoryAdapter + viewModel.recentlySentMessages.observe(this, Observer(messageHistoryAdapter::submitList)) database = QuasselDatabase.Creator.init(application) setSupportActionBar(toolbar) - send.setOnClickListener { - 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 -> - when (keyCode) { - KeyEvent.KEYCODE_ENTER, - KeyEvent.KEYCODE_NUMPAD_ENTER -> if (event.hasNoModifiers()) { - send() - true - } else { - false - } - KeyEvent.KEYCODE_TAB -> { - autoComplete(event.isShiftPressed) - true - } - else -> false - } - } - viewModel.getBuffer().observe( this, Observer { if (it != null && drawerLayout.isDrawerOpen(Gravity.START)) { drawerLayout.closeDrawer(Gravity.START, true) } - } - ) + }) - supportActionBar?.setDisplayHomeAsUpEnabled(true) - drawerToggle = ActionBarDrawerToggle( - this, - drawerLayout, - R.string.label_open, - R.string.label_close - ) - drawerToggle.syncState() + // Don’t show a drawer toggle if in tablet landscape mode + if (resources.getBoolean(R.bool.buffer_drawer_exists)) { + supportActionBar?.setDisplayHomeAsUpEnabled(true) + drawerToggle = ActionBarDrawerToggle( + this, + drawerLayout, + R.string.label_open, + R.string.label_close + ) + drawerToggle.syncState() + } viewModel.connectionProgress.observe(this, Observer { it -> val (state, progress, max) = it ?: Triple(ConnectionState.DISCONNECTED, 0, 0) @@ -255,7 +186,8 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc progressBar.hide() } ConnectionState.INIT -> { - progressBar.isIndeterminate = false + // Show indeterminate when no progress has been made yet + progressBar.isIndeterminate = progress == 0 || max == 0 progressBar.progress = progress progressBar.max = max } @@ -265,27 +197,6 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc } }) - val autocompleteAdapter = AutoCompleteAdapter( - this, - viewModel.autoCompleteData, - handler::post, - ::runOnUiThread, - // This is still broken when mixing tab complete and UI auto complete - 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 } @@ -297,78 +208,6 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc val completion: AutoCompleteAdapter.AutoCompleteItem ) - private var autocompletionState: AutoCompletionState? = null - private fun autoComplete(reverse: Boolean = false) { - val originalWord = lastWord.value - - val previous = autocompletionState - if (!originalWord.second.isEmpty()) { - val autoCompletedWords = viewModel.autoCompleteData.value?.second.orEmpty() - if (previous != null && lastWord.value.first == previous.originalWord && lastWord.value.second.start == previous.range.start) { - val previousIndex = autoCompletedWords.indexOf(previous.completion) - val autoCompletedWord = if (previousIndex != -1) { - val change = if (reverse) -1 else +1 - val newIndex = (previousIndex + change + autoCompletedWords.size) % autoCompletedWords.size - - autoCompletedWords[newIndex] - } else { - autoCompletedWords.firstOrNull() - } - if (autoCompletedWord != null) { - val newState = AutoCompletionState( - previous.originalWord, - originalWord.second, - previous.completion, - autoCompletedWord - ) - autocompletionState = newState - inputEditor.autoComplete(newState) - } else { - autocompletionState = null - } - } else { - val autoCompletedWord = autoCompletedWords.firstOrNull() - if (autoCompletedWord != null) { - val newState = AutoCompletionState( - originalWord.first, - originalWord.second, - null, - autoCompletedWord - ) - autocompletionState = newState - inputEditor.autoComplete(newState) - } else { - autocompletionState = null - } - } - } - } - - private fun send() { - val text = chatline.text - if (text.isNotBlank()) { - viewModel.session { session -> - viewModel.getBuffer().let { bufferId -> - session.bufferSyncer?.bufferInfo(bufferId)?.also { bufferInfo -> - val output = mutableListOf<IAliasManager.Command>() - for (line in text.lineSequence()) { - viewModel.addRecentlySentMessage(line) - session.aliasManager?.processInput( - bufferInfo, - inputEditor.formattedString, - output - ) - } - for (command in output) { - session.rpcHandler?.sendInput(command.buffer, command.message) - } - } - } - } - } - chatline.setText("") - } - override fun onSaveInstanceState(outState: Bundle?) { super.onSaveInstanceState(outState) outState?.putInt("OPEN_BUFFER", viewModel.getBuffer().value ?: -1) @@ -492,14 +331,6 @@ class ChatActivity : ServiceBoundActivity(), SharedPreferences.OnSharedPreferenc else -> super.onOptionsItemSelected(item) } - override fun onMenuItemClick(item: MenuItem?) = when (item?.itemId) { - R.id.input_history -> { - historyPanel.panelState = SlidingUpPanelLayout.PanelState.EXPANDED - true - } - else -> inputEditor.onMenuItemClick(item) - } - override fun onDestroy() { handler.onDestroy() super.onDestroy() diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MessageHistoryAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MessageHistoryAdapter.kt deleted file mode 100644 index c88ed9581b1761009e0a9502f04f8c0f83541a70..0000000000000000000000000000000000000000 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/MessageHistoryAdapter.kt +++ /dev/null @@ -1,83 +0,0 @@ -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 - -class MessageHistoryAdapter( - lifecycleOwner: LifecycleOwner, - liveData: LiveData<List<CharSequence>?>, - runInBackground: (() -> Unit) -> Any, - runOnUiThread: (Runnable) -> Any, - private val clickListener: ((CharSequence) -> Unit)? = null -) : RecyclerView.Adapter<MessageHistoryAdapter.MessageViewHolder>() { - var data = mutableListOf<CharSequence>() - - init { - liveData.observe(lifecycleOwner, Observer { it: List<CharSequence>? -> - runInBackground { - val list = it ?: emptyList() - val old: List<CharSequence> = data - val new: List<CharSequence> = list - val result = DiffUtil.calculateDiff(object : DiffUtil.Callback() { - override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) = - old[oldItemPosition] == new[newItemPosition] - - 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@MessageHistoryAdapter) - }) - } - }) - } - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = MessageViewHolder( - LayoutInflater.from(parent.context).inflate(R.layout.widget_history_message, parent, false), - clickListener = clickListener - ) - - override fun onBindViewHolder(holder: MessageViewHolder, position: Int) = - holder.bind(data[position]) - - override fun getItemCount() = data.size - - class MessageViewHolder( - itemView: View, - private val clickListener: ((CharSequence) -> Unit)? = null - ) : RecyclerView.ViewHolder(itemView) { - @BindView(R.id.content) - lateinit var content: TextView - - var value: CharSequence? = null - - init { - ButterKnife.bind(this, itemView) - itemView.setOnClickListener { - val value = value - if (value != null) - clickListener?.invoke(value) - } - } - - fun bind(data: CharSequence) { - value = data - - content.text = data - } - } -} \ No newline at end of file diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/NickListAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/NickListAdapter.kt deleted file mode 100644 index ce4f8b57e1ddcfb842acf1bce1b71a04b5a1f642..0000000000000000000000000000000000000000 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/NickListAdapter.kt +++ /dev/null @@ -1,131 +0,0 @@ -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.libquassel.util.irc.IrcCaseMappers -import de.kuschku.quasseldroid_ng.R -import de.kuschku.quasseldroid_ng.util.helper.visibleIf - -class NickListAdapter( - lifecycleOwner: LifecycleOwner, - liveData: LiveData<List<IrcUserItem>?>, - runInBackground: (() -> Unit) -> Any, - runOnUiThread: (Runnable) -> Any, - private val clickListener: ((String) -> Unit)? = null -) : RecyclerView.Adapter<NickListAdapter.NickViewHolder>() { - var data = mutableListOf<IrcUserItem>() - - init { - liveData.observe( - lifecycleOwner, Observer { it: List<IrcUserItem>? -> - runInBackground { - val list = it ?: emptyList() - val old: List<IrcUserItem> = data - val new: List<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@NickListAdapter) - } - ) - } - } - ) - } - - 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 - } - - data class IrcUserItem( - val nick: String, - val modes: String, - val lowestMode: Int, - val realname: CharSequence, - val away: Boolean, - val networkCasemapping: String - ) - - 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: 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/ToolbarFragment.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/ToolbarFragment.kt index 207c933b878bd1162a33f0ba2969bae102431539..7c8b69f1c9e36817db540375e36f0d2a066f3d11 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 @@ -93,8 +93,7 @@ class ToolbarFragment : ServiceBoundFragment() { } } } - } - ) + }) return view } @@ -109,5 +108,4 @@ class ToolbarFragment : ServiceBoundFragment() { val network: INetwork.NetworkInfo? = null, val description: String? = null ) - } \ No newline at end of file diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/buffers/BufferListAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/buffers/BufferListAdapter.kt index 6a437ebc1cfb7f831fb874f1827783241cad565a..f5cbb490b395d697103dbc7e00187f3ebf2ddfda 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/buffers/BufferListAdapter.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/buffers/BufferListAdapter.kt @@ -70,27 +70,27 @@ class BufferListAdapter( }.sortedBy { props -> props.network.networkName }.map { props -> - BufferListItem( - props, - BufferState( - networkExpanded = !collapsedNetworks.contains(props.network.networkId), - selected = selected == props.info.bufferId - ) + BufferListItem( + props, + BufferState( + networkExpanded = !collapsedNetworks.contains(props.network.networkId), + selected = selected == props.info.bufferId ) + ) }.filter { (props, state) -> props.info.type.hasFlag(BufferInfo.Type.StatusBuffer) || state.networkExpanded } val result = DiffUtil.calculateDiff( object : DiffUtil.Callback() { - override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) - = old[oldItemPosition].props.info.bufferId == new[newItemPosition].props.info.bufferId + override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) = + old[oldItemPosition].props.info.bufferId == new[newItemPosition].props.info.bufferId override fun getOldListSize() = old.size override fun getNewListSize() = new.size - override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) - = old[oldItemPosition] == new[newItemPosition] + override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) = + old[oldItemPosition] == new[newItemPosition] }, true ) runOnUiThread( @@ -98,11 +98,9 @@ class BufferListAdapter( data.clear() data.addAll(new) result.dispatchUpdatesTo(this@BufferListAdapter) - } - ) + }) } - } - ) + }) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = when (viewType) { @@ -140,8 +138,8 @@ class BufferListAdapter( ) } - override fun onBindViewHolder(holder: BufferViewHolder, position: Int) - = holder.bind(data[position].props, data[position].state) + override fun onBindViewHolder(holder: BufferViewHolder, position: Int) = + holder.bind(data[position].props, data[position].state) override fun getItemCount() = data.size diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/buffers/BufferViewConfigAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/buffers/BufferViewConfigAdapter.kt index 53b3cc1edb1c5fd594d06798eb46b3e3f7c8dd8a..72ff5616d1a062cdf097182b76395c15fb272a24 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/buffers/BufferViewConfigAdapter.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/buffers/BufferViewConfigAdapter.kt @@ -31,14 +31,13 @@ class BufferViewConfigAdapter( data.addAll(list) } notifyDataSetChanged() - } - ) + }) } override fun isEmpty() = data.isEmpty() - override fun onBindViewHolder(holder: BufferViewConfigViewHolder, position: Int) - = holder.bind(getItem(position)) + override fun onBindViewHolder(holder: BufferViewConfigViewHolder, position: Int) = + holder.bind(getItem(position)) override fun onCreateViewHolder(parent: ViewGroup, dropDown: Boolean) : BufferViewConfigViewHolder { 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 70b1a339acb1b1148a7039859d52abb0beb787ee..2c398209052f36dc82182c8e90267a1a86623035 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 @@ -79,7 +79,7 @@ class BufferViewConfigFragment : ServiceBoundFragment() { actionMode?.finish() true } - R.id.action_delete -> { + R.id.action_delete -> { MaterialDialog.Builder(activity!!) .content(R.string.buffer_delete_confirmation) .positiveText(R.string.label_yes) @@ -95,7 +95,7 @@ class BufferViewConfigFragment : ServiceBoundFragment() { actionMode?.finish() true } - R.id.action_rename -> { + R.id.action_rename -> { MaterialDialog.Builder(activity!!) .input( getString(R.string.label_buffer_name), @@ -114,21 +114,21 @@ class BufferViewConfigFragment : ServiceBoundFragment() { actionMode?.finish() true } - R.id.action_unhide -> { + R.id.action_unhide -> { bufferSyncer?.let { bufferViewConfig?.requestAddBuffer(info, bufferSyncer) } true } - R.id.action_hide_temp -> { + R.id.action_hide_temp -> { bufferViewConfig?.requestRemoveBuffer(info.bufferId) true } - R.id.action_hide_perm -> { + R.id.action_hide_perm -> { bufferViewConfig?.requestRemoveBufferPermanently(info.bufferId) true } - else -> false + else -> false } } else { false @@ -210,9 +210,9 @@ class BufferViewConfigFragment : ServiceBoundFragment() { ) ) }.filter { props -> - minimumActivity.toInt() <= props.bufferActivity.toInt() || - props.info.type.hasFlag(Buffer_Type.StatusBuffer) - } + minimumActivity.toInt() <= props.bufferActivity.toInt() || + props.info.type.hasFlag(Buffer_Type.StatusBuffer) + } }, viewModel.selectedBufferId, viewModel.collapsedNetworks, 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/input/AutoCompleteAdapter.kt similarity index 72% rename from app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/AutoCompleteAdapter.kt rename to app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/input/AutoCompleteAdapter.kt index f96a87cb483998f9bfb229d097f0b9d86cba7125..62778a67e8307673cbf7cda0b99d4b3256bbed85 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/AutoCompleteAdapter.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/input/AutoCompleteAdapter.kt @@ -1,10 +1,8 @@ -package de.kuschku.quasseldroid_ng.ui.chat +package de.kuschku.quasseldroid_ng.ui.chat.input -import android.arch.lifecycle.LifecycleOwner -import android.arch.lifecycle.LiveData -import android.arch.lifecycle.Observer import android.graphics.drawable.Drawable import android.support.v4.graphics.drawable.DrawableCompat +import android.support.v7.recyclerview.extensions.ListAdapter import android.support.v7.util.DiffUtil import android.support.v7.widget.RecyclerView import android.view.LayoutInflater @@ -17,48 +15,22 @@ import butterknife.ButterKnife import de.kuschku.libquassel.quassel.BufferInfo import de.kuschku.libquassel.quassel.syncables.interfaces.INetwork import de.kuschku.quasseldroid_ng.R -import de.kuschku.quasseldroid_ng.ui.chat.NickListAdapter.Companion.VIEWTYPE_AWAY import de.kuschku.quasseldroid_ng.ui.chat.buffers.BufferListAdapter +import de.kuschku.quasseldroid_ng.ui.chat.nicks.NickListAdapter.Companion.VIEWTYPE_AWAY import de.kuschku.quasseldroid_ng.util.helper.getCompatDrawable import de.kuschku.quasseldroid_ng.util.helper.styledAttributes import de.kuschku.quasseldroid_ng.util.helper.visibleIf class AutoCompleteAdapter( - lifecycleOwner: LifecycleOwner, - liveData: LiveData<Pair<String, List<AutoCompleteItem>>?>, - runInBackground: (() -> Unit) -> Any, - runOnUiThread: (Runnable) -> Any, private val clickListener: ((String) -> Unit)? = null -) : RecyclerView.Adapter<AutoCompleteAdapter.AutoCompleteViewHolder>() { - var data = mutableListOf<AutoCompleteItem>() - - init { - liveData.observe( - lifecycleOwner, Observer { it: Pair<String, List<AutoCompleteItem>>? -> - runInBackground { - val word = it?.first ?: "" - val list = it?.second ?: emptyList() - val old: List<AutoCompleteItem> = data - val new: List<AutoCompleteItem> = if (word.length >= 3) list else emptyList() - val result = DiffUtil.calculateDiff( - object : DiffUtil.Callback() { - override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) = - old[oldItemPosition].name == new[newItemPosition].name - - 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) - }) - } - }) - } +) : ListAdapter<AutoCompleteAdapter.AutoCompleteItem, AutoCompleteAdapter.AutoCompleteViewHolder>( + object : DiffUtil.ItemCallback<AutoCompleteItem>() { + override fun areItemsTheSame(oldItem: AutoCompleteItem, newItem: AutoCompleteItem) = + oldItem.name == newItem.name + + override fun areContentsTheSame(oldItem: AutoCompleteItem, newItem: AutoCompleteItem) = + oldItem == newItem + }) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = when (viewType) { VIEWTYPE_CHANNEL -> AutoCompleteViewHolder.ChannelViewHolder( @@ -81,11 +53,9 @@ class AutoCompleteAdapter( } override fun onBindViewHolder(holder: AutoCompleteViewHolder, position: Int) = - holder.bind(data[position]) - - override fun getItemCount() = data.size + holder.bind(getItem(position)) - override fun getItemViewType(position: Int) = data[position].let { it -> + override fun getItemViewType(position: Int) = getItem(position).let { when { it is AutoCompleteItem.ChannelItem -> VIEWTYPE_CHANNEL it is AutoCompleteItem.UserItem && it.away -> VIEWTYPE_NICK_AWAY @@ -96,11 +66,11 @@ class AutoCompleteAdapter( sealed class AutoCompleteItem(open val name: String) : Comparable<AutoCompleteItem> { override fun compareTo(other: AutoCompleteItem): Int { return when { - this is AutoCompleteItem.UserItem && - other is AutoCompleteItem.ChannelItem -> -1 - this is AutoCompleteItem.ChannelItem && - other is AutoCompleteItem.UserItem -> 1 - else -> this.name.compareTo(other.name) + this is UserItem && + other is ChannelItem -> -1 + this is ChannelItem && + other is UserItem -> 1 + else -> this.name.compareTo(other.name) } } @@ -224,8 +194,8 @@ class AutoCompleteAdapter( } companion object { - val VIEWTYPE_CHANNEL = 0 - val VIEWTYPE_NICK_ACTIVE = 1 - val VIEWTYPE_NICK_AWAY = 2 + const val VIEWTYPE_CHANNEL = 0 + const val VIEWTYPE_NICK_ACTIVE = 1 + const val VIEWTYPE_NICK_AWAY = 2 } } \ No newline at end of file diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/input/Editor.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/input/Editor.kt new file mode 100644 index 0000000000000000000000000000000000000000..d7463e063bceb81a8950d3a800c70b9366e3c808 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/input/Editor.kt @@ -0,0 +1,224 @@ +package de.kuschku.quasseldroid_ng.ui.chat.input + +import android.arch.lifecycle.LiveData +import android.arch.lifecycle.MutableLiveData +import android.arch.lifecycle.Observer +import android.support.v7.app.AppCompatActivity +import android.support.v7.widget.* +import android.text.Editable +import android.text.InputType +import android.text.TextWatcher +import android.view.KeyEvent +import android.view.MenuItem +import android.view.inputmethod.EditorInfo +import de.kuschku.quasseldroid_ng.R +import de.kuschku.quasseldroid_ng.settings.AppearanceSettings +import de.kuschku.quasseldroid_ng.settings.Settings +import de.kuschku.quasseldroid_ng.ui.chat.ChatActivity +import de.kuschku.quasseldroid_ng.util.helper.lastWordIndices +import de.kuschku.quasseldroid_ng.util.helper.lineSequence +import de.kuschku.quasseldroid_ng.util.helper.retint +import io.reactivex.Observable +import io.reactivex.subjects.BehaviorSubject + +class Editor( + // Contexts + activity: AppCompatActivity, + // LiveData + private val autoCompleteData: LiveData<Pair<String, List<AutoCompleteAdapter.AutoCompleteItem>>?>, + lastWordContainer: MutableLiveData<Observable<Pair<String, IntRange>>>, + // Views + val chatline: AppCompatEditText, + send: AppCompatImageButton, + autoCompleteLists: List<RecyclerView>, + formattingMenu: ActionMenuView, + formattingToolbar: Toolbar, + // Listeners + private val sendCallback: (Sequence<Pair<CharSequence, String>>) -> Unit, + private val panelStateCallback: (Boolean) -> Unit +) : ActionMenuView.OnMenuItemClickListener, Toolbar.OnMenuItemClickListener { + override fun onMenuItemClick(item: MenuItem?) = when (item?.itemId) { + R.id.input_history -> { + panelStateCallback(true) + true + } + else -> formatHandler.onMenuItemClick(item) + } + + private val appearanceSettings = Settings.appearance(activity) + + private val lastWord = BehaviorSubject.createDefault(Pair("", IntRange.EMPTY)) + private val textWatcher = object : TextWatcher { + override fun afterTextChanged(s: Editable?) { + val previous = autocompletionState + val next = if (previous != null && s != null) { + val suffix = if (previous.range.start == 0) ": " else " " + val end = Math.min( + s.length, previous.range.start + previous.completion.name.length + suffix.length + ) + val sequence = s.substring(previous.range.start, end) + if (sequence == previous.completion.name + suffix) { + previous.originalWord to (previous.range.start until end) + } else { + autocompletionState = null + s.lastWordIndices(chatline.selectionStart, onlyBeforeCursor = true)?.let { indices -> + s.substring(indices) to indices + } + } + } else { + s?.lastWordIndices(chatline.selectionStart, onlyBeforeCursor = true)?.let { indices -> + s.substring(indices) to indices + } + } + + lastWord.onNext(next ?: Pair("", IntRange.EMPTY)) + } + + override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit + override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) = Unit + } + + val formatHandler = FormatHandler(chatline) + + private var autocompletionState: ChatActivity.AutoCompletionState? = null + + init { + send.setOnClickListener { + send() + } + + chatline.setOnKeyListener { _, keyCode, event -> + when (keyCode) { + KeyEvent.KEYCODE_ENTER, + KeyEvent.KEYCODE_NUMPAD_ENTER -> if (event.hasNoModifiers()) { + send() + true + } else { + false + } + KeyEvent.KEYCODE_TAB -> { + autoComplete(event.isShiftPressed) + true + } + else -> false + } + } + + 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.addTextChangedListener(textWatcher) + + + val autocompleteAdapter = AutoCompleteAdapter( + // This is still broken when mixing tab complete and UI auto complete + formatHandler::autoComplete + ) + + autoCompleteData.observe(activity, Observer { + val query = it?.first ?: "" + val list = if (query.length >= 3) it?.second.orEmpty() else emptyList() + + autocompleteAdapter.submitList(list) + }) + + if (appearanceSettings.showAutocomplete) { + for (autoCompleteList in autoCompleteLists) { + autoCompleteList.layoutManager = LinearLayoutManager(activity) + autoCompleteList.itemAnimator = DefaultItemAnimator() + autoCompleteList.adapter = autocompleteAdapter + } + } + + lastWordContainer.value = lastWord + + activity.menuInflater.inflate(formatHandler.menu, formattingMenu.menu) + formattingMenu.menu.retint(activity) + formattingMenu.setOnMenuItemClickListener(this) + + activity.menuInflater.inflate(R.menu.input_panel, formattingToolbar.menu) + formattingToolbar.menu.retint(activity) + formattingToolbar.setOnMenuItemClickListener(this) + } + + private fun send() { + if (rawText.isNotBlank()) { + sendCallback(strippedText.lineSequence().zip(formattedText)) + } + chatline.setText("") + } + + fun setMultiLine(enabled: Boolean) { + val selectionStart = chatline.selectionStart + val selectionEnd = chatline.selectionEnd + + if (enabled) { + chatline.inputType = chatline.inputType and InputType.TYPE_TEXT_FLAG_MULTI_LINE.inv() + } else { + chatline.inputType = chatline.inputType or InputType.TYPE_TEXT_FLAG_MULTI_LINE + } + + chatline.setSelection(selectionStart, selectionEnd) + } + + private fun autoComplete(reverse: Boolean = false) { + val originalWord = lastWord.value + + val previous = autocompletionState + if (!originalWord.second.isEmpty()) { + val autoCompletedWords = autoCompleteData.value?.second.orEmpty() + if (previous != null && lastWord.value.first == previous.originalWord && lastWord.value.second.start == previous.range.start) { + val previousIndex = autoCompletedWords.indexOf(previous.completion) + val autoCompletedWord = if (previousIndex != -1) { + val change = if (reverse) -1 else +1 + val newIndex = (previousIndex + change + autoCompletedWords.size) % autoCompletedWords.size + + autoCompletedWords[newIndex] + } else { + autoCompletedWords.firstOrNull() + } + if (autoCompletedWord != null) { + val newState = ChatActivity.AutoCompletionState( + previous.originalWord, + originalWord.second, + previous.completion, + autoCompletedWord + ) + autocompletionState = newState + formatHandler.autoComplete(newState) + } else { + autocompletionState = null + } + } else { + val autoCompletedWord = autoCompletedWords.firstOrNull() + if (autoCompletedWord != null) { + val newState = ChatActivity.AutoCompletionState( + originalWord.first, + originalWord.second, + null, + autoCompletedWord + ) + autocompletionState = newState + formatHandler.autoComplete(newState) + } else { + autocompletionState = null + } + } + } + } + + val formattedText: Sequence<String> + get() = formatHandler.formattedText + val rawText: CharSequence + get() = formatHandler.rawText + val strippedText: CharSequence + get() = formatHandler.strippedText +} \ No newline at end of file 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/input/FormatHandler.kt similarity index 89% rename from app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/InputEditor.kt rename to app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/input/FormatHandler.kt index 82aac52f62a00edb552ea886d65f4506ba2dac21..71502038656472a1758b0e5cf23f3c74da95f5b0 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/input/FormatHandler.kt @@ -1,8 +1,9 @@ -package de.kuschku.quasseldroid_ng.ui.chat +package de.kuschku.quasseldroid_ng.ui.chat.input import android.graphics.Typeface import android.support.annotation.MenuRes import android.text.Editable +import android.text.SpannableString import android.text.Spanned import android.text.style.StrikethroughSpan import android.text.style.StyleSpan @@ -11,15 +12,33 @@ import android.text.style.UnderlineSpan import android.view.MenuItem import android.widget.EditText import de.kuschku.quasseldroid_ng.R +import de.kuschku.quasseldroid_ng.ui.chat.ChatActivity import de.kuschku.quasseldroid_ng.util.helper.lastWordIndices +import de.kuschku.quasseldroid_ng.util.helper.lineSequence import de.kuschku.quasseldroid_ng.util.helper.selection import de.kuschku.quasseldroid_ng.util.irc.format.IrcFormatSerializer import de.kuschku.quasseldroid_ng.util.irc.format.spans.* -class InputEditor(private val editText: EditText) { +class FormatHandler(private val editText: EditText) { private val serializer = IrcFormatSerializer(editText.context) - val formattedString: String - get() = serializer.toEscapeCodes(editText.text) + val formattedText: Sequence<String> + get() = editText.text.lineSequence().map { serializer.toEscapeCodes(SpannableString(it)) } + val rawText: CharSequence + get() = editText.text + val strippedText: CharSequence + get() = editText.text.let { + val text = SpannableString(it) + val toRemove = mutableListOf<Any>() + for (span in text.getSpans(0, text.length, Any::class.java)) { + if ((text.getSpanFlags(span) and Spanned.SPAN_COMPOSING) != 0) { + toRemove.add(span) + } + } + for (span in toRemove) { + text.removeSpan(span) + } + text + } @MenuRes val menu: Int = R.menu.editor @@ -243,7 +262,7 @@ class InputEditor(private val editText: EditText) { } } - fun share(text: CharSequence?) { + fun replace(text: CharSequence?) { editText.setText(text) editText.setSelection(editText.text.length) } diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/input/MessageHistoryAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/input/MessageHistoryAdapter.kt new file mode 100644 index 0000000000000000000000000000000000000000..8c784e2752e116ed748e30a54f25c2e7a8f1f8f3 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/input/MessageHistoryAdapter.kt @@ -0,0 +1,57 @@ +package de.kuschku.quasseldroid_ng.ui.chat.input + +import android.support.v7.recyclerview.extensions.ListAdapter +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 + +class MessageHistoryAdapter( + private val clickListener: ((CharSequence) -> Unit)? = null +) : ListAdapter<CharSequence, MessageHistoryAdapter.MessageViewHolder>( + object : DiffUtil.ItemCallback<CharSequence>() { + override fun areItemsTheSame(oldItem: CharSequence?, newItem: CharSequence?) = + oldItem === newItem + + override fun areContentsTheSame(oldItem: CharSequence?, newItem: CharSequence?) = + oldItem == newItem + }) { + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = + MessageViewHolder( + LayoutInflater.from(parent.context).inflate(R.layout.widget_history_message, parent, false), + clickListener = clickListener + ) + + override fun onBindViewHolder(holder: MessageViewHolder, position: Int) = + holder.bind(getItem(position)) + + class MessageViewHolder( + itemView: View, + private val clickListener: ((CharSequence) -> Unit)? = null + ) : RecyclerView.ViewHolder(itemView) { + @BindView(R.id.content) + lateinit var content: TextView + + var value: CharSequence? = null + + init { + ButterKnife.bind(this, itemView) + itemView.setOnClickListener { + val value = value + if (value != null) + clickListener?.invoke(value) + } + } + + fun bind(data: CharSequence) { + value = data + + content.text = data + } + } +} \ No newline at end of file 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 57bbb6fd7172ffc0d2d4cd519482ec2b67f9e73e..1eb2082c2b26fda9a7b4178d014463c5a3d889be 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 @@ -8,7 +8,6 @@ import android.view.LayoutInflater import android.view.ViewGroup 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.settings.AppearanceSettings import de.kuschku.quasseldroid_ng.util.helper.getOrPut @@ -17,19 +16,16 @@ class MessageAdapter( context: Context, appearanceSettings: AppearanceSettings, var markerLinePosition: Pair<MsgId, MsgId>? = null -) : PagedListAdapter<QuasselDatabase.DatabaseMessage, QuasselMessageViewHolder>( - object : DiffUtil.ItemCallback<QuasselDatabase.DatabaseMessage>() { - override fun areItemsTheSame(oldItem: QuasselDatabase.DatabaseMessage, - newItem: QuasselDatabase.DatabaseMessage) = - DatabaseMessage.MessageDiffCallback.areItemsTheSame(oldItem, newItem) +) : PagedListAdapter<DatabaseMessage, QuasselMessageViewHolder>( + object : DiffUtil.ItemCallback<DatabaseMessage>() { + override fun areItemsTheSame(oldItem: DatabaseMessage, newItem: DatabaseMessage) = + oldItem.messageId == newItem.messageId - override fun areContentsTheSame(oldItem: QuasselDatabase.DatabaseMessage, - newItem: QuasselDatabase.DatabaseMessage) = - DatabaseMessage.MessageDiffCallback.areContentsTheSame(oldItem, newItem) && + override fun areContentsTheSame(oldItem: DatabaseMessage, newItem: DatabaseMessage) = + oldItem == newItem && oldItem.messageId != markerLinePosition?.first && oldItem.messageId != markerLinePosition?.second - } -) { + }) { private val messageRenderer: MessageRenderer = QuasselMessageRenderer( context, appearanceSettings @@ -53,8 +49,7 @@ class MessageAdapter( messageCache.getOrPut(it.messageId) { messageRenderer.render(it, markerLinePosition?.second ?: -1) } - } - ) + }) } } @@ -67,13 +62,12 @@ class MessageAdapter( } } - private fun viewType(type: Message_Types, flags: Message_Flags): Int { + private fun viewType(type: Message_Types, flags: Message_Flags) = if (flags.hasFlag(Message_Flag.Highlight)) { - return -type.value + -type.value } else { - return type.value + type.value } - } override fun getItemId(position: Int): Long { return getItem(position)?.messageId?.toLong() ?: 0L 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 7513fbe59497b541256a0c52c7c4885e71775706..49a76a1e9f289781e02eec13d300c6f40c5bd742 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 @@ -84,8 +84,7 @@ class MessageListFragment : ServiceBoundFragment() { scrollDown.visibility = View.VISIBLE scrollDown.toggle(canScrollDown && isScrollingDown) } - } - ) + }) database = QuasselDatabase.Creator.init(context!!.applicationContext) val data = viewModel.getBuffer().switchMapNotNull { buffer -> @@ -136,16 +135,14 @@ class MessageListFragment : ServiceBoundFragment() { lastBuffer = buffer } } - } - ) + }) } viewModel.markerLine.observe( this, Observer { adapter.markerLinePosition = it adapter.notifyDataSetChanged() - } - ) + }) var lastBuffer = -1 data.observe( @@ -161,8 +158,7 @@ class MessageListFragment : ServiceBoundFragment() { activity?.runOnUiThread { messageList.scrollToPosition(0) } handler.postDelayed({ activity?.runOnUiThread { messageList.scrollToPosition(0) } }, 16) } - } - ) + }) scrollDown.hide() scrollDown.setOnClickListener { messageList.scrollToPosition(0) } return view 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 99c5e96133425ef196d79e3ec6d7e535dae4abab..74836d7b1a4a8fd31322626d983e1c60a5fcd0cf 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 @@ -333,8 +333,7 @@ class QuasselMessageRenderer( } /* for (result in channelPattern.findAll(content)) { - text.setSpan(URLSpan(result.value), result.range.start, result.range.endInclusive, Spanned.SPAN_INCLUSIVE_INCLUSIVE) - } + text.setSpan(URLSpan(result.value), result.range.start, result.range.endInclusive, Spanned.SPAN_INCLUSIVE_INCLUSIVE)} */ return text diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/nicks/NickListAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/nicks/NickListAdapter.kt new file mode 100644 index 0000000000000000000000000000000000000000..2b1a21ee64e6bde3ece12b3b87e386de6a9d6654 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/nicks/NickListAdapter.kt @@ -0,0 +1,96 @@ +package de.kuschku.quasseldroid_ng.ui.chat.nicks + +import android.support.v7.recyclerview.extensions.ListAdapter +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 + +class NickListAdapter( + private val clickListener: ((String) -> Unit)? = null +) : ListAdapter<NickListAdapter.IrcUserItem, NickListAdapter.NickViewHolder>( + object : DiffUtil.ItemCallback<IrcUserItem>() { + override fun areItemsTheSame(oldItem: IrcUserItem, newItem: IrcUserItem) = + oldItem.nick == newItem.nick + + override fun areContentsTheSame(oldItem: IrcUserItem?, newItem: IrcUserItem?) = + oldItem == newItem + }) { + 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(getItem(position)) + + override fun getItemViewType(position: Int) = if (getItem(position).away) { + VIEWTYPE_AWAY + } else { + VIEWTYPE_ACTIVE + } + + data class IrcUserItem( + val nick: String, + val modes: String, + val lowestMode: Int, + val realname: CharSequence, + val away: Boolean, + val networkCasemapping: String + ) + + 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: 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/NickListFragment.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/nicks/NickListFragment.kt similarity index 69% rename from app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/NickListFragment.kt rename to app/src/main/java/de/kuschku/quasseldroid_ng/ui/chat/nicks/NickListFragment.kt index 5ff1deaa63b5a14f26818c1659bfaf284beefa41..ba8d29d332b393a6720b2d43774e59f5d56698c1 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/nicks/NickListFragment.kt @@ -1,5 +1,6 @@ -package de.kuschku.quasseldroid_ng.ui.chat +package de.kuschku.quasseldroid_ng.ui.chat.nicks +import android.arch.lifecycle.Observer import android.arch.lifecycle.ViewModelProviders import android.os.Bundle import android.support.v7.widget.DefaultItemAnimator @@ -10,6 +11,7 @@ import android.view.View import android.view.ViewGroup import butterknife.BindView import butterknife.ButterKnife +import de.kuschku.libquassel.util.irc.IrcCaseMappers import de.kuschku.quasseldroid_ng.R import de.kuschku.quasseldroid_ng.settings.AppearanceSettings import de.kuschku.quasseldroid_ng.settings.Settings @@ -47,32 +49,29 @@ class NickListFragment : ServiceBoundFragment() { val view = inflater.inflate(R.layout.fragment_nick_list, container, false) ButterKnife.bind(this, view) - nickList.adapter = NickListAdapter( - this, - viewModel.nickData.map { - it.map { - it.copy( - modes = when (appearanceSettings.showPrefix) { - AppearanceSettings.ShowPrefixMode.ALL -> it.modes - else -> it.modes.substring( - 0, Math.min( - it.modes.length, 1 - ) - ) - }, - realname = ircFormatDeserializer?.formatString( - it.realname.toString(), appearanceSettings.colorizeMirc - ) ?: it.realname - ) - } - }, - handlerThread::post, - activity!!::runOnUiThread, - clickListener - ) - + val nickListAdapter = NickListAdapter(clickListener) + nickList.adapter = nickListAdapter nickList.layoutManager = LinearLayoutManager(context) nickList.itemAnimator = DefaultItemAnimator() + viewModel.nickData.map { + it.map { + it.copy( + modes = when (appearanceSettings.showPrefix) { + AppearanceSettings.ShowPrefixMode.ALL -> + it.modes + else -> + it.modes.substring(0, Math.min(it.modes.length, 1)) + }, + realname = ircFormatDeserializer?.formatString( + it.realname.toString(), appearanceSettings.colorizeMirc + ) ?: it.realname + ) + }.sortedBy { + IrcCaseMappers[it.networkCasemapping].toLowerCase(it.nick) + }.sortedBy { + it.lowestMode + } + }.observe(this, Observer(nickListAdapter::submitList)) return view } diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/SetupActivity.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/SetupActivity.kt index 8ff4782130e2cf162e5752af6694eeab6f4367d6..1ec6a99efbf8480a334d6353a039f8f95f02b0cf 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/SetupActivity.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/SetupActivity.kt @@ -63,8 +63,8 @@ abstract class SetupActivity : AppCompatActivity() { currentPage.value?.requestFocus() } - fun updateRecentsHeader() - = updateRecentsHeaderIfExisting(title.toString(), icon, recentsHeaderColor) + fun updateRecentsHeader() = + updateRecentsHeaderIfExisting(title.toString(), icon, recentsHeaderColor) override fun setTitle(title: CharSequence?) { super.setTitle(title) @@ -96,8 +96,7 @@ abstract class SetupActivity : AppCompatActivity() { button.hide() adapter.lastValidItem = viewPager.currentItem - 1 } - } - ) + }) viewPager.addOnPageChangeListener(pageChangeListener) pageChanged() updateRecentsHeader() diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountEditActivity.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountEditActivity.kt index e564e80a50e3dce28986b43277affd9a95b4ea76..a7e2a41da8e03844828779b178266a74497981c4 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountEditActivity.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountEditActivity.kt @@ -82,29 +82,26 @@ class AccountEditActivity : AppCompatActivity() { nameValidator = object : TextValidator( nameWrapper::setError, resources.getString(R.string.hintInvalidName) ) { - override fun validate(text: Editable) - = text.isNotBlank() + override fun validate(text: Editable) = text.isNotBlank() } hostValidator = object : TextValidator( hostWrapper::setError, resources.getString(R.string.hintInvalidHost) ) { - override fun validate(text: Editable) - = text.toString().matches(Patterns.DOMAIN_NAME.toRegex()) + override fun validate(text: Editable) = + text.toString().matches(Patterns.DOMAIN_NAME.toRegex()) } portValidator = object : TextValidator( portWrapper::setError, resources.getString(R.string.hintInvalidPort) ) { - override fun validate(text: Editable) - = text.toString().toIntOrNull() in (0 until 65536) + override fun validate(text: Editable) = text.toString().toIntOrNull() in (0 until 65536) } userValidator = object : TextValidator( userWrapper::setError, resources.getString(R.string.hintInvalidUser) ) { - override fun validate(text: Editable) - = text.isNotBlank() + override fun validate(text: Editable) = text.isNotBlank() } name.addTextChangedListener(nameValidator) diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSetupConnectionSlide.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSetupConnectionSlide.kt index e9fdc5a9b99d6c4199a9360b09bcc3ee63b5756a..23a837b86ab086d0b7f41993d48d6a94dbc55115 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSetupConnectionSlide.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSetupConnectionSlide.kt @@ -53,16 +53,15 @@ class AccountSetupConnectionSlide : SlideFragment() { hostValidator = object : TextValidator( hostWrapper::setError, resources.getString(R.string.hintInvalidHost) ) { - override fun validate(text: Editable) - = text.toString().matches(Patterns.DOMAIN_NAME.toRegex()) + override fun validate(text: Editable) = + text.toString().matches(Patterns.DOMAIN_NAME.toRegex()) override fun onChanged() = updateValidity() } portValidator = object : TextValidator( portWrapper::setError, resources.getString(R.string.hintInvalidPort) ) { - override fun validate(text: Editable) - = text.toString().toIntOrNull() in (0 until 65536) + override fun validate(text: Editable) = text.toString().toIntOrNull() in (0 until 65536) override fun onChanged() = updateValidity() } diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSetupNameSlide.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSetupNameSlide.kt index 2e0f8c4298e590a881ef21d1d9470a4febe2f3d9..ab839228c781ab8bdb53e0549944d917e18fb2e2 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSetupNameSlide.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSetupNameSlide.kt @@ -43,8 +43,7 @@ class AccountSetupNameSlide : SlideFragment() { nameValidator = object : TextValidator( nameWrapper::setError, resources.getString(R.string.hintInvalidName) ) { - override fun validate(text: Editable) - = text.isNotBlank() + override fun validate(text: Editable) = text.isNotBlank() override fun onChanged() = updateValidity() } diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSetupUserSlide.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSetupUserSlide.kt index f995d230fbff84b189fa53a4a7fb7b86183b306b..b9fa2556eb414646dccfe2761d8c5439ea6ef81a 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSetupUserSlide.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSetupUserSlide.kt @@ -50,8 +50,7 @@ class AccountSetupUserSlide : SlideFragment() { userValidator = object : TextValidator( userWrapper::setError, resources.getString(R.string.hintInvalidUser) ) { - override fun validate(text: Editable) - = text.isNotBlank() + override fun validate(text: Editable) = text.isNotBlank() override fun onChanged() = updateValidity() } diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/viewmodel/QuasselViewModel.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/viewmodel/QuasselViewModel.kt index 20971dc9e7f2a414c13b1432014951e9ca3a9f48..fa61f0f236187782d655769fd66b4d27c7cec2ed 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/viewmodel/QuasselViewModel.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/viewmodel/QuasselViewModel.kt @@ -16,11 +16,11 @@ import de.kuschku.libquassel.session.ISession import de.kuschku.libquassel.session.SessionManager import de.kuschku.libquassel.util.and import de.kuschku.libquassel.util.hasFlag -import de.kuschku.quasseldroid_ng.ui.chat.AutoCompleteAdapter -import de.kuschku.quasseldroid_ng.ui.chat.NickListAdapter import de.kuschku.quasseldroid_ng.ui.chat.ToolbarFragment import de.kuschku.quasseldroid_ng.ui.chat.buffers.BufferListAdapter import de.kuschku.quasseldroid_ng.ui.chat.buffers.BufferViewConfigFragment +import de.kuschku.quasseldroid_ng.ui.chat.input.AutoCompleteAdapter +import de.kuschku.quasseldroid_ng.ui.chat.nicks.NickListAdapter import de.kuschku.quasseldroid_ng.util.helper.* import io.reactivex.Observable import java.util.concurrent.TimeUnit @@ -184,8 +184,7 @@ class QuasselViewModel : ViewModel() { } } } - } - ) + }) } } else { Observable.just(emptyList()) diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/Patterns.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/Patterns.kt index 4ae713468fc78f9eed13e71c16ac14b87db80183..52ce7acf83e340f13be5ffcf9f8e232a4677f176 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/util/Patterns.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/Patterns.kt @@ -6,58 +6,47 @@ import java.util.regex.Pattern @SuppressWarnings("Access") object Patterns { @Language("RegExp") - const val IPv4 - = "(?:(?:[0-1]?[0-9]?[0-9]|2[0-5][0-5])\\.){3}(?:[0-1]?[0-9]?[0-9]|2[0-5][0-5])" + const val IPv4 = "(?:(?:[0-1]?[0-9]?[0-9]|2[0-5][0-5])\\.){3}(?:[0-1]?[0-9]?[0-9]|2[0-5][0-5])" @Language("RegExp") - const val IPv6 - = "(?:(?:(?:[0-9a-fA-F]{1,4}:){7}(?:[0-9a-fA-F]{1,4}))|(?:(?:(?:[0-9a-fA-F]{1,4}:){1,7}|:):(?:[0-9a-fA-F]{1,4}))|(?:(?:(?:[0-9a-fA-F]{1,4}:){1,6}|:):(?:[0-9a-fA-F]{1,4}:)?(?:[0-9a-fA-F]{1,4}))|(?:(?:(?:[0-9a-fA-F]{1,4}:){1,5}|:):(?:[0-9a-fA-F]{1,4}:){0,2}(?:[0-9a-fA-F]{1,4}))|(?:(?:(?:[0-9a-fA-F]{1,4}:){1,4}|:):(?:[0-9a-fA-F]{1,4}:){0,3}(?:[0-9a-fA-F]{1,4}))|(?:(?:(?:[0-9a-fA-F]{1,4}:){1,3}|:):(?:[0-9a-fA-F]{1,4}:){1,4}(?:[0-9a-fA-F]{1,4}))|(?:(?:(?:[0-9a-fA-F]{1,4}:){1,2}|:):(?:[0-9a-fA-F]{1,4}:){0,5}(?:[0-9a-fA-F]{1,4}))|(?:(?:(?:[0-9a-fA-F]{1,4}:)|:):(?:[0-9a-fA-F]{1,4}:){0,6}(?:[0-9a-fA-F]{1,4})))" + const val IPv6 = "(?:(?:(?:[0-9a-fA-F]{1,4}:){7}(?:[0-9a-fA-F]{1,4}))|(?:(?:(?:[0-9a-fA-F]{1,4}:){1,7}|:):(?:[0-9a-fA-F]{1,4}))|(?:(?:(?:[0-9a-fA-F]{1,4}:){1,6}|:):(?:[0-9a-fA-F]{1,4}:)?(?:[0-9a-fA-F]{1,4}))|(?:(?:(?:[0-9a-fA-F]{1,4}:){1,5}|:):(?:[0-9a-fA-F]{1,4}:){0,2}(?:[0-9a-fA-F]{1,4}))|(?:(?:(?:[0-9a-fA-F]{1,4}:){1,4}|:):(?:[0-9a-fA-F]{1,4}:){0,3}(?:[0-9a-fA-F]{1,4}))|(?:(?:(?:[0-9a-fA-F]{1,4}:){1,3}|:):(?:[0-9a-fA-F]{1,4}:){1,4}(?:[0-9a-fA-F]{1,4}))|(?:(?:(?:[0-9a-fA-F]{1,4}:){1,2}|:):(?:[0-9a-fA-F]{1,4}:){0,5}(?:[0-9a-fA-F]{1,4}))|(?:(?:(?:[0-9a-fA-F]{1,4}:)|:):(?:[0-9a-fA-F]{1,4}:){0,6}(?:[0-9a-fA-F]{1,4})))" @Language("RegExp") const val IP_ADDRESS_STRING = """(?:$IPv4|$IPv6)""" @Language("RegExp") - const val UCS_CHAR - = "[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\uD800\uDC00-\uD83F\uDFFD\uD840\uDC00-\uD87F\uDFFD\uD880\uDC00-\uD8BF\uDFFD\uD8C0\uDC00-\uD8FF\uDFFD\uD900\uDC00-\uD93F\uDFFD\uD940\uDC00-\uD97F\uDFFD\uD980\uDC00-\uD9BF\uDFFD\uD9C0\uDC00-\uD9FF\uDFFD\uDA00\uDC00-\uDA3F\uDFFD\uDA40\uDC00-\uDA7F\uDFFD\uDA80\uDC00-\uDABF\uDFFD\uDAC0\uDC00-\uDAFF\uDFFD\uDB00\uDC00-\uDB3F\uDFFD\uDB44\uDC00-\uDB7F\uDFFD&&[^\u00A0[\u2000-\u200A]\u2028\u2029\u202F\u3000]]" + const val UCS_CHAR = "[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF\uD800\uDC00-\uD83F\uDFFD\uD840\uDC00-\uD87F\uDFFD\uD880\uDC00-\uD8BF\uDFFD\uD8C0\uDC00-\uD8FF\uDFFD\uD900\uDC00-\uD93F\uDFFD\uD940\uDC00-\uD97F\uDFFD\uD980\uDC00-\uD9BF\uDFFD\uD9C0\uDC00-\uD9FF\uDFFD\uDA00\uDC00-\uDA3F\uDFFD\uDA40\uDC00-\uDA7F\uDFFD\uDA80\uDC00-\uDABF\uDFFD\uDAC0\uDC00-\uDAFF\uDFFD\uDB00\uDC00-\uDB3F\uDFFD\uDB44\uDC00-\uDB7F\uDFFD&&[^\u00A0[\u2000-\u200A]\u2028\u2029\u202F\u3000]]" /** * Valid characters for IRI label defined in RFC 3987. */ @Language("RegExp") - const val LABEL_CHAR - = """a-zA-Z0-9$UCS_CHAR""" + const val LABEL_CHAR = """a-zA-Z0-9$UCS_CHAR""" /** * Valid characters for IRI TLD defined in RFC 3987. */ @Language("RegExp") - const val TLD_CHAR - = """a-zA-Z$UCS_CHAR""" + const val TLD_CHAR = """a-zA-Z$UCS_CHAR""" /** * RFC 1035 Section 2.3.4 limits the labels to a maximum 63 octets. */ @Language("RegExp") - const val IRI_LABEL - = """[$LABEL_CHAR](?:[${LABEL_CHAR}_\-]{0,61}[$LABEL_CHAR])?""" + const val IRI_LABEL = """[$LABEL_CHAR](?:[${LABEL_CHAR}_\-]{0,61}[$LABEL_CHAR])?""" /** * RFC 3492 references RFC 1034 and limits Punycode algorithm output to 63 characters. */ @Language("RegExp") - const val PUNYCODE_TLD - = """xn--[\w\-]{0,58}\w""" + const val PUNYCODE_TLD = """xn--[\w\-]{0,58}\w""" @Language("RegExp") - const val TLD - = """(?:$PUNYCODE_TLD|[$TLD_CHAR]{2,63})""" + const val TLD = """(?:$PUNYCODE_TLD|[$TLD_CHAR]{2,63})""" @Language("RegExp") - const val HOST_NAME - = """(?:$IRI_LABEL\.)+$TLD.?""" + const val HOST_NAME = """(?:$IRI_LABEL\.)+$TLD.?""" @Language("RegExp") - const val LOCAL_HOST_NAME - = """(?:$IRI_LABEL\.)*$IRI_LABEL""" + const val LOCAL_HOST_NAME = """(?:$IRI_LABEL\.)*$IRI_LABEL""" @Language("RegExp") - const val DOMAIN_NAME_STR - = """(?:$LOCAL_HOST_NAME|$HOST_NAME|$IP_ADDRESS_STRING)""" + const val DOMAIN_NAME_STR = """(?:$LOCAL_HOST_NAME|$HOST_NAME|$IP_ADDRESS_STRING)""" val DOMAIN_NAME: Pattern = Pattern.compile(DOMAIN_NAME_STR) } diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/ContextHelper.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/ContextHelper.kt index 4d656cc54e30e11d38a3127dcc5d3831efc090b4..f62f03f2cf0773d8a39054dff437f9013f3d8aff 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/ContextHelper.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/ContextHelper.kt @@ -18,11 +18,12 @@ fun Context.getStatusBarHeight(): Int { return result } -inline fun <reified T> Context.systemService(): T = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - getSystemService(T::class.java) -} else { - getSystemService(T::class.java.simpleName) as T -} +inline fun <reified T> Context.systemService(): T = + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + getSystemService(T::class.java) + } else { + getSystemService(T::class.java.simpleName) as T + } fun Context.getCompatDrawable(@DrawableRes id: Int): Drawable { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/LiveDataHelper.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/LiveDataHelper.kt index 5c81c989806fd9c0659e7c19ce54769765e8bbff..b44582900bdbb0d4f45c9658d3f6f12df70717cf 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/LiveDataHelper.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/LiveDataHelper.kt @@ -27,8 +27,7 @@ inline fun <X, Y> LiveData<X?>.switchMap( result.value = null } } - } - ) + }) return result } @@ -54,8 +53,7 @@ inline fun <X, Y> LiveData<X>.switchMapNotNull( result.value = null } } - } - ) + }) return result } @@ -82,8 +80,7 @@ inline fun <X, Y> LiveData<X?>.switchMapRx( result.value = null } } - } - ) + }) return result } @@ -139,8 +136,8 @@ inline fun <T> LiveData<T>.observeForeverSticky(observer: Observer<T>) { observer.onChanged(value) } -inline fun <T> LiveData<T>.toObservable(lifecycleOwner: LifecycleOwner): Observable<T> - = Observable.fromPublisher(LiveDataReactiveStreams.toPublisher(lifecycleOwner, this)) +inline fun <T> LiveData<T>.toObservable(lifecycleOwner: LifecycleOwner): Observable<T> = + Observable.fromPublisher(LiveDataReactiveStreams.toPublisher(lifecycleOwner, this)) inline operator fun <T> LiveData<T>.invoke() = value diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/MenuHelper.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/MenuHelper.kt new file mode 100644 index 0000000000000000000000000000000000000000..d2d70dcb4a87e7442964c6bb3b25fb8cc6c7a8a0 --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/MenuHelper.kt @@ -0,0 +1,18 @@ +package de.kuschku.quasseldroid_ng.util.helper + +import android.content.Context +import android.support.v4.graphics.drawable.DrawableCompat +import android.view.Menu +import de.kuschku.quasseldroid_ng.R + +fun Menu.retint(context: Context) { + context.theme.styledAttributes(R.attr.colorControlNormal) { + val color = getColor(0, 0) + + for (item in (0 until size()).map { getItem(it) }) { + val drawable = item.icon.mutate() + DrawableCompat.setTint(drawable, color) + item.icon = drawable + } + } +} \ No newline at end of file diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/ThemeHelper.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/ThemeHelper.kt index 137e10e6d36ed942b61d09c6279610ca1bc61a9a..3b62d67e5a900536cedafd051b5e1d76a1c0eed5 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/ThemeHelper.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/helper/ThemeHelper.kt @@ -3,10 +3,10 @@ package de.kuschku.quasseldroid_ng.util.helper import android.content.res.Resources import android.content.res.TypedArray -inline fun <R> Resources.Theme.styledAttributes(vararg attributes: Int, f: TypedArray.() -> R) - = this.obtainStyledAttributes(attributes).run { - f() -} +inline fun <R> Resources.Theme.styledAttributes(vararg attributes: Int, f: TypedArray.() -> R) = + this.obtainStyledAttributes(attributes).run { + f() + } inline fun <R> TypedArray.use(block: (TypedArray) -> R): R { val result = block(this) diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/util/irc/format/IrcFormatDeserializer.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/util/irc/format/IrcFormatDeserializer.kt index 51035256600bbda617cd635e0fa30b07a70b3941..641daf540b4a03abe7ac31bc26f536208603c6bc 100644 --- a/app/src/main/java/de/kuschku/quasseldroid_ng/util/irc/format/IrcFormatDeserializer.kt +++ b/app/src/main/java/de/kuschku/quasseldroid_ng/util/irc/format/IrcFormatDeserializer.kt @@ -90,7 +90,7 @@ class IrcFormatDeserializer(private val context: Context) { while (i < str.length) { val character = str[i] when (character) { - CODE_BOLD -> { + CODE_BOLD -> { plainText.append(str.substring(i - normalCount, i)) normalCount = 0 @@ -116,7 +116,7 @@ class IrcFormatDeserializer(private val context: Context) { italic = FormatDescription(plainText.length, ItalicIrcFormat()) } } - CODE_UNDERLINE -> { + CODE_UNDERLINE -> { plainText.append(str.substring(i - normalCount, i)) normalCount = 0 @@ -241,7 +241,7 @@ class IrcFormatDeserializer(private val context: Context) { ) } } - CODE_RESET -> { + CODE_RESET -> { plainText.append(str.substring(i - normalCount, i)) normalCount = 0 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 ed35f704fbcee23297c5d095b4dbb17e4cbb22cc..62a2351b063a7ab41b87e4817cc9cd10c9cd3081 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 @@ -49,8 +49,8 @@ abstract class ServiceBoundActivity : AppCompatActivity(), updateRecentsHeader() } - fun updateRecentsHeader() - = updateRecentsHeaderIfExisting(title.toString(), icon, recentsHeaderColor) + fun updateRecentsHeader() = + updateRecentsHeaderIfExisting(title.toString(), icon, recentsHeaderColor) override fun setTitle(title: CharSequence?) { super.setTitle(title) diff --git a/app/src/main/res/layout-sw720dp-land/activity_main.xml b/app/src/main/res/layout-sw720dp-land/activity_main.xml index 7af3ba7a1e84bea436eefcdf583232c95143c7c9..3e3145e8d8cfb32e18e83c8be70cf3270e7d3732 100644 --- a/app/src/main/res/layout-sw720dp-land/activity_main.xml +++ b/app/src/main/res/layout-sw720dp-land/activity_main.xml @@ -47,7 +47,7 @@ <fragment android:id="@+id/fragment_nick_list" - android:name="de.kuschku.quasseldroid_ng.ui.chat.NickListFragment" + android:name="de.kuschku.quasseldroid_ng.ui.chat.nicks.NickListFragment" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="end" diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 6df810bd322bf94d06129e5abfe9534c665023b7..908b2b8d77b8defbb261899531d8e7693db4ee00 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -10,7 +10,7 @@ <fragment android:id="@+id/fragment_nick_list" - android:name="de.kuschku.quasseldroid_ng.ui.chat.NickListFragment" + android:name="de.kuschku.quasseldroid_ng.ui.chat.nicks.NickListFragment" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="end" diff --git a/app/src/main/res/layout/layout_editor.xml b/app/src/main/res/layout/layout_editor.xml index c98d345702e6e792f1256380bdc9e362cacc1d22..8af1417d769c33906fb2029b2f70c64e0c3215b5 100644 --- a/app/src/main/res/layout/layout_editor.xml +++ b/app/src/main/res/layout/layout_editor.xml @@ -8,7 +8,7 @@ android:id="@+id/chatline_scroller" android:layout_width="0dp" android:layout_height="0dp" - app:layout_constraintBottom_toTopOf="@+id/autocomplete_list2" + app:layout_constraintBottom_toTopOf="@+id/autocomplete_list_expanded" app:layout_constraintEnd_toStartOf="@+id/send" app:layout_constraintHorizontal_bias="1.0" app:layout_constraintStart_toStartOf="parent" @@ -30,7 +30,6 @@ android:paddingTop="8dp" android:textColor="?attr/colorForeground" android:textSize="16sp" /> - </ScrollView> <android.support.v7.widget.AppCompatImageButton @@ -47,7 +46,7 @@ app:srcCompat="@drawable/ic_send" /> <de.kuschku.quasseldroid_ng.util.ui.AutoCompleteRecyclerView - android:id="@+id/autocomplete_list2" + android:id="@+id/autocomplete_list_expanded" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_constraintBottom_toTopOf="@+id/formatting_toolbar_container" /> @@ -65,12 +64,16 @@ android:layout_width="match_parent" android:layout_height="?attr/actionBarSize"> - <android.support.v7.widget.ActionMenuView - android:id="@+id/formatting_menu" + <HorizontalScrollView android:layout_width="match_parent" - android:layout_height="?attr/actionBarSize" /> + android:layout_height="match_parent"> + <android.support.v7.widget.ActionMenuView + android:id="@+id/formatting_menu" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:theme="?attr/formatBarTheme" /> + </HorizontalScrollView> </android.support.v7.widget.Toolbar> - </android.support.design.widget.AppBarLayout> </android.support.constraint.ConstraintLayout> \ No newline at end of file diff --git a/app/src/main/res/menu/editor.xml b/app/src/main/res/menu/editor.xml index f50026af71408b0a2a1f2274792e05ed32899eae..3add5e54ebb575acc1bd45651ab500e74edca737 100644 --- a/app/src/main/res/menu/editor.xml +++ b/app/src/main/res/menu/editor.xml @@ -26,7 +26,6 @@ android:icon="@drawable/ic_format_monospace" android:title="@string/label_monospace" app:showAsAction="always" /> - <!-- <item android:id="@+id/format_foreground" android:icon="@drawable/ic_format_foreground" @@ -37,7 +36,6 @@ android:icon="@drawable/ic_format_background" android:title="@string/label_background" app:showAsAction="always" /> - --> <item android:id="@+id/format_clear" android:icon="@drawable/ic_format_clear" diff --git a/app/src/main/res/values-sw720dp/bools.xml b/app/src/main/res/values-sw720dp/bools.xml new file mode 100644 index 0000000000000000000000000000000000000000..4faec7d15be37131fb8559db83c442574c9adbe7 --- /dev/null +++ b/app/src/main/res/values-sw720dp/bools.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <bool name="buffer_drawer_exists">false</bool> +</resources> \ No newline at end of file diff --git a/app/src/main/res/values/bools.xml b/app/src/main/res/values/bools.xml new file mode 100644 index 0000000000000000000000000000000000000000..d56dfc8c3474f259dec7ec8b5f638170fd257831 --- /dev/null +++ b/app/src/main/res/values/bools.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <bool name="buffer_drawer_exists">true</bool> +</resources> \ No newline at end of file diff --git a/app/src/main/res/values/strings_preferences.xml b/app/src/main/res/values/strings_preferences.xml index d9d856e155f04d55da5850d063ad73e16e659793..4fac01a4fc27f604ec222e992ac6f8ca2eda7c86 100644 --- a/app/src/main/res/values/strings_preferences.xml +++ b/app/src/main/res/values/strings_preferences.xml @@ -106,9 +106,9 @@ <string name="preference_backlog_title">Backlog</string> - <string name="preference_dynamic_fetch_key" translatable="false">dynamic_fetch</string> - <string name="preference_dynamic_fetch_title">Dynamic Fetch Amount</string> - <string name="preference_dynamic_fetch_summary">The number of backlog messages to fetch each time</string> + <string name="preference_page_size_key" translatable="false">page_size</string> + <string name="preference_page_size_title">Page Size</string> + <string name="preference_page_size_summary">The number of messages loaded at a time</string> <string name="preference_connection_title">Connection</string> diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index c9747aaabd10a690a7f0dc6fa1659505788a717c..ab9de71809071bb655df85eb7ed6362b5b48268d 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -79,11 +79,11 @@ <PreferenceCategory android:title="@string/preference_backlog_title"> <EditTextPreference - android:defaultValue="20" + android:defaultValue="150" android:inputType="number" - android:key="@string/preference_dynamic_fetch_key" - android:summary="@string/preference_dynamic_fetch_summary" - android:title="@string/preference_dynamic_fetch_title" /> + android:key="@string/preference_page_size_key" + android:summary="@string/preference_page_size_summary" + android:title="@string/preference_page_size_title" /> </PreferenceCategory> <PreferenceCategory android:title="@string/preference_connection_title">