Commit Graph

4122 Commits

Author SHA1 Message Date
Jose Olarte III
85ac6632ed fix(ios): resolve getSharedImage() with null when no share pending
When no shared image exists, return a bare Capacitor resolve instead of
an object with null base64/fileName/shareId fields, matching the
TypeScript contract and web implementation.
2026-07-01 17:04:45 +08:00
Jose Olarte III
0c91b687f9 feat(ios): clean up native share storage after import (Phase 1F)
Add SharedImageUtility.clearProcessedShare() to permanently delete the
shared image file and remove all App Group metadata (sharedPhotoFileName,
sharedPhotoFilePath, sharedPhotoShareId, sharedPhotoReady,
sharedPhotoProcessedShareId). The helper is idempotent and logs cleanup
started/completed plus a warning on file-deletion failure. Expose it through
the SharedImage plugin with a web no-op stub.

Wire cleanup into the import flow so it runs only after both
storeSharedImageInTempDB() and markProcessed() succeed; a cleanup failure is
logged but does not fail the already-successful import. After cleanup a
subsequent getSharedImage() finds no pending share. iOS only; Android, the
Share Extension, and Phase 1E duplicate suppression are unchanged.
2026-06-30 22:17:37 +08:00
Jose Olarte III
7093f38e09 feat(ios): skip already-processed shares in getSharedImageData (Phase 1E)
Return nil from getSharedImageData() when the current sharedPhotoShareId
equals the stored sharedPhotoProcessedShareId, so a share that was already
marked processed is no longer re-imported on subsequent app activations.

The check runs before reading the image file and logs
"[ShareTarget] shareId=<id> already processed; skipping". It leaves the
image file and all metadata intact (cleanup is deferred to a later phase),
and does not change behavior for brand-new shares. iOS only; no changes to
markProcessed(), the Share Extension, Android, or the JS flow.
2026-06-30 22:05:29 +08:00
Jose Olarte III
cb748f9105 feat(ios): mark shares processed after successful import
Call SharedImage.markProcessed(shareId) from the share import workflow once
a shared image has been successfully stored in the temp DB. The call is
gated to iOS and a non-empty shareId, and a mark-processed failure is logged
as a warning without failing the already-successful import.

Add explicit logging for processing started/succeeded/failed and
markProcessed invoked. On a storage failure the share is left intact and not
marked processed, so it remains available for retry. Android is unchanged.
2026-06-30 20:36:09 +08:00
Jose Olarte III
a3e9a0104d feat(ios): expose shareId from getSharedImage()
Include the existing native sharedPhotoShareId in the SharedImage
getSharedImage() result so the web layer can identify the current share.
Add shareId to the native result dictionary and plugin response (NSNull on
the no-image branch), and add shareId: string to the TypeScript
SharedImageResult interface.

This surfaces a value that was already produced natively (previously used
only for logging) so application code can later pass it to markProcessed().
No behavior changes beyond exposing the value; Android untouched. Updates
doc/share-target-ios-audit.md accordingly.
2026-06-30 11:02:59 +08:00
Jose Olarte III
981f8b77d0 feat(ios): add markProcessed share-completion API (Phase 1D)
Add a native iOS markProcessed(shareId) method to the SharedImage plugin
that records an explicit completion signal in App Group UserDefaults
(sharedPhotoProcessedShareId) and logs "[ShareTarget] shareId=<id> marked
processed". The API is exposed to TypeScript via the plugin definitions and
a web no-op stub.

Deliberately does not delete files or clear share metadata (cleanup is
deferred to a later phase), is not yet called from application code, and
does not touch Android. Documents the share-target lifecycle and plugin API
in doc/share-target-ios-audit.md.
2026-06-30 11:00:52 +08:00
Jose Olarte III
125406a54c docs(ios): clean up AppBridgeViewController registration comments
Replace the transitional Phase 2B-1 comments (which referenced a temporary
AppDelegate registration safety net) with a concise description of the
plugin registration now that it is finalized. Comment-only change; plugin
registration behavior is unchanged.
2026-06-30 10:30:30 +08:00
Jose Olarte III
c6d5876da3 refactor(ios): remove orphaned Share Extension diagnostics API
Remove the getShareExtensionDiagnostics() API now that the share-target
investigation is complete and it has no remaining callers.

- Drop getShareExtensionDiagnostics from the plugin definition, web stub,
  Swift plugin method + registration, and SharedImageUtility implementation
- Remove the ShareExtensionDiagnostics TypeScript interface and its now-dead
  import in the web stub
