'init'
This commit is contained in:
14
app/hooks/useAuth.ts
Normal file
14
app/hooks/useAuth.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
function useAuth() {
|
||||
const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
const authStatus = localStorage.getItem('auth_key');
|
||||
setIsAuthenticated(authStatus !== '');
|
||||
}, []);
|
||||
|
||||
return isAuthenticated;
|
||||
}
|
||||
|
||||
export default useAuth;
|
||||
70
app/hooks/useConsoleLogger.ts
Normal file
70
app/hooks/useConsoleLogger.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import { usePrivateKeyHash } from "../providers/AccountProvider/usePrivateKeyHash";
|
||||
import { usePrivatePlain } from "../providers/AccountProvider/usePrivatePlain";
|
||||
import { usePublicKey } from "../providers/AccountProvider/usePublicKey";
|
||||
|
||||
export enum ConsoleLogLevel {
|
||||
INFO = "INFO",
|
||||
ERROR = "ERROR",
|
||||
WARN = "WARN"
|
||||
}
|
||||
|
||||
export function useConsoleLogger(component: string) {
|
||||
const privatePlain = usePrivatePlain();
|
||||
const publicKey = usePublicKey();
|
||||
const privateKey = usePrivateKeyHash();
|
||||
|
||||
const constructTechnicalDetails = () => {
|
||||
let time = new Date().toISOString();
|
||||
//console.groupCollapsed('Details');
|
||||
console.log('%cPublic Key: %c%s', 'color: orange; font-weight: bold;', 'color: white;', publicKey.trim() != "" ? publicKey : '[EMPTY]');
|
||||
console.log('%cPrivate Key Hash: %c%s', 'color: orange; font-weight: bold;', 'color: white;', privateKey.trim() != "" ? privateKey : '[EMPTY]');
|
||||
console.log('%cPrivate Plain: %c%s', 'color: orange; font-weight: bold;', 'color: white;', privatePlain.trim() != "" ? privatePlain : '[EMPTY]');
|
||||
//console.groupEnd();
|
||||
//console.groupCollapsed('Trace');
|
||||
console.info('%cTime: %c%s', 'color: green; font-weight: bold;', 'color: white;', time);
|
||||
console.info('%cComponent:%c %s', 'color: red; font-weight: bold;', 'color: #7CFC00; font-weight: bold;', component);
|
||||
console.trace('%cStack trace:', 'color: purple; font-weight: bold;');
|
||||
//console.groupEnd();
|
||||
}
|
||||
|
||||
const constructLogLevelColor = (logLevel : ConsoleLogLevel) => {
|
||||
switch(logLevel){
|
||||
case ConsoleLogLevel.INFO:
|
||||
return 'color: white; background-color: #00B5FF;';
|
||||
case ConsoleLogLevel.ERROR:
|
||||
return 'color: white; background-color: red;';
|
||||
case ConsoleLogLevel.WARN:
|
||||
return 'color: black; background-color: yellow;';
|
||||
default:
|
||||
return 'color: black; background-color: white;';
|
||||
}
|
||||
}
|
||||
|
||||
const constructMessageDetails = (message: string, logLevel : ConsoleLogLevel) => {
|
||||
return [
|
||||
`%c ${logLevel} %c ${message}`,
|
||||
constructLogLevelColor(logLevel),
|
||||
'color: #fefefe; font-weight: normal;'
|
||||
];
|
||||
}
|
||||
|
||||
const error = (message : string) => {
|
||||
console.groupCollapsed(...constructMessageDetails(message, ConsoleLogLevel.ERROR));
|
||||
constructTechnicalDetails();
|
||||
console.groupEnd();
|
||||
}
|
||||
|
||||
const info = (message : string) => {
|
||||
console.groupCollapsed(...constructMessageDetails(message, ConsoleLogLevel.INFO));
|
||||
constructTechnicalDetails();
|
||||
console.groupEnd();
|
||||
}
|
||||
|
||||
const warn = (message : string) => {
|
||||
console.groupCollapsed(...constructMessageDetails(message, ConsoleLogLevel.WARN));
|
||||
constructTechnicalDetails();
|
||||
console.groupEnd();
|
||||
}
|
||||
|
||||
return {error, info, warn};
|
||||
}
|
||||
60
app/hooks/useDialogContextMenu.tsx
Normal file
60
app/hooks/useDialogContextMenu.tsx
Normal file
@@ -0,0 +1,60 @@
|
||||
import { IconBell, IconBellOff, IconPin, IconPinnedOff } from "@tabler/icons-react";
|
||||
import { useContextMenu } from "../providers/ContextMenuProvider/useContextMenu"
|
||||
import { useRosettaColors } from "./useRosettaColors";
|
||||
import { useDialogState } from "../providers/DialogStateProvider.tsx/useDialogState";
|
||||
|
||||
export function useDialogContextMenu() : {
|
||||
openContextMenu: (dialog_id: string) => void;
|
||||
} {
|
||||
const openContext = useContextMenu();
|
||||
const colors = useRosettaColors();
|
||||
const {muted, pinned, muteToggle, pinToggle} = useDialogState();
|
||||
|
||||
const openContextMenu = (dialog_id: string) => {
|
||||
openContext([
|
||||
{
|
||||
label: 'Unmute',
|
||||
action: () => {
|
||||
muteToggle(dialog_id);
|
||||
},
|
||||
icon: <IconBell color={colors.success} size={14}></IconBell>,
|
||||
cond: async () => {
|
||||
return muted.includes(dialog_id) === true;
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Mute',
|
||||
action: () => {
|
||||
muteToggle(dialog_id);
|
||||
},
|
||||
icon: <IconBellOff color={colors.error} size={14}></IconBellOff>,
|
||||
cond: async () => {
|
||||
return muted.includes(dialog_id) === false;
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Pin',
|
||||
action: () => {
|
||||
pinToggle(dialog_id);
|
||||
},
|
||||
icon: <IconPin color={colors.success} size={14}></IconPin>,
|
||||
cond: async () => {
|
||||
return pinned.includes(dialog_id) === false;
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Unpin',
|
||||
action: () => {
|
||||
pinToggle(dialog_id);
|
||||
},
|
||||
icon: <IconPinnedOff color={colors.error} size={14}></IconPinnedOff>,
|
||||
cond: async () => {
|
||||
return pinned.includes(dialog_id) === true;
|
||||
}
|
||||
}
|
||||
], true, true);
|
||||
}
|
||||
return {
|
||||
openContextMenu
|
||||
}
|
||||
}
|
||||
13
app/hooks/useFileStorage.ts
Normal file
13
app/hooks/useFileStorage.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
export function useFileStorage() {
|
||||
const writeFile = async (file: string, data : string | Buffer, inWorkingDir : boolean = true) => {
|
||||
const result = await window.electron.ipcRenderer.invoke('fileStorage:writeFile', file, data, inWorkingDir);
|
||||
return result;
|
||||
}
|
||||
|
||||
const readFile = async (file : string, inWorkingDir : boolean = true) => {
|
||||
const result = await window.electron.ipcRenderer.invoke('fileStorage:readFile', file, inWorkingDir);
|
||||
return result;
|
||||
}
|
||||
|
||||
return {writeFile, readFile};
|
||||
}
|
||||
15
app/hooks/useLogger.ts
Normal file
15
app/hooks/useLogger.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { usePublicKey } from "../providers/AccountProvider/usePublicKey";
|
||||
import { useUserCache } from "../providers/InformationProvider/useUserCache";
|
||||
|
||||
export function useLogger(view : string = 'general') {
|
||||
const publicKey = usePublicKey();
|
||||
const userInfo = useUserCache(publicKey);
|
||||
|
||||
const logFunction = (message : string) => {
|
||||
const publicTrimmed = publicKey.substring(0, 10) + '...' + publicKey.substring(publicKey.length - 10);
|
||||
const logString = `${userInfo ? `[${userInfo.title}]` : `[unknown]`} [${publicTrimmed}] [${view}] [${new Date().toISOString()}] ${message}`;
|
||||
window.electron.ipcRenderer.invoke('logger:log', logString);
|
||||
}
|
||||
|
||||
return logFunction;
|
||||
}
|
||||
8
app/hooks/useMainColor.ts
Normal file
8
app/hooks/useMainColor.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { useMantineTheme } from "@mantine/core";
|
||||
import { useColorScheme } from "@mantine/hooks";
|
||||
|
||||
export function useMainColor () {
|
||||
const colorScheme = useColorScheme();
|
||||
const theme = useMantineTheme();
|
||||
return colorScheme == "light" ? theme.colors.gray[1] : theme.colors.dark[8];
|
||||
}
|
||||
7
app/hooks/useNotification.ts
Normal file
7
app/hooks/useNotification.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export function useNotification() {
|
||||
const show = (title : string, body : string) => {
|
||||
window.electron.ipcRenderer.invoke('notification:show', title, body);
|
||||
}
|
||||
|
||||
return show;
|
||||
}
|
||||
27
app/hooks/useQueue.ts
Normal file
27
app/hooks/useQueue.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { useRef } from "react";
|
||||
|
||||
/**
|
||||
* Нужно, чтобы избежать состояния гонки
|
||||
*/
|
||||
export function useQueue<T>() {
|
||||
const queue = useRef<T[]>([]);
|
||||
|
||||
const inProcess = (task: T): boolean => {
|
||||
return queue.current.includes(task);
|
||||
}
|
||||
|
||||
const addToQueue = (task: T) => {
|
||||
queue.current.push(task);
|
||||
}
|
||||
|
||||
const removeFromQueue = (task: T) => {
|
||||
queue.current = queue.current.filter(t => t !== task);
|
||||
}
|
||||
|
||||
return {
|
||||
inProcess,
|
||||
addToQueue,
|
||||
removeFromQueue,
|
||||
queue
|
||||
}
|
||||
}
|
||||
8
app/hooks/useRosettaBreakpoints.ts
Normal file
8
app/hooks/useRosettaBreakpoints.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { useMediaQuery } from "@mantine/hooks";
|
||||
|
||||
export function useRosettaBreakpoints() {
|
||||
return {
|
||||
lg: useMediaQuery('(min-width: 775px)'),
|
||||
md: useMediaQuery('(min-width: 490px)')
|
||||
}
|
||||
}
|
||||
20
app/hooks/useRosettaColors.ts
Normal file
20
app/hooks/useRosettaColors.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { useComputedColorScheme, useMantineTheme } from "@mantine/core";
|
||||
|
||||
export function useRosettaColors () {
|
||||
const colorScheme = useComputedColorScheme();
|
||||
const theme = useMantineTheme();
|
||||
|
||||
return {
|
||||
boxColor: colorScheme == 'light' ? theme.white : theme.colors.dark[7],
|
||||
mainColor: colorScheme == 'light' ? theme.colors.gray[1] : theme.colors.dark[8],
|
||||
borderColor: colorScheme == 'light' ? theme.colors.gray[2] : theme.colors.dark[6],
|
||||
chevrons: {
|
||||
active: colorScheme == 'light' ? theme.colors.gray[6] : theme.colors.dark[2],
|
||||
disabled: colorScheme == 'light' ? theme.colors.gray[3] : theme.colors.dark[6]
|
||||
},
|
||||
success: theme.colors.green[5],
|
||||
error: theme.colors.red[5],
|
||||
brandColor: theme.colors.blue[6],
|
||||
warning: theme.colors.orange[5]
|
||||
};
|
||||
}
|
||||
0
app/hooks/useSetup.ts
Normal file
0
app/hooks/useSetup.ts
Normal file
124
app/hooks/useUpdater.ts
Normal file
124
app/hooks/useUpdater.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { PacketRequestUpdate } from "../providers/ProtocolProvider/protocol/packets/packet.requestupdate";
|
||||
import { APPLICATION_ARCH, APPLICATION_PLATFROM, CORE_VERSION } from "../constants";
|
||||
import { PacketKernelUpdate } from "../providers/ProtocolProvider/protocol/packets/packet.kernelupdate";
|
||||
import { usePacket } from "../providers/ProtocolProvider/usePacket";
|
||||
import { PacketAppUpdate } from "../providers/ProtocolProvider/protocol/packets/packet.appupdate";
|
||||
import { compareVersions } from "../utils/update";
|
||||
import { useSender } from "../providers/ProtocolProvider/useSender";
|
||||
import { useConsoleLogger } from "./useConsoleLogger";
|
||||
import { useFileStorage } from "./useFileStorage";
|
||||
import { APP_VERSION } from "../version";
|
||||
import { useMemory } from "../providers/MemoryProvider/useMemory";
|
||||
|
||||
export enum UpdateStatus {
|
||||
IDLE,
|
||||
DOWNLOADING,
|
||||
COMPILE,
|
||||
READY_FOR_RESTART
|
||||
}
|
||||
|
||||
export function useUpdater() {
|
||||
const send = useSender();
|
||||
const [kernelOutdatedForNextAppUpdates,
|
||||
setKernelOutdatedForNextAppUpdates] = useState(false);
|
||||
const [kernelUpdateUrl, setKernelUpdateUrl] = useState("");
|
||||
const [appUpdateUrl, setAppUpdateUrl] = useState("");
|
||||
const [appActualVersion, setAppActualVersion] = useState("");
|
||||
const [kernelActualVersion, setKernelActualVersion] = useState("");
|
||||
const [downloadProgress, setDownloadProgress] = useMemory<number>("dp", 0, true);
|
||||
const [updateStatus, setUpdateStatus] = useMemory<UpdateStatus>("us", UpdateStatus.IDLE, true);
|
||||
const {error, info} = useConsoleLogger('useUpdater');
|
||||
const {writeFile} = useFileStorage();
|
||||
|
||||
useEffect(() => {
|
||||
let packet = new PacketRequestUpdate();
|
||||
packet.setAppVersion(APP_VERSION);
|
||||
packet.setKernelVersion(CORE_VERSION);
|
||||
packet.setArch(APPLICATION_ARCH);
|
||||
packet.setPlatform(APPLICATION_PLATFROM);
|
||||
send(packet);
|
||||
}, []);
|
||||
|
||||
usePacket(0x0D, (packet : PacketKernelUpdate) => {
|
||||
let url = packet.getUrl();
|
||||
let version = packet.getVersion();
|
||||
setKernelActualVersion(version);
|
||||
setKernelUpdateUrl(url);
|
||||
console.info("Kernel update available: ", version, url);
|
||||
}, []);
|
||||
|
||||
usePacket(0x0E, (packet : PacketAppUpdate) => {
|
||||
let url = packet.getUrl();
|
||||
let version = packet.getVersion();
|
||||
let kernelVersionRequired = packet.getKernelVersionRequired();
|
||||
if(compareVersions(CORE_VERSION, kernelVersionRequired) < 0){
|
||||
error("Kernel version is outdated. Cannot update app.");
|
||||
setKernelOutdatedForNextAppUpdates(true);
|
||||
return;
|
||||
}
|
||||
setAppActualVersion(version);
|
||||
setAppUpdateUrl(url);
|
||||
}, []);
|
||||
|
||||
const downloadLastApplicationUpdate = () => {
|
||||
if(appUpdateUrl == ""){
|
||||
return;
|
||||
}
|
||||
if(updateStatus != UpdateStatus.IDLE){
|
||||
return;
|
||||
}
|
||||
setUpdateStatus(UpdateStatus.DOWNLOADING);
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", appUpdateUrl, true);
|
||||
xhr.responseType = "blob";
|
||||
|
||||
xhr.onprogress = (event) => {
|
||||
if (event.lengthComputable) {
|
||||
const percentComplete = (event.loaded / event.total) * 100;
|
||||
setDownloadProgress(Math.round(percentComplete));
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onload = async () => {
|
||||
if (xhr.status === 200) {
|
||||
setUpdateStatus(UpdateStatus.COMPILE);
|
||||
const blob : Blob = xhr.response;
|
||||
let bundleName = `bundle ${appActualVersion}.zip`;
|
||||
await writeFile(bundleName, Buffer.from(await blob.arrayBuffer()));
|
||||
info("Update downloaded, starting compiler...");
|
||||
await window.electron.ipcRenderer.invoke('update:installServiceUpdate', bundleName);
|
||||
info("Update compiled successfully.");
|
||||
setTimeout(() => {
|
||||
setUpdateStatus(UpdateStatus.READY_FOR_RESTART);
|
||||
}, 10000);
|
||||
}
|
||||
}
|
||||
|
||||
xhr.onerror = () => {
|
||||
error("Error downloading update");
|
||||
setUpdateStatus(UpdateStatus.IDLE);
|
||||
}
|
||||
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
const restartAppForUpdateApply = () => {
|
||||
if(updateStatus != UpdateStatus.READY_FOR_RESTART){
|
||||
return;
|
||||
}
|
||||
window.electron.ipcRenderer.invoke('update:restartApp');
|
||||
}
|
||||
|
||||
return {
|
||||
appUpdateUrl,
|
||||
kernelUpdateUrl,
|
||||
appActualVersion,
|
||||
kernelActualVersion,
|
||||
kernelOutdatedForNextAppUpdates,
|
||||
downloadProgress,
|
||||
updateStatus,
|
||||
downloadLastApplicationUpdate,
|
||||
restartAppForUpdateApply
|
||||
}
|
||||
}
|
||||
13
app/hooks/useViewPanelsState.ts
Normal file
13
app/hooks/useViewPanelsState.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { useMemory } from "../providers/MemoryProvider/useMemory";
|
||||
|
||||
export enum ViewPanelsState {
|
||||
DIALOGS_PANEL_HIDE,
|
||||
DIALOGS_PANEL_SHOW,
|
||||
DIALOGS_PANEL_ONLY,
|
||||
DIALOGS_PANEL_HIDE_VIEW_RIGHT_PANEL
|
||||
}
|
||||
|
||||
export function useViewPanelsState() : [ViewPanelsState, (state: ViewPanelsState) => void] {
|
||||
const [viewState, setViewState] = useMemory<ViewPanelsState>('view_panels_state', ViewPanelsState.DIALOGS_PANEL_SHOW, true);
|
||||
return [viewState, setViewState];
|
||||
}
|
||||
30
app/hooks/useWindow.ts
Normal file
30
app/hooks/useWindow.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
// Desc: Custom hook to handle window resizing
|
||||
|
||||
export enum ElectronTheme {
|
||||
SYSTEM = 'system',
|
||||
DARK = 'dark',
|
||||
LIGHT = 'light'
|
||||
}
|
||||
|
||||
const useWindow = () => {
|
||||
|
||||
const setSize = (width : number, height : number) => {
|
||||
window.api.send('window-resize', { width: width, height: height });
|
||||
}
|
||||
|
||||
const setResizeble = (isResizeble : boolean) => {
|
||||
window.api.send('window-resizeble', isResizeble);
|
||||
}
|
||||
|
||||
const setTheme = (theme : ElectronTheme) => {
|
||||
window.api.send('window-theme', theme);
|
||||
}
|
||||
|
||||
return {
|
||||
setSize,
|
||||
setResizeble,
|
||||
setTheme
|
||||
}
|
||||
}
|
||||
|
||||
export default useWindow;
|
||||
22
app/hooks/useWindowActions.ts
Normal file
22
app/hooks/useWindowActions.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
export function useWindowActions() {
|
||||
const toggle = () => {
|
||||
console.info("TOGGLE");
|
||||
window.electron.ipcRenderer.invoke('window-toggle');
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
console.info("CLOSE");
|
||||
window.electron.ipcRenderer.invoke('window-close');
|
||||
}
|
||||
|
||||
const minimize = () => {
|
||||
console.info("MINIMIZE");
|
||||
window.electron.ipcRenderer.invoke('window-minimize');
|
||||
}
|
||||
|
||||
return {
|
||||
toggle,
|
||||
minimize,
|
||||
close
|
||||
}
|
||||
}
|
||||
25
app/hooks/useWindowFocus.ts
Normal file
25
app/hooks/useWindowFocus.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export function useWindowFocus() {
|
||||
const [isFocused, setIsFocused] = useState<boolean>(document.hasFocus());
|
||||
|
||||
function handleFocus() {
|
||||
setIsFocused(true);
|
||||
}
|
||||
|
||||
function handleBlur() {
|
||||
setIsFocused(false);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('focus', handleFocus);
|
||||
window.addEventListener('blur', handleBlur);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('focus', handleFocus);
|
||||
window.removeEventListener('blur', handleBlur);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return isFocused;
|
||||
}
|
||||
39
app/hooks/useWindowState.ts
Normal file
39
app/hooks/useWindowState.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
interface WindowState {
|
||||
isMinimized: boolean;
|
||||
isMaximized: boolean;
|
||||
isFullScreen: boolean;
|
||||
isVisible: boolean;
|
||||
isFocused: boolean;
|
||||
isResizable: boolean;
|
||||
isClosable: boolean;
|
||||
isDestroyed: boolean;
|
||||
bounds: any;
|
||||
}
|
||||
|
||||
export function useWindowState() : WindowState {
|
||||
const [windowState, setWindowState] = useState<WindowState>({
|
||||
isMinimized: false,
|
||||
isMaximized: false,
|
||||
isFullScreen: false,
|
||||
isVisible: false,
|
||||
isFocused: false,
|
||||
isResizable: false,
|
||||
isClosable: false,
|
||||
isDestroyed: false,
|
||||
bounds: {}
|
||||
});
|
||||
useEffect(() => {
|
||||
window.electron.ipcRenderer.on('window-state-changed', () => {
|
||||
window.electron.ipcRenderer.invoke('window-state').then((state) => {
|
||||
setWindowState(state);
|
||||
});
|
||||
});
|
||||
window.electron.ipcRenderer.invoke('window-state').then((state) => {
|
||||
setWindowState(state);
|
||||
});
|
||||
}, []);
|
||||
|
||||
return windowState;
|
||||
}
|
||||
Reference in New Issue
Block a user