feat(ios): improve share extension UX and fix image reload issues

Improve iOS share extension implementation to skip interstitial UI and
fix issues with subsequent image shares not updating the view.

iOS Share Extension Improvements:
- Replace SLComposeServiceViewController with custom UIViewController
  to eliminate interstitial "Post" button UI
- Use minimal URL (timesafari://) instead of deep link for app launch
- Implement app lifecycle detection via Capacitor appStateChange listener
  instead of relying solely on deep links

Deep Link and Navigation Fixes:
- Remove "shared-photo" from deep link schemas (no longer needed)
- Add empty path URL handling for share extension launches
- Implement processing lock to prevent duplicate image processing
- Add retry mechanism (300ms delay) to handle race conditions with
  AppDelegate writing temp files
- Use router.replace() when already on /shared-photo route to force refresh
- Clear old images from temp DB before storing new ones
- Delete temp file immediately after reading to prevent stale data

SharedPhotoView Component:
- Add route watcher (@Watch) to reload image when fileName query
  parameter changes
- Extract image loading logic into reusable loadSharedImage() method
- Improve error handling to clear image state on failures

This fixes the issue where sharing a second image while already on
SharedPhotoView would display the previous image instead of the new one.
This commit is contained in:
Jose Olarte III
2025-11-25 18:22:43 +08:00
parent ae49c0e907
commit eff4126043
6 changed files with 565 additions and 75 deletions

View File

@@ -120,7 +120,7 @@
<script lang="ts">
import axios from "axios";
import { Component, Vue } from "vue-facing-decorator";
import { Component, Vue, Watch } from "vue-facing-decorator";
import {
RouteLocationNormalizedLoaded,
RouteLocationRaw,
@@ -191,7 +191,29 @@ export default class SharedPhotoView extends Vue {
*/
async mounted() {
this.notify = createNotifyHelpers(this.$notify);
await this.loadSharedImage();
}
/**
* Watches for route query changes to reload image when navigating
* to the same route with different query parameters (e.g., new fileName)
*/
@Watch("$route.query.fileName")
async onFileNameChange(newFileName: string | undefined) {
if (newFileName) {
await this.loadSharedImage();
}
}
/**
* Loads the shared image from temporary storage
*
* Retrieves the shared image data from the temp database, converts it to a blob,
* and updates component state. Cleans up temporary storage after successful loading.
*
* @async
*/
private async loadSharedImage() {
try {
// Get activeDid from active_identity table (single source of truth)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -209,6 +231,9 @@ export default class SharedPhotoView extends Vue {
this.imageFileName = this.$route.query["fileName"] as string;
} else {
logger.error("No appropriate image found in temp storage.", temp);
// Clear image state if no temp data found
this.imageBlob = undefined;
this.imageFileName = undefined;
}
} catch (err: unknown) {
logger.error("Got an error loading an identifier:", err);
@@ -216,6 +241,9 @@ export default class SharedPhotoView extends Vue {
NOTIFY_SHARED_PHOTO_LOAD_ERROR.message,
TIMEOUTS.STANDARD,
);
// Clear image state on error
this.imageBlob = undefined;
this.imageFileName = undefined;
}
}