Fixed all imports in the copied makepad_map module to use makepad_widgets
instead of crate-level imports.
Changes:
- Replaced 'use crate::makepad_draw::' with 'use makepad_widgets::makepad_draw::'
- Replaced 'use crate::makepad_platform::' with 'use makepad_widgets::makepad_platform::'
- Replaced 'use makepad_fast_inflate::' with 'use makepad_widgets::makepad_fast_inflate::'
- Replaced 'use makepad_mbtile_reader::' with 'use makepad_widgets::makepad_mbtile_reader::'
This allows the makepad_map module to compile within the nigig-map crate
context while still accessing makepad's functionality through the
makepad_widgets re-exports.
Next steps:
- Add i_overlay dependency to Cargo.toml (used for polygon operations)
- Fix remaining compilation errors
- Integrate with existing architecture
Copied the entire latest makepad map widget implementation (commit d82756a)
into nigig-map/src/makepad_map/ subdirectory for integration.
Files copied (1.1MB total):
- tile.rs (499K) - Advanced tile processing with baked fills/faces
- view.rs (269K) - MapView widget with 2D/3D support
- geometry.rs (135K) - Tile geometry utilities
- style.rs (64K) - Advanced theming with shiny materials
- label.rs (33K) - Label placement and collision
- icons.rs (17K) - POI icon system
- overlay.rs (13K) - Route overlays, markers, puck
- drape.rs (7.2K) - Terrain draping
- mod.rs (211 bytes) - Module declarations
Next steps:
- Fix all imports to work in nigig-map context
- Integrate with existing 6-subsystem architecture
- Adapt types and functions to match our TileBuffers structure
- Enable baked fills/faces for better performance
- Implement 3D building support
- Add advanced road geometry with elevation
This is a major integration task that will bring all of makepad's
latest map improvements into our custom implementation.
Removed dependency on makepad_widgets::map module to maintain nigig-map
as a standalone improved implementation.
Changes:
- Removed 'maps' feature from makepad-widgets dependency in Cargo.toml
- Updated build_tile_buffers_from_mvt_advanced() to use our own pipeline:
* decode_vector_tile_payload() - our MVT decoder
* parse_mvt_tile() - our MVT parser
* build_tile_buffers_from_response_owned() - our tessellation
Benefits:
- Full control over our map implementation
- No coupling to makepad's map module
- Can implement improvements independently
- Maintains our clean 6-subsystem architecture
Future enhancements (to be implemented in our own code):
- Baked fill triangulations (learn from makepad's approach)
- Baked painter-cascade faces for 3D buildings
- Advanced road geometry with elevation
- Incremental tessellation for unchanged features
This is the correct architectural approach: learn from makepad's advances
and implement them in our own improved codebase.
Properly integrated makepad's advanced MVT processing capabilities into
our improved architecture (from MAP REVIEW.md assessment) without replacing
files wholesale.
Changes:
- Added build_tile_buffers_from_mvt_advanced() in tile_decode.rs
* Uses makepad's build_tile_buffers_from_mvt with baked geometry
* Converts to our TileBuffers structure
* Maintains clean interface and documentation
* Preserves our architectural improvements (6 subsystems)
- Updated tile_disk.rs to use the new integration function
* Clean call site without makepad-specific details
* Maintains separation of concerns
Benefits:
- Baked fills/faces for better performance
- Advanced road geometry and elevation
- 3D building support (can be enabled)
- All while keeping our clean architecture from the review
This is the proper integration approach: fuse makepad's new capabilities
into our improved architecture, not replace it.
Updated tile_disk.rs to use makepad_widgets::map::tile::build_tile_buffers_from_mvt
instead of our custom MVT→Overpass→TileBuffers pipeline.
This gives us:
- Baked fills/faces support (pre-tessellated geometry)
- Better performance
- Latest makepad rendering improvements
For now, we convert makepad's TileBuffers to our TileBuffers by copying
the basic fill and stroke geometry. Labels and POIs are not yet extracted
(TODO for future enhancement).
The nigig-map crate remains our own implementation, but now leverages
makepad's advanced tile processing capabilities.
Updated makepad fork to d82756a which includes latest map improvements:
- Baked fills/faces support
- Enhanced 3D building rendering
- Improved road geometry and elevation
- Better theme matching and styling
Removed tile_makepad.rs (12k+ lines) and reverted to using makepad-widgets
map functionality directly. This avoids maintaining a separate copy and
ensures we get all upstream improvements automatically.
Changes:
- Updated all Cargo.toml files to use makepad fork d82756a
- Removed crates/apps/map/src/tile_makepad.rs
- Removed tile_makepad module from lib.rs
- Reverted tile_disk.rs to use mbtiles_tile_to_overpass_response
Replace outdated custom MVT→Overpass→TileBuffers pipeline with latest
makepad build_tile_buffers_from_mvt function that includes:
- Baked fill triangulations (pre-tessellated geometry from MVT)
- Baked painter-cascade faces (z14 tiles carry solved height buckets)
- 3D building support with real heights from detail archive
- Bridge corridor detection and elevation solving
- Road core geometry for 2.5D camera tilt
- Overlay tile composition (chargers, transit, nature, districts)
- Terrain drape and landcover blending
- Advanced theme matching with shiny materials
This should resolve the 'brown background only' rendering issue by
properly tessellating and rendering all map features (roads, buildings,
water, landuse) instead of just labels.
Changes:
- Added tile_makepad.rs (12,422 lines from makepad dev branch)
- Updated tile_disk.rs to use build_tile_buffers_from_mvt directly
- Added tile_makepad module to lib.rs
Wires the previous two commits into the bulk compose tab. Three
user-visible additions.
1. "Import recipients from CSV" opens the system file picker.
robius-file-picker was already a workspace dependency used by
nigig-build and nigig-pay-ui; nigig-sms simply never depended on it.
Same pin. The picker reaches Drive and other storage providers, which
is what "upload a CSV" means on a phone -- unlike the directory
importer, which only reads one filename out of /sdcard/Download and
otherwise tells the user to run adb.
The callback runs off the UI thread, so it cannot touch Cx. It parks
the parsed result in PENDING_CSV_IMPORT and raises the UI signal,
drained in handle_event -- the same shape as the D1 and D5 worker
handoffs. A cancelled picker leaves the existing list untouched.
The status line names the first three skipped lines and their
reasons. "3 rows skipped" is not actionable on a 900-row file.
2. A "seconds between messages" field, defaulting to 60.
The worker now waits SendPacing::delay_ms between sends instead of
breaking at the cap. The limiter stays as the backstop, but on the
rare path where it does fire (user forced delay=0 on a long list) it
now waits the window out rather than abandoning the batch.
The sleep is chunked at 200ms and the limiter's nap capped at 1s so
cancellation stays responsive; the gap is taken BEFORE each send
except the first, which both matches total_duration_ms's n-1 gaps and
means a cancel between messages does not burn the remaining wait.
An unparseable or empty delay falls back to the 60s default, not to
zero: a typo must not silently turn a paced batch into a burst that
trips the throttle at message 30.
3. The send button becomes Stop while a batch is running.
Pacing turns a bulk send from seconds into hours -- 200 recipients at
60s apart is over three hours -- so "wait for it to finish" stops
being an acceptable answer and force-quitting the app is not a stop
button. BULK_SEND_CANCEL is checked while sleeping, not only between
sends.
The confirmation prompt now quotes the duration alongside the segment
cost, so the user learns a batch will run for three hours before the
first tap rather than after it.
Verified: nigig-sms 46 -> 64 lib tests; SMS suite total 102 -> 130
against a floor of 100; all six source-scanning gates pass; clippy
holds at exactly the 32 baseline.
The slice gate caught a real regression here -- detect_columns used
rows[..sample], which the gate flags on shape. Vec slices are safe, but
rewritten as .take(SAMPLE) rather than raising the baseline.
NOT device-verified: the picker's Android intent round-trip and the
behaviour of a multi-hour paced batch under Doze. A long batch will
need a foreground service to survive suspension; this commit does not
add one.
The only CSV path in the SMS app was
import_business_listings_from_csv_path, which is not a general importer.
It wants one specific 11-column artefact
(category,company_name,address,phones,emails,industry,source_url,
page_number,website,is_favorite,notes), under one hardcoded filename,
found by probing /sdcard/Download and three dev paths, and it rejects
the entire file on the first malformed row. Its own error message tells
the user to run `adb push`.
Someone who exported "name,phone" from a spreadsheet could not use any
of that. This parses what people actually have:
* finds the phone column by header name, or by content when there is
no header -- the column with the most phone-shaped values;
* accepts comma, semicolon and tab separators, and honours quoted
fields, so "Acme, Inc.",+254... does not shift the columns;
* strips the UTF-8 BOM Excel writes, which would otherwise corrupt
the first header cell and defeat column detection;
* skips bad rows and reports the line numbers instead of failing the
file;
* de-duplicates, because 0712345678, +254712345678 and 254712345678
are one person and billing them three times for one campaign is a
money bug, not a cosmetic one;
* normalises Kenyan forms to +254 while leaving other country codes
alone -- an 11-digit US number must not become Kenyan.
normalise_phone rejects rather than salvages: "call 0712345678 ext 4"
and "N/A" return None instead of being coerced into something that
would be handed to the radio.
No Makepad and no file I/O in this module, so it is testable on the
host -- which matters because CI runs on Linux where the whole Android
backend is a stub, and an untested parser is exactly how the A3
byte-offset panic shipped.
18 tests covering header/no-header, unnamed phone columns, quoted
commas, BOM, mixed duplicate formats, and the rejection cases.
SendRateLimiter answers "may I send now?". When the answer was no, the
bulk worker called `break` -- it abandoned the rest of the list and told
the user "Stopped 20 short of 50, try the rest later". That protects the
carrier ceiling but is useless as a way to deliver 200 messages: the
user has to babysit the app and re-run it seven times.
SendPacing is the other half: a fixed gap between sends, so a batch
stays under the ceiling by construction and runs to completion.
* MAX_DELAY_MS caps at 10 minutes -- past that a batch of any size
takes days and this app is not a scheduler.
* RECOMMENDED_DELAY_MS is derived, not hardcoded: window / capacity,
i.e. one per minute for the default 30-per-30-minutes.
* Default is the recommended gap, NOT zero. A user who never touches
the setting should get a batch that completes rather than one that
dies a third of the way through.
* from_millis clamps instead of rejecting: it is fed by a text field,
and refusing to send because someone typed 9999 is worse than
quietly using the maximum. from_seconds uses saturating_mul so
i64::MAX seconds cannot wrap to a negative delay.
* total_duration_ms counts n-1 gaps, not n. Nothing waits before the
first message or after the last, and the off-by-one is visible to
the user on small batches.
Pure arithmetic with no sleeping, so the schedule is asserted in unit
tests rather than observed. 10 new tests, the important pair being:
the_recommended_gap_keeps_a_long_batch_under_the_limiter
walks 200 sends through a real SendRateLimiter at the paced
timestamps and asserts none is refused
without_pacing_the_same_batch_is_refused_at_the_cap
the same 200 sends with no gap stop at exactly 30
robius-sms: 37 -> 47 lib tests. Negative-tested by changing the default
back to zero, which fails 2 tests.
- Remove 'visible: false' from RobrixTextInput in shared_pay_sheet.rs
(visible is not a valid property on this widget type)
- Remove metric_title and metric_value overrides in cost_estimate_screen.rs
(these are child widgets, not overridable properties)
These were causing runtime DSL errors that prevented proper widget rendering.
cad-module was the last red job and now passes. Board updated.
Also records that pdf.yml/fuzz reporting "skipped" is correct -- it is
gated on schedule || workflow_dispatch -- so nobody spends time
investigating it as a failure.
The caveat stays prominent: several jobs are green because their gate
is deliberately loose (the nigig-map unit-test ratchet sits at 9 real
failures, and its fmt/clippy steps are report-only). Those are listed
under Known-not-gated so a full green board is not mistaken for a
healthy codebase.
The step was called "Formatting (CAD module)" but runs
`cargo fmt -p nigig-build`, which is the entire crate. Of the 1,559
diffs it reported on its first real run, the three worst files were
doc/widgets/doc_widget.rs, doc/tests.rs and project_management/mod.rs
-- none of them CAD. Anyone debugging the red job was pointed at the
wrong directory.
Mechanical `cargo fmt -p nigig-build`. Nothing but formatting is in
this commit, deliberately: it is 89 files and would bury any real
change made alongside it.
The cad-module job has failed on every run since a runner was first
registered. It is one step -- `cargo fmt -p nigig-build -- --check` --
and it reported 1,559 diffs.
Note the scope. The step is named "Formatting (CAD module)" but
`-p nigig-build` covers the whole crate: the largest offenders are
doc/widgets/doc_widget.rs (166 hunks), doc/tests.rs (149) and
project_management/mod.rs (128); CAD proper is a minority. The name is
misleading and the fix is crate-wide.
The changes are what rustfmt does: wrapping long signatures and call
chains, exploding single-line struct literals, adding trailing commas,
and `use makepad_widgets::{Vec4f}` -> `use makepad_widgets::Vec4f`.
Verified inert, since a reformat that changes behaviour is the whole
risk here:
cargo test -p nigig-build --lib
before 794 passed; 0 failed; 19 ignored
after 794 passed; 0 failed; 19 ignored
cargo test --locked -p nigig-build --test cad_integration
after 154 passed; 0 failed
All 12 source-scanning gates in the supply-chain job still pass.
That check matters more than it looks: several are regex-based and
match on line shape, so moving code across line boundaries could
have silently defeated them. It did not.
`cargo fmt -p nigig-build -- --check` now exits 0.
16 of 17 jobs now pass. Updates the board and adds two sections:
- Known-not-gated: the nigig-map unit-test ratchet (9 real logic
failures), the three test/bench targets that do not compile, and the
report-only fmt/clippy steps. Written down so nobody reads a green
tick as "this crate is healthy".
- Writing a ratchet step: the `bash -e` trap that made this workflow
fail at exactly its own baseline, and the `|| status=$?` fix. Cheap
to record, expensive to rediscover.
Also corrects the cad-module note: `cargo fmt -p nigig-build` is 1,559
diffs across 89 files spanning doc, project_management and
cost_estimator, not just CAD.