diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/ClockLayout.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/ClockLayout.java index 6cefe72..6f36ae0 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/ClockLayout.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/ClockLayout.java @@ -22,6 +22,7 @@ final class ClockLayout { private final boolean fixedPlacement; private final int width; private final int height; + private final float textSizePx; private int placedLeft; private ClockLayout( @@ -33,7 +34,8 @@ final class ClockLayout { int placedLeft, boolean fixedPlacement, int width, - int height + int height, + float textSizePx ) { this.source = source; this.model = model; @@ -44,6 +46,7 @@ final class ClockLayout { this.fixedPlacement = fixedPlacement; this.width = width; this.height = height; + this.textSizePx = textSizePx; } static ClockLayout measure( @@ -54,7 +57,8 @@ final class ClockLayout { int rootWidth, Bounds cutoutBounds, boolean middleAutoNearestSide, - AnchorSide middleSide + AnchorSide middleSide, + float textSizePx ) { if (source == null || model == null || model.rows.isEmpty()) { return null; @@ -64,6 +68,7 @@ final class ClockLayout { ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); ClockProxyRenderer.copyTextStyleIfChanged(source, probe); + applyTextSizeOverride(probe, textSizePx); ArrayList measuredRows = new ArrayList<>(); for (int i = 0; i < model.rows.size(); i++) { ClockLayoutTextFactory.Row row = model.rows.get(i); @@ -121,7 +126,8 @@ final class ClockLayout { 0, false, alignment.width, - bounds.height); + bounds.height, + effectiveTextSize(source, textSizePx)); } static ClockLayout simpleText( @@ -172,7 +178,8 @@ final class ClockLayout { 0, false, width, - measured.height); + measured.height, + source.getTextSize()); } static int centeredTextBaseline(TextView source, int containerHeight) { @@ -338,7 +345,8 @@ final class ClockLayout { bounds.left, true, bounds.width, - bounds.height); + bounds.height, + textSizePx); } private static void addSplitSegment( @@ -493,7 +501,26 @@ final class ClockLayout { ClockPlacement placement() { String description = model != null ? model.contentDescription : String.valueOf(source.getText()); - return new ClockPlacement(source, description, rows, new Bounds(placedLeft, top, width, height)); + return new ClockPlacement( + source, + description, + rows, + new Bounds(placedLeft, top, width, height), + android.graphics.Color.TRANSPARENT, + textSizePx); + } + + private static void applyTextSizeOverride(TextView view, float textSizePx) { + if (view != null && textSizePx > 0f && view.getTextSize() != textSizePx) { + view.setTextSize(android.util.TypedValue.COMPLEX_UNIT_PX, textSizePx); + } + } + + private static float effectiveTextSize(TextView source, float textSizePx) { + if (textSizePx > 0f) { + return textSizePx; + } + return source != null ? source.getTextSize() : 0f; } private record MeasuredClockRow( diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/ClockProxyRenderer.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/ClockProxyRenderer.java index 9075696..91b730c 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/ClockProxyRenderer.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/ClockProxyRenderer.java @@ -51,7 +51,7 @@ final class ClockProxyRenderer { for (int i = 0; i < placement.rows.size(); i++) { ClockRow row = placement.rows.get(i); TextView view = views.get(i); - if (copyTextStyleIfChanged(placement.source, view)) { + if (copyTextStyleIfChanged(placement.source, view, placement.textSizePx)) { hostChanged = true; } if (applyTextColorOverrideIfNeeded(view, placement.textColorOverride)) { @@ -176,13 +176,18 @@ final class ClockProxyRenderer { } static boolean copyTextStyleIfChanged(TextView source, TextView target) { + return copyTextStyleIfChanged(source, target, 0f); + } + + static boolean copyTextStyleIfChanged(TextView source, TextView target, float textSizePx) { boolean changed = false; if (target.getCurrentTextColor() != source.getCurrentTextColor()) { target.setTextColor(source.getCurrentTextColor()); changed = true; } - if (target.getTextSize() != source.getTextSize()) { - target.setTextSize(android.util.TypedValue.COMPLEX_UNIT_PX, source.getTextSize()); + float desiredTextSize = textSizePx > 0f ? textSizePx : source.getTextSize(); + if (target.getTextSize() != desiredTextSize) { + target.setTextSize(android.util.TypedValue.COMPLEX_UNIT_PX, desiredTextSize); changed = true; } if (!Objects.equals(target.getTypeface(), source.getTypeface())) { diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/ClockRenderModels.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/ClockRenderModels.java index 1e297ff..8ab5c3b 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/ClockRenderModels.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/ClockRenderModels.java @@ -12,6 +12,7 @@ final class ClockPlacement { final ArrayList rows; final Bounds bounds; final int textColorOverride; + final float textSizePx; ClockPlacement( TextView source, @@ -19,7 +20,7 @@ final class ClockPlacement { ArrayList rows, Bounds bounds ) { - this(source, contentDescription, rows, bounds, android.graphics.Color.TRANSPARENT); + this(source, contentDescription, rows, bounds, android.graphics.Color.TRANSPARENT, 0f); } ClockPlacement( @@ -28,12 +29,24 @@ final class ClockPlacement { ArrayList rows, Bounds bounds, int textColorOverride + ) { + this(source, contentDescription, rows, bounds, textColorOverride, 0f); + } + + ClockPlacement( + TextView source, + String contentDescription, + ArrayList rows, + Bounds bounds, + int textColorOverride, + float textSizePx ) { this.source = source; this.contentDescription = contentDescription; this.rows = rows; this.bounds = bounds; this.textColorOverride = textColorOverride; + this.textSizePx = textSizePx; } } diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedIconSnapshotRenderController.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedIconSnapshotRenderController.java index 5aff65a..46d7fcd 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedIconSnapshotRenderController.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedIconSnapshotRenderController.java @@ -145,7 +145,7 @@ public final class UnlockedIconSnapshotRenderController { return new RenderResult(false, false, false); } } - currentClockLayout = buildClockLayout(root, anchors, settings); + currentClockLayout = buildClockLayout(root, anchors, settings, scene); currentClockGeometry = clockGeometrySignature( root, currentClockLayout, @@ -184,7 +184,7 @@ public final class UnlockedIconSnapshotRenderController { lastCollectedIconsByRoot.put(root, collectedIcons); } if (currentClockLayout == null && clockEnabledForScene(settings, scene)) { - currentClockLayout = buildClockLayout(root, anchors, settings); + currentClockLayout = buildClockLayout(root, anchors, settings, scene); currentClockGeometry = clockGeometrySignature( root, currentClockLayout, @@ -694,13 +694,16 @@ public final class UnlockedIconSnapshotRenderController { private ClockLayout buildClockLayout( View root, RootAnchors anchors, - SbtSettings settings + SbtSettings settings, + SceneKey scene ) { return buildClockLayout( root, anchors != null ? anchors.clockView : null, anchors != null ? anchors.clockContainer : null, + anchors, settings, + scene, UnlockedLayoutPlanner.cutoutBounds(ViewGeometry.middleCutout(root), settings != null ? settings.clockMiddleCutoutGapPx : 0)); } @@ -708,7 +711,9 @@ public final class UnlockedIconSnapshotRenderController { View root, TextView source, View clockContainer, + RootAnchors anchors, SbtSettings settings, + SceneKey scene, Bounds cutoutBounds ) { if (root == null || source == null || settings == null) { @@ -723,15 +728,53 @@ public final class UnlockedIconSnapshotRenderController { return null; } int baselineY = stableClockBaselineY(root, source, clockContainer); + int statusbarHeight = statusbarHeightForClock(root, sourceBounds, anchors, scene); + float textSizePx = clockTextSizePx(statusbarHeight, settings, scene); + int verticalOffsetPx = stepsToPx(settings.clockVerticalOffsetPx, statusbarHeight); return ClockLayout.measure( source, model, UnlockedLayoutPlanner.positionFor(settings.clockPosition), - baselineY - textOffsetScaler.scale(settings.clockVerticalOffsetPx, source), + baselineY - verticalOffsetPx, root.getWidth(), cutoutBounds, settings.clockMiddleAutoNearestSide, - UnlockedLayoutPlanner.sideFor(settings.clockMiddleCutoutSide)); + UnlockedLayoutPlanner.sideFor(settings.clockMiddleCutoutSide), + textSizePx); + } + + private float clockTextSizePx(int statusbarHeight, SbtSettings settings, SceneKey scene) { + int steps = scene != null && scene.isLockscreen() + ? settings.clockLockTextSizeSteps + : settings.clockTextSizeSteps; + return Math.max(1f, Math.max(1, statusbarHeight) * Math.max(1, steps) / 100f); + } + + private int statusbarHeightForClock( + View root, + Bounds sourceBounds, + RootAnchors anchors, + SceneKey scene + ) { + int stored = StatusbarHeightStore.get(root); + if (stored > 0) { + return stored; + } + Bounds statusBounds = StatusbarHeightSource.bounds(root, scene, anchors); + if (statusBounds != null && statusBounds.top >= 0 && statusBounds.height > 0) { + return Math.max(1, statusBounds.top + statusBounds.height); + } + if (sourceBounds != null && sourceBounds.top >= 0 && sourceBounds.height > 0) { + return Math.max(1, sourceBounds.top + sourceBounds.height); + } + return Math.max(1, root != null ? root.getHeight() : 1); + } + + private int stepsToPx(int steps, int statusbarHeight) { + if (steps == 0 || statusbarHeight <= 0) { + return 0; + } + return Math.round((float) steps * statusbarHeight / 100f); } private Integer clockGeometrySignature( @@ -870,7 +913,8 @@ public final class UnlockedIconSnapshotRenderController { model.contentDescription, rows, previousPlacement.bounds, - statusBarTintTargetColor()); + statusBarTintTargetColor(), + previousPlacement.textSizePx); } private Integer clockSourceGeometrySignature(TextView source) { @@ -930,7 +974,8 @@ public final class UnlockedIconSnapshotRenderController { currentText.contentDescription, rows, previous.bounds, - currentText.textColorOverride); + currentText.textColorOverride, + currentText.textSizePx); } private ClockRow matchingClockRow(ClockRow previousRow, ArrayList currentRows) { diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedLayoutBand.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedLayoutBand.java index 3d917b7..58fd7c5 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedLayoutBand.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedLayoutBand.java @@ -30,6 +30,7 @@ final class UnlockedLayoutBand { int clipEndPx; private int solverCollisionTop = Integer.MIN_VALUE; private int solverCollisionHeight = Integer.MIN_VALUE; + private int solverVerticalScaleHeight = 0; private UnlockedLayoutBand( LayoutItemKind kind, @@ -133,6 +134,11 @@ final class UnlockedLayoutBand { return this; } + UnlockedLayoutBand withSolverVerticalScale(int sourceHeight) { + solverVerticalScaleHeight = Math.max(0, sourceHeight); + return this; + } + static UnlockedLayoutBand dotIcons( LayoutItemKind kind, ViewGroup host, @@ -373,8 +379,20 @@ final class UnlockedLayoutBand { ArrayList solverCollisionBoxes() { ArrayList boxes = collisionBoxes(); - if (isTextKind() - || solverCollisionTop == Integer.MIN_VALUE + if (solverVerticalScaleHeight > 0 && !boxes.isEmpty()) { + ArrayList solverBoxes = new ArrayList<>(); + for (Bounds box : boxes) { + int top = pixelToStepFloor(box.top, solverVerticalScaleHeight); + int bottom = pixelToStepCeil(box.top + box.height, solverVerticalScaleHeight); + solverBoxes.add(new Bounds( + box.left, + top, + box.width, + Math.max(1, bottom - top))); + } + return solverBoxes; + } + if (solverCollisionTop == Integer.MIN_VALUE || solverCollisionHeight <= 0 || boxes.isEmpty()) { return boxes; @@ -390,6 +408,20 @@ final class UnlockedLayoutBand { return solverBoxes; } + private int pixelToStepFloor(int px, int sourceHeight) { + if (sourceHeight <= 0) { + return px; + } + return (int) Math.floor((px * 100.0) / sourceHeight); + } + + private int pixelToStepCeil(int px, int sourceHeight) { + if (sourceHeight <= 0) { + return px; + } + return (int) Math.ceil((px * 100.0) / sourceHeight); + } + private Bounds collisionBounds(SnapshotPlacement placement) { Bounds relative = relativeCollisionBounds(placement); Bounds bounds = placement.bounds; @@ -708,7 +740,8 @@ final class UnlockedLayoutBand { placement.contentDescription, rows, new Bounds(clipLeft, placement.bounds.top, Math.max(0, clipRight - clipLeft), placement.bounds.height), - placement.textColorOverride); + placement.textColorOverride, + placement.textSizePx); } private boolean isTextKind() { diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedLayoutPlanner.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedLayoutPlanner.java index bdb9a72..5f77cb5 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedLayoutPlanner.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedLayoutPlanner.java @@ -21,6 +21,7 @@ import se.ajpanton.statusbartweak.runtime.layoutsolver.PackedStatusBarLayoutSolv import se.ajpanton.statusbartweak.runtime.mode.NotificationDisplayStyle; import se.ajpanton.statusbartweak.runtime.mode.SceneKey; import se.ajpanton.statusbartweak.runtime.notifications.NotificationUnreadTracker; +import se.ajpanton.statusbartweak.shell.settings.SbtDefaults; import se.ajpanton.statusbartweak.shell.settings.SbtSettings; final class UnlockedLayoutPlanner { @@ -90,11 +91,15 @@ final class UnlockedLayoutPlanner { LayoutEdges edges = layoutEdges(root, settings, anchors, scene, aodStatusAnchorBounds); int statusbarHeight = statusbarHeight(root, anchors, scene, aodStatusContentBounds); if (clockEnabledForScene(settings, scene) && clockLayout != null && clockLayout.width() > 0) { + int clockHeightSteps = clockTextSizeSteps(settings, scene); bands.add(UnlockedLayoutBand.clock( clockHost, clockLayout, positionFor(settings.clockPosition), - sideFor(settings.clockMiddleCutoutSide))); + sideFor(settings.clockMiddleCutoutSide)) + .withSolverCollision( + logicalRowTop(clockHeightSteps, settings.clockVerticalOffsetPx), + clockHeightSteps)); } ClockLayout carrierLayout = carrierLayout( root, @@ -109,7 +114,8 @@ final class UnlockedLayoutPlanner { carrierHost, carrierLayout, positionFor(settings.layoutCarrierPosition), - sideFor(settings.layoutCarrierMiddleSide))); + sideFor(settings.layoutCarrierMiddleSide)) + .withSolverVerticalScale(statusbarHeight)); } int statusCount = statusCountForScene(settings, scene); if (scene != null && scene.isAod() && !isUsableAodAnchor(aodStatusAnchorBounds)) { @@ -147,16 +153,16 @@ final class UnlockedLayoutPlanner { placements, stepsToPx(verticalOffsetSteps, statusbarHeight)); if (!placements.isEmpty()) { - bands.add(UnlockedLayoutBand.icons( + UnlockedLayoutBand band = UnlockedLayoutBand.icons( LayoutItemKind.STATUS, statusHost, statusRenderer, placements, positionFor(stringAt(positions, i, settings.layoutStatusPosition)), - sideFor(stringAt(middleSides, i, settings.layoutStatusMiddleSide))) - .withSolverCollision( - logicalRowTop(statusHeightSteps, verticalOffsetSteps), - statusHeightSteps)); + sideFor(stringAt(middleSides, i, settings.layoutStatusMiddleSide))); + bands.add(band.withSolverCollision( + logicalRowTop(statusHeightSteps, verticalOffsetSteps), + statusHeightSteps)); } } } @@ -200,7 +206,7 @@ final class UnlockedLayoutPlanner { if (!placements.isEmpty()) { LayoutPosition position = positionFor(stringAt(positions, i, settings.layoutNotifPosition)); AnchorSide middleSide = sideFor(stringAt(middleSides, i, settings.layoutNotifMiddleSide)); - bands.add(dotNotificationScene + UnlockedLayoutBand band = dotNotificationScene ? UnlockedLayoutBand.dotIcons( LayoutItemKind.NOTIFICATIONS, notificationHost, @@ -208,19 +214,16 @@ final class UnlockedLayoutPlanner { placements, position, middleSide) - .withSolverCollision( - logicalRowTop(notificationHeightSteps, verticalOffsetSteps), - notificationHeightSteps) : UnlockedLayoutBand.icons( LayoutItemKind.NOTIFICATIONS, notificationHost, notificationRenderer, placements, position, - middleSide) - .withSolverCollision( - logicalRowTop(notificationHeightSteps, verticalOffsetSteps), - notificationHeightSteps)); + middleSide); + bands.add(band.withSolverCollision( + logicalRowTop(notificationHeightSteps, verticalOffsetSteps), + notificationHeightSteps)); } } } @@ -263,10 +266,17 @@ final class UnlockedLayoutPlanner { return new LayoutPlan(null, new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), null); } ArrayList itemOrder = orderedKinds(settings.layoutItemOrder); - splitClockIfNeeded(root, bands, itemOrder, clockCutoutBounds, settings); + splitClockIfNeeded(root, bands, itemOrder, clockCutoutBounds, settings, scene); sortBandsForItemOrder(bands, itemOrder); int itemPadding = Math.max(0, settings.layoutItemPaddingPx); - solveWithPackedLayout(root, edges, bands, layoutCutoutBounds, settings, itemPadding, scene); + solveWithPackedLayout( + root, + edges, + bands, + layoutCutoutBounds, + settings, + itemPadding, + scene); ArrayList statusPlacements = new ArrayList<>(); ArrayList notificationPlacements = new ArrayList<>(); @@ -1120,6 +1130,15 @@ final class UnlockedLayoutPlanner { return Math.max(1, height); } + private int clockTextSizeSteps(SbtSettings settings, SceneKey scene) { + if (settings == null) { + return SbtDefaults.CLOCK_TEXT_SIZE_STEPS_DEFAULT; + } + return scene != null && scene.isLockscreen() + ? settings.clockLockTextSizeSteps + : settings.clockTextSizeSteps; + } + private int statusIconHeightSteps(SbtSettings settings, SceneKey scene) { if (scene != null && scene.isLockscreen()) { return settings.layoutStatusLockIconHeightSteps; @@ -1260,7 +1279,8 @@ final class UnlockedLayoutPlanner { ArrayList bands, ArrayList itemOrder, Bounds cutoutBounds, - SbtSettings settings + SbtSettings settings, + SceneKey scene ) { if (root == null || cutoutBounds == null || bands == null || settings == null) { return; @@ -1291,16 +1311,23 @@ final class UnlockedLayoutPlanner { return; } bands.remove(index); + int clockHeightSteps = clockTextSizeSteps(settings, scene); bands.add(index, UnlockedLayoutBand.fixedClock( clockBand.host, splitLayouts.get(1), SplitRegion.RIGHT, - clockBand.middleSide)); + clockBand.middleSide) + .withSolverCollision( + logicalRowTop(clockHeightSteps, settings.clockVerticalOffsetPx), + clockHeightSteps)); bands.add(index, UnlockedLayoutBand.fixedClock( clockBand.host, splitLayouts.get(0), SplitRegion.LEFT, - clockBand.middleSide)); + clockBand.middleSide) + .withSolverCollision( + logicalRowTop(clockHeightSteps, settings.clockVerticalOffsetPx), + clockHeightSteps)); } private ArrayList bandsForPosition( @@ -1643,7 +1670,8 @@ final class UnlockedLayoutPlanner { first.contentDescription, rows, union, - first.textColorOverride); + first.textColorOverride, + first.textSizePx); } static Bounds cutoutBounds(Rect cutout, int cutoutGap) { diff --git a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedStockSourceCollector.java b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedStockSourceCollector.java index 1faeaf7..a4e9373 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedStockSourceCollector.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/runtime/render/UnlockedStockSourceCollector.java @@ -1487,6 +1487,8 @@ final class UnlockedStockSourceCollector { settings.clockMiddleAutoNearestSide, settings.clockMiddleCutoutGapPx, settings.clockVerticalOffsetPx, + settings.clockTextSizeSteps, + settings.clockLockTextSizeSteps, settings.clockShowSeconds, settings.clockShowDatePrefix, settings.clockCustomFormatEnabled, diff --git a/app/src/main/java/se/ajpanton/statusbartweak/shell/settings/SbtDefaults.java b/app/src/main/java/se/ajpanton/statusbartweak/shell/settings/SbtDefaults.java index 5cf513b..258b6ac 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/shell/settings/SbtDefaults.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/shell/settings/SbtDefaults.java @@ -82,6 +82,7 @@ public final class SbtDefaults { public static final int CLOCK_VERTICAL_OFFSET_PX_DEFAULT = 0; public static final int CLOCK_VERTICAL_OFFSET_PX_MIN = -99; public static final int CLOCK_VERTICAL_OFFSET_PX_MAX = 99; + public static final int CLOCK_TEXT_SIZE_STEPS_DEFAULT = 40; public static final boolean CLOCK_SHOW_SECONDS_DEFAULT = false; public static final boolean CLOCK_SHOW_DATE_PREFIX_DEFAULT = false; public static final boolean CLOCK_CUSTOM_FORMAT_ENABLED_DEFAULT = false; diff --git a/app/src/main/java/se/ajpanton/statusbartweak/shell/settings/SbtSettings.java b/app/src/main/java/se/ajpanton/statusbartweak/shell/settings/SbtSettings.java index 22b1005..7337bd2 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/shell/settings/SbtSettings.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/shell/settings/SbtSettings.java @@ -94,6 +94,8 @@ public final class SbtSettings { public static final String KEY_CLOCK_MIDDLE_AUTO_NEAREST_SIDE = "clock_middle_auto_nearest_side"; public static final String KEY_CLOCK_MIDDLE_CUTOUT_GAP_PX = "clock_middle_cutout_gap_px"; public static final String KEY_CLOCK_VERTICAL_OFFSET_PX = "clock_vertical_offset_px"; + public static final String KEY_CLOCK_TEXT_SIZE_STEPS = "clock_text_size_steps"; + public static final String KEY_CLOCK_LOCK_TEXT_SIZE_STEPS = "layout_lock_clock_text_size_steps"; public static final String KEY_CLOCK_SHOW_SECONDS = "clock_show_seconds"; public static final String KEY_CLOCK_SHOW_DATE_PREFIX = "clock_show_date_prefix"; public static final String KEY_CLOCK_CUSTOM_FORMAT_ENABLED = "clock_custom_format_enabled"; @@ -328,6 +330,8 @@ public final class SbtSettings { public final boolean clockMiddleAutoNearestSide; public final int clockMiddleCutoutGapPx; public final int clockVerticalOffsetPx; + public final int clockTextSizeSteps; + public final int clockLockTextSizeSteps; public final boolean clockShowSeconds; public final boolean clockShowDatePrefix; public final boolean clockCustomFormatEnabled; @@ -458,6 +462,8 @@ public final class SbtSettings { boolean clockMiddleAutoNearestSide, int clockMiddleCutoutGapPx, int clockVerticalOffsetPx, + int clockTextSizeSteps, + int clockLockTextSizeSteps, boolean clockShowSeconds, boolean clockShowDatePrefix, boolean clockCustomFormatEnabled, @@ -630,6 +636,8 @@ public final class SbtSettings { clockVerticalOffsetPx, SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_MIN, SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_MAX); + this.clockTextSizeSteps = clampIconHeightSteps(clockTextSizeSteps); + this.clockLockTextSizeSteps = clampIconHeightSteps(clockLockTextSizeSteps); this.clockShowSeconds = clockShowSeconds; this.clockShowDatePrefix = clockShowDatePrefix; this.clockCustomFormatEnabled = clockCustomFormatEnabled; @@ -889,6 +897,8 @@ public final class SbtSettings { SbtDefaults.CLOCK_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT, SbtDefaults.CLOCK_MIDDLE_CUTOUT_GAP_PX_DEFAULT, SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_DEFAULT, + SbtDefaults.CLOCK_TEXT_SIZE_STEPS_DEFAULT, + SbtDefaults.CLOCK_TEXT_SIZE_STEPS_DEFAULT, SbtDefaults.CLOCK_SHOW_SECONDS_DEFAULT, SbtDefaults.CLOCK_SHOW_DATE_PREFIX_DEFAULT, SbtDefaults.CLOCK_CUSTOM_FORMAT_ENABLED_DEFAULT, @@ -1212,6 +1222,10 @@ public final class SbtSettings { clampInt(prefs.getInt(KEY_CLOCK_VERTICAL_OFFSET_PX, SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_DEFAULT), SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_MIN, SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_MAX), + clampIconHeightSteps(prefs.getInt(KEY_CLOCK_TEXT_SIZE_STEPS, + SbtDefaults.CLOCK_TEXT_SIZE_STEPS_DEFAULT)), + clampIconHeightSteps(prefs.getInt(KEY_CLOCK_LOCK_TEXT_SIZE_STEPS, + SbtDefaults.CLOCK_TEXT_SIZE_STEPS_DEFAULT)), prefs.getBoolean(KEY_CLOCK_SHOW_SECONDS, SbtDefaults.CLOCK_SHOW_SECONDS_DEFAULT), prefs.getBoolean(KEY_CLOCK_SHOW_DATE_PREFIX, SbtDefaults.CLOCK_SHOW_DATE_PREFIX_DEFAULT), prefs.getBoolean(KEY_CLOCK_CUSTOM_FORMAT_ENABLED, SbtDefaults.CLOCK_CUSTOM_FORMAT_ENABLED_DEFAULT), @@ -1526,6 +1540,10 @@ public final class SbtSettings { clampInt(bundle.getInt(KEY_CLOCK_VERTICAL_OFFSET_PX, SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_DEFAULT), SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_MIN, SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_MAX), + clampIconHeightSteps(bundle.getInt(KEY_CLOCK_TEXT_SIZE_STEPS, + SbtDefaults.CLOCK_TEXT_SIZE_STEPS_DEFAULT)), + clampIconHeightSteps(bundle.getInt(KEY_CLOCK_LOCK_TEXT_SIZE_STEPS, + SbtDefaults.CLOCK_TEXT_SIZE_STEPS_DEFAULT)), bundle.getBoolean(KEY_CLOCK_SHOW_SECONDS, SbtDefaults.CLOCK_SHOW_SECONDS_DEFAULT), bundle.getBoolean(KEY_CLOCK_SHOW_DATE_PREFIX, SbtDefaults.CLOCK_SHOW_DATE_PREFIX_DEFAULT), bundle.getBoolean(KEY_CLOCK_CUSTOM_FORMAT_ENABLED, SbtDefaults.CLOCK_CUSTOM_FORMAT_ENABLED_DEFAULT), diff --git a/app/src/main/java/se/ajpanton/statusbartweak/shell/settings/SbtSettingsProvider.java b/app/src/main/java/se/ajpanton/statusbartweak/shell/settings/SbtSettingsProvider.java index 43d20cb..cfb3cb1 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/shell/settings/SbtSettingsProvider.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/shell/settings/SbtSettingsProvider.java @@ -139,6 +139,10 @@ public class SbtSettingsProvider extends ContentProvider { prefs.getInt(SbtSettings.KEY_CLOCK_MIDDLE_CUTOUT_GAP_PX, SbtDefaults.CLOCK_MIDDLE_CUTOUT_GAP_PX_DEFAULT)); out.putInt(SbtSettings.KEY_CLOCK_VERTICAL_OFFSET_PX, prefs.getInt(SbtSettings.KEY_CLOCK_VERTICAL_OFFSET_PX, SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_DEFAULT)); + out.putInt(SbtSettings.KEY_CLOCK_TEXT_SIZE_STEPS, + prefs.getInt(SbtSettings.KEY_CLOCK_TEXT_SIZE_STEPS, SbtDefaults.CLOCK_TEXT_SIZE_STEPS_DEFAULT)); + out.putInt(SbtSettings.KEY_CLOCK_LOCK_TEXT_SIZE_STEPS, + prefs.getInt(SbtSettings.KEY_CLOCK_LOCK_TEXT_SIZE_STEPS, SbtDefaults.CLOCK_TEXT_SIZE_STEPS_DEFAULT)); out.putBoolean(SbtSettings.KEY_CLOCK_SHOW_SECONDS, prefs.getBoolean(SbtSettings.KEY_CLOCK_SHOW_SECONDS, SbtDefaults.CLOCK_SHOW_SECONDS_DEFAULT)); out.putBoolean(SbtSettings.KEY_CLOCK_SHOW_DATE_PREFIX, diff --git a/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LayoutFragment.java b/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LayoutFragment.java index 66618e0..4700125 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LayoutFragment.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LayoutFragment.java @@ -92,6 +92,7 @@ public final class LayoutFragment extends Fragment { root.findViewById(R.id.clock_vertical_offset_plus_fast), root.findViewById(R.id.clock_vertical_offset_reset), SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_DEFAULT); + addClockTextSizeControl(root, prefs); bindStepper(prefs, SbtSettings.KEY_LAYOUT_NOTIF_VERTICAL_OFFSET_PX, root.findViewById(R.id.notif_vertical_offset_input), @@ -226,6 +227,7 @@ public final class LayoutFragment extends Fragment { countDefault, legacyEnabledDefault); LayoutXmlCardSupport.setIndexedCardTitle(requireContext(), sourceCard, sectionTitleId, 0, count); + setCompatPadding(sourceCard, count <= 1); boolean cardsMode = LockedNotificationModeUi.MODE_CARDS.equals( LockedNotificationModeUi.currentMode(requireContext())); LayoutSectionCopySupport.addDropdownRow( @@ -273,6 +275,8 @@ public final class LayoutFragment extends Fragment { middleSideDefault, verticalOffsetDefault, copyTag); + setTopMargin(copy, 0); + setCompatPadding(copy, false); cardsParent.addView(copy, Math.min(insertIndex, cardsParent.getChildCount())); } }; @@ -319,6 +323,19 @@ public final class LayoutFragment extends Fragment { null); } + private void addClockTextSizeControl(View root, SharedPreferences prefs) { + View row = LayoutXmlCardSupport.directSectionChild(root.findViewById(R.id.clock_position_group)); + if (row == null || !(row.getParent() instanceof LinearLayout parent)) { + return; + } + int index = parent.indexOfChild(row); + parent.addView(iconHeightControl( + prefs, + SbtSettings.KEY_CLOCK_TEXT_SIZE_STEPS, + SbtDefaults.CLOCK_TEXT_SIZE_STEPS_DEFAULT, + R.string.layout_clock_text_size_steps), Math.max(0, index)); + } + private void addChipHeightControl(View root, SharedPreferences prefs) { View offsetInput = root.findViewById(R.id.chip_vertical_offset_input); if (offsetInput == null) { @@ -473,6 +490,20 @@ public final class LayoutFragment extends Fragment { return null; } + private void setTopMargin(View view, int topDp) { + if (view == null || !(view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams params)) { + return; + } + params.topMargin = ViewTreeSupport.dp(requireContext(), topDp); + view.setLayoutParams(params); + } + + private void setCompatPadding(View view, boolean enabled) { + if (view instanceof MaterialCardView card) { + card.setUseCompatPadding(enabled); + } + } + private void removeGeneratedCopyCards(@Nullable LinearLayout parent, String tag) { if (parent == null) { return; diff --git a/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LayoutSectionCopySupport.java b/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LayoutSectionCopySupport.java index 3bb6f67..f8e6893 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LayoutSectionCopySupport.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LayoutSectionCopySupport.java @@ -246,12 +246,14 @@ final class LayoutSectionCopySupport { "layout_lock_clock_middle_auto_nearest_side", "layout_lock_clock_middle_side", "layout_lock_clock_vertical_offset_px", + SbtSettings.KEY_CLOCK_LOCK_TEXT_SIZE_STEPS, null, SbtDefaults.CLOCK_ENABLED_LOCKSCREEN_DEFAULT, SbtDefaults.CLOCK_POSITION_DEFAULT, SbtDefaults.CLOCK_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT, SbtDefaults.CLOCK_MIDDLE_CUTOUT_SIDE_DEFAULT, SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_DEFAULT, + SbtDefaults.CLOCK_TEXT_SIZE_STEPS_DEFAULT, 1); } return new KeySet( @@ -260,12 +262,14 @@ final class LayoutSectionCopySupport { SbtSettings.KEY_CLOCK_MIDDLE_AUTO_NEAREST_SIDE, SbtSettings.KEY_CLOCK_MIDDLE_CUTOUT_SIDE, SbtSettings.KEY_CLOCK_VERTICAL_OFFSET_PX, + SbtSettings.KEY_CLOCK_TEXT_SIZE_STEPS, null, SbtDefaults.CLOCK_ENABLED_UNLOCKED_DEFAULT, SbtDefaults.CLOCK_POSITION_DEFAULT, SbtDefaults.CLOCK_MIDDLE_AUTO_NEAREST_SIDE_DEFAULT, SbtDefaults.CLOCK_MIDDLE_CUTOUT_SIDE_DEFAULT, SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_DEFAULT, + SbtDefaults.CLOCK_TEXT_SIZE_STEPS_DEFAULT, 1); } diff --git a/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LockedSceneLayoutFragment.java b/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LockedSceneLayoutFragment.java index 47e3183..5795642 100644 --- a/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LockedSceneLayoutFragment.java +++ b/app/src/main/java/se/ajpanton/statusbartweak/shell/ui/LockedSceneLayoutFragment.java @@ -114,6 +114,7 @@ abstract class LockedSceneLayoutFragment extends Fragment { SbtDefaults.CLOCK_MIDDLE_CUTOUT_SIDE_DEFAULT, sceneKey("clock_vertical_offset_px"), SbtDefaults.CLOCK_VERTICAL_OFFSET_PX_DEFAULT); + addClockTextSizeControl(context, prefs, clockCard); LayoutSectionCopySupport.addDropdown( context, prefs, @@ -357,10 +358,11 @@ abstract class LockedSceneLayoutFragment extends Fragment { countKey, count, rebuild[0]); + setCompatPadding(primary, count <= 1); addCopyDropdownToCard(context, prefs, primary, copySection, cardsMode, refresh); wrapper.addView(primary); for (int i = 1; i < count; i++) { - wrapper.addView(configuredIconContainerCard( + View copy = configuredIconContainerCard( context, prefs, cardId, @@ -390,7 +392,10 @@ abstract class LockedSceneLayoutFragment extends Fragment { null, null, count, - null)); + null); + setTopMargin(context, copy, 0); + setCompatPadding(copy, false); + wrapper.addView(copy); } }; rebuild[0].run(); @@ -513,6 +518,25 @@ abstract class LockedSceneLayoutFragment extends Fragment { return card; } + private void addClockTextSizeControl(Context context, SharedPreferences prefs, View card) { + View row = LayoutXmlCardSupport.directSectionChild( + card != null ? card.findViewById(R.id.clock_position_group) : null); + if (row == null || !(row.getParent() instanceof LinearLayout parent)) { + return; + } + int index = parent.indexOfChild(row); + parent.addView( + sizeStepper( + context, + prefs, + R.string.layout_clock_text_size_steps, + SbtSettings.KEY_CLOCK_LOCK_TEXT_SIZE_STEPS, + SbtDefaults.CLOCK_TEXT_SIZE_STEPS_DEFAULT, + SbtDefaults.LAYOUT_ICON_HEIGHT_STEPS_MIN, + SbtDefaults.LAYOUT_ICON_HEIGHT_STEPS_MAX), + Math.max(0, index)); + } + private void configureSingleEnabledCheckbox( View root, SharedPreferences prefs, @@ -839,6 +863,20 @@ abstract class LockedSceneLayoutFragment extends Fragment { return content instanceof LinearLayout layout ? layout : null; } + private void setTopMargin(Context context, View view, int topDp) { + if (view == null || !(view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams params)) { + return; + } + params.topMargin = ViewTreeSupport.dp(context, topDp); + view.setLayoutParams(params); + } + + private void setCompatPadding(View view, boolean enabled) { + if (view instanceof com.google.android.material.card.MaterialCardView card) { + card.setUseCompatPadding(enabled); + } + } + private View outlinedCard(Context context, int titleId, View content) { return ViewTreeSupport.outlinedCard( context, diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e8a5cbc..8280e3d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -198,6 +198,7 @@ Copy from Number of containers Icon height (% of statusbar) + Clock text size (% of statusbar) Chip height (% of statusbar) Locked notifications mode Mirrors the Samsung notification display style for AOD and lockscreen.