LongClickEraser generalized
This commit is contained in:
parent
a18f3210c3
commit
bbaedc71c9
@ -37,10 +37,7 @@ import android.widget.TextView;
|
|||||||
import org.solovyev.android.Views;
|
import org.solovyev.android.Views;
|
||||||
import org.solovyev.android.calculator.history.History;
|
import org.solovyev.android.calculator.history.History;
|
||||||
import org.solovyev.android.calculator.history.HistoryDragProcessor;
|
import org.solovyev.android.calculator.history.HistoryDragProcessor;
|
||||||
import org.solovyev.android.calculator.view.AngleUnitsButton;
|
import org.solovyev.android.calculator.view.*;
|
||||||
import org.solovyev.android.calculator.view.LongClickEraser;
|
|
||||||
import org.solovyev.android.calculator.view.NumeralBasesButton;
|
|
||||||
import org.solovyev.android.calculator.view.ViewsCache;
|
|
||||||
import org.solovyev.android.views.dragbutton.DirectionDragButton;
|
import org.solovyev.android.views.dragbutton.DirectionDragButton;
|
||||||
import org.solovyev.android.views.dragbutton.DragButton;
|
import org.solovyev.android.views.dragbutton.DragButton;
|
||||||
import org.solovyev.android.views.dragbutton.DragDirection;
|
import org.solovyev.android.views.dragbutton.DragDirection;
|
||||||
@ -216,7 +213,7 @@ public abstract class BaseUi implements SharedPreferences.OnSharedPreferenceChan
|
|||||||
|
|
||||||
final View eraseButton = getButton(views, R.id.cpp_button_erase);
|
final View eraseButton = getButton(views, R.id.cpp_button_erase);
|
||||||
if (eraseButton != null) {
|
if (eraseButton != null) {
|
||||||
LongClickEraser.createAndAttach(eraseButton);
|
EditorLongClickEraser.attachTo(eraseButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
clearButton = getButton(views, R.id.cpp_button_clear);
|
clearButton = getButton(views, R.id.cpp_button_clear);
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package org.solovyev.android.calculator;
|
package org.solovyev.android.calculator;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
@ -12,7 +11,6 @@ import android.support.annotation.IdRes;
|
|||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
import android.view.GestureDetector;
|
|
||||||
import android.view.HapticFeedbackConstants;
|
import android.view.HapticFeedbackConstants;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@ -23,6 +21,7 @@ import android.widget.ImageButton;
|
|||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
|
import org.solovyev.android.calculator.view.EditTextLongClickEraser;
|
||||||
import org.solovyev.android.views.dragbutton.DirectionDragButton;
|
import org.solovyev.android.views.dragbutton.DirectionDragButton;
|
||||||
import org.solovyev.android.views.dragbutton.DragButton;
|
import org.solovyev.android.views.dragbutton.DragButton;
|
||||||
import org.solovyev.android.views.dragbutton.DragDirection;
|
import org.solovyev.android.views.dragbutton.DragDirection;
|
||||||
@ -77,7 +76,7 @@ public class KeyboardUi {
|
|||||||
addButton(row, 0, "6");
|
addButton(row, 0, "6");
|
||||||
addOperationButton(row, R.id.cpp_kb_button_divide, "/").setText("%", up).setText("sqrt", down);
|
addOperationButton(row, R.id.cpp_kb_button_divide, "/").setText("%", up).setText("sqrt", down);
|
||||||
final View backspace = addImageButton(row, R.id.cpp_kb_button_backspace, R.drawable.ic_backspace_white_24dp);
|
final View backspace = addImageButton(row, R.id.cpp_kb_button_backspace, R.drawable.ic_backspace_white_24dp);
|
||||||
LongClickEraser.createAndAttach(backspace, user.getEditor());
|
EditTextLongClickEraser.attachTo(backspace, user.getEditor());
|
||||||
|
|
||||||
row = makeRow();
|
row = makeRow();
|
||||||
addButton(row, 0, "1");
|
addButton(row, 0, "1");
|
||||||
@ -290,125 +289,4 @@ public class KeyboardUi {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class LongClickEraser implements View.OnTouchListener, View.OnClickListener {
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final View view;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final EditText editText;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final GestureDetector gestureDetector;
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private final Eraser eraser = new Eraser();
|
|
||||||
|
|
||||||
private LongClickEraser(@NonNull final View view, @NonNull EditText editText) {
|
|
||||||
this.view = view;
|
|
||||||
this.editText = editText;
|
|
||||||
this.gestureDetector = new GestureDetector(view.getContext(), new GestureDetector.SimpleOnGestureListener() {
|
|
||||||
public void onLongPress(MotionEvent e) {
|
|
||||||
if (eraser.isTracking()) {
|
|
||||||
eraser.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void createAndAttach(@NonNull View view, @NonNull EditText editText) {
|
|
||||||
final LongClickEraser l = new LongClickEraser(view, editText);
|
|
||||||
view.setOnClickListener(l);
|
|
||||||
view.setOnTouchListener(l);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void erase(@NonNull EditText editText) {
|
|
||||||
final int start = clampSelection(editText.getSelectionStart());
|
|
||||||
final int end = clampSelection(editText.getSelectionEnd());
|
|
||||||
if (start != end) {
|
|
||||||
editText.getText().delete(Math.min(start, end), Math.max(start, end));
|
|
||||||
} else if (start > 0) {
|
|
||||||
editText.getText().delete(start - 1, start);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int clampSelection(int selection) {
|
|
||||||
return selection < 0 ? 0 : selection;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
|
||||||
@Override
|
|
||||||
public boolean onTouch(View v, MotionEvent event) {
|
|
||||||
switch (event.getAction()) {
|
|
||||||
case MotionEvent.ACTION_CANCEL:
|
|
||||||
case MotionEvent.ACTION_UP:
|
|
||||||
eraser.stopTracking();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
eraser.startTracking();
|
|
||||||
gestureDetector.onTouchEvent(event);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
erase(editText);
|
|
||||||
v.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class Eraser implements Runnable {
|
|
||||||
private static final int DELAY = 300;
|
|
||||||
private long delay;
|
|
||||||
private boolean erasing;
|
|
||||||
private boolean tracking = true;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
erase(editText);
|
|
||||||
if (editText.length() == 0 || clampSelection(editText.getSelectionStart()) == 0) {
|
|
||||||
stop();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
delay = Math.max(50, 2 * delay / 3);
|
|
||||||
view.postDelayed(this, delay);
|
|
||||||
}
|
|
||||||
|
|
||||||
void start() {
|
|
||||||
if (erasing) {
|
|
||||||
stop();
|
|
||||||
}
|
|
||||||
erasing = true;
|
|
||||||
delay = DELAY;
|
|
||||||
view.removeCallbacks(this);
|
|
||||||
view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
|
|
||||||
run();
|
|
||||||
}
|
|
||||||
|
|
||||||
void stop() {
|
|
||||||
view.removeCallbacks(this);
|
|
||||||
if (!erasing) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
erasing = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stopTracking() {
|
|
||||||
stop();
|
|
||||||
tracking = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isTracking() {
|
|
||||||
return tracking;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void startTracking() {
|
|
||||||
tracking = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -5,17 +5,9 @@ import android.view.HapticFeedbackConstants;
|
|||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import org.solovyev.android.calculator.App;
|
|
||||||
import org.solovyev.android.calculator.Calculator;
|
|
||||||
import org.solovyev.android.calculator.Editor;
|
|
||||||
import org.solovyev.android.calculator.EditorState;
|
|
||||||
import org.solovyev.android.calculator.Locator;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
import static android.text.TextUtils.isEmpty;
|
public abstract class BaseLongClickEraser implements View.OnTouchListener {
|
||||||
|
|
||||||
public final class LongClickEraser implements View.OnTouchListener {
|
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
private final View view;
|
private final View view;
|
||||||
@ -23,16 +15,10 @@ public final class LongClickEraser implements View.OnTouchListener {
|
|||||||
@Nonnull
|
@Nonnull
|
||||||
private final GestureDetector gestureDetector;
|
private final GestureDetector gestureDetector;
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
private final Editor editor = App.getEditor();
|
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
private final Calculator calculator = Locator.getInstance().getCalculator();
|
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
private final Eraser eraser = new Eraser();
|
private final Eraser eraser = new Eraser();
|
||||||
|
|
||||||
private LongClickEraser(@Nonnull final View view) {
|
protected BaseLongClickEraser(@Nonnull final View view) {
|
||||||
this.view = view;
|
this.view = view;
|
||||||
this.gestureDetector = new GestureDetector(view.getContext(), new GestureDetector.SimpleOnGestureListener() {
|
this.gestureDetector = new GestureDetector(view.getContext(), new GestureDetector.SimpleOnGestureListener() {
|
||||||
public void onLongPress(MotionEvent e) {
|
public void onLongPress(MotionEvent e) {
|
||||||
@ -41,11 +27,7 @@ public final class LongClickEraser implements View.OnTouchListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
this.view.setOnTouchListener(this);
|
||||||
|
|
||||||
public static void createAndAttach(@Nonnull View view) {
|
|
||||||
final LongClickEraser l = new LongClickEraser(view);
|
|
||||||
view.setOnTouchListener(l);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -63,17 +45,21 @@ public final class LongClickEraser implements View.OnTouchListener {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract void onStopErase();
|
||||||
|
|
||||||
|
protected abstract void onStartErase();
|
||||||
|
|
||||||
|
protected abstract boolean erase();
|
||||||
|
|
||||||
private class Eraser implements Runnable {
|
private class Eraser implements Runnable {
|
||||||
private static final int DELAY = 300;
|
private static final int DELAY = 300;
|
||||||
private long delay;
|
private long delay;
|
||||||
private boolean erasing;
|
private boolean erasing;
|
||||||
private boolean tracking = true;
|
private boolean tracking = true;
|
||||||
private boolean wasCalculatingOnFly;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
final EditorState state = editor.erase();
|
if (!erase()) {
|
||||||
if (isEmpty(state.text)) {
|
|
||||||
stop();
|
stop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -89,10 +75,7 @@ public final class LongClickEraser implements View.OnTouchListener {
|
|||||||
delay = DELAY;
|
delay = DELAY;
|
||||||
view.removeCallbacks(this);
|
view.removeCallbacks(this);
|
||||||
view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
|
view.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
|
||||||
wasCalculatingOnFly = calculator.isCalculateOnFly();
|
onStartErase();
|
||||||
if (wasCalculatingOnFly) {
|
|
||||||
calculator.setCalculateOnFly(false);
|
|
||||||
}
|
|
||||||
run();
|
run();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,9 +86,7 @@ public final class LongClickEraser implements View.OnTouchListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
erasing = false;
|
erasing = false;
|
||||||
if (wasCalculatingOnFly) {
|
onStopErase();
|
||||||
calculator.setCalculateOnFly(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stopTracking() {
|
public void stopTracking() {
|
@ -1,66 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2013 serso aka se.solovyev
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*
|
|
||||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
* Contact details
|
|
||||||
*
|
|
||||||
* Email: se.solovyev@gmail.com
|
|
||||||
* Site: http://se.solovyev.org
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.solovyev.android.calculator.view;
|
|
||||||
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.os.Vibrator;
|
|
||||||
|
|
||||||
import org.solovyev.android.views.dragbutton.DragButton;
|
|
||||||
import org.solovyev.android.views.dragbutton.DragEvent;
|
|
||||||
import org.solovyev.android.views.dragbutton.DragListener;
|
|
||||||
import org.solovyev.android.views.dragbutton.DragListenerWrapper;
|
|
||||||
import org.solovyev.android.view.VibratorContainer;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User: serso
|
|
||||||
* Date: 4/20/12
|
|
||||||
* Time: 3:27 PM
|
|
||||||
*/
|
|
||||||
public class DragListenerVibrator extends DragListenerWrapper {
|
|
||||||
|
|
||||||
private static final float VIBRATION_TIME_SCALE = 0.5f;
|
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
private final VibratorContainer vibrator;
|
|
||||||
|
|
||||||
public DragListenerVibrator(@Nonnull DragListener dragListener,
|
|
||||||
@Nullable Vibrator vibrator,
|
|
||||||
@Nonnull SharedPreferences preferences) {
|
|
||||||
super(dragListener);
|
|
||||||
this.vibrator = new VibratorContainer(vibrator, preferences, VIBRATION_TIME_SCALE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onDrag(@Nonnull DragButton dragButton, @Nonnull DragEvent event) {
|
|
||||||
boolean consumed = super.onDrag(dragButton, event);
|
|
||||||
|
|
||||||
if (consumed) {
|
|
||||||
vibrator.vibrate();
|
|
||||||
}
|
|
||||||
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,54 @@
|
|||||||
|
package org.solovyev.android.calculator.view;
|
||||||
|
|
||||||
|
import android.text.Editable;
|
||||||
|
import android.view.HapticFeedbackConstants;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.EditText;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
public class EditTextLongClickEraser extends BaseLongClickEraser implements View.OnClickListener {
|
||||||
|
@Nonnull
|
||||||
|
private final EditText editView;
|
||||||
|
|
||||||
|
private EditTextLongClickEraser(@Nonnull View view, @Nonnull EditText editView) {
|
||||||
|
super(view);
|
||||||
|
this.editView = editView;
|
||||||
|
view.setOnClickListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void attachTo(@Nonnull View view, @Nonnull EditText editView) {
|
||||||
|
new EditTextLongClickEraser(view, editView);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStopErase() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStartErase() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean erase() {
|
||||||
|
final int start = editView.getSelectionStart();
|
||||||
|
final int end = editView.getSelectionEnd();
|
||||||
|
if (start < 0 || end < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final Editable text = editView.getText();
|
||||||
|
if (start != end) {
|
||||||
|
text.delete(Math.min(start, end), Math.max(start, end));
|
||||||
|
} else if (start > 0) {
|
||||||
|
text.delete(start - 1, start);
|
||||||
|
}
|
||||||
|
return text.length() != 0;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
erase();
|
||||||
|
v.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
package org.solovyev.android.calculator.view;
|
||||||
|
|
||||||
|
import android.view.View;
|
||||||
|
import org.solovyev.android.calculator.*;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
import static android.text.TextUtils.isEmpty;
|
||||||
|
|
||||||
|
public class EditorLongClickEraser extends BaseLongClickEraser {
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private final Editor editor = App.getEditor();
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private final Calculator calculator = Locator.getInstance().getCalculator();
|
||||||
|
|
||||||
|
private boolean wasCalculatingOnFly;
|
||||||
|
|
||||||
|
private EditorLongClickEraser(@Nonnull View view) {
|
||||||
|
super(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void attachTo(@Nonnull View view) {
|
||||||
|
new EditorLongClickEraser(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean erase() {
|
||||||
|
final EditorState state = editor.erase();
|
||||||
|
return !isEmpty(state.text);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStartErase() {
|
||||||
|
wasCalculatingOnFly = calculator.isCalculateOnFly();
|
||||||
|
if (wasCalculatingOnFly) {
|
||||||
|
calculator.setCalculateOnFly(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStopErase() {
|
||||||
|
if (wasCalculatingOnFly) {
|
||||||
|
calculator.setCalculateOnFly(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user