mirror of
https://github.com/AeThex-Corporation/AeThex-OS.git
synced 2026-04-18 14:37:19 +00:00
- ModuleManager: Central tracking for installed marketplace modules - DataAnalyzerWidget: Real-time CPU/RAM/Battery/Storage widget (unlocked by Data Analyzer module) - BottomNavBar: Navigation bar for Projects/Chat/Marketplace/Settings - RootShell: Real root command execution utility - TerminalActivity: Full root shell with neofetch, sysinfo, real Linux commands - Terminal Pro module: Adds aliases (ll, la, h), command history - ArcadeActivity + SnakeGame: Pixel Arcade module unlocks retro games - fade_in/fade_out animations for smooth transitions
374 lines
10 KiB
TypeScript
374 lines
10 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
import { Camera, CameraResultType, CameraSource } from '@capacitor/camera';
|
|
import { Filesystem, Directory, Encoding } from '@capacitor/filesystem';
|
|
import { Share } from '@capacitor/share';
|
|
import { PushNotifications } from '@capacitor/push-notifications';
|
|
import { Geolocation, Position } from '@capacitor/geolocation';
|
|
import { LocalNotifications } from '@capacitor/local-notifications';
|
|
import { Network } from '@capacitor/network';
|
|
import { Toast } from '@capacitor/toast';
|
|
import { Clipboard } from '@capacitor/clipboard';
|
|
import { ScreenOrientation } from '@capacitor/screen-orientation';
|
|
import { Browser } from '@capacitor/browser';
|
|
import { App } from '@capacitor/app';
|
|
import { Haptics, ImpactStyle } from '@capacitor/haptics';
|
|
|
|
interface UseNativeFeaturesReturn {
|
|
// Camera
|
|
takePhoto: () => Promise<string | null>;
|
|
pickPhoto: () => Promise<string | null>;
|
|
|
|
// Files
|
|
saveFile: (data: string, filename: string) => Promise<boolean>;
|
|
readFile: (filename: string) => Promise<string | null>;
|
|
pickFile: () => Promise<string | null>;
|
|
|
|
// Share
|
|
shareText: (text: string, title?: string) => Promise<void>;
|
|
shareUrl: (url: string, title?: string) => Promise<void>;
|
|
|
|
// Notifications
|
|
requestNotificationPermission: () => Promise<boolean>;
|
|
sendLocalNotification: (title: string, body: string) => Promise<void>;
|
|
|
|
// Location
|
|
getCurrentLocation: () => Promise<Position | null>;
|
|
watchLocation: (callback: (position: Position) => void) => () => void;
|
|
|
|
// Network
|
|
networkStatus: { connected: boolean; connectionType: string };
|
|
|
|
// Clipboard
|
|
copyToClipboard: (text: string) => Promise<void>;
|
|
pasteFromClipboard: () => Promise<string>;
|
|
|
|
// Screen
|
|
lockOrientation: (orientation: 'portrait' | 'landscape') => Promise<void>;
|
|
unlockOrientation: () => Promise<void>;
|
|
|
|
// Browser
|
|
openInBrowser: (url: string) => Promise<void>;
|
|
|
|
// Toast
|
|
showToast: (text: string, duration?: 'short' | 'long') => Promise<void>;
|
|
|
|
// Haptics
|
|
vibrate: (style?: 'light' | 'medium' | 'heavy') => Promise<void>;
|
|
}
|
|
|
|
export function useNativeFeatures(): UseNativeFeaturesReturn {
|
|
const [networkStatus, setNetworkStatus] = useState({ connected: true, connectionType: 'unknown' });
|
|
|
|
// Initialize network monitoring
|
|
useEffect(() => {
|
|
const initNetwork = async () => {
|
|
const status = await Network.getStatus();
|
|
setNetworkStatus({ connected: status.connected, connectionType: status.connectionType });
|
|
|
|
Network.addListener('networkStatusChange', status => {
|
|
setNetworkStatus({ connected: status.connected, connectionType: status.connectionType });
|
|
});
|
|
};
|
|
|
|
initNetwork();
|
|
|
|
return () => {
|
|
Network.removeAllListeners();
|
|
};
|
|
}, []);
|
|
|
|
// Camera functions
|
|
const takePhoto = async (): Promise<string | null> => {
|
|
try {
|
|
const image = await Camera.getPhoto({
|
|
quality: 90,
|
|
allowEditing: true,
|
|
resultType: CameraResultType.Base64,
|
|
source: CameraSource.Camera
|
|
});
|
|
return image.base64String || null;
|
|
} catch (error) {
|
|
console.error('Camera error:', error);
|
|
return null;
|
|
}
|
|
};
|
|
|
|
const pickPhoto = async (): Promise<string | null> => {
|
|
try {
|
|
const image = await Camera.getPhoto({
|
|
quality: 90,
|
|
allowEditing: true,
|
|
resultType: CameraResultType.Base64,
|
|
source: CameraSource.Photos
|
|
});
|
|
return image.base64String || null;
|
|
} catch (error) {
|
|
console.error('Photo picker error:', error);
|
|
return null;
|
|
}
|
|
};
|
|
|
|
// File system functions
|
|
const saveFile = async (data: string, filename: string): Promise<boolean> => {
|
|
try {
|
|
await Filesystem.writeFile({
|
|
path: filename,
|
|
data: data,
|
|
directory: Directory.Documents,
|
|
encoding: Encoding.UTF8
|
|
});
|
|
await showToast(`Saved ${filename}`, 'short');
|
|
return true;
|
|
} catch (error) {
|
|
console.error('File save error:', error);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
const readFile = async (filename: string): Promise<string | null> => {
|
|
try {
|
|
const result = await Filesystem.readFile({
|
|
path: filename,
|
|
directory: Directory.Documents,
|
|
encoding: Encoding.UTF8
|
|
});
|
|
return result.data as string;
|
|
} catch (error) {
|
|
console.error('File read error:', error);
|
|
return null;
|
|
}
|
|
};
|
|
|
|
const pickFile = async (): Promise<string | null> => {
|
|
// Use HTML5 File API - works in both web and mobile WebView
|
|
return new Promise((resolve) => {
|
|
const input = document.createElement('input');
|
|
input.type = 'file';
|
|
input.accept = '*/*';
|
|
|
|
input.onchange = async (event) => {
|
|
const target = event.target as HTMLInputElement;
|
|
const file = target.files?.[0];
|
|
|
|
if (!file) {
|
|
resolve(null);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// Read file as text or base64 depending on type
|
|
const reader = new FileReader();
|
|
|
|
if (file.type.startsWith('text/') ||
|
|
file.type === 'application/json' ||
|
|
file.type === 'application/javascript' ||
|
|
file.name.endsWith('.aethex')) {
|
|
reader.onload = () => resolve(reader.result as string);
|
|
reader.onerror = () => resolve(null);
|
|
reader.readAsText(file);
|
|
} else {
|
|
// Binary files as base64
|
|
reader.onload = () => {
|
|
const base64 = (reader.result as string).split(',')[1];
|
|
resolve(base64);
|
|
};
|
|
reader.onerror = () => resolve(null);
|
|
reader.readAsDataURL(file);
|
|
}
|
|
} catch (error) {
|
|
console.error('File pick error:', error);
|
|
resolve(null);
|
|
}
|
|
};
|
|
|
|
input.oncancel = () => resolve(null);
|
|
input.click();
|
|
});
|
|
};
|
|
|
|
// Share functions
|
|
const shareText = async (text: string, title?: string): Promise<void> => {
|
|
try {
|
|
await Share.share({
|
|
text: text,
|
|
title: title || 'Share',
|
|
dialogTitle: 'Share via'
|
|
});
|
|
await Haptics.impact({ style: ImpactStyle.Light });
|
|
} catch (error) {
|
|
console.error('Share error:', error);
|
|
}
|
|
};
|
|
|
|
const shareUrl = async (url: string, title?: string): Promise<void> => {
|
|
try {
|
|
await Share.share({
|
|
url: url,
|
|
title: title || 'Share',
|
|
dialogTitle: 'Share via'
|
|
});
|
|
await Haptics.impact({ style: ImpactStyle.Light });
|
|
} catch (error) {
|
|
console.error('Share error:', error);
|
|
}
|
|
};
|
|
|
|
// Notification functions
|
|
const requestNotificationPermission = async (): Promise<boolean> => {
|
|
try {
|
|
const result = await PushNotifications.requestPermissions();
|
|
if (result.receive === 'granted') {
|
|
await PushNotifications.register();
|
|
return true;
|
|
}
|
|
return false;
|
|
} catch (error) {
|
|
console.error('Notification permission error:', error);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
const sendLocalNotification = async (title: string, body: string): Promise<void> => {
|
|
try {
|
|
await LocalNotifications.schedule({
|
|
notifications: [
|
|
{
|
|
title: title,
|
|
body: body,
|
|
id: Date.now(),
|
|
schedule: { at: new Date(Date.now() + 1000) },
|
|
sound: undefined,
|
|
attachments: undefined,
|
|
actionTypeId: '',
|
|
extra: null
|
|
}
|
|
]
|
|
});
|
|
} catch (error) {
|
|
console.error('Local notification error:', error);
|
|
}
|
|
};
|
|
|
|
// Location functions
|
|
const getCurrentLocation = async (): Promise<Position | null> => {
|
|
try {
|
|
const position = await Geolocation.getCurrentPosition({
|
|
enableHighAccuracy: true,
|
|
timeout: 10000
|
|
});
|
|
return position;
|
|
} catch (error) {
|
|
console.error('Location error:', error);
|
|
return null;
|
|
}
|
|
};
|
|
|
|
const watchLocation = (callback: (position: Position) => void) => {
|
|
const watchId = Geolocation.watchPosition(
|
|
{ enableHighAccuracy: true },
|
|
(position, err) => {
|
|
if (position) callback(position);
|
|
}
|
|
);
|
|
|
|
return () => {
|
|
if (watchId) Geolocation.clearWatch({ id: watchId });
|
|
};
|
|
};
|
|
|
|
// Clipboard functions
|
|
const copyToClipboard = async (text: string): Promise<void> => {
|
|
try {
|
|
await Clipboard.write({ string: text });
|
|
await showToast('Copied to clipboard', 'short');
|
|
await Haptics.impact({ style: ImpactStyle.Light });
|
|
} catch (error) {
|
|
console.error('Clipboard error:', error);
|
|
}
|
|
};
|
|
|
|
const pasteFromClipboard = async (): Promise<string> => {
|
|
try {
|
|
const result = await Clipboard.read();
|
|
return result.value;
|
|
} catch (error) {
|
|
console.error('Clipboard error:', error);
|
|
return '';
|
|
}
|
|
};
|
|
|
|
// Screen orientation
|
|
const lockOrientation = async (orientation: 'portrait' | 'landscape'): Promise<void> => {
|
|
try {
|
|
await ScreenOrientation.lock({ orientation: orientation });
|
|
} catch (error) {
|
|
console.error('Orientation lock error:', error);
|
|
}
|
|
};
|
|
|
|
const unlockOrientation = async (): Promise<void> => {
|
|
try {
|
|
await ScreenOrientation.unlock();
|
|
} catch (error) {
|
|
console.error('Orientation unlock error:', error);
|
|
}
|
|
};
|
|
|
|
// Browser
|
|
const openInBrowser = async (url: string): Promise<void> => {
|
|
try {
|
|
await Browser.open({ url });
|
|
} catch (error) {
|
|
console.error('Browser error:', error);
|
|
}
|
|
};
|
|
|
|
// Toast
|
|
const showToast = async (text: string, duration: 'short' | 'long' = 'short'): Promise<void> => {
|
|
try {
|
|
await Toast.show({
|
|
text: text,
|
|
duration: duration,
|
|
position: 'bottom'
|
|
});
|
|
} catch (error) {
|
|
console.error('Toast error:', error);
|
|
}
|
|
};
|
|
|
|
// Haptics
|
|
const vibrate = async (style: 'light' | 'medium' | 'heavy' = 'medium'): Promise<void> => {
|
|
try {
|
|
const styleMap = {
|
|
light: ImpactStyle.Light,
|
|
medium: ImpactStyle.Medium,
|
|
heavy: ImpactStyle.Heavy
|
|
};
|
|
await Haptics.impact({ style: styleMap[style] });
|
|
} catch (error) {
|
|
console.error('Haptics error:', error);
|
|
}
|
|
};
|
|
|
|
return {
|
|
takePhoto,
|
|
pickPhoto,
|
|
saveFile,
|
|
readFile,
|
|
pickFile,
|
|
shareText,
|
|
shareUrl,
|
|
requestNotificationPermission,
|
|
sendLocalNotification,
|
|
getCurrentLocation,
|
|
watchLocation,
|
|
networkStatus,
|
|
copyToClipboard,
|
|
pasteFromClipboard,
|
|
lockOrientation,
|
|
unlockOrientation,
|
|
openInBrowser,
|
|
showToast,
|
|
vibrate
|
|
};
|
|
}
|