Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use ArSvgies package + cache images in localStorage for wallets and contacts #230

Open
wants to merge 2 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
]
},
"dependencies": {
"@7i7o/arsvgies": "^1.1.0",
"@arconnect/components": "^0.2.6",
"@arconnect/keystone-sdk": "^0.0.5",
"@arconnect/warp-dre": "^0.0.1",
Expand Down
17 changes: 9 additions & 8 deletions src/components/Recipient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { searchArNSName } from "~lib/arns";
import { useToasts } from "@arconnect/components";
import { formatAddress, isAddressFormat } from "~utils/format";
import { ExtensionStorage } from "~utils/storage";
import Squircle from "./Squircle";

export type Contact = {
name: string;
Expand All @@ -17,6 +18,7 @@ export type Contact = {
notes: string;
ArNSAddress: string;
avatarId: string;
avatar: string;
};

export const generateProfileIcon = (name) => {
Expand Down Expand Up @@ -183,7 +185,7 @@ export default function Recipient({ onClick, onClose }: RecipientProps) {
}}
>
{contact.profileIcon ? (
<ProfilePicture src={contact.profileIcon} alt="Profile" />
<ProfilePicture img={contact.profileIcon} />
) : (
<AutoContactPic>
{generateProfileIcon(contact?.name || contact.address)}
Expand Down Expand Up @@ -253,16 +255,15 @@ const ContactItem = styled.div`
}
`;

export const ProfilePicture = styled.img<{ size?: string }>`
width: ${(props) => (props.size ? props.size : "34px")};
height: ${(props) => (props.size ? props.size : "34px")};
border-radius: 50%;
export const ProfilePicture = styled(Squircle)<{ size?: string }>`
width: ${(props) => (props.size ? props.size : "2rem")};
height: ${(props) => (props.size ? props.size : "2rem")};
margin-right: 10px;
`;

export const AutoContactPic = styled.div<{ size?: string }>`
width: ${(props) => (props.size ? props.size : "34px")};
height: ${(props) => (props.size ? props.size : "34px")};
export const AutoContactPic = styled(Squircle)<{ size?: string }>`
width: ${(props) => (props.size ? props.size : "2rem")};
height: ${(props) => (props.size ? props.size : "2rem")};
display: flex;
background-color: #ab9aff26;
align-items: center;
Expand Down
10 changes: 2 additions & 8 deletions src/components/dashboard/list/WalletListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import type { StoredWallet } from "~wallets";
import HardwareWalletIcon from "~components/hardware/HardwareWalletIcon";
import keystoneLogo from "url:/assets/hardware/keystone.png";
import BaseElement, { SettingIcon } from "./BaseElement";
import { svgie } from "~utils/svgies";

export default function WalletListItem({
wallet,
Expand All @@ -20,11 +19,6 @@ export default function WalletListItem({
// format address
const formattedAddress = useMemo(() => formatAddress(address, 8), [address]);

const svgieAvatar = useMemo(
() => svgie(address, { asDataURI: true }),
[address]
);

// allow dragging with the drag icon
const dragControls = useDragControls();

Expand All @@ -40,11 +34,11 @@ export default function WalletListItem({
title={name}
description={formattedAddress}
active={active}
img={avatar || svgieAvatar}
img={avatar || wallet?.avatar}
dragControls={dragControls}
{...props}
>
{!avatar && !svgieAvatar && <SettingIcon as={WalletIcon} />}
{!avatar && !wallet?.avatar && <SettingIcon as={WalletIcon} />}
{wallet.type === "hardware" && wallet.api === "keystone" && (
<HardwareIcon icon={keystoneLogo} color="#2161FF" />
)}
Expand Down
40 changes: 31 additions & 9 deletions src/components/dashboard/subsettings/AddContact.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import styled from "styled-components";
import { useLocation } from "wouter";
import copy from "copy-to-clipboard";
import { gql } from "~gateways/api";
import { arSvgie } from "@7i7o/arsvgies";

export default function AddContact() {
// contacts
Expand Down Expand Up @@ -60,7 +61,8 @@ export default function AddContact() {
profileIcon: "",
notes: "",
ArNSAddress: "",
avatarId: ""
avatarId: "",
avatar: ""
});

useEffect(() => {
Expand Down Expand Up @@ -128,10 +130,24 @@ export default function AddContact() {

const handleInputChange = (e) => {
const { name, value } = e.target;
setContact({
...contact,
[name]: value
});
if (name !== "address") {
setContact({
...contact,
[name]: value
});
} else {
if (!value || value.length !== 43) {
setContact({
...contact,
[name]: value,
avatar: ""
});
} else {
arSvgie(value, { asDataURI: true }).then((avatar) =>
setContact({ ...contact, [name]: value, avatar })
);
}
}
};

async function fetchArnsAddresses(ownerAddress) {
Expand Down Expand Up @@ -200,7 +216,8 @@ export default function AddContact() {
profileIcon: contact.profileIcon,
notes: contact.notes,
ArNSAddress: contact.ArNSAddress,
avatarId: contact.avatarId
avatarId: contact.avatarId,
avatar: contact.avatar
};

try {
Expand All @@ -213,7 +230,8 @@ export default function AddContact() {
profileIcon: "",
notes: "",
ArNSAddress: "",
avatarId: ""
avatarId: "",
avatar: ""
});

setLocation(`/contacts/${contact.address}`);
Expand All @@ -232,7 +250,8 @@ export default function AddContact() {
profileIcon: "",
notes: "",
ArNSAddress: "",
avatarId: ""
avatarId: "",
avatar: ""
});

removeContactModal.setOpen(false);
Expand All @@ -257,7 +276,10 @@ export default function AddContact() {
{contact.avatarId && contact.profileIcon && (
<ContactPic src={contact.profileIcon} />
)}
{!contact.avatarId && !contact.profileIcon && (
{!contact.profileIcon && contact.avatar && (
<ContactPic img={contact.avatar} />
)}
{!contact.avatarId && !contact.profileIcon && !contact.avatar && (
<AutoContactPic>
{generateProfileIcon(contact.name, contact.address)}
</AutoContactPic>
Expand Down
55 changes: 34 additions & 21 deletions src/components/dashboard/subsettings/ContactSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
useToasts
} from "@arconnect/components";
import { CheckIcon, CopyIcon } from "@iconicicons/react";
import { useState, useEffect, type MouseEventHandler, useMemo } from "react";
import { useState, useEffect, type MouseEventHandler } from "react";
import { useStorage } from "@plasmohq/storage/hook";
import { ExtensionStorage } from "~utils/storage";
import styled from "styled-components";
Expand All @@ -22,7 +22,8 @@ import { uploadUserAvatar, getUserAvatar } from "~lib/avatar";
import { getAllArNSNames } from "~lib/arns";
import copy from "copy-to-clipboard";
import { EventType, trackEvent } from "~utils/analytics";
import { svgie } from "~utils/svgies";
import Squircle from "~components/Squircle";
import { arSvgie } from "@7i7o/arsvgies";

export default function ContactSettings({ address }: Props) {
// contacts
Expand All @@ -43,21 +44,15 @@ export default function ContactSettings({ address }: Props) {
profileIcon: "",
notes: "",
ArNSAddress: "",
avatarId: ""
avatarId: "",
avatar: ""
});
const [contactIndex, setContactIndex] = useState(-1);
const [arnsResults, setArnsResults] = useState([]);
const [avatarLoading, setAvatarLoading] = useState(false);
const [copied, setCopied] = useState(false);
const [originalContact, setOriginalContact] = useState(null);

const svgieAvatar = useMemo(() => {
if (!contact.address || contact.avatarId) {
return "";
}
return svgie(contact.address, { asDataURI: true });
}, [contact.address, contact.avatarId]);

useEffect(() => {
const loadedContact = storedContacts.find((c) => c.address === address);
if (loadedContact) {
Expand All @@ -71,7 +66,8 @@ export default function ContactSettings({ address }: Props) {
profileIcon: "",
notes: "",
ArNSAddress: "",
avatarId: ""
avatarId: "",
avatar: ""
});
setContactIndex(-1);
}
Expand All @@ -88,12 +84,30 @@ export default function ContactSettings({ address }: Props) {

const handleInputChange = (e) => {
const { name, value } = e.target;
setContact({
...contact,
[name]: value
});
if (name !== "address") {
setContact({
...contact,
[name]: value
});
} else {
if (!value || value.length !== 43) {
setContact({
...contact,
[name]: value,
avatar: ""
});
} else {
arSvgie(value, { asDataURI: true }).then((avatar) =>
setContact({ ...contact, [name]: value, avatar })
);
}
}
};

useEffect(() => {
console.log(`Changed Address: ${contact.address}`);
}, [contact.address]);

const saveContact = async () => {
// check if the address has been changed to a different one that's already in use
const addressChanged =
Expand Down Expand Up @@ -293,7 +307,7 @@ export default function ContactSettings({ address }: Props) {
<SubTitle>{browser.i18n.getMessage("contact_avatar")}</SubTitle>
<PicWrapper>
{contact.avatarId && !avatarLoading ? (
<ContactPic src={contact.profileIcon} />
<ContactPic img={contact.profileIcon} />
) : (
avatarLoading &&
contact.avatarId && (
Expand All @@ -302,10 +316,10 @@ export default function ContactSettings({ address }: Props) {
</AutoContactPic>
)
)}
{!contact.profileIcon && svgieAvatar && (
<ContactPic src={svgieAvatar} />
{!contact.profileIcon && contact.avatar && (
<ContactPic img={contact.avatar} />
)}
{!contact.profileIcon && !svgieAvatar && (
{!contact.profileIcon && !contact.avatar && (
<AutoContactPic>
{generateProfileIcon(contact.name, contact.address)}
</AutoContactPic>
Expand Down Expand Up @@ -550,10 +564,9 @@ export const AutoContactPic = styled.div`
background-color: #ab9aff26;
`;

export const ContactPic = styled.img`
export const ContactPic = styled(Squircle)`
width: 100px;
height: 100px;
border-radius: 100%;
margin-bottom: 10px;
`;

Expand Down
17 changes: 17 additions & 0 deletions src/components/dashboard/subsettings/WalletSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import browser from "webextension-polyfill";
import styled from "styled-components";
import copy from "copy-to-clipboard";
import { formatAddress } from "~utils/format";
import Squircle from "~components/Squircle";

export default function WalletSettings({ address }: Props) {
// wallets
Expand Down Expand Up @@ -219,6 +220,11 @@ export default function WalletSettings({ address }: Props) {
<CheckIcon />
</IconButton>
</InputWithBtn>
<Spacer y={1} />
<PictureWrapper>
<ProfilePicture img={wallet?.avatar} size="240px" />
</PictureWrapper>
<Spacer y={1} />
</div>
<div>
<Button
Expand Down Expand Up @@ -314,6 +320,17 @@ const Wrapper = styled.div`
height: 100%;
`;

const PictureWrapper = styled.div`
width: 100%;
display: flex;
justify-content: center;
`;

const ProfilePicture = styled(Squircle)<{ size?: string }>`
width: ${(props) => (props.size ? props.size : "2rem")};
height: ${(props) => (props.size ? props.size : "2rem")};
`;

const WalletName = styled(Text).attrs({
title: true,
noMargin: true
Expand Down
24 changes: 17 additions & 7 deletions src/components/popup/Head.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ import { ExtensionStorage } from "~utils/storage";
import HardwareWalletIcon, {
hwIconAnimateProps
} from "~components/hardware/HardwareWalletIcon";
import { useHardwareApi } from "~wallets/hooks";
import { useHardwareApi, useWalletsDetails } from "~wallets/hooks";
import { useHistory } from "~utils/hash_router";
import { useEffect, useMemo, useState } from "react";
import keystoneLogo from "url:/assets/hardware/keystone.png";
import WalletSwitcher from "./WalletSwitcher";
import styled from "styled-components";
import { svgie } from "~utils/svgies";
import { type StoredWallet } from "~wallets";

export default function Head({
title,
Expand Down Expand Up @@ -72,9 +72,19 @@ export default function Head({

const ans = useAnsProfile(activeAddress);

const svgieAvatar = useMemo(
() => svgie(activeAddress, { asDataURI: true }),
[activeAddress]
// wallets
const [wallets, setWallets] = useStorage<StoredWallet[]>(
{
key: "wallets",
instance: ExtensionStorage
},
[]
);

// this wallet
const wallet = useMemo(
() => wallets?.find((w) => w.address === activeAddress),
[wallets, activeAddress]
);

// first render for animation
Expand Down Expand Up @@ -117,13 +127,13 @@ export default function Head({
>
<PageTitle>{title}</PageTitle>
<ClickableAvatar
img={ans?.avatar || svgieAvatar}
img={ans?.avatar || wallet?.avatar}
onClick={() => {
if (!allowOpen) return;
setOpen(true);
}}
>
{!ans?.avatar && !svgieAvatar && <NoAvatarIcon />}
{!ans?.avatar && !wallet?.avatar && <NoAvatarIcon />}
<AnimatePresence initial={false}>
{hardwareApi === "keystone" && (
<HardwareWalletIcon
Expand Down
Loading