Browse Source
- Add useDefineForClassFields for class field initialization - Remove test-playwright from includes - Add tsconfig.node.json reference - Remove redundant node_modules excludecross-platform-factory
7 changed files with 327 additions and 0 deletions
@ -0,0 +1,20 @@ |
|||||
|
export interface PlatformService { |
||||
|
// File system operations
|
||||
|
readFile(path: string): Promise<string>; |
||||
|
writeFile(path: string, content: string): Promise<void>; |
||||
|
deleteFile(path: string): Promise<void>; |
||||
|
listFiles(directory: string): Promise<string[]>; |
||||
|
|
||||
|
// Camera operations
|
||||
|
takePicture(): Promise<string>; |
||||
|
pickImage(): Promise<string>; |
||||
|
|
||||
|
// Platform specific features
|
||||
|
isCapacitor(): boolean; |
||||
|
isElectron(): boolean; |
||||
|
isPyWebView(): boolean; |
||||
|
isWeb(): boolean; |
||||
|
|
||||
|
// Deep linking
|
||||
|
handleDeepLink(url: string): Promise<void>; |
||||
|
} |
@ -0,0 +1,36 @@ |
|||||
|
import { Capacitor } from "@capacitor/core"; |
||||
|
import { PlatformService } from "./PlatformService"; |
||||
|
import { WebPlatformService } from "./platforms/WebPlatformService"; |
||||
|
import { CapacitorPlatformService } from "./platforms/CapacitorPlatformService"; |
||||
|
import { ElectronPlatformService } from "./platforms/ElectronPlatformService"; |
||||
|
import { PyWebViewPlatformService } from "./platforms/PyWebViewPlatformService"; |
||||
|
|
||||
|
export class PlatformServiceFactory { |
||||
|
private static instance: PlatformService | null = null; |
||||
|
|
||||
|
public static getInstance(): PlatformService { |
||||
|
if (PlatformServiceFactory.instance) { |
||||
|
return PlatformServiceFactory.instance; |
||||
|
} |
||||
|
|
||||
|
const platform = process.env.VITE_PLATFORM || "web"; |
||||
|
|
||||
|
switch (platform) { |
||||
|
case "capacitor": |
||||
|
PlatformServiceFactory.instance = new CapacitorPlatformService(); |
||||
|
break; |
||||
|
case "electron": |
||||
|
PlatformServiceFactory.instance = new ElectronPlatformService(); |
||||
|
break; |
||||
|
case "pywebview": |
||||
|
PlatformServiceFactory.instance = new PyWebViewPlatformService(); |
||||
|
break; |
||||
|
case "web": |
||||
|
default: |
||||
|
PlatformServiceFactory.instance = new WebPlatformService(); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
return PlatformServiceFactory.instance; |
||||
|
} |
||||
|
} |
@ -0,0 +1,80 @@ |
|||||
|
import { PlatformService } from "../PlatformService"; |
||||
|
import { Capacitor } from "@capacitor/core"; |
||||
|
import { Filesystem, Directory } from "@capacitor/filesystem"; |
||||
|
import { Camera, CameraResultType, CameraSource } from "@capacitor/camera"; |
||||
|
import { App } from "@capacitor/app"; |
||||
|
|
||||
|
export class CapacitorPlatformService implements PlatformService { |
||||
|
async readFile(path: string): Promise<string> { |
||||
|
const file = await Filesystem.readFile({ |
||||
|
path, |
||||
|
directory: Directory.Data, |
||||
|
}); |
||||
|
return file.data; |
||||
|
} |
||||
|
|
||||
|
async writeFile(path: string, content: string): Promise<void> { |
||||
|
await Filesystem.writeFile({ |
||||
|
path, |
||||
|
data: content, |
||||
|
directory: Directory.Data, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
async deleteFile(path: string): Promise<void> { |
||||
|
await Filesystem.deleteFile({ |
||||
|
path, |
||||
|
directory: Directory.Data, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
async listFiles(directory: string): Promise<string[]> { |
||||
|
const result = await Filesystem.readdir({ |
||||
|
path: directory, |
||||
|
directory: Directory.Data, |
||||
|
}); |
||||
|
return result.files; |
||||
|
} |
||||
|
|
||||
|
async takePicture(): Promise<string> { |
||||
|
const image = await Camera.getPhoto({ |
||||
|
quality: 90, |
||||
|
allowEditing: true, |
||||
|
resultType: CameraResultType.Uri, |
||||
|
source: CameraSource.Camera, |
||||
|
}); |
||||
|
return image.webPath || ""; |
||||
|
} |
||||
|
|
||||
|
async pickImage(): Promise<string> { |
||||
|
const image = await Camera.getPhoto({ |
||||
|
quality: 90, |
||||
|
allowEditing: true, |
||||
|
resultType: CameraResultType.Uri, |
||||
|
source: CameraSource.Photos, |
||||
|
}); |
||||
|
return image.webPath || ""; |
||||
|
} |
||||
|
|
||||
|
isCapacitor(): boolean { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
isElectron(): boolean { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
isPyWebView(): boolean { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
isWeb(): boolean { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
async handleDeepLink(url: string): Promise<void> { |
||||
|
// Capacitor handles deep links automatically
|
||||
|
// This is just a placeholder for the interface
|
||||
|
return Promise.resolve(); |
||||
|
} |
||||
|
} |
@ -0,0 +1,47 @@ |
|||||
|
import { PlatformService } from '../PlatformService'; |
||||
|
|
||||
|
export class ElectronPlatformService implements PlatformService { |
||||
|
async readFile(path: string): Promise<string> { |
||||
|
throw new Error('Not implemented'); |
||||
|
} |
||||
|
|
||||
|
async writeFile(path: string, content: string): Promise<void> { |
||||
|
throw new Error('Not implemented'); |
||||
|
} |
||||
|
|
||||
|
async deleteFile(path: string): Promise<void> { |
||||
|
throw new Error('Not implemented'); |
||||
|
} |
||||
|
|
||||
|
async listFiles(directory: string): Promise<string[]> { |
||||
|
throw new Error('Not implemented'); |
||||
|
} |
||||
|
|
||||
|
async takePicture(): Promise<string> { |
||||
|
throw new Error('Not implemented'); |
||||
|
} |
||||
|
|
||||
|
async pickImage(): Promise<string> { |
||||
|
throw new Error('Not implemented'); |
||||
|
} |
||||
|
|
||||
|
isCapacitor(): boolean { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
isElectron(): boolean { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
isPyWebView(): boolean { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
isWeb(): boolean { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
async handleDeepLink(url: string): Promise<void> { |
||||
|
throw new Error('Not implemented'); |
||||
|
} |
||||
|
} |
@ -0,0 +1,47 @@ |
|||||
|
import { PlatformService } from '../PlatformService'; |
||||
|
|
||||
|
export class PyWebViewPlatformService implements PlatformService { |
||||
|
async readFile(path: string): Promise<string> { |
||||
|
throw new Error('Not implemented'); |
||||
|
} |
||||
|
|
||||
|
async writeFile(path: string, content: string): Promise<void> { |
||||
|
throw new Error('Not implemented'); |
||||
|
} |
||||
|
|
||||
|
async deleteFile(path: string): Promise<void> { |
||||
|
throw new Error('Not implemented'); |
||||
|
} |
||||
|
|
||||
|
async listFiles(directory: string): Promise<string[]> { |
||||
|
throw new Error('Not implemented'); |
||||
|
} |
||||
|
|
||||
|
async takePicture(): Promise<string> { |
||||
|
throw new Error('Not implemented'); |
||||
|
} |
||||
|
|
||||
|
async pickImage(): Promise<string> { |
||||
|
throw new Error('Not implemented'); |
||||
|
} |
||||
|
|
||||
|
isCapacitor(): boolean { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
isElectron(): boolean { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
isPyWebView(): boolean { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
isWeb(): boolean { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
async handleDeepLink(url: string): Promise<void> { |
||||
|
throw new Error('Not implemented'); |
||||
|
} |
||||
|
} |
@ -0,0 +1,87 @@ |
|||||
|
import { PlatformService } from "../PlatformService"; |
||||
|
|
||||
|
export class WebPlatformService implements PlatformService { |
||||
|
async readFile(path: string): Promise<string> { |
||||
|
throw new Error("File system access not available in web platform"); |
||||
|
} |
||||
|
|
||||
|
async writeFile(path: string, content: string): Promise<void> { |
||||
|
throw new Error("File system access not available in web platform"); |
||||
|
} |
||||
|
|
||||
|
async deleteFile(path: string): Promise<void> { |
||||
|
throw new Error("File system access not available in web platform"); |
||||
|
} |
||||
|
|
||||
|
async listFiles(directory: string): Promise<string[]> { |
||||
|
throw new Error("File system access not available in web platform"); |
||||
|
} |
||||
|
|
||||
|
async takePicture(): Promise<string> { |
||||
|
return new Promise((resolve, reject) => { |
||||
|
const input = document.createElement("input"); |
||||
|
input.type = "file"; |
||||
|
input.accept = "image/*"; |
||||
|
input.capture = "environment"; |
||||
|
|
||||
|
input.onchange = (e) => { |
||||
|
const file = (e.target as HTMLInputElement).files?.[0]; |
||||
|
if (file) { |
||||
|
const reader = new FileReader(); |
||||
|
reader.onload = (event) => { |
||||
|
resolve(event.target?.result as string); |
||||
|
}; |
||||
|
reader.readAsDataURL(file); |
||||
|
} else { |
||||
|
reject(new Error("No file selected")); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
input.click(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
async pickImage(): Promise<string> { |
||||
|
return new Promise((resolve, reject) => { |
||||
|
const input = document.createElement("input"); |
||||
|
input.type = "file"; |
||||
|
input.accept = "image/*"; |
||||
|
|
||||
|
input.onchange = (e) => { |
||||
|
const file = (e.target as HTMLInputElement).files?.[0]; |
||||
|
if (file) { |
||||
|
const reader = new FileReader(); |
||||
|
reader.onload = (event) => { |
||||
|
resolve(event.target?.result as string); |
||||
|
}; |
||||
|
reader.readAsDataURL(file); |
||||
|
} else { |
||||
|
reject(new Error("No file selected")); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
input.click(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
isCapacitor(): boolean { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
isElectron(): boolean { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
isPyWebView(): boolean { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
isWeb(): boolean { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
async handleDeepLink(url: string): Promise<void> { |
||||
|
// Web platform can handle deep links through URL parameters
|
||||
|
return Promise.resolve(); |
||||
|
} |
||||
|
} |
@ -0,0 +1,10 @@ |
|||||
|
{ |
||||
|
"compilerOptions": { |
||||
|
"composite": true, |
||||
|
"skipLibCheck": true, |
||||
|
"module": "ESNext", |
||||
|
"moduleResolution": "bundler", |
||||
|
"allowSyntheticDefaultImports": true |
||||
|
}, |
||||
|
"include": ["vite.config.*"] |
||||
|
} |
Loading…
Reference in new issue