diff --git a/.gitea/workflows/windows.yaml b/.gitea/workflows/windows.yaml
index cc000e5..e4095df 100644
--- a/.gitea/workflows/windows.yaml
+++ b/.gitea/workflows/windows.yaml
@@ -10,8 +10,6 @@ on:
paths:
- 'lib/**'
-
-
jobs:
build:
runs-on: windows-latest
diff --git a/app/components/DialogsList/DialogsList.tsx b/app/components/DialogsList/DialogsList.tsx
index 275a1bc..97c8ab2 100644
--- a/app/components/DialogsList/DialogsList.tsx
+++ b/app/components/DialogsList/DialogsList.tsx
@@ -4,7 +4,7 @@ import animationData from './lottie.json';
import { Box, Flex, Skeleton, Text } from "@mantine/core";
import { useDialogsList } from "@/app/providers/DialogListProvider/useDialogsList";
import { GroupDialog } from "../GroupDialog/GroupDialog";
-import React from "react";
+import { AnimatePresence, motion } from "framer-motion";
interface DialogsListProps {
mode: 'all' | 'requests';
@@ -13,6 +13,7 @@ interface DialogsListProps {
export function DialogsList(props : DialogsListProps) {
const {dialogs, loadingDialogs} = useDialogsList();
+ const filteredDialogs = dialogs.filter(v => (v.is_request == (props.mode == 'requests')));
return (
<>
@@ -36,21 +37,30 @@ export function DialogsList(props : DialogsListProps) {
))}
>
)}
- {loadingDialogs === 0 && dialogs.filter(v => (v.is_request == (props.mode == 'requests'))).map((dialog) => (
-
- {dialog.dialog_id.startsWith('#group:') ? (
-
- ) : (
-
- )}
-
- ))}
+
+
+ {loadingDialogs === 0 && filteredDialogs.map((dialog) => (
+
+ {dialog.dialog_id.startsWith('#group:') ? (
+
+ ) : (
+
+ )}
+
+ ))}
+
+
>
);
}
\ No newline at end of file
diff --git a/app/components/DialogsPanelHeader/DialogsPanelHeader.tsx b/app/components/DialogsPanelHeader/DialogsPanelHeader.tsx
index 04553c9..963aa26 100644
--- a/app/components/DialogsPanelHeader/DialogsPanelHeader.tsx
+++ b/app/components/DialogsPanelHeader/DialogsPanelHeader.tsx
@@ -7,14 +7,16 @@ import { useHotkeys } from "@mantine/hooks";
import { useNavigate } from "react-router-dom";
import { usePublicKey } from "@/app/providers/AccountProvider/usePublicKey";
import { DialogHeaderText } from "../DialogHeaderText/DialogHeaderText";
+import { useCoreDevice } from "@/app/providers/DeviceProvider/useCoreDevice";
export function DialogsPanelHeader() {
const colors = useRosettaColors();
const logout = useLogout();
const navigate = useNavigate();
const publicKey = usePublicKey();
- const viewKeys = window.platform == 'darwin' ? '⌘' : 'Ctrl+';
- const triggerKeys = window.platform == 'darwin' ? 'mod' : 'Ctrl';
+ const {platform} = useCoreDevice();
+ const viewKeys = platform == 'darwin' ? '⌘' : 'Ctrl+';
+ const triggerKeys = platform == 'darwin' ? 'mod' : 'Ctrl';
useHotkeys([
[`${triggerKeys}+L`, () => logout()],
diff --git a/app/components/MessageAttachments/MessageAttachments.tsx b/app/components/MessageAttachments/MessageAttachments.tsx
index 44c7714..6446d1e 100644
--- a/app/components/MessageAttachments/MessageAttachments.tsx
+++ b/app/components/MessageAttachments/MessageAttachments.tsx
@@ -42,6 +42,7 @@ export function MessageAttachments(props: MessageAttachmentsProps) {
text: props.text,
parent: props.parent,
}
+ console.info("Rendering attachment", attachProps);
switch (att.type) {
case AttachmentType.MESSAGES:
return
diff --git a/app/components/MessageAttachments/MessageAvatar.tsx b/app/components/MessageAttachments/MessageAvatar.tsx
index 99b1e01..561cb21 100644
--- a/app/components/MessageAttachments/MessageAvatar.tsx
+++ b/app/components/MessageAttachments/MessageAvatar.tsx
@@ -19,7 +19,7 @@ export function MessageAvatar(props: AttachmentProps) {
download,
downloadStatus,
getBlob,
- getPreview} = useAttachment(props.attachment, props.chacha_key_plain);
+ getPreview} = useAttachment(props.attachment, props.parent);
const mainRef = useRef(null);
const { open } = useImageViewer();
const preview = getPreview();
diff --git a/app/components/MessageAttachments/MessageFile.tsx b/app/components/MessageAttachments/MessageFile.tsx
index fb4e26f..e17a5d6 100644
--- a/app/components/MessageAttachments/MessageFile.tsx
+++ b/app/components/MessageAttachments/MessageFile.tsx
@@ -6,6 +6,7 @@ import { IconArrowDown, IconFile, IconX } from "@tabler/icons-react";
import { dotCenterIfNeeded, humanFilesize } from "@/app/utils/utils";
import { AnimatedRoundedProgress } from "../AnimatedRoundedProgress/AnimatedRoundedProgress";
import { DeliveredMessageState } from "@/app/providers/DialogProvider/DialogProvider";
+import { useCore } from "@/app/hooks/useCore";
export function MessageFile(props : AttachmentProps) {
const colors = useRosettaColors();
@@ -18,7 +19,7 @@ export function MessageFile(props : AttachmentProps) {
} =
useAttachment(
props.attachment,
- props.chacha_key_plain,
+ props.parent,
);
const preview = getPreview();
const error = downloadStatus == DownloadStatus.ERROR;
@@ -27,15 +28,15 @@ export function MessageFile(props : AttachmentProps) {
const filetype = filename.split(".")[filename.split(".").length - 1];
const isEncrypting = props.delivered == DeliveredMessageState.WAITING && uploadedPercentage <= 0;
const isUploading = props.delivered == DeliveredMessageState.WAITING && uploadedPercentage > 0 && uploadedPercentage < 100;
+ const {getDownloadsPath} = useCore();
const onClick = async () => {
if(downloadStatus == DownloadStatus.ERROR){
return;
}
if(downloadStatus == DownloadStatus.DOWNLOADED){
- //let content = await getBlob();
- //let buffer = Buffer.from(content.split(",")[1], 'base64');
- let pathInDownloads = window.downloadsPath + "/Rosetta Downloads/" + filename;
+ const downloadsPath = await getDownloadsPath();
+ let pathInDownloads = downloadsPath + "/Rosetta Downloads/" + filename;
//await writeFile(pathInDownloads, buffer, false);
window.shell.showItemInFolder(pathInDownloads);
return;
diff --git a/app/components/MessageAttachments/MessageImage.tsx b/app/components/MessageAttachments/MessageImage.tsx
index 77f8ef2..695fa7d 100644
--- a/app/components/MessageAttachments/MessageImage.tsx
+++ b/app/components/MessageAttachments/MessageImage.tsx
@@ -19,7 +19,7 @@ export function MessageImage(props: AttachmentProps) {
download,
downloadStatus,
getBlob,
- getPreview } = useAttachment(props.attachment, props.chacha_key_plain);
+ getPreview } = useAttachment(props.attachment, props.parent);
const mainRef = useRef(null);
const error = downloadStatus == DownloadStatus.ERROR;
const { open } = useImageViewer();
@@ -29,6 +29,7 @@ export function MessageImage(props: AttachmentProps) {
const [blurhashPreview, setBlurhashPreview] = useState("");
useEffect(() => {
+ console.info("Consturcting image, download status: " + downloadStatus);
constructBlob();
constructFromBlurhash();
}, [downloadStatus]);
diff --git a/app/components/Messages/Messages.tsx b/app/components/Messages/Messages.tsx
index e08df20..970a9b3 100644
--- a/app/components/Messages/Messages.tsx
+++ b/app/components/Messages/Messages.tsx
@@ -21,6 +21,7 @@ export function Messages() {
const isFirstRenderRef = useRef(true);
const previousScrollHeightRef = useRef(0);
const distanceFromButtomRef = useRef(0);
+ const distanceFromTopRef = useRef(0);
const [affix, setAffix] = useState(false);
const [wallpaper] = useSetting
@@ -120,7 +121,8 @@ export function Messages() {
const lastMessage = messages[messages.length - 1];
// Скроллим если пользователь внизу или это его собственное сообщение
- if ((shouldAutoScrollRef.current || lastMessage.from_me)) {
+ if ((shouldAutoScrollRef.current || lastMessage.from_me) && distanceFromTopRef.current > 10) {
+ console.info(distanceFromTopRef.current);
scrollToBottom(true);
}
}, [messages.length, loading, scrollToBottom]);
@@ -175,6 +177,8 @@ export function Messages() {
onScrollPositionChange={(scroll) => {
if (!viewportRef.current) return;
+ distanceFromTopRef.current = scroll.y;
+
// Загружаем старые сообщения при достижении верха
if (scroll.y === 0 && !loading && messages.length >= 20) {
loadMessagesToScrollAreaTop();
diff --git a/app/components/Topbar/Topbar.tsx b/app/components/Topbar/Topbar.tsx
index 63590f9..c4006bf 100644
--- a/app/components/Topbar/Topbar.tsx
+++ b/app/components/Topbar/Topbar.tsx
@@ -5,17 +5,19 @@ import { useProtocolState } from "@/app/providers/ProtocolProvider/useProtocolSt
import { ProtocolState } from "@/app/providers/ProtocolProvider/ProtocolProvider";
import { WindowsFrameButtons } from "../WindowsFrameButtons/WindowsFrameButtons";
import { MacFrameButtons } from "../MacFrameButtons/MacFrameButtons";
+import { useCoreDevice } from "@/app/providers/DeviceProvider/useCoreDevice";
export function Topbar() {
const colors = useRosettaColors();
const [protocolState] = useProtocolState();
+ const {platform} = useCoreDevice();
return (
- {window.platform == 'win32' && }
- {window.platform == 'darwin' && }
- {window.platform == 'linux' && }
+ {platform == 'win32' && }
+ {platform == 'darwin' && }
+ {platform == 'linux' && }
{(protocolState == ProtocolState.CONNECTED || protocolState == ProtocolState.SYNCHRONIZATION || !window.location.hash.includes("main")) &&
diff --git a/app/constants.ts b/app/constants.ts
index 6e96d3c..bba5292 100644
--- a/app/constants.ts
+++ b/app/constants.ts
@@ -1,13 +1,7 @@
import { AttachmentType } from "./providers/ProtocolProvider/protocol/packets/packet.message";
-
-export const CORE_VERSION = window.version || "1.0.0";
-
/**
* Application directives
*/
-export const APPLICATION_PLATFROM = window.platform || "unknown";
-export const APPLICATION_ARCH = window.arch || "unknown";
-export const APP_PATH = window.appPath || ".";
export const SIZE_LOGIN_WIDTH_PX = 300;
export const DEVTOOLS_CHEATCODE = "rosettadev1";
export const AVATAR_PASSWORD_TO_ENCODE = "rosetta-a";
@@ -62,5 +56,6 @@ export const ALLOWED_DOMAINS_ZONES = [
'gg',
'fm',
'tv',
- 'im'
+ 'im',
+ 'sc'
];
\ No newline at end of file
diff --git a/app/hooks/useCore.ts b/app/hooks/useCore.ts
new file mode 100644
index 0000000..6f6f470
--- /dev/null
+++ b/app/hooks/useCore.ts
@@ -0,0 +1,62 @@
+export function useCore() {
+ const openExternal = (url: string) => {
+ window.shell.openExternal(url);
+ };
+
+ const showItemInFolder = (fullPath: string) => {
+ window.shell.showItemInFolder(fullPath);
+ };
+
+ const getCoreVersion = async () => {
+ const version = await window.electron.ipcRenderer.invoke('ipcCore:getCoreVersion');
+ return version;
+ }
+
+ const getArch = async () => {
+ const arch = await window.electron.ipcRenderer.invoke('ipcCore:getArch');
+ return arch;
+ }
+
+ const getUserDir = async () => {
+ const userDir = await window.electron.ipcRenderer.invoke('ipcCore:getUserDir');
+ return userDir;
+ }
+
+ const getAppPath = async () => {
+ const appPath = await window.electron.ipcRenderer.invoke('ipcCore:getAppPath');
+ return appPath;
+ }
+
+ const getDownloadsPath = async () => {
+ const downloadsPath = await window.electron.ipcRenderer.invoke('ipcCore:getDownloadsPath');
+ return downloadsPath;
+ }
+
+ const getPlatform = async () => {
+ const platform = await window.electron.ipcRenderer.invoke('ipcCore:getPlatform');
+ return platform;
+ }
+
+ const getDeviceName = async () => {
+ const deviceName = await window.electron.ipcRenderer.invoke('device:name');
+ return deviceName;
+ }
+
+ const getDeviceId = async () => {
+ const deviceId = await window.electron.ipcRenderer.invoke('device:id');
+ return deviceId;
+ }
+
+ return {
+ openExternal,
+ showItemInFolder,
+ getCoreVersion,
+ getArch,
+ getUserDir,
+ getAppPath,
+ getDownloadsPath,
+ getPlatform,
+ getDeviceName,
+ getDeviceId
+ }
+}
\ No newline at end of file
diff --git a/app/hooks/useSetup.ts b/app/hooks/useSetup.ts
deleted file mode 100644
index e69de29..0000000
diff --git a/app/providers/AttachmentProvider/useAttachment.ts b/app/providers/AttachmentProvider/useAttachment.ts
index d153d60..d5d88d2 100644
--- a/app/providers/AttachmentProvider/useAttachment.ts
+++ b/app/providers/AttachmentProvider/useAttachment.ts
@@ -1,4 +1,4 @@
-import { useContext, useEffect, useState } from "react";
+import { useEffect, useState } from "react";
import { useDownloadStatus } from "../TransportProvider/useDownloadStatus";
import { useUploadStatus } from "../TransportProvider/useUploadStatus";
import { useFileStorage } from "../../hooks/useFileStorage";
@@ -10,10 +10,11 @@ import { useDialogsCache } from "../DialogProvider/useDialogsCache";
import { useConsoleLogger } from "../../hooks/useConsoleLogger";
import { Attachment, AttachmentType } from "../ProtocolProvider/protocol/packets/packet.message";
import { useMemory } from "../MemoryProvider/useMemory";
-import { DialogContext } from "../DialogProvider/DialogProvider";
import { useSaveAvatar } from "../AvatarProvider/useSaveAvatar";
import { AVATAR_PASSWORD_TO_ENCODE } from "@/app/constants";
import { useDialog } from "../DialogProvider/useDialog";
+import { useCore } from "@/app/hooks/useCore";
+import { MessageProps } from "@/app/components/Messages/Message";
export enum DownloadStatus {
DOWNLOADED,
@@ -24,7 +25,7 @@ export enum DownloadStatus {
ERROR
}
-export function useAttachment(attachment: Attachment, keyPlain: string) {
+export function useAttachment(attachment: Attachment, parentMessage: MessageProps) {
const uuidRegex = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
const uploadedPercentage = useUploadStatus(attachment.id);
const downloadPercentage = useDownloadStatus(attachment.id);
@@ -37,13 +38,8 @@ export function useAttachment(attachment: Attachment, keyPlain: string) {
const {updateAttachmentInDialogCache} = useDialogsCache();
const {info} = useConsoleLogger('useAttachment');
const {updateAttachmentsInMessagesByAttachmentId} = useDialog();
-
+ const {getDownloadsPath} = useCore();
- const context = useContext(DialogContext);
- if(!context) {
- throw new Error("useAttachment must be used within a DialogProvider");
- }
- const {dialog} = context;
const saveAvatar = useSaveAvatar();
useEffect(() => {
@@ -85,7 +81,8 @@ export function useAttachment(attachment: Attachment, keyPlain: string) {
const preview = getPreview();
const filesize = parseInt(preview.split("::")[0]);
const filename = preview.split("::")[1];
- let pathInDownloads = window.downloadsPath + "/Rosetta Downloads/" + filename;
+ const downloadsPath = await getDownloadsPath();
+ let pathInDownloads = downloadsPath + "/Rosetta Downloads/" + filename;
const exists = await fileExists(pathInDownloads, false);
const existsLength = await size(pathInDownloads, false);
if(exists && existsLength == filesize){
@@ -152,7 +149,7 @@ export function useAttachment(attachment: Attachment, keyPlain: string) {
}
setDownloadStatus(DownloadStatus.DECRYPTING);
//console.info("Decrypted attachment ", Buffer.from(keyPlain, 'binary').toString('hex'));
- const decrypted = await decodeWithPassword(keyPlain, downloadedBlob);
+ const decrypted = await decodeWithPassword(parentMessage.chacha_key_plain, downloadedBlob);
setDownloadTag("");
if(attachment.type == AttachmentType.FILE) {
/**
@@ -161,8 +158,9 @@ export function useAttachment(attachment: Attachment, keyPlain: string) {
*/
const preview = getPreview();
const filename = preview.split("::")[1];
+ const downloadsPath = await getDownloadsPath();
let buffer = Buffer.from(decrypted.split(",")[1], 'base64');
- let pathInDownloads = window.downloadsPath + "/Rosetta Downloads/" + filename;
+ let pathInDownloads = downloadsPath + "/Rosetta Downloads/" + filename;
/**
* Пишем файл в загрузки, но перед этим выбираем ему название, если файл в загрузках
* уже есть с таким названием то добавляем к названию (1), (2) и так далее, чтобы не перезаписать существующий файл
@@ -170,7 +168,7 @@ export function useAttachment(attachment: Attachment, keyPlain: string) {
let finalPath = pathInDownloads;
let fileIndex = 1;
while (await fileExists(finalPath, false)) {
- finalPath = window.downloadsPath + "/Rosetta Downloads/" + filename.split(".").slice(0, -1).join(".") + ` (${fileIndex})` + "." + filename.split(".").slice(-1);
+ finalPath = downloadsPath + "/Rosetta Downloads/" + filename.split(".").slice(0, -1).join(".") + ` (${fileIndex})` + "." + filename.split(".").slice(-1);
fileIndex++;
}
await writeFile(finalPath, buffer, false);
@@ -185,7 +183,10 @@ export function useAttachment(attachment: Attachment, keyPlain: string) {
await writeFile(avatarPath,
Buffer.from(await encodeWithPassword(AVATAR_PASSWORD_TO_ENCODE, decrypted)));
setDownloadStatus(DownloadStatus.DOWNLOADED);
- saveAvatar(dialog, avatarPath, decrypted);
+ /**
+ * Устанавливаем аватарку тому, кто ее прислал.
+ */
+ saveAvatar(parentMessage.from, avatarPath, decrypted);
return;
}
/**
diff --git a/app/providers/AvatarProvider/AvatarProvider.tsx b/app/providers/AvatarProvider/AvatarProvider.tsx
index 0ef4274..ba8b5e4 100644
--- a/app/providers/AvatarProvider/AvatarProvider.tsx
+++ b/app/providers/AvatarProvider/AvatarProvider.tsx
@@ -7,7 +7,15 @@ import { useConsoleLogger } from "@/app/hooks/useConsoleLogger";
import { useSystemAccounts } from "../SystemAccountsProvider/useSystemAccounts";
import { AVATAR_PASSWORD_TO_ENCODE } from "@/app/constants";
-export const AvatarContext = createContext({});
+export interface AvatarProviderContextValue {
+ deliveredAvatars: string[];
+ saveAvatar: (fromPublicKey: string, path : string, decryptedContent : string) => Promise;
+ loadAvatarsFromCacheByPublicKey: (publicKey : string, allDecode? : boolean) => Promise;
+ changeAvatar: (base64Image : string, entity : string) => Promise;
+ decodedAvatarsCache: AvatarCacheEntry[];
+}
+
+export const AvatarContext = createContext(null);
interface AvatarProviderProps {
children: React.ReactNode;
diff --git a/app/providers/AvatarProvider/useSaveAvatar.ts b/app/providers/AvatarProvider/useSaveAvatar.ts
index b9ba0db..1177f69 100644
--- a/app/providers/AvatarProvider/useSaveAvatar.ts
+++ b/app/providers/AvatarProvider/useSaveAvatar.ts
@@ -1,9 +1,9 @@
import { useContext } from "react";
import { AvatarContext } from "./AvatarProvider";
-export function useSaveAvatar() {
+export function useSaveAvatar() : (fromPublicKey: string, path : string, decryptedContent : string) => Promise {
const context : any = useContext(AvatarContext);
- if(!context){
+ if(!context){
throw new Error("useSaveAvatar must be used within an AvatarProvider");
}
return context.saveAvatar;
diff --git a/app/providers/DeviceProvider/useCoreDevice.ts b/app/providers/DeviceProvider/useCoreDevice.ts
new file mode 100644
index 0000000..c57b8c2
--- /dev/null
+++ b/app/providers/DeviceProvider/useCoreDevice.ts
@@ -0,0 +1,33 @@
+import { useCore } from "@/app/hooks/useCore";
+import { useEffect, useState } from "react";
+
+export function useCoreDevice() : {
+ deviceId: string;
+ deviceName: string;
+ platform: string;
+} {
+ const { getDeviceId, getDeviceName, getPlatform } = useCore();
+ const [deviceId, setDeviceId] = useState("");
+ const [deviceName, setDeviceName] = useState("");
+ const [platform, setPlatform] = useState("");
+
+ useEffect(() => {
+ fetchDeviceInfo();
+ }, []);
+
+ const fetchDeviceInfo = async () => {
+ const deviceId = await getDeviceId();
+ const deviceName = await getDeviceName();
+ const platform = await getPlatform();
+ setDeviceId(deviceId);
+ setDeviceName(deviceName);
+ setPlatform(platform);
+ console.info("Device info - ID:", deviceId, "Name:", deviceName);
+ }
+
+ return {
+ deviceId,
+ deviceName,
+ platform
+ }
+}
\ No newline at end of file
diff --git a/app/providers/DialogProvider/DialogProvider.tsx b/app/providers/DialogProvider/DialogProvider.tsx
index d5fe8b7..38affed 100644
--- a/app/providers/DialogProvider/DialogProvider.tsx
+++ b/app/providers/DialogProvider/DialogProvider.tsx
@@ -840,10 +840,13 @@ export function DialogProvider(props: DialogProviderProps) {
});
continue;
}
- const decrypted = await decodeWithPassword(privatePlain, Buffer.from(fileData, 'binary').toString());
+ let blob = "";
+ if(meta.type != AttachmentType.IMAGE){
+ blob = await decodeWithPassword(privatePlain, Buffer.from(fileData, 'binary').toString());
+ }
attachments.push({
id: meta.id,
- blob: decrypted,
+ blob: blob,
type: meta.type,
preview: meta.preview
});
diff --git a/app/providers/DialogProvider/useDialogFiber.ts b/app/providers/DialogProvider/useDialogFiber.ts
index 4ee0a24..b3710b3 100644
--- a/app/providers/DialogProvider/useDialogFiber.ts
+++ b/app/providers/DialogProvider/useDialogFiber.ts
@@ -445,7 +445,7 @@ export function useDialogFiber() {
* чтобы когда приходит пачка сообщений с сервера в момент того как
* пользователь был неактивен, не слать уведомления по всем этим сообщениям
*/
- if (!muted.includes(fromPublicKey) || protocolState == ProtocolState.SYNCHRONIZATION) {
+ if (!muted.includes(fromPublicKey) || protocolState != ProtocolState.SYNCHRONIZATION) {
/**
* Если пользователь в муте или сейчас идет синхронизация - не отправляем уведомление
*/
diff --git a/app/providers/SystemProvider/SystemProvider.tsx b/app/providers/SystemProvider/SystemProvider.tsx
index 3ced45c..fcdc3cf 100644
--- a/app/providers/SystemProvider/SystemProvider.tsx
+++ b/app/providers/SystemProvider/SystemProvider.tsx
@@ -2,6 +2,7 @@ import { decodeWithPassword, encodeWithPassword } from "@/app/workers/crypto/cry
import { useFileStorage } from "@/app/hooks/useFileStorage";
import { generateRandomKey } from "@/app/utils/utils";
import { createContext, useEffect, useState } from "react";
+import { useCore } from "@/app/hooks/useCore";
interface SystemProviderContextValue {
id: string;
@@ -21,7 +22,10 @@ export interface SystemProviderProps {
*/
export function SystemProvider(props: SystemProviderProps) {
const [deviceId, setDeviceId] = useState("");
+ const [deviceName, setDeviceName] = useState("");
+ const [deviceOs, setDeviceOs] = useState("");
const {writeFile, readFile} = useFileStorage();
+ const { getDeviceId, getDeviceName, getPlatform } = useCore();
useEffect(() => {
fetchDeviceId();
@@ -29,6 +33,10 @@ export function SystemProvider(props: SystemProviderProps) {
const fetchDeviceId = async () => {
const device = await readFile("device");
+ const name = await getDeviceName();
+ const platform = await getPlatform();
+ setDeviceName(name);
+ setDeviceOs(platform);
if(device){
const decoded = await decodeDevice(Buffer.from(device).toString('utf-8'));
if(decoded){
@@ -47,12 +55,11 @@ export function SystemProvider(props: SystemProviderProps) {
}
const decodeDevice = async (data: string) => {
- const hwid = window.deviceId;
- const platform = window.deviceName;
+ const hwid = await getDeviceId();
+ const deviceName = await getDeviceName();
const salt = "rosetta-device-salt";
-
try {
- const decoded = await decodeWithPassword(hwid + platform + salt, data);
+ const decoded = await decodeWithPassword(hwid + deviceName + salt, data);
return decoded;
} catch (e) {
console.error("Failed to decode device data:", e);
@@ -61,29 +68,24 @@ export function SystemProvider(props: SystemProviderProps) {
}
const encodeDevice = async (data: string) => {
- const hwid = window.deviceId;
- const platform = window.deviceName;
+ const hwid = await getDeviceId();
+ const deviceName = await getDeviceName();
const salt = "rosetta-device-salt";
try {
- const encoded = await encodeWithPassword(hwid + platform + salt, data);
+ const encoded = await encodeWithPassword(hwid + deviceName + salt, data);
return encoded;
} catch (e) {
console.error("Failed to encode device data:", e);
return null;
}
}
-
- const systemName = window.deviceName || "Unknown Device";
- const systemOs = window.platform || "Unknown OS";
-
-
return (
{props.children}
diff --git a/app/providers/UpdateProvider/UpdateProvider.tsx b/app/providers/UpdateProvider/UpdateProvider.tsx
index c9b97d6..129fce0 100644
--- a/app/providers/UpdateProvider/UpdateProvider.tsx
+++ b/app/providers/UpdateProvider/UpdateProvider.tsx
@@ -4,8 +4,8 @@ import { useSender } from "../ProtocolProvider/useSender";
import { usePacket } from "../ProtocolProvider/usePacket";
import { useConsoleLogger } from "@/app/hooks/useConsoleLogger";
import { useFileStorage } from "@/app/hooks/useFileStorage";
-import { APPLICATION_ARCH, APPLICATION_PLATFROM, CORE_VERSION } from "@/app/constants";
import { APP_VERSION } from "@/app/version";
+import { useCore } from "@/app/hooks/useCore";
export interface UpdateProviderProps {
children: React.ReactNode;
@@ -58,6 +58,7 @@ export function UpdateProvider(props: UpdateProviderProps) {
const [appUpdateUrl, setAppUpdateUrl] = useState("");
const [appActualVersion, setAppActualVersion] = useState("");
const {writeFile} = useFileStorage();
+ const {getCoreVersion, getArch, getPlatform} = useCore();
useEffect(() => {
let packet = new PacketRequestUpdate();
@@ -75,6 +76,9 @@ export function UpdateProvider(props: UpdateProviderProps) {
}, []);
const checkForUpdates = async () => {
+ const coreVersion = await getCoreVersion();
+ const arch = await getArch();
+ const platform = await getPlatform();
if(updateServerRef.current == null){
/**
* SDU еще не определен
@@ -85,7 +89,7 @@ export function UpdateProvider(props: UpdateProviderProps) {
* Запрашиваем обновления с SDU сервера
*/
let response = await fetch
- (`${updateServerRef.current}/updates/get?app=${APP_VERSION}&kernel=${CORE_VERSION}&arch=${APPLICATION_ARCH}&platform=${APPLICATION_PLATFROM}`).catch((e) => {
+ (`${updateServerRef.current}/updates/get?app=${APP_VERSION}&kernel=${coreVersion}&arch=${arch}&platform=${platform}`).catch((e) => {
error("Failed to check for updates: " + e.message);
});
if(!response || response.status != 200){
diff --git a/app/version.ts b/app/version.ts
index a1b3d59..36c3ecf 100644
--- a/app/version.ts
+++ b/app/version.ts
@@ -1,15 +1,13 @@
-export const APP_VERSION = "1.0.4";
-export const CORE_MIN_REQUIRED_VERSION = "1.4.9";
+export const APP_VERSION = "1.0.5";
+export const CORE_MIN_REQUIRED_VERSION = "1.5.0";
export const RELEASE_NOTICE = `
-**Обновление v1.0.4** :emoji_1f631:
-- Улучшеный UI для взаимодействия с отправкой изображений
-- Исправлена блокировка потока при отправке изображений большого размера
-- Исправлены проблемы с утечками памяти
-- Исправлен вылет из приложения при попытке переслать сообщение
-- Исправлены проблемы со скроллам в групповых чатах
-- Исправлены проблемы с дерганием скролла в личных сообщениях
-- Улучшен наблюдатель за изменениями размера в контенте
-- Исправлена проблема с отображением аватара в упоминаниях
-- Множественные исправления мелких багов и улучшения производительности
+**Обновление v1.0.5** :emoji_1f631:
+- Оптимизирован код ядра
+- Исправление ошибки с системой обновления в результате гонки потоков в ядре
+- Исправление уведомлений при синхронизации
+- Анимация перемещения диалогов
+- Оптимизирован код вложений
+- Исправлен скролл при подгрузке сообщений сверху
+- Ускорена загрузка диалогов при большом количестве тяжелых изображений
`;
\ No newline at end of file
diff --git a/app/views/DeviceConfirm/DeviceConfirm.tsx b/app/views/DeviceConfirm/DeviceConfirm.tsx
index 3fae8f2..7c60086 100644
--- a/app/views/DeviceConfirm/DeviceConfirm.tsx
+++ b/app/views/DeviceConfirm/DeviceConfirm.tsx
@@ -10,11 +10,14 @@ import { AnimatedButton } from "@/app/components/AnimatedButton/AnimatedButton";
import { useLogout } from "@/app/providers/AccountProvider/useLogout";
import { usePacket } from "@/app/providers/ProtocolProvider/usePacket";
import { PacketDeviceResolve, Solution } from "@/app/providers/ProtocolProvider/protocol/packets/packet.device.resolve";
+import { useCoreDevice } from "@/app/providers/DeviceProvider/useCoreDevice";
export function DeviceConfirm() {
const [protocolState] = useProtocolState();
const navigate = useNavigate();
const logout = useLogout();
+ const {deviceName} = useCoreDevice();
+
useEffect(() => {
if(protocolState == ProtocolState.CONNECTED) {
@@ -60,7 +63,7 @@ export function DeviceConfirm() {
- Confirm device {window.deviceName} on your first device to loading your chats.
+ Confirm device {deviceName} on your first device to loading your chats.
diff --git a/app/views/Update/Update.tsx b/app/views/Update/Update.tsx
index 5edc24e..32a63a4 100644
--- a/app/views/Update/Update.tsx
+++ b/app/views/Update/Update.tsx
@@ -4,15 +4,26 @@ import { RosettaPower } from "@/app/components/RosettaPower/RosettaPower";
import { SettingsAlert } from "@/app/components/SettingsAlert/SettingsAlert";
import { SettingsInput } from "@/app/components/SettingsInput/SettingsInput";
import { UpdateAlert } from "@/app/components/UpdateAlert/UpdateAlert";
-import { CORE_VERSION } from "@/app/constants";
+import { useCore } from "@/app/hooks/useCore";
import { UpdateStatus } from "@/app/providers/UpdateProvider/UpdateProvider";
import { useUpdater } from "@/app/providers/UpdateProvider/useUpdater";
import { APP_VERSION } from "@/app/version";
import { Box, Text } from "@mantine/core";
+import { useEffect, useState } from "react";
export function Update() {
const {updateStatus} = useUpdater();
-
+ const {getCoreVersion} = useCore();
+ const [coreVersion, setCoreVersion] = useState("");
+
+ useEffect(() => {
+ const fetchCoreVersion = async () => {
+ const version = await getCoreVersion();
+ setCoreVersion(version);
+ }
+ fetchCoreVersion();
+ }, [getCoreVersion]);
+
return (
<>
@@ -23,7 +34,7 @@ export function Update() {
-
+
If the kernel version is outdated, you need to reinstall the application so that this kernel continues to receive current updates.
diff --git a/lib/main/app.ts b/lib/main/app.ts
index a5a5d65..04ea6eb 100644
--- a/lib/main/app.ts
+++ b/lib/main/app.ts
@@ -1,4 +1,4 @@
-import { BrowserWindow, shell, app, ipcMain, nativeTheme, screen, powerMonitor } from 'electron'
+import { BrowserWindow, shell, ipcMain, nativeTheme, screen, powerMonitor } from 'electron'
import { join } from 'path'
import fs from 'fs'
import { WORKING_DIR } from './constants';
@@ -79,11 +79,6 @@ export function foundationIpcRegistration(mainWindow: BrowserWindow) {
ipcMain.removeAllListeners("write-file");
ipcMain.removeAllListeners("read-file");
ipcMain.removeAllListeners("mkdir");
- ipcMain.removeHandler("get-core-version");
- ipcMain.removeHandler("get-arch");
- ipcMain.removeAllListeners("get-user-dir");
- ipcMain.removeHandler("get-downloads-path")
- ipcMain.removeHandler("get-app-path");
ipcMain.removeHandler('open-dev-tools');
ipcMain.removeHandler('window-state');
ipcMain.removeHandler('window-toggle');
@@ -92,14 +87,6 @@ export function foundationIpcRegistration(mainWindow: BrowserWindow) {
ipcMain.removeHandler('showItemInFolder');
ipcMain.removeHandler('openExternal');
- ipcMain.handle('showItemInFolder', (_, fullPath: string) => {
- shell.showItemInFolder(fullPath);
- });
-
- ipcMain.handle('openExternal', (_, url: string) => {
- shell.openExternal(url);
- });
-
ipcMain.handle('open-dev-tools', () => {
if (mainWindow.webContents.isDevToolsOpened()) {
return;
@@ -208,27 +195,4 @@ export function foundationIpcRegistration(mainWindow: BrowserWindow) {
mainWindow.webContents.send("mkdir-reply");
});
});
- /**
- * Change to get-core-version
- */
- ipcMain.handle("get-core-version", () => {
- return app.getVersion();
- });
-
- ipcMain.handle("get-arch", () => {
- return process.arch;
- })
-
- ipcMain.on("get-user-dir", () => {
- const userDir = app.getPath("userData");
- mainWindow.webContents.send("get-user-dir-reply", userDir);
- });
-
- ipcMain.handle("get-app-path", () => {
- return app.getAppPath();
- });
-
- ipcMain.handle("get-downloads-path", () => {
- return app.getPath("downloads");
- });
}
diff --git a/lib/main/ipcs/ipcCore.ts b/lib/main/ipcs/ipcCore.ts
new file mode 100644
index 0000000..a5bf78d
--- /dev/null
+++ b/lib/main/ipcs/ipcCore.ts
@@ -0,0 +1,34 @@
+import { app, ipcMain, shell } from "electron";
+
+ipcMain.handle("ipcCore:getCoreVersion", () => {
+ return app.getVersion();
+});
+
+ipcMain.handle("ipcCore:getArch", () => {
+ return process.arch;
+})
+
+ipcMain.handle("ipcCore:getUserDir", () => {
+ const userDir = app.getPath("userData");
+ return userDir;
+});
+
+ipcMain.handle("ipcCore:getAppPath", () => {
+ return app.getAppPath();
+});
+
+ipcMain.handle("ipcCore:getDownloadsPath", () => {
+ return app.getPath("downloads");
+});
+
+ipcMain.handle('ipcCore:showItemInFolder', (_, fullPath: string) => {
+ shell.showItemInFolder(fullPath);
+});
+
+ipcMain.handle('ipcCore:openExternal', (_, url: string) => {
+ shell.openExternal(url);
+});
+
+ipcMain.handle('ipcCore:getPlatform', () => {
+ return process.platform;
+});
\ No newline at end of file
diff --git a/lib/main/main.ts b/lib/main/main.ts
index a169a38..8a550ef 100644
--- a/lib/main/main.ts
+++ b/lib/main/main.ts
@@ -7,6 +7,7 @@ import './ipcs/ipcFilestorage'
import './ipcs/ipcUpdate'
import './ipcs/ipcNotification'
import './ipcs/ipcDevice'
+import './ipcs/ipcCore'
import { Tray } from 'electron/main'
import { join } from 'path'
import { Logger } from './logger'
diff --git a/lib/preload/preload.ts b/lib/preload/preload.ts
index 6135ec5..ce67cae 100644
--- a/lib/preload/preload.ts
+++ b/lib/preload/preload.ts
@@ -4,46 +4,25 @@ import api from './api'
const exposeContext = async () => {
- let version = await ipcRenderer.invoke("get-core-version");
- let appPath = await ipcRenderer.invoke("get-app-path");
- let arch = await ipcRenderer.invoke("get-arch");
- let deviceName = await ipcRenderer.invoke("device:name");
- let deviceId = await ipcRenderer.invoke("device:id");
-
- let downloadsPath = await ipcRenderer.invoke("get-downloads-path");
if (process.contextIsolated) {
try {
contextBridge.exposeInMainWorld('electron', electronAPI)
contextBridge.exposeInMainWorld('api', api)
- contextBridge.exposeInMainWorld('version', version);
- contextBridge.exposeInMainWorld('platform', process.platform);
- contextBridge.exposeInMainWorld('appPath', appPath);
- contextBridge.exposeInMainWorld('arch', arch);
- contextBridge.exposeInMainWorld('deviceName', deviceName);
- contextBridge.exposeInMainWorld('deviceId', deviceId);
contextBridge.exposeInMainWorld('shell', {
openExternal: (url: string) => {
- ipcRenderer.invoke('openExternal', url);
+ ipcRenderer.invoke('ipcCore:openExternal', url);
},
showItemInFolder: (fullPath: string) => {
- ipcRenderer.invoke('showItemInFolder', fullPath);
+ ipcRenderer.invoke('ipcCore:showItemInFolder', fullPath);
}
});
- contextBridge.exposeInMainWorld('downloadsPath', downloadsPath)
} catch (error) {
console.error(error)
}
} else {
window.electron = electronAPI
- window.api = api
- window.version = version;
- window.platform = process.platform;
- window.appPath = appPath;
- window.arch = arch;
+ window.api = api;
window.shell = shell;
- window.downloadsPath = downloadsPath;
- window.deviceName = deviceName;
- window.deviceId = deviceId;
}
}
diff --git a/package.json b/package.json
index cb48eb0..f080cee 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "Rosetta",
- "version": "1.4.9",
+ "version": "1.5.0",
"description": "Rosetta Messenger",
"main": "./out/main/main.js",
"license": "MIT",