feat(todo): a location's search goes through the instance (ADR 0033, D32)
The picker now searches with the server's `search`, and says search isn't available where the instance has no Photon rather than that it failed. A debug build may still ask for komoot's public one, for an instance without. A point on the map stays unnamed through the instance, which searches by name alone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
c9d3eb4dd1
commit
5d9c640e5a
2 changed files with 170 additions and 8 deletions
|
|
@ -8,7 +8,8 @@ import 'package:halkyon_todo_flutter/src/feature/location/model/task_location.da
|
|||
import 'package:halkyon_todo_flutter/src/feature/location/widget/location_picker.dart';
|
||||
import 'package:material_ui/material_ui.dart';
|
||||
|
||||
class _Places(final List<TaskLocation> found) implements PlaceSearchGateway {
|
||||
class _Places(final List<TaskLocation> found, {final bool isOffered = true})
|
||||
implements PlaceSearchGateway {
|
||||
final asked = <String>[];
|
||||
LatLon? near;
|
||||
|
||||
|
|
@ -25,6 +26,9 @@ class _Places(final List<TaskLocation> found) implements PlaceSearchGateway {
|
|||
|
||||
@override
|
||||
Future<TaskLocation?> at(LatLon point, {String? language}) async => null;
|
||||
|
||||
@override
|
||||
Future<bool> offered() async => isOffered;
|
||||
}
|
||||
|
||||
/// The location picker (ADR 0033, D32), without tiles.
|
||||
|
|
@ -132,6 +136,21 @@ void main() {
|
|||
expect(find.byKey(locationMapKey), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('an instance without a search says so, the map stays', (
|
||||
tester,
|
||||
) async {
|
||||
await open(tester, places: _Places(const [], isOffered: false));
|
||||
await tester.pump();
|
||||
expect(find.byKey(locationSearchKey), findsNothing);
|
||||
expect(
|
||||
find.text(
|
||||
"Search isn't available here. Move the map and tap to place a pin.",
|
||||
),
|
||||
findsOneWidget,
|
||||
);
|
||||
expect(find.byKey(locationMapKey), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('recent places show before a search', (tester) async {
|
||||
await open(tester, places: _Places(const []), recents: const [aeschach]);
|
||||
expect(find.text('Recent'), findsOneWidget);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,72 @@
|
|||
import 'package:halkyon_todo_client/halkyon_todo_client.dart';
|
||||
import 'package:halkyon_todo_flutter/src/feature/location/data/place_search_gateway.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
/// Replies as Photon's (ADR 0033, D32).
|
||||
void main() {
|
||||
test("the instance's places keep their address and object", () async {
|
||||
final gateway = InstancePlaceSearch(
|
||||
asked: () async => true,
|
||||
find: (query, near, language) async {
|
||||
expect((query, near?.lat, language), ('Lindau EDEKA', 47.5, 'de'));
|
||||
return [
|
||||
Place(
|
||||
name: 'EDEKA',
|
||||
detail: 'Ludwig-Kick-Straße 1, Lindau',
|
||||
kind: 'house',
|
||||
osmType: 'N',
|
||||
osmId: 7,
|
||||
lat: 47.55,
|
||||
lon: 9.7,
|
||||
),
|
||||
];
|
||||
},
|
||||
);
|
||||
final [place] = await gateway.search(
|
||||
'Lindau EDEKA',
|
||||
near: (lat: 47.5, lon: 9.7),
|
||||
language: 'de',
|
||||
);
|
||||
expect(place.address, 'Ludwig-Kick-Straße 1, Lindau');
|
||||
expect((place.lat, place.lon), (47.55, 9.7));
|
||||
expect((place.osmType, place.osmId), ('N', 7));
|
||||
});
|
||||
|
||||
test('a place without a detail has no address', () async {
|
||||
final gateway = InstancePlaceSearch(
|
||||
asked: () async => true,
|
||||
find: (_, _, _) async => [
|
||||
Place(name: 'Lindau', kind: 'city', lat: 47.55, lon: 9.7),
|
||||
],
|
||||
);
|
||||
final [place] = await gateway.search('Lindau');
|
||||
expect(place.address, '');
|
||||
});
|
||||
|
||||
test("an instance that can't be asked offers no search", () async {
|
||||
final gateway = InstancePlaceSearch(
|
||||
asked: () async => throw Exception('offline'),
|
||||
find: (_, _, _) async => const [],
|
||||
);
|
||||
expect(await gateway.offered(), isFalse);
|
||||
});
|
||||
|
||||
test('a refusal reaches the picker, which says the search failed', () {
|
||||
final gateway = InstancePlaceSearch(
|
||||
asked: () async => true,
|
||||
find: (_, _, _) async => throw SearchRefused(reason: 'unreachable'),
|
||||
);
|
||||
expect(gateway.search('Lindau'), throwsA(isA<SearchRefused>()));
|
||||
});
|
||||
|
||||
test('a point on the map has no name from the instance', () async {
|
||||
final gateway = InstancePlaceSearch(
|
||||
asked: () async => true,
|
||||
find: (_, _, _) async => const [],
|
||||
);
|
||||
expect(await gateway.at((lat: 47.5, lon: 9.7)), isNull);
|
||||
});
|
||||
|
||||
Map<String, Object?> feature(
|
||||
Map<String, Object?> properties, {
|
||||
List<num> at = const [9.70, 47.55],
|
||||
|
|
|
|||
Loading…
Reference in a new issue