Skip to content

Commit eca39c2

Browse files
authored
refactor!: redesign Geolocation as static utility with watcher handle (#24279)
Redesigns the Geolocation API as a static utility class with a watcher handle, replacing the previous per-UI facade. *API surface* Geolocation.getPosition() and Geolocation.watchPosition() are static. UI is implicit (UI.getCurrent()), with explicit-UI overloads for background threads. watchPosition() returns a GeolocationWatcher handle that exposes both a callback API (addPositionListener) and a reactive Signal<GeolocationResult>. The owner component drives the watcher's lifecycle: watchPosition() accepts an unattached owner and starts the underlying browser watch on first attach (so it's safe from a view constructor); the watch auto-stops on detach; stop() and resume() work explicitly. Per-UI state (the GeolocationClient and the availability signal) lives in UIInternals; static methods resolve the client there or install a default one through the GeolocationClientFactory Lookup SPI. options is now a non-null parameter — callers who want browser defaults use the no-options overloads, or pass an empty GeolocationOptions explicitly. The fields inside GeolocationOptions remain independently optional. *Error model* Callback exceptions thrown from onSuccess/onError in getPosition and from watcher position listeners are routed to VaadinSession.getErrorHandler() instead of being silently swallowed by CompletableFuture.whenComplete or aborting the listener loop. GeolocationError.message() is renamed to debugInfo() to make it clear the value is a free-form, non-localised string suitable for logs and bug reports — not for UI display. *Test seam* GeolocationClient and WatchHandle become public so external test drivers and native bridges can replace the production client through Lookup. GeolocationOutcome becomes package-private since the public API no longer exposes it. The watcher's bridge-failure error path is unchanged.
1 parent 09ccde4 commit eca39c2

18 files changed

Lines changed: 801 additions & 747 deletions

File tree

‎DESIGN_GUIDELINES.md‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,9 @@ holds `private final UI ui`, and all `executeJs` calls go through
3131
`ui.getElement()` or `ui.getPage()`. Follow the `Page` / `History`
3232
pattern. Enforce single-instance creation in the constructor if needed.
3333

34-
If the facade hands out a stateful handle (e.g.
35-
`Geolocation.watchPosition()` returning a `GeolocationWatcher`), make the
36-
handle's constructor **package-private** so application code cannot bypass
37-
the facade.
34+
If a feature hands out a stateful handle (e.g. `Geolocation.watchPosition()`
35+
returning a `GeolocationWatcher`), make the handle's constructor
36+
**package-private** so application code cannot bypass the entry point.
3837

3938
### Keep internal mutators off user-facing classes
4039

‎flow-server/src/main/java/com/vaadin/flow/component/UI.java‎

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
import tools.jackson.databind.node.BaseJsonNode;
3333

3434
import com.vaadin.flow.component.dependency.JsModule;
35-
import com.vaadin.flow.component.geolocation.Geolocation;
3635
import com.vaadin.flow.component.internal.JavaScriptNavigationStateRenderer;
3736
import com.vaadin.flow.component.internal.UIInternalUpdater;
3837
import com.vaadin.flow.component.internal.UIInternals;
@@ -136,8 +135,6 @@ public class UI extends Component
136135

137136
private final Page page;
138137

139-
private final Geolocation geolocation;
140-
141138
/*
142139
* Despite section 6 of RFC 4122, this particular use of UUID *is* adequate
143140
* for security capabilities. Type 4 UUIDs contain 122 bits of random data,
@@ -168,7 +165,6 @@ protected UI(UIInternalUpdater internalsHandler) {
168165
Component.setElement(this, Element.get(getNode()));
169166
pushConfiguration = new PushConfigurationImpl(this);
170167
page = new Page(this);
171-
geolocation = new Geolocation(this);
172168
}
173169

174170
/**
@@ -951,16 +947,6 @@ public Page getPage() {
951947
return page;
952948
}
953949

954-
/**
955-
* Returns the {@link Geolocation} facade for this UI, used to read the end
956-
* user's physical location from the browser.
957-
*
958-
* @return the Geolocation facade
959-
*/
960-
public Geolocation getGeolocation() {
961-
return geolocation;
962-
}
963-
964950
/**
965951
* Updates this UI to show the view corresponding to the given navigation
966952
* target.

‎flow-server/src/main/java/com/vaadin/flow/component/geolocation/BrowserGeolocationClient.java‎

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ private record AvailabilityDetail(
7777

7878
@Override
7979
public CompletableFuture<GeolocationOutcome> get(
80-
@Nullable GeolocationOptions options) {
80+
GeolocationOptions options) {
8181
CompletableFuture<GeolocationOutcome> future = new CompletableFuture<>();
8282
ui.getElement()
8383
.executeJs("return window.Vaadin.Flow.geolocation.get($0)",
@@ -98,8 +98,7 @@ public CompletableFuture<GeolocationOutcome> get(
9898
}
9999

100100
@Override
101-
public WatchHandle startWatch(Component owner,
102-
@Nullable GeolocationOptions options,
101+
public WatchHandle startWatch(Component owner, GeolocationOptions options,
103102
SerializableConsumer<GeolocationResult> onUpdate) {
104103
return new BrowserWatchHandle(owner, options, onUpdate);
105104
}
@@ -154,8 +153,7 @@ private final class BrowserWatchHandle implements WatchHandle {
154153
private @Nullable DomListenerRegistration errorListener;
155154
private boolean active = true;
156155

157-
BrowserWatchHandle(Component owner,
158-
@Nullable GeolocationOptions options,
156+
BrowserWatchHandle(Component owner, GeolocationOptions options,
159157
SerializableConsumer<GeolocationResult> onUpdate) {
160158
this.owner = owner;
161159
Element el = owner.getElement();

0 commit comments

Comments
 (0)