prefs: Report errors while editing custom layouts

Errors are obtained by running the parser, validation is throttle to
when the user stops editing for a second.
This commit is contained in:
Jules Aguillon 2023-12-17 11:56:17 +01:00
parent dd327cc812
commit 7af6adcf11
3 changed files with 71 additions and 3 deletions

View File

@ -6,6 +6,7 @@ import android.content.DialogInterface;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Handler;
import android.text.InputType;
import android.text.Layout;
import android.widget.EditText;
@ -37,6 +38,14 @@ public class CustomLayoutEditDialog
callback.select(null);
}
});
input.set_on_text_change(new LayoutEntryEditText.OnChangeListener()
{
public void on_change()
{
String error = callback.validate(input.getText().toString());
input.setError(error);
}
});
dialog.show();
}
@ -45,6 +54,11 @@ public class CustomLayoutEditDialog
/** The entered text when the user clicks "OK", [null] when the user
cancels editing. */
public void select(String text);
/** Return a human readable error string if the [text] contains an error.
Return [null] otherwise. The error string will be displayed atop the
input box. This method is called everytime the text changes. */
public String validate(String text);
}
/** An editable text view that shows line numbers. */
@ -52,6 +66,19 @@ public class CustomLayoutEditDialog
{
/** Used to draw line numbers. */
Paint _ln_paint;
OnChangeListener _on_change_listener = null;
/** Delay validation to when user stops typing for a second. */
Handler _on_change_throttler;
Runnable _on_change_delayed = new Runnable()
{
public void run()
{
OnChangeListener l = LayoutEntryEditText.this._on_change_listener;
if (l != null)
l.on_change();
}
};
public LayoutEntryEditText(Context ctx)
{
@ -61,6 +88,12 @@ public class CustomLayoutEditDialog
setHorizontallyScrolling(true);
setInputType(InputType.TYPE_CLASS_TEXT
| InputType.TYPE_TEXT_FLAG_MULTI_LINE);
_on_change_throttler = new Handler(ctx.getMainLooper());
}
public void set_on_text_change(OnChangeListener l)
{
_on_change_listener = l;
}
@Override
@ -86,5 +119,20 @@ public class CustomLayoutEditDialog
break;
}
}
@Override
protected void onTextChanged(CharSequence text, int _start, int _lengthBefore, int _lengthAfter)
{
if (_on_change_throttler != null)
{
_on_change_throttler.removeCallbacks(_on_change_delayed);
_on_change_throttler.postDelayed(_on_change_delayed, 1000);
}
}
public static interface OnChangeListener
{
public void on_change();
}
}
}

View File

@ -201,9 +201,7 @@ class KeyboardData
{
try
{
XmlPullParser parser = Xml.newPullParser();
parser.setInput(new StringReader(src));
return parse_keyboard(parser);
return load_string_exn(src);
}
catch (Exception e)
{
@ -211,6 +209,15 @@ class KeyboardData
}
}
/** Like [load_string] but throws an exception on error and do not return
[null]. */
public static KeyboardData load_string_exn(String src) throws Exception
{
XmlPullParser parser = Xml.newPullParser();
parser.setInput(new StringReader(src));
return parse_keyboard(parser);
}
private static KeyboardData parse_keyboard(XmlPullParser parser) throws Exception
{
if (!expect_tag(parser, "keyboard"))

View File

@ -177,6 +177,19 @@ public class LayoutsPreference extends ListGroupPreference<LayoutsPreference.Lay
else
callback.select(new CustomLayout(text));
}
public String validate(String text)
{
try
{
KeyboardData.load_string_exn(text);
return null; // Validation passed
}
catch (Exception e)
{
return e.getMessage();
}
}
});
}