From a9e8862c0a79dd2df12085539001def4248cb165 Mon Sep 17 00:00:00 2001 From: William Grant Date: Mon, 22 May 2023 16:11:49 +1000 Subject: [PATCH 01/24] feat: convered EditProfileDialog to a functional component --- ts/components/dialog/EditProfileDialog.tsx | 512 ++++++++++----------- 1 file changed, 239 insertions(+), 273 deletions(-) diff --git a/ts/components/dialog/EditProfileDialog.tsx b/ts/components/dialog/EditProfileDialog.tsx index 34d4947a1..0f664633f 100644 --- a/ts/components/dialog/EditProfileDialog.tsx +++ b/ts/components/dialog/EditProfileDialog.tsx @@ -1,20 +1,15 @@ -import React, { ChangeEvent, MouseEvent } from 'react'; +import React, { ChangeEvent, MouseEvent, ReactElement, useState } from 'react'; import { QRCode } from 'react-qr-svg'; import { Avatar, AvatarSize } from '../avatar/Avatar'; import { SyncUtils, ToastUtils, UserUtils } from '../../session/utils'; import { YourSessionIDPill, YourSessionIDSelectable } from '../basic/YourSessionIDPill'; - -import { ConversationModel } from '../../models/conversation'; - -import autoBind from 'auto-bind'; import styled from 'styled-components'; import { uploadOurAvatar } from '../../interactions/conversationInteractions'; import { ConversationTypeEnum } from '../../models/conversationAttributes'; import { MAX_USERNAME_BYTES } from '../../session/constants'; import { getConversationController } from '../../session/conversations'; -import { sanitizeSessionUsername } from '../../session/utils/String'; import { editProfileModal } from '../../state/ducks/modalDialog'; import { pickFileForAvatar } from '../../types/attachments/VisualAttachment'; import { saveQRCode } from '../../util/saveQRCode'; @@ -23,6 +18,9 @@ import { SessionWrapperModal } from '../SessionWrapperModal'; import { SessionButton, SessionButtonType } from '../basic/SessionButton'; import { SessionSpinner } from '../basic/SessionSpinner'; import { SessionIconButton } from '../icon'; +import { sanitizeSessionUsername } from '../../session/utils/String'; +import { useOurConversationUsername } from '../../hooks/useParamSelector'; +import { useOurAvatarPath } from '../../hooks/useParamSelector'; const handleSaveQRCode = (event: MouseEvent) => { event.preventDefault(); @@ -51,311 +49,279 @@ const QRView = ({ sessionID }: { sessionID: string }) => { ); }; -interface State { - profileName: string; - updatedProfileName: string; - oldAvatarPath: string; - newAvatarObjectUrl: string | null; - mode: 'default' | 'edit' | 'qr'; - loading: boolean; -} - -export class EditProfileDialog extends React.Component<{}, State> { - private readonly convo: ConversationModel; - - constructor(props: any) { - super(props); - - autoBind(this); - - this.convo = getConversationController().get(UserUtils.getOurPubKeyStrFromCache()); - - this.state = { - profileName: this.convo.getRealSessionUsername() || '', - updatedProfileName: this.convo.getRealSessionUsername() || '', - oldAvatarPath: this.convo.getAvatarPath() || '', - newAvatarObjectUrl: null, - mode: 'default', - loading: false, - }; - } +const commitProfileEdits = async (newName: string, scaledAvatarUrl: string | null) => { + const ourNumber = UserUtils.getOurPubKeyStrFromCache(); + const conversation = await getConversationController().getOrCreateAndWait( + ourNumber, + ConversationTypeEnum.PRIVATE + ); - public componentDidMount() { - window.addEventListener('keyup', this.onKeyUp); + if (scaledAvatarUrl?.length) { + try { + const blobContent = await (await fetch(scaledAvatarUrl)).blob(); + if (!blobContent || !blobContent.size) { + throw new Error('Failed to fetch blob content from scaled avatar'); + } + await uploadOurAvatar(await blobContent.arrayBuffer()); + } catch (error) { + if (error.message && error.message.length) { + ToastUtils.pushToastError('edit-profile', error.message); + } + window.log.error( + 'showEditProfileDialog Error ensuring that image is properly sized:', + error && error.stack ? error.stack : error + ); + } + return; } + // do not update the avatar if it did not change + conversation.setSessionDisplayNameNoCommit(newName); - public componentWillUnmount() { - window.removeEventListener('keyup', this.onKeyUp); - } + // might be good to not trigger a sync if the name did not change + await conversation.commit(); + await setLastProfileUpdateTimestamp(Date.now()); + await SyncUtils.forceSyncConfigurationNowIfNeeded(true); +}; - public render() { - const i18n = window.i18n; +type ProfileAvatarProps = { + newAvatarObjectUrl: string | null; + oldAvatarPath: string | null; + profileName: string | undefined; + ourId: string; +}; - const viewDefault = this.state.mode === 'default'; - const viewEdit = this.state.mode === 'edit'; - const viewQR = this.state.mode === 'qr'; +const ProfileAvatar = (props: ProfileAvatarProps): ReactElement => { + const { newAvatarObjectUrl, oldAvatarPath, profileName, ourId } = props; + return ( + + ); +}; - const sessionID = UserUtils.getOurPubKeyStrFromCache(); +type ProfileHeaderProps = ProfileAvatarProps & { + fireInputEvent: () => void; + setMode: (mode: ProfileDialogModes) => void; +}; - const backButton = - viewEdit || viewQR - ? [ - { - iconType: 'chevron', - iconRotation: 90, - onClick: () => { - this.setState({ mode: 'default' }); - }, - }, - ] - : undefined; +const ProfileHeader = (props: ProfileHeaderProps): ReactElement => { + const { newAvatarObjectUrl, oldAvatarPath, profileName, ourId, fireInputEvent, setMode } = props; - return ( -
- +
+ +
{ + void fireInputEvent(); + }} + data-testid="image-upload-section" + /> +
{ + setMode('qr'); + }} + role="button" > - {viewQR && } - {viewDefault && this.renderDefaultView()} - {viewEdit && this.renderEditView()} - -
- - - - - - {viewDefault || viewQR ? ( - { - window.clipboard.writeText(sessionID); - ToastUtils.pushCopiedToClipBoard(); - }} - dataTestId="copy-button-profile-update" - /> - ) : ( - !this.state.loading && ( - - ) - )} -
- -
- ); - } - - private renderProfileHeader() { - return ( - <> -
-
- {this.renderAvatar()} -
-
{ - this.setState(state => ({ ...state, mode: 'qr' })); - }} - role="button" - > - -
-
+
- - ); - } +
+
+ ); +}; - private async fireInputEvent() { - const scaledAvatarUrl = await pickFileForAvatar(); +type ProfileDialogModes = 'default' | 'edit' | 'qr'; - if (scaledAvatarUrl) { - this.setState({ - newAvatarObjectUrl: scaledAvatarUrl, - mode: 'edit', - }); - } - } +export const EditProfileDialog = (): ReactElement => { + const _profileName = useOurConversationUsername() || ''; + const [profileName, setProfileName] = useState(_profileName); + const [updatedProfileName, setUpdateProfileName] = useState(profileName); + const oldAvatarPath = useOurAvatarPath() || ''; + const [newAvatarObjectUrl, setNewAvatarObjectUrl] = useState(null); - private renderDefaultView() { - const name = this.state.updatedProfileName || this.state.profileName; - return ( - <> - {this.renderProfileHeader()} + const [mode, setMode] = useState('default'); + const [loading, setLoading] = useState(false); -
-

{name}

- { - this.setState({ mode: 'edit' }); - }} - dataTestId="edit-profile-icon" - /> -
- - ); - } + const ourId = UserUtils.getOurPubKeyStrFromCache(); - private renderEditView() { - const placeholderText = window.i18n('displayName'); + const closeDialog = () => { + window.removeEventListener('keyup', handleOnKeyUp); + window.inboxStore?.dispatch(editProfileModal(null)); + }; + + const backButton = + mode === 'edit' || mode === 'qr' + ? [ + { + iconType: 'chevron', + iconRotation: 90, + onClick: () => { + setMode('default'); + }, + }, + ] + : undefined; + + const onClickOK = async () => { + /** + * Tidy the profile name input text and save the new profile name and avatar + */ + try { + const newName = profileName ? profileName.trim() : ''; - return ( - <> - {this.renderProfileHeader()} -
- -
- - ); - } + if (newName.length === 0 || newName.length > MAX_USERNAME_BYTES) { + return; + } - private renderAvatar() { - const { oldAvatarPath, newAvatarObjectUrl, profileName } = this.state; - const userName = profileName || this.convo.id; + // this throw if the length in bytes is too long + const sanitizedName = sanitizeSessionUsername(newName); + const trimName = sanitizedName.trim(); - return ( - - ); - } + setUpdateProfileName(trimName); + setLoading(true); - private onNameEdited(event: ChangeEvent) { - const displayName = event.target.value; - try { - const newName = sanitizeSessionUsername(displayName); - this.setState({ - profileName: newName, - }); + await commitProfileEdits(newName, newAvatarObjectUrl); + setMode('default'); + setUpdateProfileName(profileName); + setLoading(false); } catch (e) { - this.setState({ - profileName: displayName, - }); ToastUtils.pushToastError('nameTooLong', window.i18n('displayNameTooLong')); } - } + }; - private onKeyUp(event: any) { + const handleOnKeyUp = (event: any) => { switch (event.key) { case 'Enter': - if (this.state.mode === 'edit') { - this.onClickOK(); + if (mode === 'edit') { + onClickOK(); } break; case 'Esc': case 'Escape': - this.closeDialog(); + closeDialog(); break; default: } - } + }; - /** - * Tidy the profile name input text and save the new profile name and avatar - */ - private onClickOK() { - const { newAvatarObjectUrl, profileName } = this.state; - try { - const newName = profileName ? profileName.trim() : ''; - - if (newName.length === 0 || newName.length > MAX_USERNAME_BYTES) { - return; - } - - // this throw if the length in bytes is too long - const sanitizedName = sanitizeSessionUsername(newName); - const trimName = sanitizedName.trim(); - - this.setState( - { - profileName: trimName, - loading: true, - }, - async () => { - await commitProfileEdits(newName, newAvatarObjectUrl); - this.setState({ - loading: false, + const fireInputEvent = async () => { + const scaledAvatarUrl = await pickFileForAvatar(); + if (scaledAvatarUrl) { + setNewAvatarObjectUrl(scaledAvatarUrl); + setMode('edit'); + } + }; - mode: 'default', - updatedProfileName: this.state.profileName, - }); - } - ); + const onNameEdited = (event: ChangeEvent) => { + const displayName = event.target.value; + try { + const newName = sanitizeSessionUsername(displayName); + setProfileName(newName); } catch (e) { + setProfileName(displayName); ToastUtils.pushToastError('nameTooLong', window.i18n('displayNameTooLong')); - - return; } - } + }; - private closeDialog() { - window.removeEventListener('keyup', this.onKeyUp); - window.inboxStore?.dispatch(editProfileModal(null)); - } -} + return ( +
+ + {mode === 'qr' && } + {mode === 'default' && ( + <> + +
+

{updatedProfileName || profileName}

+ { + setMode('edit'); + }} + dataTestId="edit-profile-icon" + /> +
+ + )} + {mode === 'edit' && ( + <> + +
+ +
+ + )} -async function commitProfileEdits(newName: string, scaledAvatarUrl: string | null) { - const ourNumber = UserUtils.getOurPubKeyStrFromCache(); - const conversation = await getConversationController().getOrCreateAndWait( - ourNumber, - ConversationTypeEnum.PRIVATE - ); +
+ + - if (scaledAvatarUrl?.length) { - try { - const blobContent = await (await fetch(scaledAvatarUrl)).blob(); - if (!blobContent || !blobContent.size) { - throw new Error('Failed to fetch blob content from scaled avatar'); - } - await uploadOurAvatar(await blobContent.arrayBuffer()); - } catch (error) { - if (error.message && error.message.length) { - ToastUtils.pushToastError('edit-profile', error.message); - } - window.log.error( - 'showEditProfileDialog Error ensuring that image is properly sized:', - error && error.stack ? error.stack : error - ); - } - return; - } - // do not update the avatar if it did not change - conversation.setSessionDisplayNameNoCommit(newName); + - // might be good to not trigger a sync if the name did not change - await conversation.commit(); - await setLastProfileUpdateTimestamp(Date.now()); - await SyncUtils.forceSyncConfigurationNowIfNeeded(true); -} + {mode === 'default' || mode === 'qr' ? ( + { + window.clipboard.writeText(ourId); + ToastUtils.pushCopiedToClipBoard(); + }} + dataTestId="copy-button-profile-update" + /> + ) : ( + !loading && ( + + ) + )} +
+
+
+ ); +}; From ebeaec20809ab7f7bf6235713627de32f49ced48 Mon Sep 17 00:00:00 2001 From: William Grant Date: Mon, 22 May 2023 17:49:54 +1000 Subject: [PATCH 02/24] feat: initial work for set display picture modal done still need to do logic and handle multiple modals on screen --- _locales/en/messages.json | 4 +- ts/components/dialog/DisplayPictureModal.tsx | 50 ++++++++++++++++++++ ts/components/dialog/EditProfileDialog.tsx | 14 +++--- ts/components/dialog/ModalContainer.tsx | 4 ++ ts/state/ducks/modalDialog.tsx | 8 ++++ ts/state/selectors/modal.ts | 6 +++ ts/types/LocalizerKeys.ts | 32 ++++++++++++- 7 files changed, 109 insertions(+), 9 deletions(-) create mode 100644 ts/components/dialog/DisplayPictureModal.tsx diff --git a/_locales/en/messages.json b/_locales/en/messages.json index e79bc63df..ec19331bd 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -507,5 +507,7 @@ "reactionPopupThree": "$name$, $name2$ & $name3$", "reactionPopupMany": "$name$, $name2$, $name3$ &", "reactionListCountSingular": "And $otherSingular$ has reacted $emoji$ to this message", - "reactionListCountPlural": "And $otherPlural$ have reacted $emoji$ to this message" + "reactionListCountPlural": "And $otherPlural$ have reacted $emoji$ to this message", + "setDisplayPicture": "Set Display Picture", + "upload": "Upload" } diff --git a/ts/components/dialog/DisplayPictureModal.tsx b/ts/components/dialog/DisplayPictureModal.tsx new file mode 100644 index 000000000..4da383a0a --- /dev/null +++ b/ts/components/dialog/DisplayPictureModal.tsx @@ -0,0 +1,50 @@ +import React, { ReactElement } from 'react'; +import { SessionWrapperModal } from '../SessionWrapperModal'; +import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton'; +import { Avatar, AvatarSize } from '../avatar/Avatar'; +import { SpacerLG } from '../basic/Text'; +import { UserUtils } from '../../session/utils'; +import { useDispatch } from 'react-redux'; +import { updateDisplayPictureModel } from '../../state/ducks/modalDialog'; + +type Props = {}; + +export const DisplayPictureModal = (props: Props): ReactElement => { + const {} = props; + const dispatch = useDispatch(); + + const onClickClose = () => { + dispatch(updateDisplayPictureModel(null)); + }; + + return ( + +
+
+ +
+
+ + + +
+ {}} + /> + {}} + /> +
+
+ ); +}; diff --git a/ts/components/dialog/EditProfileDialog.tsx b/ts/components/dialog/EditProfileDialog.tsx index 0f664633f..a076ca746 100644 --- a/ts/components/dialog/EditProfileDialog.tsx +++ b/ts/components/dialog/EditProfileDialog.tsx @@ -5,12 +5,10 @@ import { Avatar, AvatarSize } from '../avatar/Avatar'; import { SyncUtils, ToastUtils, UserUtils } from '../../session/utils'; import { YourSessionIDPill, YourSessionIDSelectable } from '../basic/YourSessionIDPill'; -import styled from 'styled-components'; -import { uploadOurAvatar } from '../../interactions/conversationInteractions'; -import { ConversationTypeEnum } from '../../models/conversationAttributes'; -import { MAX_USERNAME_BYTES } from '../../session/constants'; +import { SyncUtils, ToastUtils, UserUtils } from '../../session/utils'; + import { getConversationController } from '../../session/conversations'; -import { editProfileModal } from '../../state/ducks/modalDialog'; +import { editProfileModal, updateDisplayPictureModel } from '../../state/ducks/modalDialog'; import { pickFileForAvatar } from '../../types/attachments/VisualAttachment'; import { saveQRCode } from '../../util/saveQRCode'; import { setLastProfileUpdateTimestamp } from '../../util/storage'; @@ -21,6 +19,7 @@ import { SessionIconButton } from '../icon'; import { sanitizeSessionUsername } from '../../session/utils/String'; import { useOurConversationUsername } from '../../hooks/useParamSelector'; import { useOurAvatarPath } from '../../hooks/useParamSelector'; +import { useDispatch } from 'react-redux'; const handleSaveQRCode = (event: MouseEvent) => { event.preventDefault(); @@ -110,6 +109,8 @@ type ProfileHeaderProps = ProfileAvatarProps & { const ProfileHeader = (props: ProfileHeaderProps): ReactElement => { const { newAvatarObjectUrl, oldAvatarPath, profileName, ourId, fireInputEvent, setMode } = props; + const dispatch = useDispatch(); + return (
@@ -123,7 +124,8 @@ const ProfileHeader = (props: ProfileHeaderProps): ReactElement => { className="image-upload-section" role="button" onClick={async () => { - void fireInputEvent(); + // void fireInputEvent(); + dispatch(updateDisplayPictureModel({})); }} data-testid="image-upload-section" /> diff --git a/ts/components/dialog/ModalContainer.tsx b/ts/components/dialog/ModalContainer.tsx index d54bbe7e8..131f81495 100644 --- a/ts/components/dialog/ModalContainer.tsx +++ b/ts/components/dialog/ModalContainer.tsx @@ -7,6 +7,7 @@ import { getChangeNickNameDialog, getConfirmModal, getDeleteAccountModalState, + getDisplayPictureModalState, getEditProfileDialog, getInviteContactModal, getOnionPathDialog, @@ -36,6 +37,7 @@ import { SessionNicknameDialog } from './SessionNicknameDialog'; import { BanOrUnBanUserDialog } from './BanOrUnbanUserDialog'; import { ReactListModal } from './ReactListModal'; import { ReactClearAllModal } from './ReactClearAllModal'; +import { DisplayPictureModal } from './DisplayPictureModal'; export const ModalContainer = () => { const confirmModalState = useSelector(getConfirmModal); @@ -55,6 +57,7 @@ export const ModalContainer = () => { const banOrUnbanUserModalState = useSelector(getBanOrUnbanUserModalState); const reactListModalState = useSelector(getReactListDialog); const reactClearAllModalState = useSelector(getReactClearAllDialog); + const DisplayPictureModalState = useSelector(getDisplayPictureModalState); return ( <> @@ -79,6 +82,7 @@ export const ModalContainer = () => { {confirmModalState && } {reactListModalState && } {reactClearAllModalState && } + {DisplayPictureModalState && } ); }; diff --git a/ts/state/ducks/modalDialog.tsx b/ts/state/ducks/modalDialog.tsx index ea8428b70..53ba355d6 100644 --- a/ts/state/ducks/modalDialog.tsx +++ b/ts/state/ducks/modalDialog.tsx @@ -34,6 +34,8 @@ export type ReactModalsState = { messageId: string; } | null; +export type DisplayPictureModalState = {} | null; + export type ModalState = { confirmModal: ConfirmModalState; inviteContactModal: InviteContactModalState; @@ -52,6 +54,7 @@ export type ModalState = { deleteAccountModal: DeleteAccountModalState; reactListModalState: ReactModalsState; reactClearAllModalState: ReactModalsState; + displayPictureModalState: DisplayPictureModalState; }; export const initialModalState: ModalState = { @@ -72,6 +75,7 @@ export const initialModalState: ModalState = { deleteAccountModal: null, reactListModalState: null, reactClearAllModalState: null, + displayPictureModalState: null, }; const ModalSlice = createSlice({ @@ -129,6 +133,9 @@ const ModalSlice = createSlice({ updateReactClearAllModal(state, action: PayloadAction) { return { ...state, reactClearAllModalState: action.payload }; }, + updateDisplayPictureModel(state, action: PayloadAction) { + return { ...state, displayPictureModalState: action.payload }; + }, }, }); @@ -151,5 +158,6 @@ export const { updateBanOrUnbanUserModal, updateReactListModal, updateReactClearAllModal, + updateDisplayPictureModel, } = actions; export const modalReducer = reducer; diff --git a/ts/state/selectors/modal.ts b/ts/state/selectors/modal.ts index f959bc243..efb38e1a5 100644 --- a/ts/state/selectors/modal.ts +++ b/ts/state/selectors/modal.ts @@ -8,6 +8,7 @@ import { ChangeNickNameModalState, ConfirmModalState, DeleteAccountModalState, + DisplayPictureModalState, EditProfileModalState, InviteContactModalState, ModalState, @@ -109,3 +110,8 @@ export const getReactClearAllDialog = createSelector( getModal, (state: ModalState): ReactModalsState => state.reactClearAllModalState ); + +export const getDisplayPictureModalState = createSelector( + getModal, + (state: ModalState): DisplayPictureModalState => state.displayPictureModalState +); diff --git a/ts/types/LocalizerKeys.ts b/ts/types/LocalizerKeys.ts index d7a9cb14b..e8d58a0c5 100644 --- a/ts/types/LocalizerKeys.ts +++ b/ts/types/LocalizerKeys.ts @@ -506,5 +506,33 @@ export type LocalizerKeys = | 'reactionPopupTwo' | 'reactionPopupThree' | 'reactionPopupMany' - | 'reactionListCountSingular' - | 'reactionListCountPlural'; + | 'timerSetTo' + | 'iAmSure' + | 'primaryColorRed' + | 'selectMessage' + | 'enterAnOpenGroupURL' + | 'delete' + | 'changePasswordInvalid' + | 'themesSettingTitle' + | 'timerOption_6_hours' + | 'confirmPassword' + | 'downloadAttachment' + | 'trimDatabaseDescription' + | 'showUserDetails' + | 'titleIsNow' + | 'removePasswordToastDescription' + | 'recoveryPhrase' + | 'deleteAccountFromLogin' + | 'newMessages' + | 'you' + | 'pruneSettingTitle' + | 'unbanUser' + | 'notificationForConvo_mentions_only' + | 'trustThisContactDialogDescription' + | 'unknownCountry' + | 'searchFor...' + | 'displayNameTooLong' + | 'joinedTheGroup' + | 'editGroupName' + | 'reportIssue' + | 'setDisplayPicture'; From 88587a203d71d0731765de2f68b4dd7cf6603e99 Mon Sep 17 00:00:00 2001 From: William Grant Date: Tue, 23 May 2023 12:27:21 +1000 Subject: [PATCH 03/24] feat: added button state logic and migrated avatar upload logic from EditProfileDialog show loading spinner while avatar is loading --- ts/components/dialog/DisplayPictureModal.tsx | 101 ++++++++++++++++--- ts/components/dialog/EditProfileDialog.tsx | 37 ++++--- ts/state/ducks/modalDialog.tsx | 3 +- 3 files changed, 114 insertions(+), 27 deletions(-) diff --git a/ts/components/dialog/DisplayPictureModal.tsx b/ts/components/dialog/DisplayPictureModal.tsx index 4da383a0a..67f2e0ff3 100644 --- a/ts/components/dialog/DisplayPictureModal.tsx +++ b/ts/components/dialog/DisplayPictureModal.tsx @@ -1,48 +1,121 @@ -import React, { ReactElement } from 'react'; +import React, { useState } from 'react'; import { SessionWrapperModal } from '../SessionWrapperModal'; import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton'; -import { Avatar, AvatarSize } from '../avatar/Avatar'; import { SpacerLG } from '../basic/Text'; -import { UserUtils } from '../../session/utils'; import { useDispatch } from 'react-redux'; import { updateDisplayPictureModel } from '../../state/ducks/modalDialog'; +import { ProfileAvatar, ProfileAvatarProps } from './EditProfileDialog'; +import styled from 'styled-components'; +import { uploadOurAvatar } from '../../interactions/conversationInteractions'; +import { ToastUtils } from '../../session/utils'; +import { SessionSpinner } from '../basic/SessionSpinner'; -type Props = {}; +const StyledAvatarContainer = styled.div` + cursor: pointer; +`; -export const DisplayPictureModal = (props: Props): ReactElement => { - const {} = props; +const uploadProfileAvatar = async (scaledAvatarUrl: string | null) => { + if (scaledAvatarUrl?.length) { + try { + const blobContent = await (await fetch(scaledAvatarUrl)).blob(); + if (!blobContent || !blobContent.size) { + throw new Error('Failed to fetch blob content from scaled avatar'); + } + await uploadOurAvatar(await blobContent.arrayBuffer()); + } catch (error) { + if (error.message && error.message.length) { + ToastUtils.pushToastError('edit-profile', error.message); + } + window.log.error( + 'showEditProfileDialog Error ensuring that image is properly sized:', + error && error.stack ? error.stack : error + ); + } + } +}; + +export type DisplayPictureModalProps = ProfileAvatarProps & { + avatarAction: () => Promise; + removeAction: () => void; +}; + +export const DisplayPictureModal = (props: DisplayPictureModalProps) => { const dispatch = useDispatch(); - const onClickClose = () => { + if (!props) { + return null; + } + + const { + newAvatarObjectUrl: _newAvatarObjectUrl, + oldAvatarPath, + profileName, + ourId, + avatarAction, + removeAction, + } = props; + + const [newAvatarObjectUrl, setNewAvatarObjectUrl] = useState(_newAvatarObjectUrl); + const [loading, setLoading] = useState(false); + + const closeDialog = () => { dispatch(updateDisplayPictureModel(null)); }; return ( -
-
- -
+
{ + const updatedAvatarObjectUrl = await avatarAction(); + if (updatedAvatarObjectUrl) { + setNewAvatarObjectUrl(updatedAvatarObjectUrl); + } + }} + > + + +
+
{}} + onClick={async () => { + setLoading(true); + if (newAvatarObjectUrl === _newAvatarObjectUrl) { + window.log.debug(`Avatar Object URL has not changed!`); + return; + } + + await uploadProfileAvatar(newAvatarObjectUrl); + setLoading(false); + closeDialog(); + }} + disabled={_newAvatarObjectUrl === newAvatarObjectUrl} /> {}} + onClick={() => { + removeAction(); + }} + disabled={!oldAvatarPath} />
diff --git a/ts/components/dialog/EditProfileDialog.tsx b/ts/components/dialog/EditProfileDialog.tsx index a076ca746..94a0c45a5 100644 --- a/ts/components/dialog/EditProfileDialog.tsx +++ b/ts/components/dialog/EditProfileDialog.tsx @@ -82,14 +82,14 @@ const commitProfileEdits = async (newName: string, scaledAvatarUrl: string | nul await SyncUtils.forceSyncConfigurationNowIfNeeded(true); }; -type ProfileAvatarProps = { +export type ProfileAvatarProps = { newAvatarObjectUrl: string | null; oldAvatarPath: string | null; profileName: string | undefined; ourId: string; }; -const ProfileAvatar = (props: ProfileAvatarProps): ReactElement => { +export const ProfileAvatar = (props: ProfileAvatarProps): ReactElement => { const { newAvatarObjectUrl, oldAvatarPath, profileName, ourId } = props; return ( { }; type ProfileHeaderProps = ProfileAvatarProps & { - fireInputEvent: () => void; + onClick: () => void; setMode: (mode: ProfileDialogModes) => void; }; const ProfileHeader = (props: ProfileHeaderProps): ReactElement => { - const { newAvatarObjectUrl, oldAvatarPath, profileName, ourId, fireInputEvent, setMode } = props; - - const dispatch = useDispatch(); + const { newAvatarObjectUrl, oldAvatarPath, profileName, ourId, onClick, setMode } = props; return (
@@ -123,10 +121,7 @@ const ProfileHeader = (props: ProfileHeaderProps): ReactElement => {
{ - // void fireInputEvent(); - dispatch(updateDisplayPictureModel({})); - }} + onClick={onClick} data-testid="image-upload-section" />
{ type ProfileDialogModes = 'default' | 'edit' | 'qr'; export const EditProfileDialog = (): ReactElement => { + const dispatch = useDispatch(); + const _profileName = useOurConversationUsername() || ''; const [profileName, setProfileName] = useState(_profileName); const [updatedProfileName, setUpdateProfileName] = useState(profileName); @@ -223,6 +220,22 @@ export const EditProfileDialog = (): ReactElement => { setNewAvatarObjectUrl(scaledAvatarUrl); setMode('edit'); } + + return scaledAvatarUrl; + }; + + const handleProfileHeaderClick = () => { + closeDialog(); + dispatch( + updateDisplayPictureModel({ + newAvatarObjectUrl, + oldAvatarPath, + profileName, + ourId, + avatarAction: fireInputEvent, + removeAction: () => {}, + }) + ); }; const onNameEdited = (event: ChangeEvent) => { @@ -252,7 +265,7 @@ export const EditProfileDialog = (): ReactElement => { oldAvatarPath={oldAvatarPath} profileName={profileName} ourId={ourId} - fireInputEvent={fireInputEvent} + onClick={handleProfileHeaderClick} setMode={setMode} />
@@ -275,7 +288,7 @@ export const EditProfileDialog = (): ReactElement => { oldAvatarPath={oldAvatarPath} profileName={profileName} ourId={ourId} - fireInputEvent={fireInputEvent} + onClick={handleProfileHeaderClick} setMode={setMode} />
diff --git a/ts/state/ducks/modalDialog.tsx b/ts/state/ducks/modalDialog.tsx index 53ba355d6..238bf54ac 100644 --- a/ts/state/ducks/modalDialog.tsx +++ b/ts/state/ducks/modalDialog.tsx @@ -1,6 +1,7 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { SessionConfirmDialogProps } from '../../components/dialog/SessionConfirm'; import { PasswordAction } from '../../components/dialog/SessionPasswordDialog'; +import { DisplayPictureModalProps } from '../../components/dialog/DisplayPictureModal'; export type BanType = 'ban' | 'unban'; export type ConfirmModalState = SessionConfirmDialogProps | null; @@ -34,7 +35,7 @@ export type ReactModalsState = { messageId: string; } | null; -export type DisplayPictureModalState = {} | null; +export type DisplayPictureModalState = DisplayPictureModalProps | null; export type ModalState = { confirmModal: ConfirmModalState; From cb7c36e2e63c16f7e0146699c77df3f1dea6d10a Mon Sep 17 00:00:00 2001 From: William Grant Date: Tue, 23 May 2023 14:40:33 +1000 Subject: [PATCH 04/24] feat: initial remove profile work done --- ts/components/dialog/DisplayPictureModal.tsx | 15 +++++++++------ ts/components/dialog/EditProfileDialog.tsx | 1 - ts/interactions/conversationInteractions.ts | 18 ++++++++++++++++++ 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/ts/components/dialog/DisplayPictureModal.tsx b/ts/components/dialog/DisplayPictureModal.tsx index 67f2e0ff3..7cf18561b 100644 --- a/ts/components/dialog/DisplayPictureModal.tsx +++ b/ts/components/dialog/DisplayPictureModal.tsx @@ -6,7 +6,7 @@ import { useDispatch } from 'react-redux'; import { updateDisplayPictureModel } from '../../state/ducks/modalDialog'; import { ProfileAvatar, ProfileAvatarProps } from './EditProfileDialog'; import styled from 'styled-components'; -import { uploadOurAvatar } from '../../interactions/conversationInteractions'; +import { clearOurAvatar, uploadOurAvatar } from '../../interactions/conversationInteractions'; import { ToastUtils } from '../../session/utils'; import { SessionSpinner } from '../basic/SessionSpinner'; @@ -36,7 +36,6 @@ const uploadProfileAvatar = async (scaledAvatarUrl: string | null) => { export type DisplayPictureModalProps = ProfileAvatarProps & { avatarAction: () => Promise; - removeAction: () => void; }; export const DisplayPictureModal = (props: DisplayPictureModalProps) => { @@ -48,14 +47,14 @@ export const DisplayPictureModal = (props: DisplayPictureModalProps) => { const { newAvatarObjectUrl: _newAvatarObjectUrl, - oldAvatarPath, + oldAvatarPath: _oldAvatarPath, profileName, ourId, avatarAction, - removeAction, } = props; const [newAvatarObjectUrl, setNewAvatarObjectUrl] = useState(_newAvatarObjectUrl); + const [oldAvatarPath, setOldAvatarPath] = useState(_oldAvatarPath); const [loading, setLoading] = useState(false); const closeDialog = () => { @@ -112,8 +111,12 @@ export const DisplayPictureModal = (props: DisplayPictureModalProps) => { text={window.i18n('remove')} buttonColor={SessionButtonColor.Danger} buttonType={SessionButtonType.Simple} - onClick={() => { - removeAction(); + onClick={async () => { + setLoading(true); + await clearOurAvatar(); + setNewAvatarObjectUrl(null); + setOldAvatarPath(null); + setLoading(false); }} disabled={!oldAvatarPath} /> diff --git a/ts/components/dialog/EditProfileDialog.tsx b/ts/components/dialog/EditProfileDialog.tsx index 94a0c45a5..d502adc93 100644 --- a/ts/components/dialog/EditProfileDialog.tsx +++ b/ts/components/dialog/EditProfileDialog.tsx @@ -233,7 +233,6 @@ export const EditProfileDialog = (): ReactElement => { profileName, ourId, avatarAction: fireInputEvent, - removeAction: () => {}, }) ); }; diff --git a/ts/interactions/conversationInteractions.ts b/ts/interactions/conversationInteractions.ts index 6b6c7ca27..86a4df97c 100644 --- a/ts/interactions/conversationInteractions.ts +++ b/ts/interactions/conversationInteractions.ts @@ -487,6 +487,24 @@ export async function uploadOurAvatar(newAvatarDecrypted?: ArrayBuffer) { }; } +export async function clearOurAvatar() { + const ourConvo = getConversationController().get(UserUtils.getOurPubKeyStrFromCache()); + if (!ourConvo) { + window.log.warn('ourConvo not found... This is not a valid case'); + return; + } + + // TODO check if defined first + ourConvo.set('avatarPointer', undefined); + ourConvo.set('avatarInProfile', undefined); + ourConvo.set('profileKey', undefined); + + await ourConvo.commit(); + await SyncUtils.forceSyncConfigurationNowIfNeeded(true); + + // TODO send messages to opengroups to clear avatar from there +} + export async function replyToMessage(messageId: string) { const quotedMessageModel = await Data.getMessageById(messageId); if (!quotedMessageModel) { From 84d3d5b1b40477de203c22bbcc2a0b2f88292b39 Mon Sep 17 00:00:00 2001 From: William Grant Date: Tue, 23 May 2023 14:59:01 +1000 Subject: [PATCH 05/24] feat: small refactoring --- ts/components/dialog/DisplayPictureModal.tsx | 40 +++++++++++--------- ts/interactions/conversationInteractions.ts | 4 ++ 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/ts/components/dialog/DisplayPictureModal.tsx b/ts/components/dialog/DisplayPictureModal.tsx index 7cf18561b..96feefc74 100644 --- a/ts/components/dialog/DisplayPictureModal.tsx +++ b/ts/components/dialog/DisplayPictureModal.tsx @@ -61,6 +61,26 @@ export const DisplayPictureModal = (props: DisplayPictureModalProps) => { dispatch(updateDisplayPictureModel(null)); }; + const handleUpload = async () => { + setLoading(true); + if (newAvatarObjectUrl === _newAvatarObjectUrl) { + window.log.debug(`Avatar Object URL has not changed!`); + return; + } + + await uploadProfileAvatar(newAvatarObjectUrl); + setLoading(false); + closeDialog(); + }; + + const handleRemove = async () => { + setLoading(true); + await clearOurAvatar(); + setNewAvatarObjectUrl(null); + setOldAvatarPath(null); + setLoading(false); + }; + return ( { { - setLoading(true); - if (newAvatarObjectUrl === _newAvatarObjectUrl) { - window.log.debug(`Avatar Object URL has not changed!`); - return; - } - - await uploadProfileAvatar(newAvatarObjectUrl); - setLoading(false); - closeDialog(); - }} + onClick={handleUpload} disabled={_newAvatarObjectUrl === newAvatarObjectUrl} /> { - setLoading(true); - await clearOurAvatar(); - setNewAvatarObjectUrl(null); - setOldAvatarPath(null); - setLoading(false); - }} + onClick={handleRemove} disabled={!oldAvatarPath} />
diff --git a/ts/interactions/conversationInteractions.ts b/ts/interactions/conversationInteractions.ts index 86a4df97c..c85185766 100644 --- a/ts/interactions/conversationInteractions.ts +++ b/ts/interactions/conversationInteractions.ts @@ -487,6 +487,9 @@ export async function uploadOurAvatar(newAvatarDecrypted?: ArrayBuffer) { }; } +/** + * This function can be used for clearing our avatar. + */ export async function clearOurAvatar() { const ourConvo = getConversationController().get(UserUtils.getOurPubKeyStrFromCache()); if (!ourConvo) { @@ -500,6 +503,7 @@ export async function clearOurAvatar() { ourConvo.set('profileKey', undefined); await ourConvo.commit(); + await setLastProfileUpdateTimestamp(Date.now()); await SyncUtils.forceSyncConfigurationNowIfNeeded(true); // TODO send messages to opengroups to clear avatar from there From b59f1bf4453423e43323645921038b8b7074f3f5 Mon Sep 17 00:00:00 2001 From: William Grant Date: Tue, 23 May 2023 15:36:39 +1000 Subject: [PATCH 06/24] feat: desktop now supports avatar being removed via sync configuration message disabled buttons while loading --- ts/components/dialog/DisplayPictureModal.tsx | 5 +++-- ts/interactions/conversationInteractions.ts | 10 +++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/ts/components/dialog/DisplayPictureModal.tsx b/ts/components/dialog/DisplayPictureModal.tsx index 96feefc74..ab891b7d0 100644 --- a/ts/components/dialog/DisplayPictureModal.tsx +++ b/ts/components/dialog/DisplayPictureModal.tsx @@ -79,6 +79,7 @@ export const DisplayPictureModal = (props: DisplayPictureModalProps) => { setNewAvatarObjectUrl(null); setOldAvatarPath(null); setLoading(false); + closeDialog(); }; return ( @@ -115,14 +116,14 @@ export const DisplayPictureModal = (props: DisplayPictureModalProps) => { text={window.i18n('upload')} buttonType={SessionButtonType.Simple} onClick={handleUpload} - disabled={_newAvatarObjectUrl === newAvatarObjectUrl} + disabled={loading || _newAvatarObjectUrl === newAvatarObjectUrl} />
diff --git a/ts/interactions/conversationInteractions.ts b/ts/interactions/conversationInteractions.ts index c85185766..bbd0044e4 100644 --- a/ts/interactions/conversationInteractions.ts +++ b/ts/interactions/conversationInteractions.ts @@ -490,23 +490,23 @@ export async function uploadOurAvatar(newAvatarDecrypted?: ArrayBuffer) { /** * This function can be used for clearing our avatar. */ -export async function clearOurAvatar() { +export async function clearOurAvatar(commit: boolean = true) { const ourConvo = getConversationController().get(UserUtils.getOurPubKeyStrFromCache()); if (!ourConvo) { window.log.warn('ourConvo not found... This is not a valid case'); return; } - // TODO check if defined first ourConvo.set('avatarPointer', undefined); ourConvo.set('avatarInProfile', undefined); ourConvo.set('profileKey', undefined); - await ourConvo.commit(); await setLastProfileUpdateTimestamp(Date.now()); - await SyncUtils.forceSyncConfigurationNowIfNeeded(true); - // TODO send messages to opengroups to clear avatar from there + if (commit) { + await ourConvo.commit(); + await SyncUtils.forceSyncConfigurationNowIfNeeded(true); + } } export async function replyToMessage(messageId: string) { From c301eace4805a297537ebbe2bd91a0321ba5842c Mon Sep 17 00:00:00 2001 From: William Grant Date: Tue, 23 May 2023 16:06:45 +1000 Subject: [PATCH 07/24] feat: added proper typings to icons and added thumbnail icon confirmed support for svgs with multiple paths --- ts/components/icon/Icons.tsx | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/ts/components/icon/Icons.tsx b/ts/components/icon/Icons.tsx index 9f1f2c6b2..ebc5ff38b 100644 --- a/ts/components/icon/Icons.tsx +++ b/ts/components/icon/Icons.tsx @@ -64,6 +64,7 @@ export type SessionIconType = | 'doubleCheckCircle' | 'gallery' | 'stop' + | 'thumbnail' | 'timer00' | 'timer05' | 'timer10' @@ -81,7 +82,10 @@ export type SessionIconType = export type SessionIconSize = 'tiny' | 'small' | 'medium' | 'large' | 'huge' | 'huge2' | 'max'; -export const icons = { +export const icons: Record< + string, + { path: string | Array; viewBox: string; ratio: number } +> = { addUser: { path: 'M8.85,2.17c-1.73,0-3.12,1.4-3.12,3.12s1.4,3.12,3.12,3.12c1.73,0,3.13-1.4,3.13-3.12S10.58,2.17,8.85,2.17z M8.85,0.08c2.88,0,5.21,2.33,5.21,5.21s-2.33,5.21-5.21,5.21s-5.2-2.33-5.2-5.21C3.65,2.42,5.98,0.08,8.85,0.08z M20.83,5.29 c0.54,0,0.98,0.41,1.04,0.93l0.01,0.11v2.08h2.08c0.54,0,0.98,0.41,1.04,0.93v0.12c0,0.54-0.41,0.98-0.93,1.04l-0.11,0.01h-2.08 v2.08c0,0.58-0.47,1.04-1.04,1.04c-0.54,0-0.98-0.41-1.04-0.93l-0.01-0.11v-2.08h-2.08c-0.54,0-0.98-0.41-1.04-0.93l-0.01-0.11 c0-0.54,0.41-0.98,0.93-1.04l0.11-0.01h2.08V6.34C19.79,5.76,20.26,5.29,20.83,5.29z M12.5,12.58c2.8,0,5.09,2.21,5.2,4.99v0.22 v2.08c0,0.58-0.47,1.04-1.04,1.04c-0.54,0-0.98-0.41-1.04-0.93l-0.01-0.11v-2.08c0-1.67-1.3-3.03-2.95-3.12h-0.18H5.21 c-1.67,0-3.03,1.3-3.12,2.95v0.18v2.08c0,0.58-0.47,1.04-1.04,1.04c-0.54,0-0.98-0.41-1.04-0.93L0,19.88V17.8 c0-2.8,2.21-5.09,4.99-5.2h0.22h7.29V12.58z', @@ -473,6 +477,16 @@ export const icons = { viewBox: '-1 -1 35 35', ratio: 1, }, + thumbnail: { + path: [ + 'M34.915 23.8987L26.594 17.812C26.5393 17.7682 26.4714 17.7444 26.4014 17.7444C26.3313 17.7444 26.2634 17.7682 26.2087 17.812L18.748 23.9886C18.6905 24.0313 18.6207 24.0544 18.549 24.0544C18.4773 24.0544 18.4075 24.0313 18.35 23.9886L14.6003 20.9324C14.5468 20.8918 14.4814 20.8698 14.4141 20.8698C14.3469 20.8698 14.2815 20.8918 14.2279 20.9324L4.0706 28.1491C4.03144 28.1797 3.99959 28.2186 3.97737 28.263C3.95516 28.3075 3.94314 28.3563 3.94219 28.406V30.743C3.94549 30.9361 4.02366 31.1204 4.16022 31.257C4.29678 31.3935 4.48104 31.4717 4.67413 31.475H34.3115C34.5056 31.475 34.6918 31.3979 34.8291 31.2606C34.9663 31.1233 35.0434 30.9372 35.0434 30.743V24.1427C35.0447 24.0944 35.0335 24.0467 35.011 24.004C34.9885 23.9613 34.9555 23.925 34.915 23.8987Z', + 'M11.0947 18.7492C12.6904 18.7492 13.984 17.4556 13.984 15.8599C13.984 14.2642 12.6904 12.9707 11.0947 12.9707C9.49902 12.9707 8.20546 14.2642 8.20546 15.8599C8.20546 17.4556 9.49902 18.7492 11.0947 18.7492Z', + 'M40.3597 4.62408L8.19261 0.874467C7.77128 0.822682 7.34385 0.855312 6.93527 0.970455C6.52668 1.0856 6.14511 1.28095 5.81282 1.54511C5.48052 1.80927 5.20415 2.13696 4.99984 2.50905C4.79552 2.88115 4.66734 3.2902 4.62277 3.71236L4.46868 5.0992H7.03691L7.16532 4.00771C7.17565 3.92437 7.20256 3.84394 7.24446 3.77116C7.28637 3.69838 7.34241 3.63473 7.4093 3.58395C7.51881 3.496 7.65413 3.44638 7.79454 3.4427H7.85874L22.1509 5.0992H35.6855C36.4753 5.10365 37.2535 5.29018 37.9595 5.64429C38.6655 5.99841 39.2803 6.51056 39.7561 7.14095H40.0643C40.2326 7.16031 40.3865 7.24541 40.4923 7.37771C40.5981 7.51 40.6474 7.67876 40.6293 7.84721L40.5395 8.57915C40.7184 9.09576 40.8138 9.63762 40.822 10.1843V28.4958L43.1847 8.18108C43.2788 7.33533 43.0345 6.48672 42.5053 5.82036C41.976 5.154 41.2048 4.72397 40.3597 4.62408Z', + 'M35.6855 35.3016H3.30013C2.44871 35.3016 1.63216 34.9634 1.03011 34.3613C0.428069 33.7593 0.0898438 32.9427 0.0898438 32.0913V10.2614C0.0898438 9.40994 0.428069 8.59339 1.03011 7.99135C1.63216 7.3893 2.44871 7.05108 3.30013 7.05108H35.6855C36.5369 7.05108 37.3535 7.3893 37.9555 7.99135C38.5576 8.59339 38.8958 9.40994 38.8958 10.2614V32.0913C38.8958 32.9427 38.5576 33.7593 37.9555 34.3613C37.3535 34.9634 36.5369 35.3016 35.6855 35.3016ZM3.30013 9.59363C3.12985 9.59363 2.96654 9.66127 2.84613 9.78168C2.72572 9.90209 2.65807 10.0654 2.65807 10.2357V32.0656C2.65807 32.2359 2.72572 32.3992 2.84613 32.5196C2.96654 32.64 3.12985 32.7077 3.30013 32.7077H35.6855C35.8558 32.7077 36.0191 32.64 36.1395 32.5196C36.2599 32.3992 36.3276 32.2359 36.3276 32.0656V10.2357C36.3276 10.0654 36.2599 9.90209 36.1395 9.78168C36.0191 9.66127 35.8558 9.59363 35.6855 9.59363H3.30013Z', + ], + viewBox: '0 0 44 36', + ratio: 1, + }, timer00: { path: 'M11.428367,3.44328115 L10.5587469,3.94535651 C10.4906607,3.79477198 10.4145019,3.64614153 10.330127,3.5 C10.2457522,3.35385847 10.1551138,3.21358774 10.0587469,3.07933111 L10.928367,2.57725574 C11.0225793,2.71323387 11.1119641,2.85418158 11.1961524,3 C11.2803407,3.14581842 11.3577126,3.2937018 11.428367,3.44328115 Z M9.42274426,1.07163304 L8.92066889,1.94125309 C8.78641226,1.84488615 8.64614153,1.75424783 8.5,1.66987298 C8.35385847,1.58549813 8.20522802,1.50933927 8.05464349,1.44125309 L8.55671885,0.571633044 C8.7062982,0.642287382 8.85418158,0.719659271 9,0.803847577 C9.14581842,0.888035884 9.28676613,0.977420696 9.42274426,1.07163304 Z M11.9794631,6.5 L10.9753124,6.5 C10.9916403,6.33554688 11,6.1687497 11,6 C11,5.8312503 10.9916403,5.66445312 10.9753124,5.5 L11.9794631,5.5 C11.9930643,5.66486669 12,5.83162339 12,6 C12,6.16837661 11.9930643,6.33513331 11.9794631,6.5 Z M10.928367,9.42274426 L10.0587469,8.92066889 C10.1551138,8.78641226 10.2457522,8.64614153 10.330127,8.5 C10.4145019,8.35385847 10.4906607,8.20522802 10.5587469,8.05464349 L11.428367,8.55671885 C11.3577126,8.7062982 11.2803407,8.85418158 11.1961524,9 C11.1119641,9.14581842 11.0225793,9.28676613 10.928367,9.42274426 Z M8.55671885,11.428367 L8.05464349,10.5587469 C8.20522802,10.4906607 8.35385847,10.4145019 8.5,10.330127 C8.64614153,10.2457522 8.78641226,10.1551138 8.92066889,10.0587469 L9.42274426,10.928367 C9.28676613,11.0225793 9.14581842,11.1119641 9,11.1961524 C8.85418158,11.2803407 8.7062982,11.3577126 8.55671885,11.428367 Z M2.57725574,10.928367 L3.07933111,10.0587469 C3.21358774,10.1551138 3.35385847,10.2457522 3.5,10.330127 C3.64614153,10.4145019 3.79477198,10.4906607 3.94535651,10.5587469 L3.44328115,11.428367 C3.2937018,11.3577126 3.14581842,11.2803407 3,11.1961524 C2.85418158,11.1119641 2.71323387,11.0225793 2.57725574,10.928367 Z M5.5,11.9794631 L5.5,10.9753124 C5.66445312,10.9916403 5.8312503,11 6,11 C6.1687497,11 6.33554688,10.9916403 6.5,10.9753124 L6.5,11.9794631 C6.33513331,11.9930643 6.16837661,12 6,12 C5.83162339,12 5.66486669,11.9930643 5.5,11.9794631 Z M0.571633044,8.55671885 L1.44125309,8.05464349 C1.50933927,8.20522802 1.58549813,8.35385847 1.66987298,8.5 C1.75424783,8.64614153 1.84488615,8.78641226 1.94125309,8.92066889 L1.07163304,9.42274426 C0.977420696,9.28676613 0.888035884,9.14581842 0.803847577,9 C0.719659271,8.85418158 0.642287382,8.7062982 0.571633044,8.55671885 Z M0.0205368885,5.5 L1.02468762,5.5 C1.00835972,5.66445312 1,5.8312503 1,6 C1,6.1687497 1.00835972,6.33554688 1.02468762,6.5 L0.0205368885,6.5 C0.00693566443,6.33513331 -9.95062878e-13,6.16837661 -9.95093808e-13,6 C-9.95124738e-13,5.83162339 0.00693566443,5.66486669 0.0205368885,5.5 Z M1.07163304,2.57725574 L1.94125309,3.07933111 C1.84488615,3.21358774 1.75424783,3.35385847 1.66987298,3.5 C1.58549813,3.64614153 1.50933927,3.79477198 1.44125309,3.94535651 L0.571633044,3.44328115 C0.642287382,3.2937018 0.719659271,3.14581842 0.803847577,3 C0.888035884,2.85418158 0.977420696,2.71323387 1.07163304,2.57725574 Z M3.44328115,0.571633044 L3.94535651,1.44125309 C3.79477198,1.50933927 3.64614153,1.58549813 3.5,1.66987298 C3.35385847,1.75424783 3.21358774,1.84488615 3.07933111,1.94125309 L2.57725574,1.07163304 C2.71323387,0.977420696 2.85418158,0.888035884 3,0.803847577 C3.14581842,0.719659271 3.2937018,0.642287382 3.44328115,0.571633044 Z M6.5,0.0205368885 L6.5,7 L5.5,7 L5.5,0.0205368885 C5.66486669,0.00693566443 5.83162339,5.01e-14 6,5.01e-14 C6.16837661,5.01e-14 6.33513331,0.00693566443 6.5,0.0205368885 Z', From 3a0b7d1c724119bfff79a2fc4f16188fc6669822 Mon Sep 17 00:00:00 2001 From: William Grant Date: Tue, 23 May 2023 16:25:21 +1000 Subject: [PATCH 08/24] feat: added upload image button if user doesn't have an avatar set --- ts/components/dialog/DisplayPictureModal.tsx | 43 ++++++++++++++++---- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/ts/components/dialog/DisplayPictureModal.tsx b/ts/components/dialog/DisplayPictureModal.tsx index ab891b7d0..4049cc22b 100644 --- a/ts/components/dialog/DisplayPictureModal.tsx +++ b/ts/components/dialog/DisplayPictureModal.tsx @@ -9,11 +9,36 @@ import styled from 'styled-components'; import { clearOurAvatar, uploadOurAvatar } from '../../interactions/conversationInteractions'; import { ToastUtils } from '../../session/utils'; import { SessionSpinner } from '../basic/SessionSpinner'; +import { SessionIconButton } from '../icon'; const StyledAvatarContainer = styled.div` cursor: pointer; `; +const UploadImageButton = () => { + return ( +
+
+ +
+ +
+ ); +}; + const uploadProfileAvatar = async (scaledAvatarUrl: string | null) => { if (scaledAvatarUrl?.length) { try { @@ -99,12 +124,16 @@ export const DisplayPictureModal = (props: DisplayPictureModalProps) => { }} > - + {newAvatarObjectUrl || oldAvatarPath ? ( + + ) : ( + + )}
@@ -113,7 +142,7 @@ export const DisplayPictureModal = (props: DisplayPictureModalProps) => {
Date: Tue, 23 May 2023 16:49:19 +1000 Subject: [PATCH 09/24] fix: moved all avatar logic from editProfileDialog to DisplayPictureModal --- ts/components/dialog/DisplayPictureModal.tsx | 49 ++++++++--------- ts/components/dialog/EditProfileDialog.tsx | 57 ++++---------------- 2 files changed, 31 insertions(+), 75 deletions(-) diff --git a/ts/components/dialog/DisplayPictureModal.tsx b/ts/components/dialog/DisplayPictureModal.tsx index 4049cc22b..7ed5b60e6 100644 --- a/ts/components/dialog/DisplayPictureModal.tsx +++ b/ts/components/dialog/DisplayPictureModal.tsx @@ -3,13 +3,14 @@ import { SessionWrapperModal } from '../SessionWrapperModal'; import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton'; import { SpacerLG } from '../basic/Text'; import { useDispatch } from 'react-redux'; -import { updateDisplayPictureModel } from '../../state/ducks/modalDialog'; -import { ProfileAvatar, ProfileAvatarProps } from './EditProfileDialog'; +import { editProfileModal, updateDisplayPictureModel } from '../../state/ducks/modalDialog'; +import { ProfileAvatar } from './EditProfileDialog'; import styled from 'styled-components'; import { clearOurAvatar, uploadOurAvatar } from '../../interactions/conversationInteractions'; import { ToastUtils } from '../../session/utils'; import { SessionSpinner } from '../basic/SessionSpinner'; import { SessionIconButton } from '../icon'; +import { pickFileForAvatar } from '../../types/attachments/VisualAttachment'; const StyledAvatarContainer = styled.div` cursor: pointer; @@ -59,8 +60,10 @@ const uploadProfileAvatar = async (scaledAvatarUrl: string | null) => { } }; -export type DisplayPictureModalProps = ProfileAvatarProps & { - avatarAction: () => Promise; +export type DisplayPictureModalProps = { + oldAvatarPath: string | null; + profileName: string | undefined; + ourId: string; }; export const DisplayPictureModal = (props: DisplayPictureModalProps) => { @@ -70,41 +73,41 @@ export const DisplayPictureModal = (props: DisplayPictureModalProps) => { return null; } - const { - newAvatarObjectUrl: _newAvatarObjectUrl, - oldAvatarPath: _oldAvatarPath, - profileName, - ourId, - avatarAction, - } = props; + const { oldAvatarPath, profileName, ourId } = props; - const [newAvatarObjectUrl, setNewAvatarObjectUrl] = useState(_newAvatarObjectUrl); - const [oldAvatarPath, setOldAvatarPath] = useState(_oldAvatarPath); + const [newAvatarObjectUrl, setNewAvatarObjectUrl] = useState(oldAvatarPath); const [loading, setLoading] = useState(false); const closeDialog = () => { dispatch(updateDisplayPictureModel(null)); + dispatch(editProfileModal({})); + }; + + const handleAvatarClick = async () => { + const updatedAvatarObjectUrl = await pickFileForAvatar(); + if (updatedAvatarObjectUrl) { + setNewAvatarObjectUrl(updatedAvatarObjectUrl); + } }; const handleUpload = async () => { setLoading(true); - if (newAvatarObjectUrl === _newAvatarObjectUrl) { + if (newAvatarObjectUrl === oldAvatarPath) { window.log.debug(`Avatar Object URL has not changed!`); return; } await uploadProfileAvatar(newAvatarObjectUrl); setLoading(false); - closeDialog(); + dispatch(updateDisplayPictureModel(null)); }; const handleRemove = async () => { setLoading(true); await clearOurAvatar(); setNewAvatarObjectUrl(null); - setOldAvatarPath(null); setLoading(false); - closeDialog(); + dispatch(updateDisplayPictureModel(null)); }; return ( @@ -114,15 +117,7 @@ export const DisplayPictureModal = (props: DisplayPictureModalProps) => { showHeader={true} showExitIcon={true} > -
{ - const updatedAvatarObjectUrl = await avatarAction(); - if (updatedAvatarObjectUrl) { - setNewAvatarObjectUrl(updatedAvatarObjectUrl); - } - }} - > +
{newAvatarObjectUrl || oldAvatarPath ? ( { text={window.i18n('save')} buttonType={SessionButtonType.Simple} onClick={handleUpload} - disabled={loading || _newAvatarObjectUrl === newAvatarObjectUrl} + disabled={loading || newAvatarObjectUrl === oldAvatarPath} /> { event.preventDefault(); @@ -48,32 +49,12 @@ const QRView = ({ sessionID }: { sessionID: string }) => { ); }; -const commitProfileEdits = async (newName: string, scaledAvatarUrl: string | null) => { +const updateDisplayName = async (newName: string) => { const ourNumber = UserUtils.getOurPubKeyStrFromCache(); const conversation = await getConversationController().getOrCreateAndWait( ourNumber, ConversationTypeEnum.PRIVATE ); - - if (scaledAvatarUrl?.length) { - try { - const blobContent = await (await fetch(scaledAvatarUrl)).blob(); - if (!blobContent || !blobContent.size) { - throw new Error('Failed to fetch blob content from scaled avatar'); - } - await uploadOurAvatar(await blobContent.arrayBuffer()); - } catch (error) { - if (error.message && error.message.length) { - ToastUtils.pushToastError('edit-profile', error.message); - } - window.log.error( - 'showEditProfileDialog Error ensuring that image is properly sized:', - error && error.stack ? error.stack : error - ); - } - return; - } - // do not update the avatar if it did not change conversation.setSessionDisplayNameNoCommit(newName); // might be good to not trigger a sync if the name did not change @@ -82,8 +63,8 @@ const commitProfileEdits = async (newName: string, scaledAvatarUrl: string | nul await SyncUtils.forceSyncConfigurationNowIfNeeded(true); }; -export type ProfileAvatarProps = { - newAvatarObjectUrl: string | null; +type ProfileAvatarProps = { + newAvatarObjectUrl?: string | null; oldAvatarPath: string | null; profileName: string | undefined; ourId: string; @@ -107,17 +88,12 @@ type ProfileHeaderProps = ProfileAvatarProps & { }; const ProfileHeader = (props: ProfileHeaderProps): ReactElement => { - const { newAvatarObjectUrl, oldAvatarPath, profileName, ourId, onClick, setMode } = props; + const { oldAvatarPath, profileName, ourId, onClick, setMode } = props; return (
- +
{ const [profileName, setProfileName] = useState(_profileName); const [updatedProfileName, setUpdateProfileName] = useState(profileName); const oldAvatarPath = useOurAvatarPath() || ''; - const [newAvatarObjectUrl, setNewAvatarObjectUrl] = useState(null); const [mode, setMode] = useState('default'); const [loading, setLoading] = useState(false); @@ -190,7 +165,7 @@ export const EditProfileDialog = (): ReactElement => { setUpdateProfileName(trimName); setLoading(true); - await commitProfileEdits(newName, newAvatarObjectUrl); + await updateDisplayName(newName); setMode('default'); setUpdateProfileName(profileName); setLoading(false); @@ -214,25 +189,13 @@ export const EditProfileDialog = (): ReactElement => { } }; - const fireInputEvent = async () => { - const scaledAvatarUrl = await pickFileForAvatar(); - if (scaledAvatarUrl) { - setNewAvatarObjectUrl(scaledAvatarUrl); - setMode('edit'); - } - - return scaledAvatarUrl; - }; - const handleProfileHeaderClick = () => { closeDialog(); dispatch( updateDisplayPictureModel({ - newAvatarObjectUrl, oldAvatarPath, profileName, ourId, - avatarAction: fireInputEvent, }) ); }; @@ -260,7 +223,6 @@ export const EditProfileDialog = (): ReactElement => { {mode === 'default' && ( <> { {mode === 'edit' && ( <> Date: Tue, 23 May 2023 16:56:25 +1000 Subject: [PATCH 10/24] fix: rename oldAvatarPath to avatarPath for clarity --- ts/components/dialog/DisplayPictureModal.tsx | 52 +++++++++++--------- ts/components/dialog/EditProfileDialog.tsx | 21 ++++---- 2 files changed, 38 insertions(+), 35 deletions(-) diff --git a/ts/components/dialog/DisplayPictureModal.tsx b/ts/components/dialog/DisplayPictureModal.tsx index 7ed5b60e6..47a124bbf 100644 --- a/ts/components/dialog/DisplayPictureModal.tsx +++ b/ts/components/dialog/DisplayPictureModal.tsx @@ -61,7 +61,7 @@ const uploadProfileAvatar = async (scaledAvatarUrl: string | null) => { }; export type DisplayPictureModalProps = { - oldAvatarPath: string | null; + avatarPath: string | null; profileName: string | undefined; ourId: string; }; @@ -73,9 +73,9 @@ export const DisplayPictureModal = (props: DisplayPictureModalProps) => { return null; } - const { oldAvatarPath, profileName, ourId } = props; + const { avatarPath, profileName, ourId } = props; - const [newAvatarObjectUrl, setNewAvatarObjectUrl] = useState(oldAvatarPath); + const [newAvatarObjectUrl, setNewAvatarObjectUrl] = useState(avatarPath); const [loading, setLoading] = useState(false); const closeDialog = () => { @@ -92,7 +92,7 @@ export const DisplayPictureModal = (props: DisplayPictureModalProps) => { const handleUpload = async () => { setLoading(true); - if (newAvatarObjectUrl === oldAvatarPath) { + if (newAvatarObjectUrl === avatarPath) { window.log.debug(`Avatar Object URL has not changed!`); return; } @@ -119,10 +119,10 @@ export const DisplayPictureModal = (props: DisplayPictureModalProps) => { >
- {newAvatarObjectUrl || oldAvatarPath ? ( + {newAvatarObjectUrl || avatarPath ? ( @@ -132,24 +132,28 @@ export const DisplayPictureModal = (props: DisplayPictureModalProps) => {
- - - -
- - -
+ {loading ? ( + + ) : ( + <> + +
+ + +
+ + )} ); }; diff --git a/ts/components/dialog/EditProfileDialog.tsx b/ts/components/dialog/EditProfileDialog.tsx index 1742d64e1..bf5f80343 100644 --- a/ts/components/dialog/EditProfileDialog.tsx +++ b/ts/components/dialog/EditProfileDialog.tsx @@ -64,17 +64,17 @@ const updateDisplayName = async (newName: string) => { }; type ProfileAvatarProps = { + avatarPath: string | null; newAvatarObjectUrl?: string | null; - oldAvatarPath: string | null; profileName: string | undefined; ourId: string; }; export const ProfileAvatar = (props: ProfileAvatarProps): ReactElement => { - const { newAvatarObjectUrl, oldAvatarPath, profileName, ourId } = props; + const { newAvatarObjectUrl, avatarPath, profileName, ourId } = props; return ( { - const { oldAvatarPath, profileName, ourId, onClick, setMode } = props; + const { avatarPath, profileName, ourId, onClick, setMode } = props; return (
- +
{ const _profileName = useOurConversationUsername() || ''; const [profileName, setProfileName] = useState(_profileName); const [updatedProfileName, setUpdateProfileName] = useState(profileName); - const oldAvatarPath = useOurAvatarPath() || ''; + const avatarPath = useOurAvatarPath() || ''; + const ourId = UserUtils.getOurPubKeyStrFromCache(); const [mode, setMode] = useState('default'); const [loading, setLoading] = useState(false); - const ourId = UserUtils.getOurPubKeyStrFromCache(); - const closeDialog = () => { window.removeEventListener('keyup', handleOnKeyUp); window.inboxStore?.dispatch(editProfileModal(null)); @@ -193,7 +192,7 @@ export const EditProfileDialog = (): ReactElement => { closeDialog(); dispatch( updateDisplayPictureModel({ - oldAvatarPath, + avatarPath, profileName, ourId, }) @@ -223,7 +222,7 @@ export const EditProfileDialog = (): ReactElement => { {mode === 'default' && ( <> { {mode === 'edit' && ( <> Date: Tue, 23 May 2023 17:01:56 +1000 Subject: [PATCH 11/24] refactor: rename DisplayPictureModal to EditProfilePictureModal --- ts/components/dialog/EditProfileDialog.tsx | 4 ++-- ...yPictureModal.tsx => EditProfilePictureModal.tsx} | 12 ++++++------ ts/components/dialog/ModalContainer.tsx | 10 ++++++---- ts/state/ducks/modalDialog.tsx | 10 +++++----- ts/state/selectors/modal.ts | 6 +++--- 5 files changed, 22 insertions(+), 20 deletions(-) rename ts/components/dialog/{DisplayPictureModal.tsx => EditProfilePictureModal.tsx} (92%) diff --git a/ts/components/dialog/EditProfileDialog.tsx b/ts/components/dialog/EditProfileDialog.tsx index bf5f80343..3b5b4e848 100644 --- a/ts/components/dialog/EditProfileDialog.tsx +++ b/ts/components/dialog/EditProfileDialog.tsx @@ -7,7 +7,7 @@ import { SyncUtils, ToastUtils, UserUtils } from '../../session/utils'; import { YourSessionIDPill, YourSessionIDSelectable } from '../basic/YourSessionIDPill'; import { getConversationController } from '../../session/conversations'; -import { editProfileModal, updateDisplayPictureModel } from '../../state/ducks/modalDialog'; +import { editProfileModal, updateEditProfilePictureModel } from '../../state/ducks/modalDialog'; import { saveQRCode } from '../../util/saveQRCode'; import { setLastProfileUpdateTimestamp } from '../../util/storage'; import { SessionWrapperModal } from '../SessionWrapperModal'; @@ -191,7 +191,7 @@ export const EditProfileDialog = (): ReactElement => { const handleProfileHeaderClick = () => { closeDialog(); dispatch( - updateDisplayPictureModel({ + updateEditProfilePictureModel({ avatarPath, profileName, ourId, diff --git a/ts/components/dialog/DisplayPictureModal.tsx b/ts/components/dialog/EditProfilePictureModal.tsx similarity index 92% rename from ts/components/dialog/DisplayPictureModal.tsx rename to ts/components/dialog/EditProfilePictureModal.tsx index 47a124bbf..187ddb604 100644 --- a/ts/components/dialog/DisplayPictureModal.tsx +++ b/ts/components/dialog/EditProfilePictureModal.tsx @@ -3,7 +3,7 @@ import { SessionWrapperModal } from '../SessionWrapperModal'; import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton'; import { SpacerLG } from '../basic/Text'; import { useDispatch } from 'react-redux'; -import { editProfileModal, updateDisplayPictureModel } from '../../state/ducks/modalDialog'; +import { editProfileModal, updateEditProfilePictureModel } from '../../state/ducks/modalDialog'; import { ProfileAvatar } from './EditProfileDialog'; import styled from 'styled-components'; import { clearOurAvatar, uploadOurAvatar } from '../../interactions/conversationInteractions'; @@ -60,13 +60,13 @@ const uploadProfileAvatar = async (scaledAvatarUrl: string | null) => { } }; -export type DisplayPictureModalProps = { +export type EditProfilePictureModalProps = { avatarPath: string | null; profileName: string | undefined; ourId: string; }; -export const DisplayPictureModal = (props: DisplayPictureModalProps) => { +export const EditProfilePictureModal = (props: EditProfilePictureModalProps) => { const dispatch = useDispatch(); if (!props) { @@ -79,7 +79,7 @@ export const DisplayPictureModal = (props: DisplayPictureModalProps) => { const [loading, setLoading] = useState(false); const closeDialog = () => { - dispatch(updateDisplayPictureModel(null)); + dispatch(updateEditProfilePictureModel(null)); dispatch(editProfileModal({})); }; @@ -99,7 +99,7 @@ export const DisplayPictureModal = (props: DisplayPictureModalProps) => { await uploadProfileAvatar(newAvatarObjectUrl); setLoading(false); - dispatch(updateDisplayPictureModel(null)); + dispatch(updateEditProfilePictureModel(null)); }; const handleRemove = async () => { @@ -107,7 +107,7 @@ export const DisplayPictureModal = (props: DisplayPictureModalProps) => { await clearOurAvatar(); setNewAvatarObjectUrl(null); setLoading(false); - dispatch(updateDisplayPictureModel(null)); + dispatch(updateEditProfilePictureModel(null)); }; return ( diff --git a/ts/components/dialog/ModalContainer.tsx b/ts/components/dialog/ModalContainer.tsx index 131f81495..b7f5f32a3 100644 --- a/ts/components/dialog/ModalContainer.tsx +++ b/ts/components/dialog/ModalContainer.tsx @@ -7,7 +7,7 @@ import { getChangeNickNameDialog, getConfirmModal, getDeleteAccountModalState, - getDisplayPictureModalState, + getEditProfilePictureModalState, getEditProfileDialog, getInviteContactModal, getOnionPathDialog, @@ -37,7 +37,7 @@ import { SessionNicknameDialog } from './SessionNicknameDialog'; import { BanOrUnBanUserDialog } from './BanOrUnbanUserDialog'; import { ReactListModal } from './ReactListModal'; import { ReactClearAllModal } from './ReactClearAllModal'; -import { DisplayPictureModal } from './DisplayPictureModal'; +import { EditProfilePictureModal } from './EditProfilePictureModal'; export const ModalContainer = () => { const confirmModalState = useSelector(getConfirmModal); @@ -57,7 +57,7 @@ export const ModalContainer = () => { const banOrUnbanUserModalState = useSelector(getBanOrUnbanUserModalState); const reactListModalState = useSelector(getReactListDialog); const reactClearAllModalState = useSelector(getReactClearAllDialog); - const DisplayPictureModalState = useSelector(getDisplayPictureModalState); + const EditProfilePictureModalState = useSelector(getEditProfilePictureModalState); return ( <> @@ -82,7 +82,9 @@ export const ModalContainer = () => { {confirmModalState && } {reactListModalState && } {reactClearAllModalState && } - {DisplayPictureModalState && } + {EditProfilePictureModalState && ( + + )} ); }; diff --git a/ts/state/ducks/modalDialog.tsx b/ts/state/ducks/modalDialog.tsx index 238bf54ac..8cd86097a 100644 --- a/ts/state/ducks/modalDialog.tsx +++ b/ts/state/ducks/modalDialog.tsx @@ -1,7 +1,7 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import { SessionConfirmDialogProps } from '../../components/dialog/SessionConfirm'; import { PasswordAction } from '../../components/dialog/SessionPasswordDialog'; -import { DisplayPictureModalProps } from '../../components/dialog/DisplayPictureModal'; +import { EditProfilePictureModalProps } from '../../components/dialog/EditProfilePictureModal'; export type BanType = 'ban' | 'unban'; export type ConfirmModalState = SessionConfirmDialogProps | null; @@ -35,7 +35,7 @@ export type ReactModalsState = { messageId: string; } | null; -export type DisplayPictureModalState = DisplayPictureModalProps | null; +export type EditProfilePictureModalState = EditProfilePictureModalProps | null; export type ModalState = { confirmModal: ConfirmModalState; @@ -55,7 +55,7 @@ export type ModalState = { deleteAccountModal: DeleteAccountModalState; reactListModalState: ReactModalsState; reactClearAllModalState: ReactModalsState; - displayPictureModalState: DisplayPictureModalState; + displayPictureModalState: EditProfilePictureModalState; }; export const initialModalState: ModalState = { @@ -134,7 +134,7 @@ const ModalSlice = createSlice({ updateReactClearAllModal(state, action: PayloadAction) { return { ...state, reactClearAllModalState: action.payload }; }, - updateDisplayPictureModel(state, action: PayloadAction) { + updateEditProfilePictureModel(state, action: PayloadAction) { return { ...state, displayPictureModalState: action.payload }; }, }, @@ -159,6 +159,6 @@ export const { updateBanOrUnbanUserModal, updateReactListModal, updateReactClearAllModal, - updateDisplayPictureModel, + updateEditProfilePictureModel, } = actions; export const modalReducer = reducer; diff --git a/ts/state/selectors/modal.ts b/ts/state/selectors/modal.ts index efb38e1a5..8b12869c5 100644 --- a/ts/state/selectors/modal.ts +++ b/ts/state/selectors/modal.ts @@ -8,7 +8,7 @@ import { ChangeNickNameModalState, ConfirmModalState, DeleteAccountModalState, - DisplayPictureModalState, + EditProfilePictureModalState, EditProfileModalState, InviteContactModalState, ModalState, @@ -111,7 +111,7 @@ export const getReactClearAllDialog = createSelector( (state: ModalState): ReactModalsState => state.reactClearAllModalState ); -export const getDisplayPictureModalState = createSelector( +export const getEditProfilePictureModalState = createSelector( getModal, - (state: ModalState): DisplayPictureModalState => state.displayPictureModalState + (state: ModalState): EditProfilePictureModalState => state.displayPictureModalState ); From b00eb52d358135f963c4144d7f7fe5982ae1661a Mon Sep 17 00:00:00 2001 From: William Grant Date: Tue, 23 May 2023 17:31:41 +1000 Subject: [PATCH 12/24] fix: pass yarn ready --- ts/components/dialog/EditProfileDialog.tsx | 13 ++++++++++--- ts/components/dialog/EditProfilePictureModal.tsx | 7 +++---- ts/components/dialog/ModalContainer.tsx | 2 +- ts/state/selectors/modal.ts | 2 +- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/ts/components/dialog/EditProfileDialog.tsx b/ts/components/dialog/EditProfileDialog.tsx index 3b5b4e848..d1c1b28fb 100644 --- a/ts/components/dialog/EditProfileDialog.tsx +++ b/ts/components/dialog/EditProfileDialog.tsx @@ -15,8 +15,12 @@ import { SessionButton, SessionButtonType } from '../basic/SessionButton'; import { SessionSpinner } from '../basic/SessionSpinner'; import { SessionIconButton } from '../icon'; import { sanitizeSessionUsername } from '../../session/utils/String'; -import { useOurConversationUsername } from '../../hooks/useParamSelector'; -import { useOurAvatarPath } from '../../hooks/useParamSelector'; +import { setLastProfileUpdateTimestamp } from '../../util/storage'; +import { ConversationTypeEnum } from '../../models/conversationAttributes'; +import { MAX_USERNAME_BYTES } from '../../session/constants'; +import styled from 'styled-components'; +import { saveQRCode } from '../../util/saveQRCode'; +import { useOurAvatarPath, useOurConversationUsername } from '../../hooks/useParamSelector'; import { useDispatch } from 'react-redux'; import styled from 'styled-components'; import { ConversationTypeEnum } from '../../models/conversationAttributes'; @@ -116,6 +120,7 @@ const ProfileHeader = (props: ProfileHeaderProps): ReactElement => { type ProfileDialogModes = 'default' | 'edit' | 'qr'; +// tslint:disable-next-line: max-func-body-length export const EditProfileDialog = (): ReactElement => { const dispatch = useDispatch(); @@ -177,7 +182,7 @@ export const EditProfileDialog = (): ReactElement => { switch (event.key) { case 'Enter': if (mode === 'edit') { - onClickOK(); + void onClickOK(); } break; case 'Esc': @@ -211,6 +216,8 @@ export const EditProfileDialog = (): ReactElement => { }; return ( + /* The
element has a child element that allows keyboard interaction */ + /* tslint:disable-next-line: react-a11y-event-has-role */
{ return (
@@ -93,7 +92,7 @@ export const EditProfilePictureModal = (props: EditProfilePictureModalProps) => const handleUpload = async () => { setLoading(true); if (newAvatarObjectUrl === avatarPath) { - window.log.debug(`Avatar Object URL has not changed!`); + window.log.debug('Avatar Object URL has not changed!'); return; } @@ -117,7 +116,7 @@ export const EditProfilePictureModal = (props: EditProfilePictureModalProps) => showHeader={true} showExitIcon={true} > -
+
{newAvatarObjectUrl || avatarPath ? ( Date: Tue, 23 May 2023 17:42:03 +1000 Subject: [PATCH 13/24] fix: cleanup --- _locales/en/messages.json | 3 +-- ts/state/ducks/modalDialog.tsx | 6 +++--- ts/state/selectors/modal.ts | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index ec19331bd..50e40ecb0 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -508,6 +508,5 @@ "reactionPopupMany": "$name$, $name2$, $name3$ &", "reactionListCountSingular": "And $otherSingular$ has reacted $emoji$ to this message", "reactionListCountPlural": "And $otherPlural$ have reacted $emoji$ to this message", - "setDisplayPicture": "Set Display Picture", - "upload": "Upload" + "setDisplayPicture": "Set Display Picture" } diff --git a/ts/state/ducks/modalDialog.tsx b/ts/state/ducks/modalDialog.tsx index 8cd86097a..27007b962 100644 --- a/ts/state/ducks/modalDialog.tsx +++ b/ts/state/ducks/modalDialog.tsx @@ -55,7 +55,7 @@ export type ModalState = { deleteAccountModal: DeleteAccountModalState; reactListModalState: ReactModalsState; reactClearAllModalState: ReactModalsState; - displayPictureModalState: EditProfilePictureModalState; + editProfilePictureModalState: EditProfilePictureModalState; }; export const initialModalState: ModalState = { @@ -76,7 +76,7 @@ export const initialModalState: ModalState = { deleteAccountModal: null, reactListModalState: null, reactClearAllModalState: null, - displayPictureModalState: null, + editProfilePictureModalState: null, }; const ModalSlice = createSlice({ @@ -135,7 +135,7 @@ const ModalSlice = createSlice({ return { ...state, reactClearAllModalState: action.payload }; }, updateEditProfilePictureModel(state, action: PayloadAction) { - return { ...state, displayPictureModalState: action.payload }; + return { ...state, editProfilePictureModalState: action.payload }; }, }, }); diff --git a/ts/state/selectors/modal.ts b/ts/state/selectors/modal.ts index e2ccd6e52..259aad8b5 100644 --- a/ts/state/selectors/modal.ts +++ b/ts/state/selectors/modal.ts @@ -113,5 +113,5 @@ export const getReactClearAllDialog = createSelector( export const getEditProfilePictureModalState = createSelector( getModal, - (state: ModalState): EditProfilePictureModalState => state.displayPictureModalState + (state: ModalState): EditProfilePictureModalState => state.editProfilePictureModalState ); From 7cc5cd0440a55dda8074cd341426d5945e2de18c Mon Sep 17 00:00:00 2001 From: William Grant Date: Thu, 25 May 2023 12:01:48 +1000 Subject: [PATCH 14/24] fix: EditProfilePictureModalState should be camel case --- ts/components/dialog/ModalContainer.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ts/components/dialog/ModalContainer.tsx b/ts/components/dialog/ModalContainer.tsx index 0a79048a3..9a0d7b6b7 100644 --- a/ts/components/dialog/ModalContainer.tsx +++ b/ts/components/dialog/ModalContainer.tsx @@ -57,7 +57,7 @@ export const ModalContainer = () => { const banOrUnbanUserModalState = useSelector(getBanOrUnbanUserModalState); const reactListModalState = useSelector(getReactListDialog); const reactClearAllModalState = useSelector(getReactClearAllDialog); - const EditProfilePictureModalState = useSelector(getEditProfilePictureModalState); + const editProfilePictureModalState = useSelector(getEditProfilePictureModalState); return ( <> @@ -82,8 +82,8 @@ export const ModalContainer = () => { {confirmModalState && } {reactListModalState && } {reactClearAllModalState && } - {EditProfilePictureModalState && ( - + {editProfilePictureModalState && ( + )} ); From 534080ddd7b18ca3919524eea5ffd6e9d5fb2637 Mon Sep 17 00:00:00 2001 From: William Grant Date: Thu, 25 May 2023 12:10:28 +1000 Subject: [PATCH 15/24] fix: compressed and flattened thumbail svg path --- ts/components/icon/Icons.tsx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ts/components/icon/Icons.tsx b/ts/components/icon/Icons.tsx index ebc5ff38b..670acec97 100644 --- a/ts/components/icon/Icons.tsx +++ b/ts/components/icon/Icons.tsx @@ -478,12 +478,8 @@ export const icons: Record< ratio: 1, }, thumbnail: { - path: [ - 'M34.915 23.8987L26.594 17.812C26.5393 17.7682 26.4714 17.7444 26.4014 17.7444C26.3313 17.7444 26.2634 17.7682 26.2087 17.812L18.748 23.9886C18.6905 24.0313 18.6207 24.0544 18.549 24.0544C18.4773 24.0544 18.4075 24.0313 18.35 23.9886L14.6003 20.9324C14.5468 20.8918 14.4814 20.8698 14.4141 20.8698C14.3469 20.8698 14.2815 20.8918 14.2279 20.9324L4.0706 28.1491C4.03144 28.1797 3.99959 28.2186 3.97737 28.263C3.95516 28.3075 3.94314 28.3563 3.94219 28.406V30.743C3.94549 30.9361 4.02366 31.1204 4.16022 31.257C4.29678 31.3935 4.48104 31.4717 4.67413 31.475H34.3115C34.5056 31.475 34.6918 31.3979 34.8291 31.2606C34.9663 31.1233 35.0434 30.9372 35.0434 30.743V24.1427C35.0447 24.0944 35.0335 24.0467 35.011 24.004C34.9885 23.9613 34.9555 23.925 34.915 23.8987Z', - 'M11.0947 18.7492C12.6904 18.7492 13.984 17.4556 13.984 15.8599C13.984 14.2642 12.6904 12.9707 11.0947 12.9707C9.49902 12.9707 8.20546 14.2642 8.20546 15.8599C8.20546 17.4556 9.49902 18.7492 11.0947 18.7492Z', - 'M40.3597 4.62408L8.19261 0.874467C7.77128 0.822682 7.34385 0.855312 6.93527 0.970455C6.52668 1.0856 6.14511 1.28095 5.81282 1.54511C5.48052 1.80927 5.20415 2.13696 4.99984 2.50905C4.79552 2.88115 4.66734 3.2902 4.62277 3.71236L4.46868 5.0992H7.03691L7.16532 4.00771C7.17565 3.92437 7.20256 3.84394 7.24446 3.77116C7.28637 3.69838 7.34241 3.63473 7.4093 3.58395C7.51881 3.496 7.65413 3.44638 7.79454 3.4427H7.85874L22.1509 5.0992H35.6855C36.4753 5.10365 37.2535 5.29018 37.9595 5.64429C38.6655 5.99841 39.2803 6.51056 39.7561 7.14095H40.0643C40.2326 7.16031 40.3865 7.24541 40.4923 7.37771C40.5981 7.51 40.6474 7.67876 40.6293 7.84721L40.5395 8.57915C40.7184 9.09576 40.8138 9.63762 40.822 10.1843V28.4958L43.1847 8.18108C43.2788 7.33533 43.0345 6.48672 42.5053 5.82036C41.976 5.154 41.2048 4.72397 40.3597 4.62408Z', - 'M35.6855 35.3016H3.30013C2.44871 35.3016 1.63216 34.9634 1.03011 34.3613C0.428069 33.7593 0.0898438 32.9427 0.0898438 32.0913V10.2614C0.0898438 9.40994 0.428069 8.59339 1.03011 7.99135C1.63216 7.3893 2.44871 7.05108 3.30013 7.05108H35.6855C36.5369 7.05108 37.3535 7.3893 37.9555 7.99135C38.5576 8.59339 38.8958 9.40994 38.8958 10.2614V32.0913C38.8958 32.9427 38.5576 33.7593 37.9555 34.3613C37.3535 34.9634 36.5369 35.3016 35.6855 35.3016ZM3.30013 9.59363C3.12985 9.59363 2.96654 9.66127 2.84613 9.78168C2.72572 9.90209 2.65807 10.0654 2.65807 10.2357V32.0656C2.65807 32.2359 2.72572 32.3992 2.84613 32.5196C2.96654 32.64 3.12985 32.7077 3.30013 32.7077H35.6855C35.8558 32.7077 36.0191 32.64 36.1395 32.5196C36.2599 32.3992 36.3276 32.2359 36.3276 32.0656V10.2357C36.3276 10.0654 36.2599 9.90209 36.1395 9.78168C36.0191 9.66127 35.8558 9.59363 35.6855 9.59363H3.30013Z', - ], + path: + 'm34.915 23.899-8.321-6.087a.308.308 0 0 0-.385 0l-7.461 6.177a.334.334 0 0 1-.398 0l-3.75-3.057a.308.308 0 0 0-.372 0L4.07 28.15a.335.335 0 0 0-.129.257v2.337a.745.745 0 0 0 .732.732h29.638a.732.732 0 0 0 .731-.732v-6.6a.281.281 0 0 0-.128-.244Zm-23.82-5.15a2.89 2.89 0 1 0 0-5.778 2.89 2.89 0 0 0 0 5.778ZM40.36 4.624 8.193.874a3.197 3.197 0 0 0-3.57 2.838L4.469 5.1h2.568l.128-1.091a.63.63 0 0 1 .244-.424.642.642 0 0 1 .386-.141h.064L22.15 5.099h13.534a5.137 5.137 0 0 1 4.071 2.042h.308a.642.642 0 0 1 .565.706l-.09.732a5.14 5.14 0 0 1 .283 1.605v18.312L43.185 8.18a3.223 3.223 0 0 0-2.825-3.557Zm-4.675 30.678H3.3a3.21 3.21 0 0 1-3.21-3.21v-21.83a3.21 3.21 0 0 1 3.21-3.21h32.385a3.21 3.21 0 0 1 3.21 3.21v21.83a3.21 3.21 0 0 1-3.21 3.21ZM3.3 9.594a.642.642 0 0 0-.642.642v21.83a.642.642 0 0 0 .642.642h32.385a.642.642 0 0 0 .643-.642v-21.83a.642.642 0 0 0-.643-.642H3.3Z', viewBox: '0 0 44 36', ratio: 1, }, From 69a50cdcc87b28e91163046512cf847125cf955a Mon Sep 17 00:00:00 2001 From: William Grant Date: Thu, 25 May 2023 13:12:02 +1000 Subject: [PATCH 16/24] fix: sort localised keys generated by updateI18nKeysType --- tools/updateI18nKeysType.py | 7 +- ts/types/LocalizerKeys.ts | 647 +++++++++++++++++++++--------------- 2 files changed, 385 insertions(+), 269 deletions(-) diff --git a/tools/updateI18nKeysType.py b/tools/updateI18nKeysType.py index 585a07490..bcd61e8d8 100755 --- a/tools/updateI18nKeysType.py +++ b/tools/updateI18nKeysType.py @@ -6,6 +6,7 @@ from os import path, listdir from glob import glob import json import sys +from collections import OrderedDict LOCALES_FOLDER = './_locales' @@ -16,10 +17,10 @@ LOCALIZED_KEYS_FILE = './ts/types/LocalizerKeys.ts' stringToWrite = "export type LocalizerKeys =\n | " with open(EN_FILE,'r') as jsonFile: - data = json.load(jsonFile) - keys = data.keys() + data = json.loads(jsonFile.read(), object_pairs_hook=OrderedDict) + keys = sorted(list(data.keys())) - stringToWrite += json.dumps(list(keys), sort_keys=True).replace(',', '\n |').replace('"', '\'')[1:-1] + stringToWrite += json.dumps(keys, sort_keys=True).replace(',', '\n |').replace('"', '\'')[1:-1] stringToWrite += ';\n' diff --git a/ts/types/LocalizerKeys.ts b/ts/types/LocalizerKeys.ts index e8d58a0c5..100809db0 100644 --- a/ts/types/LocalizerKeys.ts +++ b/ts/types/LocalizerKeys.ts @@ -1,14 +1,19 @@ export type LocalizerKeys = - | 'copyErrorAndQuit' - | 'unknown' - | 'databaseError' - | 'mainMenuFile' - | 'mainMenuEdit' - | 'mainMenuView' - | 'mainMenuWindow' - | 'mainMenuHelp' + | 'ByUsingThisService...' + | 'about' + | 'accept' + | 'activeMembers' + | 'add' + | 'addACaption' + | 'addAsModerator' + | 'addModerators' + | 'addingContacts' + | 'allUsersAreRandomly...' + | 'anonymous' + | 'answeredACall' | 'appMenuHide' | 'appMenuHideOthers' + | 'appMenuQuit' | 'appMenuUnhide' | 'appMenuQuit' | 'editMenuUndo' @@ -91,154 +96,393 @@ export type LocalizerKeys = | 'photo' | 'cannotUpdate' | 'cannotUpdateDetail' - | 'ok' - | 'cancel' + | 'changeAccountPasswordDescription' + | 'changeAccountPasswordTitle' + | 'changeNickname' + | 'changeNicknameMessage' + | 'changePassword' + | 'changePasswordInvalid' + | 'changePasswordTitle' + | 'changePasswordToastDescription' + | 'chooseAnAction' + | 'classicDarkThemeTitle' + | 'classicLightThemeTitle' + | 'clear' + | 'clearAll' + | 'clearAllConfirmationBody' + | 'clearAllConfirmationTitle' + | 'clearAllData' + | 'clearAllReactions' + | 'clearDataSettingsTitle' + | 'clearDevice' + | 'clearNickname' + | 'clickToTrustContact' | 'close' + | 'closedGroupInviteFailMessage' + | 'closedGroupInviteFailMessagePlural' + | 'closedGroupInviteFailTitle' + | 'closedGroupInviteFailTitlePlural' + | 'closedGroupInviteOkText' + | 'closedGroupInviteSuccessMessage' + | 'closedGroupInviteSuccessTitle' + | 'closedGroupInviteSuccessTitlePlural' + | 'closedGroupMaxSize' + | 'confirmNewPassword' + | 'confirmPassword' + | 'connectToServerFail' + | 'connectToServerSuccess' + | 'connectingToServer' + | 'contactAvatarAlt' + | 'contactsHeader' + | 'contextMenuNoSuggestions' | 'continue' - | 'error' + | 'continueYourSession' + | 'conversationsHeader' + | 'conversationsSettingsTitle' + | 'copiedToClipboard' + | 'copyErrorAndQuit' + | 'copyMessage' + | 'copyOpenGroupURL' + | 'copySessionID' + | 'couldntFindServerMatching' + | 'create' + | 'createAccount' + | 'createClosedGroupNamePrompt' + | 'createClosedGroupPlaceholder' + | 'createConversationNewContact' + | 'createConversationNewGroup' + | 'createGroup' + | 'createPassword' + | 'createSessionID' + | 'databaseError' + | 'debugLog' + | 'debugLogExplanation' + | 'decline' + | 'declineRequestMessage' | 'delete' - | 'messageDeletionForbidden' - | 'deleteJustForMe' + | 'deleteAccountFromLogin' + | 'deleteAccountWarning' + | 'deleteContactConfirmation' + | 'deleteConversationConfirmation' | 'deleteForEveryone' - | 'deleteMessagesQuestion' + | 'deleteJustForMe' | 'deleteMessageQuestion' | 'deleteMessages' | 'deleteConversation' | 'deleted' - | 'messageDeletedPlaceholder' + | 'destination' + | 'device' + | 'deviceOnly' + | 'dialogClearAllDataDeletionFailedDesc' + | 'dialogClearAllDataDeletionFailedMultiple' + | 'dialogClearAllDataDeletionFailedTitle' + | 'dialogClearAllDataDeletionFailedTitleQuestion' + | 'dialogClearAllDataDeletionQuestion' + | 'disabledDisappearingMessages' + | 'disappearingMessages' + | 'disappearingMessagesDisabled' + | 'displayName' + | 'displayNameEmpty' + | 'displayNameTooLong' + | 'documents' + | 'documentsEmptyState' + | 'done' + | 'downloadAttachment' + | 'editGroup' + | 'editGroupName' + | 'editMenuCopy' + | 'editMenuCut' + | 'editMenuDeleteContact' + | 'editMenuDeleteGroup' + | 'editMenuPaste' + | 'editMenuRedo' + | 'editMenuSelectAll' + | 'editMenuUndo' + | 'editProfileModalTitle' + | 'emptyGroupNameError' + | 'enable' + | 'endCall' + | 'enterAnOpenGroupURL' + | 'enterDisplayName' + | 'enterNewPassword' + | 'enterPassword' + | 'enterRecoveryPhrase' + | 'enterSessionID' + | 'enterSessionIDOfRecipient' + | 'enterSessionIDOrONSName' + | 'entireAccount' + | 'error' + | 'establishingConnection' + | 'expandedReactionsText' + | 'failedResolveOns' + | 'failedToAddAsModerator' + | 'failedToRemoveFromModerator' + | 'faq' + | 'fileSizeWarning' | 'from' - | 'to' - | 'sent' - | 'received' - | 'sendMessage' + | 'getStarted' + | 'goToReleaseNotes' + | 'goToSupportPage' | 'groupMembers' - | 'moreInformation' - | 'resend' - | 'deleteConversationConfirmation' - | 'clear' - | 'clearAllData' - | 'deleteAccountWarning' - | 'deleteAccountFromLogin' - | 'deleteContactConfirmation' - | 'quoteThumbnailAlt' + | 'groupNamePlaceholder' + | 'helpSettingsTitle' + | 'helpUsTranslateSession' + | 'hideBanner' + | 'hideMenuBarDescription' + | 'hideMenuBarTitle' + | 'hideRequestBanner' + | 'hideRequestBannerDescription' + | 'iAmSure' | 'imageAttachmentAlt' - | 'videoAttachmentAlt' - | 'lightboxImageAlt' | 'imageCaptionIconAlt' - | 'addACaption' - | 'copySessionID' - | 'copyOpenGroupURL' - | 'save' - | 'saveLogToDesktop' - | 'saved' - | 'tookAScreenshot' - | 'savedTheFile' - | 'linkPreviewsTitle' + | 'incomingCallFrom' + | 'incomingError' + | 'invalidGroupNameTooLong' + | 'invalidGroupNameTooShort' + | 'invalidNumberError' + | 'invalidOldPassword' + | 'invalidOpenGroupUrl' + | 'invalidPassword' + | 'invalidPubkeyFormat' + | 'invalidSessionId' + | 'inviteContacts' + | 'join' + | 'joinACommunity' + | 'joinOpenGroup' + | 'joinOpenGroupAfterInvitationConfirmationDesc' + | 'joinOpenGroupAfterInvitationConfirmationTitle' + | 'joinedTheGroup' + | 'keepDisabled' + | 'kickedFromTheGroup' + | 'learnMore' + | 'leaveAndRemoveForEveryone' + | 'leaveGroup' + | 'leaveGroupConfirmation' + | 'leaveGroupConfirmationAdmin' + | 'leftTheGroup' + | 'lightboxImageAlt' + | 'linkDevice' | 'linkPreviewDescription' | 'linkPreviewsConfirmMessage' - | 'mediaPermissionsTitle' - | 'mediaPermissionsDescription' - | 'spellCheckTitle' - | 'spellCheckDescription' - | 'spellCheckDirty' - | 'readReceiptSettingDescription' - | 'readReceiptSettingTitle' - | 'typingIndicatorsSettingDescription' - | 'typingIndicatorsSettingTitle' - | 'zoomFactorSettingTitle' - | 'themesSettingTitle' - | 'primaryColor' - | 'primaryColorGreen' - | 'primaryColorBlue' - | 'primaryColorYellow' - | 'primaryColorPink' - | 'primaryColorPurple' - | 'primaryColorOrange' - | 'primaryColorRed' - | 'classicDarkThemeTitle' - | 'classicLightThemeTitle' - | 'oceanDarkThemeTitle' - | 'oceanLightThemeTitle' - | 'pruneSettingTitle' - | 'pruneSettingDescription' - | 'enable' - | 'keepDisabled' - | 'notificationSettingsDialog' - | 'nameAndMessage' - | 'noNameOrMessage' - | 'nameOnly' - | 'newMessage' - | 'createConversationNewContact' - | 'createConversationNewGroup' - | 'joinACommunity' - | 'chooseAnAction' - | 'newMessages' - | 'notificationMostRecentFrom' - | 'notificationFrom' - | 'notificationMostRecent' - | 'sendFailed' + | 'linkPreviewsTitle' + | 'linkVisitWarningMessage' + | 'linkVisitWarningTitle' + | 'loading' + | 'mainMenuEdit' + | 'mainMenuFile' + | 'mainMenuHelp' + | 'mainMenuView' + | 'mainMenuWindow' + | 'markAllAsRead' + | 'maxPasswordAttempts' + | 'maximumAttachments' + | 'media' + | 'mediaEmptyState' | 'mediaMessage' - | 'messageBodyMissing' - | 'messageBody' - | 'unblockToSend' - | 'unblockGroupToSend' - | 'youChangedTheTimer' - | 'timerSetOnSync' + | 'mediaPermissionsDescription' + | 'mediaPermissionsTitle' + | 'members' + | 'message' + | 'messageBody' + | 'messageBodyMissing' + | 'messageDeletedPlaceholder' + | 'messageDeletionForbidden' + | 'messageRequestAccepted' + | 'messageRequestAcceptedOurs' + | 'messageRequestAcceptedOursNoName' + | 'messageRequestPending' + | 'messageRequests' + | 'messagesHeader' + | 'moreInformation' + | 'multipleJoinedTheGroup' + | 'multipleKickedFromTheGroup' + | 'multipleLeftTheGroup' + | 'mustBeApproved' + | 'nameAndMessage' + | 'nameOnly' + | 'newMessage' + | 'newMessages' + | 'next' + | 'nicknamePlaceholder' + | 'noAudioInputFound' + | 'noAudioOutputFound' + | 'noBlockedContacts' + | 'noCameraFound' + | 'noContactsForGroup' + | 'noContactsToAdd' + | 'noGivenPassword' + | 'noMediaUntilApproved' + | 'noMembersInThisGroup' + | 'noMessageRequestsPending' + | 'noModeratorsToRemove' + | 'noNameOrMessage' + | 'noSearchResults' + | 'noteToSelf' + | 'notificationForConvo' + | 'notificationForConvo_all' + | 'notificationForConvo_disabled' + | 'notificationForConvo_mentions_only' + | 'notificationFrom' + | 'notificationMostRecent' + | 'notificationMostRecentFrom' + | 'notificationPreview' + | 'notificationSettingsDialog' + | 'notificationSubtitle' + | 'notificationsSettingsContent' + | 'notificationsSettingsTitle' + | 'oceanDarkThemeTitle' + | 'oceanLightThemeTitle' + | 'offline' + | 'ok' + | 'oneNonImageAtATimeToast' + | 'onionPathIndicatorDescription' + | 'onionPathIndicatorTitle' + | 'onlyAdminCanRemoveMembers' + | 'onlyAdminCanRemoveMembersDesc' + | 'open' + | 'openGroupInvitation' + | 'openGroupURL' + | 'openMessageRequestInbox' + | 'openMessageRequestInboxDescription' + | 'or' + | 'orJoinOneOfThese' + | 'originalMessageNotFound' + | 'otherPlural' + | 'otherSingular' + | 'password' + | 'passwordCharacterError' + | 'passwordLengthError' + | 'passwordTypeError' + | 'passwordViewTitle' + | 'passwordsDoNotMatch' + | 'permissionsSettingsTitle' + | 'photo' + | 'pickClosedGroupMember' + | 'pinConversation' + | 'pleaseWaitOpenAndOptimizeDb' + | 'previewThumbnail' + | 'primaryColor' + | 'primaryColorBlue' + | 'primaryColorGreen' + | 'primaryColorOrange' + | 'primaryColorPink' + | 'primaryColorPurple' + | 'primaryColorRed' + | 'primaryColorYellow' + | 'privacySettingsTitle' + | 'pruneSettingDescription' + | 'pruneSettingTitle' + | 'publicChatExists' + | 'quoteThumbnailAlt' + | 'rateLimitReactMessage' + | 'reactionListCountPlural' + | 'reactionListCountSingular' + | 'reactionNotification' + | 'reactionPopup' + | 'reactionPopupMany' + | 'reactionPopupOne' + | 'reactionPopupThree' + | 'reactionPopupTwo' + | 'readReceiptSettingDescription' + | 'readReceiptSettingTitle' + | 'received' + | 'recoveryPhrase' + | 'recoveryPhraseEmpty' + | 'recoveryPhraseRevealButtonText' + | 'recoveryPhraseRevealMessage' + | 'recoveryPhraseSavePromptMain' + | 'recoveryPhraseSecureTitle' + | 'remove' + | 'removeAccountPasswordDescription' + | 'removeAccountPasswordTitle' + | 'removeFromModerators' + | 'removeModerators' + | 'removePassword' + | 'removePasswordInvalid' + | 'removePasswordTitle' + | 'removePasswordToastDescription' + | 'removeResidueMembers' + | 'replyToMessage' + | 'replyingToMessage' + | 'reportIssue' + | 'requestsPlaceholder' + | 'requestsSubtitle' + | 'resend' + | 'respondingToRequestWarning' + | 'restoreUsingRecoveryPhrase' + | 'ringing' + | 'save' + | 'saveLogToDesktop' + | 'saved' + | 'savedTheFile' + | 'searchFor...' + | 'searchForContactsOnly' + | 'selectMessage' + | 'sendFailed' + | 'sendMessage' + | 'sendRecoveryPhraseMessage' + | 'sendRecoveryPhraseTitle' + | 'sent' + | 'sessionMessenger' + | 'setAccountPasswordDescription' + | 'setAccountPasswordTitle' + | 'setDisplayPicture' + | 'setPassword' + | 'setPasswordFail' + | 'setPasswordInvalid' + | 'setPasswordTitle' + | 'setPasswordToastDescription' + | 'settingsHeader' + | 'shareBugDetails' + | 'show' + | 'showDebugLog' + | 'showRecoveryPhrase' + | 'showRecoveryPhrasePasswordRequest' + | 'showUserDetails' + | 'spellCheckDescription' + | 'spellCheckDirty' + | 'spellCheckTitle' + | 'stagedImageAttachment' + | 'stagedPreviewThumbnail' + | 'startConversation' + | 'startInTrayDescription' + | 'startInTrayTitle' + | 'startNewConversationBy...' + | 'startedACall' + | 'support' + | 'surveyTitle' + | 'themesSettingTitle' | 'theyChangedTheTimer' + | 'thisMonth' + | 'thisWeek' | 'timerOption_0_seconds' - | 'timerOption_5_seconds' + | 'timerOption_0_seconds_abbreviated' | 'timerOption_10_seconds' - | 'timerOption_30_seconds' - | 'timerOption_1_minute' - | 'timerOption_5_minutes' - | 'timerOption_30_minutes' - | 'timerOption_1_hour' - | 'timerOption_6_hours' + | 'timerOption_10_seconds_abbreviated' | 'timerOption_12_hours' + | 'timerOption_12_hours_abbreviated' | 'timerOption_1_day' + | 'timerOption_1_day_abbreviated' + | 'timerOption_1_hour' + | 'timerOption_1_hour_abbreviated' + | 'timerOption_1_minute' + | 'timerOption_1_minute_abbreviated' | 'timerOption_1_week' + | 'timerOption_1_week_abbreviated' | 'timerOption_2_weeks' - | 'disappearingMessages' - | 'changeNickname' - | 'clearNickname' - | 'nicknamePlaceholder' - | 'changeNicknameMessage' - | 'timerOption_0_seconds_abbreviated' - | 'timerOption_5_seconds_abbreviated' - | 'timerOption_10_seconds_abbreviated' + | 'timerOption_2_weeks_abbreviated' + | 'timerOption_30_minutes' + | 'timerOption_30_minutes_abbreviated' + | 'timerOption_30_seconds' | 'timerOption_30_seconds_abbreviated' - | 'timerOption_1_minute_abbreviated' + | 'timerOption_5_minutes' | 'timerOption_5_minutes_abbreviated' - | 'timerOption_30_minutes_abbreviated' - | 'timerOption_1_hour_abbreviated' + | 'timerOption_5_seconds' + | 'timerOption_5_seconds_abbreviated' + | 'timerOption_6_hours' | 'timerOption_6_hours_abbreviated' - | 'timerOption_12_hours_abbreviated' - | 'timerOption_1_day_abbreviated' - | 'timerOption_1_week_abbreviated' - | 'timerOption_2_weeks_abbreviated' - | 'disappearingMessagesDisabled' - | 'disabledDisappearingMessages' - | 'youDisabledDisappearingMessages' + | 'timerSetOnSync' | 'timerSetTo' - | 'noteToSelf' - | 'hideMenuBarTitle' - | 'hideMenuBarDescription' - | 'startConversation' - | 'invalidNumberError' - | 'failedResolveOns' - | 'autoUpdateSettingTitle' - | 'autoUpdateSettingDescription' - | 'autoUpdateNewVersionTitle' - | 'autoUpdateNewVersionMessage' - | 'autoUpdateNewVersionInstructions' - | 'autoUpdateRestartButtonLabel' - | 'autoUpdateLaterButtonLabel' - | 'autoUpdateDownloadButtonLabel' - | 'autoUpdateDownloadedMessage' - | 'autoUpdateDownloadInstructions' - | 'leftTheGroup' - | 'multipleLeftTheGroup' - | 'updatedTheGroup' | 'titleIsNow' | 'joinedTheGroup' | 'multipleJoinedTheGroup' @@ -247,144 +491,15 @@ export type LocalizerKeys = | 'block' | 'unblock' | 'unblocked' - | 'blocked' - | 'blockedSettingsTitle' - | 'conversationsSettingsTitle' - | 'unbanUser' - | 'userUnbanned' - | 'userUnbanFailed' - | 'banUser' - | 'banUserAndDeleteAll' - | 'userBanned' - | 'userBanFailed' - | 'leaveGroup' - | 'leaveAndRemoveForEveryone' - | 'leaveGroupConfirmation' - | 'leaveGroupConfirmationAdmin' - | 'cannotRemoveCreatorFromGroup' - | 'cannotRemoveCreatorFromGroupDesc' - | 'noContactsForGroup' - | 'failedToAddAsModerator' - | 'failedToRemoveFromModerator' - | 'copyMessage' - | 'selectMessage' - | 'editGroup' - | 'editGroupName' + | 'unknown' + | 'unknownCountry' + | 'unpinConversation' + | 'unreadMessages' | 'updateGroupDialogTitle' - | 'showRecoveryPhrase' - | 'yourSessionID' - | 'setAccountPasswordTitle' - | 'setAccountPasswordDescription' - | 'changeAccountPasswordTitle' - | 'changeAccountPasswordDescription' - | 'removeAccountPasswordTitle' - | 'removeAccountPasswordDescription' - | 'enterPassword' - | 'confirmPassword' - | 'enterNewPassword' - | 'confirmNewPassword' - | 'showRecoveryPhrasePasswordRequest' - | 'recoveryPhraseSavePromptMain' - | 'invalidOpenGroupUrl' - | 'copiedToClipboard' - | 'passwordViewTitle' - | 'password' - | 'setPassword' - | 'changePassword' - | 'createPassword' - | 'removePassword' - | 'maxPasswordAttempts' - | 'typeInOldPassword' - | 'invalidOldPassword' - | 'invalidPassword' - | 'noGivenPassword' - | 'passwordsDoNotMatch' - | 'setPasswordInvalid' - | 'changePasswordInvalid' - | 'removePasswordInvalid' - | 'setPasswordTitle' - | 'changePasswordTitle' - | 'removePasswordTitle' - | 'setPasswordToastDescription' - | 'changePasswordToastDescription' - | 'removePasswordToastDescription' - | 'publicChatExists' - | 'connectToServerFail' - | 'connectingToServer' - | 'connectToServerSuccess' - | 'setPasswordFail' - | 'passwordLengthError' - | 'passwordTypeError' - | 'passwordCharacterError' - | 'remove' - | 'invalidSessionId' - | 'invalidPubkeyFormat' - | 'emptyGroupNameError' - | 'editProfileModalTitle' - | 'groupNamePlaceholder' - | 'inviteContacts' - | 'addModerators' - | 'removeModerators' - | 'addAsModerator' - | 'removeFromModerators' - | 'add' - | 'addingContacts' - | 'noContactsToAdd' - | 'noMembersInThisGroup' - | 'noModeratorsToRemove' - | 'onlyAdminCanRemoveMembers' - | 'onlyAdminCanRemoveMembersDesc' - | 'createAccount' - | 'startInTrayTitle' - | 'startInTrayDescription' - | 'yourUniqueSessionID' - | 'allUsersAreRandomly...' - | 'getStarted' - | 'createSessionID' - | 'recoveryPhrase' - | 'enterRecoveryPhrase' - | 'displayName' - | 'anonymous' - | 'removeResidueMembers' - | 'enterDisplayName' - | 'continueYourSession' - | 'linkDevice' - | 'restoreUsingRecoveryPhrase' - | 'or' - | 'ByUsingThisService...' - | 'beginYourSession' - | 'welcomeToYourSession' - | 'searchFor...' - | 'searchForContactsOnly' - | 'enterSessionID' - | 'enterSessionIDOfRecipient' - | 'message' - | 'appearanceSettingsTitle' - | 'privacySettingsTitle' - | 'notificationsSettingsTitle' - | 'audioNotificationsSettingsTitle' - | 'notificationsSettingsContent' - | 'notificationPreview' - | 'recoveryPhraseEmpty' - | 'displayNameEmpty' - | 'displayNameTooLong' - | 'members' - | 'activeMembers' - | 'join' - | 'joinOpenGroup' - | 'createGroup' - | 'create' - | 'createClosedGroupNamePrompt' - | 'createClosedGroupPlaceholder' - | 'openGroupURL' - | 'enterAnOpenGroupURL' - | 'next' - | 'invalidGroupNameTooShort' - | 'invalidGroupNameTooLong' - | 'pickClosedGroupMember' - | 'closedGroupMaxSize' - | 'noBlockedContacts' + | 'updatedTheGroup' | 'userAddedToModerators' + | 'userBanFailed' + | 'userBanned' | 'userRemovedFromModerators' | 'orJoinOneOfThese' | 'helpUsTranslateSession' From cb2328bcd00f8e8176a72f12e801ff98d3ec33cb Mon Sep 17 00:00:00 2001 From: William Grant Date: Mon, 10 Jul 2023 17:32:46 +1000 Subject: [PATCH 17/24] fix: icon path typing error --- ts/components/icon/Icons.tsx | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/ts/components/icon/Icons.tsx b/ts/components/icon/Icons.tsx index 670acec97..d00ddd0fd 100644 --- a/ts/components/icon/Icons.tsx +++ b/ts/components/icon/Icons.tsx @@ -82,10 +82,7 @@ export type SessionIconType = export type SessionIconSize = 'tiny' | 'small' | 'medium' | 'large' | 'huge' | 'huge2' | 'max'; -export const icons: Record< - string, - { path: string | Array; viewBox: string; ratio: number } -> = { +export const icons: Record = { addUser: { path: 'M8.85,2.17c-1.73,0-3.12,1.4-3.12,3.12s1.4,3.12,3.12,3.12c1.73,0,3.13-1.4,3.13-3.12S10.58,2.17,8.85,2.17z M8.85,0.08c2.88,0,5.21,2.33,5.21,5.21s-2.33,5.21-5.21,5.21s-5.2-2.33-5.2-5.21C3.65,2.42,5.98,0.08,8.85,0.08z M20.83,5.29 c0.54,0,0.98,0.41,1.04,0.93l0.01,0.11v2.08h2.08c0.54,0,0.98,0.41,1.04,0.93v0.12c0,0.54-0.41,0.98-0.93,1.04l-0.11,0.01h-2.08 v2.08c0,0.58-0.47,1.04-1.04,1.04c-0.54,0-0.98-0.41-1.04-0.93l-0.01-0.11v-2.08h-2.08c-0.54,0-0.98-0.41-1.04-0.93l-0.01-0.11 c0-0.54,0.41-0.98,0.93-1.04l0.11-0.01h2.08V6.34C19.79,5.76,20.26,5.29,20.83,5.29z M12.5,12.58c2.8,0,5.09,2.21,5.2,4.99v0.22 v2.08c0,0.58-0.47,1.04-1.04,1.04c-0.54,0-0.98-0.41-1.04-0.93l-0.01-0.11v-2.08c0-1.67-1.3-3.03-2.95-3.12h-0.18H5.21 c-1.67,0-3.03,1.3-3.12,2.95v0.18v2.08c0,0.58-0.47,1.04-1.04,1.04c-0.54,0-0.98-0.41-1.04-0.93L0,19.88V17.8 c0-2.8,2.21-5.09,4.99-5.2h0.22h7.29V12.58z', @@ -544,10 +541,8 @@ export const icons: Record< ratio: 1, }, timer50: { - path: [ - 'M8.49999998,1.66987313 L8.99999998,0.80384773 C10.3298113,1.57161469 11.3667294,2.84668755 11.7955548,4.4470858 C12.6532057,7.64788242 10.7537107,10.9379042 7.5529141,11.795555 C4.35211748,12.6532059 1.06209574,10.753711 0.204444873,7.55291434 C-0.27253249,5.77281059 0.103264647,3.96510985 1.08141192,2.56355986 L1.94944135,3.0683506 L1.94144625,3.07944279 L6.25000012,5.56698754 L5.75000012,6.43301294 L1.44144624,3.9454682 C0.98322086,4.96059039 0.85962347,6.13437085 1.1703707,7.29409529 C1.88507976,9.96142581 4.62676454,11.5443383 7.29409506,10.8296292 C9.96142557,10.1149201 11.544338,7.37323536 10.829629,4.70590484 C10.4722744,3.37223964 9.60817605,2.30967894 8.49999998,1.66987313 Z', - 'M6.00250506,1.00000061 L6,1 C5.8312503,1 5.66445312,1.00835972 5.5,1.02468762 L5.5,0.0205368885 C5.66486669,0.00693566443 5.83162339,0 6,0 L6.00250686,5.12480482e-07 C9.31506271,0.0013544265 12,2.68712686 12,6 L11,6 C11,3.23941132 8.76277746,1.00135396 6.00250506,1.00000061 Z M3.44328115,0.571633044 L3.94535651,1.44125309 C3.79477198,1.50933927 3.64614153,1.58549813 3.5,1.66987298 C3.35385847,1.75424783 3.21358774,1.84488615 3.07933111,1.94125309 L2.57725574,1.07163304 C2.71323387,0.977420696 2.85418158,0.888035884 3,0.803847577 C3.14581842,0.719659271 3.2937018,0.642287382 3.44328115,0.571633044 Z', - ], + path: + 'M8.49999998,1.66987313 L8.99999998,0.80384773 C10.3298113,1.57161469 11.3667294,2.84668755 11.7955548,4.4470858 C12.6532057,7.64788242 10.7537107,10.9379042 7.5529141,11.795555 C4.35211748,12.6532059 1.06209574,10.753711 0.204444873,7.55291434 C-0.27253249,5.77281059 0.103264647,3.96510985 1.08141192,2.56355986 L1.94944135,3.0683506 L1.94144625,3.07944279 L6.25000012,5.56698754 L5.75000012,6.43301294 L1.44144624,3.9454682 C0.98322086,4.96059039 0.85962347,6.13437085 1.1703707,7.29409529 C1.88507976,9.96142581 4.62676454,11.5443383 7.29409506,10.8296292 C9.96142557,10.1149201 11.544338,7.37323536 10.829629,4.70590484 C10.4722744,3.37223964 9.60817605,2.30967894 8.49999998,1.66987313 Z M6.00250506,1.00000061 L6,1 C5.8312503,1 5.66445312,1.00835972 5.5,1.02468762 L5.5,0.0205368885 C5.66486669,0.00693566443 5.83162339,0 6,0 L6.00250686,5.12480482e-07 C9.31506271,0.0013544265 12,2.68712686 12,6 L11,6 C11,3.23941132 8.76277746,1.00135396 6.00250506,1.00000061 Z M3.44328115,0.571633044 L3.94535651,1.44125309 C3.79477198,1.50933927 3.64614153,1.58549813 3.5,1.66987298 C3.35385847,1.75424783 3.21358774,1.84488615 3.07933111,1.94125309 L2.57725574,1.07163304 C2.71323387,0.977420696 2.85418158,0.888035884 3,0.803847577 C3.14581842,0.719659271 3.2937018,0.642287382 3.44328115,0.571633044 Z', viewBox: '0 0 12 12', ratio: 1, }, From 41d27609279d990a3b4cd50a6cf6585180b140a5 Mon Sep 17 00:00:00 2001 From: William Grant Date: Mon, 10 Jul 2023 17:49:57 +1000 Subject: [PATCH 18/24] fix: removed duplicate imports and ordered localised keys --- ts/components/dialog/EditProfileDialog.tsx | 5 - ts/types/LocalizerKeys.ts | 324 ++++++--------------- 2 files changed, 91 insertions(+), 238 deletions(-) diff --git a/ts/components/dialog/EditProfileDialog.tsx b/ts/components/dialog/EditProfileDialog.tsx index d1c1b28fb..96f62af5a 100644 --- a/ts/components/dialog/EditProfileDialog.tsx +++ b/ts/components/dialog/EditProfileDialog.tsx @@ -15,16 +15,11 @@ import { SessionButton, SessionButtonType } from '../basic/SessionButton'; import { SessionSpinner } from '../basic/SessionSpinner'; import { SessionIconButton } from '../icon'; import { sanitizeSessionUsername } from '../../session/utils/String'; -import { setLastProfileUpdateTimestamp } from '../../util/storage'; import { ConversationTypeEnum } from '../../models/conversationAttributes'; import { MAX_USERNAME_BYTES } from '../../session/constants'; import styled from 'styled-components'; -import { saveQRCode } from '../../util/saveQRCode'; import { useOurAvatarPath, useOurConversationUsername } from '../../hooks/useParamSelector'; import { useDispatch } from 'react-redux'; -import styled from 'styled-components'; -import { ConversationTypeEnum } from '../../models/conversationAttributes'; -import { MAX_USERNAME_BYTES } from '../../session/constants'; const handleSaveQRCode = (event: MouseEvent) => { event.preventDefault(); diff --git a/ts/types/LocalizerKeys.ts b/ts/types/LocalizerKeys.ts index 100809db0..9f6118474 100644 --- a/ts/types/LocalizerKeys.ts +++ b/ts/types/LocalizerKeys.ts @@ -15,85 +15,46 @@ export type LocalizerKeys = | 'appMenuHideOthers' | 'appMenuQuit' | 'appMenuUnhide' - | 'appMenuQuit' - | 'editMenuUndo' - | 'editMenuRedo' - | 'editMenuCut' - | 'editMenuCopy' - | 'editMenuPaste' - | 'editMenuDeleteContact' - | 'editMenuDeleteGroup' - | 'editMenuSelectAll' - | 'windowMenuClose' - | 'windowMenuMinimize' - | 'windowMenuZoom' - | 'viewMenuResetZoom' - | 'viewMenuZoomIn' - | 'viewMenuZoomOut' - | 'viewMenuToggleFullScreen' - | 'viewMenuToggleDevTools' - | 'contextMenuNoSuggestions' - | 'openGroupInvitation' - | 'joinOpenGroupAfterInvitationConfirmationTitle' - | 'joinOpenGroupAfterInvitationConfirmationDesc' - | 'couldntFindServerMatching' - | 'enterSessionIDOrONSName' - | 'startNewConversationBy...' - | 'loading' - | 'done' - | 'youLeftTheGroup' - | 'youGotKickedFromGroup' - | 'unreadMessages' - | 'debugLogExplanation' - | 'reportIssue' - | 'markAllAsRead' - | 'incomingError' - | 'media' - | 'mediaEmptyState' - | 'document' - | 'documents' - | 'documentsEmptyState' - | 'today' - | 'yesterday' - | 'thisWeek' - | 'thisMonth' - | 'voiceMessage' - | 'stagedPreviewThumbnail' - | 'previewThumbnail' - | 'stagedImageAttachment' - | 'oneNonImageAtATimeToast' - | 'cannotMixImageAndNonImageAttachments' - | 'maximumAttachments' - | 'fileSizeWarning' - | 'unableToLoadAttachment' - | 'offline' - | 'debugLog' - | 'showDebugLog' - | 'shareBugDetails' - | 'goToReleaseNotes' - | 'goToSupportPage' - | 'about' - | 'show' - | 'sessionMessenger' - | 'noSearchResults' - | 'conversationsHeader' - | 'contactsHeader' - | 'messagesHeader' - | 'searchMessagesHeader' - | 'settingsHeader' - | 'typingAlt' - | 'contactAvatarAlt' - | 'downloadAttachment' - | 'replyToMessage' - | 'replyingToMessage' - | 'originalMessageNotFound' - | 'you' - | 'audioPermissionNeededTitle' - | 'audioPermissionNeeded' - | 'image' + | 'appearanceSettingsTitle' + | 'areYouSureClearDevice' + | 'areYouSureDeleteDeviceOnly' + | 'areYouSureDeleteEntireAccount' | 'audio' - | 'video' - | 'photo' + | 'audioMessageAutoplayDescription' + | 'audioMessageAutoplayTitle' + | 'audioNotificationsSettingsTitle' + | 'audioPermissionNeeded' + | 'audioPermissionNeededTitle' + | 'autoUpdateDownloadButtonLabel' + | 'autoUpdateDownloadInstructions' + | 'autoUpdateDownloadedMessage' + | 'autoUpdateLaterButtonLabel' + | 'autoUpdateNewVersionInstructions' + | 'autoUpdateNewVersionMessage' + | 'autoUpdateNewVersionTitle' + | 'autoUpdateRestartButtonLabel' + | 'autoUpdateSettingDescription' + | 'autoUpdateSettingTitle' + | 'banUser' + | 'banUserAndDeleteAll' + | 'beginYourSession' + | 'block' + | 'blocked' + | 'blockedSettingsTitle' + | 'callMediaPermissionsDescription' + | 'callMediaPermissionsDialogContent' + | 'callMediaPermissionsDialogTitle' + | 'callMediaPermissionsTitle' + | 'callMissed' + | 'callMissedCausePermission' + | 'callMissedNotApproved' + | 'callMissedTitle' + | 'cameraPermissionNeeded' + | 'cameraPermissionNeededTitle' + | 'cancel' + | 'cannotMixImageAndNonImageAttachments' + | 'cannotRemoveCreatorFromGroup' + | 'cannotRemoveCreatorFromGroupDesc' | 'cannotUpdate' | 'cannotUpdateDetail' | 'changeAccountPasswordDescription' @@ -163,12 +124,13 @@ export type LocalizerKeys = | 'deleteAccountFromLogin' | 'deleteAccountWarning' | 'deleteContactConfirmation' + | 'deleteConversation' | 'deleteConversationConfirmation' | 'deleteForEveryone' | 'deleteJustForMe' | 'deleteMessageQuestion' | 'deleteMessages' - | 'deleteConversation' + | 'deleteMessagesQuestion' | 'deleted' | 'destination' | 'device' @@ -184,6 +146,7 @@ export type LocalizerKeys = | 'displayName' | 'displayNameEmpty' | 'displayNameTooLong' + | 'document' | 'documents' | 'documentsEmptyState' | 'done' @@ -233,6 +196,7 @@ export type LocalizerKeys = | 'hideRequestBanner' | 'hideRequestBannerDescription' | 'iAmSure' + | 'image' | 'imageAttachmentAlt' | 'imageCaptionIconAlt' | 'incomingCallFrom' @@ -274,6 +238,7 @@ export type LocalizerKeys = | 'mainMenuView' | 'mainMenuWindow' | 'markAllAsRead' + | 'markUnread' | 'maxPasswordAttempts' | 'maximumAttachments' | 'media' @@ -314,6 +279,9 @@ export type LocalizerKeys = | 'noMediaUntilApproved' | 'noMembersInThisGroup' | 'noMessageRequestsPending' + | 'noMessagesInEverythingElse' + | 'noMessagesInNoteToSelf' + | 'noMessagesInReadOnly' | 'noModeratorsToRemove' | 'noNameOrMessage' | 'noSearchResults' @@ -417,6 +385,7 @@ export type LocalizerKeys = | 'savedTheFile' | 'searchFor...' | 'searchForContactsOnly' + | 'searchMessagesHeader' | 'selectMessage' | 'sendFailed' | 'sendMessage' @@ -439,6 +408,7 @@ export type LocalizerKeys = | 'showRecoveryPhrase' | 'showRecoveryPhrasePasswordRequest' | 'showUserDetails' + | 'someOfYourDeviceUseOutdatedVersion' | 'spellCheckDescription' | 'spellCheckDirty' | 'spellCheckTitle' @@ -484,12 +454,26 @@ export type LocalizerKeys = | 'timerSetOnSync' | 'timerSetTo' | 'titleIsNow' - | 'joinedTheGroup' - | 'multipleJoinedTheGroup' - | 'kickedFromTheGroup' - | 'multipleKickedFromTheGroup' - | 'block' + | 'to' + | 'today' + | 'tookAScreenshot' + | 'trimDatabase' + | 'trimDatabaseConfirmationBody' + | 'trimDatabaseDescription' + | 'trustThisContactDialogDescription' + | 'trustThisContactDialogTitle' + | 'tryAgain' + | 'typeInOldPassword' + | 'typingAlt' + | 'typingIndicatorsSettingDescription' + | 'typingIndicatorsSettingTitle' + | 'unableToCall' + | 'unableToCallTitle' + | 'unableToLoadAttachment' + | 'unbanUser' | 'unblock' + | 'unblockGroupToSend' + | 'unblockToSend' | 'unblocked' | 'unknown' | 'unknownCountry' @@ -501,153 +485,27 @@ export type LocalizerKeys = | 'userBanFailed' | 'userBanned' | 'userRemovedFromModerators' - | 'orJoinOneOfThese' - | 'helpUsTranslateSession' - | 'closedGroupInviteFailTitle' - | 'closedGroupInviteFailTitlePlural' - | 'closedGroupInviteFailMessage' - | 'closedGroupInviteFailMessagePlural' - | 'closedGroupInviteOkText' - | 'closedGroupInviteSuccessTitlePlural' - | 'closedGroupInviteSuccessTitle' - | 'closedGroupInviteSuccessMessage' - | 'notificationForConvo' - | 'notificationForConvo_all' - | 'notificationForConvo_disabled' - | 'notificationForConvo_mentions_only' - | 'onionPathIndicatorTitle' - | 'onionPathIndicatorDescription' - | 'unknownCountry' - | 'device' - | 'destination' - | 'learnMore' - | 'linkVisitWarningTitle' - | 'linkVisitWarningMessage' - | 'open' - | 'audioMessageAutoplayTitle' - | 'audioMessageAutoplayDescription' - | 'clickToTrustContact' - | 'trustThisContactDialogTitle' - | 'trustThisContactDialogDescription' - | 'pinConversation' - | 'unpinConversation' - | 'markUnread' - | 'showUserDetails' - | 'sendRecoveryPhraseTitle' - | 'sendRecoveryPhraseMessage' - | 'dialogClearAllDataDeletionFailedTitle' - | 'dialogClearAllDataDeletionFailedDesc' - | 'dialogClearAllDataDeletionFailedTitleQuestion' - | 'dialogClearAllDataDeletionFailedMultiple' - | 'dialogClearAllDataDeletionQuestion' - | 'clearDevice' - | 'tryAgain' - | 'areYouSureClearDevice' - | 'deviceOnly' - | 'entireAccount' - | 'areYouSureDeleteDeviceOnly' - | 'areYouSureDeleteEntireAccount' - | 'iAmSure' - | 'recoveryPhraseSecureTitle' - | 'recoveryPhraseRevealMessage' - | 'recoveryPhraseRevealButtonText' - | 'notificationSubtitle' - | 'surveyTitle' - | 'faq' - | 'support' - | 'clearAll' - | 'clearDataSettingsTitle' - | 'messageRequests' - | 'requestsSubtitle' - | 'requestsPlaceholder' - | 'hideRequestBannerDescription' - | 'incomingCallFrom' - | 'ringing' - | 'establishingConnection' - | 'accept' - | 'decline' - | 'endCall' - | 'permissionsSettingsTitle' - | 'helpSettingsTitle' - | 'cameraPermissionNeededTitle' - | 'cameraPermissionNeeded' - | 'unableToCall' - | 'unableToCallTitle' - | 'callMissed' - | 'callMissedTitle' - | 'noCameraFound' - | 'noAudioInputFound' - | 'noAudioOutputFound' - | 'callMediaPermissionsTitle' - | 'callMissedCausePermission' - | 'callMissedNotApproved' - | 'callMediaPermissionsDescription' - | 'callMediaPermissionsDialogContent' - | 'callMediaPermissionsDialogTitle' - | 'startedACall' - | 'answeredACall' - | 'trimDatabase' - | 'trimDatabaseDescription' - | 'trimDatabaseConfirmationBody' - | 'pleaseWaitOpenAndOptimizeDb' - | 'messageRequestPending' - | 'messageRequestAccepted' - | 'messageRequestAcceptedOurs' - | 'messageRequestAcceptedOursNoName' - | 'declineRequestMessage' - | 'respondingToRequestWarning' - | 'hideRequestBanner' - | 'openMessageRequestInbox' - | 'noMessageRequestsPending' - | 'noMediaUntilApproved' - | 'mustBeApproved' - | 'youHaveANewFriendRequest' - | 'clearAllConfirmationTitle' - | 'clearAllConfirmationBody' - | 'noMessagesInReadOnly' - | 'noMessagesInNoteToSelf' - | 'noMessagesInEverythingElse' - | 'hideBanner' - | 'someOfYourDeviceUseOutdatedVersion' - | 'openMessageRequestInboxDescription' - | 'clearAllReactions' - | 'expandedReactionsText' - | 'reactionNotification' - | 'rateLimitReactMessage' - | 'otherSingular' - | 'otherPlural' - | 'reactionPopup' - | 'reactionPopupOne' - | 'reactionPopupTwo' - | 'reactionPopupThree' - | 'reactionPopupMany' - | 'timerSetTo' - | 'iAmSure' - | 'primaryColorRed' - | 'selectMessage' - | 'enterAnOpenGroupURL' - | 'delete' - | 'changePasswordInvalid' - | 'themesSettingTitle' - | 'timerOption_6_hours' - | 'confirmPassword' - | 'downloadAttachment' - | 'trimDatabaseDescription' - | 'showUserDetails' - | 'titleIsNow' - | 'removePasswordToastDescription' - | 'recoveryPhrase' - | 'deleteAccountFromLogin' - | 'newMessages' + | 'userUnbanFailed' + | 'userUnbanned' + | 'video' + | 'videoAttachmentAlt' + | 'viewMenuResetZoom' + | 'viewMenuToggleDevTools' + | 'viewMenuToggleFullScreen' + | 'viewMenuZoomIn' + | 'viewMenuZoomOut' + | 'voiceMessage' + | 'welcomeToYourSession' + | 'windowMenuClose' + | 'windowMenuMinimize' + | 'windowMenuZoom' + | 'yesterday' | 'you' - | 'pruneSettingTitle' - | 'unbanUser' - | 'notificationForConvo_mentions_only' - | 'trustThisContactDialogDescription' - | 'unknownCountry' - | 'searchFor...' - | 'displayNameTooLong' - | 'joinedTheGroup' - | 'editGroupName' - | 'reportIssue' - | 'setDisplayPicture'; + | 'youChangedTheTimer' + | 'youDisabledDisappearingMessages' + | 'youGotKickedFromGroup' + | 'youHaveANewFriendRequest' + | 'youLeftTheGroup' + | 'yourSessionID' + | 'yourUniqueSessionID' + | 'zoomFactorSettingTitle'; From 853c9a21074cf642fd8053cb06d239b8a23010f9 Mon Sep 17 00:00:00 2001 From: William Grant Date: Tue, 18 Jul 2023 17:05:19 +1000 Subject: [PATCH 19/24] feat: fixed integration tests except for linked device profile sync, need to update avatar-update-blue files for linux --- .../dialog/EditProfilePictureModal.tsx | 8 +++++++- ts/test/automation/linked_device_user.spec.ts | 6 ++---- .../avatar-updated-blue-darwin.jpeg | Bin 1320 -> 1998 bytes ts/test/automation/setup/beforeEach.ts | 8 ++++---- ts/test/automation/user_actions.spec.ts | 8 +++----- .../avatar-updated-blue-darwin.jpeg | Bin 1014 -> 1112 bytes 6 files changed, 16 insertions(+), 14 deletions(-) diff --git a/ts/components/dialog/EditProfilePictureModal.tsx b/ts/components/dialog/EditProfilePictureModal.tsx index 7f69082f6..2c21bf535 100644 --- a/ts/components/dialog/EditProfilePictureModal.tsx +++ b/ts/components/dialog/EditProfilePictureModal.tsx @@ -116,7 +116,12 @@ export const EditProfilePictureModal = (props: EditProfilePictureModalProps) => showHeader={true} showExitIcon={true} > -
+
{newAvatarObjectUrl || avatarPath ? ( buttonType={SessionButtonType.Simple} onClick={handleUpload} disabled={newAvatarObjectUrl === avatarPath} + dataTestId="save-button-profile-update" /> { await waitForTestIdWithText(windowA, 'copy-button-profile-update', 'Copy'); await clickOnTestIdWithText(windowA, 'image-upload-section'); + await clickOnTestIdWithText(windowA, 'image-upload-click'); await clickOnTestIdWithText(windowA, 'save-button-profile-update'); await waitForTestIdWithText(windowA, 'loading-spinner'); - await waitForTestIdWithText(windowA, 'copy-button-profile-update', 'Copy'); - await clickOnTestIdWithText(windowA, 'modal-close-button'); - - await sleepFor(500); + await sleepFor(5000); const leftpaneAvatarContainer = await waitForTestIdWithText(windowB, 'leftpane-primary-avatar'); await sleepFor(500); const screenshot = await leftpaneAvatarContainer.screenshot({ diff --git a/ts/test/automation/linked_device_user.spec.ts-snapshots/avatar-updated-blue-darwin.jpeg b/ts/test/automation/linked_device_user.spec.ts-snapshots/avatar-updated-blue-darwin.jpeg index 06f76803d05b50a2e18257fe21ad2158ff2d3c60..1cd8d20b1a19f57aabadf1c415cb7d66580ee226 100644 GIT binary patch delta 1347 zcmZ{kdsNbQ7>B<<5ou&9c{^Uxm7pCjG_85fYbih7{@kv>QTX z0|M{|e)NK!^h+l6OS+6j2+62~y!ADbk^oq00$@uF0Qv&}AW4i@&@Amo;0l9w01Xrb zLqY40fjNKx1cxB-cOf7RxYj0^=En3(JpjRA5L^omefDVq0va$)IBKgFV!I<=-^n*2 zi*AS^6g)I`_9GTD>bPyQxS@^S%_DSf(cJmuY>bOo!VC5l$E3e4=VUD3z5YjomuK~AS-)r+|_gtTXy)!V+L zbr71{dTaO{GqH(kk>5@^egW^VO)WQab{+j<==RsTKCO{rN&1WX)(6Al+xap=yt-T5 z_kmvh=PYv4F!ZhtUUG*x=D3r!Vf%wU<# zM~E4^jdeZ6wV{`mmd*1kmv4s%B|KI_svIC9g3;xknG4>f6GJSm2D05`bLrr&T$zvt zf41hiqcAmEAuzZ|OZO18pmm8Ecz#qduGdq+h;<5LIER+Io0+42Wd}wvjaU;;@npqJpAZlsyDSiDVqJgyn-w4%1$pvwkPvu zmdoqK-E&6p;OqHpgO7NvRka-^cIg{E>($(>s!nN?Ep5M6cvLdU-};H0y4-7)y+ujj z)hDE3J~s{*nwNPxEqGVhFV+z_iaV@uGJ9gNC$1~X_ui>SX@# zh^1%8u(y@JxyQZf?5jT)H-C>>PvNK>crDYFgCheoeQi4NGbL@T*K^j54DwzHZY?q5 zh=Z$&hMe3g8s4^(-<*-GLS8nZ_UDl%S5)ZpJp-`|s$ZI#3u7=v@P-Si+UOI9FT!&u zc9hZ0AtD`ndPBMQ(*SSz{$oP4#67U~H9Bvr!kqEp&^|0t%)LON1V@YJaU6(Wa{_xP z>?IR1oWxqrTkUr9l6bm=Q02E=wlqAio~K=&h^@}^vC2#_t?`|56sKNRw&97w5a(LS z?jp8q7w!C5_t{7qc~W)yUm^l`p4Z+(-9txU=ded|1dS7Kb5lsO*Qs6)rMLi{YgMkJ z?$e{)2Ke7sbIX{)(#TQ&l4l1Mq!OEelWHA{*=wrJM5ZULtHYFPT@vaff4NE*#>Gy( zsxa5_wLm71FTYQy*wmu--<52)zlvBpUsB8|>GzwxE2g_+o@(B_8MIW_BY2myM(Eu` ztuW>Vj5!VOky-k+#?__q$Eh~*JILxRC07xsJ{Hq0rQUd>JRLJKKhn#}cZ(Dc-gt4} z=wO&{yBAHyh*!5hmpBQ{9XkSRM`lulH8bCO29>%Lb&VtzlFo>NM}wvtREZtpnWpCV z_>dv>#)DpsvrY4teE7j?p)WBaqbxK$E}e8H@JhA4Ez{$W&1?A*QH0IPK8LkIvkW4> Tij4oCfY^u)T$1|~s9W|h(}!6YNl96=#P*1!+KB8G_< zAAbCQi-Ct3XuKe^AcH-_xfdM`OiBt2-J6$wd0V$+M@4isoAjAU``g^CCjSZ5(p|94 zOh7x&bdztNkK&rVYJvK!Ws19gMsYi7+B6IHi}TmA1d3{h<)(&io94CK9_K5Ba0`_^6c>kkem%rmI`Wx;%RM`+n=``Ll| z-AnnF|LmP4wwdvau0qfJc-0HhEthPVu9knY^ocZ|^Vxm(_4W02hfm+hY?ZC`H7Gx( zH1W)jjXe(@Yn$gCU8NniaZd0SBduv>OH3-69y$KmGQV_r{?roD&308DTFUbxx$mV^ z=ssV-n5KJU*U{2z#bO;^M{6;^M&m|0V!^$OQWU diff --git a/ts/test/automation/setup/beforeEach.ts b/ts/test/automation/setup/beforeEach.ts index f47f97418..6ba353549 100644 --- a/ts/test/automation/setup/beforeEach.ts +++ b/ts/test/automation/setup/beforeEach.ts @@ -1,5 +1,5 @@ import { Page } from '@playwright/test'; -import { readdirSync, rmdirSync } from 'fs-extra'; +import { readdirSync, rm } from 'fs-extra'; import { join } from 'path'; import { homedir } from 'os'; import { isLinux, isMacOS } from '../../../OS'; @@ -25,9 +25,9 @@ function cleanUpOtherTest() { alreadyCleanedWaiting = true; const parentFolderOfAllDataPath = isMacOS() - ? '~/Library/Application Support/' + ? join(homedir(), 'Library', 'Application Support') : isLinux() - ? `${homedir()}/.config/` + ? join(homedir(), '.config') : null; if (!parentFolderOfAllDataPath) { throw new Error('Only macOS is currrently supported '); @@ -43,7 +43,7 @@ function cleanUpOtherTest() { allAppDataPath.map(folder => { const pathToRemove = join(parentFolderOfAllDataPath, folder); - rmdirSync(pathToRemove, { recursive: true }); + rm(pathToRemove, { recursive: true }, () => pathToRemove); }); console.info('...done'); } diff --git a/ts/test/automation/user_actions.spec.ts b/ts/test/automation/user_actions.spec.ts index d26476440..cc93bdd3f 100644 --- a/ts/test/automation/user_actions.spec.ts +++ b/ts/test/automation/user_actions.spec.ts @@ -132,7 +132,7 @@ sessionTestOneWindow('Change username', async ([window]) => { await window.click('.session-icon-button.small'); }); -sessionTestOneWindow('Change avatar', async ([window]) => { +sessionTestOneWindow('Change profile picture', async ([window]) => { await newUser(window, 'Alice'); // Open profile await clickOnTestIdWithText(window, 'leftpane-primary-avatar'); @@ -140,13 +140,11 @@ sessionTestOneWindow('Change avatar', async ([window]) => { await waitForTestIdWithText(window, 'copy-button-profile-update', 'Copy'); await clickOnTestIdWithText(window, 'image-upload-section'); + await clickOnTestIdWithText(window, 'image-upload-click'); await clickOnTestIdWithText(window, 'save-button-profile-update'); await waitForTestIdWithText(window, 'loading-spinner'); - await waitForTestIdWithText(window, 'copy-button-profile-update', 'Copy'); - await clickOnTestIdWithText(window, 'modal-close-button'); - - await sleepFor(500); + await sleepFor(5000); const leftpaneAvatarContainer = await waitForTestIdWithText(window, 'leftpane-primary-avatar'); await sleepFor(500); const screenshot = await leftpaneAvatarContainer.screenshot({ diff --git a/ts/test/automation/user_actions.spec.ts-snapshots/avatar-updated-blue-darwin.jpeg b/ts/test/automation/user_actions.spec.ts-snapshots/avatar-updated-blue-darwin.jpeg index 079323ef7cceff940f71519c5a4c6ef4300767fb..79defdd42effc9c516bf577f443c4b92e59d026c 100644 GIT binary patch delta 371 zcmeyyeuHDfIi~sr3>M6cN(@YbjLd?J|Bo<;F)%VRGN1rP4v@G2rnn$bTnea~i5W!) zGYbc}Q!_)t+fv9M8i;=+UfZ!z!yO<)pa7G$tz zID24XplE&4*S7glzm}`2zWe58G^^`0o5pL+f~BnTM!EZa^dBpf-aFB>%=A_}&y|JZ zL3cl^Zu@)Yail#PL(!2#n(WJ7gl*iuxy|Zi>Ys0#SEr>ga9Ny>;$f72dr(Z)foR Wx?_clrgt+~CM8S^6k%rme-i+8 Date: Tue, 18 Jul 2023 12:11:07 +0200 Subject: [PATCH 20/24] test: fix update profile picture snapshots - loop until match when validating screenshot - wait 15s and take screenshot when updating screenshot --- ts/test/automation/linked_device_user.spec.ts | 38 +++++++++++++++---- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/ts/test/automation/linked_device_user.spec.ts b/ts/test/automation/linked_device_user.spec.ts index f74679585..b171e4684 100644 --- a/ts/test/automation/linked_device_user.spec.ts +++ b/ts/test/automation/linked_device_user.spec.ts @@ -70,7 +70,7 @@ test('Check changed username syncs', async () => { await waitForTestIdWithText(windowB, 'your-profile-name', newUsername); }); -test('Check profile picture syncs', async () => { +test('Check profile picture syncs', async ({}, testinfo) => { const [windowA] = await openApp(1); // not using sessionTest here as we need to close and reopen one of the window const userA = await newUser(windowA, 'Alice'); const [windowB] = await linkedDevice(userA.recoveryPhrase); // not using sessionTest here as we need to close and reopen one of the window @@ -83,14 +83,36 @@ test('Check profile picture syncs', async () => { await clickOnTestIdWithText(windowA, 'save-button-profile-update'); await waitForTestIdWithText(windowA, 'loading-spinner'); - await sleepFor(5000); + if (testinfo.config.updateSnapshots === 'all') { + await sleepFor(15000, true); // long time to be sure a poll happened when we want to update the snapshot + } else { + await sleepFor(2000); // short time as we will loop right below until the snapshot is what we expect + } + const leftpaneAvatarContainer = await waitForTestIdWithText(windowB, 'leftpane-primary-avatar'); - await sleepFor(500); - const screenshot = await leftpaneAvatarContainer.screenshot({ - type: 'jpeg', - // path: 'avatar-updated-blue', - }); - expect(screenshot).toMatchSnapshot({ name: 'avatar-updated-blue.jpeg' }); + const start = Date.now(); + let correctScreenshot = false; + let tryNumber = 0; + do { + try { + await sleepFor(500); + + const screenshot = await leftpaneAvatarContainer.screenshot({ + type: 'jpeg', + // path: 'avatar-updated-blue', + }); + expect(screenshot).toMatchSnapshot({ name: 'avatar-updated-blue.jpeg' }); + correctScreenshot = true; + console.warn( + `screenshot matching of "Check profile picture syncs" passed after "${tryNumber}" retries!` + ); + } catch (e) { + console.warn( + `screenshot matching of "Check profile picture syncs" try "${tryNumber}" failed with: ${e.message}` + ); + } + tryNumber++; + } while (Date.now() - start <= 20000 && !correctScreenshot); }); test('Check contacts syncs', async () => { From 5d73e4e0f1df99dc11c6c824094f2ef553c32031 Mon Sep 17 00:00:00 2001 From: William Grant Date: Wed, 19 Jul 2023 10:27:52 +1000 Subject: [PATCH 21/24] fix: updated avatar to correct image --- .../avatar-updated-blue-darwin.jpeg | Bin 1998 -> 1174 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/ts/test/automation/linked_device_user.spec.ts-snapshots/avatar-updated-blue-darwin.jpeg b/ts/test/automation/linked_device_user.spec.ts-snapshots/avatar-updated-blue-darwin.jpeg index 1cd8d20b1a19f57aabadf1c415cb7d66580ee226..3c94dc5842a6d080f1051aa88bea8c1cee43aa7a 100644 GIT binary patch delta 418 zcmX@dKaF$4J*Ikb21X!YKn9FV9RH6nND2UjnNegInG6F3fl^XH875RIR(56-wm{=db*12ln&Ly%dJ!JgrH!^A+* z`YgYt25Xd_i?05%_PWgWLtp>NsRue{ov4fwW94biTKs+0$^F+lD}An%2fgW8oS80g zW1Gj?Z1%8o(U;!dzy0~)ubG;6R@$mwIKd}yOHWtj(z-uulevA&W_z!>_Wb?vLl=72 z>t0S^cS&SmIOlYiE8INd(0QRr%eDl2#aq38YUFjVK6>F5Uu}ymn~b)8(fe>K({4j_ z{C0V5XTLpVXB%V%TNs#PIVUVFF8!i!sA-iS%Ch+5x_!|qYaefu^|-P(#Vs*n?>W)% zSGV_7`nSLSYkO|itc$ZHZC5k3)om^OePzk~*KT{ZWLZa+rA@l0q_{EXebg(ysdLKI f@9*FK`1BW};BA5IRi{@l9+GyL7%0Nb{{JQbEqk13 delta 1281 zcmbQnd5(X>J*IjY21W)(Rz^k!1Yl=mVrAoCX8C`F!Bl{Ok(rs1m5r5=6QY2Tfr*)g zRZxhHUC}U5*vK)laH6PcP~#zSGpEp|$qP4bx(L)J2{exx#Y_ekRyJlPpp=#%0}~S? zGb1|-GswVt5WxsBQc+mR&@nLap{UWui-nC7|KDQZVFp?!$SlZU&+xp(#X(Sz!NrA9 zP=EzHGc?{#)dKwEw(ffp6!&}o#gpHoMXz0|OU+-oOg{KV$^8AQy|MK= zfoG)`&+MIK&SSYwlKqOt;tK0cZ62ySa-PJ_St~W)!+M>ZRh4|bsJ#_Wxub(vnyR>#LU8h^1c;G?vgRV7uRB}(}Jl31OGA}fTf7!xgZS(vleEKF+ zJLTIJ-_w`2%}>mH%D^7ttq&HVbTq-6xpFYyeYE;j$(iKlPGHm5E&`@1dI z@X7Jr{xdEW{+-_OY^CLrefRl`?|iw=8l3+w(?0iXTEvppr;|2b+*6$0#1D$ z>(ZV~9+iree%8`d?bKV`zUTOKCNAx>KjmTn)UD{W$|Wn$c`sGUg`Uey{vPkF7kY7H zPim@n#JSfl>lpXVsnCn}e>9!_dfNPN<-hh@+Fi0W_sxB}*_?Oj%~`Lf-iw-5?x0+d zAvMSGf#Jo>`l(+w1%{sXHJf+IxOvGF{rc`Z`#ZwwWAA^hL9-}mG8 zmsfgp*}eB=8PP9R<=P#(;^M)#Vw%M*tB1Gtiv<4rRn|M*`%2g?_x8&H&!gMbJt}|m z$-P+dl{<90?VepyxoYixMo%C8ns_=U>OuXpNiuwna$M Date: Thu, 20 Jul 2023 14:29:09 +1000 Subject: [PATCH 22/24] fix: revert rm to rmdirSync so we don't remove config files before a test has been completed --- ts/test/automation/setup/beforeEach.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ts/test/automation/setup/beforeEach.ts b/ts/test/automation/setup/beforeEach.ts index 6ba353549..016cf072d 100644 --- a/ts/test/automation/setup/beforeEach.ts +++ b/ts/test/automation/setup/beforeEach.ts @@ -1,5 +1,5 @@ import { Page } from '@playwright/test'; -import { readdirSync, rm } from 'fs-extra'; +import { readdirSync, rmdirSync } from 'fs-extra'; import { join } from 'path'; import { homedir } from 'os'; import { isLinux, isMacOS } from '../../../OS'; @@ -43,7 +43,7 @@ function cleanUpOtherTest() { allAppDataPath.map(folder => { const pathToRemove = join(parentFolderOfAllDataPath, folder); - rm(pathToRemove, { recursive: true }, () => pathToRemove); + rmdirSync(pathToRemove, { recursive: true }); }); console.info('...done'); } From 9d4201aa95e0a359b0a1ce9a493ecf6e99e01580 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Mon, 21 Aug 2023 10:19:57 +1000 Subject: [PATCH 23/24] fix: void rather than eslint disable --- ts/components/dialog/EditProfilePictureModal.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ts/components/dialog/EditProfilePictureModal.tsx b/ts/components/dialog/EditProfilePictureModal.tsx index 046844807..35d9f1f4a 100644 --- a/ts/components/dialog/EditProfilePictureModal.tsx +++ b/ts/components/dialog/EditProfilePictureModal.tsx @@ -119,8 +119,7 @@ export const EditProfilePictureModal = (props: EditProfilePictureModalProps) =>
void handleAvatarClick} data-testid={'image-upload-click'} > From 95ac1492b54e40a4cbad9746e6472a1c519a5896 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Fri, 25 Aug 2023 13:20:29 +1000 Subject: [PATCH 24/24] fix: call function to upload avatar am a dumbass, will help with dumbassing --- ts/components/dialog/EditProfilePictureModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ts/components/dialog/EditProfilePictureModal.tsx b/ts/components/dialog/EditProfilePictureModal.tsx index 35d9f1f4a..2554c420f 100644 --- a/ts/components/dialog/EditProfilePictureModal.tsx +++ b/ts/components/dialog/EditProfilePictureModal.tsx @@ -119,7 +119,7 @@ export const EditProfilePictureModal = (props: EditProfilePictureModalProps) =>
void handleAvatarClick} + onClick={() => void handleAvatarClick()} data-testid={'image-upload-click'} >