Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ android {
applicationId "com.maison.mona"
minSdkVersion 26
targetSdkVersion 35
versionCode 801
versionName "8.0.1"
versionCode 803
versionName "8.0.3"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
aaptOptions {
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
Expand Down
8 changes: 4 additions & 4 deletions ios/App/App.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -348,12 +348,12 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 801;
CURRENT_PROJECT_VERSION = 803;
DEVELOPMENT_TEAM = 843UJ9V2XK;
INFOPLIST_FILE = App/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 8.0.1;
MARKETING_VERSION = 8.0.3;
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
PRODUCT_BUNDLE_IDENTIFIER = com.mona.starter;
PRODUCT_NAME = "$(TARGET_NAME)";
Expand All @@ -369,12 +369,12 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 801;
CURRENT_PROJECT_VERSION = 803;
DEVELOPMENT_TEAM = 843UJ9V2XK;
INFOPLIST_FILE = App/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 8.0.1;
MARKETING_VERSION = 8.0.3;
PRODUCT_BUNDLE_IDENTIFIER = "ca.umontreal.mona-ios";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
Expand Down
34 changes: 31 additions & 3 deletions src/components/DiscoveryDetails.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<template>
<template v-if="isReady">
<div class="discoveryDetailsContainer">
<div class="discoverydetails">
<div class="chipsContainer">
Expand Down Expand Up @@ -144,7 +145,13 @@
></ion-icon>
PHOTOGRAPHIER
</ion-button>
</div>
</div>
</template>
<template v-else>
<div class="discoveryDetailsContainer loading-placeholder">
<div class="loading-text">Chargement…</div>
</div>
</template>
</template>

<script>
Expand Down Expand Up @@ -267,8 +274,8 @@ export default {
},

setup(props) {
const id = parseInt(props.selectedDiscovery.id.toString() || "-1");
const type = props.selectedDiscovery.dType || "-1";
const id = parseInt(((props.selectedDiscovery && props.selectedDiscovery.id) ? props.selectedDiscovery.id.toString() : "-1"));
const type = (props.selectedDiscovery && props.selectedDiscovery.dType) ? props.selectedDiscovery.dType : "-1";
//former: const type = parseInt(props.selectedDiscoveryType.toString() || "-1");

const discovery =
Expand All @@ -281,6 +288,16 @@ export default {
};
},

computed: {
isReady() {
return (
this.discovery &&
typeof this.discovery.id === "number" &&
typeof this.discovery.getTitle === "function"
);
},
},

mounted() {
const userData = UserData.getCollected(
this.discovery.id,
Expand Down Expand Up @@ -609,4 +626,15 @@ ion-button {
text-decoration: underline;
}

.loading-placeholder {
display: flex;
align-items: center;
justify-content: center;
height: 40vh;
}
.loading-text {
font-size: 3.8vw;
color: #666;
}

</style>
31 changes: 29 additions & 2 deletions src/components/DiscoveryDetailsFullModale.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<template>
<ion-content>
<template v-if="isReady">
<ion-content>
<div class="discoveryDetailsContainer">
<div class="discoverydetails">
<div class="chipsContainer">
Expand Down Expand Up @@ -309,7 +310,13 @@
PHOTOGRAPHIER
</ion-button>
</div>
</ion-content>
</ion-content>
</template>
<template v-else>
<ion-content class="loading-placeholder">
<div class="loading-text">Chargement…</div>
</ion-content>
</template>
</template>

<script>
Expand Down Expand Up @@ -711,6 +718,15 @@ export default {
return this.details3 && this.details3.trim() !== '';
},
},
computed: {
isReady() {
return (
this.discovery &&
typeof this.discovery.id === "number" &&
typeof this.discovery.getTitle === "function"
);
},
},
};
</script>

Expand Down Expand Up @@ -1041,4 +1057,15 @@ a {
color: black;
font-weight: normal;
}

.loading-placeholder {
display: flex;
align-items: center;
justify-content: center;
height: 60vh;
}
.loading-text {
font-size: 3.8vw;
color: #666;
}
</style>
4 changes: 2 additions & 2 deletions src/components/LogoutContainer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ export default {
document.querySelector("ion-back-button").click();
},

disconnectUser() {
UserData.resetPreferences(false); // `false` to keep hasSeenTutorial to true
async disconnectUser() {
await UserData.clearLocalDataAndReset(false); // wipe local DBs and cache, keep tutorial flag

// Go to main page
this.$router.replace("/register")
Expand Down
37 changes: 34 additions & 3 deletions src/internal/databases/Database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,38 @@ export abstract class Database {

if (typeof content.data === "string") {
const parsed = JSON.parse(content.data);

// Validate and construct elements; if any element is malformed,
// consider the local DB file corrupt and fetch from server instead.
const validated: Discovery[] = [];

for (const element of parsed) {
// for (const element of parsed.data) {
this.data.push(this.createSingleElement(element));
try {
const candidate = this.createSingleElement(element);

// Basic validation: must have numeric id and a callable getTitle
if (
!candidate ||
typeof candidate.id !== "number" ||
typeof candidate.getTitle !== "function"
) {
throw new Error("Invalid discovery object");
}

validated.push(candidate);
} catch (e) {
console.warn(`${this.type} db: detected corrupt element while parsing local file (${e}). Will rebuild from server.`);
// Delete the corrupted local file and populate from server
try {
await Filesystem.deleteFile({ path: this.path, directory: Directory.Data });
} catch (_ignored) {}

return await this.populateFromServer();
}
}
}

this.data = validated;
}

console.log(`${this.type} db: successfully populated (locally).`);
} catch (err) {
Expand Down Expand Up @@ -126,4 +152,9 @@ export abstract class Database {

return this.data.slice(a, b);
}

// Reset in-memory data for this database (useful when clearing local files)
public static resetData() {
this.data = [];
}
}
27 changes: 27 additions & 0 deletions src/internal/databases/UserData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,17 @@ export class UserData {
this.updateFile();
}

public static async clearLocalDataAndReset(resetTutorial = true) {
// Remove local mirrored DB files and cache, then reset preferences
await this.deleteLocalDatabaseFiles();
await this.invalidateCacheFile();
// Clear any in-memory caches that could hold stale discovery objects
this.sortedDiscoveries = [];
this.sortedDiscoveriesDistance = [];

this.resetPreferences(resetTutorial);
}

public static async ensureDataSchemaUpToDate() {
await this.populate();
const storedVersion = this.data?.schemaVersion ?? 0;
Expand Down Expand Up @@ -308,6 +319,22 @@ export class UserData {
}).catch(() => undefined),
),
);

// Also reset in-memory DBs so app doesn't keep using stale data after files are deleted
try {
const { ArtworkDatabase } = await import("@/internal/databases/ArtworkDatabase");
const { PlaceDatabase } = await import("@/internal/databases/PlaceDatabase");
const { HeritageDatabase } = await import("@/internal/databases/HeritageDatabase");
const { BadgeDatabase } = await import("@/internal/databases/BadgeDatabase");

ArtworkDatabase.resetData();
PlaceDatabase.resetData();
HeritageDatabase.resetData();
BadgeDatabase.resetData();
} catch (err) {
// If dynamic import fails for any reason, ignore — best-effort reset
console.warn("Failed to reset in-memory DBs:", err);
}
}

private static parseCachePayload(parsed: any): { version: number; data: any[] } | null {
Expand Down