garage_auth, garage_entitlements, garage_iap and garage_ui, moved out of Garage-Services and Metro-Map-Maker into one public repo. MIT, one readme, docs under docs/. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013F4NWNvYcdeSgqbWMT1VQ7
188 lines
6.3 KiB
Dart
188 lines
6.3 KiB
Dart
import "package:flutter/widgets.dart";
|
|
import "package:flutter_test/flutter_test.dart";
|
|
import "package:garage_ui/garage_ui.dart";
|
|
|
|
import "support/test_scheme.dart";
|
|
|
|
// A property row used to be label + control and nothing else, so a page
|
|
// needing to explain a setting had to either fold it into the label or give up
|
|
// and hardcode a Text somewhere. Two slots now:
|
|
//
|
|
// subtitle - inside the label column, right aligned against the split
|
|
// description - full width under the whole row
|
|
//
|
|
// Both render at density.textXxs, which is the rung below the control font -
|
|
// it didnt exist before either, because in A&A the control font is already the
|
|
// smallest thing on screen.
|
|
|
|
Widget _host(Widget child, {Density density = const Density()}) => Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: GarageTheme(
|
|
data: ThemeData(colorScheme: testScheme, density: density),
|
|
child: Center(child: SizedBox(width: 400, child: child)),
|
|
),
|
|
);
|
|
|
|
double _fontOf(WidgetTester tester, String text) {
|
|
final widget = tester.widget<Text>(find.text(text));
|
|
return widget.style!.fontSize!;
|
|
}
|
|
|
|
void main() {
|
|
testWidgets("subtitle and description both render at textXxs", (
|
|
tester,
|
|
) async {
|
|
await tester.pumpWidget(
|
|
_host(
|
|
PropertyRow(
|
|
label: "Username",
|
|
subtitle: "Display name used across dashboard",
|
|
description: "Changing this breaks any links to your old name.",
|
|
scheme: testScheme,
|
|
child: const SizedBox(),
|
|
),
|
|
),
|
|
);
|
|
|
|
const density = Density();
|
|
expect(density.textXxs, 9.0); // 10 * 0.875, rounded
|
|
expect(_fontOf(tester, "Display name used across dashboard"), 9.0);
|
|
expect(_fontOf(tester, "Changing this breaks any links to your old name."),
|
|
9.0);
|
|
});
|
|
|
|
testWidgets("both slots track the density", (tester) async {
|
|
await tester.pumpWidget(
|
|
_host(
|
|
PropertyRow(
|
|
label: "Username",
|
|
subtitle: "a subtitle",
|
|
scheme: testScheme,
|
|
child: const SizedBox(),
|
|
),
|
|
density: const Density(fontSize: 16.0, lineHeight: 1.25),
|
|
),
|
|
);
|
|
|
|
expect(_fontOf(tester, "a subtitle"), 14.0); // 16 * 0.875
|
|
});
|
|
|
|
testWidgets("a description makes the row taller, not the control shorter", (
|
|
tester,
|
|
) async {
|
|
Future<double> heightWith({String? description}) async {
|
|
await tester.pumpWidget(
|
|
_host(
|
|
PropertyRow(
|
|
key: const Key("row"),
|
|
label: "Username",
|
|
description: description,
|
|
scheme: testScheme,
|
|
child: const SizedBox(),
|
|
),
|
|
),
|
|
);
|
|
// the row eases between heights now, so the frame straight after the
|
|
// pump is still the old one.
|
|
await tester.pumpAndSettle();
|
|
return tester.getSize(find.byKey(const Key("row"))).height;
|
|
}
|
|
|
|
final bare = await heightWith();
|
|
final withCopy = await heightWith(description: "some copy");
|
|
|
|
// the bare row is the row minimum - controlHeight plus a step, so that
|
|
// neither the control nor the label column is the thing setting it. a
|
|
// description adds on top of that rather than squeezing into it.
|
|
expect(bare, const Density().propertyRowHeight);
|
|
expect(withCopy, greaterThan(bare));
|
|
});
|
|
|
|
testWidgets("the gap between section rows is gapXs, off the density", (
|
|
tester,
|
|
) async {
|
|
// the numbers PropertiesSection used to hardcode - 4 between rows, 8 under
|
|
// the last - are exactly gapXs and gapMd at compact, which is the tell they
|
|
// were always meant to be these tokens. at normal they should now move.
|
|
const compact = Density();
|
|
const normal = Density.normal();
|
|
expect(compact.gapXs, 4.0);
|
|
expect(normal.gapXs, 5.0);
|
|
|
|
Future<double> gapBetweenRows(Density density) async {
|
|
await tester.pumpWidget(
|
|
_host(
|
|
PropertiesSection(
|
|
title: "Profile",
|
|
scheme: testScheme,
|
|
collapsed: false,
|
|
onToggle: () {},
|
|
rows: [
|
|
for (var i = 0; i < 2; i++)
|
|
PropertyRow(
|
|
key: Key("row$i"),
|
|
label: "Row $i",
|
|
scheme: testScheme,
|
|
child: const SizedBox(),
|
|
),
|
|
],
|
|
),
|
|
density: density,
|
|
),
|
|
);
|
|
final first = tester.getRect(find.byKey(const Key("row0")));
|
|
final second = tester.getRect(find.byKey(const Key("row1")));
|
|
return second.top - first.bottom;
|
|
}
|
|
|
|
expect(await gapBetweenRows(compact), compact.gapXs);
|
|
expect(await gapBetweenRows(normal), normal.gapXs);
|
|
});
|
|
|
|
testWidgets("a subtitle doesnt change the row height", (tester) async {
|
|
// the whole reason the minimum sits above controlHeight. a label plus a
|
|
// subtitle is laid out on the font's own metrics; at plain controlHeight
|
|
// that made the LABEL COLUMN set the row height on some fonts and not
|
|
// others. both rows have to come out the same.
|
|
Future<double> h({String? subtitle}) async {
|
|
await tester.pumpWidget(
|
|
_host(
|
|
PropertyRow(
|
|
key: const Key("row"),
|
|
label: "Username",
|
|
subtitle: subtitle,
|
|
scheme: testScheme,
|
|
child: const TextField(),
|
|
),
|
|
),
|
|
);
|
|
// the row eases between heights now, so the frame straight after the
|
|
// pump is still the old one.
|
|
await tester.pumpAndSettle();
|
|
return tester.getSize(find.byKey(const Key("row"))).height;
|
|
}
|
|
|
|
expect(await h(subtitle: "a subtitle"), await h());
|
|
});
|
|
|
|
test("the row minimum clears whichever of the two is taller", () {
|
|
// at compact the LABEL COLUMN is the binding one - 26 against a 23px
|
|
// control - which is the whole reason this token exists. at the roomier
|
|
// tiers the control wins again. either way the row clears both, so a
|
|
// subtitle never changes the height.
|
|
const compact = Density();
|
|
expect(compact.labelColumnHeight, 26.0);
|
|
expect(compact.controlHeight, 23.0);
|
|
expect(compact.propertyRowHeight, 28.0);
|
|
|
|
const normal = Density.normal();
|
|
expect(normal.labelColumnHeight, 26.0);
|
|
expect(normal.propertyRowHeight, normal.controlHeight + normal.gapXxs);
|
|
|
|
for (final d in [compact, normal]) {
|
|
expect(d.propertyRowHeight, greaterThan(d.labelColumnHeight));
|
|
expect(d.propertyRowHeight, greaterThan(d.controlHeight));
|
|
}
|
|
});
|
|
}
|