Mobile follow up number 5 #78
Labels
No labels
Compat/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Status
Abandoned
Status
Blocked
Status
Need More Info
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
gtfs.zone/coloring-book#78
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Three independent bug fixes for mobile and desktop UX. Notification overlap is a one-line CSS tweak. Duplicate stop-creation/move notifications are caused by
handleStopCreatedandhandleStopDragCompleteinmap-controller.tsfiring their ownshowNotificationcalls in addition to the globalpatch:changehandler already showing ahumanLabelnotification — fix is to remove the redundant calls. Stop drag on mobile is broken because the drag uses onlymousedown/mousemove/mouseupevents which MapLibre does not synthesize from touch on mobile — fix is to add paralleltouchstart/touchmove/touchendhandlers viathis.map.on(...), which receiveMapTouchEventwith the samepointandlngLatproperties asMapMouseEvent.Relevant context
src/modules/notification-system.ts:36— container classfixed top-28 left-2 z-[100]src/index.ts:190–192— globalpatch:changelistener callsnotifications.showInfo(humanLabel(r?.patch))src/modules/map-controller.ts:750–795—handleStopDragComplete(line 766) andhandleStopCreated(line 794) each callthis.showNotification(...), duplicating the patch notificationsrc/modules/interaction-handler.ts— drag state machine usesmousedown/mousemove/mouseupviathis.map.on(...).MapTouchEvent(maplibre-gl.d.ts:9727) exposes identical.point(canvas pixels) and.lngLatproperties plus.preventDefault()that blocks MapLibre pan/zoom. It also has.points: Point[]for multi-touch detection.src/modules/interaction-handler.ts:87–119—setupEventListeners(): where to add the three new touch bindingssrc/modules/interaction-handler.ts:471–491—destroy(): where to addmap.off()cleanup for the three touch bindingsPhase 1: Fix notification overlap
Goal: Push the notification container down ~16px so it clears the bottom of the search card.
src/modules/notification-system.ts:36, change the container class fromfixed top-28 left-2 z-[100] space-y-2 max-w-xstofixed top-32 left-2 z-[100] space-y-2 max-w-xs(top-32= 128px, up from 112px).Phase 2: Fix duplicate notifications
Goal: Each stop creation or move should produce exactly one notification (from the global
patch:changehandler, which already shows a human-readable label).Why duplicates happen:
handleStopCreatedandhandleStopDragCompleteeach explicitly callthis.showNotification(...)after updating the DB. ButgtfsParser.createStopandgtfsParser.updateStopCoordinatesboth go through the patch system, which firespatch:change, which runsnotifications.showInfo(humanLabel(r?.patch))inindex.ts. Two notifications for one operation.src/modules/map-controller.ts, remove thethis.showNotification(\Stop ${stop_id} created`, 'success')call fromhandleStopCreated(~line 794). Keep thelayerManager?.updateStopsData()` call.src/modules/map-controller.ts, remove thethis.showNotification(\Stop ${stop_id} coordinates updated`, 'success')call fromhandleStopDragComplete(~line 766). Keep thelayerManager?.updateStopsData()call and the error-pathshowNotification` (error notifications are fine to keep as they're not covered by the patch system).Phase 3: Fix mobile stop drag
Goal: Stop dragging works on mobile (touch) using the same state machine as mouse drag.
Why it's broken: MapLibre does not translate touch events into
mousedown/mousemove/mouseupin a way that the current drag detection picks up. Touch events need their own handlers.Approach: Add
touchstart,touchmove,touchendlisteners viathis.map.on(...).MapTouchEventhas.point(canvas pixelPoint),.lngLat,.points(array for multi-touch guard), and.preventDefault()(blocks MapLibre pan/zoom). The handlers mirror the mouse ones exactly.In
src/modules/interaction-handler.ts, importMapTouchEventfrom'maplibre-gl'alongside the existingMapMouseEventimport.In
setupEventListeners(), after the existing mouse bindings, add:Add
handleTouchStart(e: MapTouchEvent): void— same logic ashandleMouseDownbut:if (e.points.length !== 1) return;(ignore multi-touch)e.pointforqueryRenderedFeaturese.preventDefault()(instead ofe.preventDefault()on the mouse event) to block MapLibre pan/zoom when drag startsAdd
handleTouchMove(e: MapTouchEvent): void— same logic ashandleMouseMovebut:if (e.points.length !== 1) return;e.lngLatfor coordinatese.preventDefault()to block scroll during dragAdd
handleTouchEnd(_e: MapTouchEvent): void— delegates directly tothis.handleMouseUp()(no coordinate read needed, same cleanup logic).In
destroy(), add correspondingthis.map.off(...)calls for the three touch listeners (mirror the existing mouse.offcalls).Gotchas:
MapTouchEvent.pointis the centroid of all touches, which is fine since we guard for single-touch.e.preventDefault()ontouchstartprevents both pan and pinch-zoom for that gesture — this is correct since we're taking over the touch for dragging.touchendevent'slngLat/pointmay be undefined (finger already lifted); that's whyhandleTouchEnddelegates tohandleMouseUpwhich reads fromstopsGeoJSONrather than the event coordinates.Original Issue
A few more issues:
Move stop on mobileto Mobile follow up number 5