- Remove the diagnostics-only [ShareTarget] log line and the now-unused
  shareExtensionLastStartKey constant in SharedImageUtility

getSharedImage/hasSharedImage, SharedPhotoReady logic, ShareViewController,
AppDelegate, and Android are unchanged. TypeScript type-check passes.
2026-06-29 18:12:35 +08:00
Jose Olarte III
0a70914d0c docs(ios): remove completed share-target investigation audits
Remove the point-in-time, read-only audit documents produced during the
iOS share-target investigation. Each was a "no code modified" snapshot and
is no longer needed now that the investigation is complete. None were
referenced by other docs or code.

- doc/share-target-ios-audit.md
- doc/share-target-ios-launch-flow-audit.md
- doc/share-extension-configuration-audit.md
- doc/share-extension-app-group-audit.md

Permanent implementation, setup, design, and decision docs are retained.
2026-06-29 18:00:31 +08:00
Jose Olarte III
b48ab3dc42 chore(ios): remove temporary cold-start share diagnostics
Remove the temporary diagnostics added during the iOS share-target
investigation, tagged with the TEMPORARY SHARE TARGET DIAGNOSTICS marker.

- Drop the pendingShareExists field/computation from ShareExtensionDiagnostics
  across the Swift utility, TS definitions, and web stub
- Remove the cold-start diagnostics block in main.capacitor.ts (the iOS
  getShareExtensionDiagnostics call and [ShareTarget] Cold-start state dump)
- Drop pendingShareExists from the getShareExtensionDiagnostics log line

Kept getShareExtensionDiagnostics itself (unmarked plugin API + registration),
the unmarked [ShareTarget] print logging, share-target functionality, and
Android code unchanged.
2026-06-29 17:55:55 +08:00
Jose Olarte III
43328e9d4b chore(ios): remove temporary Share Target trace diagnostics
Remove the native trace infrastructure that was added solely for the iOS
share-target investigation. This reverts the temporary share-extension and
app-launch trace logging along with the APIs and debug UI built on top of it.

- Remove getShareExtensionTrace/clearShareExtensionTrace/getAppLaunchTrace/
  clearAppLaunchTrace from the native plugin, TS definitions, and web stubs
- Remove appendTrace (ShareViewController) and appendAppLaunchTrace
  (SharedImageUtility) implementations and all call sites
- Drop the share-extension-trace.log / app-launch-trace.log file handling
- Delete ShareTargetDebugView, its /share-target-debug route, and the
  TestView entry point
- Remove now-unused AppDelegate isTimesafariURL helper and launchURL local
- Strip trace dump/alert logic from main.capacitor.ts

Share-target behavior, plugin registration, image storage, SharedPhotoReady
logic, Android, and the share-extension diagnostics snapshot are unchanged.
2026-06-29 17:43:17 +08:00
Jose Olarte III
02e6e3427d refactor(ios): remove SharedImage plugin-readiness polling (Phase 2B-3)
The SharedImage plugin is now registered deterministically from
AppBridgeViewController.capacitorDidLoad() before the web layer loads, so
JS no longer needs to wait for it. Remove the readiness machinery that
existed solely to tolerate the old async AppDelegate registration:
waitForSharedImagePluginReady(), the sleep() helper, the
STARTUP_PLUGIN_MAX_ATTEMPTS/RETRY_DELAY_MS constants and retry loop, and
the three readiness-only console diagnostics (waiting / ready after N /
giving up).

The iOS startup branch now calls checkForSharedImageAndNavigate()
immediately. All other share-target behavior is unchanged: cold-start,
extension, and launch diagnostics; native trace APIs; the Share Target
Debug Panel; appStateChange/appUrlOpen handling; actual shared-image
handling; and the Android startup path. No JS readiness diagnostics
remain; no Android changes.
2026-06-26 21:14:59 +08:00
Jose Olarte III
337a8f7536 refactor(ios): remove AppDelegate SharedImage registration (Phase 2B-2)
Now that AppBridgeViewController registers SharedImagePlugin from
capacitorDidLoad(), remove the obsolete plugin-registration logic from
AppDelegate: the 5-attempt retry loop in didFinishLaunchingWithOptions,
the registerSharedImagePlugin() method, and the registration-specific
logging. SharedImagePlugin is now registered from a single, deterministic
site.

