refactor(FN-1240): remove dashboard Capacitor coupling in favor of @fusion/mobile
- Remove legacy dashboard Capacitor config, scripts, and package dependencies now managed by @fusion/mobile - Rewrite network, splash-screen, and status-bar plugin managers to use guarded global Capacitor plugin adapters without direct @capacitor imports - Update plugin tests to stub Capacitor globals and drop obsolete capacitor config test coverage - Simplify dashboard mobile README guidance and add a @gsxdsm/fusion patch changeset documenting the migration
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
import { Network, type ConnectionType } from "@capacitor/network";
|
||||
import type {
|
||||
PluginManager,
|
||||
NetworkStatus,
|
||||
@@ -6,6 +5,38 @@ import type {
|
||||
PluginNetworkListenerHandle,
|
||||
} from "./types.js";
|
||||
|
||||
type NativeConnectionType = "wifi" | "cellular" | "none" | "unknown";
|
||||
|
||||
interface NativeNetworkStatus {
|
||||
connected: boolean;
|
||||
connectionType: NativeConnectionType;
|
||||
}
|
||||
|
||||
interface NativeNetworkPlugin {
|
||||
getStatus: () => Promise<NativeNetworkStatus>;
|
||||
addListener: (
|
||||
eventName: "networkStatusChange",
|
||||
callback: (status: NativeNetworkStatus) => void,
|
||||
) => PluginNetworkListenerHandle | Promise<PluginNetworkListenerHandle>;
|
||||
}
|
||||
|
||||
interface CapacitorGlobal {
|
||||
Capacitor?: {
|
||||
Plugins?: Record<string, unknown>;
|
||||
};
|
||||
}
|
||||
|
||||
function getNativeNetworkPlugin(): NativeNetworkPlugin | null {
|
||||
const plugins = (globalThis as CapacitorGlobal).Capacitor?.Plugins;
|
||||
const candidate = plugins?.Network as Partial<NativeNetworkPlugin> | undefined;
|
||||
|
||||
if (!candidate || typeof candidate.getStatus !== "function" || typeof candidate.addListener !== "function") {
|
||||
return null;
|
||||
}
|
||||
|
||||
return candidate as NativeNetworkPlugin;
|
||||
}
|
||||
|
||||
export class NetworkManager implements PluginManager {
|
||||
private status: NetworkStatus;
|
||||
private listeners: Array<NetworkStatusCallback> = [];
|
||||
@@ -22,9 +53,15 @@ export class NetworkManager implements PluginManager {
|
||||
return;
|
||||
}
|
||||
|
||||
const networkPlugin = getNativeNetworkPlugin();
|
||||
|
||||
try {
|
||||
const currentStatus = await Network.getStatus();
|
||||
this.status = this.toNetworkStatus(currentStatus.connected, currentStatus.connectionType);
|
||||
if (networkPlugin) {
|
||||
const currentStatus = await networkPlugin.getStatus();
|
||||
this.status = this.toNetworkStatus(currentStatus.connected, currentStatus.connectionType);
|
||||
} else {
|
||||
this.status = { connected: true, connectionType: "unknown" };
|
||||
}
|
||||
} catch {
|
||||
// Network plugin may not be available in browser context
|
||||
this.status = { connected: true, connectionType: "unknown" };
|
||||
@@ -39,10 +76,17 @@ export class NetworkManager implements PluginManager {
|
||||
return;
|
||||
}
|
||||
|
||||
const networkPlugin = getNativeNetworkPlugin();
|
||||
if (!networkPlugin) {
|
||||
this.networkListenerHandle = null;
|
||||
this.monitoring = false;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.networkListenerHandle = await Network.addListener(
|
||||
const listenerHandle = networkPlugin.addListener(
|
||||
"networkStatusChange",
|
||||
(status) => {
|
||||
(status: NativeNetworkStatus) => {
|
||||
const nextStatus = this.toNetworkStatus(status.connected, status.connectionType);
|
||||
const previousConnected = this.status.connected;
|
||||
this.status = nextStatus;
|
||||
@@ -58,6 +102,8 @@ export class NetworkManager implements PluginManager {
|
||||
this.emit("network:change", nextStatus);
|
||||
},
|
||||
);
|
||||
|
||||
this.networkListenerHandle = await Promise.resolve(listenerHandle);
|
||||
this.monitoring = true;
|
||||
} catch {
|
||||
// Network plugin may not be available in browser context
|
||||
@@ -108,7 +154,7 @@ export class NetworkManager implements PluginManager {
|
||||
}
|
||||
}
|
||||
|
||||
private toNetworkStatus(connected: boolean, connectionType: ConnectionType): NetworkStatus {
|
||||
private toNetworkStatus(connected: boolean, connectionType: NativeConnectionType): NetworkStatus {
|
||||
return {
|
||||
connected,
|
||||
connectionType: connectionType as NetworkStatus["connectionType"],
|
||||
|
||||
@@ -1,6 +1,27 @@
|
||||
import { SplashScreen } from "@capacitor/splash-screen";
|
||||
import type { PluginManager } from "./types.js";
|
||||
|
||||
interface NativeSplashScreenPlugin {
|
||||
hide: (options: { fadeOutDuration: number }) => Promise<void>;
|
||||
show: (options: { autoHide: boolean }) => Promise<void>;
|
||||
}
|
||||
|
||||
interface CapacitorGlobal {
|
||||
Capacitor?: {
|
||||
Plugins?: Record<string, unknown>;
|
||||
};
|
||||
}
|
||||
|
||||
function getNativeSplashScreenPlugin(): NativeSplashScreenPlugin | null {
|
||||
const plugins = (globalThis as CapacitorGlobal).Capacitor?.Plugins;
|
||||
const candidate = plugins?.SplashScreen as Partial<NativeSplashScreenPlugin> | undefined;
|
||||
|
||||
if (!candidate || typeof candidate.hide !== "function" || typeof candidate.show !== "function") {
|
||||
return null;
|
||||
}
|
||||
|
||||
return candidate as NativeSplashScreenPlugin;
|
||||
}
|
||||
|
||||
export interface SplashScreenOptions {
|
||||
autoHide?: boolean;
|
||||
hideDelay?: number;
|
||||
@@ -34,16 +55,26 @@ export class SplashScreenManager implements PluginManager {
|
||||
}
|
||||
|
||||
async hide(): Promise<void> {
|
||||
const splashScreenPlugin = getNativeSplashScreenPlugin();
|
||||
if (!splashScreenPlugin) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await SplashScreen.hide({ fadeOutDuration: 300 });
|
||||
await splashScreenPlugin.hide({ fadeOutDuration: 300 });
|
||||
} catch {
|
||||
// Ignore errors — splash screen may not be available in browser/web context
|
||||
}
|
||||
}
|
||||
|
||||
async show(): Promise<void> {
|
||||
const splashScreenPlugin = getNativeSplashScreenPlugin();
|
||||
if (!splashScreenPlugin) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await SplashScreen.show({ autoHide: false });
|
||||
await splashScreenPlugin.show({ autoHide: false });
|
||||
} catch {
|
||||
// Ignore errors — splash screen may not be available in browser/web context
|
||||
}
|
||||
|
||||
@@ -1,10 +1,30 @@
|
||||
import { StatusBar, Style } from "@capacitor/status-bar";
|
||||
import type {
|
||||
PluginManager,
|
||||
ThemeMode,
|
||||
ThemeChangeCallback,
|
||||
} from "./types.js";
|
||||
|
||||
interface NativeStatusBarPlugin {
|
||||
setStyle: (options: { style: "DARK" | "LIGHT" }) => Promise<void>;
|
||||
}
|
||||
|
||||
interface CapacitorGlobal {
|
||||
Capacitor?: {
|
||||
Plugins?: Record<string, unknown>;
|
||||
};
|
||||
}
|
||||
|
||||
function getNativeStatusBarPlugin(): NativeStatusBarPlugin | null {
|
||||
const plugins = (globalThis as CapacitorGlobal).Capacitor?.Plugins;
|
||||
const candidate = plugins?.StatusBar as Partial<NativeStatusBarPlugin> | undefined;
|
||||
|
||||
if (!candidate || typeof candidate.setStyle !== "function") {
|
||||
return null;
|
||||
}
|
||||
|
||||
return candidate as NativeStatusBarPlugin;
|
||||
}
|
||||
|
||||
export interface StatusBarOptions {
|
||||
themeMode?: ThemeMode;
|
||||
}
|
||||
@@ -50,11 +70,16 @@ export class StatusBarManager implements PluginManager {
|
||||
}
|
||||
|
||||
private async applyTheme(mode: ThemeMode): Promise<void> {
|
||||
const statusBarPlugin = getNativeStatusBarPlugin();
|
||||
if (!statusBarPlugin) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isDark = mode === "dark" || (mode === "system" && this.isSystemDark());
|
||||
|
||||
try {
|
||||
await StatusBar.setStyle({
|
||||
style: isDark ? Style.Dark : Style.Light,
|
||||
await statusBarPlugin.setStyle({
|
||||
style: isDark ? "DARK" : "LIGHT",
|
||||
});
|
||||
} catch {
|
||||
// StatusBar plugin may not be available in browser context
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import type { PluginListenerHandle } from "@capacitor/core";
|
||||
|
||||
/** Network connectivity status */
|
||||
export interface NetworkStatus {
|
||||
connected: boolean;
|
||||
@@ -38,6 +36,11 @@ export interface PluginManager {
|
||||
destroy(): Promise<void>;
|
||||
}
|
||||
|
||||
/** Minimal listener handle contract used by network plugin adapters. */
|
||||
export interface PluginListenerHandle {
|
||||
remove: () => void | Promise<void>;
|
||||
}
|
||||
|
||||
/** Shared network listener handle type for manager implementations. */
|
||||
export type PluginNetworkListenerHandle = PluginListenerHandle;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user