BOOK NOW, OpenStreetMap, and one segmented control instead of two

── The circle says what pressing it does ──

"ONE TOUCH" named the *mechanism* — one gesture, no form — which is something
the product team knows and a customer has to be taught. Nobody arrives at that
screen wanting a touch; they want a parcel collected. The caption under the
sphere still carries what makes it different from the form below.

Renamed in the comments too. A codebase explaining "One Touch" against a button
that says BOOK NOW is a trap for whoever reads it next.

── OpenStreetMap everywhere ──

One line: the default provider was CARTO, it is `osm`. Nothing else moves —
`DmMapTiles` already reads the template, subdomains, retina flag and
attribution off the provider, so the credit line follows on its own.

One thing recorded on the provider itself rather than left to be discovered:
these are donated servers and the OSM Foundation's tile policy does not permit
a distributed app to lean on them. A block looks like every tile turning into
the ground colour at once, with no other symptom. Moving off it is one define —
`DM_MAP_PROVIDER=carto|maptiler|stadia`, all serving OpenStreetMap data — and
the map_config test now asserts the identifying User-Agent rather than only the
URL, because that is what attributable traffic depends on.

── Orders had a second copy of the segmented control ──

Its own `_Tab`, a pill radius, 3pt of padding and the count folded into the
label's text — beside the pickup window's day switcher, which is DmChoiceChip
in a rounded groove with 4pt of padding and the count in a bubble. Two controls
doing one job, drifting apart a padding value at a time.

It is the same control now, and `_Tab` is gone. DmChoiceChip's horizontal
padding drops 12 → 9: three of them split a 390pt phone and "Cancelled"
truncated to "Cancell…" at the old value. The day switcher has two chips and
acres of room, so it loses nothing.
This commit is contained in:
2026-09-30 11:19:30 +05:30
parent 8757b16cf5
commit c7a74c57b8
24 changed files with 98 additions and 121 deletions

View File

@@ -92,7 +92,7 @@ Future<void> serverAdvance(
/// The sheet is left open: tests that are about the sheet itself go no
/// further.
Future<void> openSend(WidgetTester tester) async {
await tester.tap(find.text('ONE TOUCH'));
await tester.tap(find.text('BOOK NOW'));
await settle(tester);
}
@@ -218,14 +218,14 @@ void main() {
await tester.tap(find.text('Sign in'));
await settle(tester);
expect(find.text('That number or PIN is incorrect'), findsOneWidget);
expect(find.text('ONE TOUCH'), findsNothing);
expect(find.text('BOOK NOW'), findsNothing);
// The right one lands on Home.
await tester.enterText(find.byType(TextField).first, '1234');
await settle(tester, 200);
await tester.tap(find.text('Sign in'));
await settle(tester);
expect(find.text('ONE TOUCH'), findsOneWidget);
expect(find.text('BOOK NOW'), findsOneWidget);
await drainToasts(tester);
});
@@ -256,7 +256,7 @@ void main() {
await tester.tap(find.text('Create PIN and continue'));
await settle(tester);
expect(find.text('ONE TOUCH'), findsOneWidget);
expect(find.text('BOOK NOW'), findsOneWidget);
await drainToasts(tester);
});
@@ -265,7 +265,7 @@ void main() {
// Home greets by name, carries the sphere, and ends on the live card.
expect(find.text('Hello, Joe'), findsOneWidget);
expect(find.text('ONE TOUCH'), findsOneWidget);
expect(find.text('BOOK NOW'), findsOneWidget);
// The seeded active booking surfaces on Home. Its state is the uppercase
// micro-label beside the destination, in the chip vocabulary — "Assigned",
// not the rail's "Miler assigned".
@@ -934,7 +934,7 @@ void main() {
addTearDown(tester.platformDispatcher.clearTextScaleFactorTestValue);
await signIn(tester); // login + OTP
expect(find.text('ONE TOUCH'), findsOneWidget); // home
expect(find.text('BOOK NOW'), findsOneWidget); // home
await openSend(tester); // the whole booking, one screen
await pickCity(tester, 'Chennai');
@@ -1014,15 +1014,19 @@ void main() {
await tester.tap(find.bySemanticsLabel('Orders'));
await settle(tester);
// Each tab carries its own count — the figure is the rows that tab will
// actually show, which for a collected multi-destination pickup is one
// per destination. The count shares a paragraph with the label, so it is
// a span rather than a Text of its own.
// ── Label and count are separate widgets now ──
//
// The filter used to fold the figure into the label's own paragraph
// ("Active (4)"), so this matched one span. It is [DmChoiceChip] now —
// the same control as the pickup window's day switcher — which puts the
// count in a bubble beside the label. Two Texts, not one string.
//
// The figure is still the rows that tab will show, which for a collected
// multi-destination pickup is one per destination.
expect(find.text('Active'), findsOneWidget);
expect(
find.textContaining(
'Active (${state.entriesOf(BookingStatus.active).length})',
),
findsOneWidget,
find.text('${state.entriesOf(BookingStatus.active).length}'),
findsWidgets,
);
// The tab row scrolls — three labels plus their counts do not fit a 390pt

View File

@@ -230,7 +230,7 @@ void main() {
// districts inside a state, then a separate window sheet. There are no
// states to open now — the list is flat and the state is a heading — and
// the window is the same sheet's second step.
await tester.tap(find.text('ONE TOUCH'));
await tester.tap(find.text('BOOK NOW'));
await _settle(tester);
await _shot(tester, '07-pickup-where');

View File

@@ -53,13 +53,19 @@ void main() {
});
group('resolved configuration', () {
test('defaults to CARTO and identifies the app to the provider', () {
test('defaults to OpenStreetMap and identifies the app to it', () {
// ── The User-Agent is not decoration here ──
//
// OSM's tile usage policy asks a distributed app for a valid
// identifying agent, and blocks traffic it cannot attribute. A block
// looks like every tile turning into the ground colour at once, with no
// other symptom — so this asserts the identification, not just the URL.
final config = DmMapConfig.fromEnvironment();
expect(config.provider.id, 'carto');
expect(config.provider.id, 'osm');
expect(config.warning, isNull);
expect(config.userAgent, contains('Doormile/'));
expect(config.userAgent, contains(DmMapConfig.packageName));
expect(config.attribution, contains('CARTO'));
expect(config.attribution, contains('OpenStreetMap'));
});
test('is swappable without touching a screen', () {

View File

@@ -8,7 +8,7 @@ import 'package:doormile_cx/ui/widgets/states.dart';
/// ─────────────────────────────────────────────────────────────────────────
/// A SHEET DOES NOT CHANGE SIZE WHILE IT IS OPENING
///
/// Tapping ONE TOUCH opened a tall sheet that snapped shorter a few frames
/// Tapping BOOK NOW opened a tall sheet that snapped shorter a few frames
/// later. Nothing was wrong with either height — the sheet was simply as tall
/// as whatever [DmAsyncList] happened to be rendering, and that changes twice
/// before the customer has done anything: four skeleton rows at 302pt, then

Binary file not shown.

Before

Width:  |  Height:  |  Size: 430 KiB

After

Width:  |  Height:  |  Size: 432 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 247 KiB

After

Width:  |  Height:  |  Size: 250 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 213 KiB

After

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 259 KiB

After

Width:  |  Height:  |  Size: 259 KiB