All non-registration responsibilities are unchanged: notification
handling, URL and universal-link proxying, SharedPhotoReady activation
logic, every lifecycle callback, the temporary app launch tracing, and
all temporary share-target diagnostics remain intact. No JS or Android
changes.
2026-06-26 19:35:43 +08:00
Jose Olarte III
4978e93711 feat(ios): register SharedImage via CAPBridgeViewController subclass (Phase 2B-1)
Introduce AppBridgeViewController, a CAPBridgeViewController subclass that
registers the app-local SharedImagePlugin from capacitorDidLoad(), where
the Capacitor bridge is guaranteed to exist. This is the first step toward
replacing AppDelegate's timed retry registration with a deterministic,
bridge-ready registration point.

Point the existing root bridge controller in Main.storyboard at
AppBridgeViewController (same VC id/scene; only the custom class changes)
and add the new file to the App target in project.pbxproj.

The existing AppDelegate registration and its retry loop are intentionally
left in place as a temporary safety net, so the plugin is now registered
from both sites during this phase. No diagnostics, retry logic, JS, or
Android code changed; plugin name ("SharedImage") and implementation are
unchanged.
2026-06-26 19:26:00 +08:00
Jose Olarte III
9941264022 chore(ios): add temporary Share Target debug panel (temporary)
Add a dedicated, temporary debug view for the iOS Share Target
investigation so native traces can be inspected without attaching Xcode.
Kept separate from the Notification/Notiwind test panel so it is easy to
remove once the investigation is complete.

The panel (src/views/ShareTargetDebugView.vue, route
/share-target-debug) has three buttons:
- Dump Native Traces: calls SharedImage.getShareExtensionTrace() and
  getAppLaunchTrace(), logs both in full (untruncated) between
  EXTENSION TRACE START/END and APP LAUNCH TRACE START/END markers, and
  shows them in read-only scrollable fields.
- Clear Share Extension Trace: clears the native log and the field.
- Clear App Launch Trace: clears the native log and the field.

Register the route alongside the existing /test debug route and link to
the panel from TestView. No share-target behavior changed; Android
untouched. All additions marked TEMPORARY SHARE TARGET DIAGNOSTICS.
2026-06-26 18:10:08 +08:00
Jose Olarte III
256018d30d chore(ios): add native app launch lifecycle trace diagnostics (temporary)
Add temporary, append-only tracing of the native iOS application launch
lifecycle to diagnose failed cold-start shares when Xcode is not
attached during launch. Writes app-launch-trace.log in the same App
Group container as share-extension-trace.log, reusing the same style
(ISO8601 timestamps, append-only, all logging failures swallowed).

AppDelegate now traces every lifecycle callback
(didFinishLaunchingWithOptions, application(open:),
applicationDidBecomeActive, applicationWill/DidEnterForeground/Background,
applicationWillResignActive, applicationWillTerminate, and
checkForSharedImageOnActivation), recording the callback name, whether a
URL was supplied, the URL value, whether it matches timesafari://,
whether launch options carried a URL, and whether shared-image
activation ran.

Expose read-only getAppLaunchTrace()/clearAppLaunchTrace() plugin APIs
(mirroring the share-extension trace APIs) with matching TypeScript
definitions and web stubs. main.capacitor.ts logs the full launch trace
between APP LAUNCH TRACE START/END markers inside the existing
diagnostics block.

No share-target behavior changed; Android untouched. All additions are
marked TEMPORARY SHARE TARGET DIAGNOSTICS.
2026-06-26 17:06:50 +08:00
Jose Olarte III
c1a5bae5c8 feat(ios): wait for SharedImage plugin before initial startup check (Phase 2A)
Eliminate the iOS startup race between asynchronous SharedImage plugin
registration and the first shared-image check. Previously the initial
check fired on a fixed 1000ms timer that only assumed the native plugin
(registered by AppDelegate with retries from T+500ms) was ready, so a
slow registration could make the first getSharedImage() call throw and
miss a cold-start share.

Replace the fixed delay with waitForSharedImagePluginReady(), which
probes the plugin via a read-only hasSharedImage() call and retries
within a bounded budget (10 attempts, 300ms apart) until the plugin
actually responds. The initial check runs only once readiness is
confirmed, with a best-effort fallback if the budget is exhausted.

Scope is limited to the initial startup check on iOS. appStateChange,
appUrlOpen/handleDeepLink, router navigation, share processing, Android
behavior, and all native Swift code are unchanged. Temporary
share-target diagnostics are preserved and extended with startup
readiness logging.

