diff --git a/app/src/main/java/com/ubergeek42/WeechatAndroid/fragments/BufferFragment.kt b/app/src/main/java/com/ubergeek42/WeechatAndroid/fragments/BufferFragment.kt index 85819a76..84672214 100644 --- a/app/src/main/java/com/ubergeek42/WeechatAndroid/fragments/BufferFragment.kt +++ b/app/src/main/java/com/ubergeek42/WeechatAndroid/fragments/BufferFragment.kt @@ -64,15 +64,8 @@ import com.ubergeek42.WeechatAndroid.upload.i import com.ubergeek42.WeechatAndroid.upload.insertAddingSpacesAsNeeded import com.ubergeek42.WeechatAndroid.upload.suppress import com.ubergeek42.WeechatAndroid.upload.validateUploadConfig +import com.ubergeek42.WeechatAndroid.utils.* import com.ubergeek42.WeechatAndroid.utils.Assert.assertThat -import com.ubergeek42.WeechatAndroid.utils.FriendlyExceptions -import com.ubergeek42.WeechatAndroid.utils.Toaster -import com.ubergeek42.WeechatAndroid.utils.Utils -import com.ubergeek42.WeechatAndroid.utils.afterTextChanged -import com.ubergeek42.WeechatAndroid.utils.equalsIgnoringUselessSpans -import com.ubergeek42.WeechatAndroid.utils.makeCopyWithoutUselessSpans -import com.ubergeek42.WeechatAndroid.utils.indexOfOrElse -import com.ubergeek42.WeechatAndroid.utils.ulet import com.ubergeek42.WeechatAndroid.views.BufferFragmentFullScreenController import com.ubergeek42.WeechatAndroid.views.OnBackGestureListener import com.ubergeek42.WeechatAndroid.views.OnJumpedUpWhileScrollingListener @@ -155,6 +148,7 @@ class BufferFragment : Fragment(), BufferEye { savedInstanceState?.let { restoreRecyclerViewState(it) restoreSearchState(it) + restoreHistoryState(it) } } @@ -287,6 +281,7 @@ class BufferFragment : Fragment(), BufferEye { super.onSaveInstanceState(outState) saveRecyclerViewState(outState) saveSearchState(outState) + saveHistoryState(outState) } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -521,11 +516,21 @@ class BufferFragment : Fragment(), BufferEye { return@OnKeyListener true } KeyEvent.KEYCODE_VOLUME_DOWN, KeyEvent.KEYCODE_VOLUME_UP -> { - if (P.volumeBtnSize) { - val change = if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) 1f else -1f - val textSize = (P.textSize + change).coerceIn(5f, 30f) - P.setTextSizeColorAndLetterWidth(textSize) - return@OnKeyListener true + val up = keyCode == KeyEvent.KEYCODE_VOLUME_UP + when (P.volumeRole) { + P.VolumeRole.TEXT_SIZE -> { + val change = if (up) 1f else -1f + val textSize = (P.textSize + change).coerceIn(5f, 30f) + P.setTextSizeColorAndLetterWidth(textSize) + return@OnKeyListener true + } + P.VolumeRole.SEND_HISTORY -> { + ulet(ui?.chatInput) { + history.navigateOffset(it, if (up) 1 else -1) + } + return@OnKeyListener true + } + else -> {} } } } @@ -951,6 +956,20 @@ class BufferFragment : Fragment(), BufferEye { } } + //////////////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////// history + //////////////////////////////////////////////////////////////////////////////////////////////// + + private val history = History() + + private fun saveHistoryState(outState: Bundle) { + outState.putBundle(KEY_HISTORY, history.save()) + } + + private fun restoreHistoryState(savedInstanceState: Bundle) { + savedInstanceState.getBundle(KEY_HISTORY)?.let { history.restore(it) } + } + //////////////////////////////////////////////////////////////////////////////////////////////// private fun setPendingInputForParallelFragments() = ulet(buffer, ui) { buffer, ui -> @@ -994,7 +1013,7 @@ private const val KEY_LAST_FOCUSED_MATCH = "lastFocusedMatch" private const val KEY_REGEX = "regex" private const val KEY_CASE_SENSITIVE = "caseSensitive" private const val KEY_SOURCE = "source" - +private const val KEY_HISTORY = "history" private enum class ConnectivityState( val displayBadge: Boolean, diff --git a/app/src/main/java/com/ubergeek42/WeechatAndroid/service/P.java b/app/src/main/java/com/ubergeek42/WeechatAndroid/service/P.java index eaab2c27..8a244c72 100644 --- a/app/src/main/java/com/ubergeek42/WeechatAndroid/service/P.java +++ b/app/src/main/java/com/ubergeek42/WeechatAndroid/service/P.java @@ -123,7 +123,10 @@ public static void storeThemeOrColorSchemeColors(Context context) { public static boolean notificationVibrate; public static String notificationSound; - public static boolean showSend, showTab, showPaperclip, hotlistSync, volumeBtnSize; + public static boolean showSend, showTab, showPaperclip, hotlistSync; + + public enum VolumeRole {NONE, TEXT_SIZE, SEND_HISTORY}; + public static VolumeRole volumeRole; public static boolean showBufferFilter; @@ -167,7 +170,7 @@ public static void storeThemeOrColorSchemeColors(Context context) { showTab = p.getBoolean(PREF_SHOW_TAB, PREF_SHOW_TAB_D); showPaperclip = p.getBoolean(PREF_SHOW_PAPERCLIP, PREF_SHOW_PAPERCLIP_D); hotlistSync = p.getBoolean(PREF_HOTLIST_SYNC, PREF_HOTLIST_SYNC_D); - volumeBtnSize = p.getBoolean(PREF_VOLUME_BTN_SIZE, PREF_VOLUME_BTN_SIZE_D); + volumeRole = VolumeRole.values()[Integer.parseInt(p.getString(PREF_VOLUME_ROLE, PREF_VOLUME_ROLE_D))]; // buffer list filter showBufferFilter = p.getBoolean(PREF_SHOW_BUFFER_FILTER, PREF_SHOW_BUFFER_FILTER_D); @@ -365,7 +368,7 @@ public static void loadServerKeyVerifier() { case PREF_SHOW_TAB: showTab = p.getBoolean(key, PREF_SHOW_TAB_D); break; case PREF_SHOW_PAPERCLIP: showPaperclip = p.getBoolean(key, PREF_SHOW_PAPERCLIP_D); break; case PREF_HOTLIST_SYNC: hotlistSync = p.getBoolean(key, PREF_HOTLIST_SYNC_D); break; - case PREF_VOLUME_BTN_SIZE: volumeBtnSize = p.getBoolean(key, PREF_VOLUME_BTN_SIZE_D); break; + case PREF_VOLUME_ROLE: volumeRole = VolumeRole.values()[Integer.parseInt(p.getString(PREF_VOLUME_ROLE, PREF_VOLUME_ROLE_D))]; break; // buffer list fragment case PREF_SHOW_BUFFER_FILTER: showBufferFilter = p.getBoolean(key, PREF_SHOW_BUFFER_FILTER_D); break; diff --git a/app/src/main/java/com/ubergeek42/WeechatAndroid/utils/Constants.java b/app/src/main/java/com/ubergeek42/WeechatAndroid/utils/Constants.java index 80d1cc2b..8e7790c9 100644 --- a/app/src/main/java/com/ubergeek42/WeechatAndroid/utils/Constants.java +++ b/app/src/main/java/com/ubergeek42/WeechatAndroid/utils/Constants.java @@ -4,6 +4,7 @@ import com.ubergeek42.WeechatAndroid.R; import com.ubergeek42.WeechatAndroid.Weechat; +import com.ubergeek42.WeechatAndroid.service.P; import java.util.Set; @@ -123,8 +124,8 @@ public class Constants { final public static boolean PREF_SHOW_SEND_D = true; public final static String PREF_SHOW_TAB = "tabbtn_show"; final public static boolean PREF_SHOW_TAB_D = true; - public final static String PREF_VOLUME_BTN_SIZE = "volumebtn_size"; - final public static boolean PREF_VOLUME_BTN_SIZE_D = true; + public final static String PREF_VOLUME_ROLE = "buttons__volume"; + final public static String PREF_VOLUME_ROLE_D = String.valueOf(P.VolumeRole.TEXT_SIZE.ordinal()); final public static String PREF_SHOW_PAPERCLIP = "buttons__show_paperclip"; final public static boolean PREF_SHOW_PAPERCLIP_D = true; @@ -256,5 +257,6 @@ static public class Deprecated { final static public String PREF_SSH_KEY = "ssh_key"; final public static String PREF_SSH_KEY_D = null; final static public String PREF_SSH_KEY_PASSPHRASE = "ssh_key_passphrase"; final public static String PREF_SSH_KEY_PASSPHRASE_D = null; final static public String PREF_SSH_KNOWN_HOSTS = "ssh_known_hosts"; final public static String PREF_SSH_KNOWN_HOSTS_D = ""; + final static public String PREF_VOLUME_BTN_SIZE = "volumebtn_size"; final public static boolean PREF_VOLUME_BTN_SIZE_D = true; } } diff --git a/app/src/main/java/com/ubergeek42/WeechatAndroid/utils/History.kt b/app/src/main/java/com/ubergeek42/WeechatAndroid/utils/History.kt new file mode 100644 index 00000000..2f93acde --- /dev/null +++ b/app/src/main/java/com/ubergeek42/WeechatAndroid/utils/History.kt @@ -0,0 +1,54 @@ +package com.ubergeek42.WeechatAndroid.utils + +import android.os.Bundle +import android.text.Editable +import android.widget.EditText +import androidx.core.os.bundleOf +import com.ubergeek42.WeechatAndroid.service.P + +class History { + private var index = -1 + private var userInput: Editable? = null + private var selectionStart: Int? = null + private var selectionEnd: Int? = null + + fun navigateOffset(editText: EditText, offset: Int) { + if (index == -1) { + userInput = editText.text + selectionStart = editText.selectionStart + selectionEnd = editText.selectionEnd + } + val newIndex = index + offset + messageAt(newIndex)?.let { + editText.text = it + editText.post { + if (newIndex == -1) { + // Restore user selection. + editText.setSelection(selectionStart ?: 0, selectionEnd ?: editText.length()) + } else { + // Go to end for sent messages. + editText.setSelection(editText.length()) + } + } + index = newIndex + } + } + + fun save(): Bundle = bundleOf( + Pair("index", index), + Pair("userInput", userInput), + Pair("selStart", selectionStart), + Pair("selEnd", selectionEnd), + ) + + fun restore(bundle: Bundle) { + index = bundle.getInt("index", -1) + userInput = bundle.get("userInput") as Editable? + selectionStart = bundle.getInt("selStart", -1).let { if (it == -1) null else it } + selectionEnd = bundle.getInt("selEnd", -1).let { if (it == -1) null else it } + } + + private fun messageAt(index: Int): Editable? = + if (index == -1) userInput else P.sentMessages.getOrNull(P.sentMessages.size - 1 - index) + ?.let { Editable.Factory.getInstance().newEditable(it) } +} \ No newline at end of file diff --git a/app/src/main/java/com/ubergeek42/WeechatAndroid/utils/MigratePreferences.kt b/app/src/main/java/com/ubergeek42/WeechatAndroid/utils/MigratePreferences.kt index 93c45941..db093a7c 100644 --- a/app/src/main/java/com/ubergeek42/WeechatAndroid/utils/MigratePreferences.kt +++ b/app/src/main/java/com/ubergeek42/WeechatAndroid/utils/MigratePreferences.kt @@ -1,14 +1,15 @@ package com.ubergeek42.WeechatAndroid.utils import android.content.Context +import androidx.core.content.edit import androidx.preference.PreferenceManager import androidx.preference.PrivateKeyPickerPreference +import com.ubergeek42.WeechatAndroid.service.P.VolumeRole import com.ubergeek42.WeechatAndroid.upload.applicationContext import com.ubergeek42.WeechatAndroid.utils.AndroidKeyStoreUtils.InsideSecurityHardware import com.ubergeek42.cats.Kitty import com.ubergeek42.cats.Root import com.ubergeek42.weechat.relay.connection.SSHConnection -import java.util.* class MigratePreferences(val context: Context) { @@ -177,6 +178,14 @@ class MigratePreferences(val context: Context) { "you may have to import them in settings.") } } + + add(5, 6) { + val volumeChangesSize = preferences.getBoolean(Constants.Deprecated.PREF_VOLUME_BTN_SIZE, Constants.Deprecated.PREF_VOLUME_BTN_SIZE_D) + preferences.edit { + this.remove(Constants.Deprecated.PREF_VOLUME_BTN_SIZE) + this.putString(Constants.PREF_VOLUME_ROLE, (if (volumeChangesSize) VolumeRole.TEXT_SIZE else VolumeRole.NONE).ordinal.toString(10)) + } + } } } diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 210c724f..0752863a 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -703,11 +703,9 @@ wenn der Büroklammer-Taste versteckt wurde, um mehr Platz für das Eingabefeld zu schaffen. - - Lautstärketasten ändern die Textgröße - - Wenn diese Option aktiviert ist, - ändern die Lautstärketasten die Textgröße, anstelle der Lautstärke + Nichts tun + Lautstärketasten ändern die Textgröße + Navigieren im Sendeverlauf diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 6175a40a..eb52f498 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -691,12 +691,9 @@ Quand le bouton « trombone » devient invisible pour laisser de la place au champ de saisie, il reste possible de joindre des fichiers via le menu déroulant. - - Taille du texte via le volume - - Si coché, les boutons du volume audio changent la taille du texte - lorsque Weechat-Android est au premier plan - + Ne rien faire + Changer la taille du texte + Naviguer dans les messages envoyés diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 05b5514a..10229587 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -699,10 +699,9 @@ Когда кнопка «Скрепка» скрыта, чтобы оставить больше места для поля ввода, выбирать файлы можно через меню. - - Кнопки громкости меняют размер текста - - Если настройка включена, кнопки громкости будут менять размер текста вместо громкости + Ничего не делать + Кнопки громкости меняют размер текста + Навигация по истории отправлений diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0e1ff29b..45b8ead1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -714,10 +714,16 @@ When the paperclip button gets hidden to provide more space for the input field, you can still attach files via overflow menu. - - Volume buttons change text size - - If set, volume buttons will change text size instead of volume + Volume button role + + @string/pref_buttons_volume__actions__none + @string/pref_buttons_volume__actions__text_size + @string/pref_buttons_volume__actions__history + + + Do nothing + Change text size + Navigate sent history diff --git a/app/src/main/res/values/values.xml b/app/src/main/res/values/values.xml index 227bad40..0c5e0a26 100644 --- a/app/src/main/res/values/values.xml +++ b/app/src/main/res/values/values.xml @@ -78,6 +78,12 @@ 4 + + 0 + 1 + 2 + + content_images content_media diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 76737c00..1185a61a 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -350,11 +350,13 @@ android:persistent="false" android:selectable="false" android:dependency="buttons__show_paperclip" /> - +