batch of updates 7

This commit is contained in:
PhilReact 2024-12-30 08:13:33 +02:00
parent a4c1fd564b
commit f6cac4b91f
19 changed files with 810 additions and 415 deletions

45
package-lock.json generated
View File

@ -40,6 +40,7 @@
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"html-to-text": "^9.0.5", "html-to-text": "^9.0.5",
"jssha": "3.3.1", "jssha": "3.3.1",
"lit": "^3.2.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"mime": "^4.0.4", "mime": "^4.0.4",
"moment": "^2.30.1", "moment": "^2.30.1",
@ -1360,6 +1361,19 @@
"resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.4.0.tgz", "resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.4.0.tgz",
"integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==" "integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA=="
}, },
"node_modules/@lit-labs/ssr-dom-shim": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.2.1.tgz",
"integrity": "sha512-wx4aBmgeGvFmOKucFKY+8VFJSYZxs9poN3SDNQFF6lT6NrQUnHiPB2PWz2sc4ieEcAaYYzN+1uWahEeTq2aRIQ=="
},
"node_modules/@lit/reactive-element": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.0.4.tgz",
"integrity": "sha512-GFn91inaUa2oHLak8awSIigYz0cU0Payr1rcFsrkf5OJ5eSPxElyZfKh0f2p9FsTiZWXQdWGJeXZICEfXXYSXQ==",
"dependencies": {
"@lit-labs/ssr-dom-shim": "^1.2.0"
}
},
"node_modules/@mui/base": { "node_modules/@mui/base": {
"version": "5.0.0-beta.40", "version": "5.0.0-beta.40",
"resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.40.tgz", "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.40.tgz",
@ -2876,8 +2890,7 @@
"node_modules/@types/trusted-types": { "node_modules/@types/trusted-types": {
"version": "2.0.7", "version": "2.0.7",
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="
"dev": true
}, },
"node_modules/@types/use-sync-external-store": { "node_modules/@types/use-sync-external-store": {
"version": "0.0.6", "version": "0.0.6",
@ -6029,6 +6042,34 @@
"uc.micro": "^2.0.0" "uc.micro": "^2.0.0"
} }
}, },
"node_modules/lit": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/lit/-/lit-3.2.1.tgz",
"integrity": "sha512-1BBa1E/z0O9ye5fZprPtdqnc0BFzxIxTTOO/tQFmyC/hj1O3jL4TfmLBw0WEwjAokdLwpclkvGgDJwTIh0/22w==",
"dependencies": {
"@lit/reactive-element": "^2.0.4",
"lit-element": "^4.1.0",
"lit-html": "^3.2.0"
}
},
"node_modules/lit-element": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.1.1.tgz",
"integrity": "sha512-HO9Tkkh34QkTeUmEdNYhMT8hzLid7YlMlATSi1q4q17HE5d9mrrEHJ/o8O2D0cMi182zK1F3v7x0PWFjrhXFew==",
"dependencies": {
"@lit-labs/ssr-dom-shim": "^1.2.0",
"@lit/reactive-element": "^2.0.4",
"lit-html": "^3.2.0"
}
},
"node_modules/lit-html": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.2.1.tgz",
"integrity": "sha512-qI/3lziaPMSKsrwlxH/xMgikhQ0EGOX2ICU73Bi/YHFvz2j/yMCIrw4+puF2IpQ4+upd3EWbvnHM9+PnJn48YA==",
"dependencies": {
"@types/trusted-types": "^2.0.2"
}
},
"node_modules/local-pkg": { "node_modules/local-pkg": {
"version": "0.5.0", "version": "0.5.0",
"resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz", "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz",

View File

@ -65,6 +65,7 @@
"react-virtuoso": "^4.10.4", "react-virtuoso": "^4.10.4",
"recoil": "^0.7.7", "recoil": "^0.7.7",
"short-unique-id": "^5.2.0", "short-unique-id": "^5.2.0",
"lit": "^3.2.1",
"slate": "^0.103.0", "slate": "^0.103.0",
"slate-react": "^0.109.0", "slate-react": "^0.109.0",
"tiptap-extension-resize-image": "^1.1.8", "tiptap-extension-resize-image": "^1.1.8",

View File

@ -77,7 +77,7 @@ display: flex;
border: 1px solid var(--50-white, rgba(255, 255, 255, 0.5)); border: 1px solid var(--50-white, rgba(255, 255, 255, 0.5));
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
width: 140px; width: auto;
height: 25px; height: 25px;
padding: 5px 15px 5px 15px; padding: 5px 15px 5px 15px;
gap: 5px; gap: 5px;

View File

@ -51,6 +51,7 @@ import {
createAccount, createAccount,
generateRandomSentence, generateRandomSentence,
saveFileToDisk, saveFileToDisk,
saveSeedPhraseToDisk
} from "./utils/generateWallet/generateWallet"; } from "./utils/generateWallet/generateWallet";
import { kdf } from "./deps/kdf"; import { kdf } from "./deps/kdf";
import { generateSaveWalletData } from "./utils/generateWallet/storeWallet"; import { generateSaveWalletData } from "./utils/generateWallet/storeWallet";
@ -116,6 +117,8 @@ import { useHandleTutorials } from "./components/Tutorials/useHandleTutorials";
import { CoreSyncStatus } from "./components/CoreSyncStatus"; import { CoreSyncStatus } from "./components/CoreSyncStatus";
import BoundedNumericTextField from "./common/BoundedNumericTextField"; import BoundedNumericTextField from "./common/BoundedNumericTextField";
import { Wallets } from "./Wallets"; import { Wallets } from "./Wallets";
import './utils/seedPhrase/RandomSentenceGenerator';
import { test } from "vitest";
type extStates = type extStates =
| "not-authenticated" | "not-authenticated"
@ -323,7 +326,8 @@ function App() {
const { isShow, onCancel, onOk, show, message } = useModal(); const { isShow, onCancel, onOk, show, message } = useModal();
const { isShow: isShowUnsavedChanges, onCancel: onCancelUnsavedChanges, onOk: onOkUnsavedChanges, show: showUnsavedChanges, message: messageUnsavedChanges } = useModal(); const { isShow: isShowUnsavedChanges, onCancel: onCancelUnsavedChanges, onOk: onOkUnsavedChanges, show: showUnsavedChanges, message: messageUnsavedChanges } = useModal();
const {downloadResource} = useFetchResources() const {downloadResource} = useFetchResources()
const [showSeed, setShowSeed] = useState(false)
const [creationStep, setCreationStep] = useState(1)
const { const {
isShow: isShowInfo, isShow: isShowInfo,
onCancel: onCancelInfo, onCancel: onCancelInfo,
@ -366,6 +370,11 @@ function App() {
const [fullScreen, setFullScreen] = useRecoilState(fullScreenAtom); const [fullScreen, setFullScreen] = useRecoilState(fullScreenAtom);
const resetAtomIsUsingImportExportSettingsAtom = useResetRecoilState(isUsingImportExportSettingsAtom) const resetAtomIsUsingImportExportSettingsAtom = useResetRecoilState(isUsingImportExportSettingsAtom)
const { toggleFullScreen } = useAppFullScreen(setFullScreen); const { toggleFullScreen } = useAppFullScreen(setFullScreen);
const generatorRef = useRef(null)
const exportSeedphrase = ()=> {
const seedPhrase = generatorRef.current.parsedString
saveSeedPhraseToDisk(seedPhrase)
}
const {showTutorial, openTutorialModal, shownTutorialsInitiated, setOpenTutorialModal} = useHandleTutorials() const {showTutorial, openTutorialModal, shownTutorialsInitiated, setOpenTutorialModal} = useHandleTutorials()
const passwordRef = useRef<HTMLInputElement>(null); const passwordRef = useRef<HTMLInputElement>(null);
@ -1028,7 +1037,8 @@ function App() {
res(); res();
}, 250); }, 250);
}); });
const res = await createAccount(); const res = await createAccount(generatorRef.current.parsedString);
const wallet = await res.generateSaveWalletData( const wallet = await res.generateSaveWalletData(
walletToBeDownloadedPassword, walletToBeDownloadedPassword,
crypto.kdfThreads, crypto.kdfThreads,
@ -1102,6 +1112,8 @@ function App() {
setExtstate("authenticated"); setExtstate("authenticated");
setIsOpenSendQort(false); setIsOpenSendQort(false);
setIsOpenSendQortSuccess(false); setIsOpenSendQortSuccess(false);
setShowSeed(false)
setCreationStep(1)
}; };
const resetAllStates = () => { const resetAllStates = () => {
@ -1131,6 +1143,8 @@ function App() {
setTxList([]); setTxList([]);
setMemberGroups([]); setMemberGroups([]);
resetAllRecoil() resetAllRecoil()
setShowSeed(false)
setCreationStep(1)
}; };
function roundUpToDecimals(number, decimals = 8) { function roundUpToDecimals(number, decimals = 8) {
@ -1353,9 +1367,10 @@ function App() {
return ( return (
<AuthenticatedContainer <AuthenticatedContainer
sx={{ sx={{
width: isMobile ? "100vw" : "350px", width: isMobile ? "100vw" : "auto",
display: "flex", display: "flex",
backgroundColor: "var(--bg-2)", backgroundColor: "var(--bg-2)",
justifyContent: 'flex-end'
}} }}
> >
{isMobile && ( {isMobile && (
@ -1378,11 +1393,13 @@ function App() {
</Box> </Box>
)} )}
<AuthenticatedContainerInnerLeft {desktopViewMode !== "apps" && desktopViewMode !== "dev" && desktopViewMode !== "chat" && (
sx={{ <AuthenticatedContainerInnerLeft
overflowY: isMobile && "auto", sx={{
}} overflowY: isMobile && "auto",
> padding: '0px 20px'
}}
>
<Spacer height="48px" /> <Spacer height="48px" />
{authenticatedMode === "ltc" ? ( {authenticatedMode === "ltc" ? (
@ -1534,6 +1551,7 @@ function App() {
Get QORT at Q-Trade Get QORT at Q-Trade
</TextP> </TextP>
</AuthenticatedContainerInnerLeft> </AuthenticatedContainerInnerLeft>
)}
<AuthenticatedContainerInnerRight sx={{ <AuthenticatedContainerInnerRight sx={{
height: "100%", height: "100%",
justifyContent: "space-between", justifyContent: "space-between",
@ -1620,7 +1638,7 @@ function App() {
showTutorial('qapps', true) showTutorial('qapps', true)
} else { } else {
showTutorial('create-account', true) showTutorial('getting-started', true)
} }
}} > }} >
@ -1652,10 +1670,10 @@ function App() {
<AppContainer <AppContainer
sx={{ sx={{
height: isMobile ? "100%" : "100vh", height: isMobile ? "100%" : "100vh",
backgroundImage: desktopViewMode === 'apps' && 'url("appsBg.svg")', // backgroundImage: desktopViewMode === 'apps' && 'url("appsBg.svg")',
backgroundSize: desktopViewMode === 'apps' && 'cover', // backgroundSize: desktopViewMode === 'apps' && 'cover',
backgroundPosition: desktopViewMode === 'apps' && 'center', // backgroundPosition: desktopViewMode === 'apps' && 'center',
backgroundRepeat: desktopViewMode === 'apps' && 'no-repeat', // backgroundRepeat: desktopViewMode === 'apps' && 'no-repeat',
}} }}
> >
<GlobalContext.Provider value={{ <GlobalContext.Provider value={{
@ -1714,7 +1732,7 @@ function App() {
desktopViewMode={desktopViewMode} desktopViewMode={desktopViewMode}
setDesktopViewMode={setDesktopViewMode} setDesktopViewMode={setDesktopViewMode}
/> />
{(!isMobile && desktopViewMode !== 'apps') && renderProfile()} {!isMobile && renderProfile()}
</Box> </Box>
<Box <Box
@ -2519,7 +2537,7 @@ function App() {
)} )}
</> </>
)} )}
{extState === "create-wallet" && ( {extState === "create-wallet" && (
<> <>
{!walletToBeDownloaded && ( {!walletToBeDownloaded && (
<> <>
@ -2538,7 +2556,15 @@ function App() {
cursor: "pointer", cursor: "pointer",
}} }}
onClick={() => { onClick={() => {
if(creationStep === 2){
setCreationStep(1)
return
}
setExtstate("not-authenticated"); setExtstate("not-authenticated");
setShowSeed(false)
setCreationStep(1)
setWalletToBeDownloadedPasswordConfirm('')
setWalletToBeDownloadedPassword('')
}} }}
src={Return} src={Return}
/> />
@ -2564,6 +2590,117 @@ function App() {
Set up your Qortal account Set up your Qortal account
</TextP> </TextP>
<Spacer height="14px" /> <Spacer height="14px" />
<Box sx={{
display: 'flex',
maxWidth: '100%',
justifyContent: 'center',
padding: '10px'
}}>
<Box sx={{
display: creationStep === 1 ? 'flex' : 'none',
flexDirection: 'column',
alignItems: 'center',
width: '350px',
maxWidth: '95%'
}}>
<Typography sx={{
fontSize: '14px'
}}>
A <span onClick={()=> {
setShowSeed(true)
}} style={{
fontSize: '14px',
color: 'steelblue',
cursor: 'pointer'
}}>SEEDPHRASE</span> has been randomly generated in the background.
</Typography>
<Typography sx={{
fontSize: '14px',
marginTop: '5px'
}}>
If you wish to VIEW THE SEEDPHRASE, click the word 'SEEDPHRASE' in this text. Seedphrases are used to generate the private key for your Qortal account. For security by default, seedphrases are NOT displayed unless specifically chosen.
</Typography>
<Typography sx={{
fontSize: '16px',
marginTop: '15px',
textAlign: 'center'
}}>
Create your Qortal account by clicking <span style={{
fontWeight: 'bold'
}}>NEXT</span> below.
</Typography>
<Spacer height="17px" />
<CustomButton onClick={()=> {
setCreationStep(2)
}}>
Next
</CustomButton>
</Box>
<div style={{
display: 'none'
}}>
<random-sentence-generator
ref={generatorRef}
template="adverb verb noun adjective noun adverb verb noun adjective noun adjective verbed adjective noun"
></random-sentence-generator>
</div>
<Dialog
open={showSeed}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogContent>
<Box sx={{
flexDirection: 'column',
maxWidth: '400px',
alignItems: 'center',
gap: '10px',
display: showSeed ? 'flex' : 'none'
}}>
<Typography sx={{
fontSize: '14px'
}}>Your seedphrase</Typography>
<Box sx={{
textAlign: 'center',
width: '100%',
backgroundColor: '#1f2023',
borderRadius: '5px',
padding: '10px',
}}>
{generatorRef.current?.parsedString}
</Box>
<CustomButton sx={{
padding: '7px',
fontSize: '12px'
}} onClick={exportSeedphrase}>
Export Seedphrase
</CustomButton>
</Box>
</DialogContent>
<DialogActions>
<Button variant="contained" onClick={()=> setShowSeed(false)}>
close
</Button>
</DialogActions>
</Dialog>
</Box>
<Box sx={{
display: creationStep === 2 ? 'flex' : 'none',
flexDirection: 'column',
alignItems: 'center',
}}>
<Spacer height="14px" />
<CustomLabel htmlFor="standard-adornment-password"> <CustomLabel htmlFor="standard-adornment-password">
Wallet Password Wallet Password
</CustomLabel> </CustomLabel>
@ -2592,6 +2729,7 @@ function App() {
<CustomButton onClick={createAccountFunc}> <CustomButton onClick={createAccountFunc}>
Create Account Create Account
</CustomButton> </CustomButton>
</Box>
<ErrorText>{walletToBeDownloadedError}</ErrorText> <ErrorText>{walletToBeDownloadedError}</ErrorText>
</> </>
)} )}
@ -2611,9 +2749,12 @@ function App() {
</TextP> </TextP>
<Spacer height="100px" /> <Spacer height="100px" />
<CustomButton <CustomButton
onClick={() => { onClick={async () => {
saveFileToDiskFunc(); await saveFileToDiskFunc();
returnToMain(); returnToMain();
await showInfo({
message: `Keep your wallet file secure.`,
});
}} }}
> >
Backup Account Backup Account

View File

@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useRef, useState } from "react"; import React, { useCallback, useContext, useEffect, useRef, useState } from "react";
import { Spacer } from "../common/Spacer"; import { Spacer } from "../common/Spacer";
import { CustomButton, TextItalic, TextP, TextSpan } from "../App-styles"; import { CustomButton, TextItalic, TextP, TextSpan } from "../App-styles";
import { import {
@ -14,6 +14,7 @@ import {
Switch, Switch,
Tooltip, Tooltip,
Typography, Typography,
ButtonBase
} from "@mui/material"; } from "@mui/material";
import Logo1 from "../assets/svgs/Logo1.svg"; import Logo1 from "../assets/svgs/Logo1.svg";
import Logo1Dark from "../assets/svgs/Logo1Dark.svg"; import Logo1Dark from "../assets/svgs/Logo1Dark.svg";
@ -21,6 +22,8 @@ import Info from "../assets/svgs/Info.svg";
import { CustomizedSnackbars } from "../components/Snackbar/Snackbar"; import { CustomizedSnackbars } from "../components/Snackbar/Snackbar";
import { set } from "lodash"; import { set } from "lodash";
import { cleanUrl, isUsingLocal } from "../background"; import { cleanUrl, isUsingLocal } from "../background";
import HelpIcon from '@mui/icons-material/Help';
import { GlobalContext } from "../App";
const manifestData = chrome?.runtime?.getManifest(); const manifestData = chrome?.runtime?.getManifest();
@ -55,6 +58,8 @@ export const NotAuthenticated = ({
const importedApiKeyRef = useRef(null) const importedApiKeyRef = useRef(null)
const currentNodeRef = useRef(null) const currentNodeRef = useRef(null)
const hasLocalNodeRef = useRef(null) const hasLocalNodeRef = useRef(null)
const { showTutorial } = useContext(GlobalContext);
const isLocal = cleanUrl(currentNode?.url) === "127.0.0.1:12391"; const isLocal = cleanUrl(currentNode?.url) === "127.0.0.1:12391";
const handleFileChangeApiKey = (event) => { const handleFileChangeApiKey = (event) => {
const file = event.target.files[0]; // Get the selected file const file = event.target.files[0]; // Get the selected file
@ -627,6 +632,17 @@ export const NotAuthenticated = ({
</DialogActions> </DialogActions>
</Dialog> </Dialog>
)} )}
<ButtonBase onClick={()=> {
showTutorial('create-account', true)
}} sx={{
position: 'fixed',
bottom: '25px',
right: '25px'
}}>
<HelpIcon sx={{
color: 'var(--unread)'
}} />
</ButtonBase>
</> </>
); );
}; };

View File

@ -34,46 +34,8 @@ import { RESOURCE_TYPE_NUMBER_GROUP_CHAT_REACTIONS } from "./constants/resourceT
import TradeBotRespondRequest from './transactions/TradeBotRespondRequest'; import TradeBotRespondRequest from './transactions/TradeBotRespondRequest';
let inMemoryKey: CryptoKey | null = null;
let inMemoryIV: Uint8Array | null = null;
async function initializeKeyAndIV() {
if (!inMemoryKey) {
inMemoryKey = await generateKey(); // Generates the key in memory
}
}
async function generateKey(): Promise<CryptoKey> {
return await crypto.subtle.generateKey(
{
name: "AES-GCM",
length: 256
},
true,
["encrypt", "decrypt"]
);
}
async function encryptData(data: string, key: CryptoKey): Promise<{ iv: Uint8Array; encryptedData: ArrayBuffer }> {
const encoder = new TextEncoder();
const encodedData = encoder.encode(data);
// Generate a random IV each time you encrypt
const iv = crypto.getRandomValues(new Uint8Array(12));
const encryptedData = await crypto.subtle.encrypt(
{
name: "AES-GCM",
iv: iv
},
key,
encodedData
);
return { iv, encryptedData };
}
export function cleanUrl(url) { export function cleanUrl(url) {
return url?.replace(/^(https?:\/\/)?(www\.)?/, ''); return url?.replace(/^(https?:\/\/)?(www\.)?/, '');
} }
@ -1064,15 +1026,7 @@ function base64ToJson(base64) {
export async function getKeyPair() { export async function getKeyPair() {
const res = await chrome.storage.local.get(["keyPair"]); const res = await chrome.storage.local.get(["keyPair"]);
if (res?.keyPair) { if (res?.keyPair) {
const combinedData = atob(res?.keyPair) return res.keyPair;
.split("")
.map((c) => c.charCodeAt(0));
const iv = new Uint8Array(combinedData.slice(0, 12)); // First 12 bytes are the IV
const encryptedData = new Uint8Array(combinedData.slice(12)).buffer;
const decryptedBase64Data = await decryptData(encryptedData, inMemoryKey, iv);
return decryptedBase64Data
} else { } else {
throw new Error("Wallet not authenticated"); throw new Error("Wallet not authenticated");
} }
@ -1573,14 +1527,8 @@ async function decryptWallet({ password, wallet, walletVersion }) {
rvnPrivateKey: wallet2._addresses[0].rvnWallet.derivedMasterPrivateKey rvnPrivateKey: wallet2._addresses[0].rvnWallet.derivedMasterPrivateKey
}; };
const dataString = JSON.stringify(toSave); const dataString = JSON.stringify(toSave);
await initializeKeyAndIV();
const { iv, encryptedData } = await encryptData(dataString, inMemoryKey);
// Combine IV and encrypted data into a single Uint8Array
const combinedData = new Uint8Array([...iv, ...new Uint8Array(encryptedData)]);
const encryptedBase64Data = btoa(String.fromCharCode(...combinedData));
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
chrome.storage.local.set({ keyPair: encryptedBase64Data }, () => { chrome.storage.local.set({ keyPair: dataString }, () => {
if (chrome.runtime.lastError) { if (chrome.runtime.lastError) {
reject(new Error(chrome.runtime.lastError.message)); reject(new Error(chrome.runtime.lastError.message));
} else { } else {

View File

@ -20,10 +20,12 @@ import { HomeIcon } from "../../assets/Icons/HomeIcon";
import { MessagingIcon } from "../../assets/Icons/MessagingIcon"; import { MessagingIcon } from "../../assets/Icons/MessagingIcon";
import { Save } from "../Save/Save"; import { Save } from "../Save/Save";
import { HubsIcon } from "../../assets/Icons/HubsIcon"; import { HubsIcon } from "../../assets/Icons/HubsIcon";
import { IconWrapper } from "../Desktop/DesktopFooter";
import { AppsIcon } from "../../assets/Icons/AppsIcon";
const uid = new ShortUniqueId({ length: 8 }); const uid = new ShortUniqueId({ length: 8 });
export const AppsDesktop = ({ mode, setMode, show , myName, goToHome, setDesktopSideView, hasUnreadDirects, isDirects, isGroups, hasUnreadGroups, toggleSideViewGroups, toggleSideViewDirects}) => { export const AppsDesktop = ({ mode, setMode, show , myName, goToHome, setDesktopSideView, hasUnreadDirects, isDirects, isGroups, hasUnreadGroups, toggleSideViewGroups, toggleSideViewDirects, setDesktopViewMode, isApps, desktopViewMode}) => {
const [availableQapps, setAvailableQapps] = useState([]); const [availableQapps, setAvailableQapps] = useState([]);
const [selectedAppInfo, setSelectedAppInfo] = useState(null); const [selectedAppInfo, setSelectedAppInfo] = useState(null);
const [selectedCategory, setSelectedCategory] = useState(null) const [selectedCategory, setSelectedCategory] = useState(null)
@ -334,46 +336,44 @@ export const AppsDesktop = ({ mode, setMode, show , myName, goToHome, setDesktop
<HomeIcon <HomeIcon
height={34} height={34}
color="rgba(250, 250, 250, 0.5)" color={desktopViewMode === 'home' ? 'white': "rgba(250, 250, 250, 0.5)"}
/> />
</ButtonBase> </ButtonBase>
<ButtonBase <ButtonBase
onClick={() => { onClick={() => {
setDesktopSideView("directs"); setDesktopViewMode('apps')
toggleSideViewDirects()
}} }}
> >
<IconWrapper
color={isApps ? 'white' :"rgba(250, 250, 250, 0.5)"}
label="Apps"
disableWidth
>
<AppsIcon height={30} color={isApps ? 'white' :"rgba(250, 250, 250, 0.5)"} />
</IconWrapper>
</ButtonBase>
<ButtonBase
onClick={() => {
setDesktopViewMode('chat')
}}
>
<IconWrapper
color={(hasUnreadDirects || hasUnreadGroups) ? "var(--unread)" : desktopViewMode === 'chat' ? 'white' :"rgba(250, 250, 250, 0.5)"}
label="Chat"
disableWidth
>
<MessagingIcon <MessagingIcon
height={30} height={30}
color={ color={
hasUnreadDirects (hasUnreadDirects || hasUnreadGroups)
? "var(--unread)" ? "var(--unread)"
: isDirects : desktopViewMode === 'chat'
? "white" ? "white"
: "rgba(250, 250, 250, 0.5)" : "rgba(250, 250, 250, 0.5)"
} }
/> />
</IconWrapper>
</ButtonBase>
<ButtonBase
onClick={() => {
setDesktopSideView("groups");
toggleSideViewGroups()
}}
>
<HubsIcon
height={30}
color={
hasUnreadGroups
? "var(--unread)"
: isGroups
? "white"
: "rgba(250, 250, 250, 0.5)"
}
/>
</ButtonBase> </ButtonBase>
<Save isDesktop myName={myName} /> <Save isDesktop myName={myName} />
{mode !== 'home' && ( {mode !== 'home' && (

View File

@ -18,7 +18,7 @@ import AppIcon from "../../assets/svgs/AppIcon.svg";
import { HomeIcon } from "../../assets/Icons/HomeIcon"; import { HomeIcon } from "../../assets/Icons/HomeIcon";
import { Save } from "../Save/Save"; import { Save } from "../Save/Save";
export const IconWrapper = ({ children, label, color, selected }) => { export const IconWrapper = ({ children, label, color, selected, disableWidth, customWidth }) => {
return ( return (
<Box <Box
sx={{ sx={{
@ -27,8 +27,8 @@ export const IconWrapper = ({ children, label, color, selected }) => {
alignItems: "center", alignItems: "center",
gap: "5px", gap: "5px",
flexDirection: "column", flexDirection: "column",
height: "89px", height: customWidth ? customWidth : disableWidth ? 'auto' : "89px",
width: "89px", width: customWidth? customWidth : disableWidth ? 'auto' : "89px",
borderRadius: "50%", borderRadius: "50%",
backgroundColor: selected ? "rgba(28, 29, 32, 1)" : "transparent", backgroundColor: selected ? "rgba(28, 29, 32, 1)" : "transparent",
}} }}

View File

@ -128,74 +128,7 @@ export const DesktopHeader = ({
alignItems: "center", alignItems: "center",
}} }}
> >
<ButtonBase
onClick={() => {
goToHome();
}}
>
<IconWrapper
color="rgba(250, 250, 250, 0.5)"
label="Home"
selected={isHome}
>
<HomeIcon
height={25}
color={isHome ? "white" : "rgba(250, 250, 250, 0.5)"}
/>
</IconWrapper>
</ButtonBase>
<ButtonBase
onClick={() => {
setDesktopSideView("groups");
}}
>
<IconWrapper
color="rgba(250, 250, 250, 0.5)"
label="Groups"
selected={isGroups}
>
<HubsIcon
height={25}
color={
hasUnreadGroups
? "var(--unread)"
: isGroups
? "white"
: "rgba(250, 250, 250, 0.5)"
}
/>
</IconWrapper>
</ButtonBase>
<ButtonBase
onClick={() => {
setDesktopSideView("directs");
}}
>
<IconWrapper
color="rgba(250, 250, 250, 0.5)"
label="Messaging"
selected={isDirects}
>
<MessagingIcon
height={25}
color={
hasUnreadDirects
? "var(--unread)"
: isDirects
? "white"
: "rgba(250, 250, 250, 0.5)"
}
/>
</IconWrapper>
</ButtonBase>
<Box
sx={{
width: "1px",
height: "50px",
background: "white",
borderRadius: "50px",
}}
/>
<ButtonBase <ButtonBase
onClick={() => { onClick={() => {
goToAnnouncements() goToAnnouncements()
@ -231,6 +164,7 @@ export const DesktopHeader = ({
label="Chat" label="Chat"
selected={isChat} selected={isChat}
selectColor="#09b6e8" selectColor="#09b6e8"
customHeight="55px"
> >
<ChatIcon <ChatIcon
height={25} height={25}
@ -257,6 +191,7 @@ export const DesktopHeader = ({
label="Threads" label="Threads"
selected={isForum} selected={isForum}
selectColor="#09b6e8" selectColor="#09b6e8"
customHeight="55px"
> >
<ThreadsIcon <ThreadsIcon
height={25} height={25}
@ -279,6 +214,7 @@ export const DesktopHeader = ({
color="rgba(250, 250, 250, 0.5)" color="rgba(250, 250, 250, 0.5)"
label="Members" label="Members"
selected={false} selected={false}
customHeight="55px"
> >
<MembersIcon <MembersIcon
height={25} height={25}

View File

@ -0,0 +1,104 @@
import { Box, ButtonBase } from '@mui/material';
import React from 'react'
import { HomeIcon } from "../assets/Icons/HomeIcon";
import { MessagingIcon } from "../assets/Icons/MessagingIcon";
import { Save } from "./Save/Save";
import { HubsIcon } from "../assets/Icons/HubsIcon";
import { CoreSyncStatus } from "./CoreSyncStatus";
import { IconWrapper } from './Desktop/DesktopFooter';
import AppIcon from "./../assets/svgs/AppIcon.svg";
import { useRecoilState } from 'recoil';
import { AppsIcon } from '../assets/Icons/AppsIcon';
export const DesktopSideBar = ({goToHome, setDesktopSideView, toggleSideViewDirects, hasUnreadDirects, isDirects, toggleSideViewGroups,hasUnreadGroups, isGroups, isApps, setDesktopViewMode, desktopViewMode, myName }) => {
return (
<Box sx={{
width: '60px',
flexDirection: 'column',
height: '100vh',
alignItems: 'center',
display: 'flex',
gap: '25px'
}}>
<ButtonBase
sx={{
width: '60px',
height: '60px',
paddingTop: '23px'
}}
onClick={() => {
goToHome();
}}
>
<HomeIcon
height={34}
color={desktopViewMode === 'home' ? 'white': "rgba(250, 250, 250, 0.5)"}
/>
</ButtonBase>
<ButtonBase
onClick={() => {
setDesktopViewMode('apps')
// setIsOpenSideViewDirects(false)
// setIsOpenSideViewGroups(false)
}}
>
<IconWrapper
color={isApps ? 'white' : "rgba(250, 250, 250, 0.5)"}
label="Apps"
selected={isApps}
disableWidth
>
<AppsIcon color={isApps ? 'white' : "rgba(250, 250, 250, 0.5)"} height={30} />
</IconWrapper>
</ButtonBase>
<ButtonBase
onClick={() => {
setDesktopViewMode('chat')
}}
>
<IconWrapper
color={(hasUnreadDirects || hasUnreadGroups) ? "var(--unread)" : desktopViewMode === 'chat' ? 'white' :"rgba(250, 250, 250, 0.5)"}
label="Chat"
disableWidth
>
<MessagingIcon
height={30}
color={
(hasUnreadDirects || hasUnreadGroups)
? "var(--unread)"
: desktopViewMode === 'chat'
? "white"
: "rgba(250, 250, 250, 0.5)"
}
/>
</IconWrapper>
</ButtonBase>
{/* <ButtonBase
onClick={() => {
setDesktopSideView("groups");
toggleSideViewGroups()
}}
>
<HubsIcon
height={30}
color={
hasUnreadGroups
? "var(--danger)"
: isGroups
? "white"
: "rgba(250, 250, 250, 0.5)"
}
/>
</ButtonBase> */}
<Save isDesktop disableWidth myName={myName} />
{/* <CoreSyncStatus imageSize="30px" position="left" /> */}
</Box>
)
}

View File

@ -86,7 +86,7 @@ import { getRootHeight } from "../../utils/mobile/mobileUtils";
import { ReturnIcon } from "../../assets/Icons/ReturnIcon"; import { ReturnIcon } from "../../assets/Icons/ReturnIcon";
import { ExitIcon } from "../../assets/Icons/ExitIcon"; import { ExitIcon } from "../../assets/Icons/ExitIcon";
import { HomeDesktop } from "./HomeDesktop"; import { HomeDesktop } from "./HomeDesktop";
import { DesktopFooter } from "../Desktop/DesktopFooter"; import { DesktopFooter, IconWrapper } from "../Desktop/DesktopFooter";
import { DesktopHeader } from "../Desktop/DesktopHeader"; import { DesktopHeader } from "../Desktop/DesktopHeader";
import { Apps } from "../Apps/Apps"; import { Apps } from "../Apps/Apps";
import { AppsNavBar } from "../Apps/AppsNavBar"; import { AppsNavBar } from "../Apps/AppsNavBar";
@ -98,6 +98,9 @@ import { useSetRecoilState } from "recoil";
import { selectedGroupIdAtom } from "../../atoms/global"; import { selectedGroupIdAtom } from "../../atoms/global";
import { sortArrayByTimestampAndGroupName } from "../../utils/time"; import { sortArrayByTimestampAndGroupName } from "../../utils/time";
import { AdminSpace } from "../Chat/AdminSpace"; import { AdminSpace } from "../Chat/AdminSpace";
import { HubsIcon } from "../../assets/Icons/HubsIcon";
import { MessagingIcon } from "../../assets/Icons/MessagingIcon";
import { DesktopSideBar } from "../DesktopSideBar";
// let touchStartY = 0; // let touchStartY = 0;
// let disablePullToRefresh = false; // let disablePullToRefresh = false;
@ -1359,6 +1362,10 @@ export const Group = ({
setupGroupWebsocketInterval.current = null; setupGroupWebsocketInterval.current = null;
settimeoutForRefetchSecretKey.current = null; settimeoutForRefetchSecretKey.current = null;
initiatedGetMembers.current = false; initiatedGetMembers.current = false;
if(!isMobile){
setDesktopViewMode('home')
}
}; };
const openDevModeFunc = () => { const openDevModeFunc = () => {
@ -1445,7 +1452,9 @@ export const Group = ({
setTriedToFetchSecretKey(false); setTriedToFetchSecretKey(false);
setFirstSecretKeyInCreation(false); setFirstSecretKeyInCreation(false);
setGroupSection("chat"); setGroupSection("chat");
if(!isMobile){
setDesktopViewMode('chat')
}
chrome?.runtime?.sendMessage({ chrome?.runtime?.sendMessage({
action: "addTimestampEnterChat", action: "addTimestampEnterChat",
payload: { payload: {
@ -1458,7 +1467,6 @@ export const Group = ({
setSelectedGroup(findGroup); setSelectedGroup(findGroup);
setMobileViewMode("group"); setMobileViewMode("group");
setDesktopSideView('groups') setDesktopSideView('groups')
setDesktopViewMode('home')
getTimestampEnterChat(); getTimestampEnterChat();
isLoadingOpenSectionFromNotification.current = false; isLoadingOpenSectionFromNotification.current = false;
}, 200); }, 200);
@ -1497,6 +1505,9 @@ export const Group = ({
setTriedToFetchSecretKey(false); setTriedToFetchSecretKey(false);
setFirstSecretKeyInCreation(false); setFirstSecretKeyInCreation(false);
setGroupSection("announcement"); setGroupSection("announcement");
if(!isMobile){
setDesktopViewMode('chat')
}
chrome?.runtime?.sendMessage({ chrome?.runtime?.sendMessage({
action: "addGroupNotificationTimestamp", action: "addGroupNotificationTimestamp",
payload: { payload: {
@ -1508,7 +1519,6 @@ export const Group = ({
setSelectedGroup(findGroup); setSelectedGroup(findGroup);
setMobileViewMode("group"); setMobileViewMode("group");
setDesktopSideView('groups') setDesktopSideView('groups')
setDesktopViewMode('home')
getGroupAnnouncements(); getGroupAnnouncements();
}, 200); }, 200);
} }
@ -1560,12 +1570,13 @@ export const Group = ({
setFirstSecretKeyInCreation(false); setFirstSecretKeyInCreation(false);
setGroupSection("forum"); setGroupSection("forum");
setDefaultThread(data); setDefaultThread(data);
if(!isMobile){
setDesktopViewMode('chat')
}
setTimeout(() => { setTimeout(() => {
setSelectedGroup(findGroup); setSelectedGroup(findGroup);
setMobileViewMode("group"); setMobileViewMode("group");
setDesktopSideView('groups') setDesktopSideView('groups')
setDesktopViewMode('home')
getGroupAnnouncements(); getGroupAnnouncements();
}, 200); }, 200);
} }
@ -1591,32 +1602,13 @@ export const Group = ({
} }
setDesktopViewMode('home') setDesktopViewMode('home')
setGroupSection("default");
clearAllQueues();
await new Promise((res) => { await new Promise((res) => {
setTimeout(() => { setTimeout(() => {
res(null); res(null);
}, 200); }, 200);
}); });
setGroupSection("home");
setSelectedGroup(null);
setNewChat(false);
setSelectedDirect(null);
setSecretKey(null);
setGroupOwner(null)
lastFetchedSecretKey.current = null;
initiatedGetMembers.current = false;
setSecretKeyPublishDate(null);
setAdmins([]);
setSecretKeyDetails(null);
setAdminsWithNames([]);
setMembers([]);
setMemberCountFromSecretKeyData(null);
setIsForceShowCreationKeyPopup(false)
setTriedToFetchSecretKey(false);
setFirstSecretKeyInCreation(false);
setIsOpenSideViewDirects(false)
setIsOpenSideViewGroups(false)
}; };
const goToAnnouncements = async () => { const goToAnnouncements = async () => {
@ -1690,6 +1682,66 @@ export const Group = ({
borderRadius: !isMobile && '0px 15px 15px 0px' borderRadius: !isMobile && '0px 15px 15px 0px'
}} }}
> >
{!isMobile && (
<Box sx={{
width: '100%',
alignItems: 'center',
justifyContent: 'center',
display: 'flex',
gap: '10px'
}}>
<ButtonBase
onClick={() => {
setDesktopSideView("groups");
}}
>
<IconWrapper
color={(groupChatHasUnread ||
groupsAnnHasUnread)
? "var(--unread)"
: desktopSideView === 'groups' ? 'white' :"rgba(250, 250, 250, 0.5)"}
label="Groups"
selected={desktopSideView === 'groups'}
customWidth="75px"
>
<HubsIcon
height={24}
color={
(groupChatHasUnread ||
groupsAnnHasUnread)
? "var(--unread)"
: desktopSideView === 'groups'
? "white"
: "rgba(250, 250, 250, 0.5)"
}
/>
</IconWrapper>
</ButtonBase>
<ButtonBase
onClick={() => {
setDesktopSideView("directs");
}}
>
<IconWrapper
customWidth="75px"
color={directChatHasUnread ? "var(--unread)" : desktopSideView === 'directs' ? 'white' :"rgba(250, 250, 250, 0.5)"}
label="Messaging"
selected={desktopSideView === 'directs'}
>
<MessagingIcon
height={24}
color={
directChatHasUnread
? "var(--unread)"
: desktopSideView === 'directs'
? "white"
: "rgba(250, 250, 250, 0.5)"
}
/>
</IconWrapper>
</ButtonBase>
</Box>
)}
{isMobile && ( {isMobile && (
<Box <Box
sx={{ sx={{
@ -1899,172 +1951,66 @@ export const Group = ({
borderRadius: !isMobile && '0px 15px 15px 0px' borderRadius: !isMobile && '0px 15px 15px 0px'
}} }}
> >
{/* <div {!isMobile && (
style={{ <Box sx={{
display: "flex", width: '100%',
width: "100%", alignItems: 'center',
justifyContent: "center", justifyContent: 'center',
gap: "20px", display: 'flex',
padding: "10px", gap: '10px'
flexDirection: "column", }}>
}} <ButtonBase
>
{isMobile && (
<Box
sx={{
width: "100%",
display: "flex",
justifyContent: "flex-end",
}}
>
<CloseIcon
onClick={() => {
setIsOpenDrawer(false);
}}
sx={{
cursor: "pointer",
color: "white",
}}
/>
</Box>
)}
<CustomButton
onClick={() => { onClick={() => {
setChatMode((prev) => setDesktopSideView("groups");
prev === "directs" ? "groups" : "directs"
);
}}
sx={{
backgroundColor: chatMode === 'directs' && ( groupChatHasUnread || groupsAnnHasUnread) ? 'red' : 'revert'
}} }}
> >
{chatMode === "groups" && ( <IconWrapper
<> color={(groupChatHasUnread ||
<MarkUnreadChatAltIcon groupsAnnHasUnread)
sx={{ ? "var(--unread)"
color: directChatHasUnread ? "red" : "white", : desktopSideView === 'groups' ? 'white' :"rgba(250, 250, 250, 0.5)"}
}} label="Groups"
/> selected={desktopSideView === 'groups'}
</> customWidth="75px"
)} >
<HubsIcon
{chatMode === "directs" ? "Switch to groups" : "Direct msgs"} height={24}
</CustomButton> color={
</div> */} (groupChatHasUnread ||
{/* <div groupsAnnHasUnread)
style={{ ? "var(--unread)"
display: "flex", : desktopSideView === 'groups'
width: "100%", ? "white"
flexDirection: "column", : "rgba(250, 250, 250, 0.5)"
alignItems: "flex-start", }
flexGrow: 1, />
overflowY: "auto", </IconWrapper>
visibility: chatMode === "groups" && "hidden", </ButtonBase>
position: chatMode === "groups" && "fixed", <ButtonBase
left: chatMode === "groups" && "-1000px", onClick={() => {
}} setDesktopSideView("directs");
> }}
{directs.map((direct: any) => ( >
<List sx={{ <IconWrapper
width: '100%' customWidth="75px"
}} className="group-list" dense={true}> color={directChatHasUnread ? "var(--unread)" : desktopSideView === 'directs' ? 'white' :"rgba(250, 250, 250, 0.5)"}
<ListItem label="Messaging"
// secondaryAction={ selected={desktopSideView === 'directs' }
// <IconButton edge="end" aria-label="delete"> >
// <SettingsIcon /> <MessagingIcon
// </IconButton> height={24}
// } color={
onClick={() => { directChatHasUnread
setSelectedDirect(null); ? "var(--unread)"
setNewChat(false); : desktopSideView === 'directs'
// setSelectedGroup(null); ? "white"
setIsOpenDrawer(false); : "rgba(250, 250, 250, 0.5)"
chrome?.runtime?.sendMessage({ }
action: "addTimestampEnterChat", />
payload: { </IconWrapper>
timestamp: Date.now(), </ButtonBase>
groupId: direct.address, </Box>
}, )}
});
setTimeout(() => {
setSelectedDirect(direct);
getTimestampEnterChat();
}, 200);
}}
sx={{
display: "flex",
width: "100%",
flexDirection: "column",
cursor: "pointer",
border: "1px #232428 solid",
padding: "2px",
borderRadius: "2px",
background:
direct?.address === selectedDirect?.address && "white",
}}
>
<Box
sx={{
display: "flex",
width: "100%",
}}
>
<ListItemAvatar>
<Avatar
sx={{
background: "#232428",
color: "white",
}}
alt={direct?.name || direct?.address}
// src={`${getBaseApiReact()}/arbitrary/THUMBNAIL/${groupOwner?.name}/qortal_group_avatar_${group.groupId}?async=true`}
>
{(direct?.name || direct?.address)?.charAt(0)}
</Avatar>
</ListItemAvatar>
<ListItemText
primary={direct?.name || direct?.address}
primaryTypographyProps={{
style: {
color:
direct?.address === selectedDirect?.address &&
"black",
textWrap: "wrap",
overflow: "hidden",
},
}} // Change the color of the primary text
secondaryTypographyProps={{
style: {
color:
direct?.address === selectedDirect?.address &&
"black",
},
}}
sx={{
width: "150px",
fontFamily: "Inter",
fontSize: "16px",
}}
/>
{direct?.sender !== myAddress &&
direct?.timestamp &&
((!timestampEnterData[direct?.address] &&
Date.now() - direct?.timestamp <
timeDifferenceForNotificationChats) ||
timestampEnterData[direct?.address] <
direct?.timestamp) && (
<MarkChatUnreadIcon
sx={{
color: "red",
}}
/>
)}
</Box>
</ListItem>
</List>
))}
</div> */}
<div <div
style={{ style={{
display: "flex", display: "flex",
@ -2095,7 +2041,6 @@ export const Group = ({
onClick={() => { onClick={() => {
setMobileViewMode("group"); setMobileViewMode("group");
setDesktopSideView('groups') setDesktopSideView('groups')
setDesktopViewMode('home')
initiatedGetMembers.current = false; initiatedGetMembers.current = false;
clearAllQueues(); clearAllQueues();
setSelectedDirect(null); setSelectedDirect(null);
@ -2347,8 +2292,14 @@ export const Group = ({
alignItems: "flex-start", alignItems: "flex-start",
}} }}
> >
{!isMobile && ((desktopSideView === 'groups' && desktopViewMode !== 'apps') || isOpenSideViewGroups) && renderGroups()} {!isMobile && ((desktopViewMode !== 'apps' && desktopViewMode !== 'dev') || isOpenSideViewGroups) && (
{!isMobile && ((desktopSideView === 'directs' && desktopViewMode !== 'apps') || isOpenSideViewDirects) && renderDirects()} <DesktopSideBar desktopViewMode={desktopViewMode} toggleSideViewGroups={toggleSideViewGroups} toggleSideViewDirects={toggleSideViewDirects} goToHome={goToHome} mode={appsMode} setMode={setAppsMode} setDesktopSideView={setDesktopSideView} hasUnreadDirects={directChatHasUnread} isApps={desktopViewMode === 'apps'} myName={userInfo?.name} isGroups={isOpenSideViewGroups}
isDirects={isOpenSideViewDirects} hasUnreadGroups={groupChatHasUnread ||
groupsAnnHasUnread} setDesktopViewMode={setDesktopViewMode} />
)}
{!isMobile && desktopViewMode === 'chat' && desktopSideView !== 'directs' && renderGroups()}
{!isMobile && desktopViewMode === 'chat' && desktopSideView === 'directs' && renderDirects()}
<Box <Box
sx={{ sx={{
@ -2454,9 +2405,37 @@ export const Group = ({
</Box> </Box>
</> </>
)} )}
{selectedGroup && mobileViewMode !== 'groups' && ( {desktopViewMode === 'chat' && !selectedGroup && (
<> <Box
{!isMobile && selectedGroup && ( sx={{
width: "100%",
display: "flex",
justifyContent: "center",
alignItems: 'center',
height: '100%',
}}
>
<Typography
sx={{
fontSize: "14px",
fontWeight: 400,
color: 'rgba(255, 255, 255, 0.2)'
}}
>
No group selected
</Typography>
</Box>
)}
{mobileViewMode !== 'groups' && (
<div style={{
width: '100%',
display: selectedGroup? 'block' : 'none',
opacity: !(desktopViewMode === 'chat' && selectedGroup) ? 0 : 1,
position: !(desktopViewMode === 'chat' && selectedGroup) ? 'absolute' : 'relative',
left: !(desktopViewMode === 'chat' && selectedGroup) ? '-100000px' : '0px',
}}>
{!isMobile && (
<DesktopHeader <DesktopHeader
isPrivate={isPrivate} isPrivate={isPrivate}
@ -2753,7 +2732,7 @@ export const Group = ({
isOwner={groupOwner?.owner === myAddress} isOwner={groupOwner?.owner === myAddress}
/> />
)} )}
</> </div>
)} )}
{selectedDirect && !newChat && ( {selectedDirect && !newChat && (
@ -2797,43 +2776,7 @@ export const Group = ({
</Box> </Box>
</> </>
)} )}
{!isMobile && groupSection === "home" && (
<DesktopFooter
isPrivate={isPrivate}
selectedGroup={selectedGroup}
groupSection={groupSection}
isUnread={isUnread}
goToAnnouncements={goToAnnouncements}
isUnreadChat={isUnreadChat}
goToChat={goToChat}
goToThreads={goToThreads}
setOpenManageMembers={setOpenManageMembers}
groupChatHasUnread={groupChatHasUnread}
groupsAnnHasUnread={groupsAnnHasUnread}
directChatHasUnread={directChatHasUnread}
chatMode={chatMode}
openDrawerGroups={openDrawerGroups}
goToHome={goToHome}
setIsOpenDrawerProfile={setIsOpenDrawerProfile}
mobileViewMode={mobileViewMode}
setMobileViewMode={setMobileViewMode}
setMobileViewModeKeepOpen={setMobileViewModeKeepOpen}
hasUnreadGroups={groupChatHasUnread ||
groupsAnnHasUnread}
hasUnreadDirects={directChatHasUnread}
myName={userInfo?.name || null}
isHome={groupSection === "home" && desktopViewMode === 'home'}
isGroups={desktopSideView === 'groups' && desktopViewMode !== 'apps'}
isDirects={desktopSideView === 'directs' && desktopViewMode !== 'apps'}
setDesktopViewMode={setDesktopViewMode}
isApps={desktopViewMode === 'apps'}
setDesktopSideView={setDesktopSideView}
desktopViewMode={desktopViewMode}
hide={desktopViewMode === 'apps'}
setIsOpenSideViewDirects={setIsOpenSideViewDirects}
setIsOpenSideViewGroups={setIsOpenSideViewGroups}
/>
)}
{isMobile && mobileViewMode === "home" && ( {isMobile && mobileViewMode === "home" && (
<Home <Home
refreshHomeDataFunc={refreshHomeDataFunc} refreshHomeDataFunc={refreshHomeDataFunc}
@ -2848,20 +2791,20 @@ export const Group = ({
setOpenManageMembers={setOpenManageMembers} setOpenManageMembers={setOpenManageMembers}
setOpenAddGroup={setOpenAddGroup} setOpenAddGroup={setOpenAddGroup}
setMobileViewMode={setMobileViewMode} setMobileViewMode={setMobileViewMode}
setDesktopViewMode={setDesktopViewMode}
/> />
)} )}
{isMobile && ( {isMobile && (
<Apps mode={appsMode} setMode={setAppsMode} show={mobileViewMode === "apps"} myName={userInfo?.name} /> <Apps mode={appsMode} setMode={setAppsMode} show={mobileViewMode === "apps"} myName={userInfo?.name} />
)} )}
{!isMobile && ( {!isMobile && (
<AppsDesktop toggleSideViewGroups={toggleSideViewGroups} toggleSideViewDirects={toggleSideViewDirects} goToHome={goToHome} mode={appsMode} setMode={setAppsMode} setDesktopSideView={setDesktopSideView} hasUnreadDirects={directChatHasUnread} show={desktopViewMode === "apps"} myName={userInfo?.name} isGroups={isOpenSideViewGroups} <AppsDesktop toggleSideViewGroups={toggleSideViewGroups} toggleSideViewDirects={toggleSideViewDirects} goToHome={goToHome} mode={appsMode} setMode={setAppsMode} setDesktopSideView={setDesktopSideView} hasUnreadDirects={directChatHasUnread} show={desktopViewMode === "apps"} myName={userInfo?.name} isGroups={isOpenSideViewGroups}
isDirects={isOpenSideViewDirects} hasUnreadGroups={groupChatHasUnread || isDirects={isOpenSideViewDirects} hasUnreadGroups={groupChatHasUnread ||
groupsAnnHasUnread} /> groupsAnnHasUnread} setDesktopViewMode={setDesktopViewMode} isApps={desktopViewMode === 'apps'} desktopViewMode={desktopViewMode} />
)} )}
{!isMobile && !selectedGroup && {!isMobile && desktopViewMode === 'home' && (
groupSection === "home" && desktopViewMode !== "apps" && (
<HomeDesktop <HomeDesktop
refreshHomeDataFunc={refreshHomeDataFunc} refreshHomeDataFunc={refreshHomeDataFunc}
myAddress={myAddress} myAddress={myAddress}
@ -2875,6 +2818,8 @@ export const Group = ({
setOpenManageMembers={setOpenManageMembers} setOpenManageMembers={setOpenManageMembers}
setOpenAddGroup={setOpenAddGroup} setOpenAddGroup={setOpenAddGroup}
setMobileViewMode={setMobileViewMode} setMobileViewMode={setMobileViewMode}
setDesktopViewMode={setDesktopViewMode}
/> />
)} )}
@ -2886,7 +2831,7 @@ export const Group = ({
width: "31px", width: "31px",
// minWidth: "135px", // minWidth: "135px",
padding: "5px", padding: "5px",
display: (isMobile || desktopViewMode === 'apps') ? "none" : "flex", display: (isMobile || desktopViewMode === 'apps' || desktopViewMode === 'dev' || desktopViewMode === 'chat') ? "none" : "flex",
}} }}
> >

View File

@ -20,7 +20,7 @@ import { myGroupsWhereIAmAdminAtom } from "../../atoms/global";
import { useSetRecoilState } from "recoil"; import { useSetRecoilState } from "recoil";
export const requestQueueGroupJoinRequests = new RequestQueueWithPromise(2) export const requestQueueGroupJoinRequests = new RequestQueueWithPromise(2)
export const GroupJoinRequests = ({ myAddress, groups, setOpenManageMembers, getTimestampEnterChat, setSelectedGroup, setGroupSection, setMobileViewMode }) => { export const GroupJoinRequests = ({ myAddress, groups, setOpenManageMembers, getTimestampEnterChat, setSelectedGroup, setGroupSection, setMobileViewMode, setDesktopViewMode }) => {
const [groupsWithJoinRequests, setGroupsWithJoinRequests] = React.useState([]) const [groupsWithJoinRequests, setGroupsWithJoinRequests] = React.useState([])
const [loading, setLoading] = React.useState(true) const [loading, setLoading] = React.useState(true)
const {txList, setTxList} = React.useContext(MyContext) const {txList, setTxList} = React.useContext(MyContext)
@ -185,6 +185,9 @@ export const GroupJoinRequests = ({ myAddress, groups, setOpenManageMembers, get
getTimestampEnterChat() getTimestampEnterChat()
setGroupSection("announcement") setGroupSection("announcement")
setOpenManageMembers(true) setOpenManageMembers(true)
if(!isMobile){
setDesktopViewMode('chat')
}
setTimeout(() => { setTimeout(() => {
executeEvent("openGroupJoinRequest", {}); executeEvent("openGroupJoinRequest", {});

View File

@ -21,6 +21,7 @@ export const Home = ({
setOpenManageMembers, setOpenManageMembers,
setOpenAddGroup, setOpenAddGroup,
setMobileViewMode, setMobileViewMode,
setDesktopViewMode
}) => { }) => {
return ( return (
<Box <Box
@ -97,6 +98,7 @@ export const Home = ({
myAddress={myAddress} myAddress={myAddress}
groups={groups} groups={groups}
setMobileViewMode={setMobileViewMode} setMobileViewMode={setMobileViewMode}
setDesktopViewMode={setDesktopViewMode}
/> />
<GroupInvites <GroupInvites
setOpenAddGroup={setOpenAddGroup} setOpenAddGroup={setOpenAddGroup}

View File

@ -21,6 +21,7 @@ export const HomeDesktop = ({
setOpenManageMembers, setOpenManageMembers,
setOpenAddGroup, setOpenAddGroup,
setMobileViewMode, setMobileViewMode,
setDesktopViewMode
}) => { }) => {
return ( return (
<Box <Box
@ -67,7 +68,7 @@ export const HomeDesktop = ({
display: "flex", display: "flex",
gap: "15px", gap: "15px",
flexWrap: "wrap", flexWrap: "wrap",
justifyContent: "flex-start", justifyContent: "center",
}} }}
> >
<Box sx={{ <Box sx={{
@ -106,6 +107,7 @@ export const HomeDesktop = ({
myAddress={myAddress} myAddress={myAddress}
groups={groups} groups={groups}
setMobileViewMode={setMobileViewMode} setMobileViewMode={setMobileViewMode}
setDesktopViewMode={setDesktopViewMode}
/> />
</Box> </Box>
<Box sx={{ <Box sx={{

View File

@ -57,6 +57,8 @@ useEffect(()=> {
}, []) }, [])
const showTutorial = useCallback(async (type, isForce) => { const showTutorial = useCallback(async (type, isForce) => {
try { try {
console.log('type, isForce', type, isForce)
const isOnline = await checkIfGatewayIsOnline() const isOnline = await checkIfGatewayIsOnline()
if(!isOnline) return if(!isOnline) return
switch (type) { switch (type) {

View File

@ -79,8 +79,8 @@ const hasExtension = (filename) => {
return filename.includes(".") && filename.split(".").pop().length > 0; return filename.includes(".") && filename.split(".").pop().length > 0;
}; };
export const createAccount = async()=> { export const createAccount = async(generatedSeedPhrase)=> {
const generatedSeedPhrase = generateRandomSentence() if(!generatedSeedPhrase) throw new Error('No generated seed-phrase')
const threads = doInitWorkers(crypto.kdfThreads) const threads = doInitWorkers(crypto.kdfThreads)
const seed = await kdf(generatedSeedPhrase, void 0, threads) const seed = await kdf(generatedSeedPhrase, void 0, threads)
@ -118,3 +118,12 @@ fileName = hasExtension(fileName) ? fileName : fileName + "." + fileExtension;
await saveAs(blob, fileName); await saveAs(blob, fileName);
} }
export const saveSeedPhraseToDisk = async (data) => {
const blob = new Blob([data], { type: 'text/plain;charset=utf-8' })
const fileName = "qortal_seedphrase.txt"
await saveAs(blob, fileName);
}

View File

@ -0,0 +1,173 @@
// Author: irontiga <irontiga@gmail.com>
import { html, LitElement, css } from 'lit'
import * as WORDLISTS from './wordList'
class RandomSentenceGenerator extends LitElement {
static get properties() {
return {
template: { type: String, attribute: 'template' },
parsedString: { type: String },
fetchedWordlistCount: { type: Number, value: 0 },
capitalize: { type: Boolean },
partsOfSpeechMap: { type: Object },
templateEntropy: { type: Number, reflect: true, attribute: 'template-entropy' },
maxWordLength: { type: Number, attribute: 'max-word-length' }
}
}
constructor() {
super()
this.template = 'adjective noun verb adverb.'
this.maxWordLength = 0
this.parsedString = ''
this.fetchedWordlistCount = 0
this.capitalize = true
this.partsOfSpeechMap = {
'noun': 'nouns',
'adverb': 'adverbs',
'adv': 'adverbs',
'verb': 'verbs',
'interjection': 'interjections',
'adjective': 'adjectives',
'adj': 'adjectives',
'verbed': 'verbed'
}
this.partsOfSpeech = Object.keys(this.partsOfSpeechMap)
this._wordlists = WORDLISTS
}
static styles = css`
div {
text-align: center;
width: 100%;
background-color: #1f2023;
border-radius: 5px;
padding: 10px;
}
`;
render() {
return html`
<div>${this.parsedString}</div>
`
}
firstUpdated() {
// ...
}
updated(changedProperties) {
let regen = false
if (changedProperties.has('template')) {
regen = true
}
if (changedProperties.has('maxWordLength')) {
console.dir(this.maxWordLength)
if (this.maxWordLength) {
const wl = { ...this._wordlists }
for (const partOfSpeech in this._wordlists) {
if (Array.isArray(this._wordlists[partOfSpeech])) {
wl[partOfSpeech] = this._wordlists[partOfSpeech].filter(word => word.length <= this.maxWordLength)
}
}
this._wordlists = wl
}
regen = true
}
if (regen) this.generate()
}
_RNG(entropy) {
if (entropy > 1074) {
throw new Error('Javascript can not handle that much entropy!')
}
let randNum = 0
const crypto = window.crypto || window.msCrypto
if (crypto) {
const entropy256 = Math.ceil(entropy / 8)
let buffer = new Uint8Array(entropy256)
crypto.getRandomValues(buffer)
randNum = buffer.reduce((num, value) => {
return num * value
}, 1) / Math.pow(256, entropy256)
} else {
console.warn('Secure RNG not found. Using Math.random')
randNum = Math.random()
}
return randNum
}
setRNG(fn) {
this._RNG = fn
}
_captitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1)
}
getWord(partOfSpeech) {
const words = this._wordlists[this.partsOfSpeechMap[partOfSpeech]]
const requiredEntropy = Math.log(words.length) / Math.log(2)
const index = this._RNG(requiredEntropy) * words.length
return {
word: words[Math.round(index)],
entropy: words.length
}
}
generate() {
this.parsedString = this.parse(this.template)
}
parse(template) {
const split = template.split(/[\s]/g)
let entropy = 1
const final = split.map(word => {
const lower = word.toLowerCase()
this.partsOfSpeech.some(partOfSpeech => {
const partOfSpeechIndex = lower.indexOf(partOfSpeech) // Check it exists
const nextChar = word.charAt(partOfSpeech.length)
if (partOfSpeechIndex === 0 && !(nextChar && (nextChar.match(/[a-zA-Z]/g) != null))) {
const replacement = this.getWord(partOfSpeech)
word = replacement.word + word.slice(partOfSpeech.length) // Append the rest of the "word" (punctuation)
entropy = entropy * replacement.entropy
return true
}
})
return word
})
this.templateEntropy = Math.floor(Math.log(entropy) / Math.log(8))
return final.join(' ')
}
}
window.customElements.define('random-sentence-generator', RandomSentenceGenerator)
export default RandomSentenceGenerator

View File

@ -0,0 +1,40 @@
export const EXCEPTIONS = {
'are': 'were',
'eat': 'ate',
'go': 'went',
'have': 'had',
'inherit': 'inherited',
'is': 'was',
'run': 'ran',
'sit': 'sat',
'visit': 'visited'
}
export const getPastTense = (verb, exceptions = EXCEPTIONS) => {
if (exceptions[verb]) {
return exceptions[verb]
}
if ((/e$/i).test(verb)) {
return verb + 'd'
}
if ((/[aeiou]c$/i).test(verb)) {
return verb + 'ked'
}
// for american english only
if ((/el$/i).test(verb)) {
return verb + 'ed'
}
if ((/[aeio][aeiou][dlmnprst]$/).test(verb)) {
return verb + 'ed'
}
if ((/[aeiou][bdglmnprst]$/i).test(verb)) {
return verb.replace(/(.+[aeiou])([bdglmnprst])/, '$1$2$2ed')
}
return verb + 'ed'
}

File diff suppressed because one or more lines are too long