Document the change as a Phase 2A section in
doc/share-target-ios-audit.md.
2026-06-26 16:48:00 +08:00
Jose Olarte III
c9061e669e docs(ios): add share-target launch and deep-link flow audit
Add doc/share-target-ios-launch-flow-audit.md documenting the iOS
Share Extension launch path from openMainApp("timesafari://") through
the native AppDelegate, Capacitor bridge, and JS bootstrap to
/shared-photo navigation.

Covers cold- vs warm-start execution order, the single appUrlOpen
listener and its call graph, all shared-image detection mechanisms
(startup timer, appStateChange, applicationDidBecomeActive,
sharedPhotoReady flag, SharedPhotoReady notification), native launch-URL
handling, and a timing analysis of the race conditions.

Key findings: cold-start shares rely on the T+1000ms startup timer
reading the App Group payload (not appUrlOpen, which registers at
T+2000ms after the launch URL is delivered); warm-start shares are
driven by appUrlOpen/appStateChange; the launch URL event and the
SharedPhotoReady notification can be lost before JS is ready, but the
durable App Group payload is not. Audit only; no code changes.
2026-06-26 15:43:42 +08:00
Jose Olarte III
7b1fec779b chore(ios): log full Share Extension trace on startup (temporary)
Surface the complete Share Extension execution trace during app startup
so the cold-start share path can be inspected even when Xcode truncates
console output.

In checkForSharedImageAndNavigate(), after the existing diagnostics
call, retrieve SharedImage.getShareExtensionTrace() and:
- log the full untruncated trace between TRACE FULL START/END markers
- show the full trace in a user-visible alert (iOS only)
- log TRACE LENGTH and the first 500 characters

Share-target behavior is unchanged and the trace work is gated to iOS,
so Android is unaffected. All additions are marked with
"TEMPORARY SHARE TARGET DIAGNOSTICS".
2026-06-25 19:57:42 +08:00
Jose Olarte III
d1106d9aec chore(ios): add Share Extension execution trace diagnostics (temporary)
Add a lightweight, temporary trace logger to diagnose where the iOS
Share Extension stops executing during a failed cold-start share.

- ShareViewController: add appendTrace() helper that writes ISO8601-
  prefixed lines to share-extension-trace.log in the App Group
  container, ignoring failures (diagnostics only)
- Add trace entries across the share flow: viewDidLoad,
  processAndOpenApp, processSharedImage, image attachment/load,
  storeImageData, setSharedPhotoReadyFlag, openMainApp, completeRequest
- SharedImageUtility: add getShareExtensionTrace() (read-only) and
  clearShareExtensionTrace() (deletes the trace file)
- SharedImagePlugin: expose getShareExtensionTrace() and
  clearShareExtensionTrace() to JS
- definitions.ts / SharedImagePlugin.web.ts: add ShareExtensionTrace
  type, method signatures, and web stubs

