From 7144b130f73807eab6bb67b692740b401ca1ba53 Mon Sep 17 00:00:00 2001 From: ajp_anton Date: Thu, 18 Jun 2026 14:39:44 +0000 Subject: [PATCH] Allow line break shorthand tags --- .../features/clock/ClockMarkupSupport.java | 18 +++++---- .../features/clock/ClockPatternParser.java | 37 ++++++++++++++----- .../clock/ClockPatternParserTest.java | 21 +++++++++++ 3 files changed, 59 insertions(+), 17 deletions(-) create mode 100644 app/src/test/java/se/ajpanton/statusbartweak/runtime/features/clock/ClockPatternParserTest.java diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/features/clock/ClockMarkupSupport.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/features/clock/ClockMarkupSupport.java index 288e24e..57e115e 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/runtime/features/clock/ClockMarkupSupport.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/features/clock/ClockMarkupSupport.java @@ -1,7 +1,5 @@ package se.ajpanton.statusbartweak.runtime.features.clock; -import android.text.TextUtils; - import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -94,7 +92,7 @@ final class ClockMarkupSupport { } static void applyParsedTag(StringBuilder out, TagState state, ParsedTag parsedTag) { - if (TextUtils.isEmpty(parsedTag.name)) { + if (isEmpty(parsedTag.name)) { return; } if (parsedTag.selfClosing) { @@ -125,7 +123,7 @@ final class ClockMarkupSupport { String literal, TagCategory category ) { - if (TextUtils.isEmpty(name) || TextUtils.isEmpty(literal)) { + if (isEmpty(name) || isEmpty(literal)) { return; } if (category == TagCategory.FONT_COLOR) { @@ -140,7 +138,7 @@ final class ClockMarkupSupport { } private static void closeTag(StringBuilder out, TagState state, String name) { - if (TextUtils.isEmpty(name)) { + if (isEmpty(name)) { return; } String normalized = name.toLowerCase(Locale.ROOT); @@ -187,7 +185,7 @@ final class ClockMarkupSupport { } static ParsedTag parseTagLiteral(String literal) { - if (TextUtils.isEmpty(literal)) { + if (isEmpty(literal)) { return null; } String trimmed = literal.trim(); @@ -232,7 +230,7 @@ final class ClockMarkupSupport { } static List findPipePositions(String markup) { - if (TextUtils.isEmpty(markup)) { + if (isEmpty(markup)) { return Collections.emptyList(); } ArrayList positions = new ArrayList<>(); @@ -262,7 +260,7 @@ final class ClockMarkupSupport { } static boolean containsSecondsPattern(String pattern) { - if (TextUtils.isEmpty(pattern)) { + if (isEmpty(pattern)) { return false; } boolean insideTag = false; @@ -300,4 +298,8 @@ final class ClockMarkupSupport { } return false; } + + private static boolean isEmpty(CharSequence value) { + return value == null || value.length() == 0; + } } diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/features/clock/ClockPatternParser.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/features/clock/ClockPatternParser.java index dfa51b9..45f144b 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/runtime/features/clock/ClockPatternParser.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/features/clock/ClockPatternParser.java @@ -1,7 +1,5 @@ package se.ajpanton.statusbartweak.runtime.features.clock; -import android.text.TextUtils; - import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -42,6 +40,13 @@ final class ClockPatternParser { rowMarkup = new StringBuilder(); ClockMarkupSupport.appendOpenTags(rowMarkup, carriedState); rowSyntaxError = false; + if (!isEmpty(lineBreak.trailingShorthand)) { + try { + appendShorthandBlock(rowMarkup, rowState, lineBreak.trailingShorthand); + } catch (IllegalArgumentException e) { + rowSyntaxError = true; + } + } gapBeforePx = lineBreak.gapBeforePx; index = lineBreak.endIndex; continue; @@ -111,7 +116,7 @@ final class ClockPatternParser { } private ClockParsedPattern.ClockParsedRow buildParsedRow(String markup, int gapBeforePx) { - if (TextUtils.isEmpty(markup)) { + if (isEmpty(markup)) { return ClockParsedPattern.ClockParsedRow.plain("", gapBeforePx); } List pipePositions = ClockMarkupSupport.findPipePositions(markup); @@ -153,7 +158,7 @@ final class ClockPatternParser { } ArrayList tokens = tokenizeShorthand(trimmed); for (String token : tokens) { - if (TextUtils.isEmpty(token)) { + if (isEmpty(token)) { continue; } if ("/font".equalsIgnoreCase(token)) { @@ -260,6 +265,10 @@ final class ClockPatternParser { && value.endsWith(")"); } + private boolean isEmpty(CharSequence value) { + return value == null || value.length() == 0; + } + private void openClockColorTag( StringBuilder out, ClockMarkupSupport.TagState tagState, @@ -281,7 +290,7 @@ final class ClockPatternParser { private LineBreakToken tryParseLineBreak(String pattern, int index) { if (pattern.startsWith("\\n", index)) { - return new LineBreakToken(index + 2, false, ROW_GAP_AUTO); + return new LineBreakToken(index + 2, false, ROW_GAP_AUTO, ""); } if (pattern.charAt(index) != '{') { return null; @@ -296,10 +305,11 @@ final class ClockPatternParser { resetPropagation = true; body = body.substring(1).trim(); } - if (!body.startsWith("\\n")) { + ArrayList tokens = tokenizeShorthand(body); + if (tokens.isEmpty() || !tokens.get(0).startsWith("\\n")) { return null; } - String gapText = body.substring(2).trim(); + String gapText = tokens.get(0).substring(2).trim(); int gapBeforePx = ROW_GAP_AUTO; if (!gapText.isEmpty()) { try { @@ -308,18 +318,27 @@ final class ClockPatternParser { throw new IllegalArgumentException("Invalid row gap", e); } } - return new LineBreakToken(end + 1, resetPropagation, gapBeforePx); + StringBuilder trailingShorthand = new StringBuilder(); + for (int i = 1; i < tokens.size(); i++) { + if (trailingShorthand.length() > 0) { + trailingShorthand.append(' '); + } + trailingShorthand.append(tokens.get(i)); + } + return new LineBreakToken(end + 1, resetPropagation, gapBeforePx, trailingShorthand.toString()); } private static final class LineBreakToken { final int endIndex; final boolean resetPropagation; final int gapBeforePx; + final String trailingShorthand; - LineBreakToken(int endIndex, boolean resetPropagation, int gapBeforePx) { + LineBreakToken(int endIndex, boolean resetPropagation, int gapBeforePx, String trailingShorthand) { this.endIndex = endIndex; this.resetPropagation = resetPropagation; this.gapBeforePx = gapBeforePx; + this.trailingShorthand = trailingShorthand != null ? trailingShorthand : ""; } } } diff --git a/app/src/test/java/se/ajpanton/statusbartweak/runtime/features/clock/ClockPatternParserTest.java b/app/src/test/java/se/ajpanton/statusbartweak/runtime/features/clock/ClockPatternParserTest.java new file mode 100644 index 0000000..fd2d328 --- /dev/null +++ b/app/src/test/java/se/ajpanton/statusbartweak/runtime/features/clock/ClockPatternParserTest.java @@ -0,0 +1,21 @@ +package se.ajpanton.statusbartweak.runtime.features.clock; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public final class ClockPatternParserTest { + private final ClockPatternParser parser = new ClockPatternParser(); + + @Test + public void lineBreakBlockAcceptsFollowingShorthandTags() { + ClockParsedPattern combined = parser.parse("HH{\\n30 big}mm"); + ClockParsedPattern split = parser.parse("HH{\\n30}{big}mm"); + + assertEquals(split.rows.size(), combined.rows.size()); + assertEquals(2, combined.rows.size()); + assertEquals(split.rows.get(1).gapBeforePx, combined.rows.get(1).gapBeforePx); + assertEquals(30, combined.rows.get(1).gapBeforePx); + assertEquals(split.rows.get(1).markup, combined.rows.get(1).markup); + } +}