Redesign the UI after the fitness reference and replace the logo
Light sage-to-cream ambient backdrop, frosted glass controls and painted SceneArt landscapes in place of photography. Home becomes a dashboard with a two-tone greeting, a frosted summary ring, category portraits, an up-next rail of image-led cards and a floating glass tab bar. The routine library gets an image header and painted cards; the player gets a scene stage, steps on an arc, a dotted clock and a night pill with a lime spark. Goals become painted cards in their own colour. New logo: a lime sun resting on a ground line under two arcs. The splash raises the sun and lights the arcs; launcher icons and native splash are regenerated to match. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KhQh614DMeYoQEH9SoMRUw
This commit is contained in:
175
frontend/lib/Grounded/designs/DotDigits.dart
Normal file
175
frontend/lib/Grounded/designs/DotDigits.dart
Normal file
@@ -0,0 +1,175 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../utils/Colors.dart';
|
||||
|
||||
/// A clock face drawn as a string of dots traced along each digit's outline —
|
||||
/// the runner's signature readout. Only digits and ':' are drawn.
|
||||
class DotDigits extends StatelessWidget {
|
||||
final String value;
|
||||
|
||||
/// Glyph height in logical pixels.
|
||||
final double height;
|
||||
|
||||
final Color? color;
|
||||
|
||||
const DotDigits({
|
||||
super.key,
|
||||
required this.value,
|
||||
this.height = 64,
|
||||
this.color,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final _DotDigitsPainter painter =
|
||||
_DotDigitsPainter(value, height, color ?? colorInk);
|
||||
|
||||
return CustomPaint(size: painter.measure(), painter: painter);
|
||||
}
|
||||
}
|
||||
|
||||
class _DotDigitsPainter extends CustomPainter {
|
||||
final String value;
|
||||
|
||||
final double height;
|
||||
|
||||
final Color color;
|
||||
|
||||
_DotDigitsPainter(this.value, this.height, this.color);
|
||||
|
||||
/// Glyphs live in a 1 × 1.6 box.
|
||||
double get _scale => height / 1.6;
|
||||
|
||||
double get _digitWidth => _scale * 1.0;
|
||||
|
||||
double get _colonWidth => _scale * 0.5;
|
||||
|
||||
double get _tracking => _scale * 0.34;
|
||||
|
||||
Size measure() {
|
||||
double width = 0;
|
||||
for (int i = 0; i < value.length; i++) {
|
||||
width = width + (value[i] == ':' ? _colonWidth : _digitWidth);
|
||||
if (i != value.length - 1) {
|
||||
width = width + _tracking;
|
||||
}
|
||||
}
|
||||
return Size(width + height * 0.08, height + height * 0.08);
|
||||
}
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final double dot = height * 0.036;
|
||||
final double gap = height * 0.082;
|
||||
final Paint paint = Paint()..color = color;
|
||||
|
||||
canvas.translate(height * 0.04, height * 0.04);
|
||||
|
||||
double x = 0;
|
||||
for (int i = 0; i < value.length; i++) {
|
||||
final String glyph = value[i];
|
||||
|
||||
if (glyph == ':') {
|
||||
canvas.drawCircle(
|
||||
Offset(x + _colonWidth / 2, _scale * 0.52), dot * 1.25, paint);
|
||||
canvas.drawCircle(
|
||||
Offset(x + _colonWidth / 2, _scale * 1.12), dot * 1.25, paint);
|
||||
x = x + _colonWidth + _tracking;
|
||||
continue;
|
||||
}
|
||||
|
||||
final Path? outline = _glyph(glyph);
|
||||
if (outline != null) {
|
||||
final Path placed = outline.transform(
|
||||
(Matrix4.identity()
|
||||
..translateByDouble(x, 0, 0, 1)
|
||||
..scaleByDouble(_scale, _scale, 1, 1))
|
||||
.storage);
|
||||
|
||||
for (PathMetric metric in placed.computeMetrics()) {
|
||||
final int count = (metric.length / gap).floor().clamp(1, 400);
|
||||
final double step = metric.length / count;
|
||||
final int last = metric.isClosed ? count - 1 : count;
|
||||
for (int n = 0; n <= last; n++) {
|
||||
final Tangent? tangent = metric.getTangentForOffset(n * step);
|
||||
if (tangent != null) {
|
||||
canvas.drawCircle(tangent.position, dot, paint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
x = x + _digitWidth + _tracking;
|
||||
}
|
||||
}
|
||||
|
||||
Path? _glyph(String glyph) {
|
||||
switch (glyph) {
|
||||
case '0':
|
||||
return Path()
|
||||
..addRRect(RRect.fromRectAndRadius(
|
||||
const Rect.fromLTWH(0, 0, 1, 1.6), const Radius.circular(0.5)));
|
||||
case '1':
|
||||
return Path()
|
||||
..moveTo(0.22, 0.32)
|
||||
..lineTo(0.6, 0)
|
||||
..lineTo(0.6, 1.6);
|
||||
case '2':
|
||||
return Path()
|
||||
..moveTo(0.03, 0.4)
|
||||
..cubicTo(0.06, 0.02, 0.97, 0.0, 0.97, 0.44)
|
||||
..cubicTo(0.97, 0.8, 0.05, 1.08, 0.0, 1.6)
|
||||
..lineTo(1.0, 1.6);
|
||||
case '3':
|
||||
return Path()
|
||||
..moveTo(0.04, 0.26)
|
||||
..cubicTo(0.2, -0.06, 0.95, 0.0, 0.95, 0.4)
|
||||
..cubicTo(0.95, 0.68, 0.66, 0.78, 0.4, 0.78)
|
||||
..cubicTo(0.76, 0.78, 1.0, 0.92, 1.0, 1.2)
|
||||
..cubicTo(1.0, 1.66, 0.18, 1.7, 0.0, 1.34);
|
||||
case '4':
|
||||
return Path()
|
||||
..moveTo(0.76, 1.6)
|
||||
..lineTo(0.76, 0.0)
|
||||
..lineTo(0.0, 1.12)
|
||||
..lineTo(1.0, 1.12);
|
||||
case '5':
|
||||
return Path()
|
||||
..moveTo(0.92, 0.0)
|
||||
..lineTo(0.14, 0.0)
|
||||
..lineTo(0.06, 0.72)
|
||||
..cubicTo(0.36, 0.54, 1.0, 0.6, 1.0, 1.08)
|
||||
..cubicTo(1.0, 1.66, 0.2, 1.7, 0.0, 1.36);
|
||||
case '6':
|
||||
return Path()
|
||||
..moveTo(0.86, 0.14)
|
||||
..cubicTo(0.44, -0.12, 0.0, 0.24, 0.0, 1.1)
|
||||
..addOval(const Rect.fromLTWH(0.0, 0.66, 1.0, 0.94));
|
||||
case '7':
|
||||
return Path()
|
||||
..moveTo(0.0, 0.0)
|
||||
..lineTo(1.0, 0.0)
|
||||
..lineTo(0.34, 1.6);
|
||||
case '8':
|
||||
return Path()
|
||||
..addOval(const Rect.fromLTWH(0.08, 0.0, 0.84, 0.74))
|
||||
..addOval(const Rect.fromLTWH(0.0, 0.74, 1.0, 0.86));
|
||||
case '9':
|
||||
return Path()
|
||||
..addOval(const Rect.fromLTWH(0.0, 0.0, 1.0, 0.94))
|
||||
..moveTo(1.0, 0.5)
|
||||
..cubicTo(1.0, 1.36, 0.56, 1.72, 0.14, 1.46);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(covariant _DotDigitsPainter oldDelegate) {
|
||||
return oldDelegate.value != value ||
|
||||
oldDelegate.height != height ||
|
||||
oldDelegate.color != color;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user