From aa7d82c531bfb092f35e24c17a7ff58b4fd6649b Mon Sep 17 00:00:00 2001
From: Trent Larson
Date: Fri, 10 May 2024 13:17:20 -0600
Subject: [PATCH 1/3] add a share_target for people to add a photo
---
src/components/GiftedPhotoDialog.vue | 2 +-
src/constants/app.ts | 2 +
src/db/index.ts | 26 +++--
src/db/tables/temp.ts | 13 +++
src/router/index.ts | 5 +
src/views/AccountViewView.vue | 18 +--
src/views/GiftedDetails.vue | 19 +++-
src/views/HelpView.vue | 45 ++++++--
src/views/NewEditProjectView.vue | 2 +-
src/views/ProjectViewView.vue | 24 ++--
src/views/SeedBackupView.vue | 5 +-
src/views/SharedPhotoView.vue | 164 +++++++++++++++++++++++++++
src/views/TestView.vue | 55 ++++++++-
sw_scripts/additional-scripts.js | 21 +++-
sw_scripts/safari-notifications.js | 14 +++
vite.config.mjs | 21 ++++
16 files changed, 377 insertions(+), 59 deletions(-)
create mode 100644 src/db/tables/temp.ts
create mode 100644 src/views/SharedPhotoView.vue
diff --git a/src/components/GiftedPhotoDialog.vue b/src/components/GiftedPhotoDialog.vue
index 20600bf..93c3582 100644
--- a/src/components/GiftedPhotoDialog.vue
+++ b/src/components/GiftedPhotoDialog.vue
@@ -330,7 +330,7 @@ export default class GiftedPhotoDialog extends Vue {
this.uploading = false;
return;
}
- formData.append("image", this.blob, "snapshot.png"); // png is set in snapshot()
+ formData.append("image", this.blob, "snapshot.png");
formData.append("claimType", this.claimType);
try {
const response = await axios.post(
diff --git a/src/constants/app.ts b/src/constants/app.ts
index 4f51f6b..161644e 100644
--- a/src/constants/app.ts
+++ b/src/constants/app.ts
@@ -30,6 +30,8 @@ export const DEFAULT_IMAGE_API_SERVER =
export const DEFAULT_PUSH_SERVER =
window.location.protocol + "//" + window.location.host;
+export const IMAGE_TYPE_PROFILE = "profile";
+
/**
* The possible values for "group" and "type" are in App.vue.
* From the notiwind package
diff --git a/src/db/index.ts b/src/db/index.ts
index 290a001..6bb59f2 100644
--- a/src/db/index.ts
+++ b/src/db/index.ts
@@ -8,6 +8,7 @@ import {
Settings,
SettingsSchema,
} from "./tables/settings";
+import { Temp, TempSchema } from "./tables/temp";
import { DEFAULT_ENDORSER_API_SERVER } from "@/constants/app";
// Define types for tables that hold sensitive and non-sensitive data
@@ -16,6 +17,7 @@ type NonsensitiveTables = {
contacts: Table;
logs: Table;
settings: Table;
+ temp: Table;
};
// Using 'unknown' instead of 'any' for stricter typing and to avoid TypeScript warnings
@@ -25,14 +27,7 @@ export type NonsensitiveDexie =
// Initialize Dexie databases for sensitive and non-sensitive data
export const accountsDB = new BaseDexie("TimeSafariAccounts") as SensitiveDexie;
-const SensitiveSchemas = { ...AccountsSchema };
-
export const db = new BaseDexie("TimeSafari") as NonsensitiveDexie;
-const NonsensitiveSchemas = {
- ...ContactSchema,
- ...LogSchema,
- ...SettingsSchema,
-};
// Manage the encryption key. If not present in localStorage, create and store it.
const secret =
@@ -42,11 +37,18 @@ if (!localStorage.getItem("secret")) localStorage.setItem("secret", secret);
// Apply encryption to the sensitive database using the secret key
encrypted(accountsDB, { secretKey: secret });
-// Define the schema for our databases
-accountsDB.version(1).stores(SensitiveSchemas);
-// v1 was contacts & settings
-// v2 added logs
-db.version(2).stores(NonsensitiveSchemas);
+// Define the schemas for our databases
+// Only the tables with index modifications need listing. https://dexie.org/docs/Tutorial/Design#database-versioning
+accountsDB.version(1).stores(AccountsSchema);
+// v1 also had contacts & settings
+// v2 added Log
+db.version(2).stores({
+ ...ContactSchema,
+ ...LogSchema,
+ ...SettingsSchema,
+});
+// v3 added Temp
+db.version(3).stores(TempSchema);
// Event handler to initialize the non-sensitive database with default settings
db.on("populate", () => {
diff --git a/src/db/tables/temp.ts b/src/db/tables/temp.ts
new file mode 100644
index 0000000..02b592b
--- /dev/null
+++ b/src/db/tables/temp.ts
@@ -0,0 +1,13 @@
+// for ephemeral uses, eg. passing a blob from the service worker to the main thread
+
+export type Temp = {
+ id: string;
+ blob?: Blob;
+};
+
+/**
+ * Schema for the Temp table in the database.
+ */
+export const TempSchema = {
+ temp: "id",
+};
diff --git a/src/router/index.ts b/src/router/index.ts
index 6ddb916..1189599 100644
--- a/src/router/index.ts
+++ b/src/router/index.ts
@@ -169,6 +169,11 @@ const routes: Array = [
name: "seed-backup",
component: () => import("../views/SeedBackupView.vue"),
},
+ {
+ path: "/shared-photo",
+ name: "shared-photo",
+ component: () => import("@/views/SharedPhotoView.vue"),
+ },
{
path: "/start",
name: "start",
diff --git a/src/views/AccountViewView.vue b/src/views/AccountViewView.vue
index e3b1b17..93d47eb 100644
--- a/src/views/AccountViewView.vue
+++ b/src/views/AccountViewView.vue
@@ -4,16 +4,6 @@
-
-
-
-
-
-
-
Your Identity
@@ -631,6 +621,7 @@ import {
AppString,
DEFAULT_IMAGE_API_SERVER,
DEFAULT_PUSH_SERVER,
+ IMAGE_TYPE_PROFILE,
NotificationIface,
} from "@/constants/app";
import { db, accountsDB } from "@/db/index";
@@ -1129,8 +1120,7 @@ export default class AccountViewView extends Vue {
console.error("Export Error:", error);
}
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- async uploadFile(event: any) {
+ async uploadFile(event: Event) {
inputFileNameRef.value = event.target.files[0];
}
@@ -1163,7 +1153,7 @@ export default class AccountViewView extends Vue {
async submitFile() {
if (inputFileNameRef.value != null) {
await db.delete();
- await Dexie.import(inputFileNameRef.value, {
+ await Dexie.import(inputFileNameRef.value as Blob, {
progressCallback: this.progressCallback,
});
}
@@ -1387,7 +1377,7 @@ export default class AccountViewView extends Vue {
//console.log("Got image URL:", imgUrl);
},
true,
- "profile",
+ IMAGE_TYPE_PROFILE,
);
}
diff --git a/src/views/GiftedDetails.vue b/src/views/GiftedDetails.vue
index 0f9f085..a37c2e3 100644
--- a/src/views/GiftedDetails.vue
+++ b/src/views/GiftedDetails.vue
@@ -180,7 +180,24 @@ export default class GiftedDetails extends Vue {
}
this.unitCode = this.$route.query.unitCode as string;
- this.imageUrl = localStorage.getItem("imageUrl") || "";
+ this.imageUrl =
+ (this.$route.query.imageUrl as string) ||
+ localStorage.getItem("imageUrl") ||
+ "";
+
+ // this is an endpoint for sharing project info to highlight something given
+ // https://developer.mozilla.org/en-US/docs/Web/Manifest/share_target
+ if (this.$route.query.shareTitle) {
+ this.description = this.$route.query.shareTitle as string;
+ }
+ if (this.$route.query.shareText) {
+ this.description =
+ (this.description ? this.description + " " : "") +
+ (this.$route.query.shareText as string);
+ }
+ if (this.$route.query.shareUrl) {
+ this.imageUrl = this.$route.query.shareUrl as string;
+ }
try {
await db.open();
diff --git a/src/views/HelpView.vue b/src/views/HelpView.vue
index 2217011..d8ab1c3 100644
--- a/src/views/HelpView.vue
+++ b/src/views/HelpView.vue
@@ -100,8 +100,9 @@
How do I backup all my data?
- There are two sets of data to backup: the identifier secrets and the
- other data that isn't quite a secret such as settings, contacts, etc.
+ There are three sets of data to backup: the identifier secrets;
+ the non-public textual data that isn't quite a secret such as settings and contacts;
+ the non-public image for yourself; and the data that you have sent to the public.
@@ -122,7 +123,7 @@
- How do I backup my other (non-identifier-secret) data?
+ How do I backup my non-secret, non-public text data?
@@ -134,6 +135,27 @@
won't lose it.
+
+
+ How do I backup my non-secret, non-public image?
+
+
+
+ Go to Your Identity page,
+ tap on your image, and save it.
+
+
+
+
+ How do I backup my public data?
+
+
+
+ This requires use of the API, so investigate the endpoints
+ here
+ (particularly the "claim" endpoints).
+
+
How do I restore my data?
@@ -178,8 +200,7 @@
How do I erase my data?
- Before doing this, note the two kinds of data to backup: identity data,
- and other data for contacts and settings (see instructions above).
+ Before doing this, you may want to back up your data with the instructions above.
@@ -198,11 +219,11 @@
Chrome:
- Clear at chrome://settings/content/all and
+ Clear at "chrome://settings/content/all" and
also clear under dev tools Application
- Firefox: go here, Manage Data,
+ Firefox: Navigate to "about:preferences", Manage Data,
find timesafari.app and select, hit Remove Selected, then Save
Changes
@@ -232,7 +253,7 @@
There is a even more functionality in a mobile app (and more
documentation) at
-
+
EndorserSearch.com
@@ -303,7 +324,7 @@
find "timesafari.app", and click "Unregister".
- Search
+ Search
for instructions for other browsers.