mirror of
https://github.com/ankidroid/Anki-Android.git
synced 2024-09-20 12:02:16 +02:00
feat: upgrade from Volume gestures to Bindings
We remove the `VOLUME_UP` and `VOLUME_DOWN` gestures, and all associated code This removes the preferences: "gestureVolumeUp" "gestureVolumeDown" Instead, this is passed to a binding, for example: "binding_EDIT": [keycode 24] Related: 6502
This commit is contained in:
parent
68493a0c63
commit
dc6459f84b
@ -90,7 +90,6 @@ import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.drakeet.drawer.FullDraggableContainer;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.ichi2.anim.ViewAnimation;
|
||||
import com.ichi2.anki.cardviewer.Gesture;
|
||||
import com.ichi2.anki.cardviewer.GestureProcessor;
|
||||
import com.ichi2.anki.cardviewer.MissingImageHandler;
|
||||
import com.ichi2.anki.cardviewer.OnRenderProcessGoneDelegate;
|
||||
@ -347,10 +346,6 @@ public abstract class AbstractFlashcardViewer extends NavigationDrawerActivity i
|
||||
/**
|
||||
* Gesture Allocation
|
||||
*/
|
||||
@NonNull
|
||||
private ViewerCommand mGestureVolumeUp = COMMAND_NOTHING;
|
||||
@NonNull
|
||||
private ViewerCommand mGestureVolumeDown = COMMAND_NOTHING;
|
||||
protected final GestureProcessor mGestureProcessor = new GestureProcessor(this);
|
||||
|
||||
private String mCardContent;
|
||||
@ -1531,33 +1526,6 @@ public abstract class AbstractFlashcardViewer extends NavigationDrawerActivity i
|
||||
TaskManager.launchCollectionTask(new CollectionTask.AnswerAndGetCard(mCurrentCard, mCurrentEase), new AnswerCardHandler(true));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
// assign correct gesture code
|
||||
ViewerCommand gesture = COMMAND_NOTHING;
|
||||
|
||||
switch (event.getKeyCode()) {
|
||||
case KeyEvent.KEYCODE_VOLUME_UP:
|
||||
gesture = mGestureVolumeUp;
|
||||
break;
|
||||
case KeyEvent.KEYCODE_VOLUME_DOWN:
|
||||
gesture = mGestureVolumeDown;
|
||||
break;
|
||||
}
|
||||
|
||||
// Execute gesture's command, but only consume event if action is assigned. We want the volume buttons to work normally otherwise.
|
||||
if (gesture != COMMAND_NOTHING) {
|
||||
executeCommand(gesture);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
|
||||
|
||||
// Set the content view to the one provided and initialize accessors.
|
||||
protected void initLayout() {
|
||||
FrameLayout cardContainer = findViewById(R.id.flashcard_frame);
|
||||
@ -1947,8 +1915,6 @@ public abstract class AbstractFlashcardViewer extends NavigationDrawerActivity i
|
||||
mLinkOverridesTouchGesture = preferences.getBoolean("linkOverridesTouchGesture", false);
|
||||
if (mGesturesEnabled) {
|
||||
mGestureProcessor.init(preferences);
|
||||
mGestureVolumeUp = Gesture.VOLUME_UP.fromPreference(preferences);
|
||||
mGestureVolumeDown = Gesture.VOLUME_DOWN.fromPreference(preferences);
|
||||
}
|
||||
|
||||
if (preferences.getBoolean("keepScreenOn", false)) {
|
||||
|
@ -55,9 +55,7 @@ enum class Gesture(
|
||||
TAP_RIGHT(R.string.gestures_tap_right, "gestureTapRight", ViewerCommand.COMMAND_FLIP_OR_ANSWER_RECOMMENDED),
|
||||
TAP_BOTTOM_LEFT(R.string.gestures_corner_tap_bottom_left, "gestureTapBottomLeft", ViewerCommand.COMMAND_NOTHING),
|
||||
TAP_BOTTOM(R.string.gestures_tap_bottom, "gestureTapBottom", ViewerCommand.COMMAND_FLIP_OR_ANSWER_EASE1),
|
||||
TAP_BOTTOM_RIGHT(R.string.gestures_corner_tap_bottom_right, "gestureTapBottomRight", ViewerCommand.COMMAND_NOTHING),
|
||||
VOLUME_UP(R.string.gestures_volume_up, "gestureVolumeUp", ViewerCommand.COMMAND_NOTHING),
|
||||
VOLUME_DOWN(R.string.gestures_volume_down, "gestureVolumeDown", ViewerCommand.COMMAND_NOTHING);
|
||||
TAP_BOTTOM_RIGHT(R.string.gestures_corner_tap_bottom_right, "gestureTapBottomRight", ViewerCommand.COMMAND_NOTHING);
|
||||
|
||||
fun fromPreference(prefs: SharedPreferences): ViewerCommand {
|
||||
val value = prefs.getString(preferenceKey, null) ?: return preferenceDefault
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package com.ichi2.anki.cardviewer;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
import com.ichi2.anki.R;
|
||||
@ -27,6 +28,7 @@ import com.ichi2.anki.reviewer.MappableBinding;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@ -112,6 +114,38 @@ public enum ViewerCommand {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public void addBinding(SharedPreferences preferences, MappableBinding binding) {
|
||||
BiFunction<List<MappableBinding>, MappableBinding, Boolean> addAtStart = (collection, element) -> {
|
||||
// reorder the elements, moving the added binding to the first position
|
||||
collection.remove(element);
|
||||
collection.add(0, element);
|
||||
return true;
|
||||
};
|
||||
addBindingInternal(preferences, binding, addAtStart);
|
||||
}
|
||||
|
||||
public void addBindingAtEnd(SharedPreferences preferences, MappableBinding binding) {
|
||||
BiFunction<List<MappableBinding>, MappableBinding, Boolean> addAtEnd = (collection, element) -> {
|
||||
// do not reorder the elements
|
||||
if (collection.contains(element)) {
|
||||
return false;
|
||||
}
|
||||
collection.add(element);
|
||||
return true;
|
||||
};
|
||||
addBindingInternal(preferences, binding, addAtEnd);
|
||||
}
|
||||
|
||||
private void addBindingInternal(SharedPreferences preferences, MappableBinding binding, BiFunction<List<MappableBinding>, MappableBinding, Boolean> performAdd) {
|
||||
if (this == COMMAND_NOTHING) {
|
||||
return;
|
||||
}
|
||||
List<MappableBinding> bindings = MappableBinding.fromPreference(preferences, this);
|
||||
performAdd.apply(bindings, binding);
|
||||
String newValue = MappableBinding.Companion.toPreferenceString(bindings);
|
||||
preferences.edit().putString(this.getPreferenceKey(), newValue).apply();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public List<MappableBinding> getDefaultValue() {
|
||||
// If we use the serialised format, then this adds additional coupling to the properties.
|
||||
|
@ -17,10 +17,15 @@ package com.ichi2.anki.servicelayer
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.view.KeyEvent
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.core.content.edit
|
||||
import com.ichi2.anki.AnkiDroidApp
|
||||
import com.ichi2.anki.cardviewer.ViewerCommand
|
||||
import com.ichi2.anki.reviewer.Binding.Companion.keyCode
|
||||
import com.ichi2.anki.reviewer.CardSide
|
||||
import com.ichi2.anki.reviewer.FullScreenMode
|
||||
import com.ichi2.anki.reviewer.MappableBinding
|
||||
import timber.log.Timber
|
||||
|
||||
private typealias VersionIdentifier = Int
|
||||
@ -69,6 +74,7 @@ object PreferenceUpgradeService {
|
||||
/** Returns all instances of preference upgrade classes */
|
||||
internal fun getAllInstances(legacyPreviousVersionCode: LegacyVersionIdentifier) = sequence<PreferenceUpgrade> {
|
||||
yield(LegacyPreferenceUpgrade(legacyPreviousVersionCode))
|
||||
yield(UpgradeVolumeButtonsToBindings())
|
||||
}
|
||||
|
||||
/** Returns a list of preference upgrade classes which have not been applied */
|
||||
@ -155,6 +161,52 @@ object PreferenceUpgradeService {
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
internal class UpgradeVolumeButtonsToBindings : PreferenceUpgrade(2) {
|
||||
override fun upgrade(preferences: SharedPreferences) {
|
||||
upgradeVolumeGestureToKeyBind(preferences, "gestureVolumeUp", KeyEvent.KEYCODE_VOLUME_UP)
|
||||
upgradeVolumeGestureToKeyBind(preferences, "gestureVolumeDown", KeyEvent.KEYCODE_VOLUME_DOWN)
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
internal fun upgradeVolumeGestureToKeyBind(preferences: SharedPreferences, oldGesturePreferenceKey: String, volumeKeyCode: Int) {
|
||||
Timber.d("Replacing gesture '%s' with binding", oldGesturePreferenceKey)
|
||||
|
||||
// This exists as a user may have mapped "volume down" to "UNDO".
|
||||
// Undo already exists as a key binding, and we don't want to trash this during an upgrade
|
||||
if (!preferences.contains(oldGesturePreferenceKey)) {
|
||||
Timber.v("No preference to upgrade")
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
replaceGestureWithBinding(preferences, oldGesturePreferenceKey, volumeKeyCode)
|
||||
} finally {
|
||||
Timber.v("removing pref key: '%s'", oldGesturePreferenceKey)
|
||||
// remove the old key
|
||||
preferences.edit { remove(oldGesturePreferenceKey) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun replaceGestureWithBinding(preferences: SharedPreferences, oldGesturePreferenceKey: String, volumeKeyCode: Int) {
|
||||
// the preference should be set, but if it's null, then we have nothing to do
|
||||
val gesture = preferences.getString(oldGesturePreferenceKey, "0") ?: return
|
||||
// If the preference doesn't map (for example: it was removed), then nothing to do
|
||||
val asInt = gesture.toIntOrNull() ?: return
|
||||
val command = ViewerCommand.fromInt(asInt) ?: return
|
||||
|
||||
if (command == ViewerCommand.COMMAND_NOTHING) {
|
||||
return
|
||||
}
|
||||
|
||||
Timber.i("Moving preference from '%s' to '%s'", oldGesturePreferenceKey, command.preferenceKey)
|
||||
|
||||
// add to the binding_COMMANDNAME preference
|
||||
val binding = MappableBinding(keyCode(volumeKeyCode), MappableBinding.Screen.Reviewer(CardSide.BOTH))
|
||||
command.addBindingAtEnd(preferences, binding)
|
||||
}
|
||||
}
|
||||
|
||||
fun performUpgrade(preferences: SharedPreferences) {
|
||||
Timber.i("Running preference upgrade: ${this.javaClass.simpleName}")
|
||||
upgrade(preferences)
|
||||
|
@ -115,11 +115,6 @@ class ControlPreference : ListPreference {
|
||||
.onBindingChanged { binding -> checkExistingBinding(MappableBinding(binding, MappableBinding.Screen.Reviewer(CardSide.BOTH))) }
|
||||
// select a side, then add
|
||||
.onBindingSubmitted { binding ->
|
||||
// for now, volume buttons are handled by the reviewer
|
||||
if (isVolumeKey(binding)) {
|
||||
UIUtils.showThemedToast(context, R.string.bindings_no_volume, true)
|
||||
return@onBindingSubmitted
|
||||
}
|
||||
CardSideSelectionDialog.displayInstance(context) { side -> addBinding(MappableBinding(binding, MappableBinding.Screen.Reviewer(side))) }
|
||||
}
|
||||
.disallowModifierKeys()
|
||||
@ -143,11 +138,7 @@ class ControlPreference : ListPreference {
|
||||
}
|
||||
|
||||
/** Displays a warning to the user if the provided binding couldn't be used */
|
||||
fun checkExistingBinding(binding: MappableBinding) {
|
||||
if (isVolumeKey(binding.binding)) {
|
||||
UIUtils.showThemedToast(context, R.string.bindings_no_volume, true)
|
||||
return
|
||||
}
|
||||
private fun checkExistingBinding(binding: MappableBinding) {
|
||||
val existingCommands = getExistingCommands(binding).toList()
|
||||
if (existingCommands.isEmpty()) return // no conflicts
|
||||
val commandNames = existingCommands.map { context.getString(it.resourceId) }
|
||||
|
@ -72,7 +72,7 @@ constructor(context: Context, attributeSet: AttributeSet? = null, defStyleAttr:
|
||||
|
||||
/** Lists all selectable gestures from this view (excludes null) */
|
||||
fun availableValues(): List<Gesture> = Gesture.values().filter {
|
||||
!VOLUME_GESTURES.contains(it) && (mTapGestureMode == TapGestureMode.NINE_POINT || !NINE_POINT_TAP_GESTURES.contains(it))
|
||||
(mTapGestureMode == TapGestureMode.NINE_POINT || !NINE_POINT_TAP_GESTURES.contains(it))
|
||||
}
|
||||
|
||||
/** Sets a callback which is called when the gesture is changed, and non-null */
|
||||
@ -181,6 +181,5 @@ constructor(context: Context, attributeSet: AttributeSet? = null, defStyleAttr:
|
||||
|
||||
companion object {
|
||||
val NINE_POINT_TAP_GESTURES = listOf(TAP_TOP_LEFT, TAP_TOP_RIGHT, TAP_CENTER, TAP_BOTTOM_LEFT, TAP_BOTTOM_RIGHT)
|
||||
val VOLUME_GESTURES = listOf(VOLUME_UP, VOLUME_DOWN)
|
||||
}
|
||||
}
|
||||
|
@ -325,5 +325,4 @@ this formatter is used if the bind only applies to both the question and the ans
|
||||
<string name="binding_remove_binding" comment="The parameter is the name of the key/gesture.
|
||||
Keys cannot be translated yet.">Remove ‘%s’</string>
|
||||
<string name="bindings_already_bound">Already bound to %s</string>
|
||||
<string name="bindings_no_volume">Volume keys are supported in the Gestures menu</string>
|
||||
</resources>
|
||||
|
@ -18,6 +18,7 @@ package com.ichi2.anki;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import com.afollestad.materialdialogs.DialogAction;
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
@ -271,6 +272,10 @@ public class RobolectricTest implements CollectionGetter {
|
||||
|
||||
}
|
||||
|
||||
protected SharedPreferences getPreferences() {
|
||||
return AnkiDroidApp.getSharedPrefs(getTargetContext());
|
||||
}
|
||||
|
||||
|
||||
protected String getResourceString(int res) {
|
||||
return getTargetContext().getString(res);
|
||||
|
@ -0,0 +1,219 @@
|
||||
/*
|
||||
* Copyright (c) 2021 David Allison <davidallisongithub@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by the Free Software
|
||||
* Foundation; either version 3 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.ichi2.anki.servicemodel
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import androidx.core.content.edit
|
||||
import com.ichi2.anki.RobolectricTest
|
||||
import com.ichi2.anki.cardviewer.ViewerCommand
|
||||
import com.ichi2.anki.reviewer.Binding.Companion.keyCode
|
||||
import com.ichi2.anki.reviewer.CardSide
|
||||
import com.ichi2.anki.reviewer.MappableBinding
|
||||
import com.ichi2.anki.reviewer.MappableBinding.Screen.Reviewer
|
||||
import com.ichi2.anki.servicelayer.PreferenceUpgradeService.PreferenceUpgrade.UpgradeVolumeButtonsToBindings
|
||||
import org.hamcrest.CoreMatchers.equalTo
|
||||
import org.hamcrest.CoreMatchers.not
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.hamcrest.Matchers
|
||||
import org.hamcrest.Matchers.empty
|
||||
import org.hamcrest.Matchers.hasSize
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.ParameterizedRobolectricTestRunner
|
||||
import timber.log.Timber
|
||||
|
||||
@RunWith(ParameterizedRobolectricTestRunner::class)
|
||||
class UpgradeVolumeButtonsToBindingsTest(private val testData: TestData) : RobolectricTest() {
|
||||
private val changedKeys = HashSet<String>()
|
||||
|
||||
private lateinit var prefs: SharedPreferences
|
||||
private lateinit var instance: UpgradeVolumeButtonsToBindings
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
super.setUp()
|
||||
prefs = super.getPreferences()
|
||||
instance = UpgradeVolumeButtonsToBindings()
|
||||
prefs.registerOnSharedPreferenceChangeListener { _, key -> run { Timber.i("added key $key"); changedKeys.add(key) } }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_preferences_not_opened_happy_path() {
|
||||
// if the user has not opened the gestures, then nothing should be mapped
|
||||
assertThat(prefs.contains(PREF_KEY_VOLUME_DOWN), equalTo(false))
|
||||
assertThat(prefs.contains(PREF_KEY_VOLUME_UP), equalTo(false))
|
||||
|
||||
upgradeAllGestures()
|
||||
|
||||
// ensure that no settings were added to the preferences
|
||||
assertThat(changedKeys, Matchers.contains("preferenceUpgradeVersion"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test_preferences_opened_happy_path() {
|
||||
// the default is that the user has not mapped the gesture, but has opened the screen
|
||||
// so they are set to COMMAND_NOTHING
|
||||
prefs.edit { putString(PREF_KEY_VOLUME_UP, ViewerCommand.COMMAND_NOTHING.toPreferenceString()) }
|
||||
prefs.edit { putString(PREF_KEY_VOLUME_DOWN, ViewerCommand.COMMAND_NOTHING.toPreferenceString()) }
|
||||
|
||||
assertThat(prefs.contains(PREF_KEY_VOLUME_DOWN), equalTo(true))
|
||||
assertThat(prefs.contains(PREF_KEY_VOLUME_UP), equalTo(true))
|
||||
|
||||
upgradeAllGestures()
|
||||
|
||||
// ensure that no settings were added to the preferences
|
||||
assertThat(changedKeys, Matchers.contains("preferenceUpgradeVersion", PREF_KEY_VOLUME_DOWN, PREF_KEY_VOLUME_UP))
|
||||
|
||||
assertThat("Volume gestures are removed", prefs.contains(PREF_KEY_VOLUME_DOWN), equalTo(false))
|
||||
assertThat("Volume gestures are removed", prefs.contains(PREF_KEY_VOLUME_UP), equalTo(false))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun gesture_set_no_conflicts() {
|
||||
// assume that we have a preference set, and that it has no defaults
|
||||
val command = ViewerCommand.COMMAND_LOOKUP
|
||||
prefs.edit { putString(testData.affectedPreferenceKey, command.toPreferenceString()) }
|
||||
|
||||
assertThat(prefs.contains(testData.affectedPreferenceKey), equalTo(true))
|
||||
assertThat(prefs.contains(testData.unaffectedPreferenceKey), equalTo(false))
|
||||
assertThat("example command should have no defaults", MappableBinding.fromPreference(prefs, command), empty())
|
||||
|
||||
upgradeAllGestures()
|
||||
|
||||
assertThat(changedKeys, Matchers.containsInAnyOrder("preferenceUpgradeVersion", testData.affectedPreferenceKey, command.preferenceKey))
|
||||
|
||||
assertThat("legacy preference removed", prefs.contains(testData.affectedPreferenceKey), equalTo(false))
|
||||
assertThat("new preference added", prefs.contains(command.preferenceKey), equalTo(true))
|
||||
|
||||
val fromPreference = MappableBinding.fromPreference(prefs, command)
|
||||
assertThat(fromPreference, hasSize(1))
|
||||
val binding = fromPreference.first()
|
||||
|
||||
assertThat("should be a key binding", binding.isKey, equalTo(true))
|
||||
assertThat("binding should match", binding, equalTo(MappableBinding(keyCode(testData.keyCode), Reviewer(CardSide.BOTH))))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun if_mapped_to_non_empty_binding_then_added_to_end() {
|
||||
// common path
|
||||
// if the gesture was mapped to a command which already had bindings,
|
||||
// check it is added to the list at the end
|
||||
val command = ViewerCommand.COMMAND_EDIT
|
||||
prefs.edit { putString(testData.affectedPreferenceKey, command.toPreferenceString()) }
|
||||
|
||||
assertThat(prefs.contains(testData.affectedPreferenceKey), equalTo(true))
|
||||
assertThat(prefs.contains(testData.unaffectedPreferenceKey), equalTo(false))
|
||||
assertThat("new preference does not exist", prefs.contains(command.preferenceKey), equalTo(false))
|
||||
val previousCommands = MappableBinding.fromPreference(prefs, command)
|
||||
assertThat("example command should have defaults", previousCommands, not(empty()))
|
||||
|
||||
upgradeAllGestures()
|
||||
|
||||
assertThat(changedKeys, Matchers.containsInAnyOrder("preferenceUpgradeVersion", testData.affectedPreferenceKey, command.preferenceKey))
|
||||
|
||||
assertThat("legacy preference removed", prefs.contains(testData.affectedPreferenceKey), equalTo(false))
|
||||
assertThat("new preference exists", prefs.contains(command.preferenceKey), equalTo(true))
|
||||
|
||||
val currentCommands = MappableBinding.fromPreference(prefs, command)
|
||||
assertThat("a binding was added to '${command.preferenceKey}'", currentCommands, hasSize(previousCommands.size + 1))
|
||||
|
||||
// ensure that the order was not changed - the last element is not included in the zip
|
||||
previousCommands.zip(currentCommands).forEach {
|
||||
assertThat("bindings should not change order", it.first, equalTo(it.second))
|
||||
}
|
||||
|
||||
val addedBinding = currentCommands.last()
|
||||
|
||||
assertThat("last should be a key binding", addedBinding.isKey, equalTo(true))
|
||||
assertThat("last binding should match", addedBinding, equalTo(testData.binding))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun if_gesture_already_exists_then_do_not_modify_list() {
|
||||
// the gestures shouldn't already be a keybind (as we've just introduced the feature)
|
||||
// but if it is, then we want to ignore it in the upgrade.
|
||||
|
||||
val command = ViewerCommand.COMMAND_EDIT
|
||||
command.addBinding(prefs, testData.binding)
|
||||
|
||||
prefs.edit { putString(testData.affectedPreferenceKey, command.toPreferenceString()) }
|
||||
|
||||
assertThat(prefs.contains(testData.affectedPreferenceKey), equalTo(true))
|
||||
assertThat(prefs.contains(testData.unaffectedPreferenceKey), equalTo(false))
|
||||
assertThat("new preference exists", prefs.contains(command.preferenceKey), equalTo(true))
|
||||
val previousCommands = MappableBinding.fromPreference(prefs, command)
|
||||
assertThat("example command should have defaults", previousCommands, hasSize(2))
|
||||
assertThat(previousCommands.first(), equalTo(testData.binding))
|
||||
|
||||
upgradeAllGestures()
|
||||
|
||||
assertThat("Binding gestures should not be changed", changedKeys, Matchers.contains("preferenceUpgradeVersion", testData.affectedPreferenceKey))
|
||||
|
||||
assertThat("legacy preference removed", prefs.contains(testData.affectedPreferenceKey), equalTo(false))
|
||||
assertThat("new preference still exists", prefs.contains(command.preferenceKey), equalTo(true))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun invalid_preference_value_results_in_old_null_value_and_no_new_value() {
|
||||
prefs.edit { putString(testData.affectedPreferenceKey, "bananas") }
|
||||
|
||||
upgradeAllGestures()
|
||||
|
||||
assertThat("Binding gestures should not be changed", changedKeys, Matchers.contains("preferenceUpgradeVersion", testData.affectedPreferenceKey))
|
||||
|
||||
assertThat("legacy preference removed", prefs.contains(testData.affectedPreferenceKey), equalTo(false))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun invalid_command_value_results_in_old_null_value_and_no_new_value() {
|
||||
// a valid int, but not a valid command
|
||||
prefs.edit { putString(testData.affectedPreferenceKey, "-1") }
|
||||
|
||||
upgradeAllGestures()
|
||||
|
||||
assertThat("Binding gestures should not be changed", changedKeys, Matchers.containsInAnyOrder("preferenceUpgradeVersion", testData.affectedPreferenceKey))
|
||||
|
||||
assertThat("legacy preference removed", prefs.contains(testData.affectedPreferenceKey), equalTo(false))
|
||||
}
|
||||
|
||||
private fun upgradeAllGestures() {
|
||||
changedKeys.clear()
|
||||
instance.performUpgrade(prefs)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val KEYCODE_VOLUME_UP = 24
|
||||
private const val KEYCODE_VOLUME_DOWN = 25
|
||||
const val PREF_KEY_VOLUME_UP = "gestureVolumeUp"
|
||||
const val PREF_KEY_VOLUME_DOWN = "gestureVolumeDown"
|
||||
|
||||
private val volume_up_binding = MappableBinding(keyCode(KEYCODE_VOLUME_UP), Reviewer(CardSide.BOTH))
|
||||
private val volume_down_binding = MappableBinding(keyCode(KEYCODE_VOLUME_DOWN), Reviewer(CardSide.BOTH))
|
||||
|
||||
@JvmStatic
|
||||
@ParameterizedRobolectricTestRunner.Parameters(name = "{index}: isValid({0})={1}")
|
||||
fun data(): Iterable<Array<Any>> {
|
||||
// pref key, keyCode, opposite key
|
||||
return arrayListOf<Array<Any>>(
|
||||
arrayOf(TestData(PREF_KEY_VOLUME_UP, KEYCODE_VOLUME_UP, PREF_KEY_VOLUME_DOWN, volume_up_binding)),
|
||||
arrayOf(TestData(PREF_KEY_VOLUME_DOWN, KEYCODE_VOLUME_DOWN, PREF_KEY_VOLUME_UP, volume_down_binding)),
|
||||
).toList()
|
||||
}
|
||||
|
||||
data class TestData(val affectedPreferenceKey: String, val keyCode: Int, val unaffectedPreferenceKey: String, val binding: MappableBinding)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user