From 2215b11e6f217d6e6943bb28be4790f7ea677536 Mon Sep 17 00:00:00 2001 From: serso Date: Thu, 7 Jan 2016 12:11:07 +0100 Subject: [PATCH] Text highlighter optimizations --- ...berBuilder.java => BaseNumberBuilder.java} | 19 +- .../calculator/CalculatorKeyboardImpl.java | 4 +- .../android/calculator/LiteNumberBuilder.java | 20 +- .../android/calculator/NumberBuilder.java | 77 +++---- .../calculator/ToJsclTextProcessor.java | 12 +- .../android/calculator/math/MathType.java | 94 ++------- .../calculator/math/edit/VarEditorSaver.java | 2 +- .../text/FromJsclSimplifyTextProcessor.java | 8 +- .../calculator/view/EditorTextProcessor.java | 3 +- .../calculator/view/TextHighlighter.java | 195 +++++++++--------- .../android/calculator/math/MathTypeTest.java | 18 +- 11 files changed, 191 insertions(+), 261 deletions(-) rename app/src/main/java/org/solovyev/android/calculator/{AbstractNumberBuilder.java => BaseNumberBuilder.java} (81%) diff --git a/app/src/main/java/org/solovyev/android/calculator/AbstractNumberBuilder.java b/app/src/main/java/org/solovyev/android/calculator/BaseNumberBuilder.java similarity index 81% rename from app/src/main/java/org/solovyev/android/calculator/AbstractNumberBuilder.java rename to app/src/main/java/org/solovyev/android/calculator/BaseNumberBuilder.java index 728c4d6f..1337587f 100644 --- a/app/src/main/java/org/solovyev/android/calculator/AbstractNumberBuilder.java +++ b/app/src/main/java/org/solovyev/android/calculator/BaseNumberBuilder.java @@ -22,6 +22,8 @@ package org.solovyev.android.calculator; +import android.text.SpannableStringBuilder; + import org.solovyev.android.calculator.math.MathType; import org.solovyev.common.text.Strings; @@ -35,7 +37,7 @@ import jscl.NumeralBase; * Date: 12/15/11 * Time: 9:01 PM */ -public abstract class AbstractNumberBuilder { +public abstract class BaseNumberBuilder { @Nonnull protected final CalculatorEngine engine; @@ -46,7 +48,7 @@ public abstract class AbstractNumberBuilder { @Nullable protected NumeralBase nb; - protected AbstractNumberBuilder(@Nonnull CalculatorEngine engine) { + protected BaseNumberBuilder(@Nonnull CalculatorEngine engine) { this.engine = engine; this.nb = engine.getNumeralBase(); } @@ -58,15 +60,14 @@ public abstract class AbstractNumberBuilder { * @return true if we can continue of processing of current number, if false - new number should be constructed */ protected boolean canContinue(@Nonnull MathType.Result mathTypeResult) { - boolean result = mathTypeResult.getMathType().getGroupType() == MathType.MathGroupType.number && + return mathTypeResult.type.getGroupType() == MathType.MathGroupType.number && !spaceBefore(mathTypeResult) && numeralBaseCheck(mathTypeResult) && - numeralBaseInTheStart(mathTypeResult.getMathType()) || isSignAfterE(mathTypeResult); - return result; + numeralBaseInTheStart(mathTypeResult.type) || isSignAfterE(mathTypeResult); } private boolean spaceBefore(@Nonnull MathType.Result mathTypeResult) { - return numberBuilder == null && Strings.isEmpty(mathTypeResult.getMatch().trim()); + return numberBuilder == null && Strings.isEmpty(mathTypeResult.match.trim()); } private boolean numeralBaseInTheStart(@Nonnull MathType mathType) { @@ -74,12 +75,12 @@ public abstract class AbstractNumberBuilder { } private boolean numeralBaseCheck(@Nonnull MathType.Result mathType) { - return mathType.getMathType() != MathType.digit || getNumeralBase().getAcceptableCharacters().contains(mathType.getMatch().charAt(0)); + return mathType.type != MathType.digit || getNumeralBase().getAcceptableCharacters().contains(mathType.match.charAt(0)); } private boolean isSignAfterE(@Nonnull MathType.Result mathTypeResult) { if (!isHexMode()) { - final String match = mathTypeResult.getMatch(); + final String match = mathTypeResult.match; if ("−".equals(match) || "-".equals(match) || "+".equals(match)) { final StringBuilder localNb = numberBuilder; if (localNb != null && localNb.length() > 0) { @@ -100,4 +101,6 @@ public abstract class AbstractNumberBuilder { protected NumeralBase getNumeralBase() { return nb == null ? engine.getNumeralBase() : nb; } + + public abstract int process(@Nonnull SpannableStringBuilder sb, @Nonnull MathType.Result result); } diff --git a/app/src/main/java/org/solovyev/android/calculator/CalculatorKeyboardImpl.java b/app/src/main/java/org/solovyev/android/calculator/CalculatorKeyboardImpl.java index 386bdbb8..479b3814 100644 --- a/app/src/main/java/org/solovyev/android/calculator/CalculatorKeyboardImpl.java +++ b/app/src/main/java/org/solovyev/android/calculator/CalculatorKeyboardImpl.java @@ -63,7 +63,7 @@ public class CalculatorKeyboardImpl implements CalculatorKeyboard { final StringBuilder textToBeInserted = new StringBuilder(text); final MathType.Result mathType = MathType.getType(text, 0, false); - switch (mathType.getMathType()) { + switch (mathType.type) { case function: textToBeInserted.append("()"); cursorPositionOffset = -1; @@ -78,7 +78,7 @@ public class CalculatorKeyboardImpl implements CalculatorKeyboard { } if (cursorPositionOffset == 0) { - if (MathType.openGroupSymbols.contains(text)) { + if (MathType.groupSymbols.contains(text)) { cursorPositionOffset = -1; } } diff --git a/app/src/main/java/org/solovyev/android/calculator/LiteNumberBuilder.java b/app/src/main/java/org/solovyev/android/calculator/LiteNumberBuilder.java index 1051a61f..2e8160a8 100644 --- a/app/src/main/java/org/solovyev/android/calculator/LiteNumberBuilder.java +++ b/app/src/main/java/org/solovyev/android/calculator/LiteNumberBuilder.java @@ -22,6 +22,8 @@ package org.solovyev.android.calculator; +import android.text.SpannableStringBuilder; + import org.solovyev.android.calculator.math.MathType; import javax.annotation.Nonnull; @@ -34,27 +36,33 @@ import jscl.NumeralBase; * Time: 8:33 PM */ -public class LiteNumberBuilder extends AbstractNumberBuilder { +public class LiteNumberBuilder extends BaseNumberBuilder { public LiteNumberBuilder(@Nonnull CalculatorEngine engine) { super(engine); this.nb = engine.getNumeralBase(); } - public void process(@Nonnull MathType.Result mathTypeResult) { - if (canContinue(mathTypeResult)) { + @Override + public int process(@Nonnull SpannableStringBuilder sb, @Nonnull MathType.Result result) { + process(result); + return 0; + } + + public void process(@Nonnull MathType.Result result) { + if (canContinue(result)) { // let's continue building number if (numberBuilder == null) { // if new number => create new builder numberBuilder = new StringBuilder(); } - if (mathTypeResult.getMathType() != MathType.numeral_base) { + if (result.type != MathType.numeral_base) { // just add matching string - numberBuilder.append(mathTypeResult.getMatch()); + numberBuilder.append(result.match); } else { // set explicitly numeral base (do not include it into number) - nb = NumeralBase.getByPrefix(mathTypeResult.getMatch()); + nb = NumeralBase.getByPrefix(result.match); } } else { diff --git a/app/src/main/java/org/solovyev/android/calculator/NumberBuilder.java b/app/src/main/java/org/solovyev/android/calculator/NumberBuilder.java index 9a45b80c..def678de 100644 --- a/app/src/main/java/org/solovyev/android/calculator/NumberBuilder.java +++ b/app/src/main/java/org/solovyev/android/calculator/NumberBuilder.java @@ -22,8 +22,9 @@ package org.solovyev.android.calculator; +import android.text.SpannableStringBuilder; + import org.solovyev.android.calculator.math.MathType; -import org.solovyev.common.MutableObject; import java.util.ArrayList; import java.util.List; @@ -46,35 +47,28 @@ import jscl.text.Parser; * Date: 10/23/11 * Time: 2:57 PM */ -public class NumberBuilder extends AbstractNumberBuilder { +public class NumberBuilder extends BaseNumberBuilder { public NumberBuilder(@Nonnull CalculatorEngine engine) { super(engine); } - @Nullable - private static MathType.Result replaceNumberInText(@Nonnull StringBuilder text, - @Nullable String number, - int trimmedChars, - @Nullable MutableObject offset, - @Nonnull NumeralBase nb, - @Nonnull final MathEngine engine) { - MathType.Result result = null; - - if (number != null) { - // in any case remove old number from text - final int oldNumberLength = number.length() + trimmedChars; - text.delete(text.length() - oldNumberLength, text.length()); - - final String newNumber = formatNumber(number, nb, engine); - if (offset != null) { - // register offset between old number and new number - offset.setObject(newNumber.length() - oldNumberLength); - } - text.append(newNumber); + private static int replaceNumberInText(@Nonnull SpannableStringBuilder sb, + @Nullable String number, + int trimmedChars, + @Nonnull NumeralBase nb, + @Nonnull final MathEngine engine) { + if (number == null) { + return 0; } + // in any case remove old number from text + final int oldNumberLength = number.length() + trimmedChars; + sb.delete(sb.length() - oldNumberLength, sb.length()); - return result; + final String newNumber = formatNumber(number, nb, engine); + sb.append(newNumber); + // offset between old number and new number + return newNumber.length() - oldNumberLength; } @Nonnull @@ -138,47 +132,40 @@ public class NumberBuilder extends AbstractNumberBuilder { /** * Method replaces number in text according to some rules (e.g. formatting) * - * @param text text where number can be replaced - * @param mathTypeResult math type result of current token - * @param offset offset between new number length and old number length (newNumberLength - oldNumberLength) - * @return new math type result (as one can be changed due to substituting of number with constant) + * @param sb text where number can be replaced + * @param result math type result of current token + * @return offset between new number length and old number length (newNumberLength - oldNumberLength) */ - @Nonnull - public MathType.Result process(@Nonnull StringBuilder text, @Nonnull MathType.Result mathTypeResult, @Nullable MutableObject offset) { - final MathType.Result possibleResult; - if (canContinue(mathTypeResult)) { + @Override + public int process(@Nonnull SpannableStringBuilder sb, @Nonnull MathType.Result result) { + if (canContinue(result)) { // let's continue building number if (numberBuilder == null) { // if new number => create new builder numberBuilder = new StringBuilder(); } - if (mathTypeResult.getMathType() != MathType.numeral_base) { + if (result.type != MathType.numeral_base) { // just add matching string - numberBuilder.append(mathTypeResult.getMatch()); + numberBuilder.append(result.match); } else { // set explicitly numeral base (do not include it into number) - nb = NumeralBase.getByPrefix(mathTypeResult.getMatch()); + nb = NumeralBase.getByPrefix(result.match); } - - possibleResult = null; + return 0; } else { // process current number (and go to the next one) - possibleResult = processNumber(text, offset); + return processNumber(sb); } - - return possibleResult == null ? mathTypeResult : possibleResult; } /** * Method replaces number in text according to some rules (e.g. formatting) * - * @param text text where number can be replaced - * @param offset offset between new number length and old number length (newNumberLength - oldNumberLength) - * @return new math type result (as one can be changed due to substituting of number with constant) + * @param sb text where number can be replaced + * @return offset between new number length and old number length (newNumberLength - oldNumberLength) */ - @Nullable - public MathType.Result processNumber(@Nonnull StringBuilder text, @Nullable MutableObject offset) { + public int processNumber(@Nonnull SpannableStringBuilder sb) { // total number of trimmed chars int trimmedChars = 0; @@ -216,6 +203,6 @@ public class NumberBuilder extends AbstractNumberBuilder { nb = engine.getNumeralBase(); } - return replaceNumberInText(text, number, trimmedChars, offset, localNb, engine.getMathEngine0()); + return replaceNumberInText(sb, number, trimmedChars, localNb, engine.getMathEngine0()); } } diff --git a/app/src/main/java/org/solovyev/android/calculator/ToJsclTextProcessor.java b/app/src/main/java/org/solovyev/android/calculator/ToJsclTextProcessor.java index b2029a19..68772526 100644 --- a/app/src/main/java/org/solovyev/android/calculator/ToJsclTextProcessor.java +++ b/app/src/main/java/org/solovyev/android/calculator/ToJsclTextProcessor.java @@ -78,20 +78,20 @@ public class ToJsclTextProcessor implements TextProcessor 0) { - throw new CalculatorParseException(i, s, new CalculatorMessage(CalculatorMessages.msg_005, MessageType.error, mathTypeBefore.getMatch())); + throw new CalculatorParseException(i, s, new CalculatorMessage(CalculatorMessages.msg_005, MessageType.error, mathTypeBefore.match)); } } diff --git a/app/src/main/java/org/solovyev/android/calculator/math/MathType.java b/app/src/main/java/org/solovyev/android/calculator/math/MathType.java index a06d655c..1b769211 100644 --- a/app/src/main/java/org/solovyev/android/calculator/math/MathType.java +++ b/app/src/main/java/org/solovyev/android/calculator/math/MathType.java @@ -129,7 +129,7 @@ public enum MathType { } }, - open_group_symbol(800, true, false, MathGroupType.other, "[", "(", "{") { + open_group_symbol(800, true, false, MathGroupType.other, "(", "[", "{") { @Override public boolean isNeedMultiplicationSignBefore(@Nonnull MathType mathTypeBefore) { return super.isNeedMultiplicationSignBefore(mathTypeBefore) && mathTypeBefore != function && mathTypeBefore != operator; @@ -141,7 +141,7 @@ public enum MathType { } }, - close_group_symbol(900, false, true, MathGroupType.other, "]", ")", "}") { + close_group_symbol(900, false, true, MathGroupType.other, ")", "]", "}") { @Override public boolean isNeedMultiplicationSignBefore(@Nonnull MathType mathTypeBefore) { return false; @@ -223,68 +223,10 @@ public enum MathType { } }; - public static final List openGroupSymbols = Arrays.asList("[]", "()", "{}"); + public static final List groupSymbols = Arrays.asList("()", "[]", "{}"); public final static Character POWER_10 = 'E'; - public static final String IMAGINARY_NUMBER = "i"; - public static final String IMAGINARY_NUMBER_JSCL = "√(-1)"; - public static final String PI = "π"; public static final String E = "e"; public static final String C = "c"; - public static final Double C_VALUE = 299792458d; - public static final String G = "G"; - - /* public static int getPostfixFunctionStart(@Nonnull CharSequence s, int position) throws ParseException { - assert s.length() > position; - - int numberOfOpenGroups = 0; - int result = position; - for (; result >= 0; result--) { - - final MathType mathType = getType(s.toString(), result).getMathType(); - - if (Collections.contains(mathType, digit, dot, grouping_separator, power_10)) { - // continue - } else if (mathType == close_group_symbol) { - numberOfOpenGroups++; - } else if (mathType == open_group_symbol) { - if (numberOfOpenGroups > 0) { - numberOfOpenGroups--; - } else { - break; - } - } else { - if (stop(s, numberOfOpenGroups, result)) break; - } - } - - if (numberOfOpenGroups != 0){ - throw new ParseException("Could not find start of prefix function!"); - } - - return result; - } - - public static boolean stop(CharSequence s, int numberOfOpenGroups, int i) { - if (numberOfOpenGroups == 0) { - if (i > 0) { - final EndsWithFinder endsWithFinder = new EndsWithFinder(s); - endsWithFinder.setI(i + 1); - if (!Collections.contains(function.getTokens(), FilterType.included, endsWithFinder)) { - MathType type = getType(s.toString(), i).getMathType(); - if (type != constant) { - return true; - } - } - } else { - return true; - } - } - - return false; - }*/ - public static final Double G_VALUE = 6.6738480E-11; - public static final String H_REDUCED = "h"; - public static final Double H_REDUCED_VALUE = 6.6260695729E-34 / (2 * Math.PI); public final static String NAN = "NaN"; public final static String INFINITY = "∞"; public final static String INFINITY_JSCL = "Infinity"; @@ -425,6 +367,14 @@ public enum MathType { return null; } + public static boolean isOpenGroupSymbol(char c) { + return c == '(' || c == '[' || c == '{'; + } + + public static boolean isCloseGroupSymbol(char c) { + return c == ')' || c == ']' || c == '}'; + } + public static enum MathGroupType { function, number, @@ -435,33 +385,23 @@ public enum MathType { public static class Result { @Nonnull - private final MathType mathType; + public final MathType type; @Nonnull - private final String match; + public final String match; - public Result(@Nonnull MathType mathType, @Nonnull String match) { - this.mathType = mathType; + public Result(@Nonnull MathType type, @Nonnull String match) { + this.type = type; this.match = match; } public int processToJscl(@Nonnull StringBuilder result, int i) throws CalculatorParseException { - return mathType.processToJscl(result, i, match); + return type.processToJscl(result, i, match); } public int processFromJscl(@Nonnull StringBuilder result, int i) { - return mathType.processFromJscl(result, i, match); - } - - @Nonnull - public String getMatch() { - return match; - } - - @Nonnull - public MathType getMathType() { - return mathType; + return type.processFromJscl(result, i, match); } } diff --git a/app/src/main/java/org/solovyev/android/calculator/math/edit/VarEditorSaver.java b/app/src/main/java/org/solovyev/android/calculator/math/edit/VarEditorSaver.java index b98d126c..0f11bf51 100644 --- a/app/src/main/java/org/solovyev/android/calculator/math/edit/VarEditorSaver.java +++ b/app/src/main/java/org/solovyev/android/calculator/math/edit/VarEditorSaver.java @@ -120,7 +120,7 @@ public class VarEditorSaver implements View.OnClickListene if (canBeSaved) { final MathType.Result mathType = MathType.getType(name, 0, false); - if (mathType.getMathType() == MathType.text || mathType.getMathType() == MathType.constant) { + if (mathType.type == MathType.text || mathType.type == MathType.constant) { if (Strings.isEmpty(value)) { // value is empty => undefined variable diff --git a/app/src/main/java/org/solovyev/android/calculator/text/FromJsclSimplifyTextProcessor.java b/app/src/main/java/org/solovyev/android/calculator/text/FromJsclSimplifyTextProcessor.java index d6ede8f7..336c1242 100644 --- a/app/src/main/java/org/solovyev/android/calculator/text/FromJsclSimplifyTextProcessor.java +++ b/app/src/main/java/org/solovyev/android/calculator/text/FromJsclSimplifyTextProcessor.java @@ -81,14 +81,14 @@ public class FromJsclSimplifyTextProcessor implements TextProcessor numberOffset = new MutableObject<>(0); - ((NumberBuilder) numberBuilder).process(text1, mathType, numberOffset); - resultOffset += numberOffset.getObject(); - } else { - ((LiteNumberBuilder) numberBuilder).process(mathType); - } + offset += nb.process(sb, result); - final String match = mathType.getMatch(); - switch (mathType.getMathType()) { + final String match = result.match; + switch (result.type) { case open_group_symbol: - numberOfOpenGroupSymbols++; - maxNumberOfOpenGroupSymbols = Math.max(maxNumberOfOpenGroupSymbols, numberOfOpenGroupSymbols); - text1.append(text.charAt(i)); + openGroupsCount++; + groupsCount = Math.max(groupsCount, openGroupsCount); + sb.append(text.charAt(i)); break; case close_group_symbol: - numberOfOpenGroupSymbols--; - text1.append(text.charAt(i)); + openGroupsCount--; + sb.append(text.charAt(i)); break; case operator: - text1.append(match); - if (match.length() > 1) { - i += match.length() - 1; - } + i += append(sb, match); break; case function: - i = processHighlightedText(text1, i, match, "i", null); + i += append(sb, match); + makeItalic(sb, i + 1 - match.length(), i + 1); break; case constant: - i = processHighlightedText(text1, i, match, "b", null); - break; case numeral_base: - i = processHighlightedText(text1, i, match, "b", null); + i += append(sb, match); + makeBold(sb, i + 1 - match.length(), i + 1); break; default: - if (mathType.getMathType() == MathType.text || match.length() <= 1) { - text1.append(text.charAt(i)); + if (result.type == MathType.text || match.length() <= 1) { + sb.append(text.charAt(i)); } else { - text1.append(match); - i += match.length() - 1; + i += append(sb, match); } } } - if (numberBuilder instanceof NumberBuilder) { - final MutableObject numberOffset = new MutableObject(0); - ((NumberBuilder) numberBuilder).processNumber(text1, numberOffset); - resultOffset += numberOffset.getObject(); + if (nb instanceof NumberBuilder) { + offset += ((NumberBuilder) nb).processNumber(sb); } - if (maxNumberOfOpenGroupSymbols > 0) { - - final StringBuilder text2 = new StringBuilder(text1.length()); - - int i = processBracketGroup(text2, text1, 0, 0, maxNumberOfOpenGroupSymbols); - for (; i < text1.length(); i++) { - text2.append(text1.charAt(i)); - } - - result = text2.toString(); - } else { - result = text1.toString(); + if (groupsCount == 0) { + return new TextProcessorEditorResult(sb, offset); } - - return new TextProcessorEditorResult(result, resultOffset); + final List groupSpans = new ArrayList<>(groupsCount); + fillGroupSpans(sb, 0, 0, groupsCount, groupSpans); + for (GroupSpan groupSpan : Lists.reverse(groupSpans)) { + makeColor(sb, groupSpan.start, groupSpan.end, getColor(groupSpan.group, groupsCount)); + } + return new TextProcessorEditorResult(sb, offset); } - private int processHighlightedText(@Nonnull StringBuilder result, int i, @Nonnull String match, @Nonnull String tag, @Nullable Map tagAttributes) { - result.append("<").append(tag); - - if (tagAttributes != null && !tagAttributes.entrySet().isEmpty()) { - for (Map.Entry entry : tagAttributes.entrySet()) { - // attr1="attr1_value" attr2="attr2_value" - result.append(" ").append(entry.getKey()).append("=\"").append(entry.getValue()).append("\""); - } - } - - result.append(">").append(match).append(""); + private int append(SpannableStringBuilder t, String match) { + t.append(match); if (match.length() > 1) { - return i + match.length() - 1; - } else { - return i; + return match.length() - 1; } + return 0; } - private int processBracketGroup(@Nonnull StringBuilder result, @Nonnull CharSequence s, int i, int numberOfOpenings, int maxNumberOfGroups) { + private static void makeItalic(@Nonnull SpannableStringBuilder t, int start, int end) { + t.setSpan(new StyleSpan(Typeface.ITALIC), start, end, SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE); + } - result.append(""); + private static void makeBold(@Nonnull SpannableStringBuilder t, int start, int end) { + t.setSpan(new StyleSpan(Typeface.BOLD), start, end, SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE); + } - for (; i < s.length(); i++) { - char ch = s.charAt(i); - String strCh = String.valueOf(ch); + private static void makeColor(@Nonnull SpannableStringBuilder t, int start, int end, int color) { + t.setSpan(new ForegroundColorSpan(color), start, end, SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE); + } - if (MathType.open_group_symbol.getTokens().contains(strCh)) { - result.append(ch); - result.append(""); - i = processBracketGroup(result, s, i + 1, numberOfOpenings + 1, maxNumberOfGroups); - result.append(""); - if (i < s.length() && MathType.close_group_symbol.getTokens().contains(String.valueOf(s.charAt(i)))) { - result.append(s.charAt(i)); - } - } else if (MathType.close_group_symbol.getTokens().contains(strCh)) { - break; - } else { - result.append(ch); + private int fillGroupSpans(@Nonnull SpannableStringBuilder sb, int start, int group, int groupsCount, @Nonnull List spans) { + for (int i = start; i < sb.length(); i++) { + final char c = sb.charAt(i); + if (MathType.isOpenGroupSymbol(c)) { + i = highlightGroup(sb, i, group + 1, groupsCount, spans); + } else if (MathType.isCloseGroupSymbol(c)) { + return i; } } - result.append(""); - - - return i; + return sb.length(); } - private String getColor(int totalNumberOfOpenings, int numberOfOpenings) { - int offset = ((int) (255 * 0.8)) * numberOfOpenings / (totalNumberOfOpenings + 1); + private int highlightGroup(SpannableStringBuilder sb, int start, int group, int groupsCount, @Nonnull List spans) { + final int end = fillGroupSpans(sb, start + 1, group, groupsCount, spans); + if (start + 1 < end) { + spans.add(new GroupSpan(start + 1, end, group)); + } + return end; + } + + private int getColor(int group, int groupsCount) { + int offset = ((int) (255 * 0.8)) * group / (groupsCount + 1); if (!dark) { offset = -offset; } // for tests: // int result = Color.rgb(BASE_COLOUR_RED_COMPONENT - offset, BASE_COLOUR_GREEN_COMPONENT - offset, BASE_COLOUR_BLUE_COMPONENT - offset); - int result = (0xFF << 24) | ((red + offset) << 16) | ((green + offset) << 8) | (blue + offset); + return (0xFF << 24) | ((red + offset) << 16) | ((green + offset) << 8) | (blue + offset); + } - return "#" + App.toColorString(result); + private static class GroupSpan { + final int start; + final int end; + final int group; + + private GroupSpan(int start, int end, int group) { + Check.isTrue(start < end); + this.start = start; + this.end = end; + this.group = group; + } } } diff --git a/app/src/test/java/org/solovyev/android/calculator/math/MathTypeTest.java b/app/src/test/java/org/solovyev/android/calculator/math/MathTypeTest.java index 2e2628e9..885f68b9 100644 --- a/app/src/test/java/org/solovyev/android/calculator/math/MathTypeTest.java +++ b/app/src/test/java/org/solovyev/android/calculator/math/MathTypeTest.java @@ -45,29 +45,29 @@ public class MathTypeTest extends AbstractCalculatorTest { @Test public void testGetType() throws Exception { - assertEquals(MathType.function, MathType.getType("sin", 0, false).getMathType()); - assertEquals(MathType.text, MathType.getType("sn", 0, false).getMathType()); - assertEquals(MathType.text, MathType.getType("s", 0, false).getMathType()); - assertEquals(MathType.text, MathType.getType("", 0, false).getMathType()); + assertEquals(MathType.function, MathType.getType("sin", 0, false).type); + assertEquals(MathType.text, MathType.getType("sn", 0, false).type); + assertEquals(MathType.text, MathType.getType("s", 0, false).type); + assertEquals(MathType.text, MathType.getType("", 0, false).type); try { - assertEquals(MathType.text, MathType.getType("22", -1, false).getMathType()); + assertEquals(MathType.text, MathType.getType("22", -1, false).type); Assert.fail(); } catch (IllegalArgumentException e) { } try { - assertEquals(MathType.text, MathType.getType("22", 2, false).getMathType()); + assertEquals(MathType.text, MathType.getType("22", 2, false).type); Assert.fail(); } catch (IllegalArgumentException e) { } - assertEquals("atanh", MathType.getType("atanh", 0, false).getMatch()); + assertEquals("atanh", MathType.getType("atanh", 0, false).match); } @Test public void testPostfixFunctionsProcessing() throws Exception { - assertEquals(postfix_function, MathType.getType("5!", 1, false).getMathType()); - assertEquals(postfix_function, MathType.getType("!", 0, false).getMathType()); + assertEquals(postfix_function, MathType.getType("5!", 1, false).type); + assertEquals(postfix_function, MathType.getType("!", 0, false).type); } }