Share behavior is unchanged and Android is untouched. All additions are
marked with "TEMPORARY SHARE TARGET DIAGNOSTICS".
2026-06-25 19:10:57 +08:00
Jose Olarte III
6f7be2e3b2 chore(ios): add pendingShareExists cold-start share diagnostics (temporary)
Extend ShareExtensionDiagnostics with pendingShareExists across
SharedImageUtility, definitions, and the web stub, and log cold-start
state (pending share + current route) in the iOS startup share check.
2026-06-25 18:37:04 +08:00
Jose Olarte III
4fc30562fb docs(ios): add App Group configuration audit for share extension
Document App/extension entitlements, bundle IDs, teams, and signing,
flagging a code-vs-entitlement App Group ID mismatch (code uses
group.app.timesafari.share while entitlements grant
group.app.trentlarson.timesafari.share) that breaks shared storage.
2026-06-25 17:48:53 +08:00
Jose Olarte III
6afe40bc23 docs(ios): add Share Extension configuration audit
Document that TimeSafariShareExtension is a code-based extension with
ShareViewController as NSExtensionPrincipalClass, confirm viewDidLoad
executes on launch, and note no blocking Info.plist/storyboard mismatches.
2026-06-25 17:28:20 +08:00
Jose Olarte III
402bd2681f chore(ios): log share extension diagnostics on startup (temporary)
Call getShareExtensionDiagnostics() during the iOS shared-image startup
check and print the result to Xcode logs for share-target investigation.
2026-06-24 19:43:27 +08:00
Jose Olarte III
498a4926bf feat(ios): add Share Extension startup diagnostic marker and API
Write shareExtensionLastStart on ShareViewController.viewDidLoad and
expose getShareExtensionDiagnostics() through SharedImagePlugin with
shareId, file path, and fileExists for debugging failed share flows.
2026-06-24 19:38:25 +08:00
Jose Olarte III
f0ca49b5dc feat(ios): add diagnostic logging to Share Extension share flow
Log start/end, shareId, attachment counts, UTType, byte counts, filenames,
and every early return across viewDidLoad through completeRequest to trace
how far a share progresses when debugging failures.
2026-06-24 19:28:09 +08:00
Jose Olarte III
07463246f0 feat(ios): add share-target diagnostic logging in SharedImageUtility
Log shareId, sharedPhotoFilePath, metadataExists, and fileExists at the
start of getSharedImageData() and hasSharedImage() to debug pending
App Group shares without changing retrieval behavior.
2026-06-24 17:19:54 +08:00
Jose Olarte III
79ceebbd1d feat(ios): make shared image retrieval non-destructive (Phase 1C)
Stop deleting App Group metadata and image files in getSharedImageData()
so retrieval is read-only while preserving the existing plugin API shape.
Document removed deletion paths in the iOS share target audit.
2026-06-24 16:49:45 +08:00
Jose Olarte III
ddbd07f315 feat(ios): use UUID-based filenames for shared images (Phase 1B)
Store shared images as <shareId>.<ext> in the App Group container while
keeping the original filename in metadata, preventing on-disk collisions
without changing retrieval, deletion, or JS consumer behavior.
2026-06-23 19:37:11 +08:00
Jose Olarte III
35a6a6bfb3 feat(ios): add share ID tracking for share target (Phase 1A)
Generate a UUID per incoming share in the Share Extension, persist it
as sharedPhotoShareId in App Group metadata, and add [ShareTarget] logs
for receive/store/retrieve events without changing retrieval or deletion.
2026-06-23 19:13:44 +08:00
Jose Olarte III
08a55202f5 docs(ios): add share target implementation audit
Document the Share Extension → App Group → main app flow, including
read/write/delete points, startup detection hooks, timing behavior,
and race conditions to support share-target reliability work.
2026-06-23 17:20:53 +08:00
ec41dd52d5 bump version to v 1.4.3 build 69 2026-06-21 10:59:24 -06:00
463db39a6b remove hard-coded daily android notification 2026-06-19 23:43:40 -06:00
fe97dff752 Merge pull request 'Rework Thanks Button' (#234) from thanks-button-rework into master
Reviewed-on: #234
2026-06-19 07:21:37 +00:00
Jose Olarte III
903047f13b style(gift): center entity selection step heading and entity type toggle 2026-06-18 21:09:32 +08:00
Jose Olarte III
48be234af4 fix(home): offset scrolled Thank button for safe-area-inset-bottom 2026-06-17 17:57:13 +08:00
6c0907d905 remove unused function & duplicate comment 2026-06-16 16:09:31 -06:00
Jose Olarte III
8d8bcf2a7e style(home): rework Thank button and sticky scroll action bar
Replace the floating circular plus FAB with a full-width bottom bar that
matches the inline Thank button. Wrap the quick-action section in a styled
container and raise the scroll threshold to 120px.
2026-06-16 21:48:34 +08:00
a4b47904c8 Merge pull request 'Add footer to Gifted Details view' (#233) from gifted-details-footer into master
Reviewed-on: #233
2026-06-16 08:27:47 +00:00
Jose Olarte III
bb890baacf fix(gifted-details): add QuickNav footer navigation 2026-06-15 17:20:18 +08:00
dae23300fe point to a single .entitlements file (undo most of previous commit) 2026-06-02 15:50:17 -06:00
9e401febea add 'share' to the entitlements for production, for sharing with this app 2026-06-02 15:46:36 -06:00
cd4b279703 Merge pull request '16kb-pages' (#232) from 16kb-pages into master
Reviewed-on: #232
2026-05-25 20:01:18 +00:00
a3a2d97b9a update version to v 1.4.2 build 68 2026-05-24 21:50:39 -06:00
802050259c update android build, fix ios build for new version of MLKit BarcodeScanner (both build) 2026-05-24 21:24:18 -06:00
efd7d50a84 fix build error 2026-05-24 19:12:40 -06:00
39c389cda8 make do-not-pair group verbiage more clear 2026-05-24 18:38:56 -06:00
93fdcaf7ff fix timing error for a click (that only showed in firefox) 2026-05-24 18:29:11 -06:00
ad419efa0d utilize 'userMessage' if sent by server 2026-05-24 16:23:47 -06:00
ce45ddb2bd update after 'audit fix' 2026-05-24 16:23:09 -06:00