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" />
-
+