refactor(platform): replace platform checks with capability-based system

- Add PlatformCapabilities interface to define available features
- Remove isWeb(), isCapacitor(), isElectron(), isPyWebView() methods
- Update platform services to implement getCapabilities()
- Refactor DataExportSection to use capability checks instead of platform checks
- Improve platform abstraction and separation of concerns
- Make platform-specific logic more maintainable and extensible

This change decouples components from specific platform implementations,
making the codebase more maintainable and easier to extend with new platforms.
This commit is contained in:
Matthew Raymer
2025-04-08 11:29:39 +00:00
parent 4853d0a7d0
commit 08fcccc528
8 changed files with 105 additions and 152 deletions

View File

@@ -42,17 +42,17 @@
>
If no download happened yet, click again here to download now.
</a>
<div class="mt-4" v-if="showPlatformInstructions">
<div class="mt-4" v-if="platformCapabilities.needsFileHandlingInstructions">
<p>
After the download, you can save the file in your preferred storage
location.
</p>
<ul>
<li v-if="platformService.isCapacitor() && isIOS" class="list-disc list-outside ml-4">
<li v-if="platformCapabilities.isIOS" class="list-disc list-outside ml-4">
On iOS: Choose "More..." and select a place in iCloud, or go "Back"
and save to another location.
</li>
<li v-if="platformService.isCapacitor() && !isIOS" class="list-disc list-outside ml-4">
<li v-if="platformCapabilities.isMobile && !platformCapabilities.isIOS" class="list-disc list-outside ml-4">
On Android: Choose "Open" and then share
<font-awesome icon="share-nodes" class="fa-fw" />
to your prefered place.
@@ -68,7 +68,7 @@ import { NotificationIface } from "../constants/app";
import { db } from "../db/index";
import { logger } from "../utils/logger";
import { PlatformServiceFactory } from "../services/PlatformServiceFactory";
import { PlatformService } from "../services/PlatformService";
import { PlatformService, PlatformCapabilities } from "../services/PlatformService";
/**
* @vue-component
@@ -103,17 +103,10 @@ export default class DataExportSection extends Vue {
private platformService: PlatformService = PlatformServiceFactory.getInstance();
/**
* Whether the current platform is iOS
* Platform capabilities for the current platform
*/
private get isIOS(): boolean {
return /iPad|iPhone|iPod/.test(navigator.userAgent);
}
/**
* Whether to show platform-specific instructions
*/
private get showPlatformInstructions(): boolean {
return this.platformService.isCapacitor();
private get platformCapabilities(): PlatformCapabilities {
return this.platformService.getCapabilities();
}
/**
@@ -121,7 +114,7 @@ export default class DataExportSection extends Vue {
* Revokes object URL when component is unmounted (web platform only)
*/
beforeUnmount() {
if (this.downloadUrl && this.platformService.isWeb()) {
if (this.downloadUrl && this.platformCapabilities.hasFileDownload) {
URL.revokeObjectURL(this.downloadUrl);
}
}
@@ -139,7 +132,7 @@ export default class DataExportSection extends Vue {
const blob = await db.export({ prettyJson: true });
const fileName = `${db.name}-backup.json`;
if (this.platformService.isWeb()) {
if (this.platformCapabilities.hasFileDownload) {
// Web platform: Use download link
this.downloadUrl = URL.createObjectURL(blob);
const downloadAnchor = this.$refs.downloadLink as HTMLAnchorElement;
@@ -147,13 +140,10 @@ export default class DataExportSection extends Vue {
downloadAnchor.download = fileName;
downloadAnchor.click();
setTimeout(() => URL.revokeObjectURL(this.downloadUrl), 1000);
} else if (this.platformService.isCapacitor()) {
// Capacitor platform: Write to app directory
} else if (this.platformCapabilities.hasFileSystem) {
// Native platform: Write to app directory
const content = await blob.text();
await this.platformService.writeFile(fileName, content);
} else {
// Other platforms: Use platform service
await this.platformService.writeFile(fileName, await blob.text());
}
this.$notify(
@@ -161,7 +151,7 @@ export default class DataExportSection extends Vue {
group: "alert",
type: "success",
title: "Export Successful",
text: this.platformService.isWeb()
text: this.platformCapabilities.hasFileDownload
? "See your downloads directory for the backup. It is in the Dexie format."
: "The backup has been saved to your device.",
},
@@ -187,7 +177,7 @@ export default class DataExportSection extends Vue {
*/
public computedStartDownloadLinkClassNames() {
return {
hidden: this.downloadUrl && this.platformService.isWeb(),
hidden: this.downloadUrl && this.platformCapabilities.hasFileDownload,
};
}
@@ -197,7 +187,7 @@ export default class DataExportSection extends Vue {
*/
public computedDownloadLinkClassNames() {
return {
hidden: !this.downloadUrl || !this.platformService.isWeb(),
hidden: !this.downloadUrl || !this.platformCapabilities.hasFileDownload,
};
}
}