From 3296eb47015c0d49f1c865c745ffce340accb017 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Tue, 12 Aug 2025 13:49:51 +1000 Subject: [PATCH 01/18] fix: start work on UserSettings - moved the modal to a new name - added the panebutton to display to the modal (but still in ActionsPanel for now_) --- ts/components/SessionWrapperModal.tsx | 3 + ts/components/basic/SessionIdNotEditable.tsx | 12 +- .../dialog/EditProfilePictureModal.tsx | 26 +- ts/components/dialog/ModalContainer.tsx | 18 +- ...sx => UpdateConversationDetailsDialog.tsx} | 192 ++++++---- ts/components/dialog/UserProfileModal.tsx | 6 +- .../conversationSettingsHeader.tsx | 6 +- .../dialog/edit-profile/EditProfileDialog.tsx | 349 ------------------ .../dialog/edit-profile/ProfileDialogModes.ts | 1 - .../user-settings/ProfileDialogModes.ts | 1 + .../UploadFirstImage.tsx | 0 .../user-settings/UserSettingsDialog.tsx | 310 ++++++++++++++++ .../components.tsx | 0 ts/components/leftpane/ActionsPanel.tsx | 4 +- .../leftpane/LeftPaneSettingSection.tsx | 37 +- .../loading/spinner/StyledSessionSpinner.tsx | 4 +- ts/interactions/conversationInteractions.ts | 4 +- ts/react.d.ts | 11 +- ts/state/ducks/metaGroups.ts | 4 +- ts/state/ducks/modalDialog.tsx | 30 +- ts/state/ducks/sogsRoomInfo.tsx | 4 +- ts/state/ducks/user.ts | 6 +- ts/state/selectors/modal.ts | 6 +- 23 files changed, 515 insertions(+), 519 deletions(-) rename ts/components/dialog/{UpdateGroupOrCommunityDetailsDialog.tsx => UpdateConversationDetailsDialog.tsx} (62%) delete mode 100644 ts/components/dialog/edit-profile/EditProfileDialog.tsx delete mode 100644 ts/components/dialog/edit-profile/ProfileDialogModes.ts create mode 100644 ts/components/dialog/user-settings/ProfileDialogModes.ts rename ts/components/dialog/{edit-profile => user-settings}/UploadFirstImage.tsx (100%) create mode 100644 ts/components/dialog/user-settings/UserSettingsDialog.tsx rename ts/components/dialog/{edit-profile => user-settings}/components.tsx (100%) diff --git a/ts/components/SessionWrapperModal.tsx b/ts/components/SessionWrapperModal.tsx index aa010aa16..d14cd6424 100644 --- a/ts/components/SessionWrapperModal.tsx +++ b/ts/components/SessionWrapperModal.tsx @@ -230,6 +230,7 @@ export type SessionWrapperModalType = { * Instead of centering the modal (and having layout shifts on height change), we can use this to anchor the modal to a % from the top of the screen. */ topAnchor?: ModalTopAnchor; + $flexGap?: string; style?: Omit; }; @@ -360,6 +361,7 @@ export const SessionWrapperModal = (props: SessionWrapperModalType & { onClose?: removeScrollbarGutter, onClose, topAnchor, + $flexGap, } = props; const [scrolled, setScrolled] = useState(false); @@ -427,6 +429,7 @@ export const SessionWrapperModal = (props: SessionWrapperModalType & { onClose?: $alignItems="center" $flexDirection="column" paddingInline="var(--margins-lg)" // add the padding here so that the rest of the modal isn't affected (including buttonChildren/ModalHeader) + $flexGap={$flexGap} > {props.children} diff --git a/ts/components/basic/SessionIdNotEditable.tsx b/ts/components/basic/SessionIdNotEditable.tsx index 9b8a4f0b3..eae5b5ef5 100644 --- a/ts/components/basic/SessionIdNotEditable.tsx +++ b/ts/components/basic/SessionIdNotEditable.tsx @@ -26,12 +26,14 @@ export const SessionIDNotEditable = ({ tooltipNode, displayType, style: providedStyle = {}, + onClick, }: { sessionId: string; tooltipNode: ReactNode; displayType: 'blinded' | '2lines' | '3lines'; dataTestId: SessionDataTestId; style: CSSProperties; + onClick?: () => void; }) => { if (sessionId.length !== 66) { throw new Error('Unsupported case for SessionIDNotEditable: sessionId.length !== 66'); @@ -40,7 +42,11 @@ export const SessionIDNotEditable = ({ throw new Error('Unsupported case for SessionIDNotEditable: sessionId is blinded'); } - const style = tooltipNode ? { ...providedStyle, marginLeft: 'var(--margins-lg)' } : providedStyle; + const pointerStyle = onClick ? { cursor: 'pointer' } : {}; + + const style = tooltipNode + ? { ...providedStyle, ...pointerStyle, marginLeft: 'var(--margins-lg)' } + : { ...providedStyle, ...pointerStyle }; if (displayType === 'blinded') { const shortenedSessionId = PubKey.shorten(sessionId, { @@ -53,6 +59,7 @@ export const SessionIDNotEditable = ({ data-testid={dataTestId} // Note: we want the text centered even if the tooltip is offsetting it style={style} + onClick={onClick} > {shortenedSessionId} {tooltipNode} @@ -68,6 +75,7 @@ export const SessionIDNotEditable = ({ {firstLine}
@@ -80,7 +88,7 @@ export const SessionIDNotEditable = ({ } return ( - + {sessionId.slice(0, 33)}
{sessionId.slice(33)} diff --git a/ts/components/dialog/EditProfilePictureModal.tsx b/ts/components/dialog/EditProfilePictureModal.tsx index ce45e39b6..e6f0f2acc 100644 --- a/ts/components/dialog/EditProfilePictureModal.tsx +++ b/ts/components/dialog/EditProfilePictureModal.tsx @@ -3,12 +3,12 @@ import { useDispatch } from 'react-redux'; import type { AnyAction, Dispatch } from 'redux'; import styled from 'styled-components'; import { ToastUtils, UserUtils } from '../../session/utils'; -import { editProfileModal, updateEditProfilePictureModal } from '../../state/ducks/modalDialog'; +import { userSettingsModal, updateEditProfilePictureModal } from '../../state/ducks/modalDialog'; import type { EditProfilePictureModalProps } from '../../types/ReduxTypes'; import { pickFileForAvatar } from '../../types/attachments/VisualAttachment'; import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton'; import { SessionSpinner } from '../loading'; -import { ProfileAvatar } from './edit-profile/components'; +import { ProfileAvatar } from './user-settings/components'; import { useAvatarPath, useConversationUsernameWithFallback, @@ -30,7 +30,7 @@ import { SessionWrapperModal, } from '../SessionWrapperModal'; import { useIsProAvailable } from '../../hooks/useIsProAvailable'; -import { SpacerLG } from '../basic/Text'; +import { SpacerLG, SpacerSM } from '../basic/Text'; import { SessionProInfoVariant, useShowSessionProInfoDialogCbWithVariant, @@ -39,7 +39,8 @@ import { AvatarSize } from '../avatar/Avatar'; import { ProIconButton } from '../buttons/ProButton'; import { useProBadgeOnClickCb } from '../menuAndSettingsHooks/useProBadgeOnClickCb'; import { useUserHasPro } from '../../hooks/useHasPro'; -import { UploadFirstImageButton } from './edit-profile/UploadFirstImage'; +import { UploadFirstImageButton } from './user-settings/UploadFirstImage'; +import { Localizer } from '../basic/Localizer'; const StyledAvatarContainer = styled.div` cursor: pointer; @@ -96,7 +97,7 @@ const triggerUploadProfileAvatar = async ( ToastUtils.pushToastError('edit-profile', error.message); } window.log.error( - 'showEditProfileDialog Error ensuring that image is properly sized:', + 'triggerUploadProfileAvatar Error ensuring that image is properly sized:', error && error.stack ? error.stack : error ); } @@ -162,7 +163,7 @@ export const EditProfilePictureModal = ({ conversationId }: EditProfilePictureMo const closeDialog = useCallback(() => { dispatch(updateEditProfilePictureModal(null)); if (isMe) { - dispatch(editProfileModal({})); + dispatch(userSettingsModal({})); } }, [dispatch, isMe]); @@ -274,6 +275,7 @@ export const EditProfilePictureModal = ({ conversationId }: EditProfilePictureMo ) : null} } + $flexGap="var(--margins-sm)" > {isMe && proBadgeCb.cb ? ( @@ -308,9 +310,17 @@ export const EditProfilePictureModal = ({ conversationId }: EditProfilePictureMo )} - - + {} + {loading ? ( + <> + + {isMe ? : null} + + + ) : ( + + )} ); }; diff --git a/ts/components/dialog/ModalContainer.tsx b/ts/components/dialog/ModalContainer.tsx index b9d25975f..3724cf8d4 100644 --- a/ts/components/dialog/ModalContainer.tsx +++ b/ts/components/dialog/ModalContainer.tsx @@ -8,7 +8,7 @@ import { getConversationSettingsModalState, getDebugMenuModalState, getDeleteAccountModalState, - getEditProfileDialog, + getUserSettingsModal, getEditProfilePictureModalState, getEnterPasswordModalState, getHideRecoveryPasswordModalState, @@ -25,7 +25,7 @@ import { getUpdateGroupMembersModal, getUserProfileModal, getLocalizedPopupDialogState, - getUpdateGroupOrCommunityDetailsModal, + getUpdateConversationDetailsModal, } from '../../state/selectors/modal'; import { LightboxGallery } from '../lightbox/LightboxGallery'; import { BanOrUnBanUserDialog } from './BanOrUnbanUserDialog'; @@ -42,9 +42,8 @@ import { ReactListModal } from './ReactListModal'; import { SessionNicknameDialog } from './SessionNicknameDialog'; import { SessionSetPasswordDialog } from './SessionSetPasswordDialog'; import { UpdateGroupMembersDialog } from './UpdateGroupMembersDialog'; -import { UpdateGroupOrCommunityDetailsDialog } from './UpdateGroupOrCommunityDetailsDialog'; +import { UpdateConversationDetailsDialog } from './UpdateConversationDetailsDialog'; import { UserProfileModal } from './UserProfileModal'; -import { EditProfileDialog } from './edit-profile/EditProfileDialog'; import { OpenUrlModal } from './OpenUrlModal'; import { BlockOrUnblockDialog } from './blockOrUnblock/BlockOrUnblockDialog'; import { DebugMenuModal } from './debug/DebugMenuModal'; @@ -53,6 +52,7 @@ import { SessionNetworkModal } from './network/SessionNetworkModal'; import { SessionConfirm } from './SessionConfirm'; import { SessionProInfoModal } from './SessionProInfoModal'; import { LocalizedPopupDialog } from './LocalizedPopupDialog'; +import { UserSettingsDialog } from './user-settings/UserSettingsDialog'; export const ModalContainer = () => { const confirmModalState = useSelector(getConfirmModal); @@ -60,10 +60,10 @@ export const ModalContainer = () => { const addModeratorsModalState = useSelector(getAddModeratorsModal); const removeModeratorsModalState = useSelector(getRemoveModeratorsModal); const updateGroupMembersModalState = useSelector(getUpdateGroupMembersModal); - const updateGroupOrCommunityDetailsState = useSelector(getUpdateGroupOrCommunityDetailsModal); + const updateConversationDetailsModalState = useSelector(getUpdateConversationDetailsModal); const userProfileModalState = useSelector(getUserProfileModal); const changeNicknameModal = useSelector(getChangeNickNameDialog); - const editProfileModalState = useSelector(getEditProfileDialog); + const userSettingsModalState = useSelector(getUserSettingsModal); const onionPathModalState = useSelector(getOnionPathDialog); const enterPasswordModalState = useSelector(getEnterPasswordModalState); const sessionPasswordModalState = useSelector(getSessionPasswordDialog); @@ -91,7 +91,7 @@ export const ModalContainer = () => { )} {sessionPasswordModalState && } {sessionNetworkModalState && } - {editProfileModalState && } + {userSettingsModalState && } {onionPathModalState && } {reactListModalState && } {debugMenuModalState && } @@ -104,8 +104,8 @@ export const ModalContainer = () => { {updateGroupMembersModalState && ( )} - {updateGroupOrCommunityDetailsState && ( - + {updateConversationDetailsModalState && ( + )} {userProfileModalState && } {changeNicknameModal && } diff --git a/ts/components/dialog/UpdateGroupOrCommunityDetailsDialog.tsx b/ts/components/dialog/UpdateConversationDetailsDialog.tsx similarity index 62% rename from ts/components/dialog/UpdateGroupOrCommunityDetailsDialog.tsx rename to ts/components/dialog/UpdateConversationDetailsDialog.tsx index f07b2d88e..fcd88cf82 100644 --- a/ts/components/dialog/UpdateGroupOrCommunityDetailsDialog.tsx +++ b/ts/components/dialog/UpdateConversationDetailsDialog.tsx @@ -4,14 +4,19 @@ import { useDispatch } from 'react-redux'; import useKey from 'react-use/lib/useKey'; import useMount from 'react-use/lib/useMount'; -import { useAvatarPath, useIsClosedGroup, useIsPublic } from '../../hooks/useParamSelector'; +import { + useAvatarPath, + useIsClosedGroup, + useIsMe, + useIsPublic, +} from '../../hooks/useParamSelector'; import { ConvoHub } from '../../session/conversations'; import { PubKey } from '../../session/types'; import LIBSESSION_CONSTANTS from '../../session/utils/libsession/libsession_constants'; import { groupInfoActions } from '../../state/ducks/metaGroups'; import { + updateConversationDetailsModal, updateEditProfilePictureModal, - updateGroupOrCommunityDetailsModal, } from '../../state/ducks/modalDialog'; import { useGroupNameChangeFromUIPending, @@ -28,16 +33,73 @@ import { SessionWrapperModal, } from '../SessionWrapperModal'; import { ClearInputButton } from '../inputs/ClearInputButton'; -import { UploadFirstImageButton } from './edit-profile/UploadFirstImage'; -import { ProfileAvatar } from './edit-profile/components'; +import { UploadFirstImageButton } from './user-settings/UploadFirstImage'; +import { ProfileAvatar } from './user-settings/components'; import { AvatarSize } from '../avatar/Avatar'; import { useChangeDetailsOfRoomPending, useRoomDescription, } from '../../state/selectors/sogsRoomInfo'; import { ReduxSogsRoomInfos } from '../../state/ducks/sogsRoomInfo'; +import type { WithConvoId } from '../../session/types/with'; + +function useNameErrorString({ + isMe, + isPublic, + newName, +}: { + newName: string | undefined; + isPublic: boolean; + isMe: boolean; +}) { + if (isMe) { + return !newName + ? tr('displayNameErrorDescription') + : newName.length > LIBSESSION_CONSTANTS.CONTACT_MAX_NAME_LENGTH + ? tr('displayNameErrorDescriptionShorter') + : ''; + } + if (isPublic) { + return !newName + ? tr('communityNameEnterPlease') + : newName.length > LIBSESSION_CONSTANTS.BASE_GROUP_MAX_NAME_LENGTH + ? tr('updateCommunityInformationEnterShorterName') + : ''; + } + return !newName + ? tr('groupNameEnterPlease') + : newName.length > LIBSESSION_CONSTANTS.BASE_GROUP_MAX_NAME_LENGTH + ? tr('groupNameEnterShorter') + : ''; +} + +function useDescriptionErrorString({ + isMe, + isPublic, + newDescription, +}: { + newDescription: string | undefined; + isPublic: boolean; + isMe: boolean; +}) { + if (isMe) { + // no error possible for description on isMe + return ''; + } -export function UpdateGroupOrCommunityDetailsDialog(props: { conversationId: string }) { + if (!newDescription) { + // description is always optional + return ''; + } + if (newDescription.length <= LIBSESSION_CONSTANTS.GROUP_INFO_DESCRIPTION_MAX_LENGTH) { + return ''; + } + return isPublic + ? tr('updateCommunityInformationEnterShorterDescription') + : tr('updateGroupInformationEnterShorterDescription'); +} + +export function UpdateConversationDetailsDialog(props: WithConvoId) { const dispatch = useDispatch(); const { conversationId } = props; const isClosedGroup = useIsClosedGroup(conversationId); @@ -46,6 +108,7 @@ export function UpdateGroupOrCommunityDetailsDialog(props: { conversationId: str const isGroupChangePending = useGroupNameChangeFromUIPending(); const isCommunityChangePending = useChangeDetailsOfRoomPending(conversationId); const isNameChangePending = isPublic ? isCommunityChangePending : isGroupChangePending; + const isMe = useIsMe(conversationId); const [avatarPointerOnMount, setAvatarPointerOnMount] = useState(''); const refreshedAvatarPointer = convo.getAvatarPointer() || ''; @@ -58,11 +121,12 @@ export function UpdateGroupOrCommunityDetailsDialog(props: { conversationId: str throw new Error('UpdateGroupOrCommunityDetailsDialog corresponding convo not found'); } - if (!isClosedGroup && !isPublic) { - throw new Error('groupNameUpdate dialog only works closed groups'); + if (!isClosedGroup && !isPublic && !isMe) { + throw new Error( + 'UpdateGroupOrCommunityDetailsDialog dialog only works groups/communities or ourselves' + ); } const nameOnOpen = convo.getRealSessionUsername(); - const originalGroupDescription = useLibGroupDescription(conversationId); const originalCommunityDescription = useRoomDescription(conversationId); const descriptionOnOpen = isPublic ? originalCommunityDescription : originalGroupDescription; @@ -72,7 +136,7 @@ export function UpdateGroupOrCommunityDetailsDialog(props: { conversationId: str const avatarPath = useAvatarPath(conversationId) || ''; function closeDialog() { - dispatch(updateGroupOrCommunityDetailsModal(null)); + dispatch(updateConversationDetailsModal(null)); } function onClickOK() { @@ -126,37 +190,32 @@ export function UpdateGroupOrCommunityDetailsDialog(props: { conversationId: str useKey('Escape', closeDialog); useKey('Esc', closeDialog); - const errorStringName = !newName - ? tr(isPublic ? 'communityNameEnterPlease' : 'groupNameEnterPlease') - : newName.length > LIBSESSION_CONSTANTS.BASE_GROUP_MAX_NAME_LENGTH - ? tr(isPublic ? 'updateCommunityInformationEnterShorterName' : 'groupNameEnterShorter') - : ''; - const errorStringDescription = - newDescription && newDescription.length > LIBSESSION_CONSTANTS.GROUP_INFO_DESCRIPTION_MAX_LENGTH - ? tr( - isPublic - ? 'updateCommunityInformationEnterShorterDescription' - : 'updateGroupInformationEnterShorterDescription' - ) - : ''; + const errorStringName = useNameErrorString({ newName, isPublic, isMe }); + const errorStringDescription = useDescriptionErrorString({ isMe, isPublic, newDescription }); function handleEditProfilePicture() { - if (!isPublic) { - throw new Error('handleEditProfilePicture is only for communities'); + if ( + isPublic || + isMe || + (PubKey.is03Pubkey(conversationId) && window.sessionFeatureFlags.useClosedGroupV2QAButtons) + ) { + dispatch(updateEditProfilePictureModal({ conversationId })); + return; } - dispatch(updateEditProfilePictureModal({ conversationId })); + throw new Error('handleEditProfilePicture is only for communities or ourselves for now'); } const noChanges = newName === nameOnOpen && newDescription === descriptionOnOpen; const avatarWasUpdated = avatarPointerOnMount !== refreshedAvatarPointer; + const partDetail = isMe ? 'profile' : isPublic ? 'community' : 'group'; + const partDetailCap = (partDetail.charAt(0).toUpperCase() + partDetail.slice(1)) as Capitalize< + typeof partDetail + >; + return ( - } + headerChildren={} onClose={closeDialog} buttonChildren={ @@ -177,7 +236,7 @@ export function UpdateGroupOrCommunityDetailsDialog(props: { conversationId: str } > - {isPublic ? ( + {isPublic || isMe ? ( avatarPath ? ( ) ) : null} - {/* right now we only support changing the name of a community */} { setNewName(''); }} @@ -222,38 +276,32 @@ export function UpdateGroupOrCommunityDetailsDialog(props: { conversationId: str } /> - { - setNewDescription(''); - }} - show={!!newDescription} - /> - } - /> + {!isMe && partDetail !== 'profile' && ( + { + setNewDescription(''); + }} + show={!!newDescription} + /> + } + /> + )} diff --git a/ts/components/dialog/UserProfileModal.tsx b/ts/components/dialog/UserProfileModal.tsx index a04cf922c..b08669607 100644 --- a/ts/components/dialog/UserProfileModal.tsx +++ b/ts/components/dialog/UserProfileModal.tsx @@ -19,8 +19,8 @@ import { } from '../SessionWrapperModal'; import { tr } from '../../localization/localeTools'; import { PubKey } from '../../session/types'; -import type { ProfileDialogModes } from './edit-profile/ProfileDialogModes'; -import { ProfileHeader, QRView } from './edit-profile/components'; +import type { ProfileDialogModes } from './user-settings/ProfileDialogModes'; +import { ProfileHeader, QRView } from './user-settings/components'; import { useAvatarPath, useConversationUsernameWithFallback } from '../../hooks/useParamSelector'; import { SessionLucideIconButton } from '../icon/SessionIconButton'; import { LUCIDE_ICONS_UNICODE } from '../icon/lucide'; @@ -69,7 +69,7 @@ export const UserProfileModal = ({ dispatch(updateUserProfileModal(null)); } - const [mode, setMode] = useState>('default'); + const [mode, setMode] = useState('default'); const hasDisabledMsgRequests = useHasDisabledBlindedMsgRequests(conversationId); const blindedAndDisabledMsgRequests = isBlindedAndNotResolved && hasDisabledMsgRequests; diff --git a/ts/components/dialog/conversationSettings/conversationSettingsHeader.tsx b/ts/components/dialog/conversationSettings/conversationSettingsHeader.tsx index 209afb418..b980ded9b 100644 --- a/ts/components/dialog/conversationSettings/conversationSettingsHeader.tsx +++ b/ts/components/dialog/conversationSettings/conversationSettingsHeader.tsx @@ -16,8 +16,8 @@ import { UsernameFallback } from './UsernameFallback'; import { ConversationTitleDialog } from './ConversationTitleDialog'; import { SessionIDNotEditable } from '../../basic/SessionIdNotEditable'; import { AccountIdPill } from '../../basic/AccountIdPill'; -import { ProfileHeader, QRView } from '../edit-profile/components'; -import type { ProfileDialogModes } from '../edit-profile/ProfileDialogModes'; +import { ProfileHeader, QRView } from '../user-settings/components'; +import type { ProfileDialogModes } from '../user-settings/ProfileDialogModes'; import { SessionUtilUserGroups } from '../../../session/utils/libsession/libsession_utils_user_groups'; function AccountId({ conversationId }: WithConvoId) { @@ -161,7 +161,7 @@ export const ConversationSettingsHeader = ({ conversationId }: WithConvoId) => { conversationId={conversationId} dataTestId="profile-picture" // 1. We don't want to show the plus button for the current user - // as he needs to change his avatar through the EditProfileDialog + // as he needs to change his avatar through the UserSettingsModal // 2. We don't want to show the plus button for communities as they already have a qr button. // Editing the avatar is done through the pencil icon in the ModalHeader onPlusAvatarClick={!isMe && !isPublic ? (editProfilePictureCb ?? null) : null} diff --git a/ts/components/dialog/edit-profile/EditProfileDialog.tsx b/ts/components/dialog/edit-profile/EditProfileDialog.tsx deleted file mode 100644 index 0883fb617..000000000 --- a/ts/components/dialog/edit-profile/EditProfileDialog.tsx +++ /dev/null @@ -1,349 +0,0 @@ -import { isEmpty } from 'lodash'; -import { RefObject, useRef, useState } from 'react'; -import { useDispatch } from 'react-redux'; -import styled from 'styled-components'; -import useClickAway from 'react-use/lib/useClickAway'; -import { Dispatch } from '@reduxjs/toolkit'; - -import { UserUtils } from '../../../session/utils'; - -import { useHotkey } from '../../../hooks/useHotkey'; -import { useOurAvatarPath, useOurConversationUsername } from '../../../hooks/useParamSelector'; -import { ProfileManager } from '../../../session/profile_manager/ProfileManager'; -import { editProfileModal } from '../../../state/ducks/modalDialog'; -import { SessionSpinner } from '../../loading'; -import { ProfileHeader, ProfileName, QRView } from './components'; -import { EmptyDisplayNameError, RetrieveDisplayNameError } from '../../../session/utils/errors'; -import { tr } from '../../../localization/localeTools'; -import { sanitizeDisplayNameOrToast } from '../../registration/utils'; -import { useEditProfilePictureCallback } from '../../menuAndSettingsHooks/useEditProfilePictureCallback'; -import { SimpleSessionInput } from '../../inputs/SessionInput'; -import { - ModalBasicHeader, - ModalActionsContainer, - SessionWrapperModal, - ModalBottomButtonWithBorder, -} from '../../SessionWrapperModal'; -import { SessionButtonColor } from '../../basic/SessionButton'; -import { CopyToClipboardButton } from '../../buttons'; -import { SessionIDNotEditable } from '../../basic/SessionIdNotEditable'; -import { Flex } from '../../basic/Flex'; -import { AccountIdPill } from '../../basic/AccountIdPill'; -import { ModalPencilIcon } from '../shared/ModalPencilButton'; -import type { ProfileDialogModes } from './ProfileDialogModes'; - -// #region Shortcuts -const handleKeyQRMode = ( - mode: ProfileDialogModes, - setMode: (mode: ProfileDialogModes) => void, - loading: boolean -) => { - if (loading) { - return; - } - switch (mode) { - case 'default': - setMode('qr'); - break; - case 'qr': - setMode('default'); - break; - case 'edit': - default: - } -}; - -const handleKeyEditMode = ( - mode: ProfileDialogModes, - setMode: (mode: ProfileDialogModes) => void, - onClick: () => Promise, - loading: boolean -) => { - if (loading) { - return; - } - switch (mode) { - case 'default': - setMode('edit'); - break; - case 'edit': - void onClick(); - break; - case 'qr': - default: - } -}; - -const handleKeyCancel = ( - mode: ProfileDialogModes, - setMode: (mode: ProfileDialogModes) => void, - inputRef: RefObject, - updatedProfileName: string, - setProfileName: (name: string) => void, - setProfileNameError: (error: string | undefined) => void, - loading: boolean -) => { - if (loading) { - return; - } - switch (mode) { - case 'edit': - case 'qr': - if (inputRef.current !== null && document.activeElement === inputRef.current) { - return; - } - setMode('default'); - if (mode === 'edit') { - setProfileNameError(undefined); - setProfileName(updatedProfileName); - } - break; - case 'default': - default: - } -}; - -const handleKeyEscape = ( - mode: ProfileDialogModes, - cancelEdit: () => void, - loading: boolean, - dispatch: Dispatch -) => { - if (loading) { - return; - } - - if (mode === 'edit') { - cancelEdit(); - } else { - dispatch(editProfileModal(null)); - } -}; - -// #endregion - -const StyledEditProfileDialog = styled.div` - input { - border: none; - } -`; - -export const EditProfileDialog = () => { - const dispatch = useDispatch(); - - const _profileName = useOurConversationUsername() || ''; - const [profileName, setProfileName] = useState(_profileName); - const [profileNameError, setProfileNameError] = useState(undefined); - const [cannotContinue, setCannotContinue] = useState(true); - const [enlargedImage, setEnlargedImage] = useState(false); - - const copyButtonRef = useRef(null); - const inputRef = useRef(null); - - const avatarPath = useOurAvatarPath() || ''; - const us = UserUtils.getOurPubKeyStrFromCache(); - - const editProfilePictureCb = useEditProfilePictureCallback({ conversationId: us }); - const [mode, setMode] = useState('default'); - const [loading, setLoading] = useState(false); - - const closeDialog = (event?: any) => { - if (event?.key || loading) { - return; - } - dispatch(editProfileModal(null)); - }; - - const onClickOK = async () => { - try { - setLoading(true); - const sanitizedName = sanitizeDisplayNameOrToast(profileName); - - // this should never happen, but just in case - if (isEmpty(sanitizedName)) { - return; - } - - // Note: this will not throw, but just truncate the display name if it is too long. - // I guess it is expected as there is no UI to show anything else than a generic error? - const validName = await ProfileManager.updateOurProfileDisplayName(sanitizedName); - setProfileName(validName); - setMode('default'); - } catch (err) { - window.log.error('Profile update error', err); - setCannotContinue(true); - - if (err instanceof EmptyDisplayNameError || err instanceof RetrieveDisplayNameError) { - setProfileNameError(tr('displayNameErrorDescription')); - } else { - setProfileNameError(tr('errorUnknown')); - } - } finally { - setLoading(false); - } - }; - - const handleProfileHeaderClick = () => { - if (loading) { - return; - } - closeDialog(); - editProfilePictureCb?.(); - }; - - useHotkey('v', () => handleKeyQRMode(mode, setMode, loading), loading); - useHotkey('Enter', () => handleKeyEditMode(mode, setMode, onClickOK, loading), loading); - useHotkey( - 'Backspace', - () => - handleKeyCancel( - mode, - setMode, - inputRef, - profileName, - setProfileName, - setProfileNameError, - loading - ), - loading - ); - useHotkey('Escape', () => handleKeyEscape(mode, cancelEdit, loading, dispatch), loading); - - function cancelEdit() { - if (loading) { - return; - } - setMode('default'); - setProfileNameError(undefined); - setProfileName(_profileName); - } - - useClickAway(inputRef, () => { - if (mode === 'edit') { - cancelEdit(); - } - }); - - return ( - - setMode('edit')} />} - /> - } - onClose={closeDialog} - shouldOverflow={true} - buttonChildren={ - mode === 'default' || mode === 'qr' ? ( - // some bottom margin as the buttons have a border and appear to close to the edge - - - {mode === 'default' ? ( - { - setMode('qr'); - }} - buttonColor={SessionButtonColor.PrimaryDark} - dataTestId="view-qr-code-button" - /> - ) : null} - - ) : ( - !loading && ( - - - - - ) - ) - } - > - - {mode === 'qr' ? ( - setMode('default')} /> - ) : ( - setEnlargedImage(!enlargedImage)} - /> - )} - {mode === 'default' && ( - { - if (loading) { - return; - } - setMode('edit'); - }} - /> - )} - {mode === 'edit' && ( - { - setProfileName(name); - setCannotContinue(false); - }} - onEnterPressed={() => void onClickOK()} - disabled={loading} - tabIndex={0} - required={true} - centerText={true} - providedError={profileNameError} - textSize={'xl'} - inputRef={inputRef} - inputDataTestId="profile-name-input" - errorDataTestId="error-message" - padding="var(--margins-xs) var(--margins-lg)" - /> - )} - - - - - - - ); -}; diff --git a/ts/components/dialog/edit-profile/ProfileDialogModes.ts b/ts/components/dialog/edit-profile/ProfileDialogModes.ts deleted file mode 100644 index 612012fbd..000000000 --- a/ts/components/dialog/edit-profile/ProfileDialogModes.ts +++ /dev/null @@ -1 +0,0 @@ -export type ProfileDialogModes = 'default' | 'edit' | 'qr'; diff --git a/ts/components/dialog/user-settings/ProfileDialogModes.ts b/ts/components/dialog/user-settings/ProfileDialogModes.ts new file mode 100644 index 000000000..4b3678b06 --- /dev/null +++ b/ts/components/dialog/user-settings/ProfileDialogModes.ts @@ -0,0 +1 @@ +export type ProfileDialogModes = 'default' | 'qr'; diff --git a/ts/components/dialog/edit-profile/UploadFirstImage.tsx b/ts/components/dialog/user-settings/UploadFirstImage.tsx similarity index 100% rename from ts/components/dialog/edit-profile/UploadFirstImage.tsx rename to ts/components/dialog/user-settings/UploadFirstImage.tsx diff --git a/ts/components/dialog/user-settings/UserSettingsDialog.tsx b/ts/components/dialog/user-settings/UserSettingsDialog.tsx new file mode 100644 index 000000000..7e3e47076 --- /dev/null +++ b/ts/components/dialog/user-settings/UserSettingsDialog.tsx @@ -0,0 +1,310 @@ +import { RefObject, useRef, useState } from 'react'; +import { useDispatch } from 'react-redux'; +import styled from 'styled-components'; + +import { UserUtils } from '../../../session/utils'; + +import { useHotkey } from '../../../hooks/useHotkey'; +import { useOurAvatarPath, useOurConversationUsername } from '../../../hooks/useParamSelector'; +import { + updateConversationDetailsModal, + userSettingsModal, +} from '../../../state/ducks/modalDialog'; +import { ProfileHeader, ProfileName, QRView } from './components'; +import { tr } from '../../../localization/localeTools'; +import { ModalBasicHeader, SessionWrapperModal } from '../../SessionWrapperModal'; +import { SessionIDNotEditable } from '../../basic/SessionIdNotEditable'; +import { Flex } from '../../basic/Flex'; +import { AccountIdPill } from '../../basic/AccountIdPill'; +import { ModalPencilIcon } from '../shared/ModalPencilButton'; +import type { ProfileDialogModes } from './ProfileDialogModes'; +import { SessionLucideIconButton } from '../../icon/SessionIconButton'; +import { LUCIDE_ICONS_UNICODE } from '../../icon/lucide'; +import { PanelButtonGroup, PanelIconButton } from '../../buttons'; +import { LOCALE_DEFAULTS } from '../../../localization/constants'; +import { ProIconButton } from '../../buttons/ProButton'; +import { LucideIcon, type LucideIconProps } from '../../icon/LucideIcon'; +import { SessionIcon, type SessionIconProps } from '../../icon'; + +const handleKeyQRMode = (mode: ProfileDialogModes, setMode: (mode: ProfileDialogModes) => void) => { + switch (mode) { + case 'default': + setMode('qr'); + break; + case 'qr': + setMode('default'); + break; + default: + } +}; + +const handleKeyCancel = ( + mode: ProfileDialogModes, + setMode: (mode: ProfileDialogModes) => void, + inputRef: RefObject +) => { + switch (mode) { + case 'qr': + if (inputRef.current !== null && document.activeElement === inputRef.current) { + return; + } + setMode('default'); + break; + case 'default': + default: + } +}; + +function SessionIconForSettings(props: Omit) { + return ; +} + +function LucideIconForSettings(props: Omit) { + return ; +} +const StyledUserSettingsDialog = styled.div``; + +function SessionProSection() { + return ( + + + } + text={LOCALE_DEFAULTS.app_pro} + onClick={() => { + throw new Error('Not implemented'); // TODO: add link to pro page + }} + dataTestId="session-pro-settings-menu-item" + color="var(--renderer-span-primary-color)" + /> + + ); +} + +function MiscSection() { + return ( + + + } + text={tr('donate')} + onClick={() => { + throw new Error('Not implemented'); + }} + dataTestId="donate-settings-menu-item" + /> + } + text={tr('onionRoutingPath')} + onClick={() => { + throw new Error('Not implemented'); + }} + dataTestId="path-light-container" + /> + } + text={LOCALE_DEFAULTS.network_name} + onClick={() => { + throw new Error('Not implemented'); + }} + dataTestId="session-network-settings-menu-item" + /> + + ); +} + +function SettingsSection() { + return ( + + } + text={tr('sessionPrivacy')} + onClick={() => { + throw new Error('Not implemented'); + }} + dataTestId="privacy-settings-menu-item" + /> + } + text={tr('sessionNotifications')} + onClick={() => { + throw new Error('Not implemented'); + }} + dataTestId="notifications-settings-menu-item" + /> + } + text={tr('sessionConversations')} + onClick={() => { + throw new Error('Not implemented'); + }} + dataTestId="conversations-settings-menu-item" + /> + } + text={tr('sessionAppearance')} + onClick={() => { + throw new Error('Not implemented'); + }} + dataTestId="appearance-settings-menu-item" + /> + + } + text={tr('sessionMessageRequests')} + onClick={() => { + throw new Error('Not implemented'); + }} + dataTestId="message-requests-settings-menu-item" + /> + } + text={tr('preferences')} + onClick={() => { + throw new Error('Not implemented'); + }} + dataTestId="preferences-settings-menu-item" + /> + + ); +} + +function AdminSection() { + return ( + + } + text={tr('sessionRecoveryPassword')} + onClick={() => { + throw new Error('Not implemented'); + }} + dataTestId="recovery-password-settings-menu-item" + /> + } + text={tr('sessionHelp')} + onClick={() => { + throw new Error('Not implemented'); + }} + dataTestId="help-settings-menu-item" + /> + + } + text={tr('sessionClearData')} + onClick={() => { + throw new Error('Not implemented'); + }} + dataTestId="clear-data-settings-menu-item" + color="var(--danger-color)" + /> + + ); +} + +export const UserSettingsDialog = () => { + const dispatch = useDispatch(); + + const profileName = useOurConversationUsername() || ''; + const [enlargedImage, setEnlargedImage] = useState(false); + const inputRef = useRef(null); + + const avatarPath = useOurAvatarPath() || ''; + const us = UserUtils.getOurPubKeyStrFromCache(); + + const [mode, setMode] = useState('default'); + + const showUpdateProfileInformation = () => { + dispatch(updateConversationDetailsModal({ conversationId: us })); + }; + + useHotkey('v', () => handleKeyQRMode(mode, setMode)); + useHotkey('Backspace', () => handleKeyCancel(mode, setMode, inputRef)); + useHotkey('Escape', () => closeDialog()); + + function copyAccountIdToClipboard() { + window.clipboard.writeText(us); + } + + function closeDialog() { + dispatch(userSettingsModal(null)); + } + + return ( + + } + /> + } + onClose={closeDialog} + shouldOverflow={true} + buttonChildren={null} + > + + {mode === 'qr' ? ( + setMode('default')} /> + ) : ( + setMode('qr')} + enlargedImage={enlargedImage} + toggleEnlargedImage={() => setEnlargedImage(!enlargedImage)} + /> + )} + {mode === 'default' && ( + + )} + + + + } + style={{ color: 'var(--text-primary-color)' }} + onClick={copyAccountIdToClipboard} + /> + + + + + + + + + ); +}; diff --git a/ts/components/dialog/edit-profile/components.tsx b/ts/components/dialog/user-settings/components.tsx similarity index 100% rename from ts/components/dialog/edit-profile/components.tsx rename to ts/components/dialog/user-settings/components.tsx diff --git a/ts/components/leftpane/ActionsPanel.tsx b/ts/components/leftpane/ActionsPanel.tsx index 44b82590b..c97ef8de7 100644 --- a/ts/components/leftpane/ActionsPanel.tsx +++ b/ts/components/leftpane/ActionsPanel.tsx @@ -25,7 +25,7 @@ import { DURATION } from '../../session/constants'; import { reuploadCurrentAvatarUs } from '../../interactions/avatar-interactions/nts-avatar-interactions'; import { - editProfileModal, + userSettingsModal, onionPathModal, updateDebugMenuModal, } from '../../state/ducks/modalDialog'; @@ -101,7 +101,7 @@ const Section = (props: { type: SectionType }) => { const handleClick = () => { if (type === SectionType.Profile) { - dispatch(editProfileModal({})); + dispatch(userSettingsModal({})); } else if (type === SectionType.ColorMode) { void handleThemeSwitch(); } else if (type === SectionType.PathIndicator) { diff --git a/ts/components/leftpane/LeftPaneSettingSection.tsx b/ts/components/leftpane/LeftPaneSettingSection.tsx index 75230e811..a56504761 100644 --- a/ts/components/leftpane/LeftPaneSettingSection.tsx +++ b/ts/components/leftpane/LeftPaneSettingSection.tsx @@ -97,26 +97,7 @@ const categories: Array = ( titleColor: 'var(--renderer-span-primary-color)', icon: { type: 'custom', content: 'sessionPro', color: 'var(--renderer-span-primary-color)' }, }, - { - id: 'privacy', - title: tr('sessionPrivacy'), - icon: { type: 'lucide', unicode: LUCIDE_ICONS_UNICODE.LOCK_KEYHOLE }, - }, - { - id: 'session-network', - title: LOCALE_DEFAULTS.network_name, - icon: { type: 'sessionToken' }, - }, - { - id: 'donate', - title: tr('donate'), - titleColor: 'var(--renderer-span-primary-color)', - icon: { - type: 'lucide', - unicode: LUCIDE_ICONS_UNICODE.HEART, - color: 'var(--renderer-span-primary-color)', - }, - }, + { id: 'notifications', title: tr('sessionNotifications'), @@ -142,22 +123,6 @@ const categories: Array = ( title: tr('sessionPermissions'), icon: { type: 'lucide', unicode: LUCIDE_ICONS_UNICODE.CIRCLE_CHECK }, }, - { - id: 'recovery-password', - title: tr('sessionRecoveryPassword'), - icon: { type: 'recoveryPasswordFill' }, - }, - { - id: 'help', - title: tr('sessionHelp'), - icon: { type: 'lucide', unicode: LUCIDE_ICONS_UNICODE.CIRCLE_HELP }, - }, - { - id: 'clear-data', - title: tr('sessionClearData'), - titleColor: 'var(--danger-color)', - icon: { type: 'lucide', unicode: LUCIDE_ICONS_UNICODE.TRASH2, color: 'var(--danger-color)' }, - }, ] as const satisfies Array> ).map(m => ({ ...m, diff --git a/ts/components/loading/spinner/StyledSessionSpinner.tsx b/ts/components/loading/spinner/StyledSessionSpinner.tsx index a8ce66f5a..90bb5780a 100644 --- a/ts/components/loading/spinner/StyledSessionSpinner.tsx +++ b/ts/components/loading/spinner/StyledSessionSpinner.tsx @@ -17,8 +17,8 @@ export const StyledSessionSpinner = styled.div` div { position: absolute; top: calc(50% - 6.5px); - width: 16.25%; - height: 16.25%; + width: 13px; + height: 13px; border-radius: 50%; background: ${props => props.color || 'var(--primary-color)'}; animation-timing-function: cubic-bezier(0, 1, 1, 0); diff --git a/ts/interactions/conversationInteractions.ts b/ts/interactions/conversationInteractions.ts index f839db99c..5032b67cd 100644 --- a/ts/interactions/conversationInteractions.ts +++ b/ts/interactions/conversationInteractions.ts @@ -27,7 +27,7 @@ import { updateConfirmModal, updateConversationSettingsModal, updateGroupMembersModal, - updateGroupOrCommunityDetailsModal, + updateConversationDetailsModal, } from '../state/ducks/modalDialog'; import { Storage } from '../util/storage'; import { UserGroupsWrapperActions } from '../webworker/workers/browser/libsession_worker_interface'; @@ -276,7 +276,7 @@ export async function showUpdateGroupOrCommunityDetailsByConvoId(conversationId: .map(m => ConvoHub.use().getOrCreateAndWait(m, ConversationTypeEnum.PRIVATE)) ); } - window.inboxStore?.dispatch(updateGroupOrCommunityDetailsModal({ conversationId })); + window.inboxStore?.dispatch(updateConversationDetailsModal({ conversationId })); } export async function showUpdateGroupMembersByConvoId(conversationId: string) { diff --git a/ts/react.d.ts b/ts/react.d.ts index 7b70faa8c..a6754bfee 100644 --- a/ts/react.d.ts +++ b/ts/react.d.ts @@ -73,8 +73,8 @@ declare module 'react' { type CancelButtons = 'update-group-info' | 'add-admins' | 'unban-user' | 'modal-session-pro'; type ClearButtons = - | `${'group' | 'community'}-info-description` - | `${'group' | 'community'}-info-name` + | `${'group' | 'community' | 'profile'}-info-description` + | `${'group' | 'community' | 'profile'}-info-name` | 'nickname' | 'add-admins'; @@ -93,6 +93,7 @@ declare module 'react' { | 'clear-data' | 'session-network' | 'session-pro' + | 'preferences' | 'donate'; type MenuItems = 'block' | 'delete' | 'accept'; @@ -102,8 +103,8 @@ declare module 'react' { | 'nickname' | 'profile-name' | 'message' - | `update-${'group' | 'community'}-info-name` - | `update-${'group' | 'community'}-info-description` + | `update-${'group' | 'community' | 'profile'}-info-name` + | `update-${'group' | 'community' | 'profile'}-info-description` | 'recovery-phrase' | 'display-name' | 'add-admins' @@ -119,7 +120,7 @@ declare module 'react' { | 'message-info' | 'send-more'; - type Dialog = 'invite-contacts' | 'edit-profile'; + type Dialog = 'invite-contacts' | 'user-settings'; type Buttons = | 'chooser-new-conversation' diff --git a/ts/state/ducks/metaGroups.ts b/ts/state/ducks/metaGroups.ts index 5bab40d4e..b32ae8ad9 100644 --- a/ts/state/ducks/metaGroups.ts +++ b/ts/state/ducks/metaGroups.ts @@ -50,7 +50,7 @@ import { WithFromMemberLeftMessage, WithRemoveMembers, } from '../../session/types/with'; -import { updateEditProfilePictureModal, updateGroupOrCommunityDetailsModal } from './modalDialog'; +import { updateEditProfilePictureModal, updateConversationDetailsModal } from './modalDialog'; import { tr } from '../../localization/localeTools'; import { type GroupMemberGetRedux, makeGroupMemberGetRedux } from './types/groupReduxTypes'; import { uploadFileToFsWithOnionV4 } from '../../session/apis/file_server_api/FileServerApi'; @@ -1443,7 +1443,7 @@ const currentDeviceGroupNameChange = createAsyncThunk( await checkWeAreAdminOrThrow(groupPk, 'currentDeviceGroupNameChange'); await handleNameChangeFromUI({ groupPk, ...args }); - window.inboxStore?.dispatch(updateGroupOrCommunityDetailsModal(null)); + window.inboxStore?.dispatch(updateConversationDetailsModal(null)); return { groupPk, diff --git a/ts/state/ducks/modalDialog.tsx b/ts/state/ducks/modalDialog.tsx index 9f261255e..08b03a3c7 100644 --- a/ts/state/ducks/modalDialog.tsx +++ b/ts/state/ducks/modalDialog.tsx @@ -24,12 +24,12 @@ export type BanOrUnbanUserModalState = export type AddModeratorsModalState = InviteContactModalState; export type RemoveModeratorsModalState = InviteContactModalState; export type UpdateGroupMembersModalState = InviteContactModalState; -export type UpdateGroupOrCommunityDetailsModalState = WithConvoId | null; +type UpdateConversationDetailsModalState = WithConvoId | null; export type ChangeNickNameModalState = InviteContactModalState; -export type EditProfileModalState = object | null; -export type OnionPathModalState = EditProfileModalState; +export type UserSettingsModalState = object | null; +export type OnionPathModalState = object | null; export type EnterPasswordModalState = EnterPasswordModalProps | null; -export type DeleteAccountModalState = EditProfileModalState; +export type DeleteAccountModalState = object | null; export type OpenUrlModalState = { urlToOpen: string } | null; export type LocalizedPopupDialogState = { title: TrArgs; @@ -84,11 +84,11 @@ export type ModalState = { blockOrUnblockModal: BlockOrUnblockModalState; removeModeratorsModal: RemoveModeratorsModalState; addModeratorsModal: AddModeratorsModalState; - groupOrCommunityDetailsModal: UpdateGroupOrCommunityDetailsModalState; + updateConversationDetailsModal: UpdateConversationDetailsModalState; groupMembersModal: UpdateGroupMembersModalState; userProfileModal: UserProfileModalState; nickNameModal: ChangeNickNameModalState; - editProfileModal: EditProfileModalState; + userSettingsModal: UserSettingsModalState; onionPathModal: OnionPathModalState; enterPasswordModal: EnterPasswordModalState; sessionPasswordModal: SessionPasswordModalState; @@ -113,11 +113,11 @@ export const initialModalState: ModalState = { removeModeratorsModal: null, banOrUnbanUserModal: null, blockOrUnblockModal: null, - groupOrCommunityDetailsModal: null, + updateConversationDetailsModal: null, groupMembersModal: null, userProfileModal: null, nickNameModal: null, - editProfileModal: null, + userSettingsModal: null, onionPathModal: null, enterPasswordModal: null, sessionPasswordModal: null, @@ -157,11 +157,11 @@ const ModalSlice = createSlice({ updateRemoveModeratorsModal(state, action: PayloadAction) { return { ...state, removeModeratorsModal: action.payload }; }, - updateGroupOrCommunityDetailsModal( + updateConversationDetailsModal( state, - action: PayloadAction + action: PayloadAction ) { - return { ...state, groupOrCommunityDetailsModal: action.payload }; + return { ...state, updateConversationDetailsModal: action.payload }; }, updateGroupMembersModal(state, action: PayloadAction) { return { ...state, groupMembersModal: action.payload }; @@ -172,8 +172,8 @@ const ModalSlice = createSlice({ changeNickNameModal(state, action: PayloadAction) { return { ...state, nickNameModal: action.payload }; }, - editProfileModal(state, action: PayloadAction) { - return { ...state, editProfileModal: action.payload }; + userSettingsModal(state, action: PayloadAction) { + return { ...state, userSettingsModal: action.payload }; }, onionPathModal(state, action: PayloadAction) { return { ...state, onionPathModal: action.payload }; @@ -243,11 +243,11 @@ export const { updateInviteContactModal, updateAddModeratorsModal, updateRemoveModeratorsModal, - updateGroupOrCommunityDetailsModal, + updateConversationDetailsModal, updateGroupMembersModal, updateUserProfileModal, changeNickNameModal, - editProfileModal, + userSettingsModal, onionPathModal, updateEnterPasswordModal, sessionPassword, diff --git a/ts/state/ducks/sogsRoomInfo.tsx b/ts/state/ducks/sogsRoomInfo.tsx index 7e742603d..65a38653f 100644 --- a/ts/state/ducks/sogsRoomInfo.tsx +++ b/ts/state/ducks/sogsRoomInfo.tsx @@ -7,7 +7,7 @@ import { downloadAttachmentSogsV3 } from '../../receiver/attachments'; import { uploadImageForRoomSogsV3 } from '../../session/apis/open_group_api/sogsv3/sogsV3RoomImage'; import { MIME } from '../../types'; import { processNewAttachment } from '../../types/MessageAttachment'; -import { updateEditProfilePictureModal, updateGroupOrCommunityDetailsModal } from './modalDialog'; +import { updateConversationDetailsModal, updateEditProfilePictureModal } from './modalDialog'; import { changeRoomDetailsSogsV3 } from '../../session/apis/open_group_api/sogsv3/sogsV3RoomInfosChange'; type RoomInfo = { @@ -60,7 +60,7 @@ const roomDetailsChange = createAsyncThunk( roomName: newName, roomDescription: newDescription, }); - window.inboxStore?.dispatch(updateGroupOrCommunityDetailsModal(null)); + window.inboxStore?.dispatch(updateConversationDetailsModal(null)); return true; } diff --git a/ts/state/ducks/user.ts b/ts/state/ducks/user.ts index c189c45af..842ce9522 100644 --- a/ts/state/ducks/user.ts +++ b/ts/state/ducks/user.ts @@ -5,7 +5,7 @@ import { SyncUtils, UserUtils } from '../../session/utils'; import { getSodiumRenderer } from '../../session/crypto'; import { uploadAndSetOurAvatarShared } from '../../interactions/avatar-interactions/nts-avatar-interactions'; import { ed25519Str } from '../../session/utils/String'; -import { editProfileModal, updateEditProfilePictureModal } from './modalDialog'; +import { userSettingsModal, updateEditProfilePictureModal } from './modalDialog'; export type UserStateType = { ourDisplayNameInProfile: string; @@ -44,7 +44,7 @@ const updateOurAvatar = createAsyncThunk( }); window.inboxStore?.dispatch(updateEditProfilePictureModal(null)); - window.inboxStore?.dispatch(editProfileModal({})); + window.inboxStore?.dispatch(userSettingsModal({})); return res; } @@ -108,7 +108,7 @@ const userSlice = createSlice({ }, extraReducers: builder => { builder.addCase(updateOurAvatar.fulfilled, (state, action) => { - window.log.error('a updateOurAvatar was fulfilled with:', action.payload); + window.log.info('a updateOurAvatar was fulfilled with:', action.payload); state.uploadingNewAvatarCurrentUser = false; return state; diff --git a/ts/state/selectors/modal.ts b/ts/state/selectors/modal.ts index 3e27bfef8..b0d786c90 100644 --- a/ts/state/selectors/modal.ts +++ b/ts/state/selectors/modal.ts @@ -33,8 +33,8 @@ export const getBanOrUnbanUserModalState = (state: StateType) => export const getBlockOrUnblockUserModalState = (state: StateType) => getModal(state).blockOrUnblockModal; -export const getUpdateGroupOrCommunityDetailsModal = (state: StateType) => - getModal(state).groupOrCommunityDetailsModal; +export const getUpdateConversationDetailsModal = (state: StateType) => + getModal(state).updateConversationDetailsModal; export const getUpdateGroupMembersModal = (state: StateType) => getModal(state).groupMembersModal; @@ -42,7 +42,7 @@ export const getUserProfileModal = (state: StateType) => getModal(state).userPro export const getChangeNickNameDialog = (state: StateType) => getModal(state).nickNameModal; -export const getEditProfileDialog = (state: StateType) => getModal(state).editProfileModal; +export const getUserSettingsModal = (state: StateType) => getModal(state).userSettingsModal; export const getOnionPathDialog = (state: StateType) => getModal(state).onionPathModal; From ceb07e100feff82ddd03cc5d04fe73bb999136a0 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Wed, 13 Aug 2025 11:46:42 +1000 Subject: [PATCH 02/18] feat: moved all of the privacy screen to userSettingsModal --- _locales/af/messages.json | 3 - _locales/ar/messages.json | 3 - _locales/az/messages.json | 3 - _locales/bal/messages.json | 3 - _locales/be/messages.json | 3 - _locales/bg/messages.json | 3 - _locales/bn/messages.json | 3 - _locales/ca/messages.json | 3 - _locales/cs/messages.json | 3 - _locales/cy/messages.json | 3 - _locales/da/messages.json | 3 - _locales/de/messages.json | 3 - _locales/el/messages.json | 3 - _locales/en/messages.json | 16 +- _locales/eo/messages.json | 3 - _locales/es-419/messages.json | 3 - _locales/es/messages.json | 3 - _locales/et/messages.json | 3 - _locales/eu/messages.json | 3 - _locales/fa/messages.json | 3 - _locales/fi/messages.json | 3 - _locales/fil/messages.json | 3 - _locales/fr/messages.json | 3 - _locales/gl/messages.json | 3 - _locales/ha/messages.json | 3 - _locales/he/messages.json | 3 - _locales/hi/messages.json | 3 - _locales/hr/messages.json | 3 - _locales/hu/messages.json | 3 - _locales/hy-AM/messages.json | 3 - _locales/id/messages.json | 3 - _locales/it/messages.json | 3 - _locales/ja/messages.json | 3 - _locales/ka/messages.json | 3 - _locales/km/messages.json | 3 - _locales/kmr/messages.json | 3 - _locales/kn/messages.json | 3 - _locales/ko/messages.json | 3 - _locales/ku/messages.json | 3 - _locales/lg/messages.json | 3 - _locales/lo/messages.json | 1 - _locales/lt/messages.json | 3 - _locales/lv/messages.json | 3 - _locales/mk/messages.json | 3 - _locales/mn/messages.json | 3 - _locales/ms/messages.json | 3 - _locales/my/messages.json | 3 - _locales/nb/messages.json | 3 - _locales/ne/messages.json | 3 - _locales/nl/messages.json | 3 - _locales/nn/messages.json | 3 - _locales/no/messages.json | 3 - _locales/ny/messages.json | 3 - _locales/pa/messages.json | 3 - _locales/pl/messages.json | 3 - _locales/ps/messages.json | 3 - _locales/pt-BR/messages.json | 3 - _locales/pt-PT/messages.json | 3 - _locales/ro/messages.json | 3 - _locales/ru/messages.json | 3 - _locales/sh/messages.json | 3 - _locales/si/messages.json | 3 - _locales/sk/messages.json | 3 - _locales/sl/messages.json | 3 - _locales/sq/messages.json | 3 - _locales/sr-CS/messages.json | 3 - _locales/sr-SP/messages.json | 3 - _locales/sv/messages.json | 3 - _locales/sw/messages.json | 3 - _locales/ta/messages.json | 3 - _locales/te/messages.json | 3 - _locales/th/messages.json | 3 - _locales/tl/messages.json | 3 - _locales/tr/messages.json | 3 - _locales/uk/messages.json | 3 - _locales/ur/messages.json | 3 - _locales/uz/messages.json | 3 - _locales/vi/messages.json | 3 - _locales/xh/messages.json | 3 - _locales/zh-CN/messages.json | 3 - _locales/zh-TW/messages.json | 3 - ts/components/basic/SessionToggle.tsx | 15 +- ts/components/buttons/GearAvatarButton.tsx | 25 ++ .../buttons/GenericPanelButtonWithAction.tsx | 42 +++ ts/components/buttons/PanelButton.tsx | 17 +- ts/components/buttons/PanelRadioButton.tsx | 70 ++-- ts/components/buttons/PanelToggleButton.tsx | 34 ++ .../buttons/PanelWithButtonInline.tsx | 43 +++ ts/components/buttons/PlusAvatarButton.tsx | 2 +- .../UploadFirstImageButton.tsx} | 8 +- .../dialog/EditProfilePictureModal.tsx | 4 +- .../dialog/HideRecoveryPasswordDialog.tsx | 5 +- ts/components/dialog/ModalContainer.tsx | 2 +- .../dialog/OnionStatusPathDialog.tsx | 43 +-- .../dialog/SessionSetPasswordDialog.tsx | 12 +- .../UpdateConversationDetailsDialog.tsx | 2 +- ts/components/dialog/UserProfileModal.tsx | 3 +- .../conversationSettingsHeader.tsx | 3 +- .../pages/default/defaultPage.tsx | 7 +- .../DisappearingModes.tsx | 5 +- .../disappearing-messages/TimeOptions.tsx | 7 +- .../dialog/network/SessionNetworkModal.tsx | 2 - .../user-settings/UserSettingsDialog.tsx | 314 +--------------- .../dialog/user-settings/components.tsx | 40 -- .../pages/DefaultSettingsPage.tsx | 342 +++++++++++++++++ .../pages/PrivacySettingsPage.tsx | 349 ++++++++++++++++++ .../user-settings/pages/userSettingsHooks.tsx | 77 ++++ ts/components/leftpane/ActionsPanel.tsx | 50 ++- .../leftpane/LeftPaneSectionContainer.tsx | 6 - .../leftpane/LeftPaneSectionHeader.tsx | 15 +- .../leftpane/LeftPaneSettingSection.tsx | 26 +- ts/components/qrview/QrView.tsx | 40 ++ ts/components/settings/SessionSettings.tsx | 41 +- .../settings/SessionSettingsHeader.tsx | 3 - .../settings/section/CategoryPermissions.tsx | 54 +-- .../settings/section/CategoryPrivacy.tsx | 149 -------- .../section/CategoryRecoveryPassword.tsx | 4 +- ts/localization/localeTools.ts | 2 + ts/mains/main_renderer.tsx | 1 - ts/react.d.ts | 14 +- ts/state/ducks/modalDialog.tsx | 18 +- ts/state/ducks/section.tsx | 7 +- ts/state/ducks/user.ts | 2 +- ts/types/ReduxTypes.d.ts | 1 - 124 files changed, 1123 insertions(+), 1037 deletions(-) create mode 100644 ts/components/buttons/GearAvatarButton.tsx create mode 100644 ts/components/buttons/GenericPanelButtonWithAction.tsx create mode 100644 ts/components/buttons/PanelToggleButton.tsx create mode 100644 ts/components/buttons/PanelWithButtonInline.tsx rename ts/components/{dialog/user-settings/UploadFirstImage.tsx => buttons/UploadFirstImageButton.tsx} (75%) create mode 100644 ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx create mode 100644 ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx create mode 100644 ts/components/dialog/user-settings/pages/userSettingsHooks.tsx create mode 100644 ts/components/qrview/QrView.tsx delete mode 100644 ts/components/settings/section/CategoryPrivacy.tsx diff --git a/_locales/af/messages.json b/_locales/af/messages.json index 4affa89d2..7c05d36da 100644 --- a/_locales/af/messages.json +++ b/_locales/af/messages.json @@ -599,8 +599,6 @@ "open": "Oop", "other": "Ander", "passwordChange": "Wysig Wagwoord", - "passwordChangeDescription": "Verander die wagwoord wat benodig word om Session te ontsluit.", - "passwordChangedDescription": "Jou wagwoord is verander. Hou dit asseblief veilig.", "passwordConfirm": "Bevestig wagwoord", "passwordCurrentIncorrect": "Jou huidige wagwoord is verkeerd.", "passwordEnter": "Voer wagwoord in", @@ -611,7 +609,6 @@ "passwordFailed": "Kon nie wagwoord stel nie", "passwordIncorrect": "Verkeerde wagwoord", "passwordRemove": "Verwyder wagwoord", - "passwordRemovedDescription": "Jou wagwoord is verwyder.", "passwordSet": "Stel Wagwoord", "paste": "Plak", "permissionMusicAudioDenied": "Session benodig musiek en oudio toegang om lêers, musiek en oudio te stuur, maar dit is permanent geweier. Tik Instellings → Toestemmings, en skakel \"Musiek en oudio\" aan.", diff --git a/_locales/ar/messages.json b/_locales/ar/messages.json index f6655b4a2..7869e20f7 100644 --- a/_locales/ar/messages.json +++ b/_locales/ar/messages.json @@ -648,8 +648,6 @@ "open": "فتح", "other": "أخرى", "passwordChange": "تغيير كلمة السر", - "passwordChangeDescription": "تغيير كلمة السر المطلوبة لفتح Session.", - "passwordChangedDescription": "تم تغيير كلمة المرور الخاصة بك. احفظها في مامن.", "passwordConfirm": "أَكِد كلمة المرور", "passwordCurrentIncorrect": "كلمة المرور الحالية غير صحيحة.", "passwordEnter": "أدخل كلمة السر", @@ -660,7 +658,6 @@ "passwordFailed": "فشل تعيين كلمة المرور", "passwordIncorrect": "كلمة المرور خاطئة", "passwordRemove": "إزالة كلمة السر", - "passwordRemovedDescription": "تمت إزالة كلمة السر الخاصة بك.", "passwordSet": "تعيين كلمة المرور", "paste": "لصق", "permissionChange": "تغيير الصَّلاحِيَة", diff --git a/_locales/az/messages.json b/_locales/az/messages.json index 6306d4e69..49c66481b 100644 --- a/_locales/az/messages.json +++ b/_locales/az/messages.json @@ -703,8 +703,6 @@ "openSurvey": "Anketi aç", "other": "Digər", "passwordChange": "Parolu dəyişdir", - "passwordChangeDescription": "Session kilidini açmaq üçün tələb olunan parolu dəyişdir.", - "passwordChangedDescription": "Parolunuz dəyişdirildi. Lütfən, onu güvəndə saxlayın.", "passwordConfirm": "Parolu təsdiqlə", "passwordCurrentIncorrect": "Hazırkı parolunuz yanlışdır.", "passwordEnter": "Parolu daxil edin", @@ -716,7 +714,6 @@ "passwordFailed": "Parol təyin etmə uğursuz oldu", "passwordIncorrect": "Yanlış parol", "passwordRemove": "Parolu sil", - "passwordRemovedDescription": "Parolunuz silindi.", "passwordSet": "Parol təyin et", "paste": "Yapışdır", "permissionChange": "İcazəni dəyişdir", diff --git a/_locales/bal/messages.json b/_locales/bal/messages.json index 15539c8b3..cc415b2d8 100644 --- a/_locales/bal/messages.json +++ b/_locales/bal/messages.json @@ -598,8 +598,6 @@ "open": "گِس", "other": "دیگر", "passwordChange": "پاس ورڈ تبدیل کریں", - "passwordChangeDescription": "Session کو ان لاک کرنے کے لئے درکار پاس ورڈ تبدیل کریں۔", - "passwordChangedDescription": "ما گپ درخواست قبول کردی بیک اپلیکیشن پاسکوڈ ناقض کردی. براہپس محفوظے کہ.", "passwordConfirm": "رمز اے تصدیق کر", "passwordCurrentIncorrect": "تُں حالء پاسکوڈ نادرستیت.", "passwordEnter": "پاسورڈ درج بکنا", @@ -610,7 +608,6 @@ "passwordFailed": "پاسورڈ مقرر کرنے میں ناکامی", "passwordIncorrect": "غلط پاس ورڈ", "passwordRemove": "پاسورڈ برس ک", - "passwordRemovedDescription": "ما گپ درخواست قبول کردی بیک پاسکوڈ ہٹاٹی.", "passwordSet": "رمز مقرر کـــــــن", "paste": "چسپاء", "permissionMusicAudioDenied": "Session کی موسیقی اور آڈیو تک رسائی ضروری ہے تاکہ آپ فائلیں، موسیقی اور آڈیو بھیج سکیں، لیکن اسے مستقل طور پر ممنوع کر دیا گیا ہے۔ سیٹنگز ٹیپ کریں → اجازتیں، اور \"موسیقی اور آڈیو\" کو آن کریں۔", diff --git a/_locales/be/messages.json b/_locales/be/messages.json index 788fddd5b..5e332f313 100644 --- a/_locales/be/messages.json +++ b/_locales/be/messages.json @@ -598,8 +598,6 @@ "open": "Адкрыць", "other": "Іншае", "passwordChange": "Змяніць пароль", - "passwordChangeDescription": "Змяніць пароль для разблакоўкі Session.", - "passwordChangedDescription": "Ваш пароль быў зменены. Захавайце яго ў бяспецы.", "passwordConfirm": "Пацвердзіць пароль", "passwordCurrentIncorrect": "Ваш бягучы пароль няправільны.", "passwordEnter": "Увядзіце пароль", @@ -610,7 +608,6 @@ "passwordFailed": "Не атрымалася ўсталяваць пароль", "passwordIncorrect": "Няправільны пароль", "passwordRemove": "Выдаліць пароль", - "passwordRemovedDescription": "Ваш пароль быў выдалены.", "passwordSet": "Задаць пароль", "paste": "Уставіць", "permissionMusicAudioDenied": "Session патрабуе доступу да музыкі і аўдыё для адпраўкі файлаў, музыкі і аўдыё, але доступ быў пастаянна забаронены. Націсніце «Налады» → «Дазволы» і актывуйце «Музыка і аўдыё».", diff --git a/_locales/bg/messages.json b/_locales/bg/messages.json index 9df9f5b38..0684bfe09 100644 --- a/_locales/bg/messages.json +++ b/_locales/bg/messages.json @@ -598,8 +598,6 @@ "open": "Отвори", "other": "Друг", "passwordChange": "Смяна на парола", - "passwordChangeDescription": "Сменете паролата, изисквана за отключване на Session.", - "passwordChangedDescription": "Вашата парола беше променена. Моля, пазете я безопасно.", "passwordConfirm": "Потвърди парола", "passwordCurrentIncorrect": "Вашата текуща парола е неправилна.", "passwordEnter": "Въведете парола", @@ -610,7 +608,6 @@ "passwordFailed": "Неуспешно задаване на паролата", "passwordIncorrect": "Грешна парола", "passwordRemove": "Премахване на парола", - "passwordRemovedDescription": "Вашата парола беше премахната.", "passwordSet": "Задаване на парола", "paste": "Поставяне", "permissionMusicAudioDenied": "Session се нуждае от достъп до музика и аудио, за да може да изпращате файлове, музика и аудио, но достъпът е бил отказан постоянен. Отидете в Настройки → Разрешения и включете \"Музика и аудио\".", diff --git a/_locales/bn/messages.json b/_locales/bn/messages.json index 9cadb0271..3d330c36b 100644 --- a/_locales/bn/messages.json +++ b/_locales/bn/messages.json @@ -598,8 +598,6 @@ "open": "ওপেন", "other": "অন্যান্য", "passwordChange": "পাসওয়ার্ড পরিবর্তন করুন", - "passwordChangeDescription": "Session আনলক করতে প্রয়োজনীয় পাসওয়ার্ড পরিবর্তন করুন।", - "passwordChangedDescription": "আপনার পাসওয়ার্ড পরিবর্তন করা হয়েছে। দয়া করে এটি নিরাপদ রাখুন।", "passwordConfirm": "পাসওয়ার্ড নিশ্চিত করুন", "passwordCurrentIncorrect": "আপনার বর্তমান পাসওয়ার্ডটি ভুল।", "passwordEnter": "পাসওয়ার্ড লিখুন", @@ -610,7 +608,6 @@ "passwordFailed": "পাসওয়ার্ড সেট করতে ব্যর্থ হয়েছে", "passwordIncorrect": "পাসওয়ার্ড ভুল হয়েছে", "passwordRemove": "পাসওয়ার্ড সরান", - "passwordRemovedDescription": "আপনার পাসওয়ার্ড সরানো হয়েছে।", "passwordSet": "পাসওয়ার্ড সেট করুন", "paste": "পেস্ট", "permissionMusicAudioDenied": "Session এর ফাইল, সঙ্গীত এবং অডিও পাঠানোর জন্য সঙ্গীত ও অডিও অ্যাক্সেস প্রয়োজন, কিন্তু এটি স্থায়ীভাবে প্রত্যাখ্যান করা হয়েছে। Tap Settings → Permissions, and turn \"Music and audio\" on.", diff --git a/_locales/ca/messages.json b/_locales/ca/messages.json index 94f1e18f3..0cc19c851 100644 --- a/_locales/ca/messages.json +++ b/_locales/ca/messages.json @@ -702,8 +702,6 @@ "openSurvey": "Enquesta oberta", "other": "Altres", "passwordChange": "Canvia la contrasenya", - "passwordChangeDescription": "Canvia la contrasenya requerida per desblocar Session.", - "passwordChangedDescription": "La vostra contrasenya s'ha definit. Mantingueu-la segura.", "passwordConfirm": "Confirma la contrasenya", "passwordCurrentIncorrect": "La vostra contrasenya actual és incorrecta.", "passwordEnter": "Introdueix contrasenya", @@ -715,7 +713,6 @@ "passwordFailed": "No s'ha pogut canviar la contrasenya", "passwordIncorrect": "Contrasenya incorrecta", "passwordRemove": "Suprimeix la contrasenya", - "passwordRemovedDescription": "La vostra contrasenya s'ha eliminat.", "passwordSet": "Definir contrasenya", "paste": "Enganxa", "permissionChange": "Canvi de permisos", diff --git a/_locales/cs/messages.json b/_locales/cs/messages.json index fc40e5ef8..cdb0991ae 100644 --- a/_locales/cs/messages.json +++ b/_locales/cs/messages.json @@ -703,8 +703,6 @@ "openSurvey": "Otevřít dotazník", "other": "Ostatní", "passwordChange": "Změnit heslo", - "passwordChangeDescription": "Změňte heslo pro odemykání Session.", - "passwordChangedDescription": "Tvé heslo bylo změněno. Pečlivě si ho odlož.", "passwordConfirm": "Potvrďte heslo", "passwordCurrentIncorrect": "Vaše aktuální heslo je nesprávné.", "passwordEnter": "Zadejte heslo", @@ -716,7 +714,6 @@ "passwordFailed": "Nepodařilo se nastavit heslo", "passwordIncorrect": "Nesprávné heslo", "passwordRemove": "Odstranit heslo", - "passwordRemovedDescription": "Vaše heslo bylo odstraněno.", "passwordSet": "Nastavit heslo", "paste": "Vložit", "permissionChange": "Změna oprávnění", diff --git a/_locales/cy/messages.json b/_locales/cy/messages.json index 228e3becf..4968cca5a 100644 --- a/_locales/cy/messages.json +++ b/_locales/cy/messages.json @@ -609,8 +609,6 @@ "open": "Agor", "other": "Arall", "passwordChange": "Newid Cyfrinair", - "passwordChangeDescription": "Newid y cyfrinair sy'n angenrheidiol i ddatgloi Session.", - "passwordChangedDescription": "Mae eich cyfrinair wedi'i newid. Cadwch ef yn ddiogel.", "passwordConfirm": "Cadarnhau cyfrinair", "passwordCurrentIncorrect": "Mae eich cyfrinair cyfredol yn anghywir.", "passwordEnter": "Rhowch cyfrinair", @@ -621,7 +619,6 @@ "passwordFailed": "Methwyd gosod cyfrinair", "passwordIncorrect": "Cyfrinair anghywir", "passwordRemove": "Tynnu'r Cyfrinair", - "passwordRemovedDescription": "Mae eich cyfrinair wedi'i dynnu.", "passwordSet": "Gosod Cyfrinair", "paste": "Gludo", "permissionMusicAudioDenied": "Session angen mynediad at gerddoriaeth ac sain er mwyn anfon ffeiliau, cerddoriaeth a sain, ond mae wedi'i wrthod yn barhaol. Tapiwch Gosodiadau → Trwyddedau, a throi \"Cerddoriaeth a sain\" ymlaen.", diff --git a/_locales/da/messages.json b/_locales/da/messages.json index 6ac6b2de4..da5066b92 100644 --- a/_locales/da/messages.json +++ b/_locales/da/messages.json @@ -672,8 +672,6 @@ "open": "Åben", "other": "Andet", "passwordChange": "Skift adgangskode", - "passwordChangeDescription": "Skift adgangskoden, der kræves for at låse Session op.", - "passwordChangedDescription": "Din adgangskode er blevet ændret. Venligst hold den sikker.", "passwordConfirm": "Bekræft kodeord", "passwordCurrentIncorrect": "Din nuværende adgangskode er forkert.", "passwordEnter": "Indtast adgangskode", @@ -684,7 +682,6 @@ "passwordFailed": "Opdatering af adgangskode mislykkedes", "passwordIncorrect": "Forkert adgangskode", "passwordRemove": "Fjern adgangskode", - "passwordRemovedDescription": "Din adgangskode er blevet fjernet.", "passwordSet": "Indstil adgangskode", "paste": "Indsæt", "permissionChange": "Ændring af adgange", diff --git a/_locales/de/messages.json b/_locales/de/messages.json index 54c313ffb..af48e6fb6 100644 --- a/_locales/de/messages.json +++ b/_locales/de/messages.json @@ -703,8 +703,6 @@ "openSurvey": "Umfrage starten", "other": "Sonstiges", "passwordChange": "Passwort ändern", - "passwordChangeDescription": "Das Passwort zum Entsperren von Session ändern.", - "passwordChangedDescription": "Dein Passwort wurde geändert. Bitte bewahre es sicher auf.", "passwordConfirm": "Passwort bestätigen", "passwordCurrentIncorrect": "Dein aktuelles Passwort ist nicht korrekt.", "passwordEnter": "Passwort eingeben", @@ -716,7 +714,6 @@ "passwordFailed": "Passwort konnte nicht gesetzt werden", "passwordIncorrect": "Falsches Passwort", "passwordRemove": "Passwort entfernen", - "passwordRemovedDescription": "Dein Passwort wurde entfernt.", "passwordSet": "Passwort festlegen", "paste": "Einfügen", "permissionChange": "Berechtigungsänderung", diff --git a/_locales/el/messages.json b/_locales/el/messages.json index 4121e55e7..fad83fea6 100644 --- a/_locales/el/messages.json +++ b/_locales/el/messages.json @@ -609,8 +609,6 @@ "open": "Άνοιγμα", "other": "Άλλο", "passwordChange": "Αλλαγή Κωδικού Πρόσβασης", - "passwordChangeDescription": "Αλλαγή του κωδικού πρόσβασης που απαιτείται για το ξεκλείδωμα του Session.", - "passwordChangedDescription": "Ο κωδικός πρόσβασής σας έχει αλλάξει. Παρακαλώ κρατήστε τον ασφαλή.", "passwordConfirm": "Επιβεβαίωση κωδικού πρόσβασης", "passwordCurrentIncorrect": "Ο τρέχων κωδικός πρόσβασής σας είναι λανθασμένος.", "passwordEnter": "Εισαγάγετε τον Κωδικό Πρόσβασης", @@ -621,7 +619,6 @@ "passwordFailed": "Αποτυχία ορισμού κωδικού πρόσβασης", "passwordIncorrect": "Λάθος κωδικός πρόσβασης", "passwordRemove": "Αφαίρεση Κωδικού Πρόσβασης", - "passwordRemovedDescription": "Ο κωδικός πρόσβασής σας έχει αφαιρεθεί.", "passwordSet": "Ορισμός Κωδικού Πρόσβασης", "paste": "Επικόλληση", "permissionMusicAudioDenied": "Session χρειάζεται πρόσβαση στη μουσική και τον ήχο για να στείλει αρχεία, μουσική και ήχο, αλλά η πρόσβαση έχει απορριφθεί μόνιμα. Πατήστε Ρυθμίσεις → Δικαιώματα, και ενεργοποιήστε το \"Μουσική και ήχος\".", diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 61b11565f..899f04db9 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -194,8 +194,8 @@ "cameraGrantAccessQr": "Session needs camera access to scan QR codes", "cancel": "Cancel", "change": "Change", - "changePasswordDescription": "Change your password for Session. Locally stored data will be re-encrypted with your new password.", "changePasswordFail": "Failed to change password", + "changePasswordModalDescription": "Change your password for Session. Locally stored data will be re-encrypted with your new password.", "clear": "Clear", "clearAll": "Clear All", "clearDataAll": "Clear All Data", @@ -733,12 +733,11 @@ "other": "Other", "password": "Password", "passwordChange": "Change Password", - "passwordChangeDescription": "Change the password required to unlock Session.", - "passwordChangedDescription": "Your password has been changed. Please keep it safe.", + "passwordChangeShortDescription": "Change the password required to unlock Session.", + "passwordChangedDescriptionToast": "Your password has been changed. Please keep it safe.", "passwordConfirm": "Confirm password", "passwordCreate": "Create Password", "passwordCurrentIncorrect": "Your current password is incorrect.", - "passwordDescription": "Require password to unlock Session on startup.", "passwordEnter": "Enter password", "passwordEnterCurrent": "Please enter your current password", "passwordEnterNew": "Please enter your new password", @@ -749,10 +748,11 @@ "passwordIncorrect": "Incorrect password", "passwordNewConfirm": "Confirm New Password", "passwordRemove": "Remove Password", - "passwordRemoveDescription": "Remove your current password for Session. Locally stored data will be re-encrypted with a randomly generated key, stored on your device.", - "passwordRemovedDescription": "Your password has been removed.", + "passwordRemoveShortDescription": "Remove the password required to unlock Session", + "passwordRemovedDescriptionToast": "Your password has been removed.", "passwordSet": "Set Password", - "passwordSetDescription": "Set a password for Session. Locally stored data will be encrypted with this password. You will be asked to enter this password each time Session starts.", + "passwordSetDescriptionToast": "Your password has been set. Please keep it safe.", + "passwordSetShortDescription": "Require password to unlock Session on startup.", "passwordStrengthCharLength": "Longer than 12 characters", "passwordStrengthIncludeNumber": "Includes a number", "passwordStrengthIncludesLetter": "Includes a letter", @@ -879,6 +879,7 @@ "remainingCharactersTooltip": "{count, plural, one [{count} character remaining] other [{count} characters remaining]}", "remove": "Remove", "removePasswordFail": "Failed to remove password", + "removePasswordModalDescription": "Remove your current password for Session. Locally stored data will be re-encrypted with a randomly generated key, stored on your device.", "reply": "Reply", "resend": "Resend", "resolving": "Loading country information...", @@ -936,6 +937,7 @@ "sessionSettings": "Settings", "set": "Set", "setCommunityDisplayPicture": "Set Community Display Picture", + "setPasswordModalDescription": "Set a password for Session. Locally stored data will be encrypted with this password. You will be asked to enter this password each time Session starts.", "settingsRestartDescription": "You must restart Session to apply your new settings.", "share": "Share", "shareAccountIdDescription": "Invite your friend to chat with you on Session by sharing your Account ID with them.", diff --git a/_locales/eo/messages.json b/_locales/eo/messages.json index 900003c94..eff9ea4d2 100644 --- a/_locales/eo/messages.json +++ b/_locales/eo/messages.json @@ -661,8 +661,6 @@ "open": "Malfermi", "other": "Alia", "passwordChange": "Ŝanĝi Pasvorton", - "passwordChangeDescription": "Ŝanĝi la pasvorton, kiu necesas por malŝlosi Session.", - "passwordChangedDescription": "Via pasvorto estas ŝanĝita. Bonvolu konservi ĝin sekura.", "passwordConfirm": "Konfirmi pasvorton", "passwordCurrentIncorrect": "Via nuna pasvorto estas malĝusta.", "passwordEnter": "Enigi Pasvorton", @@ -673,7 +671,6 @@ "passwordFailed": "Malsukcesis agordi pasvorton", "passwordIncorrect": "Malĝusta pasvorto", "passwordRemove": "Forigi Pasvorton", - "passwordRemovedDescription": "Via pasvorto estas forigita.", "passwordSet": "Agordi Pasvorton", "paste": "Alglui", "permissionChange": "Ŝanĝi permesojn", diff --git a/_locales/es-419/messages.json b/_locales/es-419/messages.json index a75a4c190..84dbfc4ab 100644 --- a/_locales/es-419/messages.json +++ b/_locales/es-419/messages.json @@ -703,8 +703,6 @@ "openSurvey": "Abrir encuesta", "other": "Otro", "passwordChange": "Cambiar Contraseña", - "passwordChangeDescription": "Cambiar la contraseña necesaria para desbloquear Session.", - "passwordChangedDescription": "Tu contraseña ha sido cambiada. Por favor, manténla segura.", "passwordConfirm": "Confirmar contraseña", "passwordCurrentIncorrect": "Tu contraseña actual es incorrecta.", "passwordEnter": "Introducir contraseña", @@ -716,7 +714,6 @@ "passwordFailed": "Error al establecer la contraseña", "passwordIncorrect": "Contraseña Incorrecta", "passwordRemove": "Eliminar Contraseña", - "passwordRemovedDescription": "Tu contraseña ha sido eliminada.", "passwordSet": "Establecer Contraseña", "paste": "Pegar", "permissionChange": "Cambio de permiso", diff --git a/_locales/es/messages.json b/_locales/es/messages.json index 0b5513ec6..59700b6aa 100644 --- a/_locales/es/messages.json +++ b/_locales/es/messages.json @@ -703,8 +703,6 @@ "openSurvey": "Abrir encuesta", "other": "Otro", "passwordChange": "Cambiar Contraseña", - "passwordChangeDescription": "Cambiar la contraseña requerida para desbloquear Session.", - "passwordChangedDescription": "Tu contraseña ha sido cambiada. Por favor, manténla segura.", "passwordConfirm": "Confirmar contraseña", "passwordCurrentIncorrect": "Tu contraseña actual es incorrecta.", "passwordEnter": "Introducir contraseña", @@ -716,7 +714,6 @@ "passwordFailed": "Error al establecer la contraseña", "passwordIncorrect": "Contraseña incorrecta", "passwordRemove": "Eliminar Contraseña", - "passwordRemovedDescription": "Has eliminado tu contraseña.", "passwordSet": "Establecer Contraseña", "paste": "Pegar", "permissionChange": "Cambio de permiso", diff --git a/_locales/et/messages.json b/_locales/et/messages.json index 1b16afc65..42be1dd48 100644 --- a/_locales/et/messages.json +++ b/_locales/et/messages.json @@ -598,8 +598,6 @@ "open": "Ava", "other": "Muu", "passwordChange": "Muuda parool", - "passwordChangeDescription": "Muuda parooli, mida on vaja Session avamiseks.", - "passwordChangedDescription": "Teie parool on muudetud. Hoidke seda turvaliselt.", "passwordConfirm": "Kinnita parool", "passwordCurrentIncorrect": "Teie praegune parool on vale.", "passwordEnter": "Sisesta parool", @@ -610,7 +608,6 @@ "passwordFailed": "Salasõna määramine ebaõnnestus", "passwordIncorrect": "Vale parool", "passwordRemove": "Eemalda parool", - "passwordRemovedDescription": "Teie parool on eemaldatud.", "passwordSet": "Määra parool", "paste": "Aseta", "permissionMusicAudioDenied": "Session vajab muusika ja audio juurdepääsu failide, muusika ja audio saatmiseks, kuid see on jäädavalt keelatud. Puudutage Seaded → Load, ja lülitage \"Muusika ja audio\" sisse.", diff --git a/_locales/eu/messages.json b/_locales/eu/messages.json index 8a333589c..9565f1a18 100644 --- a/_locales/eu/messages.json +++ b/_locales/eu/messages.json @@ -598,8 +598,6 @@ "open": "Ireki", "other": "Bestea", "passwordChange": "Change Password", - "passwordChangeDescription": "Change the password required to unlock Session.", - "passwordChangedDescription": "Zure pasahitza aldatu da. Gorde seguru batean.", "passwordConfirm": "Pasahitza berretsi", "passwordCurrentIncorrect": "Zure oraingo pasahitza ez da zuzena.", "passwordEnter": "Sartu pasahitza", @@ -610,7 +608,6 @@ "passwordFailed": "Pasahitza ezartzea huts egin da", "passwordIncorrect": "Pasahitz okerra", "passwordRemove": "Pasahitza kendu", - "passwordRemovedDescription": "Zure pasahitza kendu da.", "passwordSet": "Pasahitza ezarri", "paste": "Itsatsi", "permissionMusicAudioDenied": "Session(e)k musika eta audio sarbidea behar du fitxategiak, musika eta audioak bidaltzeko, baina behin betiko ukatu da. Ezarpenak ukitu → Baimenak, eta aktibatu \"Musika eta audioak\".", diff --git a/_locales/fa/messages.json b/_locales/fa/messages.json index 69f41c9d4..e4c9d5d70 100644 --- a/_locales/fa/messages.json +++ b/_locales/fa/messages.json @@ -597,8 +597,6 @@ "open": "باز کن", "other": "دیگر", "passwordChange": "تغییر گذرواژه", - "passwordChangeDescription": "رمز عبور مورد نیاز برای باز کردن Session را تغییر بده.", - "passwordChangedDescription": "رمز عبور شما تغییر کرد. لطفا آن را در جای امنی نگهداری کنید.", "passwordConfirm": "تأیید کلمه‌ی عبور", "passwordCurrentIncorrect": "رمز عبور فعلی شما نادرست است.", "passwordEnter": "رمز عبور را وارد کنید", @@ -609,7 +607,6 @@ "passwordFailed": "تنظیم رمز عبور شکست خورد", "passwordIncorrect": "رمز عبور نادرست است", "passwordRemove": "حذف رمز عبور", - "passwordRemovedDescription": "گذرواژه شما حذف شده است.", "passwordSet": "تنظیم رمز عبور", "paste": "پیست", "permissionMusicAudioDenied": "Session برای فرستادن فایل، آهنگ و صوت نیاز به دسترسی به آهنگ و صدا دارد، اما این دسترسی به طور دائم رد شده است. به تنظیمات → مجوز‌ها رفته و «صدا و آهنگ» را فعال کنید.", diff --git a/_locales/fi/messages.json b/_locales/fi/messages.json index 4625ba535..b57149e9f 100644 --- a/_locales/fi/messages.json +++ b/_locales/fi/messages.json @@ -610,8 +610,6 @@ "open": "Avaa", "other": "Muu", "passwordChange": "Vaihda salasana", - "passwordChangeDescription": "Vaihda Session in avaukseen käytettävä salasana.", - "passwordChangedDescription": "Salasanasi on vaihdettu. Pidä se turvassa.", "passwordConfirm": "Vahvista salasana", "passwordCurrentIncorrect": "Nykyinen salasanasi on virheellinen.", "passwordEnter": "Syötä salasana", @@ -622,7 +620,6 @@ "passwordFailed": "Salasanan asetus epäonnistui", "passwordIncorrect": "Virheellinen salasana", "passwordRemove": "Poista salasana", - "passwordRemovedDescription": "Salasanasi on on poistettu.", "passwordSet": "Aseta salasana", "paste": "Liitä", "permissionMusicAudioDenied": "Session tarvitsee pääsyn musiikkiin ja ääniin, jotta se voi lähettää tiedostoja, musiikkia ja ääntä, mutta pääsy on pysyvästi estetty. Napauta Asetukset → Luvat ja salli \"Musiikki ja äänet\".", diff --git a/_locales/fil/messages.json b/_locales/fil/messages.json index 06404ab85..b12269a7a 100644 --- a/_locales/fil/messages.json +++ b/_locales/fil/messages.json @@ -598,8 +598,6 @@ "open": "Buksan", "other": "Iba pa", "passwordChange": "Palitan ang Password", - "passwordChangeDescription": "Palitan ang password na kinakailangan para i-unlock ang Session.", - "passwordChangedDescription": "Nabago na ang iyong password. Pakisuyong itago ito.", "passwordConfirm": "Kumpirmahin ang iyong password", "passwordCurrentIncorrect": "Maling kasalukuyang password mo.", "passwordEnter": "Ilagay ang Password", @@ -610,7 +608,6 @@ "passwordFailed": "Bigong na-reset ang password", "passwordIncorrect": "Maling password", "passwordRemove": "Alisin ang Password", - "passwordRemovedDescription": "Ang iyong password ay naalis na.", "passwordSet": "Maglagay ng Password", "paste": "Idikit", "permissionMusicAudioDenied": "Session needs music and audio access in order to send files, music and audio, but it has been permanently denied. Tap Settings → Permissions, and turn \"Music and audio\" on.", diff --git a/_locales/fr/messages.json b/_locales/fr/messages.json index 0519e40ec..38f39b0f6 100644 --- a/_locales/fr/messages.json +++ b/_locales/fr/messages.json @@ -703,8 +703,6 @@ "openSurvey": "Ouvrir le questionnaire", "other": "Autre", "passwordChange": "Changer le mot de passe", - "passwordChangeDescription": "Modifier le mot de passe requis pour déverrouiller Session", - "passwordChangedDescription": "Votre mot de passe a été changé. Veuillez le conserver en sécurité.", "passwordConfirm": "Confirmez le mot de passe", "passwordCurrentIncorrect": "Votre mot de passe actuel est incorrect.", "passwordEnter": "Entrez le mot de passe", @@ -716,7 +714,6 @@ "passwordFailed": "Échec de la définition du mot de passe", "passwordIncorrect": "Mot de passe incorrect", "passwordRemove": "Supprimer le mot de passe", - "passwordRemovedDescription": "Votre mot de passe a été supprimé.", "passwordSet": "Définir un mot de passe", "paste": "Coller", "permissionChange": "Changement de permission", diff --git a/_locales/gl/messages.json b/_locales/gl/messages.json index 86dc483cd..9c5c596a3 100644 --- a/_locales/gl/messages.json +++ b/_locales/gl/messages.json @@ -537,8 +537,6 @@ "open": "Abrir", "other": "Outra", "passwordChange": "Cambiar o contrasinal", - "passwordChangeDescription": "Cambia o contrasinal necesario para desbloquear Session.", - "passwordChangedDescription": "O teu contrasinal foi cambiado. Por favor, mantéñeo seguro.", "passwordConfirm": "Confirmar contrasinal", "passwordCurrentIncorrect": "O teu contrasinal actual é incorrecto.", "passwordEnter": "Introduza o contrasinal", @@ -548,7 +546,6 @@ "passwordFailed": "Non se puido establecer o contrasinal", "passwordIncorrect": "Contrasinal incorrecto", "passwordRemove": "Eliminar contrasinal", - "passwordRemovedDescription": "O teu contrasinal foi eliminado.", "passwordSet": "Establecer Contrasinal", "paste": "Pegar", "permissionsAppleMusic": "Session necesita usar Apple Music para reproducir anexos multimedia.", diff --git a/_locales/ha/messages.json b/_locales/ha/messages.json index 1a2873368..e01e841a4 100644 --- a/_locales/ha/messages.json +++ b/_locales/ha/messages.json @@ -598,8 +598,6 @@ "open": "Bude", "other": "Sauran", "passwordChange": "Canza Kalmar Sirri", - "passwordChangeDescription": "Canza kalmar sirrin da ake bukata don buɗe Session.", - "passwordChangedDescription": "An canza kalmar sirrinku. Da fatan za a kiyaye shi lafiya.", "passwordConfirm": "Tabbatar da kalmar sirri", "passwordCurrentIncorrect": "Kalmar sirrinka na yanzu ba daidai bane.", "passwordEnter": "Shigar da kalmar sirri", @@ -610,7 +608,6 @@ "passwordFailed": "An kasa saita kalmar sirri", "passwordIncorrect": "Kalmar wucewa da aka shigar ba daidai ba ce", "passwordRemove": "Cire Kalmar sirri", - "passwordRemovedDescription": "An cire kalmar sirrinku.", "passwordSet": "Saita Kalmar Sirri", "paste": "Manna", "permissionMusicAudioDenied": "Session yana buƙatar samun damar amfani da kiɗi da sauti don aika fayiloli, kiɗi da sauti, amma an haramta shi dindindin. Danna Saituna → Izini, kuma kunna \"Kiɗi da sauti\".", diff --git a/_locales/he/messages.json b/_locales/he/messages.json index 809353e65..c7d85fc70 100644 --- a/_locales/he/messages.json +++ b/_locales/he/messages.json @@ -598,8 +598,6 @@ "open": "פתח", "other": "אחר", "passwordChange": "שנה סיסמה", - "passwordChangeDescription": "שנה את הסיסמה הנדרשת לפתיחת Session.", - "passwordChangedDescription": "הסיסמה שלך השתנתה. שמור עליה בבטחה.", "passwordConfirm": "אשר סיסמה", "passwordCurrentIncorrect": "הסיסמה הנוכחית שלך לא נכונה.", "passwordEnter": "הזן סיסמה", @@ -610,7 +608,6 @@ "passwordFailed": "נכשל לקבוע סיסמה", "passwordIncorrect": "סיסמה שגויה", "passwordRemove": "הסר סיסמה", - "passwordRemovedDescription": "הסיסמה שלך הוסרה.", "passwordSet": "הגדר סיסמה", "paste": "הדבק", "permissionMusicAudioDenied": "Session זקוק לגישה למוזיקה ואודיו על מנת לשלוח קבצים, מוזיקה ואודיו, אבל היא נדחתה לצמיתות. Tap Settings → Permissions, and turn \"Music and audio\" on.", diff --git a/_locales/hi/messages.json b/_locales/hi/messages.json index adfa8ef96..3b3b9c2b1 100644 --- a/_locales/hi/messages.json +++ b/_locales/hi/messages.json @@ -703,8 +703,6 @@ "openSurvey": "सर्वेक्षण खोलें", "other": "अन्य", "passwordChange": "पासवर्ड बदलें", - "passwordChangeDescription": "Session को अनलॉक करने के लिए आवश्यक पासवर्ड बदलें।", - "passwordChangedDescription": "आपका पासवर्ड बदल दिया गया है। कृपया इसे सुरक्षित रखें।", "passwordConfirm": "पासवर्ड की पुष्टि करें", "passwordCurrentIncorrect": "आपका वर्तमान पासवर्ड गलत है।", "passwordEnter": "पासवर्ड दर्ज करें", @@ -716,7 +714,6 @@ "passwordFailed": "पासवर्ड सेट करने में विफल", "passwordIncorrect": "गलत पासवर्ड", "passwordRemove": "पासवर्ड हटाएं", - "passwordRemovedDescription": "आपका पासवर्ड हटा दिया गया है।", "passwordSet": "पासवर्ड सेट करें", "paste": "पेस्ट करें", "permissionChange": "अनुमति परिवर्तन", diff --git a/_locales/hr/messages.json b/_locales/hr/messages.json index a6c776487..3fe6136fe 100644 --- a/_locales/hr/messages.json +++ b/_locales/hr/messages.json @@ -598,8 +598,6 @@ "open": "Otvori", "other": "Ostalo", "passwordChange": "Promijeni lozinku", - "passwordChangeDescription": "Promijenite lozinku potrebnu za otključavanje Session.", - "passwordChangedDescription": "Vaša lozinka je promijenjena. Molimo, čuvajte je na sigurnom.", "passwordConfirm": "Potvrdi lozinku", "passwordCurrentIncorrect": "Vaša trenutna lozinka je netočna.", "passwordEnter": "Unesite lozinku", @@ -610,7 +608,6 @@ "passwordFailed": "Postavljanje lozinke nije uspjelo", "passwordIncorrect": "Neispravna lozinka", "passwordRemove": "Ukloni lozinku", - "passwordRemovedDescription": "Vaša lozinka je uklonjena.", "passwordSet": "Postavi lozinku", "paste": "Zalijepi", "permissionMusicAudioDenied": "Session treba pristup glazbi i zvuku kako bi mogao slati datoteke, glazbu i zvuk, no to je sada trajno onemogućeno. Tap Settings → Permissions, i uključite \"Glazba i zvuk\".", diff --git a/_locales/hu/messages.json b/_locales/hu/messages.json index 4ddde075e..25f0db804 100644 --- a/_locales/hu/messages.json +++ b/_locales/hu/messages.json @@ -692,8 +692,6 @@ "open": "Megnyitás", "other": "Egyéb", "passwordChange": "Jelszó megváltoztatása", - "passwordChangeDescription": "Session alkalmazás jelszavának megváltoztatása.", - "passwordChangedDescription": "A jelszó megváltozott. Tartsd biztonságos helyen!", "passwordConfirm": "Jelszó megerősítése", "passwordCurrentIncorrect": "Az aktuális jelszavad helytelen.", "passwordEnter": "Jelszó megadása", @@ -704,7 +702,6 @@ "passwordFailed": "Jelszó frissítése sikertelen", "passwordIncorrect": "Hibás jelszó", "passwordRemove": "Jelszó eltávolítása", - "passwordRemovedDescription": "A jelszavadat eltávolítottuk.", "passwordSet": "Jelszó beállítása", "paste": "Beillesztés", "permissionChange": "Engedélyváltozás", diff --git a/_locales/hy-AM/messages.json b/_locales/hy-AM/messages.json index 8f80415ee..0ac3dfa41 100644 --- a/_locales/hy-AM/messages.json +++ b/_locales/hy-AM/messages.json @@ -598,8 +598,6 @@ "open": "Բացել", "other": "Այլ", "passwordChange": "Փոխել գաղտնաբառը", - "passwordChangeDescription": "Փոխեք Session-ն ապակողպելու համար պահանջվող գաղտնաբառը:", - "passwordChangedDescription": "Ձեր գաղտնաբառը փոխվել է։ Խնդրում ենք անվտանգ պահել։", "passwordConfirm": "Հաստատել գաղտնաբառը", "passwordCurrentIncorrect": "Ձեր ներկա գաղտնաբառը սխալ է։", "passwordEnter": "Մուտքագրել գաղտնաբառը", @@ -610,7 +608,6 @@ "passwordFailed": "Չհաջողվեց սահմանել գաղտնաբառը", "passwordIncorrect": "Սխալ գաղտնաբառ", "passwordRemove": "Հեռացնել գաղտնաբառը", - "passwordRemovedDescription": "Ձեր գաղտնաբառը հեռացվել է։", "passwordSet": "Սահմանել գաղտնաբառը", "paste": "Տեղադրել", "permissionMusicAudioDenied": "Session-ը պահանջում է երաժշտության և աուդիո հասանելիությունը ֆայլեր, երաժշտություն և աուդիո ուղարկելու համար, սակայն թույլտվությունը մշտապես մերժված է: Սեղմեք Կարգավորումներ → Թույլտվություններ և միացրեք \"Երաժշտություն և աուդիո\" կարգավորումը:", diff --git a/_locales/id/messages.json b/_locales/id/messages.json index 004101bb8..fb38e6937 100644 --- a/_locales/id/messages.json +++ b/_locales/id/messages.json @@ -658,8 +658,6 @@ "open": "Buka", "other": "Lainnya", "passwordChange": "Ubah Kata Sandi", - "passwordChangeDescription": "Ubah kata sandi yang diperlukan untuk membuka kunci Session.", - "passwordChangedDescription": "Kata sandi anda telah diubah. Harap untuk menjaganya.", "passwordConfirm": "Konfirmasi kata sandi", "passwordCurrentIncorrect": "Kata sandi anda saat ini salah.", "passwordEnter": "Masukkan Kata Sandi", @@ -670,7 +668,6 @@ "passwordFailed": "Gagal memperbarui kata sandi", "passwordIncorrect": "Kata sandi salah", "passwordRemove": "Hapus Kata Sandi", - "passwordRemovedDescription": "Kata sandi Anda telah dihapus.", "passwordSet": "Atur Kata Sandi", "paste": "Tempel", "permissionChange": "Persetujuan Diubah", diff --git a/_locales/it/messages.json b/_locales/it/messages.json index a93a97904..0d12b1c81 100644 --- a/_locales/it/messages.json +++ b/_locales/it/messages.json @@ -703,8 +703,6 @@ "openSurvey": "Apri sondaggio", "other": "Altro", "passwordChange": "Cambia password", - "passwordChangeDescription": "Cambia la password richiesta per sbloccare Session.", - "passwordChangedDescription": "La tua password è stata modificata. Per favore tienila al sicuro.", "passwordConfirm": "Conferma password", "passwordCurrentIncorrect": "La tua password attuale non è corretta.", "passwordEnter": "Inserisci password", @@ -716,7 +714,6 @@ "passwordFailed": "Impossibile impostare la password", "passwordIncorrect": "Password non corretta", "passwordRemove": "Rimuovi password", - "passwordRemovedDescription": "La tua password è stata rimossa.", "passwordSet": "Imposta password", "paste": "Incolla", "permissionChange": "Modifica autorizzazione", diff --git a/_locales/ja/messages.json b/_locales/ja/messages.json index d9194f7af..f4a923b87 100644 --- a/_locales/ja/messages.json +++ b/_locales/ja/messages.json @@ -703,8 +703,6 @@ "openSurvey": "アンケートを開く", "other": "その他", "passwordChange": "パスワードを変更", - "passwordChangeDescription": "Sessionのロック解除に必要なパスワードを変更します", - "passwordChangedDescription": "パスワードが変更されました。安全に保管してください。", "passwordConfirm": "パスワードを再確認", "passwordCurrentIncorrect": "現在のパスワードが間違っています。", "passwordEnter": "パスワードを入力してください", @@ -716,7 +714,6 @@ "passwordFailed": "パスワードの設定に失敗しました", "passwordIncorrect": "パスワードが正しくありません", "passwordRemove": "パスワードを削除", - "passwordRemovedDescription": "パスワードを削除しました。", "passwordSet": "パスワードをセット", "paste": "貼り付け", "permissionChange": "権限の変更", diff --git a/_locales/ka/messages.json b/_locales/ka/messages.json index bc72f0023..f83cd4776 100644 --- a/_locales/ka/messages.json +++ b/_locales/ka/messages.json @@ -610,8 +610,6 @@ "open": "გახსენით", "other": "სხვა", "passwordChange": "პაროლის შეცვლა", - "passwordChangeDescription": "პაროლის შეცვლა აუცილებელია Session-ის გახსნისთვის.", - "passwordChangedDescription": "თქვენი პაროლი შეცვლილია. გთხოვთ, შეინახეთ იგი უსაფრთხოდ.", "passwordConfirm": "პაროლის დადასტურება", "passwordCurrentIncorrect": "თქვენი ახლანდელი პაროლი არასწორია.", "passwordEnter": "შეიყვანეთ პაროლი", @@ -622,7 +620,6 @@ "passwordFailed": "ვერ შევძელიში პაროლის დაწესება", "passwordIncorrect": "არასწორი პაროლი", "passwordRemove": "პაროლის წაშლა", - "passwordRemovedDescription": "თქვენი პაროლი წაშლილია.", "passwordSet": "პაროლის მითითება", "paste": "ჩასმა", "permissionMusicAudioDenied": "Session needs music and audio access in order to send files, music and audio, but it has been permanently denied. Tap Settings → Permissions, and turn \"Music and audio\" on.", diff --git a/_locales/km/messages.json b/_locales/km/messages.json index 7fa437d00..8934c3fac 100644 --- a/_locales/km/messages.json +++ b/_locales/km/messages.json @@ -598,8 +598,6 @@ "open": "បើក", "other": "ផ្សេងៗ", "passwordChange": "ប្តូរពាក្យសម្ងាត់", - "passwordChangeDescription": "ប្ដូរពាក្យសម្ងាត់ដែលបានតម្រូវឲ្យមានដើម្បីឈប់ទប់ស្កាត់ Session។", - "passwordChangedDescription": "ពាក្យសម្ងាត់ របស់អ្នកត្រូវ​បាន​ប្តូរ។ សូមរក្សា​វា​ឲ្យ​មាន​សុវត្ថិភាព។", "passwordConfirm": "បញ្ជាក់ពាក្យសម្ងាត់", "passwordCurrentIncorrect": "ពាក្យសម្ងាត់​បច្ចុប្បន្នរបស់អ្នក មិនត្រឹមត្រូវទេ។", "passwordEnter": "បញ្ចូលពាក្យសម្ងាត់", @@ -610,7 +608,6 @@ "passwordFailed": "ការកំណត់ពាក្យសម្ងាត់មិនបានសម្រេច", "passwordIncorrect": "ពាក្យសម្ងាត់មិនត្រឹមត្រូវ", "passwordRemove": "លុបពាក្យសម្ងាត់", - "passwordRemovedDescription": "ពាក្យសម្ងាត់ របស់អ្នកត្រូវបានលុបចេញ។", "passwordSet": "កំណត់ពាក្យសម្ងាត់", "paste": "បិទភ្ជាប់", "permissionMusicAudioDenied": "Session ត្រូវការការចូលប្រើតន្ត្រី និងសម្លេង ដើម្បីផ្ញើឯកសារ តន្ត្រី និងសម្លេង ប៉ុន្តែវាត្រូវបានបដិសេធរហូត។ ចុច ការកំណត់ → សិទ្ធិ និងបើក \"តន្ត្រី និងសម្លេង\"។", diff --git a/_locales/kmr/messages.json b/_locales/kmr/messages.json index 1e6c6f95c..d4cc42a9f 100644 --- a/_locales/kmr/messages.json +++ b/_locales/kmr/messages.json @@ -609,8 +609,6 @@ "open": "Veke", "other": "Yên din", "passwordChange": "Şîfreyê Biguherîne", - "passwordChangeDescription": "şîfreyê ku ji bo vekirina Session lazim e biguherîne.", - "passwordChangedDescription": "Te jîrêbandeya we yê danîn Muhafize mane sihîn bike.", "passwordConfirm": "Şîfreyê tesdîq bike", "passwordCurrentIncorrect": "Şîfreyê te çewt e.", "passwordEnter": "Şîfreyê têkeve", @@ -621,7 +619,6 @@ "passwordFailed": "Bi ser neket ku şîfre deyne", "passwordIncorrect": "Şîfreya nerast", "passwordRemove": "Şîfreyê Rake", - "passwordRemovedDescription": "Zoom", "passwordSet": "Şîfre çêkirin", "paste": "Pêve bike", "permissionMusicAudioDenied": "Session hewl dibe da ku bikarhênina muzîk û dengwêje bike ji bo senden dosyayan, muzîk û dengwêje, lê permîsiya wî daîmen hewce ye. Bibînin Mîhengên → Permîsyan, û \"Muzîk û dengwêje\" bike.", diff --git a/_locales/kn/messages.json b/_locales/kn/messages.json index 18feb284a..6d74ea7c9 100644 --- a/_locales/kn/messages.json +++ b/_locales/kn/messages.json @@ -598,8 +598,6 @@ "open": "ತೆರೆ", "other": "ಇತರೆ", "passwordChange": "ಪಾಸ್ವರ್ಡ್ ಬದಲಾಯಿಸಲು", - "passwordChangeDescription": "Session ತೆಗೆಯಲು ಬೇಕಾದ ಪಾಸ್ವರ್ಡ್ ಬದಲಾಯಿಸಿ.", - "passwordChangedDescription": "ನಿಮ್ಮ ಗುಪ್ತಪದವನ್ನು ಬದಲಾಯಿಸಲಾಗಿದೆ. ಅದು ಸುರಕ್ಷಿತವಾಗಿರಿಸಿ.", "passwordConfirm": "ಪಾಸ್ವರ್ಡ್ ದೃಡಪಡಿಸಿ", "passwordCurrentIncorrect": "ನಿಮ್ಮ ಪ್ರಸ್ತುತ ಪಾಸ್ಪಾಡ್ ತಪ್ಪಾಗಿದೆ.", "passwordEnter": "ಗುಪ್ತಪದ ನಮೂದಿಸಿ", @@ -610,7 +608,6 @@ "passwordFailed": "ಪಾಸ್‌ವರ್ಡ್ ಸೆಟ್ ಮಾಡಲು ವಿಫಲವಾಗಿದೆ", "passwordIncorrect": "ಪಾಸ್ವರ್ಡ್ ತಪ್ಪಾಗಿದೆ", "passwordRemove": "ಪಾಸ್ವರ್ಡ್ ತೆಗೆದುಹಾಕಿ", - "passwordRemovedDescription": "ನಿಮ್ಮ ಗುಪ್ತಪದವನ್ನು ತೆಗೆದುಹಾಕಲಾಗಿದೆ.", "passwordSet": "ಗುಪ್ತಪದವನ್ನು ಸೆಟ್ ಮಾಡಿ", "paste": "ಅಂಟಿಸಿ", "permissionMusicAudioDenied": "Session ಗೆ ಫೈಲುಗಳನ್ನು, ಸಂಗೀತ ಮತ್ತು ಶಬ್ದವನ್ನು ಕಳುಹಿಸಲು ಸಂಗೀತ ಮತ್ತು ಶಬ್ದ ಪ್ರವೇಶದ ಅಗತ್ಯವಿದೆ, ಆದರೆ ಅದು ಶಾಶ್ವತವಾಗಿ ನಿರಾಕರಿಸಲಾಗಿದೆ. ಸೆಟ್ಟಿಂಗ್ಗಳು ಟ್ಯಾಪ್ ಮಾಡಿ → ಅನುಮತಿಗಳು, ಮತ್ತು \"ಸಂಗೀತ ಮತ್ತು ಶಬ್ದ\" ಅನ್ನು ಆನ್ ಮಾಡಿ.", diff --git a/_locales/ko/messages.json b/_locales/ko/messages.json index f455e8a17..5ffa9a9d9 100644 --- a/_locales/ko/messages.json +++ b/_locales/ko/messages.json @@ -684,8 +684,6 @@ "open": "열기", "other": "기타", "passwordChange": "비밀번호 변경", - "passwordChangeDescription": "Session 잠금 해제 시 사용되는 비밀번호를 변경합니다.", - "passwordChangedDescription": "비밀번호 변경이 완료되었습니다. 안전히 관리하시기 바랍니다.", "passwordConfirm": "비밀번호 확인", "passwordCurrentIncorrect": "현재 비밀번호가 잘못되었습니다.", "passwordEnter": "비밀번호 입력", @@ -696,7 +694,6 @@ "passwordFailed": "비밀번호 설정 실패", "passwordIncorrect": "잘못된 비밀번호", "passwordRemove": "비밀번호 제거", - "passwordRemovedDescription": "당신의 비밀번호가 제거되었습니다.", "passwordSet": "비밀번호 설정", "paste": "붙여넣기", "permissionChange": "권한 변경", diff --git a/_locales/ku/messages.json b/_locales/ku/messages.json index 935dc4bf8..91d38dc27 100644 --- a/_locales/ku/messages.json +++ b/_locales/ku/messages.json @@ -599,8 +599,6 @@ "open": "کردنەوە", "other": "ئەوی تر", "passwordChange": "وشەی نهێنی بگۆڕە", - "passwordChangeDescription": "Session وشە نهێنی بگۆڕە بۆ کردنەوەی", - "passwordChangedDescription": "وشەی پەرەسەدت گۆڕدرا. تکایە ئەوە بەندەن پارێزەر بێت.", "passwordConfirm": "پشتڕاستکردنەوەی تێپەڕوشە", "passwordCurrentIncorrect": "تێپەڕەوەی ڕاستە پەیوەندە نەدرێت.", "passwordEnter": "وشەی تێپەڕ بنووسە", @@ -611,7 +609,6 @@ "passwordFailed": "شکستی دانانی وشەی نهێنی", "passwordIncorrect": "وشەی نهێنیکردنەوەی نەگونجاو", "passwordRemove": "لابردنی پەیامێکی پاراستوو", - "passwordRemovedDescription": "وشەی پەرەسەدت وەکبێژاند.", "passwordSet": "دانشتنی تێپەڕ ئەو ناو", "paste": "پەیامەکان تەنها دەبێ قەبارە بنووسە", "permissionMusicAudioDenied": "بەرنامەی Session پێویستی بە ڕێزەنامەی موسیقا و ئاواز بەدەستەکان بۆ ناردن پەیوەندەکان، موسیقا و ئاواز، بەڵام ئەمەدا دیاری کراوە. تکایە ئیش بکە لە ڕێکەوتەکان → ڕێگەدانەکان، و \"موسیقا و ئاواز\" بەرە چاودێر بکە.", diff --git a/_locales/lg/messages.json b/_locales/lg/messages.json index 59e141ad8..28457acc0 100644 --- a/_locales/lg/messages.json +++ b/_locales/lg/messages.json @@ -598,8 +598,6 @@ "open": "Bikkule", "other": "Ebirala", "passwordChange": "Change Password", - "passwordChangeDescription": "Change the password required to unlock Session.", - "passwordChangedDescription": "Password yo ekabatiddwa. Kaakasa nti bagutemye mu kifo ekitalemerera.", "passwordConfirm": "Kakasa akakufulu", "passwordCurrentIncorrect": "Password Kyo kiri mu nsobi.", "passwordEnter": "Yingiza akawunti", @@ -610,7 +608,6 @@ "passwordFailed": "Ensobi okuzaako okwongeza ekigambo", "passwordIncorrect": "Recovery Password y'ekiino si kituufu", "passwordRemove": "Ggyawo Password", - "passwordRemovedDescription": "Password yo ekatutuzzibwa.", "passwordSet": "Tereka Akasumuluzo", "paste": "Ddiba", "permissionMusicAudioDenied": "Session yeetaaga ssensa y'amakudiira ne ddoboozi okusobola okusindika abayimba n’eddobbozi, naye kyaganye dda. Nnyonnyola mu Settings → Permissions, lalu \"Music and audio\" okubigya.", diff --git a/_locales/lo/messages.json b/_locales/lo/messages.json index de33370e7..119205bb9 100644 --- a/_locales/lo/messages.json +++ b/_locales/lo/messages.json @@ -220,7 +220,6 @@ "onionRoutingPathDestination": "ຈຸດໝາຍ", "onionRoutingPathEntryNode": "ເນົດເຂົ້າ", "passwordChange": "ປ່ຽນລະຫັດຜ່ານ", - "passwordChangeDescription": "ປ່ຽນລະຫັດຕົກທາງທີ່ຈະເຜີດ Session.", "passwordConfirm": "ຢັນໄຮ", "passwordEnter": "ປ້ອນລະຫັດຜ່ານ", "permissionsAppleMusic": "Session ຕ້ອງໃຊ້ Apple Music ເພື່ອປ່ອຍແນບສື່ມວນຊົນ.", diff --git a/_locales/lt/messages.json b/_locales/lt/messages.json index 9746282a8..12e808574 100644 --- a/_locales/lt/messages.json +++ b/_locales/lt/messages.json @@ -601,8 +601,6 @@ "open": "Atverti", "other": "Kitas", "passwordChange": "Keisti slaptažodį", - "passwordChangeDescription": "Pakeisti slaptažodį, reikalingą atrakinti Session.", - "passwordChangedDescription": "Jūsų slaptažodis buvo pakeistas. Prašome saugoti jį saugiai.", "passwordConfirm": "Patvirtinkite slaptažodį", "passwordCurrentIncorrect": "Jūsų dabartinis slaptažodis yra neteisingas.", "passwordEnter": "Įveskite slaptažodį", @@ -613,7 +611,6 @@ "passwordFailed": "Nepavyko nustatyti slaptažodžio", "passwordIncorrect": "Neteisingas slaptažodis", "passwordRemove": "Šalinti slaptažodį", - "passwordRemovedDescription": "Jūsų slaptažodis buvo pašalintas.", "passwordSet": "Nustatyti slaptažodį", "paste": "Įdėti", "permissionMusicAudioDenied": "Session reikia prieigos prie muzikos ir garso, kad galėtumėte siųsti failus, muziką ir garsą, bet ji buvo visam laikui uždrausta. Bakstelėkite Nustatymai → Leidimai ir įjunkite \"Muziką ir garsą\".", diff --git a/_locales/lv/messages.json b/_locales/lv/messages.json index 9d8ba09fc..bd8ce1274 100644 --- a/_locales/lv/messages.json +++ b/_locales/lv/messages.json @@ -557,8 +557,6 @@ "open": "Atvērt", "other": "Cits", "passwordChange": "Mainīt paroli", - "passwordChangeDescription": "Mainīt paroli, kas nepieciešama Session atbloķēšanai.", - "passwordChangedDescription": "Jūsu parole tika nomainīta. Lūdzu, saglabājiet to drošībā.", "passwordConfirm": "Apstipriniet paroli", "passwordCurrentIncorrect": "Jūsu pašreizējā parole ir nepareiza.", "passwordEnter": "Ievadiet paroli", @@ -569,7 +567,6 @@ "passwordFailed": "Neizdevās iestatīt paroli", "passwordIncorrect": "Nepareiza parole", "passwordRemove": "Noņemt paroli", - "passwordRemovedDescription": "Jūsu parole tika noņemta.", "passwordSet": "Iestatīt Paroli", "paste": "Ielīmēt", "permissionsAppleMusic": "Session nepieciešams izmantot Apple Music, lai atskaņotu multivides pielikumus.", diff --git a/_locales/mk/messages.json b/_locales/mk/messages.json index a3e3983f2..f25b67dbe 100644 --- a/_locales/mk/messages.json +++ b/_locales/mk/messages.json @@ -598,8 +598,6 @@ "open": "Отвори", "other": "Други", "passwordChange": "Смени лозинка", - "passwordChangeDescription": "Смени ја лозинката што е потребна за отклучување Session.", - "passwordChangedDescription": "Вашата лозинка е променета. Ве молиме чувајте ја безбедно.", "passwordConfirm": "Потврди лозинка", "passwordCurrentIncorrect": "Вашата тековна лозинка е неточна.", "passwordEnter": "Внесете лозинка", @@ -610,7 +608,6 @@ "passwordFailed": "Неуспешно поставување лозинка", "passwordIncorrect": "Неправилна лозинка", "passwordRemove": "Отстрани лозинка", - "passwordRemovedDescription": "Вашата лозинка е отстранета.", "passwordSet": "Постави Лозинка", "paste": "Залепи", "permissionMusicAudioDenied": "Session има потреба од пристап до музика и аудио за да може да испраќа датотеки, музика и аудио, но пристапот е трајно одбиен. Допрете Поставки → Дозволи, и вклучете \"Музика и аудио\".", diff --git a/_locales/mn/messages.json b/_locales/mn/messages.json index 94c091068..638539508 100644 --- a/_locales/mn/messages.json +++ b/_locales/mn/messages.json @@ -609,8 +609,6 @@ "open": "Нээх", "other": "Бусад", "passwordChange": "Нууц үг өөрчлөх", - "passwordChangeDescription": "Session -г нээхийн тулд шаардлагатай нууц үгийг өөрчлөх.", - "passwordChangedDescription": "Таны нууц үг солигдож байна. Нууц үгээ хамгаалж байгаарай.", "passwordConfirm": "Нууц үгийг баталгаажуулах", "passwordCurrentIncorrect": "Таны одоогийн нууц үг буруу байна.", "passwordEnter": "Нууц үг оруулна уу", @@ -621,7 +619,6 @@ "passwordFailed": "Нууц үгийг тогтоохдоо алдаа гарлаа", "passwordIncorrect": "Зөв нууц үг биш", "passwordRemove": "Нууц үг устгах", - "passwordRemovedDescription": "Таны нууц үг устгагдсан.", "passwordSet": "Нууц үгээ тохируулах", "paste": "Буулгах", "permissionMusicAudioDenied": "Session-д файлууд, хөгжим, аудиог илгээхийн тулд хөгжмийн болон аудионы хандалт шаардлагатай байгаа боловч энэ нь байнга зөвшөөрөхөөс татгалзсан байна. Тохиргоо → Зөвшөөрөл хэсэгрүү ороод, \"Хөгжим болон аудио\"-г асаана уу.", diff --git a/_locales/ms/messages.json b/_locales/ms/messages.json index 5762cba1f..d76e66783 100644 --- a/_locales/ms/messages.json +++ b/_locales/ms/messages.json @@ -609,8 +609,6 @@ "open": "Buka", "other": "Lain-lain", "passwordChange": "Tukar Kata Laluan", - "passwordChangeDescription": "Tukar kata laluan yang diperlukan untuk membuka kunci Session.", - "passwordChangedDescription": "Kata laluan anda telah ditukar. Sila simpan dengan selamat.", "passwordConfirm": "Sahkan kata laluan", "passwordCurrentIncorrect": "Kata laluan semasa anda tidak betul.", "passwordEnter": "Masukkan kata laluan", @@ -621,7 +619,6 @@ "passwordFailed": "Gagal menetapkan kata laluan", "passwordIncorrect": "Kata laluan tidak betul", "passwordRemove": "Alih Keluar Kata Laluan", - "passwordRemovedDescription": "Kata laluan anda telah dibuang.", "passwordSet": "Tetapkan Kata Laluan", "paste": "Tampal", "permissionMusicAudioDenied": "Session memerlukan akses muzik dan audio untuk menghantar fail, muzik dan audio, tetapi ia telah ditolak secara kekal. Ketik Tetapan → Kebenaran, dan hidupkan \"Muzik dan audio\".", diff --git a/_locales/my/messages.json b/_locales/my/messages.json index 880aba2c3..86b5bea11 100644 --- a/_locales/my/messages.json +++ b/_locales/my/messages.json @@ -598,8 +598,6 @@ "open": "ဖွင့်", "other": "အခြား", "passwordChange": "လျှို့ဝှက် စကားဝှက် ပြောင်းပါ", - "passwordChangeDescription": "Session ဖြင့် လော့ခ်ဖွင့်ရန် လျှို့ဝှက် စကားဝှက် ပြောင်းပါ", - "passwordChangedDescription": "သင်၏ စကားဝှက် ပြောင်းလဲ ပြီးပါပြီ။ ထိန်းသိမ်းပါ။", "passwordConfirm": "စကားဝှက်ကို အတည်ပြုပါ", "passwordCurrentIncorrect": "သင့်လက်ရှိ စကားဝှက် မှား နေပါသည်။", "passwordEnter": "စကားဝှက်ထည့်ပါ", @@ -610,7 +608,6 @@ "passwordFailed": "စကားဝှက်တင်သွင်းမှု မအောင်မြင်ပါ", "passwordIncorrect": "စကားဝှက်မှားနေသည်", "passwordRemove": "စကားဝှက်ကို ဖယ်ရှားမည်", - "passwordRemovedDescription": "သင်၏ စကားဝှက် ဖယ်ရှားပြီးပါပြီ။", "passwordSet": "စကားဝှက်သတ်မှတ်မည်", "paste": "ကူးယူမည်", "permissionMusicAudioDenied": "Session သည် ဂီတနှင့်အသံဖိုင်များ ပို့ရန် လိုအပ်ပါသည်၊ ပြသနာ မရရှိရှိအောင် နိုင်ပါတယ်၊ ကြော့ကာရှာဖွေခြင်းစင့်ခဲ့ရပါသည်။ မနည်းနည်းတော့ ကောဖောက်နွိုင့်ဆက်နွှင့်နွေးကူဆိုင်ရာ 'ပို့'ထဲသို့သော 'ဂီတနှင့်အသံများ' ကိုဖွင့်ပါ။", diff --git a/_locales/nb/messages.json b/_locales/nb/messages.json index 7534d67c3..06f9fbb04 100644 --- a/_locales/nb/messages.json +++ b/_locales/nb/messages.json @@ -601,8 +601,6 @@ "open": "Åpne", "other": "Annet", "passwordChange": "Forandre passord", - "passwordChangeDescription": "Endre passordet som kreves for å låse opp Session.", - "passwordChangedDescription": "Passordet ditt er endret. Vennligst oppbevar det trygt.", "passwordConfirm": "Bekreft passordet", "passwordCurrentIncorrect": "Ditt nåværende passord er feil.", "passwordEnter": "Skriv inn passord", @@ -613,7 +611,6 @@ "passwordFailed": "Kunne ikke stille passordet", "passwordIncorrect": "Galt passord", "passwordRemove": "Fjern passord", - "passwordRemovedDescription": "Passordet ditt er fjernet.", "passwordSet": "Still passord", "paste": "Lim inn", "permissionMusicAudioDenied": "Session trenger tilgang til musikk og lyd for å sende filer, musikk og lyd, men det har blitt permanent nektet. Trykk på Innstillinger → Tillatelser, og slå på 'Musikk og lyd'.", diff --git a/_locales/ne/messages.json b/_locales/ne/messages.json index 9a7de4b27..d0407b98a 100644 --- a/_locales/ne/messages.json +++ b/_locales/ne/messages.json @@ -596,8 +596,6 @@ "open": "खोल्नुहोस्", "other": "अन्य", "passwordChange": "पासवर्ड परिवर्तन गर्नुहोस्", - "passwordChangeDescription": "Session अनलक गर्न आवश्यक पासवर्ड परिवर्तन गर्नुहोस्।", - "passwordChangedDescription": "तपाईँको पासवर्ड परिवर्तन भयो। कृपया यसलाई सुरक्षित राख्नुहोस्।", "passwordConfirm": "पासवर्ड निश्चित गर्नुहोस्", "passwordCurrentIncorrect": "तपाईंको हालको पासवर्ड सही छैन।", "passwordEnter": "पासवर्ड प्रविष्ट गर्नुहोस्", @@ -608,7 +606,6 @@ "passwordFailed": "पासवर्ड सेट गर्न असफल", "passwordIncorrect": "गलत पासवर्ड", "passwordRemove": "पासवर्ड हटाउनुहोस्", - "passwordRemovedDescription": "तपाईँको पासवर्ड हटाइएको छ।", "passwordSet": "पासवर्ड सेट गर्नुहोस्", "paste": "टाँस्नुहोस्", "permissionMusicAudioDenied": "Session लाई संगीत र अडियो पहुँच आवश्यक छ फाइलहरू, संगीत र अडियो पठाउनका लागि, तर यो स्थायी रूपमा अस्वीकृत गरिएको छ। सेटिङहरू → अनुमतिहरूमा थिच्नुहोस्, र \"संगीत र अडियो\" अन गर्नुहोस्।", diff --git a/_locales/nl/messages.json b/_locales/nl/messages.json index 0f0147d66..419779c5e 100644 --- a/_locales/nl/messages.json +++ b/_locales/nl/messages.json @@ -703,8 +703,6 @@ "openSurvey": "Enquête openen", "other": "Overige", "passwordChange": "Wachtwoord wijzigen", - "passwordChangeDescription": "Wijzig het wachtwoord dat nodig is om Session te ontgrendelen.", - "passwordChangedDescription": "Uw wachtwoord is gewijzigd. Hou het veilig.", "passwordConfirm": "Bevestig wachtwoord", "passwordCurrentIncorrect": "Uw huidige wachtwoord is onjuist.", "passwordEnter": "Voer wachtwoord in", @@ -716,7 +714,6 @@ "passwordFailed": "Instellen van wachtwoord mislukt", "passwordIncorrect": "Onjuist wachtwoord", "passwordRemove": "Wachtwoord verwijderen", - "passwordRemovedDescription": "Uw wachtwoord is verwijderd.", "passwordSet": "Wachtwoord instellen", "paste": "Plakken", "permissionChange": "Machtiging wijzigen", diff --git a/_locales/nn/messages.json b/_locales/nn/messages.json index 3cbbf48f6..311667c79 100644 --- a/_locales/nn/messages.json +++ b/_locales/nn/messages.json @@ -600,8 +600,6 @@ "open": "Åpne", "other": "Annan", "passwordChange": "Endre passord", - "passwordChangeDescription": "Endre passordet som krevst for å låsa opp Session.", - "passwordChangedDescription": "Passordet ditt er blitt endra. Vennligst oppbevar det trygt.", "passwordConfirm": "Bekreft passordet", "passwordCurrentIncorrect": "Ditt nåværande passord er feil.", "passwordEnter": "Skriv inn passord", @@ -612,7 +610,6 @@ "passwordFailed": "Kunne ikkje stilla passordet", "passwordIncorrect": "Galt passord", "passwordRemove": "Fjern passord", - "passwordRemovedDescription": "Passordet ditt er blitt fjerna.", "passwordSet": "Set Password", "paste": "Lim inn", "permissionMusicAudioDenied": "Session trenger musikk- og lydtilgang for å sende filer, musikk og lyd, men tilgangen er permanent avslått. Trykk Innstillinger → Tillatelser, og slå på \"Musikk og lyd\".", diff --git a/_locales/no/messages.json b/_locales/no/messages.json index baa1a6f07..b6d56706b 100644 --- a/_locales/no/messages.json +++ b/_locales/no/messages.json @@ -600,8 +600,6 @@ "open": "Åpne", "other": "Annet", "passwordChange": "Endre passord", - "passwordChangeDescription": "Endre passordet som kreves for å låse opp Session.", - "passwordChangedDescription": "Passordet ditt er endret. Vennligst oppbevar det trygt.", "passwordConfirm": "Bekreft passordet", "passwordCurrentIncorrect": "Ditt nåværende passord er feil.", "passwordEnter": "Skriv inn passord", @@ -612,7 +610,6 @@ "passwordFailed": "Kunne ikke stille passordet", "passwordIncorrect": "Galt passord", "passwordRemove": "Fjern passord", - "passwordRemovedDescription": "Passordet ditt har blitt fjernet.", "passwordSet": "Still passord", "paste": "Lim inn", "permissionMusicAudioDenied": "Session trenger tilgang til musikk og lyd for å sende filer, musikk og lyd, men det har blitt permanent nektet. Trykk på Innstillinger → Tillatelser, og slå på «Musikk og lyd».", diff --git a/_locales/ny/messages.json b/_locales/ny/messages.json index 2613c95f2..d6fb0ef2a 100644 --- a/_locales/ny/messages.json +++ b/_locales/ny/messages.json @@ -598,8 +598,6 @@ "open": "Amkati", "other": "Zina", "passwordChange": "Change Password", - "passwordChangeDescription": "Change the password required to unlock Session.", - "passwordChangedDescription": "Password yanu yasinthidwa. Chonde sungani mosamala.", "passwordConfirm": "Tsimikizani mawu achinsinsi", "passwordCurrentIncorrect": "Chinsinsi chanu chokhazikika sichili bwino.", "passwordEnter": "Lemberani mawu achinsinsi", @@ -610,7 +608,6 @@ "passwordFailed": "Zalephera kukhazikitsa mawu achinsinsi", "passwordIncorrect": "Mawekerede wosalakwika", "passwordRemove": "Chotsani Achinsinsi", - "passwordRemovedDescription": "Password yanu yachotsedwa.", "passwordSet": "Set Password", "paste": "Matulani", "permissionMusicAudioDenied": "Session needs music and audio access in order to send files, music and audio, but it has been permanently denied. Tap Settings → Permissions, and turn \"Music and audio\" on.", diff --git a/_locales/pa/messages.json b/_locales/pa/messages.json index 5af722a93..2f001745c 100644 --- a/_locales/pa/messages.json +++ b/_locales/pa/messages.json @@ -598,8 +598,6 @@ "open": "ਖੋਲ੍ਹੋ", "other": "ਹੋਰ", "passwordChange": "ਪਾਸਵਰਡ ਬਦਲੋ", - "passwordChangeDescription": "Session ਨੂੰ ਅਨਲੌਕ ਕਰਨ ਲਈ ਲੋੜੀਂਦੇ ਪਾਸਵਰਡ ਨੂੰ ਬਦਲੋ।", - "passwordChangedDescription": "ਤੁਹਾਡਾ ਪਾਸਵਰਡ ਬਦਲਿਆ ਗਿਆ ਹੈ। ਕਿਰਪਾ ਕਰਕੇ ਇਸਨੂੰ ਸੁਰੱਖਿਅਤ ਰੱਖੋ।", "passwordConfirm": "ਪਾਸਵਰਡ ਪੁਸ਼ਟੀ ਕਰੋ", "passwordCurrentIncorrect": "ਤੁਹਾਡਾ ਮੌਜੂਦਾ ਪਾਸਵਰਡ ਗਲਤ ਹੈ।", "passwordEnter": "ਪਾਸਵਰਡ ਦਰਜ ਕਰੋ", @@ -610,7 +608,6 @@ "passwordFailed": "ਪਾਸਵਰਡ ਸੈੱਟ ਕਰਨ ਵਿੱਚ ਅਸਫਲ ਹੋਇਆ", "passwordIncorrect": "ਗਲਤ ਪਾਸਵਰਡ", "passwordRemove": "ਪਾਸਵਰਡ ਹਟਾਓ", - "passwordRemovedDescription": "ਤੁਹਾਡਾ ਪਾਸਵਰਡ ਹਟਾ ਦਿੱਤਾ ਗਿਆ ਹੈ।", "passwordSet": "ਪਾਸਵਰਡ ਸੈੱਟ ਕਰੋ", "paste": "ਚਿਪਕਾਓ", "permissionMusicAudioDenied": "Session ਨੂੰ ਫਾਈਲਾਂ, ਸੰਗੀਤ ਅਤੇ ਆਡੀਓ ਭੇਜਣ ਲਈ ਸੰਗੀਤ ਅਤੇ ਆਡੀਓ ਪਹੁੰਚ ਦੀ ਲੋੜ ਹੈ, ਪਰ ਇਸਨੂੰ ਪੱਕੇ ਤੌਰ 'ਤੇ ਖਾਰਜ਼ ਕੀਤਾ ਗਿਆ ਹੈ। ਸੈਟਿੰਗਾਂ 'ਤੇ ਟੈਪ ਕਰੋ → ਅਨੁਮਤੀਆਂ, ਅਤੇ \"ਸੰਗੀਤ ਅਤੇ ਆਡੀਓ\" ਚਾਲੂ ਕਰੋ।", diff --git a/_locales/pl/messages.json b/_locales/pl/messages.json index 2286f21fd..b5dc0148d 100644 --- a/_locales/pl/messages.json +++ b/_locales/pl/messages.json @@ -703,8 +703,6 @@ "openSurvey": "Otwórz ankietę", "other": "Inne", "passwordChange": "Zmień hasło", - "passwordChangeDescription": "Zmień hasło wymagane do odblokowania aplikacji Session.", - "passwordChangedDescription": "Zmieniono hasło. Zachowaj je w bezpiecznym miejscu.", "passwordConfirm": "Potwierdź hasło", "passwordCurrentIncorrect": "Twoje obecne hasło jest nieprawidłowe.", "passwordEnter": "Wprowadź hasło", @@ -716,7 +714,6 @@ "passwordFailed": "Nie udało się ustawić hasła", "passwordIncorrect": "Nieprawidłowe hasło", "passwordRemove": "Usuń hasło", - "passwordRemovedDescription": "Usunięto hasło", "passwordSet": "Ustaw hasło", "paste": "Wklej", "permissionChange": "Zmiana uprawnień", diff --git a/_locales/ps/messages.json b/_locales/ps/messages.json index cfc0a52de..a0d3a8843 100644 --- a/_locales/ps/messages.json +++ b/_locales/ps/messages.json @@ -598,8 +598,6 @@ "open": "خلاص", "other": "نور", "passwordChange": "پاسورډ بدل کړئ", - "passwordChangeDescription": "د Session خلاصولو لپاره اړین پاسورډ بدل کړئ.", - "passwordChangedDescription": "ستاسو پاسورډ بدل شوی. مهرباني وکړۍ، دا خوندي وساتئ.", "passwordConfirm": "نښلول...", "passwordCurrentIncorrect": "ستاسو اوسنی پاسورډ غلط دی.", "passwordEnter": "پټنوم ولیکئ", @@ -610,7 +608,6 @@ "passwordFailed": "پټنوم تنظیم کې ناکام", "passwordIncorrect": "ناسم رمز", "passwordRemove": "پټنوم لرې کړئ", - "passwordRemovedDescription": "ستاسو پاسورډ لرې شوی دی.", "passwordSet": "پټنوم تنظیمول", "paste": "پیست", "permissionMusicAudioDenied": "Session ته د موسیقۍ او غږ لاسرسي اړتیا لري ترڅو فایلونه، موسیقۍ او غږ واستوئ، مګر دا په دائمي ډول رد شوی. تنظیماتو باندې ټپ وکړئ → اجازې، او \"موسیقي او غږ\" روښانه کړئ.", diff --git a/_locales/pt-BR/messages.json b/_locales/pt-BR/messages.json index 1cfe48269..02b0c22c8 100644 --- a/_locales/pt-BR/messages.json +++ b/_locales/pt-BR/messages.json @@ -610,8 +610,6 @@ "open": "Abrir", "other": "Outro", "passwordChange": "Alterar Senha", - "passwordChangeDescription": "Altere a senha necessária para desbloquear Session.", - "passwordChangedDescription": "Sua senha foi alterada. Por favor, mantenha-a segura.", "passwordConfirm": "Confirmar senha", "passwordCurrentIncorrect": "Sua senha atual está incorreta.", "passwordEnter": "Digite sua senha", @@ -622,7 +620,6 @@ "passwordFailed": "Falha ao definir a senha", "passwordIncorrect": "Senha incorreta", "passwordRemove": "Remover Senha", - "passwordRemovedDescription": "Sua senha foi removida.", "passwordSet": "Definir Senha", "paste": "Colar", "permissionMusicAudioDenied": "Session precisa de acesso a música e áudio para enviar arquivos, músicas e áudio, mas o acesso foi permanentemente negado. Toque em Configurações → Permissões e ative \"Música e áudio\".", diff --git a/_locales/pt-PT/messages.json b/_locales/pt-PT/messages.json index 236acb39f..b31311fc4 100644 --- a/_locales/pt-PT/messages.json +++ b/_locales/pt-PT/messages.json @@ -703,8 +703,6 @@ "openSurvey": "Abrir questionário", "other": "Outro", "passwordChange": "Alterar Palavra-passe", - "passwordChangeDescription": "Altere a palavra-passe, necessária para desbloquear Session.", - "passwordChangedDescription": "A sua palavra-passe foi alterada. Por favor, mantenha-a segura.", "passwordConfirm": "Confirmar palavra-passe", "passwordCurrentIncorrect": "A sua palavra-passe atual está incorreta.", "passwordEnter": "Introduza a palavra-passe", @@ -716,7 +714,6 @@ "passwordFailed": "Falha ao definir palavra-passe", "passwordIncorrect": "Palavra-passe Incorreta", "passwordRemove": "Remover Palavra-passe", - "passwordRemovedDescription": "A sua palavra-passe foi removida.", "passwordSet": "Configurar palavra-passe", "paste": "Colar", "permissionChange": "Alteração de permissão", diff --git a/_locales/ro/messages.json b/_locales/ro/messages.json index 50e10233a..c203c8fea 100644 --- a/_locales/ro/messages.json +++ b/_locales/ro/messages.json @@ -703,8 +703,6 @@ "openSurvey": "Deschide sondajul", "other": "Altele", "passwordChange": "Schimbã Parola", - "passwordChangeDescription": "Schimbați parola necesară pentru a debloca Session.", - "passwordChangedDescription": "Parola ta a fost schimbată. Te rugăm să o păstrezi în siguranță.", "passwordConfirm": "Confirmă parola", "passwordCurrentIncorrect": "Parola actuală este incorectă.", "passwordEnter": "Introduceți parola", @@ -716,7 +714,6 @@ "passwordFailed": "Eroare la setarea parolei", "passwordIncorrect": "Parolă incorectă", "passwordRemove": "Elimină parolă", - "passwordRemovedDescription": "Parola ta a fost eliminată.", "passwordSet": "Setează parola", "paste": "Lipire", "permissionChange": "Modificare permisiune", diff --git a/_locales/ru/messages.json b/_locales/ru/messages.json index 76f4c5b3d..3ff4e6853 100644 --- a/_locales/ru/messages.json +++ b/_locales/ru/messages.json @@ -700,8 +700,6 @@ "openSurvey": "Открытый опрос", "other": "Другое", "passwordChange": "Изменить пароль", - "passwordChangeDescription": "Измените пароль, необходимый для разблокировки Session.", - "passwordChangedDescription": "Ваш пароль был изменен. Пожалуйста, храните его в безопасном месте.", "passwordConfirm": "Подтвердить пароль", "passwordCurrentIncorrect": "Ваш пароль неверен.", "passwordEnter": "Введите пароль", @@ -712,7 +710,6 @@ "passwordFailed": "Не удалось установить пароль", "passwordIncorrect": "Неверный пароль", "passwordRemove": "Удалить пароль", - "passwordRemovedDescription": "Ваш пароль удален.", "passwordSet": "Установить пароль", "paste": "Вставить", "permissionChange": "Изменение разрешений", diff --git a/_locales/sh/messages.json b/_locales/sh/messages.json index 1703b1eb7..3ec4d4e39 100644 --- a/_locales/sh/messages.json +++ b/_locales/sh/messages.json @@ -598,8 +598,6 @@ "open": "Otvori", "other": "Ostalo", "passwordChange": "Promeni lozinku", - "passwordChangeDescription": "Promeni lozinku potrebnu za otključavanje Session.", - "passwordChangedDescription": "Tvoja šifra je promijenjena. Molimo, čuvaj je na sigurnom.", "passwordConfirm": "Potvrdi lozinku", "passwordCurrentIncorrect": "Trenutna lozinka nije ispravna.", "passwordEnter": "Unesi lozinku", @@ -610,7 +608,6 @@ "passwordFailed": "Nije uspjelo postavljanje lozinke", "passwordIncorrect": "Netočna lozinka", "passwordRemove": "Ukloni lozinku", - "passwordRemovedDescription": "Tvoja šifra je uklonjena.", "passwordSet": "Postavi lozinku", "paste": "Zalijepi", "permissionMusicAudioDenied": "Session treba pristup muzici i zvuku kako bi poslao datoteke, muziku i zvuk, ali je trajno odbijen. Dodirnite Postavke → Dozvole i uključite \"Muzika i zvuk\".", diff --git a/_locales/si/messages.json b/_locales/si/messages.json index fa52873d2..e90304fd9 100644 --- a/_locales/si/messages.json +++ b/_locales/si/messages.json @@ -598,8 +598,6 @@ "open": "විවෘත", "other": "වෙනත්", "passwordChange": "මුරපදය වෙනස් කරන්න", - "passwordChangeDescription": "Session අගුළු විවෘත කිරීමට අවශ්‍ය මුරපදය වෙනස් කරන්න.", - "passwordChangedDescription": "ඔබගේ මුරපදය වෙනස් කර ඇත. කරුණාකර එය ආරක්ෂිතව තබා ගන්න.", "passwordConfirm": "මුරපදය තහවුරු කරන්න", "passwordCurrentIncorrect": "ඔබේ වත්මන් මුරපදය නිවැරදි නැත", "passwordEnter": "මුරපදය යොදන්න", @@ -610,7 +608,6 @@ "passwordFailed": "මුරපදය සැකසීමට අසමත් විය", "passwordIncorrect": "සාවද්‍ය මුරපදයකි", "passwordRemove": "මුරපදය ඉවත් කරන්න", - "passwordRemovedDescription": "ඔබගේ මුරපදය ඉවත් කර ඇත.", "passwordSet": "මුරපදය සකසන්න", "paste": "අලවන්න", "permissionMusicAudioDenied": "Session කේතය මගින් ගොනු, සංගීත සහ ශබ්ද යවන ව්‍යාපෘතිය සඳහා සංගීත සහ ශබ්ද ප්‍රවේශ අවශ්‍ය වේ, නමුදු එය ස්ථිරවම ප්‍රතික්ෂේප කර ඇත. සැකසුම් → අවසරයන්, සහ \"සංගීත සහ ශබ්ද\" වට කරන්න.", diff --git a/_locales/sk/messages.json b/_locales/sk/messages.json index 1c851f5a4..60305afbd 100644 --- a/_locales/sk/messages.json +++ b/_locales/sk/messages.json @@ -599,8 +599,6 @@ "open": "Otvoriť", "other": "Iné", "passwordChange": "Zmeniť heslo", - "passwordChangeDescription": "Zmeňte heslo potrebné na odomknutie Session.", - "passwordChangedDescription": "Vaše heslo bolo zmenené. Uchovajte ho prosím v bezpečí.", "passwordConfirm": "Potvrdiť heslo", "passwordCurrentIncorrect": "Vaše aktuálne heslo je nesprávne.", "passwordEnter": "Zadajte heslo", @@ -611,7 +609,6 @@ "passwordFailed": "Nepodarilo sa nastaviť heslo", "passwordIncorrect": "Nesprávne heslo", "passwordRemove": "Odstrániť heslo", - "passwordRemovedDescription": "Vaše heslo bolo odstránené.", "passwordSet": "Nastaviť heslo", "paste": "Vložiť", "permissionMusicAudioDenied": "Session potrebuje prístup k hudbe a zvukom na odosielanie súborov, hudby a zvukov, ale bol natrvalo odmietnutý. Tap Settings → Permissions, and turn \"Music and audio\" on.", diff --git a/_locales/sl/messages.json b/_locales/sl/messages.json index ec1c9b7b4..17f12e7fb 100644 --- a/_locales/sl/messages.json +++ b/_locales/sl/messages.json @@ -598,8 +598,6 @@ "open": "Odpri", "other": "Drugo", "passwordChange": "Spremeni geslo", - "passwordChangeDescription": "Spremeni geslo potrebno za odklepanje Session.", - "passwordChangedDescription": "Vaše geslo je bilo spremenjeno. Prosim, hranite ga na varnem mestu.", "passwordConfirm": "Potrdi geslo", "passwordCurrentIncorrect": "Vaše trenutno geslo je napačno.", "passwordEnter": "Vnesite geslo", @@ -610,7 +608,6 @@ "passwordFailed": "Ni uspelo nastaviti gesla", "passwordIncorrect": "Napačno geslo", "passwordRemove": "Odstrani geslo", - "passwordRemovedDescription": "Vaše geslo je bilo odstranjeno.", "passwordSet": "Nastavi geslo", "paste": "Prilepi", "permissionMusicAudioDenied": "Session potrebuje dostop do glasbe in zvoka za pošiljanje datotek, glasbe in zvoka, vendar je bil ta trajno zavrnjen. Tapnite Nastavitve → Dovoljenja in vklopite \"Glasba in zvok\".", diff --git a/_locales/sq/messages.json b/_locales/sq/messages.json index 9b6b9fe82..2dc9a01a4 100644 --- a/_locales/sq/messages.json +++ b/_locales/sq/messages.json @@ -598,8 +598,6 @@ "open": "Hap", "other": "Tjetër", "passwordChange": "Ndrysho Fjalëkalimin", - "passwordChangeDescription": "Ndryshoni fjalëkalimin e kërkuar për të zhbllokuar Session.", - "passwordChangedDescription": "Fjalëkalimi juaj është ndryshuar. Ju lutemi ta mbani të sigurt.", "passwordConfirm": "Konfirmo fjalëkalimin", "passwordCurrentIncorrect": "Fjalëkalimi juaj aktual është i pasaktë.", "passwordEnter": "Jepni fjalëkalimin", @@ -610,7 +608,6 @@ "passwordFailed": "Dështoi vendosja e fjalëkalimit", "passwordIncorrect": "Fjalëkalim i pasaktë", "passwordRemove": "Hiqe Fjalëkalimin", - "passwordRemovedDescription": "Fjalëkalimi juaj është hequr.", "passwordSet": "Vendos Fjalëkalimin", "paste": "Ngjite", "permissionMusicAudioDenied": "Session ka nevojë për qasje në muzikë dhe audio për të dërguar skedarë, muzikë dhe audio, por kjo i është mohuar. Shtypni Settings → Permissions dhe aktivizoni \"Music and audio\".", diff --git a/_locales/sr-CS/messages.json b/_locales/sr-CS/messages.json index 0b09515aa..98fcc966d 100644 --- a/_locales/sr-CS/messages.json +++ b/_locales/sr-CS/messages.json @@ -598,8 +598,6 @@ "open": "Otvori", "other": "Ostalo", "passwordChange": "Promeni lozinku", - "passwordChangeDescription": "Promenite lozinku koja je potrebna za otključavanje Session.", - "passwordChangedDescription": "Vaša lozinka je promenjena. Čuvajte je na sigurnom mestu.", "passwordConfirm": "Potvrda lozinke", "passwordCurrentIncorrect": "Vaša trenutna lozinka je netačna.", "passwordEnter": "Unesite lozinku", @@ -610,7 +608,6 @@ "passwordFailed": "Postavljanje lozinke nije uspelo", "passwordIncorrect": "Pogrešna lozinka", "passwordRemove": "Ukloni lozinku", - "passwordRemovedDescription": "Vaša lozinka je uklonjena.", "passwordSet": "Postavi lozinku", "paste": "Nalepi", "permissionMusicAudioDenied": "Session treba pristup muzici i zvuku kako bi slao fajlove, muziku i zvuk, ali mu je trajno odbijeno. Tap Settings → Permissions, i omogućite \"Muzika i zvuk\".", diff --git a/_locales/sr-SP/messages.json b/_locales/sr-SP/messages.json index d9e2f259c..0323e4cdd 100644 --- a/_locales/sr-SP/messages.json +++ b/_locales/sr-SP/messages.json @@ -598,8 +598,6 @@ "open": "Отвори", "other": "Остало", "passwordChange": "Промени лозинку", - "passwordChangeDescription": "Измените лозинку потребну за откључавање Session.", - "passwordChangedDescription": "Ваша лозинка је промењена. Молимо вас да је сачувате.", "passwordConfirm": "Потврдите лозинку", "passwordCurrentIncorrect": "Ваша тренутна лозинка је нетачна.", "passwordEnter": "Унесите лозинку", @@ -610,7 +608,6 @@ "passwordFailed": "Неуспех у постављању лозинке", "passwordIncorrect": "Нетачна лозинка", "passwordRemove": "Уклони лозинку", - "passwordRemovedDescription": "Ваша лозинка је уклоњена.", "passwordSet": "Постави лозинку", "paste": "Налепи", "permissionMusicAudioDenied": "Session треба приступ музици и звуку ради слања датотека, музике и звука, али је приступ трајно одбијен. Додирните Поставке → Дозволе и укључите \"Музика и звук\".", diff --git a/_locales/sv/messages.json b/_locales/sv/messages.json index 362fa95ab..d62574362 100644 --- a/_locales/sv/messages.json +++ b/_locales/sv/messages.json @@ -703,8 +703,6 @@ "openSurvey": "Öppna undersökning", "other": "Övrigt", "passwordChange": "Ändra lösenord", - "passwordChangeDescription": "Ändra lösenordet som krävs för att låsa upp Session.", - "passwordChangedDescription": "Ditt lösenord har ändrats. Håll det säkert.", "passwordConfirm": "Bekräfta lösenord", "passwordCurrentIncorrect": "Ditt nuvarande lösenord är felaktigt.", "passwordEnter": "Ange lösenord", @@ -716,7 +714,6 @@ "passwordFailed": "Misslyckades att uppdatera lösenordet", "passwordIncorrect": "Felaktigt lösenord", "passwordRemove": "Ta bort lösenord", - "passwordRemovedDescription": "Ditt lösenord har tagits bort.", "passwordSet": "Ange lösenord", "paste": "Klistra in", "permissionChange": "Ändra tillåtelse", diff --git a/_locales/sw/messages.json b/_locales/sw/messages.json index 61f759397..a7245f228 100644 --- a/_locales/sw/messages.json +++ b/_locales/sw/messages.json @@ -599,8 +599,6 @@ "open": "Fungua", "other": "ingine", "passwordChange": "Badilisha Nywila", - "passwordChangeDescription": "Badilisha nywila inayohitajika kufungua Session.", - "passwordChangedDescription": "Nenosiri lako limebadilishwa. Tafadhali lihifadhi salama.", "passwordConfirm": "Thibitisha nenosiri", "passwordCurrentIncorrect": "Nenosiri lako la sasa sio sahihi.", "passwordEnter": "Weka nenosiri", @@ -611,7 +609,6 @@ "passwordFailed": "Imeshindikana kuweka nenosiri", "passwordIncorrect": "Nywila sio sahihi", "passwordRemove": "Ondoa Nywila", - "passwordRemovedDescription": "Nenosiri lako limeondolewa.", "passwordSet": "Weka Nywila", "paste": "Bandika", "permissionMusicAudioDenied": "Session inahitaji ruhusa ya muziki na sauti ili kutuma faili, muziki na sauti, lakini imekataliwa kabisa. Gusa Mipangilio → Ruhusa, na washa \"Muziki na sauti\".", diff --git a/_locales/ta/messages.json b/_locales/ta/messages.json index 9f22daf36..c181a048c 100644 --- a/_locales/ta/messages.json +++ b/_locales/ta/messages.json @@ -603,8 +603,6 @@ "open": "திற", "other": "பிற", "passwordChange": "கடவுச்சொல்லை மாற்றவும்", - "passwordChangeDescription": "Session ேத்தUnlock ச்சபட செய்ய வேண்டிய கடவுச்சொல்லை மாற்றவும்.", - "passwordChangedDescription": "உங்களின் கடவுச்சொல் மாற்றப்பட்டுள்ளது. தயவுசெய்து அதை பாதுகாப்பாக வைத்திருங்கள்.", "passwordConfirm": "கடவுச்சொல்லை உறுதி செய்தல்", "passwordCurrentIncorrect": "உங்கள் நடப்புக் கடவுச்சொல் தவறாக உள்ளது.", "passwordEnter": "கடவுச்சொல்லை உள்ளிடவும்", @@ -615,7 +613,6 @@ "passwordFailed": "கடவுச்சொல்லை அமைப்பதில் தோல்வி", "passwordIncorrect": "தவறான கடவுச்சொல்", "passwordRemove": "கடவுச்சொல்லை அகற்றவும்", - "passwordRemovedDescription": "உங்களின் கடவுச்சொல் நீக்கப்பட்டது.", "passwordSet": "கடவுச்சொல்லை அமை", "paste": "ஒட்டவும்", "permissionMusicAudioDenied": "Session கோப்புகளை, இசையை மற்றும் ஆடியோவின் அனுமதி கிடைக்க வேண்டியது அவசியம், ஆனால் இது நிரந்தரமாக நரம்பாகியிருக்கின்றது. அமைப்புகள்-க்கு தட்டவும் → அனுமதிகள், மற்றும் \"இசை மற்றும் ஆடியோ\" இயலுமைப்படுத்தவும்.", diff --git a/_locales/te/messages.json b/_locales/te/messages.json index 42f36becc..b21a05377 100644 --- a/_locales/te/messages.json +++ b/_locales/te/messages.json @@ -599,8 +599,6 @@ "open": "తెరవండి", "other": "ఇతరులు", "passwordChange": "పాస్వర్డ్ మార్చు", - "passwordChangeDescription": "Session ని అన్‌లాక్ చేయడానికి అవసరమైన పాస్‌వర్డ్ మార్చండి.", - "passwordChangedDescription": "మీ పాస్‌వర్డ్ మార్పు జరిగింది. దయచేసి దాన్ని సురక్షితంగా ఉంచండి.", "passwordConfirm": "పాస్‌వర్డ్‌ని నిర్ధారించండి", "passwordCurrentIncorrect": "మీ ప్రస్తుత పాస్‌వర్డ్ తప్పు.", "passwordEnter": "పాస్‌వర్డ్ ఎంటర్ చేయండి", @@ -611,7 +609,6 @@ "passwordFailed": "పాస్‌వర్డ్ సెట్ చేయడంలో విఫలమైంది", "passwordIncorrect": "సరికాని పాస్వర్డ్", "passwordRemove": "పాస్వర్డ్ తొలగించు", - "passwordRemovedDescription": "మీ పాస్‌వర్డ్ తొలగించబడింది.", "passwordSet": "పాస్‌వర్డ్ సెట్ చేయి", "paste": "పేస్ట్", "permissionMusicAudioDenied": "Session ఫైళ్లు, సంగీతం మరియు ఆడియోను పంపించడానికి మరియు ఆడియో యాక్సెస్ కావాలి, కానీ ఇది శాశ్వతంగా తిరస్కరించబడింది. సెట్టింగులు → అనుమతులు ని తట్టి, \"మ్యూజిక్ మరియు ఆడియో\"ని ఆన్ చేయండి.", diff --git a/_locales/th/messages.json b/_locales/th/messages.json index 99ba2df0a..5f7200117 100644 --- a/_locales/th/messages.json +++ b/_locales/th/messages.json @@ -599,8 +599,6 @@ "open": "เปิด", "other": "ที่อื่น", "passwordChange": "เปลี่ยนรหัสผ่าน", - "passwordChangeDescription": "เปลี่ยนรหัสผ่านที่ใช้ปลดล็อก Session", - "passwordChangedDescription": "รหัสผ่านของคุณได้รับการเปลี่ยนแปลงแล้ว กรุณารักษาเอาไว้ให้ปลอดภัย", "passwordConfirm": "Confirm password", "passwordCurrentIncorrect": "รหัสผ่านปัจจุบันของคุณไม่ถูกต้อง", "passwordEnter": "ป้อนรหัสผ่าน", @@ -611,7 +609,6 @@ "passwordFailed": "การตั้งรหัสผ่านล้มเหลว", "passwordIncorrect": "รหัสผ่านไม่ถูกต้อง", "passwordRemove": "ลบรหัสผ่าน", - "passwordRemovedDescription": "รหัสผ่านของคุณถูกลบแล้ว", "passwordSet": "ตั้งรหัสผ่าน", "paste": "วาง", "permissionMusicAudioDenied": "Session ต้องการเข้าถึงเพลงและเสียงเพื่อส่งไฟล์, เพลง และเสียง แต่คำขอนั้นถูกปฏิเสธอย่างถาวร กรุณาไปที่เมนูตั้งค่า → การอนุญาต และเปิดใช้งาน \"เพลงและเสียง\"", diff --git a/_locales/tl/messages.json b/_locales/tl/messages.json index 96ba02fd3..461375e1b 100644 --- a/_locales/tl/messages.json +++ b/_locales/tl/messages.json @@ -599,8 +599,6 @@ "open": "Buksan", "other": "Iba pa", "passwordChange": "Palitan ang Password", - "passwordChangeDescription": "Palitan ang password na kailangan para i-unlock ang Session.", - "passwordChangedDescription": "Ang iyong password ay nabago na. Mangyaring itago ito ng ligtas.", "passwordConfirm": "Kumpirmahin ang password", "passwordCurrentIncorrect": "Mali ang iyong kasalukuyang password.", "passwordEnter": "Ilagay ang password", @@ -611,7 +609,6 @@ "passwordFailed": "Nabigong mag-set ng password", "passwordIncorrect": "Maling password", "passwordRemove": "Tanggalin ang Password", - "passwordRemovedDescription": "Tinanggal ang iyong password.", "passwordSet": "Itakda ang Password", "paste": "Idikit", "permissionMusicAudioDenied": "Kailangan ng Session ng access sa musika at audio upang makapagpadala ng mga file, musika at audio, ngunit ito ay permanenteng tinanggihan. Pindutin ang Settings → Permissions, at i-on ang \"Musika at audio\".", diff --git a/_locales/tr/messages.json b/_locales/tr/messages.json index 560bea5e1..b8ec69acb 100644 --- a/_locales/tr/messages.json +++ b/_locales/tr/messages.json @@ -693,8 +693,6 @@ "open": "Aç", "other": "Diğer", "passwordChange": "Parolayı Değiştir", - "passwordChangeDescription": "Session kilidini açmak için gereken parolayı değiştirin.", - "passwordChangedDescription": "Şifreniz değiştirildi. Lütfen güvende tutunuz.", "passwordConfirm": "Şifreyi Doğrula", "passwordCurrentIncorrect": "Mevcut şifreniz yanlış.", "passwordEnter": "Parolayı girin", @@ -705,7 +703,6 @@ "passwordFailed": "Parolayı ayarlama başarısız oldu", "passwordIncorrect": "Yanlış şifre", "passwordRemove": "Parolayı Kaldır", - "passwordRemovedDescription": "Parolanız kaldırıldı.", "passwordSet": "Şifre Belirle", "paste": "Yapıştır", "permissionChange": "İzin Değişimi", diff --git a/_locales/uk/messages.json b/_locales/uk/messages.json index c3eaf8d67..95f30b7bf 100644 --- a/_locales/uk/messages.json +++ b/_locales/uk/messages.json @@ -700,8 +700,6 @@ "openSurvey": "Пройти опитування", "other": "Інші", "passwordChange": "Змінити пароль", - "passwordChangeDescription": "Змінити пароль, необхідний для розблокування Session.", - "passwordChangedDescription": "Ваш пароль змінено. Будь ласка, збережіть його в безпеці.", "passwordConfirm": "Підтвердіть пароль", "passwordCurrentIncorrect": "Ваш поточний пароль невірний.", "passwordEnter": "Введіть пароль", @@ -712,7 +710,6 @@ "passwordFailed": "Не вдалося встановити пароль", "passwordIncorrect": "Неправильний пароль", "passwordRemove": "Видалити пароль", - "passwordRemovedDescription": "Ваш пароль був видалений.", "passwordSet": "Встановити пароль", "paste": "Вставити", "permissionChange": "Потрібна зміна дозволів", diff --git a/_locales/ur/messages.json b/_locales/ur/messages.json index 7c4e10ed5..f0223398a 100644 --- a/_locales/ur/messages.json +++ b/_locales/ur/messages.json @@ -604,8 +604,6 @@ "open": "کھولیں", "other": "دیگر", "passwordChange": "پاس ورڈ تبدیل کریں", - "passwordChangeDescription": "Session کو ان لاک کرنے کے لیے مطلوبہ پاس ورڈ تبدیل کریں۔", - "passwordChangedDescription": "آپ کا پاس ورڈ تبدیل ہو گیا ہے۔ براہ کرم اسے محفوظ رکھیں۔", "passwordConfirm": "پاس ورڈ کی تصدیق کریں", "passwordCurrentIncorrect": "آپ کا موجودہ پاس ورڈ غلط ہے۔", "passwordEnter": "پاس ورڈ درج کریں", @@ -616,7 +614,6 @@ "passwordFailed": "پاس ورڈ سیٹ کرنے میں ناکامی", "passwordIncorrect": "غلط پاس ورڈ", "passwordRemove": "پاس ورڈ ہٹا دیں", - "passwordRemovedDescription": "آپ کا پاس ورڈ ہٹا دیا گیا ہے۔", "passwordSet": "پاس ورڈ سیٹ کریں", "paste": "چسپاں کریں", "permissionMusicAudioDenied": "Session کو فائلز، میوزک، اور آڈیو بھیجنے کے لیے میوزک اور آڈیو کی رسائی کی ضرورت ہے، مگر اسے مستقل طور پر انکار کر دیا گیا ہے۔ سیٹنگز پر ٹیپ کریں → اجازتیں، اور \"موسیقی اور آڈیو\" کو آن کریں۔", diff --git a/_locales/uz/messages.json b/_locales/uz/messages.json index 3629ebcb3..4c9791d3c 100644 --- a/_locales/uz/messages.json +++ b/_locales/uz/messages.json @@ -599,8 +599,6 @@ "open": "Ochish", "other": "Boshqa", "passwordChange": "Parolni o'zgartirish", - "passwordChangeDescription": "O'zingizga Sessionni ochish uchun zarur parolni o'zgartiring.", - "passwordChangedDescription": "Xabar so'rovingiz hozirda kutilmoqda.", "passwordConfirm": "Parolni tasdiqlash", "passwordCurrentIncorrect": "Sizning joriy parolingiz noto'g'ri.", "passwordEnter": "Parolni kiritish", @@ -611,7 +609,6 @@ "passwordFailed": "Parolni o'rnatishda muammo chiqdi", "passwordIncorrect": "Xato parol", "passwordRemove": "Parolni olib tashlash", - "passwordRemovedDescription": "Parolingiz saqlandi. Iltimos, uni xavfsiz joyda saqlang.", "passwordSet": "Parol oʻrnatish", "paste": "Qo'yish", "permissionMusicAudioDenied": "Session fayllar, musiqa va audioni jo'natish uchun musiqa va audio kirishiga ehtiyoj bor, ammo bu abadiy rad etilgan. Sozlamalar → Ruxsatlar, va \"Musiqa va audio\"ni yoqing.", diff --git a/_locales/vi/messages.json b/_locales/vi/messages.json index 6dc9c52c6..bed6363a7 100644 --- a/_locales/vi/messages.json +++ b/_locales/vi/messages.json @@ -653,8 +653,6 @@ "open": "Mở", "other": "Khác", "passwordChange": "Đổi mật khẩu", - "passwordChangeDescription": "Đổi mật khẩu cần thiết để mở khóa Session.", - "passwordChangedDescription": "Mật khẩu của bạn đã được đổi. Hãy giữ nó cẩn thận.", "passwordConfirm": "Xác nhận mật khẩu", "passwordCurrentIncorrect": "Mật khẩu hiện tại của bạn không chính xác.", "passwordEnter": "Nhập mật khẩu", @@ -665,7 +663,6 @@ "passwordFailed": "Đặt mật khẩu thất bại", "passwordIncorrect": "Mật khẩu không chính xác", "passwordRemove": "Xóa mật khẩu", - "passwordRemovedDescription": "Mật khẩu của bạn đã được gỡ bỏ.", "passwordSet": "Đặt Mật khẩu", "paste": "Dán", "permissionChange": "Thay đổi quyền hạn", diff --git a/_locales/xh/messages.json b/_locales/xh/messages.json index 53f592f45..4ead10beb 100644 --- a/_locales/xh/messages.json +++ b/_locales/xh/messages.json @@ -599,8 +599,6 @@ "open": "Vula", "other": "Okunye", "passwordChange": "Tshintsha Ipassword", - "passwordChangeDescription": "Tshintsha i-password efunekayo ukusikhulula Session.", - "passwordChangedDescription": "Iphasiwedi yakho itshintshiwe. Nceda uyigcine ikhuselekile.", "passwordConfirm": "Qinisekisa iphasiwedi", "passwordCurrentIncorrect": "Iphasiwedi yakho yangoku ayichaneki.", "passwordEnter": "Ngenisa i-password", @@ -611,7 +609,6 @@ "passwordFailed": "Koyekile ukumisela i-password", "passwordIncorrect": "Iphasiwedi echanekileyo", "passwordRemove": "Susa iphasiwedi", - "passwordRemovedDescription": "Iphasiwedi yakho isusiwe.", "passwordSet": "Set Password", "paste": "Ncamathisela", "permissionMusicAudioDenied": "Session ifuna ukufikelela kumculo kunye noaudio ukuze ukwazi ukuthumela iifayili, umculo kunye noaudio, kodwa oku kuthintelwe ngokusisigxina. Thepha ku-Settings → Permissions, kwaye uvule 'Umculo kunye noaudio'.", diff --git a/_locales/zh-CN/messages.json b/_locales/zh-CN/messages.json index 2e5aaaade..3e3d7b814 100644 --- a/_locales/zh-CN/messages.json +++ b/_locales/zh-CN/messages.json @@ -702,8 +702,6 @@ "openSurvey": "打开调查问卷", "other": "其它", "passwordChange": "更改密码", - "passwordChangeDescription": "更改Session的解锁密码", - "passwordChangedDescription": "您的密码已经设定。请妥善保管。", "passwordConfirm": "确认密码", "passwordCurrentIncorrect": "您当前的密码不正确。", "passwordEnter": "请输入密码", @@ -715,7 +713,6 @@ "passwordFailed": "设置密码失败", "passwordIncorrect": "密码不正确", "passwordRemove": "移除密码", - "passwordRemovedDescription": "您的密码已被移除。", "passwordSet": "设置密码", "paste": "粘贴", "permissionChange": "授权变更", diff --git a/_locales/zh-TW/messages.json b/_locales/zh-TW/messages.json index 7aef4243f..7ec4ab0e6 100644 --- a/_locales/zh-TW/messages.json +++ b/_locales/zh-TW/messages.json @@ -703,8 +703,6 @@ "openSurvey": "開啟問卷", "other": "其他", "passwordChange": "變更密碼", - "passwordChangeDescription": "更改解鎖 Session 所需的密碼。", - "passwordChangedDescription": "您的密碼變更完成。請注意保管。", "passwordConfirm": "確認密碼", "passwordCurrentIncorrect": "您目前的密碼不正確。", "passwordEnter": "輸入密碼", @@ -716,7 +714,6 @@ "passwordFailed": "設定密碼失敗", "passwordIncorrect": "密碼錯誤", "passwordRemove": "移除密碼", - "passwordRemovedDescription": "已移除密碼。", "passwordSet": "設定密碼", "paste": "貼上", "permissionChange": "權限變更", diff --git a/ts/components/basic/SessionToggle.tsx b/ts/components/basic/SessionToggle.tsx index 78fb37435..4a25a6cbb 100644 --- a/ts/components/basic/SessionToggle.tsx +++ b/ts/components/basic/SessionToggle.tsx @@ -1,4 +1,5 @@ import { type SessionDataTestId } from 'react'; +import type { CSSProperties } from 'styled-components'; import styled from 'styled-components'; const StyledKnob = styled.div<{ active: boolean }>` @@ -19,16 +20,17 @@ const StyledKnob = styled.div<{ active: boolean }>` background-color var(--default-duration) ease; transform: ${props => (props.active ? 'translateX(25px)' : '')}; + pointer-events: none; // let the container handle the event `; -const StyledSessionToggle = styled.div<{ active: boolean }>` +const StyledSessionToggle = styled.div<{ active: boolean; disabled: boolean }>` width: 51px; height: 25px; background-color: (--toggle-switch-off-background-color); border: 1px solid var(--toggle-switch-off-border-color); border-radius: 16px; position: relative; - cursor: pointer; + cursor: ${props => (props.disabled ? 'not-allowed' : 'pointer')}; transition: var(--default-duration); flex-shrink: 0; @@ -46,10 +48,15 @@ export const SessionToggle = ({ active, dataTestId, onClick, + style, }: { active: boolean; - onClick: () => void; + /** + * in undefined, the toggle won't be clickable and disabled + */ + onClick?: () => void; dataTestId?: SessionDataTestId; + style?: CSSProperties; }) => { return ( diff --git a/ts/components/buttons/GearAvatarButton.tsx b/ts/components/buttons/GearAvatarButton.tsx new file mode 100644 index 000000000..e5b849133 --- /dev/null +++ b/ts/components/buttons/GearAvatarButton.tsx @@ -0,0 +1,25 @@ +import { LUCIDE_ICONS_UNICODE } from '../icon/lucide'; +import { LucideIcon } from '../icon/LucideIcon'; + +/** + * Used only for our own avatar display at the top-left of the app (ActionPanel). + * It only supports the XL avatar size. + */ +export const GearAvatarButton = () => { + return ( + + ); +}; diff --git a/ts/components/buttons/GenericPanelButtonWithAction.tsx b/ts/components/buttons/GenericPanelButtonWithAction.tsx new file mode 100644 index 000000000..32640ed07 --- /dev/null +++ b/ts/components/buttons/GenericPanelButtonWithAction.tsx @@ -0,0 +1,42 @@ +import type { ReactNode, SessionDataTestId } from 'react'; +import styled from 'styled-components'; +import { useIsDarkTheme } from '../../state/theme/selectors/theme'; +import { StyledPanelButton, StyledContent } from './PanelButton'; +import { StyledPanelButtonSeparator } from './StyledPanelButtonGroupSeparator'; + +const StyledActionContainer = styled.div` + display: flex; + align-items: center; + pointer-events: none; // let the container handle the event (otherwise we get 2 onClick events, cancelling each others) +`; + +export type GenericPanelButtonProps = { + textElement: ReactNode; + actionElement: ReactNode; + onClick: undefined | (() => void | Promise); + rowDataTestId: SessionDataTestId; +}; + +export const GenericPanelButtonWithAction = (props: GenericPanelButtonProps) => { + const { actionElement, rowDataTestId, textElement, onClick } = props; + const isDarkTheme = useIsDarkTheme(); + const disabled = !onClick; + + return ( + <> + + + {textElement} + {actionElement} + + + + + ); +}; diff --git a/ts/components/buttons/PanelButton.tsx b/ts/components/buttons/PanelButton.tsx index 17033b8bf..f04b6c46d 100644 --- a/ts/components/buttons/PanelButton.tsx +++ b/ts/components/buttons/PanelButton.tsx @@ -4,16 +4,19 @@ import { Flex } from '../basic/Flex'; import { H8 } from '../basic/Heading'; import { SpacerXS } from '../basic/Text'; import { useIsDarkTheme } from '../../state/theme/selectors/theme'; +import { Localizer } from '../basic/Localizer'; +import type { WithTrArgs } from '../../localization/localeTools'; // NOTE Used for descendant components export const StyledContent = styled.div<{ disabled: boolean }>` display: flex; + justify-content: space-between; align-items: center; width: 100%; color: ${props => (props.disabled ? 'var(--disabled-color)' : 'inherit')}; `; -export const PanelLabel = styled.p` +const StyledPanelLabel = styled.p` color: var(--text-secondary-color); width: 100%; margin: 0; @@ -21,6 +24,14 @@ export const PanelLabel = styled.p` padding-block: var(--margins-sm); `; +export function PanelLabel({ tr }: WithTrArgs) { + return ( + + + + ); +} + const StyledRoundedPanelButtonGroup = styled.div` display: flex; flex-direction: column; @@ -113,6 +124,7 @@ export const PanelButton = (props: PanelButtonProps) => { }; const StyledSubtitle = styled.p<{ color?: string }>` + display: flex; font-size: var(--font-size-sm); line-height: 1.1; margin-top: 0; @@ -173,7 +185,7 @@ function TextOnly(props: PanelButtonTextBaseProps) { } export const PanelButtonTextWithSubText = ( - props: PanelButtonTextBaseProps & PanelButtonSubtextProps + props: PanelButtonTextBaseProps & PanelButtonSubtextProps & { extraSubTextNode?: ReactNode } ) => { return ( @@ -181,6 +193,7 @@ export const PanelButtonTextWithSubText = ( {props.subText} + {props.extraSubTextNode} ); diff --git a/ts/components/buttons/PanelRadioButton.tsx b/ts/components/buttons/PanelRadioButton.tsx index e4c791583..cd7ce0850 100644 --- a/ts/components/buttons/PanelRadioButton.tsx +++ b/ts/components/buttons/PanelRadioButton.tsx @@ -1,26 +1,17 @@ -import styled from 'styled-components'; -import { SessionDataTestId, type ReactNode } from 'react'; +import { SessionDataTestId } from 'react'; import { SessionRadio } from '../basic/SessionRadio'; -import { PanelButtonProps, StyledContent, StyledPanelButton } from './PanelButton'; -import { useIsDarkTheme } from '../../state/theme/selectors/theme'; -import { StyledPanelButtonSeparator } from './StyledPanelButtonGroupSeparator'; +import { + GenericPanelButtonWithAction, + type GenericPanelButtonProps, +} from './GenericPanelButtonWithAction'; -const StyledCheckContainer = styled.div` - display: flex; - align-items: center; -`; - -type PanelRadioButtonProps = Omit & { +type PanelRadioButtonProps = Pick & { value: any; - textElement: ReactNode; isSelected: boolean; onSelect?: (...args: Array) => void; onUnselect?: (...args: Array) => void; - // the row dataTestId is used to identify the whole row, not the radio button - rowDataTestId: SessionDataTestId; - // the radio input dataTestId is used to identify the radio button only. - // the textElement will have its own dataTestId radioInputDataTestId: SessionDataTestId; + disabled?: boolean; }; export const PanelRadioButton = (props: PanelRadioButtonProps) => { @@ -34,33 +25,28 @@ export const PanelRadioButton = (props: PanelRadioButtonProps) => { radioInputDataTestId, textElement, } = props; - const isDarkTheme = useIsDarkTheme(); return ( - <> - { - return isSelected ? onUnselect?.('bye') : onSelect?.('hi'); - }} - data-testid={rowDataTestId} - isDarkTheme={isDarkTheme} - > - - {textElement} - - - - - - - + { + return isSelected ? onUnselect?.('bye') : onSelect?.('hi'); + } + } + rowDataTestId={rowDataTestId} + textElement={textElement} + actionElement={ + + } + /> ); }; diff --git a/ts/components/buttons/PanelToggleButton.tsx b/ts/components/buttons/PanelToggleButton.tsx new file mode 100644 index 000000000..dfe04f70c --- /dev/null +++ b/ts/components/buttons/PanelToggleButton.tsx @@ -0,0 +1,34 @@ +/* eslint-disable @typescript-eslint/no-misused-promises */ +import { SessionDataTestId } from 'react'; +import { SessionToggle } from '../basic/SessionToggle'; +import { + GenericPanelButtonWithAction, + type GenericPanelButtonProps, +} from './GenericPanelButtonWithAction'; + +type PanelToggleButtonProps = Pick & { + active: boolean; + onClick: () => Promise; + toggleDataTestId: SessionDataTestId; + disabled?: boolean; +}; + +export const PanelToggleButton = (props: PanelToggleButtonProps) => { + const { active, onClick, toggleDataTestId, disabled = false, rowDataTestId, textElement } = props; + + return ( + + } + /> + ); +}; diff --git a/ts/components/buttons/PanelWithButtonInline.tsx b/ts/components/buttons/PanelWithButtonInline.tsx new file mode 100644 index 000000000..4beddf4e2 --- /dev/null +++ b/ts/components/buttons/PanelWithButtonInline.tsx @@ -0,0 +1,43 @@ +/* eslint-disable @typescript-eslint/no-misused-promises */ +import { SessionDataTestId } from 'react'; +import { SessionButton, type SessionButtonProps } from '../basic/SessionButton'; + +import { + GenericPanelButtonWithAction, + type GenericPanelButtonProps, +} from './GenericPanelButtonWithAction'; + +type PanelButtonOnRightProps = Pick & + Required> & { + onClick: () => Promise; + buttonDataTestId: SessionDataTestId; + disabled?: boolean; + buttonText: string; + }; + +export const PanelWithButtonInline = (props: PanelButtonOnRightProps) => { + const { + onClick, + buttonDataTestId, + disabled = false, + rowDataTestId, + textElement, + buttonText, + buttonColor, + } = props; + return ( + + } + /> + ); +}; diff --git a/ts/components/buttons/PlusAvatarButton.tsx b/ts/components/buttons/PlusAvatarButton.tsx index 1f13c128e..f830f4799 100644 --- a/ts/components/buttons/PlusAvatarButton.tsx +++ b/ts/components/buttons/PlusAvatarButton.tsx @@ -78,7 +78,7 @@ export const PlusAvatarButton = ({ isClosedGroup: boolean; }) => { if (!isAvatarActionSupportedAvatarSize(avatarSize)) { - throw new Error('onPlusAvatarClick is not supported for this avatar size'); + throw new Error('PlusAvatarButton is not supported for this avatar size'); } const hardcodedPosition = useAvatarActionPosition(avatarSize, 'bottom'); diff --git a/ts/components/dialog/user-settings/UploadFirstImage.tsx b/ts/components/buttons/UploadFirstImageButton.tsx similarity index 75% rename from ts/components/dialog/user-settings/UploadFirstImage.tsx rename to ts/components/buttons/UploadFirstImageButton.tsx index 2965314e3..9ec34e668 100644 --- a/ts/components/dialog/user-settings/UploadFirstImage.tsx +++ b/ts/components/buttons/UploadFirstImageButton.tsx @@ -1,8 +1,8 @@ import styled from 'styled-components'; -import { AvatarSize } from '../../avatar/Avatar'; -import { PlusAvatarButton } from '../../buttons/PlusAvatarButton'; -import { LUCIDE_ICONS_UNICODE } from '../../icon/lucide'; -import { LucideIcon } from '../../icon/LucideIcon'; +import { AvatarSize } from '../avatar/Avatar'; +import { LUCIDE_ICONS_UNICODE } from '../icon/lucide'; +import { LucideIcon } from '../icon/LucideIcon'; +import { PlusAvatarButton } from './PlusAvatarButton'; const StyledUploadButton = styled.div` background-color: var(--chat-buttons-background-color); diff --git a/ts/components/dialog/EditProfilePictureModal.tsx b/ts/components/dialog/EditProfilePictureModal.tsx index e6f0f2acc..78cf025ed 100644 --- a/ts/components/dialog/EditProfilePictureModal.tsx +++ b/ts/components/dialog/EditProfilePictureModal.tsx @@ -39,8 +39,8 @@ import { AvatarSize } from '../avatar/Avatar'; import { ProIconButton } from '../buttons/ProButton'; import { useProBadgeOnClickCb } from '../menuAndSettingsHooks/useProBadgeOnClickCb'; import { useUserHasPro } from '../../hooks/useHasPro'; -import { UploadFirstImageButton } from './user-settings/UploadFirstImage'; import { Localizer } from '../basic/Localizer'; +import { UploadFirstImageButton } from '../buttons/UploadFirstImageButton'; const StyledAvatarContainer = styled.div` cursor: pointer; @@ -163,7 +163,7 @@ export const EditProfilePictureModal = ({ conversationId }: EditProfilePictureMo const closeDialog = useCallback(() => { dispatch(updateEditProfilePictureModal(null)); if (isMe) { - dispatch(userSettingsModal({})); + dispatch(userSettingsModal({ userSettingsPage: 'default' })); } }, [dispatch, isMe]); diff --git a/ts/components/dialog/HideRecoveryPasswordDialog.tsx b/ts/components/dialog/HideRecoveryPasswordDialog.tsx index d281e0317..8a6bbfba8 100644 --- a/ts/components/dialog/HideRecoveryPasswordDialog.tsx +++ b/ts/components/dialog/HideRecoveryPasswordDialog.tsx @@ -1,8 +1,7 @@ import { isEmpty } from 'lodash'; import { useDispatch } from 'react-redux'; import { SettingsKey } from '../../data/settings-key'; -import { updateHideRecoveryPasswordModal } from '../../state/ducks/modalDialog'; -import { sectionActions } from '../../state/ducks/section'; +import { updateHideRecoveryPasswordModal, userSettingsModal } from '../../state/ducks/modalDialog'; import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton'; import { SpacerMD } from '../basic/Text'; import { @@ -30,7 +29,7 @@ export function HideRecoveryPasswordDialog(props: HideRecoveryPasswordDialogProp const onConfirmation = async () => { await window.setSettingValue(SettingsKey.hideRecoveryPassword, true); onClose(); - dispatch(sectionActions.showSettingsSection('privacy')); + dispatch(userSettingsModal({ userSettingsPage: 'privacy' })); }; if (isEmpty(state)) { diff --git a/ts/components/dialog/ModalContainer.tsx b/ts/components/dialog/ModalContainer.tsx index 3724cf8d4..8c4c5cc8f 100644 --- a/ts/components/dialog/ModalContainer.tsx +++ b/ts/components/dialog/ModalContainer.tsx @@ -86,12 +86,12 @@ export const ModalContainer = () => { return ( <> {/* Screens */} + {userSettingsModalState && } {conversationSettingsModalState && ( )} {sessionPasswordModalState && } {sessionNetworkModalState && } - {userSettingsModalState && } {onionPathModalState && } {reactListModalState && } {debugMenuModalState && } diff --git a/ts/components/dialog/OnionStatusPathDialog.tsx b/ts/components/dialog/OnionStatusPathDialog.tsx index ad04ec596..6f47f0464 100644 --- a/ts/components/dialog/OnionStatusPathDialog.tsx +++ b/ts/components/dialog/OnionStatusPathDialog.tsx @@ -10,12 +10,7 @@ import { isEmpty, isTypedArray } from 'lodash'; import { CityResponse, Reader } from 'maxmind'; import useMount from 'react-use/lib/useMount'; import { onionPathModal } from '../../state/ducks/modalDialog'; -import { - useFirstOnionPath, - useFirstOnionPathLength, - useIsOnline, - useOnionPathsCount, -} from '../../state/selectors/onions'; +import { useFirstOnionPath, useIsOnline } from '../../state/selectors/onions'; import { Flex } from '../basic/Flex'; import { Snode } from '../../data/types'; @@ -216,16 +211,6 @@ const ModalStatusLight = (props: StatusLightType) => { ); }; -// Set icon color based on result -const errorColor = 'var(--button-path-error-color)'; -const defaultColor = 'var(--button-path-default-color)'; -const connectingColor = 'var(--button-path-connecting-color)'; - -const OnionPathContainer = styled.button` - display: flex; - padding: var(--margins-lg); -`; - function OnionPathDot({ dataTestId, iconColor, @@ -257,36 +242,12 @@ function OnionPathDot({ ); } -/** - * A status light specifically for the action panel. Color is based on aggregate node states instead of individual onion node state - */ -export const ActionPanelOnionStatusLight = (props: { handleClick: () => void; id: string }) => { - const { handleClick, id } = props; - - const onionPathsCount = useOnionPathsCount(); - const firstPathLength = useFirstOnionPathLength(); - const isOnline = useIsOnline(); - - // start with red - let iconColor = errorColor; - // if we are not online or the first path is not valid, we keep red as color - if (isOnline && firstPathLength > 1) { - iconColor = - onionPathsCount >= 2 ? defaultColor : onionPathsCount >= 1 ? connectingColor : errorColor; - } - - return ( - - - - ); -}; - export const OnionPathModal = () => { const dispatch = useDispatch(); return ( dispatch(onionPathModal(null))} + topAnchor="25vh" headerChildren={} buttonChildren={ diff --git a/ts/components/dialog/SessionSetPasswordDialog.tsx b/ts/components/dialog/SessionSetPasswordDialog.tsx index eb18eb49e..a231c4227 100644 --- a/ts/components/dialog/SessionSetPasswordDialog.tsx +++ b/ts/components/dialog/SessionSetPasswordDialog.tsx @@ -19,6 +19,7 @@ import { } from '../SessionWrapperModal'; import { SimpleSessionInput } from '../inputs/SessionInput'; import { ModalFlexContainer } from './shared/ModalFlexContainer'; +import { SpacerSM } from '../basic/Text'; interface Props { passwordAction: PasswordAction; @@ -94,6 +95,7 @@ export class SessionSetPasswordDialog extends Component { } onClose={this.closeDialog} + topAnchor="35vh" $contentMinWidth={WrapperModalWidth.narrow} $contentMaxWidth={WrapperModalWidth.narrow} buttonChildren={ @@ -146,6 +148,7 @@ export class SessionSetPasswordDialog extends Component { /> )} + ); } @@ -211,7 +214,10 @@ export class SessionSetPasswordDialog extends Component { } await Storage.put('passHash', updatedHash); - ToastUtils.pushToastSuccess('setPasswordSuccessToast', tStripped('passwordSetDescription')); + ToastUtils.pushToastSuccess( + 'setPasswordSuccessToast', + tStripped('passwordSetDescriptionToast') + ); this.props.onOk(); this.closeDialog(); @@ -262,7 +268,7 @@ export class SessionSetPasswordDialog extends Component { ToastUtils.pushToastSuccess( 'setPasswordSuccessToast', - tStripped('passwordChangedDescription') + tStripped('passwordChangedDescriptionToast') ); this.props.onOk(); @@ -301,7 +307,7 @@ export class SessionSetPasswordDialog extends Component { ToastUtils.pushToastWarning( 'setPasswordSuccessToast', - tStripped('passwordRemovedDescription') + tStripped('passwordRemovedDescriptionToast') ); this.props.onOk(); diff --git a/ts/components/dialog/UpdateConversationDetailsDialog.tsx b/ts/components/dialog/UpdateConversationDetailsDialog.tsx index fcd88cf82..a50337dc4 100644 --- a/ts/components/dialog/UpdateConversationDetailsDialog.tsx +++ b/ts/components/dialog/UpdateConversationDetailsDialog.tsx @@ -33,7 +33,6 @@ import { SessionWrapperModal, } from '../SessionWrapperModal'; import { ClearInputButton } from '../inputs/ClearInputButton'; -import { UploadFirstImageButton } from './user-settings/UploadFirstImage'; import { ProfileAvatar } from './user-settings/components'; import { AvatarSize } from '../avatar/Avatar'; import { @@ -42,6 +41,7 @@ import { } from '../../state/selectors/sogsRoomInfo'; import { ReduxSogsRoomInfos } from '../../state/ducks/sogsRoomInfo'; import type { WithConvoId } from '../../session/types/with'; +import { UploadFirstImageButton } from '../buttons/UploadFirstImageButton'; function useNameErrorString({ isMe, diff --git a/ts/components/dialog/UserProfileModal.tsx b/ts/components/dialog/UserProfileModal.tsx index b08669607..3ba2cbc77 100644 --- a/ts/components/dialog/UserProfileModal.tsx +++ b/ts/components/dialog/UserProfileModal.tsx @@ -20,7 +20,7 @@ import { import { tr } from '../../localization/localeTools'; import { PubKey } from '../../session/types'; import type { ProfileDialogModes } from './user-settings/ProfileDialogModes'; -import { ProfileHeader, QRView } from './user-settings/components'; +import { ProfileHeader } from './user-settings/components'; import { useAvatarPath, useConversationUsernameWithFallback } from '../../hooks/useParamSelector'; import { SessionLucideIconButton } from '../icon/SessionIconButton'; import { LUCIDE_ICONS_UNICODE } from '../icon/lucide'; @@ -31,6 +31,7 @@ import { shortenDisplayName } from '../../session/profile_manager/ShortenDisplay import { UsernameFallback } from './conversationSettings/UsernameFallback'; import { ConversationTitleDialog } from './conversationSettings/ConversationTitleDialog'; import { SessionIDNotEditable } from '../basic/SessionIdNotEditable'; +import { QRView } from '../qrview/QrView'; const StyledHasDisabledMsgRequests = styled.div` max-width: 42ch; diff --git a/ts/components/dialog/conversationSettings/conversationSettingsHeader.tsx b/ts/components/dialog/conversationSettings/conversationSettingsHeader.tsx index b980ded9b..4955cd0e0 100644 --- a/ts/components/dialog/conversationSettings/conversationSettingsHeader.tsx +++ b/ts/components/dialog/conversationSettings/conversationSettingsHeader.tsx @@ -16,9 +16,10 @@ import { UsernameFallback } from './UsernameFallback'; import { ConversationTitleDialog } from './ConversationTitleDialog'; import { SessionIDNotEditable } from '../../basic/SessionIdNotEditable'; import { AccountIdPill } from '../../basic/AccountIdPill'; -import { ProfileHeader, QRView } from '../user-settings/components'; +import { ProfileHeader } from '../user-settings/components'; import type { ProfileDialogModes } from '../user-settings/ProfileDialogModes'; import { SessionUtilUserGroups } from '../../../session/utils/libsession/libsession_utils_user_groups'; +import { QRView } from '../../qrview/QrView'; function AccountId({ conversationId }: WithConvoId) { const isPrivate = useIsPrivate(conversationId); diff --git a/ts/components/dialog/conversationSettings/pages/default/defaultPage.tsx b/ts/components/dialog/conversationSettings/pages/default/defaultPage.tsx index 47378c15a..a09b73c55 100644 --- a/ts/components/dialog/conversationSettings/pages/default/defaultPage.tsx +++ b/ts/components/dialog/conversationSettings/pages/default/defaultPage.tsx @@ -8,7 +8,6 @@ import { import type { WithConvoId } from '../../../../../session/types/with'; import { Flex } from '../../../../basic/Flex'; import { useWeAreCommunityAdminOrModerator } from '../../../../../state/selectors/conversations'; -import { Localizer } from '../../../../basic/Localizer'; import { SpacerSM } from '../../../../basic/Text'; import { PanelButtonGroup } from '../../../../buttons'; import { PanelLabel } from '../../../../buttons/PanelButton'; @@ -47,11 +46,7 @@ import { useChangeNickname } from '../../../../menuAndSettingsHooks/useChangeNic import { useShowUpdateGroupOrCommunityDetailsCb } from '../../../../menuAndSettingsHooks/useShowUpdateGroupNameDescription'; function AdminSettingsTitle() { - return ( - - - - ); + return ; } function GroupV2AdminActions({ conversationId }: WithConvoId) { diff --git a/ts/components/dialog/conversationSettings/pages/disappearing-messages/DisappearingModes.tsx b/ts/components/dialog/conversationSettings/pages/disappearing-messages/DisappearingModes.tsx index 25dcb1a3b..351c5f490 100644 --- a/ts/components/dialog/conversationSettings/pages/disappearing-messages/DisappearingModes.tsx +++ b/ts/components/dialog/conversationSettings/pages/disappearing-messages/DisappearingModes.tsx @@ -1,6 +1,5 @@ import { tr } from '../../../../../localization/localeTools'; import { DisappearingMessageConversationModeType } from '../../../../../session/disappearing_messages/types'; -import { Localizer } from '../../../../basic/Localizer'; import { PanelButtonGroup, PanelButtonText, @@ -37,9 +36,7 @@ export const DisappearingModes = (props: DisappearingModesProps) => { return ( <> - - - + {Object.keys(options).map(_mode => { const mode = _mode as DisappearingMessageConversationModeType; diff --git a/ts/components/dialog/conversationSettings/pages/disappearing-messages/TimeOptions.tsx b/ts/components/dialog/conversationSettings/pages/disappearing-messages/TimeOptions.tsx index 83096f0ed..81a11183a 100644 --- a/ts/components/dialog/conversationSettings/pages/disappearing-messages/TimeOptions.tsx +++ b/ts/components/dialog/conversationSettings/pages/disappearing-messages/TimeOptions.tsx @@ -7,7 +7,6 @@ import { } from '../../../../../session/disappearing_messages/timerOptions'; import { PanelButtonGroup, PanelButtonText, PanelLabel } from '../../../../buttons/PanelButton'; import { PanelRadioButton } from '../../../../buttons/PanelRadioButton'; -import { Localizer } from '../../../../basic/Localizer'; import { assertUnreachable } from '../../../../../types/sqlSharedTypes'; type TimerOptionsProps = { @@ -77,11 +76,7 @@ export const TimeOptions = (props: TimerOptionsProps) => { return ( <> - {!hasOnlyOneMode && ( - - - - )} + {!hasOnlyOneMode && } {options.map(option => { // we want "time-option-1-hours", etc as accessibility id diff --git a/ts/components/dialog/network/SessionNetworkModal.tsx b/ts/components/dialog/network/SessionNetworkModal.tsx index 39253a0f2..6a112e7aa 100644 --- a/ts/components/dialog/network/SessionNetworkModal.tsx +++ b/ts/components/dialog/network/SessionNetworkModal.tsx @@ -2,7 +2,6 @@ import { useDispatch } from 'react-redux'; import { updateSessionNetworkModal } from '../../../state/ducks/modalDialog'; import { ModalBasicHeader, SessionWrapperModal } from '../../SessionWrapperModal'; import { LOCALE_DEFAULTS } from '../../../localization/constants'; -import { sectionActions } from '../../../state/ducks/section'; import { StakeSection } from './sections/StakeSection'; import { ExtraSmallText, LastRefreshedText } from './components'; import { SpacerMD, SpacerXL, SpacerXS } from '../../basic/Text'; @@ -45,7 +44,6 @@ export function SessionNetworkModal() { const dispatch = useDispatch(); const onClose = () => { - dispatch(sectionActions.showSettingsSection('privacy')); dispatch(updateSessionNetworkModal(null)); }; diff --git a/ts/components/dialog/user-settings/UserSettingsDialog.tsx b/ts/components/dialog/user-settings/UserSettingsDialog.tsx index 7e3e47076..618a75057 100644 --- a/ts/components/dialog/user-settings/UserSettingsDialog.tsx +++ b/ts/components/dialog/user-settings/UserSettingsDialog.tsx @@ -1,310 +1,18 @@ -import { RefObject, useRef, useState } from 'react'; -import { useDispatch } from 'react-redux'; -import styled from 'styled-components'; +import { type UserSettingsModalState } from '../../../state/ducks/modalDialog'; +import { DefaultSettingPage } from './pages/DefaultSettingsPage'; +import { PrivacySettingsPage } from './pages/PrivacySettingsPage'; -import { UserUtils } from '../../../session/utils'; - -import { useHotkey } from '../../../hooks/useHotkey'; -import { useOurAvatarPath, useOurConversationUsername } from '../../../hooks/useParamSelector'; -import { - updateConversationDetailsModal, - userSettingsModal, -} from '../../../state/ducks/modalDialog'; -import { ProfileHeader, ProfileName, QRView } from './components'; -import { tr } from '../../../localization/localeTools'; -import { ModalBasicHeader, SessionWrapperModal } from '../../SessionWrapperModal'; -import { SessionIDNotEditable } from '../../basic/SessionIdNotEditable'; -import { Flex } from '../../basic/Flex'; -import { AccountIdPill } from '../../basic/AccountIdPill'; -import { ModalPencilIcon } from '../shared/ModalPencilButton'; -import type { ProfileDialogModes } from './ProfileDialogModes'; -import { SessionLucideIconButton } from '../../icon/SessionIconButton'; -import { LUCIDE_ICONS_UNICODE } from '../../icon/lucide'; -import { PanelButtonGroup, PanelIconButton } from '../../buttons'; -import { LOCALE_DEFAULTS } from '../../../localization/constants'; -import { ProIconButton } from '../../buttons/ProButton'; -import { LucideIcon, type LucideIconProps } from '../../icon/LucideIcon'; -import { SessionIcon, type SessionIconProps } from '../../icon'; - -const handleKeyQRMode = (mode: ProfileDialogModes, setMode: (mode: ProfileDialogModes) => void) => { - switch (mode) { - case 'default': - setMode('qr'); - break; - case 'qr': - setMode('default'); - break; - default: +export const UserSettingsDialog = (modalState: UserSettingsModalState) => { + if (!modalState?.userSettingsPage) { + return null; } -}; -const handleKeyCancel = ( - mode: ProfileDialogModes, - setMode: (mode: ProfileDialogModes) => void, - inputRef: RefObject -) => { - switch (mode) { - case 'qr': - if (inputRef.current !== null && document.activeElement === inputRef.current) { - return; - } - setMode('default'); - break; + switch (modalState.userSettingsPage) { case 'default': + return ; + case 'privacy': + return ; default: + return ; } }; - -function SessionIconForSettings(props: Omit) { - return ; -} - -function LucideIconForSettings(props: Omit) { - return ; -} -const StyledUserSettingsDialog = styled.div``; - -function SessionProSection() { - return ( - - - } - text={LOCALE_DEFAULTS.app_pro} - onClick={() => { - throw new Error('Not implemented'); // TODO: add link to pro page - }} - dataTestId="session-pro-settings-menu-item" - color="var(--renderer-span-primary-color)" - /> - - ); -} - -function MiscSection() { - return ( - - - } - text={tr('donate')} - onClick={() => { - throw new Error('Not implemented'); - }} - dataTestId="donate-settings-menu-item" - /> - } - text={tr('onionRoutingPath')} - onClick={() => { - throw new Error('Not implemented'); - }} - dataTestId="path-light-container" - /> - } - text={LOCALE_DEFAULTS.network_name} - onClick={() => { - throw new Error('Not implemented'); - }} - dataTestId="session-network-settings-menu-item" - /> - - ); -} - -function SettingsSection() { - return ( - - } - text={tr('sessionPrivacy')} - onClick={() => { - throw new Error('Not implemented'); - }} - dataTestId="privacy-settings-menu-item" - /> - } - text={tr('sessionNotifications')} - onClick={() => { - throw new Error('Not implemented'); - }} - dataTestId="notifications-settings-menu-item" - /> - } - text={tr('sessionConversations')} - onClick={() => { - throw new Error('Not implemented'); - }} - dataTestId="conversations-settings-menu-item" - /> - } - text={tr('sessionAppearance')} - onClick={() => { - throw new Error('Not implemented'); - }} - dataTestId="appearance-settings-menu-item" - /> - - } - text={tr('sessionMessageRequests')} - onClick={() => { - throw new Error('Not implemented'); - }} - dataTestId="message-requests-settings-menu-item" - /> - } - text={tr('preferences')} - onClick={() => { - throw new Error('Not implemented'); - }} - dataTestId="preferences-settings-menu-item" - /> - - ); -} - -function AdminSection() { - return ( - - } - text={tr('sessionRecoveryPassword')} - onClick={() => { - throw new Error('Not implemented'); - }} - dataTestId="recovery-password-settings-menu-item" - /> - } - text={tr('sessionHelp')} - onClick={() => { - throw new Error('Not implemented'); - }} - dataTestId="help-settings-menu-item" - /> - - } - text={tr('sessionClearData')} - onClick={() => { - throw new Error('Not implemented'); - }} - dataTestId="clear-data-settings-menu-item" - color="var(--danger-color)" - /> - - ); -} - -export const UserSettingsDialog = () => { - const dispatch = useDispatch(); - - const profileName = useOurConversationUsername() || ''; - const [enlargedImage, setEnlargedImage] = useState(false); - const inputRef = useRef(null); - - const avatarPath = useOurAvatarPath() || ''; - const us = UserUtils.getOurPubKeyStrFromCache(); - - const [mode, setMode] = useState('default'); - - const showUpdateProfileInformation = () => { - dispatch(updateConversationDetailsModal({ conversationId: us })); - }; - - useHotkey('v', () => handleKeyQRMode(mode, setMode)); - useHotkey('Backspace', () => handleKeyCancel(mode, setMode, inputRef)); - useHotkey('Escape', () => closeDialog()); - - function copyAccountIdToClipboard() { - window.clipboard.writeText(us); - } - - function closeDialog() { - dispatch(userSettingsModal(null)); - } - - return ( - - } - /> - } - onClose={closeDialog} - shouldOverflow={true} - buttonChildren={null} - > - - {mode === 'qr' ? ( - setMode('default')} /> - ) : ( - setMode('qr')} - enlargedImage={enlargedImage} - toggleEnlargedImage={() => setEnlargedImage(!enlargedImage)} - /> - )} - {mode === 'default' && ( - - )} - - - - } - style={{ color: 'var(--text-primary-color)' }} - onClick={copyAccountIdToClipboard} - /> - - - - - - - - - ); -}; diff --git a/ts/components/dialog/user-settings/components.tsx b/ts/components/dialog/user-settings/components.tsx index 8bf6a031b..81fbcf942 100644 --- a/ts/components/dialog/user-settings/components.tsx +++ b/ts/components/dialog/user-settings/components.tsx @@ -1,52 +1,12 @@ import { type SessionDataTestId } from 'react'; import styled from 'styled-components'; -import { useDispatch } from 'react-redux'; -import { useIconToImageURL } from '../../../hooks/useIconToImageURL'; -import { updateLightBoxOptions } from '../../../state/ducks/modalDialog'; -import { prepareQRCodeForLightBox } from '../../../util/qrCodes'; -import { QRCodeLogoProps, SessionQRCode } from '../../SessionQRCode'; import { Avatar, AvatarSize } from '../../avatar/Avatar'; import { Flex } from '../../basic/Flex'; import { useProBadgeOnClickCb } from '../../menuAndSettingsHooks/useProBadgeOnClickCb'; import { useCurrentUserHasPro } from '../../../hooks/useHasPro'; import { ProIconButton } from '../../buttons/ProButton'; import { AvatarQrCodeButton } from '../../buttons/AvatarQrCodeButton'; -import { AvatarExitQrCodeButton } from '../../buttons/AvatarExitQrCodeButton'; - -const qrLogoProps: QRCodeLogoProps = { - iconType: 'brandThin', - iconSize: 42, -}; - -export const QRView = ({ sessionID, onExit }: { sessionID: string; onExit: () => void }) => { - const dispatch = useDispatch(); - const { dataURL, iconSize, iconColor, backgroundColor, loading } = useIconToImageURL(qrLogoProps); - - return ( - { - const lightBoxOptions = prepareQRCodeForLightBox(fileName, dataUrl); - dispatch(updateLightBoxOptions(lightBoxOptions)); - }} - ariaLabel={'Account ID QR code'} - dataTestId={'your-qr-code'} - // we need this for overflow buttons to be visible (see UserProfileModal) - style={{ marginTop: '15px', position: 'relative' }} - > - - - ); -}; type ProfileAvatarProps = { avatarPath: string | null; diff --git a/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx b/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx new file mode 100644 index 000000000..0f71ac734 --- /dev/null +++ b/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx @@ -0,0 +1,342 @@ +import { type RefObject, useRef, useState } from 'react'; +import { useDispatch } from 'react-redux'; +import styled from 'styled-components'; +import { useHotkey } from '../../../../hooks/useHotkey'; +import { useOurConversationUsername, useOurAvatarPath } from '../../../../hooks/useParamSelector'; +import { LOCALE_DEFAULTS } from '../../../../localization/constants'; +import { UserUtils, ToastUtils } from '../../../../session/utils'; +import { resetConversationExternal } from '../../../../state/ducks/conversations'; +import { + updateSessionProInfoModal, + onionPathModal, + updateSessionNetworkModal, + updateConversationDetailsModal, + userSettingsModal, +} from '../../../../state/ducks/modalDialog'; +import { networkDataActions } from '../../../../state/ducks/networkData'; +import { sectionActions, SectionType } from '../../../../state/ducks/section'; +import { AccountIdPill } from '../../../basic/AccountIdPill'; +import { Flex } from '../../../basic/Flex'; +import { SessionIDNotEditable } from '../../../basic/SessionIdNotEditable'; +import { PanelButtonGroup, PanelIconButton } from '../../../buttons'; +import { ProIconButton } from '../../../buttons/ProButton'; +import { type SessionIconProps, SessionIcon } from '../../../icon'; +import { LUCIDE_ICONS_UNICODE } from '../../../icon/lucide'; +import { type LucideIconProps, LucideIcon } from '../../../icon/LucideIcon'; +import { SessionLucideIconButton } from '../../../icon/SessionIconButton'; +import { QRView } from '../../../qrview/QrView'; +import { ModalBasicHeader, SessionWrapperModal } from '../../../SessionWrapperModal'; +import { showLinkVisitWarningDialog } from '../../OpenUrlModal'; +import { SessionProInfoVariant } from '../../SessionProInfoModal'; +import { ModalPencilIcon } from '../../shared/ModalPencilButton'; +import { ProfileHeader, ProfileName } from '../components'; +import type { ProfileDialogModes } from '../ProfileDialogModes'; +import { tr } from '../../../../localization/localeTools'; + +const handleKeyQRMode = (mode: ProfileDialogModes, setMode: (mode: ProfileDialogModes) => void) => { + switch (mode) { + case 'default': + setMode('qr'); + break; + case 'qr': + setMode('default'); + break; + default: + } +}; + +const handleKeyCancel = ( + mode: ProfileDialogModes, + setMode: (mode: ProfileDialogModes) => void, + inputRef: RefObject +) => { + switch (mode) { + case 'qr': + if (inputRef.current !== null && document.activeElement === inputRef.current) { + return; + } + setMode('default'); + break; + case 'default': + default: + } +}; + +function SessionIconForSettings(props: Omit) { + return ( + + ); +} + +function LucideIconForSettings(props: Omit) { + return ( + + ); +} +const StyledUserSettingsDialog = styled.div``; + +function SessionProSection() { + const dispatch = useDispatch(); + return ( + + + + + } + text={LOCALE_DEFAULTS.app_pro} + onClick={() => { + dispatch(updateSessionProInfoModal({ variant: SessionProInfoVariant.GENERIC })); + }} + dataTestId="session-pro-settings-menu-item" + color="var(--renderer-span-primary-color)" + /> + + ); +} + +function MiscSection() { + const dispatch = useDispatch(); + return ( + + + } + text={tr('donate')} + onClick={() => { + showLinkVisitWarningDialog('https://session.foundation/donate#app', dispatch); + }} + dataTestId="donate-settings-menu-item" + /> + } + text={tr('onionRoutingPath')} + onClick={() => { + dispatch(onionPathModal({})); + }} + dataTestId="path-light-container" + /> + } + text={LOCALE_DEFAULTS.network_name} + onClick={() => { + // do a refresh request on open + dispatch(networkDataActions.refreshInfoFromSeshServer() as any); + dispatch(updateSessionNetworkModal({})); + }} + dataTestId="session-network-settings-menu-item" + /> + + ); +} + +function SettingsSection() { + const dispatch = useDispatch(); + + return ( + + } + text={tr('sessionPrivacy')} + onClick={() => { + dispatch(userSettingsModal({ userSettingsPage: 'privacy' })); + }} + dataTestId="privacy-settings-menu-item" + /> + } + text={tr('sessionNotifications')} + onClick={() => { + throw new Error('Not implemented'); + }} + dataTestId="notifications-settings-menu-item" + /> + } + text={tr('sessionConversations')} + onClick={() => { + throw new Error('Not implemented'); + }} + dataTestId="conversations-settings-menu-item" + /> + } + text={tr('sessionAppearance')} + onClick={() => { + throw new Error('Not implemented'); + }} + dataTestId="appearance-settings-menu-item" + /> + + } + text={tr('sessionMessageRequests')} + onClick={() => { + dispatch(sectionActions.showLeftPaneSection(SectionType.Message)); + dispatch(sectionActions.setLeftOverlayMode('message-requests')); + dispatch(resetConversationExternal()); + }} + dataTestId="message-requests-settings-menu-item" + /> + } + text={tr('preferences')} + onClick={() => { + throw new Error('Not implemented'); + }} + dataTestId="preferences-settings-menu-item" + /> + + ); +} + +function AdminSection() { + return ( + + } + text={tr('sessionRecoveryPassword')} + onClick={() => { + throw new Error('Not implemented'); + }} + dataTestId="recovery-password-settings-menu-item" + /> + } + text={tr('sessionHelp')} + onClick={() => { + throw new Error('Not implemented'); + }} + dataTestId="help-settings-menu-item" + /> + + } + text={tr('sessionClearData')} + onClick={() => { + throw new Error('Not implemented'); + }} + dataTestId="clear-data-settings-menu-item" + color="var(--danger-color)" + /> + + ); +} + +export const DefaultSettingPage = () => { + const dispatch = useDispatch(); + + const profileName = useOurConversationUsername() || ''; + const [enlargedImage, setEnlargedImage] = useState(false); + const inputRef = useRef(null); + + const avatarPath = useOurAvatarPath() || ''; + const us = UserUtils.getOurPubKeyStrFromCache(); + + const [mode, setMode] = useState('default'); + + const showUpdateProfileInformation = () => { + dispatch(updateConversationDetailsModal({ conversationId: us })); + }; + + useHotkey('v', () => handleKeyQRMode(mode, setMode)); + useHotkey('Backspace', () => handleKeyCancel(mode, setMode, inputRef)); + useHotkey('Escape', () => closeDialog()); + + function copyAccountIdToClipboard() { + window.clipboard.writeText(us); + ToastUtils.pushCopiedToClipBoard(); + } + + function closeDialog() { + dispatch(userSettingsModal(null)); + } + + return ( + + } + /> + } + onClose={closeDialog} + shouldOverflow={true} + buttonChildren={null} + > + + {mode === 'qr' ? ( + setMode('default')} /> + ) : ( + setMode('qr')} + enlargedImage={enlargedImage} + toggleEnlargedImage={() => setEnlargedImage(!enlargedImage)} + /> + )} + {mode === 'default' && ( + + )} + + + + } + style={{ color: 'var(--text-primary-color)' }} + onClick={copyAccountIdToClipboard} + /> + + + + + + + + + ); +}; diff --git a/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx b/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx new file mode 100644 index 000000000..9410eca70 --- /dev/null +++ b/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx @@ -0,0 +1,349 @@ +import { useState, type SettingsToggles } from 'react'; +import useMount from 'react-use/lib/useMount'; +import useUpdate from 'react-use/lib/useUpdate'; +import { tr } from '../../../../localization/localeTools'; +import { + updateConfirmModal, + type UserSettingsModalState, +} from '../../../../state/ducks/modalDialog'; +import { + PanelButtonGroup, + PanelButtonTextWithSubText, + PanelLabel, +} from '../../../buttons/PanelButton'; +import { PanelToggleButton } from '../../../buttons/PanelToggleButton'; +import { + ModalBasicHeader, + SessionWrapperModal, + WrapperModalWidth, +} from '../../../SessionWrapperModal'; +import { ModalBackButton } from '../../shared/ModalBackButton'; +import { + useUserSettingsBackAction, + useUserSettingsCloseAction, + useUserSettingsTitle, +} from './userSettingsHooks'; +import { CallManager, UserUtils } from '../../../../session/utils'; +import { SessionButtonColor } from '../../../basic/SessionButton'; +import { + useHasLinkPreviewEnabled, + useWeHaveBlindedMsgRequestsEnabled, +} from '../../../../state/selectors/settings'; +import { SettingsKey } from '../../../../data/settings-key'; +import { SessionUtilUserProfile } from '../../../../session/utils/libsession/libsession_utils_user_profile'; +import type { TokenSimpleNoArgs } from '../../../../localization/locales'; +import { getPasswordHash, Storage } from '../../../../util/storage'; +import { SpacerXS } from '../../../basic/Text'; +import { PanelWithButtonInline } from '../../../buttons/PanelWithButtonInline'; +import { displayPasswordModal } from '../../../settings/SessionSettings'; + +type WithPasswordUpdatedCb = { onPasswordUpdated: (action: string) => void }; + +const toggleCallMediaPermissions = async (triggerUIUpdate: () => void) => { + const currentValue = window.getCallMediaPermissions(); + const onClose = () => window.inboxStore?.dispatch(updateConfirmModal(null)); + if (!currentValue) { + window.inboxStore?.dispatch( + updateConfirmModal({ + title: tr('callsVoiceAndVideoBeta'), + i18nMessage: { token: 'callsVoiceAndVideoModalDescription' }, + okTheme: SessionButtonColor.Danger, + okText: tr('theContinue'), + onClickOk: async () => { + await window.toggleCallMediaPermissionsTo(true); + triggerUIUpdate(); + CallManager.onTurnedOnCallMediaPermissions(); + onClose(); + }, + onClickCancel: async () => { + await window.toggleCallMediaPermissionsTo(false); + triggerUIUpdate(); + onClose(); + }, + onClickClose: onClose, + }) + ); + } else { + await window.toggleCallMediaPermissionsTo(false); + triggerUIUpdate(); + } +}; + +async function toggleLinkPreviews(isToggleOn: boolean, forceUpdate: () => void) { + if (!isToggleOn) { + window.inboxStore?.dispatch( + updateConfirmModal({ + title: tr('linkPreviewsSend'), + i18nMessage: { token: 'linkPreviewsSendModalDescription' }, + okTheme: SessionButtonColor.Danger, + okText: tr('theContinue'), + onClickOk: async () => { + const newValue = !isToggleOn; + await window.setSettingValue(SettingsKey.settingsLinkPreview, newValue); + forceUpdate(); + }, + onClickClose: () => { + window.inboxStore?.dispatch(updateConfirmModal(null)); + }, + }) + ); + } else { + await window.setSettingValue(SettingsKey.settingsLinkPreview, false); + await Storage.put(SettingsKey.hasLinkPreviewPopupBeenDisplayed, false); + forceUpdate(); + } +} + +function SettingsToggleBasic({ + active, + baseDataTestId, + onClick, + textToken, + subTextToken, +}: { + textToken: TokenSimpleNoArgs; + subTextToken: TokenSimpleNoArgs; + baseDataTestId: SettingsToggles; + active: boolean; + onClick: () => Promise; +}) { + return ( + + } + active={active} + onClick={onClick} + toggleDataTestId={`${baseDataTestId}-settings-toggle`} + rowDataTestId={`${baseDataTestId}-settings-row`} + /> + ); +} + +/** + * This is a static version of the TypingBubble component, but is only used here, hence why it's not a SessionIcon. + */ +function StaticTypingBubble({ width }: { width: string }) { + return ( + + + + + + + + + ); +} + +function HasPasswordSubSection(props: WithPasswordUpdatedCb) { + return ( + + + } + rowDataTestId={'change-password-settings-row'} + buttonDataTestId={'change-password-settings-button'} + onClick={async () => { + displayPasswordModal('change', props.onPasswordUpdated); + }} + buttonColor={SessionButtonColor.Primary} + buttonText={tr('change')} + /> + + } + rowDataTestId={'remove-password-settings-row'} + buttonDataTestId={'remove-password-settings-button'} + onClick={async () => { + displayPasswordModal('remove', props.onPasswordUpdated); + }} + buttonColor={SessionButtonColor.Danger} + buttonText={tr('remove')} + /> + + ); +} +function NoPasswordSubSection(props: WithPasswordUpdatedCb) { + return ( + + + } + rowDataTestId={'set-password-settings-row'} + buttonDataTestId={'set-password-settings-button'} + onClick={async () => { + displayPasswordModal('set', props.onPasswordUpdated); + }} + buttonColor={SessionButtonColor.Primary} + buttonText={tr('set')} + /> + + ); +} + +function PasswordSubSection() { + const [hasPassword, setHasPassword] = useState(true); + useMount(() => { + const hash = getPasswordHash(); + setHasPassword(!!hash); + }); + + function onPasswordUpdated(action: string) { + if (action === 'set' || action === 'change') { + setHasPassword(true); + } else if (action === 'remove') { + setHasPassword(false); + } + } + + if (hasPassword) { + return ; + } + return ; +} + +export function PrivacySettingsPage(modalState: UserSettingsModalState) { + const backAction = useUserSettingsBackAction(modalState); + const closeAction = useUserSettingsCloseAction(modalState); + const title = useUserSettingsTitle(modalState); + const weHaveBlindedRequestsEnabled = useWeHaveBlindedMsgRequestsEnabled(); + const isLinkPreviewsOn = useHasLinkPreviewEnabled(); + + const forceUpdate = useUpdate(); + + return ( + : undefined} + /> + } + onClose={closeAction || undefined} + shouldOverflow={true} + allowOutsideClick={false} + $contentMinWidth={WrapperModalWidth.normal} + > + + + { + await toggleCallMediaPermissions(forceUpdate); + forceUpdate(); + }} + textToken="callsVoiceAndVideoBeta" + subTextToken="callsVoiceAndVideoToggleDescription" + /> + { + await window.toggleMediaPermissions(); + forceUpdate(); + }} + textToken="permissionsMicrophone" + subTextToken="permissionsMicrophoneDescription" + /> + + + + { + const toggledValue = !weHaveBlindedRequestsEnabled; + await window.setSettingValue(SettingsKey.hasBlindedMsgRequestsEnabled, toggledValue); + await SessionUtilUserProfile.insertUserProfileIntoWrapper( + UserUtils.getOurPubKeyStrFromCache() + ); + forceUpdate(); + }} + textToken="messageRequestsCommunities" + subTextToken="messageRequestsCommunitiesDescription" + /> + + + + { + const old = Boolean(window.getSettingValue(SettingsKey.settingsReadReceipt)); + await window.setSettingValue(SettingsKey.settingsReadReceipt, !old); + forceUpdate(); + }} + textToken="readReceipts" + subTextToken="readReceiptsDescription" + /> + + + + + + + + } + /> + } + active={Boolean(window.getSettingValue(SettingsKey.settingsTypingIndicator))} + onClick={async () => { + const old = Boolean(window.getSettingValue(SettingsKey.settingsTypingIndicator)); + await window.setSettingValue(SettingsKey.settingsTypingIndicator, !old); + forceUpdate(); + }} + toggleDataTestId={'enable-typing-indicators-settings-toggle'} + rowDataTestId={'enable-typing-indicators-settings-row'} + />{' '} + + + + { + void toggleLinkPreviews(isLinkPreviewsOn, forceUpdate); + }} + textToken="linkPreviewsSend" + subTextToken="linkPreviewsDescription" + /> + + + + + ); +} diff --git a/ts/components/dialog/user-settings/pages/userSettingsHooks.tsx b/ts/components/dialog/user-settings/pages/userSettingsHooks.tsx new file mode 100644 index 000000000..39f2c3174 --- /dev/null +++ b/ts/components/dialog/user-settings/pages/userSettingsHooks.tsx @@ -0,0 +1,77 @@ +import { useDispatch } from 'react-redux'; +import { tr } from '../../../../localization/localeTools'; +import { + userSettingsModal, + type UserSettingsModalState, +} from '../../../../state/ducks/modalDialog'; +import { assertUnreachable } from '../../../../types/sqlSharedTypes'; + +export function useUserSettingsTitle(page: UserSettingsModalState | undefined) { + if (!page) { + return tr('sessionSettings'); + } + switch (page.userSettingsPage) { + case 'appearance': + return tr('sessionAppearance'); + case 'notifications': + return tr('sessionNotifications'); + case 'clear-data': + return tr('sessionClearData'); + case 'conversations': + return tr('sessionConversations'); + case 'message-requests': + return tr('sessionMessageRequests'); + case 'recovery-password': + return tr('sessionRecoveryPassword'); + case 'privacy': + return tr('sessionPrivacy'); + case 'help': + return tr('sessionHelp'); + case 'preferences': + return tr('preferences'); + case 'default': + case undefined: + return tr('sessionSettings'); + default: + assertUnreachable(page.userSettingsPage, "useTitleFromPage doesn't support this page"); + throw new Error('useTitleFromPage does not support this page'); + } +} + +export function useUserSettingsCloseAction(props: UserSettingsModalState) { + const dispatch = useDispatch(); + if (!props?.userSettingsPage) { + return null; + } + + switch (props.userSettingsPage) { + case 'default': + case 'notifications': + case 'appearance': + case 'conversations': + case 'privacy': + case 'message-requests': + case 'recovery-password': + case 'help': + case 'clear-data': + case 'preferences': + return () => dispatch(userSettingsModal(null)); + + default: + assertUnreachable(props.userSettingsPage, 'useCloseActionFromPage: invalid userSettingsPage'); + throw new Error('useCloseActionFromPage: invalid userSettingsPage'); + } +} + +export function useUserSettingsBackAction(modalState: UserSettingsModalState) { + if (!modalState?.userSettingsPage || modalState?.userSettingsPage === 'default') { + // no back button if we are on the default page + return undefined; + } + + return () => { + userSettingsModal({ + userSettingsPage: 'default', + }); + }; +} diff --git a/ts/components/leftpane/ActionsPanel.tsx b/ts/components/leftpane/ActionsPanel.tsx index c97ef8de7..46f26070d 100644 --- a/ts/components/leftpane/ActionsPanel.tsx +++ b/ts/components/leftpane/ActionsPanel.tsx @@ -24,18 +24,13 @@ import { DecryptedAttachmentsManager } from '../../session/crypto/DecryptedAttac import { DURATION } from '../../session/constants'; import { reuploadCurrentAvatarUs } from '../../interactions/avatar-interactions/nts-avatar-interactions'; -import { - userSettingsModal, - onionPathModal, - updateDebugMenuModal, -} from '../../state/ducks/modalDialog'; +import { updateDebugMenuModal, userSettingsModal } from '../../state/ducks/modalDialog'; import { loadDefaultRooms } from '../../session/apis/open_group_api/opengroupV2/ApiUtil'; import { getOpenGroupManager } from '../../session/apis/open_group_api/opengroupV2/OpenGroupManagerV2'; import { getSwarmPollingInstance } from '../../session/apis/snode_api'; import { UserUtils } from '../../session/utils'; import { Avatar, AvatarSize } from '../avatar/Avatar'; -import { ActionPanelOnionStatusLight } from '../dialog/OnionStatusPathDialog'; import { SessionLucideIconButton, type SessionLucideIconButtonProps, @@ -66,9 +61,11 @@ import { Storage } from '../../util/storage'; import { getFileInfoFromFileServer } from '../../session/apis/file_server_api/FileServerApi'; import { themesArray } from '../../themes/constants/colors'; import { isDebugMode } from '../../shared/env_vars'; +import { GearAvatarButton } from '../buttons/GearAvatarButton'; const StyledContainerAvatar = styled.div` padding: var(--margins-lg); + position: relative; `; function handleThemeSwitch() { @@ -100,22 +97,23 @@ const Section = (props: { type: SectionType }) => { const isSelected = focusedSection === type; const handleClick = () => { - if (type === SectionType.Profile) { - dispatch(userSettingsModal({})); - } else if (type === SectionType.ColorMode) { - void handleThemeSwitch(); - } else if (type === SectionType.PathIndicator) { - // Show Path Indicator Modal - dispatch(onionPathModal({})); - } else if (type === SectionType.DebugMenu) { - // Show Debug Menu + if (type === SectionType.DebugMenu) { dispatch(updateDebugMenuModal({})); - } else { - // message section - dispatch(searchActions.clearSearch()); - dispatch(sectionActions.showLeftPaneSection(type)); - dispatch(sectionActions.resetLeftOverlayMode()); + return; } + if (type === SectionType.ThemeSwitch) { + void handleThemeSwitch(); + return; + } + + if (type === SectionType.Profile) { + dispatch(userSettingsModal({ userSettingsPage: 'default' })); + return; + } + // message section + dispatch(searchActions.clearSearch()); + dispatch(sectionActions.showLeftPaneSection(type)); + dispatch(sectionActions.resetLeftOverlayMode()); }; const settingsIconRef = useRef(null); @@ -133,12 +131,13 @@ const Section = (props: { type: SectionType }) => { return ( + ); } @@ -183,11 +182,7 @@ const Section = (props: { type: SectionType }) => { dataTestId="debug-menu-section" /> ); - case SectionType.PathIndicator: - return ( - - ); - case SectionType.ColorMode: + case SectionType.ThemeSwitch: default: return ( {
{showDebugMenu &&
} -
-
+
); diff --git a/ts/components/leftpane/LeftPaneSectionContainer.tsx b/ts/components/leftpane/LeftPaneSectionContainer.tsx index d1307f529..07c500314 100644 --- a/ts/components/leftpane/LeftPaneSectionContainer.tsx +++ b/ts/components/leftpane/LeftPaneSectionContainer.tsx @@ -11,10 +11,4 @@ export const LeftPaneSectionContainer = styled.div` .session-icon-button { padding: 30px 20px; } - - // this is not ideal but it seems that nth-0last-child does not work - #onion-path-indicator-led-id { - margin: auto auto 0px auto; - opacity: 1; - } `; diff --git a/ts/components/leftpane/LeftPaneSectionHeader.tsx b/ts/components/leftpane/LeftPaneSectionHeader.tsx index 3d5578a5c..0d2efb6f5 100644 --- a/ts/components/leftpane/LeftPaneSectionHeader.tsx +++ b/ts/components/leftpane/LeftPaneSectionHeader.tsx @@ -77,10 +77,7 @@ const StyledLeftPaneBanner = styled.div` border-bottom: 1px solid var(--border-color); `; -function getLeftPaneHeaderLabel( - leftOverlayMode: LeftOverlayMode | undefined, - focusedSection: SectionType -): string { +function getLeftPaneHeaderLabel(leftOverlayMode: LeftOverlayMode | undefined): string { let label = ''; switch (leftOverlayMode) { @@ -104,14 +101,6 @@ function getLeftPaneHeaderLabel( label = tr('messages'); } - switch (focusedSection) { - case SectionType.Settings: - label = tr('sessionSettings'); - break; - case SectionType.Message: - default: - } - return label; } @@ -182,7 +171,7 @@ export const LeftPaneSectionHeader = () => { dispatch(sectionActions.setLeftOverlayMode('choose-action')); }; - const label = getLeftPaneHeaderLabel(leftOverlayMode, focusedSection); + const label = getLeftPaneHeaderLabel(leftOverlayMode); const isMessageSection = focusedSection === SectionType.Message; return ( diff --git a/ts/components/leftpane/LeftPaneSettingSection.tsx b/ts/components/leftpane/LeftPaneSettingSection.tsx index a56504761..a5eced963 100644 --- a/ts/components/leftpane/LeftPaneSettingSection.tsx +++ b/ts/components/leftpane/LeftPaneSettingSection.tsx @@ -2,13 +2,8 @@ import { type ReactNode, SessionDataTestId, useMemo } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import styled from 'styled-components'; -import { resetConversationExternal } from '../../state/ducks/conversations'; -import { - updateDeleteAccountModal, - updateSessionNetworkModal, - updateSessionProInfoModal, -} from '../../state/ducks/modalDialog'; -import { sectionActions, SectionType } from '../../state/ducks/section'; +import { updateDeleteAccountModal } from '../../state/ducks/modalDialog'; +import { sectionActions } from '../../state/ducks/section'; import { getFocusedSettingsSection } from '../../state/selectors/section'; import { useHideRecoveryPasswordEnabled } from '../../state/selectors/settings'; import type { SessionSettingCategory } from '../../types/ReduxTypes'; @@ -19,12 +14,9 @@ import { getSessionNetworkModalState } from '../../state/selectors/modal'; import { LOCALE_DEFAULTS } from '../../localization/constants'; import { Localizer } from '../basic/Localizer'; import { tr } from '../../localization/localeTools'; -import { networkDataActions } from '../../state/ducks/networkData'; -import { showLinkVisitWarningDialog } from '../dialog/OpenUrlModal'; import { LUCIDE_ICONS_UNICODE, type WithLucideUnicode } from '../icon/lucide'; import { LucideIcon } from '../icon/LucideIcon'; import { ProIconButton } from '../buttons/ProButton'; -import { SessionProInfoVariant } from '../dialog/SessionProInfoModal'; import { useIsProAvailable } from '../../hooks/useIsProAvailable'; const StyledSettingsSectionTitle = styled.span<{ @@ -162,22 +154,10 @@ const LeftPaneSettingsCategoryRow = ({ item }: { item: Categories }) => { onClick={() => { switch (id) { case 'message-requests': - dispatch(sectionActions.showLeftPaneSection(SectionType.Message)); - dispatch(sectionActions.setLeftOverlayMode('message-requests')); - dispatch(resetConversationExternal()); - break; - case 'donate': - showLinkVisitWarningDialog('https://session.foundation/donate#app', dispatch); break; case 'session-network': // if the network modal is not open yet do an info request - if (focusedSettingsSection !== 'session-network') { - dispatch(networkDataActions.refreshInfoFromSeshServer() as any); - } - dispatch(updateSessionNetworkModal({})); - break; - case 'session-pro': - dispatch(updateSessionProInfoModal({ variant: SessionProInfoVariant.GENERIC })); + break; case 'clear-data': dispatch(updateDeleteAccountModal({})); diff --git a/ts/components/qrview/QrView.tsx b/ts/components/qrview/QrView.tsx new file mode 100644 index 000000000..dbd1a2763 --- /dev/null +++ b/ts/components/qrview/QrView.tsx @@ -0,0 +1,40 @@ +import { useDispatch } from 'react-redux'; +import { useIconToImageURL } from '../../hooks/useIconToImageURL'; +import { updateLightBoxOptions } from '../../state/ducks/modalDialog'; +import { prepareQRCodeForLightBox } from '../../util/qrCodes'; +import { AvatarExitQrCodeButton } from '../buttons/AvatarExitQrCodeButton'; +import { QRCodeLogoProps, SessionQRCode } from '../SessionQRCode'; + +const qrLogoProps: QRCodeLogoProps = { + iconType: 'brandThin', + iconSize: 42, +}; + +export const QRView = ({ sessionID, onExit }: { sessionID: string; onExit: () => void }) => { + const dispatch = useDispatch(); + const { dataURL, iconSize, iconColor, backgroundColor, loading } = useIconToImageURL(qrLogoProps); + + return ( + { + const lightBoxOptions = prepareQRCodeForLightBox(fileName, dataUrl); + dispatch(updateLightBoxOptions(lightBoxOptions)); + }} + ariaLabel={'Account ID QR code'} + dataTestId={'your-qr-code'} + // we need this for overflow buttons to be visible (see UserProfileModal) + style={{ marginTop: '15px', position: 'relative' }} + > + + + ); +}; diff --git a/ts/components/settings/SessionSettings.tsx b/ts/components/settings/SessionSettings.tsx index 7a7f4d5f7..d8519f78d 100644 --- a/ts/components/settings/SessionSettings.tsx +++ b/ts/components/settings/SessionSettings.tsx @@ -2,7 +2,6 @@ import { useState } from 'react'; import styled from 'styled-components'; import { useDispatch } from 'react-redux'; -import useMount from 'react-use/lib/useMount'; import { SettingsHeader } from './SessionSettingsHeader'; import { SessionIconButton } from '../icon'; @@ -10,14 +9,11 @@ import { SessionIconButton } from '../icon'; import { SessionNotificationGroupSettings } from './SessionNotificationGroupSettings'; import { sessionPassword } from '../../state/ducks/modalDialog'; -import { sectionActions, SectionType } from '../../state/ducks/section'; import type { PasswordAction, SessionSettingCategory } from '../../types/ReduxTypes'; -import { getPasswordHash } from '../../util/storage'; import { SettingsCategoryAppearance } from './section/CategoryAppearance'; import { CategoryConversations } from './section/CategoryConversations'; import { SettingsCategoryHelp } from './section/CategoryHelp'; import { SettingsCategoryPermissions } from './section/CategoryPermissions'; -import { SettingsCategoryPrivacy } from './section/CategoryPrivacy'; import { SettingsCategoryRecoveryPassword } from './section/CategoryRecoveryPassword'; import { setDebugMode } from '../../state/ducks/debug'; import { showLinkVisitWarningDialog } from '../dialog/OpenUrlModal'; @@ -110,12 +106,8 @@ const SessionInfo = () => { ); }; -const SettingInCategory = (props: { - category: SessionSettingCategory; - onPasswordUpdated: (action: string) => void; - hasPassword: boolean; -}) => { - const { category, onPasswordUpdated, hasPassword } = props; +const SettingInCategory = (props: { category: SessionSettingCategory }) => { + const { category } = props; switch (category) { // special case for blocked user @@ -125,10 +117,7 @@ const SettingInCategory = (props: { return ; case 'notifications': return ; - case 'privacy': - return ( - - ); + case 'help': return ; case 'permissions': @@ -170,35 +159,13 @@ const StyledSettingsList = styled.div` export const SessionSettingsView = (props: SettingsViewProps) => { const { category } = props; - const dispatch = useDispatch(); - - const [hasPassword, setHasPassword] = useState(true); - useMount(() => { - const hash = getPasswordHash(); - setHasPassword(!!hash); - }); - - function onPasswordUpdated(action: string) { - if (action === 'set' || action === 'change') { - setHasPassword(true); - dispatch(sectionActions.showLeftPaneSection(SectionType.Message)); - } - - if (action === 'remove') { - setHasPassword(false); - } - } return ( - + diff --git a/ts/components/settings/SessionSettingsHeader.tsx b/ts/components/settings/SessionSettingsHeader.tsx index ef42b2036..e21d8f71c 100644 --- a/ts/components/settings/SessionSettingsHeader.tsx +++ b/ts/components/settings/SessionSettingsHeader.tsx @@ -41,9 +41,6 @@ export const SettingsHeader = (props: Props) => { case 'permissions': categoryTitleKey = 'sessionPermissions'; break; - case 'privacy': - categoryTitleKey = 'sessionPrivacy'; - break; case 'recovery-password': categoryTitleKey = 'sessionRecoveryPassword'; break; diff --git a/ts/components/settings/section/CategoryPermissions.tsx b/ts/components/settings/section/CategoryPermissions.tsx index ca1ed0c59..9737d266a 100644 --- a/ts/components/settings/section/CategoryPermissions.tsx +++ b/ts/components/settings/section/CategoryPermissions.tsx @@ -2,43 +2,11 @@ import useUpdate from 'react-use/lib/useUpdate'; import { SettingsKey } from '../../../data/settings-key'; -import { CallManager, ToastUtils } from '../../../session/utils'; -import { updateConfirmModal } from '../../../state/ducks/modalDialog'; -import { SessionButtonColor } from '../../basic/SessionButton'; +import { ToastUtils } from '../../../session/utils'; import { SessionToggleWithDescription } from '../SessionSettingListItem'; import { tr } from '../../../localization/localeTools'; -const toggleCallMediaPermissions = async (triggerUIUpdate: () => void) => { - const currentValue = window.getCallMediaPermissions(); - const onClose = () => window.inboxStore?.dispatch(updateConfirmModal(null)); - if (!currentValue) { - window.inboxStore?.dispatch( - updateConfirmModal({ - title: tr('callsVoiceAndVideoBeta'), - i18nMessage: { token: 'callsVoiceAndVideoModalDescription' }, - okTheme: SessionButtonColor.Danger, - okText: tr('theContinue'), - onClickOk: async () => { - await window.toggleCallMediaPermissionsTo(true); - triggerUIUpdate(); - CallManager.onTurnedOnCallMediaPermissions(); - onClose(); - }, - onClickCancel: async () => { - await window.toggleCallMediaPermissionsTo(false); - triggerUIUpdate(); - onClose(); - }, - onClickClose: onClose, - }) - ); - } else { - await window.toggleCallMediaPermissionsTo(false); - triggerUIUpdate(); - } -}; - async function toggleStartInTray() { try { const newValue = !(await window.getStartInTray()); @@ -60,26 +28,6 @@ export const SettingsCategoryPermissions = () => { return ( <> - { - await window.toggleMediaPermissions(); - forceUpdate(); - }} - title={tr('permissionsMicrophone')} - description={tr('permissionsMicrophoneDescription')} - active={Boolean(window.getSettingValue('media-permissions'))} - dataTestId="enable-microphone" - /> - { - await toggleCallMediaPermissions(forceUpdate); - forceUpdate(); - }} - title={tr('callsVoiceAndVideoBeta')} - description={tr('callsVoiceAndVideoToggleDescription')} - active={Boolean(window.getCallMediaPermissions())} - dataTestId="enable-calls" - /> { const old = Boolean(window.getSettingValue(SettingsKey.settingsAutoUpdate)); diff --git a/ts/components/settings/section/CategoryPrivacy.tsx b/ts/components/settings/section/CategoryPrivacy.tsx deleted file mode 100644 index 2ba30cb25..000000000 --- a/ts/components/settings/section/CategoryPrivacy.tsx +++ /dev/null @@ -1,149 +0,0 @@ -/* eslint-disable @typescript-eslint/no-misused-promises */ - -import useUpdate from 'react-use/lib/useUpdate'; -import { SettingsKey } from '../../../data/settings-key'; -import { updateConfirmModal } from '../../../state/ducks/modalDialog'; -import { SessionButtonColor } from '../../basic/SessionButton'; -import { SpacerLG } from '../../basic/Text'; -import { TypingBubble } from '../../conversation/TypingBubble'; - -import { UserUtils } from '../../../session/utils'; -import { SessionUtilUserProfile } from '../../../session/utils/libsession/libsession_utils_user_profile'; -import { - useWeHaveBlindedMsgRequestsEnabled, - useHasLinkPreviewEnabled, -} from '../../../state/selectors/settings'; -import { Storage } from '../../../util/storage'; -import { SessionSettingButtonItem, SessionToggleWithDescription } from '../SessionSettingListItem'; -import { displayPasswordModal } from '../SessionSettings'; -import { ConversationTypeEnum } from '../../../models/types'; -import { tr } from '../../../localization/localeTools'; - -async function toggleLinkPreviews(isToggleOn: boolean, forceUpdate: () => void) { - if (!isToggleOn) { - window.inboxStore?.dispatch( - updateConfirmModal({ - title: tr('linkPreviewsSend'), - i18nMessage: { token: 'linkPreviewsSendModalDescription' }, - okTheme: SessionButtonColor.Danger, - okText: tr('theContinue'), - onClickOk: async () => { - const newValue = !isToggleOn; - await window.setSettingValue(SettingsKey.settingsLinkPreview, newValue); - forceUpdate(); - }, - onClickClose: () => { - window.inboxStore?.dispatch(updateConfirmModal(null)); - }, - }) - ); - } else { - await window.setSettingValue(SettingsKey.settingsLinkPreview, false); - await Storage.put(SettingsKey.hasLinkPreviewPopupBeenDisplayed, false); - forceUpdate(); - } -} - -const TypingBubbleItem = () => { - return ( - <> - - - - ); -}; - -export const SettingsCategoryPrivacy = (props: { - hasPassword: boolean | null; - onPasswordUpdated: (action: string) => void; -}) => { - const forceUpdate = useUpdate(); - const isLinkPreviewsOn = useHasLinkPreviewEnabled(); - const weHaveBlindedRequestsEnabled = useWeHaveBlindedMsgRequestsEnabled(); - - return ( - <> - { - const old = Boolean(window.getSettingValue(SettingsKey.settingsReadReceipt)); - await window.setSettingValue(SettingsKey.settingsReadReceipt, !old); - forceUpdate(); - }} - title={tr('readReceipts')} - description={tr('readReceiptsDescription')} - active={window.getSettingValue(SettingsKey.settingsReadReceipt)} - dataTestId="enable-read-receipts" - /> - { - const old = Boolean(window.getSettingValue(SettingsKey.settingsTypingIndicator)); - await window.setSettingValue(SettingsKey.settingsTypingIndicator, !old); - forceUpdate(); - }} - title={tr('typingIndicators')} - description={tr('typingIndicatorsDescription')} - active={Boolean(window.getSettingValue(SettingsKey.settingsTypingIndicator))} - childrenDescription={} - /> - { - void toggleLinkPreviews(isLinkPreviewsOn, forceUpdate); - }} - title={tr('linkPreviewsSend')} - description={tr('linkPreviewsDescription')} - active={isLinkPreviewsOn} - /> - { - const toggledValue = !weHaveBlindedRequestsEnabled; - await window.setSettingValue(SettingsKey.hasBlindedMsgRequestsEnabled, toggledValue); - await SessionUtilUserProfile.insertUserProfileIntoWrapper( - UserUtils.getOurPubKeyStrFromCache() - ); - forceUpdate(); - }} - title={tr('messageRequestsCommunities')} - description={tr('messageRequestsCommunitiesDescription')} - active={weHaveBlindedRequestsEnabled} - /> - - {!props.hasPassword ? ( - { - displayPasswordModal('set', props.onPasswordUpdated); - forceUpdate(); - }} - buttonText={tr('passwordSet')} - dataTestId={'set-password-button'} - /> - ) : ( - <> - {/* We have a password, let's show the 'change' and 'remove' password buttons */} - { - displayPasswordModal('change', props.onPasswordUpdated); - forceUpdate(); - }} - buttonText={tr('passwordChange')} - dataTestId="change-password-settings-button" - /> - { - displayPasswordModal('remove', props.onPasswordUpdated); - forceUpdate(); - }} - buttonColor={SessionButtonColor.Danger} - buttonText={tr('passwordRemove')} - dataTestId="remove-password-settings-button" - /> - - )} - - ); -}; diff --git a/ts/components/settings/section/CategoryRecoveryPassword.tsx b/ts/components/settings/section/CategoryRecoveryPassword.tsx index 70dff355b..59c8ad005 100644 --- a/ts/components/settings/section/CategoryRecoveryPassword.tsx +++ b/ts/components/settings/section/CategoryRecoveryPassword.tsx @@ -8,6 +8,7 @@ import { mnDecode } from '../../../session/crypto/mnemonic'; import { updateHideRecoveryPasswordModal, updateLightBoxOptions, + userSettingsModal, } from '../../../state/ducks/modalDialog'; import { getIsModalVisible } from '../../../state/selectors/modal'; import { useHideRecoveryPasswordEnabled } from '../../../state/selectors/settings'; @@ -25,7 +26,6 @@ import { SessionSettingsItemWrapper, StyledSettingItem, } from '../SessionSettingListItem'; -import { sectionActions } from '../../../state/ducks/section'; import { tr } from '../../../localization/localeTools'; const StyledSettingsItemContainer = styled.div` @@ -81,7 +81,7 @@ export const SettingsCategoryRecoveryPassword = () => { const { hasPassword, passwordValid } = usePasswordModal({ onClose: () => { - dispatch(sectionActions.showSettingsSection('privacy')); + dispatch(userSettingsModal({ userSettingsPage: 'privacy' })); }, }); diff --git a/ts/localization/localeTools.ts b/ts/localization/localeTools.ts index 3ef9c18af..75f75faaa 100644 --- a/ts/localization/localeTools.ts +++ b/ts/localization/localeTools.ts @@ -137,6 +137,8 @@ export type GetMessageArgs = T extends MergedLo export type TrArgs = GetMessageArgs; +export type WithTrArgs = { tr: TrArgs }; + export function tStrippedWithObj(opts: GetMessageArgs): string { const builder = new LocalizedStringBuilder(opts.token as T, localeInUse).stripIt(); const args = messageArgsToArgsOnly(opts); diff --git a/ts/mains/main_renderer.tsx b/ts/mains/main_renderer.tsx index 66c12349a..deac14c00 100644 --- a/ts/mains/main_renderer.tsx +++ b/ts/mains/main_renderer.tsx @@ -331,7 +331,6 @@ async function start() { window.toggleMediaPermissions = async () => { const value = window.getMediaPermissions(); - if (value === true) { const valueCallPermissions = window.getCallMediaPermissions(); if (valueCallPermissions) { diff --git a/ts/react.d.ts b/ts/react.d.ts index a6754bfee..18da408ff 100644 --- a/ts/react.d.ts +++ b/ts/react.d.ts @@ -81,6 +81,16 @@ declare module 'react' { // left pane section types type Sections = 'theme' | 'settings' | 'message' | 'privacy' | 'debug-menu'; + export type SettingsToggles = + | 'enable-calls' + | 'enable-microphone' + | 'enable-communities-message-requests' + | 'enable-read-receipts' + | 'enable-typing-indicators' + | 'enable-link-previews'; + + type SettingsInlineButtons = 'set-password' | 'change-password' | 'remove-password'; + type SettingsMenuItems = | 'message-requests' | 'recovery-password' @@ -219,6 +229,7 @@ declare module 'react' { | 'modal-actions-container' | 'reveal-blocked-user-settings' | `${Sections}-section` + | `${SettingsToggles | SettingsInlineButtons}-settings-${'text' | 'sub-text' | 'toggle' | 'button' | 'row'}` // Buttons | `${Buttons}-button` @@ -259,9 +270,6 @@ declare module 'react' { | 'call-notification-answered-a-call' // settings toggle and buttons - | 'enable-read-receipts' - | 'enable-calls' - | 'enable-microphone' | 'enable-follow-system-theme' | 'unblock-button-settings-screen' | 'save-attachment-from-details' diff --git a/ts/state/ducks/modalDialog.tsx b/ts/state/ducks/modalDialog.tsx index 08b03a3c7..1248b1f69 100644 --- a/ts/state/ducks/modalDialog.tsx +++ b/ts/state/ducks/modalDialog.tsx @@ -12,6 +12,20 @@ import type { TrArgs } from '../../localization/localeTools'; export type BanType = 'ban' | 'unban'; +export type UserSettingsPage = + | 'default' + | 'privacy' + | 'notifications' + | 'conversations' + | 'message-requests' + | 'appearance' + | 'recovery-password' + | 'help' + | 'clear-data' + | 'preferences'; + +export type WithUserSettingsPage = { userSettingsPage: UserSettingsPage }; + export type ConfirmModalState = SessionConfirmDialogProps | null; export type InviteContactModalState = WithConvoId | null; @@ -26,7 +40,7 @@ export type RemoveModeratorsModalState = InviteContactModalState; export type UpdateGroupMembersModalState = InviteContactModalState; type UpdateConversationDetailsModalState = WithConvoId | null; export type ChangeNickNameModalState = InviteContactModalState; -export type UserSettingsModalState = object | null; +export type UserSettingsModalState = WithUserSettingsPage | null; export type OnionPathModalState = object | null; export type EnterPasswordModalState = EnterPasswordModalProps | null; export type DeleteAccountModalState = object | null; @@ -117,7 +131,7 @@ export const initialModalState: ModalState = { groupMembersModal: null, userProfileModal: null, nickNameModal: null, - userSettingsModal: null, + userSettingsModal: { userSettingsPage: 'privacy' }, onionPathModal: null, enterPasswordModal: null, sessionPasswordModal: null, diff --git a/ts/state/ducks/section.tsx b/ts/state/ducks/section.tsx index 7030d1fc0..605441197 100644 --- a/ts/state/ducks/section.tsx +++ b/ts/state/ducks/section.tsx @@ -7,8 +7,7 @@ export enum SectionType { Profile, Message, Settings, - ColorMode, - PathIndicator, + ThemeSwitch, DebugMenu, } @@ -49,11 +48,11 @@ const sectionSlice = createSlice({ reducers: { showLeftPaneSection(state, action: PayloadAction) { if (action.payload === SectionType.Settings) { - // on click on the gear icon: show the 'privacy' tab by default + // on click on the gear icon: show the 'appearance' tab by default return { ...state, focusedSection: action.payload, - focusedSettingsSection: 'privacy', + focusedSettingsSection: 'appearance', }; } return { diff --git a/ts/state/ducks/user.ts b/ts/state/ducks/user.ts index 842ce9522..5d4731d40 100644 --- a/ts/state/ducks/user.ts +++ b/ts/state/ducks/user.ts @@ -44,7 +44,7 @@ const updateOurAvatar = createAsyncThunk( }); window.inboxStore?.dispatch(updateEditProfilePictureModal(null)); - window.inboxStore?.dispatch(userSettingsModal({})); + window.inboxStore?.dispatch(userSettingsModal({ userSettingsPage: 'default' })); return res; } diff --git a/ts/types/ReduxTypes.d.ts b/ts/types/ReduxTypes.d.ts index 4752cba07..c0a66c139 100644 --- a/ts/types/ReduxTypes.d.ts +++ b/ts/types/ReduxTypes.d.ts @@ -6,7 +6,6 @@ */ export type SessionSettingCategory = - | 'privacy' | 'donate' | 'session-pro' | 'notifications' From 10758833a994dc1c7419043f0edcb7683c92004f Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Fri, 15 Aug 2025 09:32:29 +1000 Subject: [PATCH 03/18] feat: added user notification settings page --- ts/components/SessionWrapperModal.tsx | 60 +++-- ts/components/buttons/PanelButton.tsx | 43 +++- .../right-panel/overlay/components/Header.tsx | 11 - .../right-panel/overlay/components/index.tsx | 4 +- .../pages/default/defaultPage.tsx | 4 +- .../DisappearingMessagesPage.tsx | 13 +- .../DisappearingModes.tsx | 17 +- .../disappearing-messages/TimeOptions.tsx | 10 +- .../user-settings/UserSettingsDialog.tsx | 3 + .../components/SettingsToggleBasic.tsx | 36 +++ .../pages/DefaultSettingsPage.tsx | 13 +- .../pages/NotificationsSettingsPage.tsx | 205 ++++++++++++++++++ .../pages/PrivacySettingsPage.tsx | 49 +---- .../user-settings/pages/userSettingsHooks.tsx | 9 +- ts/components/leftpane/ActionsPanel.tsx | 4 +- .../leftpane/LeftPaneSettingSection.tsx | 20 -- .../SessionNotificationGroupSettings.tsx | 120 ---------- ts/components/settings/SessionSettings.tsx | 4 - .../settings/SessionSettingsHeader.tsx | 5 - ts/react.d.ts | 8 +- ts/types/ReduxTypes.d.ts | 3 - 21 files changed, 386 insertions(+), 255 deletions(-) create mode 100644 ts/components/dialog/user-settings/components/SettingsToggleBasic.tsx create mode 100644 ts/components/dialog/user-settings/pages/NotificationsSettingsPage.tsx delete mode 100644 ts/components/settings/SessionNotificationGroupSettings.tsx diff --git a/ts/components/SessionWrapperModal.tsx b/ts/components/SessionWrapperModal.tsx index d14cd6424..eecd366d6 100644 --- a/ts/components/SessionWrapperModal.tsx +++ b/ts/components/SessionWrapperModal.tsx @@ -234,17 +234,31 @@ export type SessionWrapperModalType = { style?: Omit; }; -function ExtraSpacerLeft({ - extraRightButton, +const useNeedsSpacerOnSide = ({ extraLeftButton, + extraRightButton, showExitIcon, -}: WithShowExitIcon & WithExtraRightButton & WithExtraLeftButton) { - // if we have two button on the right, and one on the left, we need to add one spacer - if (extraRightButton && showExitIcon && extraLeftButton) { +}: WithShowExitIcon & WithExtraRightButton & WithExtraLeftButton) => { + const buttonsLeft = extraLeftButton ? 1 : 0; + const buttonsRight = (extraRightButton ? 1 : 0) + (showExitIcon ? 1 : 0); + const extraButtonsOnRightSide = buttonsRight - buttonsLeft; + + return { + count: Math.abs(extraButtonsOnRightSide), + side: extraButtonsOnRightSide === 0 ? 'none' : extraButtonsOnRightSide > 0 ? 'left' : 'right', + }; +}; + +function ExtraSpacerLeft(props: WithShowExitIcon & WithExtraRightButton & WithExtraLeftButton) { + const extraOn = useNeedsSpacerOnSide(props); + + if (extraOn.side !== 'left' || extraOn.count === 0) { + return null; + } + if (extraOn.count === 1) { return ; } - if (extraRightButton && showExitIcon) { - // if we have two button on the right, and none on the left, we need to add two spacers + if (extraOn.count === 2) { return ( <> @@ -252,16 +266,28 @@ function ExtraSpacerLeft({ ); } - // starting here, showExitIcon is false. + throw new Error('ExtraSpacerLeft: not handled case for extraOn.count'); +} - if (extraRightButton && extraLeftButton) { - // if we have one button on each sides, no need for a spacer, +function ExtraSpacerRight(props: WithShowExitIcon & WithExtraRightButton & WithExtraLeftButton) { + const extraOn = useNeedsSpacerOnSide(props); + + if (extraOn.side !== 'right' || extraOn.count === 0) { return null; } - // otherwise we need one spacer - return ; + if (extraOn.count === 1) { + return ; + } + if (extraOn.count === 2) { + return ( + <> + + + + ); + } + throw new Error('ExtraSpacerRight: not handled case for extraOn.count'); } - /** * A basic modal header with a title, an optional left button and/or exit icon. * To be used as `headerChildren` prop as part of SessionWrapperModal. @@ -304,7 +330,7 @@ export const ModalBasicHeader = ({ padding={'0'} margin={'0'} > - {/* Note: add a spacer if no left button is set but we have an exit icon */} + {/* Note: this is just here to keep the title centered, no matter the buttons we have */} + {/* Note: this is just here to keep the title centered, no matter the buttons we have */} + {extraRightButton} {showExitIcon ? ( ` @@ -18,17 +18,42 @@ export const StyledContent = styled.div<{ disabled: boolean }>` const StyledPanelLabel = styled.p` color: var(--text-secondary-color); - width: 100%; margin: 0; - padding-left: var(--margins-lg); + align-self: flex-start; + padding-inline: var(--margins-lg); +`; + +const StyledPanelDescription = styled(StyledPanelLabel)` + color: var(--text-primary-color); +`; + +const StyledPanelLabelWithDescription = styled.div` + align-self: flex-start; + display: flex; + flex-direction: column; + gap: var(--margins-xs); padding-block: var(--margins-sm); `; -export function PanelLabel({ tr }: WithTrArgs) { +export function PanelLabelWithDescription({ + title, + description, +}: { + title: TrArgs; + description?: TrArgs; +}) { return ( - - - + + {/* less space between the label and the description */} + + + + {description ? ( + + + + ) : null} + ); } @@ -172,7 +197,9 @@ function TextOnly(props: PanelButtonTextBaseProps) { data-testid={props.textDataTestId} fontWeight={500} style={{ - whiteSpace: 'nowrap', + // We need this to wrap so we don't cut long titles in the + // user settings page, even if it means having multiple lines + whiteSpace: 'wrap', overflow: 'hidden', textOverflow: 'ellipsis', width: '100%', diff --git a/ts/components/conversation/right-panel/overlay/components/Header.tsx b/ts/components/conversation/right-panel/overlay/components/Header.tsx index 6e44945fe..d0b6c596a 100644 --- a/ts/components/conversation/right-panel/overlay/components/Header.tsx +++ b/ts/components/conversation/right-panel/overlay/components/Header.tsx @@ -16,17 +16,6 @@ export const HeaderTitle = styled.h2` word-break: break-word; `; -export const HeaderSubtitle = styled.h3` - font-family: var(--font-default); - font-size: var(--font-size-sm); - font-weight: 400; - text-align: center; - padding-top: 0px; - margin-top: 0; - // limit the width of the subtitle to have a nicer look (and not one long line) - max-width: 50ch; -`; - type HeaderProps = ( | { hideCloseButton: false; diff --git a/ts/components/conversation/right-panel/overlay/components/index.tsx b/ts/components/conversation/right-panel/overlay/components/index.tsx index 970fd27ed..2e522d9d3 100644 --- a/ts/components/conversation/right-panel/overlay/components/index.tsx +++ b/ts/components/conversation/right-panel/overlay/components/index.tsx @@ -1,4 +1,4 @@ import { StyledScrollContainer } from './Containers'; -import { Header, HeaderSubtitle, HeaderTitle } from './Header'; +import { Header, HeaderTitle } from './Header'; -export { Header, HeaderSubtitle, HeaderTitle, StyledScrollContainer }; +export { Header, HeaderTitle, StyledScrollContainer }; diff --git a/ts/components/dialog/conversationSettings/pages/default/defaultPage.tsx b/ts/components/dialog/conversationSettings/pages/default/defaultPage.tsx index a09b73c55..8cdbb9fd0 100644 --- a/ts/components/dialog/conversationSettings/pages/default/defaultPage.tsx +++ b/ts/components/dialog/conversationSettings/pages/default/defaultPage.tsx @@ -10,7 +10,7 @@ import { Flex } from '../../../../basic/Flex'; import { useWeAreCommunityAdminOrModerator } from '../../../../../state/selectors/conversations'; import { SpacerSM } from '../../../../basic/Text'; import { PanelButtonGroup } from '../../../../buttons'; -import { PanelLabel } from '../../../../buttons/PanelButton'; +import { PanelLabelWithDescription } from '../../../../buttons/PanelButton'; import { useShowAttachments } from '../../../../menuAndSettingsHooks/useShowAttachments'; import { ModalBasicHeader, SessionWrapperModal } from '../../../../SessionWrapperModal'; import { ConversationSettingsHeader } from '../../conversationSettingsHeader'; @@ -46,7 +46,7 @@ import { useChangeNickname } from '../../../../menuAndSettingsHooks/useChangeNic import { useShowUpdateGroupOrCommunityDetailsCb } from '../../../../menuAndSettingsHooks/useShowUpdateGroupNameDescription'; function AdminSettingsTitle() { - return ; + return ; } function GroupV2AdminActions({ conversationId }: WithConvoId) { diff --git a/ts/components/dialog/conversationSettings/pages/disappearing-messages/DisappearingMessagesPage.tsx b/ts/components/dialog/conversationSettings/pages/disappearing-messages/DisappearingMessagesPage.tsx index 3e3d1cc98..06ed282b8 100644 --- a/ts/components/dialog/conversationSettings/pages/disappearing-messages/DisappearingMessagesPage.tsx +++ b/ts/components/dialog/conversationSettings/pages/disappearing-messages/DisappearingMessagesPage.tsx @@ -15,10 +15,7 @@ import { } from '../../../../../state/selectors/selectedConversation'; import { Flex } from '../../../../basic/Flex'; import { SpacerLG, SpacerMD } from '../../../../basic/Text'; -import { - HeaderSubtitle, - StyledScrollContainer, -} from '../../../../conversation/right-panel/overlay/components'; +import { StyledScrollContainer } from '../../../../conversation/right-panel/overlay/components'; import { DisappearingModes } from './DisappearingModes'; import { TimeOptions } from './TimeOptions'; import { useConversationSettingsModalIsStandalone } from '../../../../../state/selectors/modal'; @@ -201,18 +198,12 @@ export const DisappearingMessagesForConversationModal = (props: ConversationSett > - - {singleMode === 'deleteAfterRead' - ? tr('disappearingMessagesDisappearAfterReadDescription') - : singleMode === 'deleteAfterSend' - ? tr('disappearingMessagesDisappearAfterSendDescription') - : tr('disappearingMessagesDescription1')} - {(hasOnlyOneMode || modeSelected !== 'off') && ( <> diff --git a/ts/components/dialog/conversationSettings/pages/disappearing-messages/DisappearingModes.tsx b/ts/components/dialog/conversationSettings/pages/disappearing-messages/DisappearingModes.tsx index 351c5f490..2f9f8a950 100644 --- a/ts/components/dialog/conversationSettings/pages/disappearing-messages/DisappearingModes.tsx +++ b/ts/components/dialog/conversationSettings/pages/disappearing-messages/DisappearingModes.tsx @@ -4,7 +4,7 @@ import { PanelButtonGroup, PanelButtonText, PanelButtonTextWithSubText, - PanelLabel, + PanelLabelWithDescription, } from '../../../../buttons/PanelButton'; import { PanelRadioButton } from '../../../../buttons/PanelRadioButton'; @@ -25,10 +25,11 @@ type DisappearingModesProps = { selected?: DisappearingMessageConversationModeType; setSelected: (value: DisappearingMessageConversationModeType) => void; hasOnlyOneMode?: boolean; + singleMode?: DisappearingMessageConversationModeType; }; export const DisappearingModes = (props: DisappearingModesProps) => { - const { options, selected, setSelected, hasOnlyOneMode } = props; + const { options, selected, setSelected, hasOnlyOneMode, singleMode } = props; if (hasOnlyOneMode) { return null; @@ -36,7 +37,17 @@ export const DisappearingModes = (props: DisappearingModesProps) => { return ( <> - + {Object.keys(options).map(_mode => { const mode = _mode as DisappearingMessageConversationModeType; diff --git a/ts/components/dialog/conversationSettings/pages/disappearing-messages/TimeOptions.tsx b/ts/components/dialog/conversationSettings/pages/disappearing-messages/TimeOptions.tsx index 81a11183a..cba831aaf 100644 --- a/ts/components/dialog/conversationSettings/pages/disappearing-messages/TimeOptions.tsx +++ b/ts/components/dialog/conversationSettings/pages/disappearing-messages/TimeOptions.tsx @@ -5,7 +5,11 @@ import { TimerOptionsArray, TimerSeconds, } from '../../../../../session/disappearing_messages/timerOptions'; -import { PanelButtonGroup, PanelButtonText, PanelLabel } from '../../../../buttons/PanelButton'; +import { + PanelButtonGroup, + PanelButtonText, + PanelLabelWithDescription, +} from '../../../../buttons/PanelButton'; import { PanelRadioButton } from '../../../../buttons/PanelRadioButton'; import { assertUnreachable } from '../../../../../types/sqlSharedTypes'; @@ -76,7 +80,9 @@ export const TimeOptions = (props: TimerOptionsProps) => { return ( <> - {!hasOnlyOneMode && } + {!hasOnlyOneMode && ( + + )} {options.map(option => { // we want "time-option-1-hours", etc as accessibility id diff --git a/ts/components/dialog/user-settings/UserSettingsDialog.tsx b/ts/components/dialog/user-settings/UserSettingsDialog.tsx index 618a75057..da154896b 100644 --- a/ts/components/dialog/user-settings/UserSettingsDialog.tsx +++ b/ts/components/dialog/user-settings/UserSettingsDialog.tsx @@ -1,5 +1,6 @@ import { type UserSettingsModalState } from '../../../state/ducks/modalDialog'; import { DefaultSettingPage } from './pages/DefaultSettingsPage'; +import { NotificationsSettingsPage } from './pages/NotificationsSettingsPage'; import { PrivacySettingsPage } from './pages/PrivacySettingsPage'; export const UserSettingsDialog = (modalState: UserSettingsModalState) => { @@ -12,6 +13,8 @@ export const UserSettingsDialog = (modalState: UserSettingsModalState) => { return ; case 'privacy': return ; + case 'notifications': + return ; default: return ; } diff --git a/ts/components/dialog/user-settings/components/SettingsToggleBasic.tsx b/ts/components/dialog/user-settings/components/SettingsToggleBasic.tsx new file mode 100644 index 000000000..dbfff9fb3 --- /dev/null +++ b/ts/components/dialog/user-settings/components/SettingsToggleBasic.tsx @@ -0,0 +1,36 @@ +import type { SettingsToggles } from 'react'; +import type { TokenSimpleNoArgs } from '../../../../localization/locales'; +import { PanelButtonTextWithSubText } from '../../../buttons/PanelButton'; +import { PanelToggleButton } from '../../../buttons/PanelToggleButton'; +import { tr } from '../../../../localization/localeTools'; + +export function SettingsToggleBasic({ + active, + baseDataTestId, + onClick, + textToken, + subTextToken, +}: { + textToken: TokenSimpleNoArgs; + subTextToken: TokenSimpleNoArgs; + baseDataTestId: SettingsToggles; + active: boolean; + onClick: () => Promise; +}) { + return ( + + } + active={active} + onClick={onClick} + toggleDataTestId={`${baseDataTestId}-settings-toggle`} + rowDataTestId={`${baseDataTestId}-settings-row`} + /> + ); +} diff --git a/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx b/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx index 0f71ac734..19588679f 100644 --- a/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx @@ -14,7 +14,7 @@ import { userSettingsModal, } from '../../../../state/ducks/modalDialog'; import { networkDataActions } from '../../../../state/ducks/networkData'; -import { sectionActions, SectionType } from '../../../../state/ducks/section'; +import { sectionActions } from '../../../../state/ducks/section'; import { AccountIdPill } from '../../../basic/AccountIdPill'; import { Flex } from '../../../basic/Flex'; import { SessionIDNotEditable } from '../../../basic/SessionIdNotEditable'; @@ -32,6 +32,7 @@ import { ModalPencilIcon } from '../../shared/ModalPencilButton'; import { ProfileHeader, ProfileName } from '../components'; import type { ProfileDialogModes } from '../ProfileDialogModes'; import { tr } from '../../../../localization/localeTools'; +import { useIsProAvailable } from '../../../../hooks/useIsProAvailable'; const handleKeyQRMode = (mode: ProfileDialogModes, setMode: (mode: ProfileDialogModes) => void) => { switch (mode) { @@ -87,6 +88,12 @@ const StyledUserSettingsDialog = styled.div``; function SessionProSection() { const dispatch = useDispatch(); + + const isProAvailable = useIsProAvailable(); + + if (!isProAvailable) { + return null; + } return ( } text={tr('sessionNotifications')} onClick={() => { - throw new Error('Not implemented'); + dispatch(userSettingsModal({ userSettingsPage: 'notifications' })); }} dataTestId="notifications-settings-menu-item" /> @@ -188,8 +195,8 @@ function SettingsSection() { } text={tr('sessionMessageRequests')} onClick={() => { - dispatch(sectionActions.showLeftPaneSection(SectionType.Message)); dispatch(sectionActions.setLeftOverlayMode('message-requests')); + dispatch(userSettingsModal(null)); dispatch(resetConversationExternal()); }} dataTestId="message-requests-settings-menu-item" diff --git a/ts/components/dialog/user-settings/pages/NotificationsSettingsPage.tsx b/ts/components/dialog/user-settings/pages/NotificationsSettingsPage.tsx new file mode 100644 index 000000000..1e60bd4c1 --- /dev/null +++ b/ts/components/dialog/user-settings/pages/NotificationsSettingsPage.tsx @@ -0,0 +1,205 @@ +import styled from 'styled-components'; +import useUpdate from 'react-use/lib/useUpdate'; +import { useState } from 'react'; + +import { tr } from '../../../../localization/localeTools'; +import { type UserSettingsModalState } from '../../../../state/ducks/modalDialog'; +import { + PanelButtonGroup, + PanelButtonTextWithSubText, + PanelLabelWithDescription, +} from '../../../buttons/PanelButton'; +import { + ModalBasicHeader, + SessionWrapperModal, + WrapperModalWidth, +} from '../../../SessionWrapperModal'; +import { ModalBackButton } from '../../shared/ModalBackButton'; +import { + useUserSettingsBackAction, + useUserSettingsCloseAction, + useUserSettingsTitle, +} from './userSettingsHooks'; +import { SettingsKey } from '../../../../data/settings-key'; +import { SettingsToggleBasic } from '../components/SettingsToggleBasic'; +import { Notifications } from '../../../../util/notifications'; +import { isAudioNotificationSupported } from '../../../../types/Settings'; +import { SpacerLG } from '../../../basic/Text'; +import { SessionButton, SessionButtonColor } from '../../../basic/SessionButton'; +import { PanelRadioButton } from '../../../buttons/PanelRadioButton'; + +const NotificationType = { message: 'message', name: 'name', count: 'count', off: 'off' } as const; + +const StyledButtonContainer = styled.div` + display: flex; + width: min-content; + flex-direction: column; + padding-inline-start: var(--margins-lg); +`; + +function NotificationsContent({ + notificationsAreEnabled, + initialNotificationEnabled, +}: { + notificationsAreEnabled: boolean; + initialNotificationEnabled: (typeof NotificationType)[keyof typeof NotificationType]; +}) { + const forceUpdate = useUpdate(); + + const initialAudioNotificationEnabled = + window.getSettingValue(SettingsKey.settingsAudioNotification) || false; + + const options = [ + { + text: tr('notificationsContentShowNameAndContent'), + subText: tr('notificationSenderNameAndPreview'), + value: NotificationType.message, + }, + { + text: tr('notificationsContentShowNameOnly'), + subText: tr('notificationSenderNameOnly'), + value: NotificationType.name, + }, + { + text: tr('notificationsContentShowNoNameOrContent'), + subText: tr('notificationsGenericOnly'), + value: NotificationType.count, + }, + ] as const; + + const items = options.map(m => ({ + text: m.text, + subText: m.subText, + value: m.value, + })); + + const onClickPreview = () => { + if (!notificationsAreEnabled) { + return; + } + Notifications.addPreviewNotification({ + conversationId: `preview-notification-${Date.now()}`, + message: items.find(m => m.value === initialNotificationEnabled)?.text || 'Message body', + title: tr('preview'), + isExpiringMessage: false, + }); + }; + + const [selected, setSelected] = useState(initialNotificationEnabled); + + if (!notificationsAreEnabled) { + return null; + } + return ( + <> + {isAudioNotificationSupported() && ( + <> + + + { + await window.setSettingValue( + SettingsKey.settingsAudioNotification, + !initialAudioNotificationEnabled + ); + forceUpdate(); + }} + textToken="notificationsSoundDesktop" + subTextToken="notificationsMakeSound" + /> + + + )} + + + + {items.map(({ value, text, subText }) => { + return ( + + } + value={value} + isSelected={selected === value} + // eslint-disable-next-line @typescript-eslint/no-misused-promises + onSelect={async () => { + await window.setSettingValue(SettingsKey.settingsNotification, value); + setSelected(value); + forceUpdate(); + }} + rowDataTestId={`set-notifications-${value}-settings-row`} + radioInputDataTestId={`set-notifications-${value}-settings-radio`} + /> + ); + })} + + + + + + + ); +} + +export function NotificationsSettingsPage(modalState: UserSettingsModalState) { + const backAction = useUserSettingsBackAction(modalState); + const closeAction = useUserSettingsCloseAction(modalState); + const title = useUserSettingsTitle(modalState); + const initialNotificationEnabled = + window.getSettingValue(SettingsKey.settingsNotification) || NotificationType.message; + const notificationsAreEnabled = + initialNotificationEnabled && initialNotificationEnabled !== NotificationType.off; + const forceUpdate = useUpdate(); + + return ( + : undefined} + /> + } + onClose={closeAction || undefined} + shouldOverflow={true} + allowOutsideClick={false} + $contentMinWidth={WrapperModalWidth.normal} + > + + + { + await window.setSettingValue( + SettingsKey.settingsNotification, + notificationsAreEnabled ? 'off' : 'message' + ); + forceUpdate(); + }} + textToken="enableNotifications" + subTextToken="notificationsMakeSound" + /> + + + + ); +} diff --git a/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx b/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx index 9410eca70..b7d79d1aa 100644 --- a/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx @@ -1,4 +1,4 @@ -import { useState, type SettingsToggles } from 'react'; +import { useState } from 'react'; import useMount from 'react-use/lib/useMount'; import useUpdate from 'react-use/lib/useUpdate'; import { tr } from '../../../../localization/localeTools'; @@ -9,7 +9,7 @@ import { import { PanelButtonGroup, PanelButtonTextWithSubText, - PanelLabel, + PanelLabelWithDescription, } from '../../../buttons/PanelButton'; import { PanelToggleButton } from '../../../buttons/PanelToggleButton'; import { @@ -31,11 +31,11 @@ import { } from '../../../../state/selectors/settings'; import { SettingsKey } from '../../../../data/settings-key'; import { SessionUtilUserProfile } from '../../../../session/utils/libsession/libsession_utils_user_profile'; -import type { TokenSimpleNoArgs } from '../../../../localization/locales'; import { getPasswordHash, Storage } from '../../../../util/storage'; import { SpacerXS } from '../../../basic/Text'; import { PanelWithButtonInline } from '../../../buttons/PanelWithButtonInline'; import { displayPasswordModal } from '../../../settings/SessionSettings'; +import { SettingsToggleBasic } from '../components/SettingsToggleBasic'; type WithPasswordUpdatedCb = { onPasswordUpdated: (action: string) => void }; @@ -94,37 +94,6 @@ async function toggleLinkPreviews(isToggleOn: boolean, forceUpdate: () => void) } } -function SettingsToggleBasic({ - active, - baseDataTestId, - onClick, - textToken, - subTextToken, -}: { - textToken: TokenSimpleNoArgs; - subTextToken: TokenSimpleNoArgs; - baseDataTestId: SettingsToggles; - active: boolean; - onClick: () => Promise; -}) { - return ( - - } - active={active} - onClick={onClick} - toggleDataTestId={`${baseDataTestId}-settings-toggle`} - rowDataTestId={`${baseDataTestId}-settings-row`} - /> - ); -} - /** * This is a static version of the TypingBubble component, but is only used here, hence why it's not a SessionIcon. */ @@ -249,7 +218,7 @@ export function PrivacySettingsPage(modalState: UserSettingsModalState) { allowOutsideClick={false} $contentMinWidth={WrapperModalWidth.normal} > - + - + - + - + {' '} - + - + ); diff --git a/ts/components/dialog/user-settings/pages/userSettingsHooks.tsx b/ts/components/dialog/user-settings/pages/userSettingsHooks.tsx index 39f2c3174..0eb20622d 100644 --- a/ts/components/dialog/user-settings/pages/userSettingsHooks.tsx +++ b/ts/components/dialog/user-settings/pages/userSettingsHooks.tsx @@ -64,14 +64,17 @@ export function useUserSettingsCloseAction(props: UserSettingsModalState) { } export function useUserSettingsBackAction(modalState: UserSettingsModalState) { + const dispatch = useDispatch(); if (!modalState?.userSettingsPage || modalState?.userSettingsPage === 'default') { // no back button if we are on the default page return undefined; } return () => { - userSettingsModal({ - userSettingsPage: 'default', - }); + dispatch( + userSettingsModal({ + userSettingsPage: 'default', + }) + ); }; } diff --git a/ts/components/leftpane/ActionsPanel.tsx b/ts/components/leftpane/ActionsPanel.tsx index f52af0d1a..4f53a1d9d 100644 --- a/ts/components/leftpane/ActionsPanel.tsx +++ b/ts/components/leftpane/ActionsPanel.tsx @@ -66,6 +66,7 @@ import { GearAvatarButton } from '../buttons/GearAvatarButton'; const StyledContainerAvatar = styled.div` padding: var(--margins-lg); position: relative; + cursor: pointer; `; function handleThemeSwitch() { @@ -129,10 +130,9 @@ const Section = (props: { type: SectionType }) => { if (type === SectionType.Profile) { return ( - + = ( [ - { - id: 'session-pro', - title: LOCALE_DEFAULTS.app_pro, - titleColor: 'var(--renderer-span-primary-color)', - icon: { type: 'custom', content: 'sessionPro', color: 'var(--renderer-span-primary-color)' }, - }, - - { - id: 'notifications', - title: tr('sessionNotifications'), - icon: { type: 'lucide', unicode: LUCIDE_ICONS_UNICODE.VOLUME_2 }, - }, { id: 'conversations', title: tr('sessionConversations'), @@ -134,12 +120,6 @@ const LeftPaneSettingsCategoryRow = ({ item }: { item: Categories }) => { const iconSize = 'medium'; - const isProAvailable = useIsProAvailable(); - - if (id === 'session-pro' && !isProAvailable) { - return null; - } - return ( { - const forceUpdate = useUpdate(); - - const initialNotificationEnabled = - window.getSettingValue(SettingsKey.settingsNotification) || NotificationType.message; - - const initialAudioNotificationEnabled = - window.getSettingValue(SettingsKey.settingsAudioNotification) || false; - - const notificationsAreEnabled = - initialNotificationEnabled && initialNotificationEnabled !== NotificationType.off; - - const options = [ - { - label: tr('notificationsContentShowNameAndContent'), - value: NotificationType.message, - }, - { label: tr('notificationsContentShowNameOnly'), value: NotificationType.name }, - { - label: tr('notificationsContentShowNoNameOrContent'), - value: NotificationType.count, - }, - ] as const; - - const items: SessionRadioItems = options.map(m => ({ - label: m.label, - value: m.value, - inputDataTestId: `input-${m.value}`, - labelDataTestId: `label-${m.value}`, - })); - - const onClickPreview = () => { - if (!notificationsAreEnabled) { - return; - } - Notifications.addPreviewNotification({ - conversationId: `preview-notification-${Date.now()}`, - message: items.find(m => m.value === initialNotificationEnabled)?.label || 'Message body', - title: tr('preview'), - isExpiringMessage: false, - }); - }; - - return ( - <> - { - await window.setSettingValue( - SettingsKey.settingsNotification, - notificationsAreEnabled ? 'off' : 'message' - ); - forceUpdate(); - }} - title={tr('sessionNotifications')} - active={notificationsAreEnabled} - /> - {notificationsAreEnabled && isAudioNotificationSupported() && ( - { - await window.setSettingValue( - SettingsKey.settingsAudioNotification, - !initialAudioNotificationEnabled - ); - forceUpdate(); - }} - title={tr('notificationsSoundDesktop')} - active={initialAudioNotificationEnabled} - /> - )} - {notificationsAreEnabled ? ( - - { - await window.setSettingValue(SettingsKey.settingsNotification, selectedRadioValue); - forceUpdate(); - }} - style={{ maxWidth: '400px' }} - /> - - - - - - ) : null} - - ); -}; diff --git a/ts/components/settings/SessionSettings.tsx b/ts/components/settings/SessionSettings.tsx index d8519f78d..71927eb8c 100644 --- a/ts/components/settings/SessionSettings.tsx +++ b/ts/components/settings/SessionSettings.tsx @@ -6,8 +6,6 @@ import { SettingsHeader } from './SessionSettingsHeader'; import { SessionIconButton } from '../icon'; -import { SessionNotificationGroupSettings } from './SessionNotificationGroupSettings'; - import { sessionPassword } from '../../state/ducks/modalDialog'; import type { PasswordAction, SessionSettingCategory } from '../../types/ReduxTypes'; import { SettingsCategoryAppearance } from './section/CategoryAppearance'; @@ -115,8 +113,6 @@ const SettingInCategory = (props: { category: SessionSettingCategory }) => { return ; case 'appearance': return ; - case 'notifications': - return ; case 'help': return ; diff --git a/ts/components/settings/SessionSettingsHeader.tsx b/ts/components/settings/SessionSettingsHeader.tsx index e21d8f71c..b498b7a3e 100644 --- a/ts/components/settings/SessionSettingsHeader.tsx +++ b/ts/components/settings/SessionSettingsHeader.tsx @@ -32,9 +32,6 @@ export const SettingsHeader = (props: Props) => { case 'conversations': categoryTitleKey = 'sessionConversations'; break; - case 'notifications': - categoryTitleKey = 'sessionNotifications'; - break; case 'help': categoryTitleKey = 'sessionHelp'; break; @@ -46,8 +43,6 @@ export const SettingsHeader = (props: Props) => { break; // these are modals or other screens case 'session-network': - case 'session-pro': - case 'donate': case 'clear-data': case 'message-requests': throw new Error(`no header for should be tried to be rendered for "${category}"`); diff --git a/ts/react.d.ts b/ts/react.d.ts index 18da408ff..3a0067da1 100644 --- a/ts/react.d.ts +++ b/ts/react.d.ts @@ -87,7 +87,11 @@ declare module 'react' { | 'enable-communities-message-requests' | 'enable-read-receipts' | 'enable-typing-indicators' - | 'enable-link-previews'; + | 'enable-link-previews' + | 'notifications' + | 'audio-notifications'; + + type SettingsRadio = `set-notifications-${'message' | 'name' | 'count'}`; type SettingsInlineButtons = 'set-password' | 'change-password' | 'remove-password'; @@ -229,7 +233,7 @@ declare module 'react' { | 'modal-actions-container' | 'reveal-blocked-user-settings' | `${Sections}-section` - | `${SettingsToggles | SettingsInlineButtons}-settings-${'text' | 'sub-text' | 'toggle' | 'button' | 'row'}` + | `${SettingsToggles | SettingsInlineButtons | SettingsRadio}-settings-${'text' | 'sub-text' | 'toggle' | 'radio' | 'button' | 'row'}` // Buttons | `${Buttons}-button` diff --git a/ts/types/ReduxTypes.d.ts b/ts/types/ReduxTypes.d.ts index c0a66c139..914a1d3c9 100644 --- a/ts/types/ReduxTypes.d.ts +++ b/ts/types/ReduxTypes.d.ts @@ -6,9 +6,6 @@ */ export type SessionSettingCategory = - | 'donate' - | 'session-pro' - | 'notifications' | 'conversations' | 'message-requests' | 'appearance' From e168dff401c97d70452622d2c2c0b06563b36a4c Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Fri, 15 Aug 2025 09:50:29 +1000 Subject: [PATCH 04/18] chore: show exit icons for user settings child page --- .../dialog/user-settings/pages/NotificationsSettingsPage.tsx | 1 + ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx | 1 + 2 files changed, 2 insertions(+) diff --git a/ts/components/dialog/user-settings/pages/NotificationsSettingsPage.tsx b/ts/components/dialog/user-settings/pages/NotificationsSettingsPage.tsx index 1e60bd4c1..888813b92 100644 --- a/ts/components/dialog/user-settings/pages/NotificationsSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/NotificationsSettingsPage.tsx @@ -172,6 +172,7 @@ export function NotificationsSettingsPage(modalState: UserSettingsModalState) { : undefined} /> } diff --git a/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx b/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx index b7d79d1aa..1722e338d 100644 --- a/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx @@ -210,6 +210,7 @@ export function PrivacySettingsPage(modalState: UserSettingsModalState) { : undefined} /> } From f498b3751195a5f845ffca0d32be3d7b7e9d7e62 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Mon, 18 Aug 2025 09:01:39 +1000 Subject: [PATCH 05/18] feat: added user settings page about Conversation --- ts/components/SessionPasswordPrompt.tsx | 1 + ts/components/SessionWrapperModal.tsx | 7 +- ts/components/avatar/Avatar.tsx | 2 +- .../{ => avatar}/AvatarExitQrCodeButton.tsx | 4 +- .../{ => avatar}/AvatarQrCodeButton.tsx | 6 +- .../buttons/{ => avatar}/GearAvatarButton.tsx | 4 +- .../buttons/{ => avatar}/PlusAvatarButton.tsx | 6 +- .../{ => avatar}/UploadFirstImageButton.tsx | 6 +- ts/components/buttons/index.ts | 4 +- .../GenericPanelButtonWithAction.tsx | 2 +- .../buttons/{ => panel}/PanelButton.tsx | 13 +- .../buttons/panel/PanelChevronButton.tsx | 35 +++++ .../buttons/{ => panel}/PanelIconButton.tsx | 8 +- .../buttons/{ => panel}/PanelRadioButton.tsx | 2 +- .../buttons/{ => panel}/PanelToggleButton.tsx | 2 +- .../{ => panel}/PanelWithButtonInline.tsx | 2 +- .../StyledPanelButtonGroupSeparator.tsx | 0 .../message-info/OverlayMessageInfo.tsx | 2 +- .../dialog/EditProfilePictureModal.tsx | 2 +- .../UpdateConversationDetailsDialog.tsx | 2 +- .../conversationSettingsItems.tsx | 5 +- .../pages/default/defaultPage.tsx | 2 +- .../DisappearingModes.tsx | 4 +- .../disappearing-messages/TimeOptions.tsx | 4 +- .../pages/notifications/NotificationPage.tsx | 4 +- .../user-settings/UserSettingsDialog.tsx | 3 + .../dialog/user-settings/components.tsx | 2 +- .../components/SettingsChevronBasic.tsx | 33 +++++ .../components/SettingsToggleBasic.tsx | 4 +- .../pages/ConversationSettingsPage.tsx | 122 ++++++++++++++++++ .../pages/DefaultSettingsPage.tsx | 2 +- .../pages/NotificationsSettingsPage.tsx | 4 +- .../pages/PrivacySettingsPage.tsx | 6 +- ts/components/leftpane/ActionsPanel.tsx | 2 +- ts/components/qrview/QrView.tsx | 2 +- .../section/CategoryConversations.tsx | 84 +----------- ts/react.d.ts | 8 +- 37 files changed, 261 insertions(+), 140 deletions(-) rename ts/components/buttons/{ => avatar}/AvatarExitQrCodeButton.tsx (81%) rename ts/components/buttons/{ => avatar}/AvatarQrCodeButton.tsx (82%) rename ts/components/buttons/{ => avatar}/GearAvatarButton.tsx (84%) rename ts/components/buttons/{ => avatar}/PlusAvatarButton.tsx (94%) rename ts/components/buttons/{ => avatar}/UploadFirstImageButton.tsx (82%) rename ts/components/buttons/{ => panel}/GenericPanelButtonWithAction.tsx (95%) rename ts/components/buttons/{ => panel}/PanelButton.tsx (94%) create mode 100644 ts/components/buttons/panel/PanelChevronButton.tsx rename ts/components/buttons/{ => panel}/PanelIconButton.tsx (90%) rename ts/components/buttons/{ => panel}/PanelRadioButton.tsx (95%) rename ts/components/buttons/{ => panel}/PanelToggleButton.tsx (94%) rename ts/components/buttons/{ => panel}/PanelWithButtonInline.tsx (93%) rename ts/components/buttons/{ => panel}/StyledPanelButtonGroupSeparator.tsx (100%) create mode 100644 ts/components/dialog/user-settings/components/SettingsChevronBasic.tsx create mode 100644 ts/components/dialog/user-settings/pages/ConversationSettingsPage.tsx diff --git a/ts/components/SessionPasswordPrompt.tsx b/ts/components/SessionPasswordPrompt.tsx index 4099ed5ae..d6826fdc0 100644 --- a/ts/components/SessionPasswordPrompt.tsx +++ b/ts/components/SessionPasswordPrompt.tsx @@ -193,6 +193,7 @@ const SessionPasswordPromptInner = () => { } $contentMinWidth={WrapperModalWidth.narrow} + topAnchor="center" buttonChildren={ clearDataView ? ( ` position: absolute; - top: ${props => props.$topAnchor}; - max-height: ${props => `calc(100vh - ${props.$topAnchor} - 5vh)`}; + top: ${props => (props.$topAnchor === 'center' ? 'auto' : props.$topAnchor)}; + max-height: ${props => + `calc(100vh - ${props.$topAnchor === 'center' ? '' : props.$topAnchor} - 5vh)`}; animation: fadein var(--default-duration); z-index: 150; @@ -209,7 +210,7 @@ export function ModalBottomButtonWithBorder({ ); } -export type ModalTopAnchor = '15vh' | '25vh' | '35vh' | '45vh'; +export type ModalTopAnchor = '15vh' | '25vh' | '35vh' | '45vh' | 'center'; export type SessionWrapperModalType = { headerChildren: ReactNode; diff --git a/ts/components/avatar/Avatar.tsx b/ts/components/avatar/Avatar.tsx index 1eef9efcc..253a4a863 100644 --- a/ts/components/avatar/Avatar.tsx +++ b/ts/components/avatar/Avatar.tsx @@ -10,7 +10,7 @@ import { import { AvatarPlaceHolder } from './AvatarPlaceHolder/AvatarPlaceHolder'; import { ClosedGroupAvatar } from './AvatarPlaceHolder/ClosedGroupAvatar'; import { useIsMessageSelectionMode } from '../../state/selectors/selectedConversation'; -import { PlusAvatarButton } from '../buttons/PlusAvatarButton'; +import { PlusAvatarButton } from '../buttons/avatar/PlusAvatarButton'; import { StyledAvatar } from './AvatarPlaceHolder/StyledAvatar'; import { CrownIcon } from './CrownIcon'; diff --git a/ts/components/buttons/AvatarExitQrCodeButton.tsx b/ts/components/buttons/avatar/AvatarExitQrCodeButton.tsx similarity index 81% rename from ts/components/buttons/AvatarExitQrCodeButton.tsx rename to ts/components/buttons/avatar/AvatarExitQrCodeButton.tsx index dc3617e00..de6b3cec9 100644 --- a/ts/components/buttons/AvatarExitQrCodeButton.tsx +++ b/ts/components/buttons/avatar/AvatarExitQrCodeButton.tsx @@ -1,5 +1,5 @@ -import { LUCIDE_ICONS_UNICODE } from '../icon/lucide'; -import { SessionLucideIconButton } from '../icon/SessionIconButton'; +import { LUCIDE_ICONS_UNICODE } from '../../icon/lucide'; +import { SessionLucideIconButton } from '../../icon/SessionIconButton'; export function AvatarExitQrCodeButton({ onExitQrCodeView }: { onExitQrCodeView: () => void }) { return ( diff --git a/ts/components/buttons/AvatarQrCodeButton.tsx b/ts/components/buttons/avatar/AvatarQrCodeButton.tsx similarity index 82% rename from ts/components/buttons/AvatarQrCodeButton.tsx rename to ts/components/buttons/avatar/AvatarQrCodeButton.tsx index 115593730..f6062e58f 100644 --- a/ts/components/buttons/AvatarQrCodeButton.tsx +++ b/ts/components/buttons/avatar/AvatarQrCodeButton.tsx @@ -1,6 +1,6 @@ -import { AvatarSize } from '../avatar/Avatar'; -import { LUCIDE_ICONS_UNICODE } from '../icon/lucide'; -import { SessionLucideIconButton } from '../icon/SessionIconButton'; +import { AvatarSize } from '../../avatar/Avatar'; +import { LUCIDE_ICONS_UNICODE } from '../../icon/lucide'; +import { SessionLucideIconButton } from '../../icon/SessionIconButton'; import { useAvatarActionPosition } from './PlusAvatarButton'; export function AvatarQrCodeButton({ diff --git a/ts/components/buttons/GearAvatarButton.tsx b/ts/components/buttons/avatar/GearAvatarButton.tsx similarity index 84% rename from ts/components/buttons/GearAvatarButton.tsx rename to ts/components/buttons/avatar/GearAvatarButton.tsx index e5b849133..d34e2c090 100644 --- a/ts/components/buttons/GearAvatarButton.tsx +++ b/ts/components/buttons/avatar/GearAvatarButton.tsx @@ -1,5 +1,5 @@ -import { LUCIDE_ICONS_UNICODE } from '../icon/lucide'; -import { LucideIcon } from '../icon/LucideIcon'; +import { LUCIDE_ICONS_UNICODE } from '../../icon/lucide'; +import { LucideIcon } from '../../icon/LucideIcon'; /** * Used only for our own avatar display at the top-left of the app (ActionPanel). diff --git a/ts/components/buttons/PlusAvatarButton.tsx b/ts/components/buttons/avatar/PlusAvatarButton.tsx similarity index 94% rename from ts/components/buttons/PlusAvatarButton.tsx rename to ts/components/buttons/avatar/PlusAvatarButton.tsx index f830f4799..4f682fc54 100644 --- a/ts/components/buttons/PlusAvatarButton.tsx +++ b/ts/components/buttons/avatar/PlusAvatarButton.tsx @@ -1,8 +1,8 @@ import type { CSSProperties } from 'styled-components'; import type { SessionDataTestId } from 'react'; -import { SessionLucideIconButton } from '../icon/SessionIconButton'; -import { AvatarSize } from '../avatar/Avatar'; -import { LUCIDE_ICONS_UNICODE } from '../icon/lucide'; +import { SessionLucideIconButton } from '../../icon/SessionIconButton'; +import { AvatarSize } from '../../avatar/Avatar'; +import { LUCIDE_ICONS_UNICODE } from '../../icon/lucide'; export function isAvatarActionSupportedAvatarSize( avatarSize: AvatarSize diff --git a/ts/components/buttons/UploadFirstImageButton.tsx b/ts/components/buttons/avatar/UploadFirstImageButton.tsx similarity index 82% rename from ts/components/buttons/UploadFirstImageButton.tsx rename to ts/components/buttons/avatar/UploadFirstImageButton.tsx index 9ec34e668..076de2926 100644 --- a/ts/components/buttons/UploadFirstImageButton.tsx +++ b/ts/components/buttons/avatar/UploadFirstImageButton.tsx @@ -1,7 +1,7 @@ import styled from 'styled-components'; -import { AvatarSize } from '../avatar/Avatar'; -import { LUCIDE_ICONS_UNICODE } from '../icon/lucide'; -import { LucideIcon } from '../icon/LucideIcon'; +import { AvatarSize } from '../../avatar/Avatar'; +import { LUCIDE_ICONS_UNICODE } from '../../icon/lucide'; +import { LucideIcon } from '../../icon/LucideIcon'; import { PlusAvatarButton } from './PlusAvatarButton'; const StyledUploadButton = styled.div` diff --git a/ts/components/buttons/index.ts b/ts/components/buttons/index.ts index 5da85709a..a3dfeb163 100644 --- a/ts/components/buttons/index.ts +++ b/ts/components/buttons/index.ts @@ -1,8 +1,8 @@ import { CopyToClipboardButton, CopyToClipboardIcon } from './CopyToClipboardButton'; import { HelpDeskButton } from './HelpDeskButton'; import { MenuButton } from './MenuButton'; -import { PanelButtonGroup } from './PanelButton'; -import { PanelIconButton } from './PanelIconButton'; +import { PanelButtonGroup } from './panel/PanelButton'; +import { PanelIconButton } from './panel/PanelIconButton'; export { CopyToClipboardButton, diff --git a/ts/components/buttons/GenericPanelButtonWithAction.tsx b/ts/components/buttons/panel/GenericPanelButtonWithAction.tsx similarity index 95% rename from ts/components/buttons/GenericPanelButtonWithAction.tsx rename to ts/components/buttons/panel/GenericPanelButtonWithAction.tsx index 32640ed07..6dc9730f1 100644 --- a/ts/components/buttons/GenericPanelButtonWithAction.tsx +++ b/ts/components/buttons/panel/GenericPanelButtonWithAction.tsx @@ -1,6 +1,6 @@ import type { ReactNode, SessionDataTestId } from 'react'; import styled from 'styled-components'; -import { useIsDarkTheme } from '../../state/theme/selectors/theme'; +import { useIsDarkTheme } from '../../../state/theme/selectors/theme'; import { StyledPanelButton, StyledContent } from './PanelButton'; import { StyledPanelButtonSeparator } from './StyledPanelButtonGroupSeparator'; diff --git a/ts/components/buttons/PanelButton.tsx b/ts/components/buttons/panel/PanelButton.tsx similarity index 94% rename from ts/components/buttons/PanelButton.tsx rename to ts/components/buttons/panel/PanelButton.tsx index cfdd8b977..a3ea337fa 100644 --- a/ts/components/buttons/PanelButton.tsx +++ b/ts/components/buttons/panel/PanelButton.tsx @@ -1,11 +1,12 @@ import { ReactNode, SessionDataTestId, type PropsWithChildren } from 'react'; import styled, { CSSProperties } from 'styled-components'; -import { Flex } from '../basic/Flex'; -import { H8 } from '../basic/Heading'; -import { SpacerXS } from '../basic/Text'; -import { useIsDarkTheme } from '../../state/theme/selectors/theme'; -import { Localizer } from '../basic/Localizer'; -import type { TrArgs } from '../../localization/localeTools'; + +import { Flex } from '../../basic/Flex'; +import { H8 } from '../../basic/Heading'; +import { SpacerXS } from '../../basic/Text'; +import { Localizer } from '../../basic/Localizer'; +import type { TrArgs } from '../../../localization/localeTools'; +import { useIsDarkTheme } from '../../../state/theme/selectors/theme'; // NOTE Used for descendant components export const StyledContent = styled.div<{ disabled: boolean }>` diff --git a/ts/components/buttons/panel/PanelChevronButton.tsx b/ts/components/buttons/panel/PanelChevronButton.tsx new file mode 100644 index 000000000..9ee869cc6 --- /dev/null +++ b/ts/components/buttons/panel/PanelChevronButton.tsx @@ -0,0 +1,35 @@ +import type { SettingsChevron } from 'react'; +import { LUCIDE_ICONS_UNICODE } from '../../icon/lucide'; +import { SessionLucideIconButton } from '../../icon/SessionIconButton'; +import { + GenericPanelButtonWithAction, + type GenericPanelButtonProps, +} from './GenericPanelButtonWithAction'; + +type PanelChevronButtonProps = Pick & { + onClick?: (...args: Array) => void; + disabled?: boolean; + baseDataTestId: SettingsChevron; +}; + +export const PanelChevronButton = (props: PanelChevronButtonProps) => { + const { onClick, disabled = false, baseDataTestId, textElement } = props; + + return ( + + } + /> + ); +}; diff --git a/ts/components/buttons/PanelIconButton.tsx b/ts/components/buttons/panel/PanelIconButton.tsx similarity index 90% rename from ts/components/buttons/PanelIconButton.tsx rename to ts/components/buttons/panel/PanelIconButton.tsx index d6d874d2f..b2b219ebf 100644 --- a/ts/components/buttons/PanelIconButton.tsx +++ b/ts/components/buttons/panel/PanelIconButton.tsx @@ -9,10 +9,10 @@ import { StyledContent, type PanelButtonSubtextProps, } from './PanelButton'; -import { LucideIcon } from '../icon/LucideIcon'; -import { SessionIcon } from '../icon/SessionIcon'; -import type { SessionIconType } from '../icon'; -import type { WithLucideUnicode } from '../icon/lucide'; +import { LucideIcon } from '../../icon/LucideIcon'; +import { SessionIcon } from '../../icon/SessionIcon'; +import type { SessionIconType } from '../../icon'; +import type { WithLucideUnicode } from '../../icon/lucide'; import { StyledPanelButtonSeparator } from './StyledPanelButtonGroupSeparator'; type PanelIconButtonProps = Omit & { diff --git a/ts/components/buttons/PanelRadioButton.tsx b/ts/components/buttons/panel/PanelRadioButton.tsx similarity index 95% rename from ts/components/buttons/PanelRadioButton.tsx rename to ts/components/buttons/panel/PanelRadioButton.tsx index cd7ce0850..6f288e98a 100644 --- a/ts/components/buttons/PanelRadioButton.tsx +++ b/ts/components/buttons/panel/PanelRadioButton.tsx @@ -1,5 +1,5 @@ import { SessionDataTestId } from 'react'; -import { SessionRadio } from '../basic/SessionRadio'; +import { SessionRadio } from '../../basic/SessionRadio'; import { GenericPanelButtonWithAction, type GenericPanelButtonProps, diff --git a/ts/components/buttons/PanelToggleButton.tsx b/ts/components/buttons/panel/PanelToggleButton.tsx similarity index 94% rename from ts/components/buttons/PanelToggleButton.tsx rename to ts/components/buttons/panel/PanelToggleButton.tsx index dfe04f70c..1279ce9ea 100644 --- a/ts/components/buttons/PanelToggleButton.tsx +++ b/ts/components/buttons/panel/PanelToggleButton.tsx @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-misused-promises */ import { SessionDataTestId } from 'react'; -import { SessionToggle } from '../basic/SessionToggle'; +import { SessionToggle } from '../../basic/SessionToggle'; import { GenericPanelButtonWithAction, type GenericPanelButtonProps, diff --git a/ts/components/buttons/PanelWithButtonInline.tsx b/ts/components/buttons/panel/PanelWithButtonInline.tsx similarity index 93% rename from ts/components/buttons/PanelWithButtonInline.tsx rename to ts/components/buttons/panel/PanelWithButtonInline.tsx index 4beddf4e2..ae1eae8a0 100644 --- a/ts/components/buttons/PanelWithButtonInline.tsx +++ b/ts/components/buttons/panel/PanelWithButtonInline.tsx @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-misused-promises */ import { SessionDataTestId } from 'react'; -import { SessionButton, type SessionButtonProps } from '../basic/SessionButton'; +import { SessionButton, type SessionButtonProps } from '../../basic/SessionButton'; import { GenericPanelButtonWithAction, diff --git a/ts/components/buttons/StyledPanelButtonGroupSeparator.tsx b/ts/components/buttons/panel/StyledPanelButtonGroupSeparator.tsx similarity index 100% rename from ts/components/buttons/StyledPanelButtonGroupSeparator.tsx rename to ts/components/buttons/panel/StyledPanelButtonGroupSeparator.tsx diff --git a/ts/components/conversation/right-panel/overlay/message-info/OverlayMessageInfo.tsx b/ts/components/conversation/right-panel/overlay/message-info/OverlayMessageInfo.tsx index b30ca7083..bf08e00da 100644 --- a/ts/components/conversation/right-panel/overlay/message-info/OverlayMessageInfo.tsx +++ b/ts/components/conversation/right-panel/overlay/message-info/OverlayMessageInfo.tsx @@ -48,7 +48,7 @@ import { AttachmentInfo, MessageInfo } from './components'; import { AttachmentCarousel } from './components/AttachmentCarousel'; import { ToastUtils } from '../../../../../session/utils'; import { LUCIDE_ICONS_UNICODE } from '../../../../icon/lucide'; -import { PanelIconLucideIcon } from '../../../../buttons/PanelIconButton'; +import { PanelIconLucideIcon } from '../../../../buttons/panel/PanelIconButton'; import { sectionActions } from '../../../../../state/ducks/section'; import { useIsIncomingRequest } from '../../../../../hooks/useParamSelector'; import { tr } from '../../../../../localization/localeTools'; diff --git a/ts/components/dialog/EditProfilePictureModal.tsx b/ts/components/dialog/EditProfilePictureModal.tsx index 76654fee3..63ba424dd 100644 --- a/ts/components/dialog/EditProfilePictureModal.tsx +++ b/ts/components/dialog/EditProfilePictureModal.tsx @@ -40,7 +40,7 @@ import { ProIconButton } from '../buttons/ProButton'; import { useProBadgeOnClickCb } from '../menuAndSettingsHooks/useProBadgeOnClickCb'; import { useUserHasPro } from '../../hooks/useHasPro'; import { Localizer } from '../basic/Localizer'; -import { UploadFirstImageButton } from '../buttons/UploadFirstImageButton'; +import { UploadFirstImageButton } from '../buttons/avatar/UploadFirstImageButton'; const StyledAvatarContainer = styled.div` cursor: pointer; diff --git a/ts/components/dialog/UpdateConversationDetailsDialog.tsx b/ts/components/dialog/UpdateConversationDetailsDialog.tsx index a50337dc4..2c7301360 100644 --- a/ts/components/dialog/UpdateConversationDetailsDialog.tsx +++ b/ts/components/dialog/UpdateConversationDetailsDialog.tsx @@ -41,7 +41,7 @@ import { } from '../../state/selectors/sogsRoomInfo'; import { ReduxSogsRoomInfos } from '../../state/ducks/sogsRoomInfo'; import type { WithConvoId } from '../../session/types/with'; -import { UploadFirstImageButton } from '../buttons/UploadFirstImageButton'; +import { UploadFirstImageButton } from '../buttons/avatar/UploadFirstImageButton'; function useNameErrorString({ isMe, diff --git a/ts/components/dialog/conversationSettings/conversationSettingsItems.tsx b/ts/components/dialog/conversationSettings/conversationSettingsItems.tsx index 175269169..662ddb1ac 100644 --- a/ts/components/dialog/conversationSettings/conversationSettingsItems.tsx +++ b/ts/components/dialog/conversationSettings/conversationSettingsItems.tsx @@ -11,7 +11,10 @@ import { showUpdateGroupMembersByConvoId } from '../../../interactions/conversat import { tr } from '../../../localization/localeTools'; import type { ConversationNotificationSettingType } from '../../../models/conversationAttributes'; import { PanelIconButton } from '../../buttons'; -import { PanelIconLucideIcon, PanelIconSessionLegacyIcon } from '../../buttons/PanelIconButton'; +import { + PanelIconLucideIcon, + PanelIconSessionLegacyIcon, +} from '../../buttons/panel/PanelIconButton'; import { LUCIDE_ICONS_UNICODE } from '../../icon/lucide'; import { useShowNotificationFor } from '../../menuAndSettingsHooks/useShowNotificationFor'; import type { WithConvoId } from '../../../session/types/with'; diff --git a/ts/components/dialog/conversationSettings/pages/default/defaultPage.tsx b/ts/components/dialog/conversationSettings/pages/default/defaultPage.tsx index 8cdbb9fd0..bed4c4aea 100644 --- a/ts/components/dialog/conversationSettings/pages/default/defaultPage.tsx +++ b/ts/components/dialog/conversationSettings/pages/default/defaultPage.tsx @@ -10,7 +10,7 @@ import { Flex } from '../../../../basic/Flex'; import { useWeAreCommunityAdminOrModerator } from '../../../../../state/selectors/conversations'; import { SpacerSM } from '../../../../basic/Text'; import { PanelButtonGroup } from '../../../../buttons'; -import { PanelLabelWithDescription } from '../../../../buttons/PanelButton'; +import { PanelLabelWithDescription } from '../../../../buttons/panel/PanelButton'; import { useShowAttachments } from '../../../../menuAndSettingsHooks/useShowAttachments'; import { ModalBasicHeader, SessionWrapperModal } from '../../../../SessionWrapperModal'; import { ConversationSettingsHeader } from '../../conversationSettingsHeader'; diff --git a/ts/components/dialog/conversationSettings/pages/disappearing-messages/DisappearingModes.tsx b/ts/components/dialog/conversationSettings/pages/disappearing-messages/DisappearingModes.tsx index 2f9f8a950..6a5789b12 100644 --- a/ts/components/dialog/conversationSettings/pages/disappearing-messages/DisappearingModes.tsx +++ b/ts/components/dialog/conversationSettings/pages/disappearing-messages/DisappearingModes.tsx @@ -5,8 +5,8 @@ import { PanelButtonText, PanelButtonTextWithSubText, PanelLabelWithDescription, -} from '../../../../buttons/PanelButton'; -import { PanelRadioButton } from '../../../../buttons/PanelRadioButton'; +} from '../../../../buttons/panel/PanelButton'; +import { PanelRadioButton } from '../../../../buttons/panel/PanelRadioButton'; function toDataTestId(mode: DisappearingMessageConversationModeType) { switch (mode) { diff --git a/ts/components/dialog/conversationSettings/pages/disappearing-messages/TimeOptions.tsx b/ts/components/dialog/conversationSettings/pages/disappearing-messages/TimeOptions.tsx index cba831aaf..8d6a10a23 100644 --- a/ts/components/dialog/conversationSettings/pages/disappearing-messages/TimeOptions.tsx +++ b/ts/components/dialog/conversationSettings/pages/disappearing-messages/TimeOptions.tsx @@ -9,8 +9,8 @@ import { PanelButtonGroup, PanelButtonText, PanelLabelWithDescription, -} from '../../../../buttons/PanelButton'; -import { PanelRadioButton } from '../../../../buttons/PanelRadioButton'; +} from '../../../../buttons/panel/PanelButton'; +import { PanelRadioButton } from '../../../../buttons/panel/PanelRadioButton'; import { assertUnreachable } from '../../../../../types/sqlSharedTypes'; type TimerOptionsProps = { diff --git a/ts/components/dialog/conversationSettings/pages/notifications/NotificationPage.tsx b/ts/components/dialog/conversationSettings/pages/notifications/NotificationPage.tsx index 8fa682698..8d6f4ab98 100644 --- a/ts/components/dialog/conversationSettings/pages/notifications/NotificationPage.tsx +++ b/ts/components/dialog/conversationSettings/pages/notifications/NotificationPage.tsx @@ -7,13 +7,13 @@ import { SessionButton } from '../../../../basic/SessionButton'; import { StyledScrollContainer } from '../../../../conversation/right-panel/overlay/components'; import { type ConversationNotificationSettingType } from '../../../../../models/conversationAttributes'; import { PanelButtonGroup } from '../../../../buttons'; -import { PanelRadioButton } from '../../../../buttons/PanelRadioButton'; +import { PanelRadioButton } from '../../../../buttons/panel/PanelRadioButton'; import { updateConversationSettingsModal, type ConversationSettingsModalState, } from '../../../../../state/ducks/modalDialog'; import { useConversationSettingsModalIsStandalone } from '../../../../../state/selectors/modal'; -import { PanelButtonText } from '../../../../buttons/PanelButton'; +import { PanelButtonText } from '../../../../buttons/panel/PanelButton'; import { useLocalisedNotificationOptions } from '../../../../menuAndSettingsHooks/useLocalisedNotificationFor'; import { useSetNotificationsFor } from '../../../../menuAndSettingsHooks/useSetNotificationsFor'; import { useShowConversationSettingsFor } from '../../../../menuAndSettingsHooks/useShowConversationSettingsFor'; diff --git a/ts/components/dialog/user-settings/UserSettingsDialog.tsx b/ts/components/dialog/user-settings/UserSettingsDialog.tsx index da154896b..3fb6689d4 100644 --- a/ts/components/dialog/user-settings/UserSettingsDialog.tsx +++ b/ts/components/dialog/user-settings/UserSettingsDialog.tsx @@ -1,4 +1,5 @@ import { type UserSettingsModalState } from '../../../state/ducks/modalDialog'; +import { ConversationSettingsPage } from './pages/ConversationSettingsPage'; import { DefaultSettingPage } from './pages/DefaultSettingsPage'; import { NotificationsSettingsPage } from './pages/NotificationsSettingsPage'; import { PrivacySettingsPage } from './pages/PrivacySettingsPage'; @@ -15,6 +16,8 @@ export const UserSettingsDialog = (modalState: UserSettingsModalState) => { return ; case 'notifications': return ; + case 'conversations': + return ; default: return ; } diff --git a/ts/components/dialog/user-settings/components.tsx b/ts/components/dialog/user-settings/components.tsx index 81fbcf942..6783d285b 100644 --- a/ts/components/dialog/user-settings/components.tsx +++ b/ts/components/dialog/user-settings/components.tsx @@ -6,7 +6,7 @@ import { Flex } from '../../basic/Flex'; import { useProBadgeOnClickCb } from '../../menuAndSettingsHooks/useProBadgeOnClickCb'; import { useCurrentUserHasPro } from '../../../hooks/useHasPro'; import { ProIconButton } from '../../buttons/ProButton'; -import { AvatarQrCodeButton } from '../../buttons/AvatarQrCodeButton'; +import { AvatarQrCodeButton } from '../../buttons/avatar/AvatarQrCodeButton'; type ProfileAvatarProps = { avatarPath: string | null; diff --git a/ts/components/dialog/user-settings/components/SettingsChevronBasic.tsx b/ts/components/dialog/user-settings/components/SettingsChevronBasic.tsx new file mode 100644 index 000000000..1d756ac2d --- /dev/null +++ b/ts/components/dialog/user-settings/components/SettingsChevronBasic.tsx @@ -0,0 +1,33 @@ +import type { SettingsChevron } from 'react'; +import type { TokenSimpleNoArgs } from '../../../../localization/locales'; +import { PanelButtonTextWithSubText } from '../../../buttons/panel/PanelButton'; +import { tr } from '../../../../localization/localeTools'; +import { PanelChevronButton } from '../../../buttons/panel/PanelChevronButton'; + +export function SettingsChevronBasic({ + baseDataTestId, + onClick, + textToken, + subTextToken, +}: { + textToken: TokenSimpleNoArgs; + subTextToken: TokenSimpleNoArgs; + baseDataTestId: SettingsChevron; + onClick: () => Promise; +}) { + return ( + + } + // eslint-disable-next-line @typescript-eslint/no-misused-promises + onClick={onClick} + baseDataTestId={baseDataTestId} + /> + ); +} diff --git a/ts/components/dialog/user-settings/components/SettingsToggleBasic.tsx b/ts/components/dialog/user-settings/components/SettingsToggleBasic.tsx index dbfff9fb3..db98fc539 100644 --- a/ts/components/dialog/user-settings/components/SettingsToggleBasic.tsx +++ b/ts/components/dialog/user-settings/components/SettingsToggleBasic.tsx @@ -1,7 +1,7 @@ import type { SettingsToggles } from 'react'; import type { TokenSimpleNoArgs } from '../../../../localization/locales'; -import { PanelButtonTextWithSubText } from '../../../buttons/PanelButton'; -import { PanelToggleButton } from '../../../buttons/PanelToggleButton'; +import { PanelButtonTextWithSubText } from '../../../buttons/panel/PanelButton'; +import { PanelToggleButton } from '../../../buttons/panel/PanelToggleButton'; import { tr } from '../../../../localization/localeTools'; export function SettingsToggleBasic({ diff --git a/ts/components/dialog/user-settings/pages/ConversationSettingsPage.tsx b/ts/components/dialog/user-settings/pages/ConversationSettingsPage.tsx new file mode 100644 index 000000000..ccd99a54b --- /dev/null +++ b/ts/components/dialog/user-settings/pages/ConversationSettingsPage.tsx @@ -0,0 +1,122 @@ +import useUpdate from 'react-use/lib/useUpdate'; +import { useDispatch, useSelector } from 'react-redux'; + +import { type UserSettingsModalState } from '../../../../state/ducks/modalDialog'; +import { PanelButtonGroup, PanelLabelWithDescription } from '../../../buttons/panel/PanelButton'; +import { + ModalBasicHeader, + SessionWrapperModal, + WrapperModalWidth, +} from '../../../SessionWrapperModal'; +import { ModalBackButton } from '../../shared/ModalBackButton'; +import { + useUserSettingsBackAction, + useUserSettingsCloseAction, + useUserSettingsTitle, +} from './userSettingsHooks'; +import { SettingsKey } from '../../../../data/settings-key'; +import { SettingsToggleBasic } from '../components/SettingsToggleBasic'; +import { ToastUtils } from '../../../../session/utils'; +import { toggleAudioAutoplay } from '../../../../state/ducks/userConfig'; + +import { getAudioAutoplay } from '../../../../state/selectors/userConfig'; +import { SettingsChevronBasic } from '../components/SettingsChevronBasic'; + +async function toggleCommunitiesPruning() { + try { + const newValue = !(await window.getOpengroupPruning()); + + // make sure to write it here too, as this is the value used on the UI to mark the toggle as true/false + await window.setSettingValue(SettingsKey.settingsOpengroupPruning, newValue); + await window.setOpengroupPruning(newValue); + ToastUtils.pushRestartNeeded(); + } catch (e) { + window.log.warn('toggleCommunitiesPruning change error:', e); + } +} + +export function ConversationSettingsPage(modalState: UserSettingsModalState) { + const forceUpdate = useUpdate(); + const backAction = useUserSettingsBackAction(modalState); + const closeAction = useUserSettingsCloseAction(modalState); + const title = useUserSettingsTitle(modalState); + const dispatch = useDispatch(); + + const isOpengroupPruningEnabled = Boolean( + window.getSettingValue(SettingsKey.settingsOpengroupPruning) + ); + const isSpellCheckActive = + window.getSettingValue(SettingsKey.settingsSpellCheck) === undefined + ? true + : window.getSettingValue(SettingsKey.settingsSpellCheck); + const audioAutoPlay = useSelector(getAudioAutoplay); + + return ( + : undefined} + /> + } + onClose={closeAction || undefined} + shouldOverflow={true} + allowOutsideClick={false} + $contentMinWidth={WrapperModalWidth.normal} + > + + + { + await toggleCommunitiesPruning(); + forceUpdate(); + }} + textToken={'conversationsMessageTrimmingTrimCommunities'} + subTextToken={'conversationsMessageTrimmingTrimCommunitiesDescription'} + /> + + + + { + window.toggleSpellCheck(); + forceUpdate(); + }} + textToken={'conversationsSpellCheck'} + subTextToken={'conversationsSpellCheckDescription'} + /> + + + + { + dispatch(toggleAudioAutoplay()); + forceUpdate(); + }} + textToken={'conversationsAutoplayAudioMessage'} + subTextToken={'conversationsAutoplayAudioMessageDescription'} + /> + + + + + { + throw new Error('Not implemented'); + }} + textToken={'conversationsBlockedContacts'} + subTextToken={'blockedContactsManageDescription'} + /> + + + ); +} diff --git a/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx b/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx index 19588679f..e28756a68 100644 --- a/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx @@ -177,7 +177,7 @@ function SettingsSection() { iconElement={} text={tr('sessionConversations')} onClick={() => { - throw new Error('Not implemented'); + dispatch(userSettingsModal({ userSettingsPage: 'conversations' })); }} dataTestId="conversations-settings-menu-item" /> diff --git a/ts/components/dialog/user-settings/pages/NotificationsSettingsPage.tsx b/ts/components/dialog/user-settings/pages/NotificationsSettingsPage.tsx index 888813b92..fea832d73 100644 --- a/ts/components/dialog/user-settings/pages/NotificationsSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/NotificationsSettingsPage.tsx @@ -8,7 +8,7 @@ import { PanelButtonGroup, PanelButtonTextWithSubText, PanelLabelWithDescription, -} from '../../../buttons/PanelButton'; +} from '../../../buttons/panel/PanelButton'; import { ModalBasicHeader, SessionWrapperModal, @@ -26,7 +26,7 @@ import { Notifications } from '../../../../util/notifications'; import { isAudioNotificationSupported } from '../../../../types/Settings'; import { SpacerLG } from '../../../basic/Text'; import { SessionButton, SessionButtonColor } from '../../../basic/SessionButton'; -import { PanelRadioButton } from '../../../buttons/PanelRadioButton'; +import { PanelRadioButton } from '../../../buttons/panel/PanelRadioButton'; const NotificationType = { message: 'message', name: 'name', count: 'count', off: 'off' } as const; diff --git a/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx b/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx index 1722e338d..f8980b0e0 100644 --- a/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx @@ -10,8 +10,8 @@ import { PanelButtonGroup, PanelButtonTextWithSubText, PanelLabelWithDescription, -} from '../../../buttons/PanelButton'; -import { PanelToggleButton } from '../../../buttons/PanelToggleButton'; +} from '../../../buttons/panel/PanelButton'; +import { PanelToggleButton } from '../../../buttons/panel/PanelToggleButton'; import { ModalBasicHeader, SessionWrapperModal, @@ -33,7 +33,7 @@ import { SettingsKey } from '../../../../data/settings-key'; import { SessionUtilUserProfile } from '../../../../session/utils/libsession/libsession_utils_user_profile'; import { getPasswordHash, Storage } from '../../../../util/storage'; import { SpacerXS } from '../../../basic/Text'; -import { PanelWithButtonInline } from '../../../buttons/PanelWithButtonInline'; +import { PanelWithButtonInline } from '../../../buttons/panel/PanelWithButtonInline'; import { displayPasswordModal } from '../../../settings/SessionSettings'; import { SettingsToggleBasic } from '../components/SettingsToggleBasic'; diff --git a/ts/components/leftpane/ActionsPanel.tsx b/ts/components/leftpane/ActionsPanel.tsx index 4f53a1d9d..83bc17d5e 100644 --- a/ts/components/leftpane/ActionsPanel.tsx +++ b/ts/components/leftpane/ActionsPanel.tsx @@ -61,7 +61,7 @@ import { Storage } from '../../util/storage'; import { getFileInfoFromFileServer } from '../../session/apis/file_server_api/FileServerApi'; import { themesArray } from '../../themes/constants/colors'; import { isDebugMode } from '../../shared/env_vars'; -import { GearAvatarButton } from '../buttons/GearAvatarButton'; +import { GearAvatarButton } from '../buttons/avatar/GearAvatarButton'; const StyledContainerAvatar = styled.div` padding: var(--margins-lg); diff --git a/ts/components/qrview/QrView.tsx b/ts/components/qrview/QrView.tsx index dbd1a2763..8cf9a7afb 100644 --- a/ts/components/qrview/QrView.tsx +++ b/ts/components/qrview/QrView.tsx @@ -2,7 +2,7 @@ import { useDispatch } from 'react-redux'; import { useIconToImageURL } from '../../hooks/useIconToImageURL'; import { updateLightBoxOptions } from '../../state/ducks/modalDialog'; import { prepareQRCodeForLightBox } from '../../util/qrCodes'; -import { AvatarExitQrCodeButton } from '../buttons/AvatarExitQrCodeButton'; +import { AvatarExitQrCodeButton } from '../buttons/avatar/AvatarExitQrCodeButton'; import { QRCodeLogoProps, SessionQRCode } from '../SessionQRCode'; const qrLogoProps: QRCodeLogoProps = { diff --git a/ts/components/settings/section/CategoryConversations.tsx b/ts/components/settings/section/CategoryConversations.tsx index 6835379b7..808f06d03 100644 --- a/ts/components/settings/section/CategoryConversations.tsx +++ b/ts/components/settings/section/CategoryConversations.tsx @@ -1,89 +1,10 @@ -import { useDispatch, useSelector } from 'react-redux'; - -import useUpdate from 'react-use/lib/useUpdate'; import { SettingsKey } from '../../../data/settings-key'; -import { ToastUtils } from '../../../session/utils'; -import { toggleAudioAutoplay } from '../../../state/ducks/userConfig'; import { useHasEnterSendEnabled } from '../../../state/selectors/settings'; -import { getAudioAutoplay } from '../../../state/selectors/userConfig'; import { SessionRadioGroup, SessionRadioItems } from '../../basic/SessionRadioGroup'; import { BlockedContactsList } from '../BlockedList'; -import { - SessionSettingsItemWrapper, - SessionToggleWithDescription, -} from '../SessionSettingListItem'; +import { SessionSettingsItemWrapper } from '../SessionSettingListItem'; import { tr } from '../../../localization/localeTools'; -async function toggleCommunitiesPruning() { - try { - const newValue = !(await window.getOpengroupPruning()); - - // make sure to write it here too, as this is the value used on the UI to mark the toggle as true/false - await window.setSettingValue(SettingsKey.settingsOpengroupPruning, newValue); - await window.setOpengroupPruning(newValue); - ToastUtils.pushRestartNeeded(); - } catch (e) { - window.log.warn('toggleCommunitiesPruning change error:', e); - } -} - -const CommunitiesPruningSetting = () => { - const forceUpdate = useUpdate(); - const isOpengroupPruningEnabled = Boolean( - window.getSettingValue(SettingsKey.settingsOpengroupPruning) - ); - return ( - { - await toggleCommunitiesPruning(); - forceUpdate(); - }} - title={tr('conversationsMessageTrimmingTrimCommunities')} - description={tr('conversationsMessageTrimmingTrimCommunitiesDescription')} - active={isOpengroupPruningEnabled} - /> - ); -}; - -const SpellCheckSetting = () => { - const forceUpdate = useUpdate(); - - const isSpellCheckActive = - window.getSettingValue(SettingsKey.settingsSpellCheck) === undefined - ? true - : window.getSettingValue(SettingsKey.settingsSpellCheck); - return ( - { - window.toggleSpellCheck(); - forceUpdate(); - }} - title={tr('conversationsSpellCheck')} - description={tr('conversationsSpellCheckDescription')} - active={isSpellCheckActive} - /> - ); -}; - -const AudioMessageAutoPlaySetting = () => { - const audioAutoPlay = useSelector(getAudioAutoplay); - const dispatch = useDispatch(); - const forceUpdate = useUpdate(); - - return ( - { - dispatch(toggleAudioAutoplay()); - forceUpdate(); - }} - title={tr('conversationsAutoplayAudioMessage')} - description={tr('conversationsAutoplayAudioMessageDescription')} - active={audioAutoPlay} - /> - ); -}; - const EnterKeyFunctionSetting = () => { const initialSetting = useHasEnterSendEnabled(); const selectedWithSettingTrue = 'enterForNewLine'; @@ -127,9 +48,6 @@ const EnterKeyFunctionSetting = () => { export const CategoryConversations = () => { return ( <> - - - diff --git a/ts/react.d.ts b/ts/react.d.ts index 3a0067da1..01da47042 100644 --- a/ts/react.d.ts +++ b/ts/react.d.ts @@ -89,9 +89,13 @@ declare module 'react' { | 'enable-typing-indicators' | 'enable-link-previews' | 'notifications' - | 'audio-notifications'; + | 'audio-notifications' + | 'audio-message-autoplay' + | 'spell-check' + | 'conversation-trimming'; type SettingsRadio = `set-notifications-${'message' | 'name' | 'count'}`; + type SettingsChevron = `blocked-contacts`; type SettingsInlineButtons = 'set-password' | 'change-password' | 'remove-password'; @@ -233,7 +237,7 @@ declare module 'react' { | 'modal-actions-container' | 'reveal-blocked-user-settings' | `${Sections}-section` - | `${SettingsToggles | SettingsInlineButtons | SettingsRadio}-settings-${'text' | 'sub-text' | 'toggle' | 'radio' | 'button' | 'row'}` + | `${SettingsToggles | SettingsInlineButtons | SettingsRadio | SettingsChevron}-settings-${'text' | 'sub-text' | 'toggle' | 'radio' | 'button' | 'chevron' | 'row'}` // Buttons | `${Buttons}-button` From 7b112ca960767da0a8f9fe4cc82b4870767f401e Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Mon, 18 Aug 2025 09:17:57 +1000 Subject: [PATCH 06/18] feat: link delete account modal to new user settings page --- ts/components/dialog/DeleteAccountModal.tsx | 1 + .../user-settings/pages/DefaultSettingsPage.tsx | 4 +++- ts/components/leftpane/LeftPaneSettingSection.tsx | 15 +-------------- ts/components/settings/SessionSettings.tsx | 2 -- ts/components/settings/SessionSettingsHeader.tsx | 2 -- ts/types/ReduxTypes.d.ts | 4 +--- 6 files changed, 6 insertions(+), 22 deletions(-) diff --git a/ts/components/dialog/DeleteAccountModal.tsx b/ts/components/dialog/DeleteAccountModal.tsx index 572a86530..ef3ff03f9 100644 --- a/ts/components/dialog/DeleteAccountModal.tsx +++ b/ts/components/dialog/DeleteAccountModal.tsx @@ -123,6 +123,7 @@ export const DeleteAccountModal = () => { } onClose={onClickCancelHandler} + topAnchor="center" buttonChildren={ { - throw new Error('Not implemented'); + dispatch(updateDeleteAccountModal({})); }} dataTestId="clear-data-settings-menu-item" color="var(--danger-color)" diff --git a/ts/components/leftpane/LeftPaneSettingSection.tsx b/ts/components/leftpane/LeftPaneSettingSection.tsx index 537dddf4f..dcf0343aa 100644 --- a/ts/components/leftpane/LeftPaneSettingSection.tsx +++ b/ts/components/leftpane/LeftPaneSettingSection.tsx @@ -2,7 +2,6 @@ import { type ReactNode, SessionDataTestId, useMemo } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import styled from 'styled-components'; -import { updateDeleteAccountModal } from '../../state/ducks/modalDialog'; import { sectionActions } from '../../state/ducks/section'; import { getFocusedSettingsSection } from '../../state/selectors/section'; import { useHideRecoveryPasswordEnabled } from '../../state/selectors/settings'; @@ -10,7 +9,6 @@ import type { SessionSettingCategory } from '../../types/ReduxTypes'; import { Flex } from '../basic/Flex'; import { SessionIcon, SessionIconType } from '../icon'; import { LeftPaneSectionHeader } from './LeftPaneSectionHeader'; -import { getSessionNetworkModalState } from '../../state/selectors/modal'; import { Localizer } from '../basic/Localizer'; import { tr } from '../../localization/localeTools'; import { LUCIDE_ICONS_UNICODE, type WithLucideUnicode } from '../icon/lucide'; @@ -111,12 +109,8 @@ const LeftPaneSettingsCategoryRow = ({ item }: { item: Categories }) => { const { id, title, titleColor, icon, dataTestId, isNew } = item; const dispatch = useDispatch(); const focusedSettingsSection = useSelector(getFocusedSettingsSection); - const sessionNetworkModalState = useSelector(getSessionNetworkModalState); - const isSelected = useMemo( - () => (sessionNetworkModalState ? id === 'session-network' : focusedSettingsSection === id), - [focusedSettingsSection, id, sessionNetworkModalState] - ); + const isSelected = useMemo(() => focusedSettingsSection === id, [focusedSettingsSection, id]); const iconSize = 'medium'; @@ -135,13 +129,6 @@ const LeftPaneSettingsCategoryRow = ({ item }: { item: Categories }) => { switch (id) { case 'message-requests': break; - case 'session-network': - // if the network modal is not open yet do an info request - - break; - case 'clear-data': - dispatch(updateDeleteAccountModal({})); - break; default: dispatch(sectionActions.showSettingsSection(id)); } diff --git a/ts/components/settings/SessionSettings.tsx b/ts/components/settings/SessionSettings.tsx index 71927eb8c..16e765641 100644 --- a/ts/components/settings/SessionSettings.tsx +++ b/ts/components/settings/SessionSettings.tsx @@ -123,8 +123,6 @@ const SettingInCategory = (props: { category: SessionSettingCategory }) => { // these are just buttons or modals and don't have screens case 'message-requests': - case 'session-network': - case 'clear-data': default: return null; } diff --git a/ts/components/settings/SessionSettingsHeader.tsx b/ts/components/settings/SessionSettingsHeader.tsx index b498b7a3e..bc8322dce 100644 --- a/ts/components/settings/SessionSettingsHeader.tsx +++ b/ts/components/settings/SessionSettingsHeader.tsx @@ -42,8 +42,6 @@ export const SettingsHeader = (props: Props) => { categoryTitleKey = 'sessionRecoveryPassword'; break; // these are modals or other screens - case 'session-network': - case 'clear-data': case 'message-requests': throw new Error(`no header for should be tried to be rendered for "${category}"`); diff --git a/ts/types/ReduxTypes.d.ts b/ts/types/ReduxTypes.d.ts index 914a1d3c9..5066ff8d2 100644 --- a/ts/types/ReduxTypes.d.ts +++ b/ts/types/ReduxTypes.d.ts @@ -10,10 +10,8 @@ export type SessionSettingCategory = | 'message-requests' | 'appearance' | 'permissions' - | 'session-network' | 'recovery-password' - | 'help' - | 'clear-data'; + | 'help'; export type PasswordAction = 'set' | 'change' | 'remove' | 'enter'; From 57a4cffe068d4bc0d01f1944fa88bbb5cf3c9341 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Mon, 18 Aug 2025 09:57:50 +1000 Subject: [PATCH 07/18] feat: added the help settings page and remove it from legacy settings --- .../buttons/panel/PanelWithButtonInline.tsx | 7 +- .../user-settings/UserSettingsDialog.tsx | 3 + .../components/SettingsExternalLinkBasic.tsx | 64 +++++++++++++ .../SettingsPanelButtonInlineBasic.tsx | 42 +++++++++ .../pages/DefaultSettingsPage.tsx | 2 +- .../user-settings/pages/HelpSettingsPage.tsx | 94 +++++++++++++++++++ .../pages/PrivacySettingsPage.tsx | 51 +++------- .../leftpane/LeftPaneSettingSection.tsx | 7 -- ts/components/settings/SessionSettings.tsx | 7 -- .../settings/SessionSettingsHeader.tsx | 7 -- .../settings/section/CategoryHelp.tsx | 35 ------- ts/react.d.ts | 9 +- ts/types/ReduxTypes.d.ts | 4 +- 13 files changed, 231 insertions(+), 101 deletions(-) create mode 100644 ts/components/dialog/user-settings/components/SettingsExternalLinkBasic.tsx create mode 100644 ts/components/dialog/user-settings/components/SettingsPanelButtonInlineBasic.tsx create mode 100644 ts/components/dialog/user-settings/pages/HelpSettingsPage.tsx delete mode 100644 ts/components/settings/section/CategoryHelp.tsx diff --git a/ts/components/buttons/panel/PanelWithButtonInline.tsx b/ts/components/buttons/panel/PanelWithButtonInline.tsx index ae1eae8a0..f444e7f14 100644 --- a/ts/components/buttons/panel/PanelWithButtonInline.tsx +++ b/ts/components/buttons/panel/PanelWithButtonInline.tsx @@ -7,7 +7,10 @@ import { type GenericPanelButtonProps, } from './GenericPanelButtonWithAction'; -type PanelButtonOnRightProps = Pick & +export type PanelWithButtonInlineProps = Pick< + GenericPanelButtonProps, + 'rowDataTestId' | 'textElement' +> & Required> & { onClick: () => Promise; buttonDataTestId: SessionDataTestId; @@ -15,7 +18,7 @@ type PanelButtonOnRightProps = Pick { +export const PanelWithButtonInline = (props: PanelWithButtonInlineProps) => { const { onClick, buttonDataTestId, diff --git a/ts/components/dialog/user-settings/UserSettingsDialog.tsx b/ts/components/dialog/user-settings/UserSettingsDialog.tsx index 3fb6689d4..7458b8171 100644 --- a/ts/components/dialog/user-settings/UserSettingsDialog.tsx +++ b/ts/components/dialog/user-settings/UserSettingsDialog.tsx @@ -1,6 +1,7 @@ import { type UserSettingsModalState } from '../../../state/ducks/modalDialog'; import { ConversationSettingsPage } from './pages/ConversationSettingsPage'; import { DefaultSettingPage } from './pages/DefaultSettingsPage'; +import { HelpSettingsPage } from './pages/HelpSettingsPage'; import { NotificationsSettingsPage } from './pages/NotificationsSettingsPage'; import { PrivacySettingsPage } from './pages/PrivacySettingsPage'; @@ -18,6 +19,8 @@ export const UserSettingsDialog = (modalState: UserSettingsModalState) => { return ; case 'conversations': return ; + case 'help': + return ; default: return ; } diff --git a/ts/components/dialog/user-settings/components/SettingsExternalLinkBasic.tsx b/ts/components/dialog/user-settings/components/SettingsExternalLinkBasic.tsx new file mode 100644 index 000000000..e77fda20f --- /dev/null +++ b/ts/components/dialog/user-settings/components/SettingsExternalLinkBasic.tsx @@ -0,0 +1,64 @@ +import type { SettingsExternalLinkButtons } from 'react'; +import type { TokenSimpleNoArgs } from '../../../../localization/locales'; +import { PanelButtonTextWithSubText } from '../../../buttons/panel/PanelButton'; +import { tr } from '../../../../localization/localeTools'; +import { + GenericPanelButtonWithAction, + type GenericPanelButtonProps, +} from '../../../buttons/panel/GenericPanelButtonWithAction'; +import { SessionLucideIconButton } from '../../../icon/SessionIconButton'; +import { LUCIDE_ICONS_UNICODE } from '../../../icon/lucide'; + +const PanelExternalLinkButton = ( + props: Pick & { + onClick?: () => void; + baseDataTestId: SettingsExternalLinkButtons; + } +) => { + const { onClick, baseDataTestId, textElement } = props; + + return ( + + } + /> + ); +}; + +export function SettingsExternalLinkBasic({ + baseDataTestId, + onClick, + textToken, + subTextToken, +}: { + textToken: TokenSimpleNoArgs; + subTextToken: TokenSimpleNoArgs; + baseDataTestId: SettingsExternalLinkButtons; + onClick: () => Promise; +}) { + return ( + + } + // eslint-disable-next-line @typescript-eslint/no-misused-promises + onClick={onClick} + baseDataTestId={baseDataTestId} + /> + ); +} diff --git a/ts/components/dialog/user-settings/components/SettingsPanelButtonInlineBasic.tsx b/ts/components/dialog/user-settings/components/SettingsPanelButtonInlineBasic.tsx new file mode 100644 index 000000000..589d8e82a --- /dev/null +++ b/ts/components/dialog/user-settings/components/SettingsPanelButtonInlineBasic.tsx @@ -0,0 +1,42 @@ +import type { SettingsInlineButtons } from 'react'; +import type { TokenSimpleNoArgs } from '../../../../localization/locales'; +import { PanelButtonTextWithSubText } from '../../../buttons/panel/PanelButton'; +import { tr } from '../../../../localization/localeTools'; +import { + PanelWithButtonInline, + type PanelWithButtonInlineProps, +} from '../../../buttons/panel/PanelWithButtonInline'; + +export function SettingsPanelButtonInlineBasic({ + baseDataTestId, + onClick, + textToken, + subTextToken, + buttonColor, + buttonText, + disabled, +}: { + textToken: TokenSimpleNoArgs; + subTextToken: TokenSimpleNoArgs; + baseDataTestId: SettingsInlineButtons; +} & Pick) { + return ( + + } + // eslint-disable-next-line @typescript-eslint/no-misused-promises + onClick={onClick} + buttonColor={buttonColor} + buttonText={buttonText} + disabled={disabled} + rowDataTestId={`${baseDataTestId}-settings-row`} + buttonDataTestId={`${baseDataTestId}-settings-button`} + /> + ); +} diff --git a/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx b/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx index cbf1e9bce..5a990d013 100644 --- a/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx @@ -230,7 +230,7 @@ function AdminSection() { iconElement={} text={tr('sessionHelp')} onClick={() => { - throw new Error('Not implemented'); + dispatch(userSettingsModal({ userSettingsPage: 'help' })); }} dataTestId="help-settings-menu-item" /> diff --git a/ts/components/dialog/user-settings/pages/HelpSettingsPage.tsx b/ts/components/dialog/user-settings/pages/HelpSettingsPage.tsx new file mode 100644 index 000000000..7247003ed --- /dev/null +++ b/ts/components/dialog/user-settings/pages/HelpSettingsPage.tsx @@ -0,0 +1,94 @@ +import { useDispatch } from 'react-redux'; + +import { tr } from '../../../../localization/localeTools'; +import { type UserSettingsModalState } from '../../../../state/ducks/modalDialog'; +import { PanelButtonGroup, PanelLabelWithDescription } from '../../../buttons/panel/PanelButton'; +import { + ModalBasicHeader, + SessionWrapperModal, + WrapperModalWidth, +} from '../../../SessionWrapperModal'; +import { ModalBackButton } from '../../shared/ModalBackButton'; +import { + useUserSettingsBackAction, + useUserSettingsCloseAction, + useUserSettingsTitle, +} from './userSettingsHooks'; +import { SessionButtonColor } from '../../../basic/SessionButton'; +import { saveLogToDesktop } from '../../../../util/logger/renderer_process_logging'; +import { SettingsPanelButtonInlineBasic } from '../components/SettingsPanelButtonInlineBasic'; +import { SettingsExternalLinkBasic } from '../components/SettingsExternalLinkBasic'; +import { showLinkVisitWarningDialog } from '../../OpenUrlModal'; + +export function HelpSettingsPage(modalState: UserSettingsModalState) { + const backAction = useUserSettingsBackAction(modalState); + const closeAction = useUserSettingsCloseAction(modalState); + const title = useUserSettingsTitle(modalState); + + const dispatch = useDispatch(); + + return ( + : undefined} + /> + } + onClose={closeAction || undefined} + shouldOverflow={true} + allowOutsideClick={false} + $contentMinWidth={WrapperModalWidth.normal} + > + + + saveLogToDesktop()} + buttonColor={SessionButtonColor.Primary} + buttonText={tr('helpReportABugExportLogs')} + /> + + + + { + showLinkVisitWarningDialog('https://getsession.org/faq', dispatch); + }} + /> + { + showLinkVisitWarningDialog('https://getsession.org/translate', dispatch); + }} + /> + + { + showLinkVisitWarningDialog('https://getsession.org/survey', dispatch); + }} + /> + { + showLinkVisitWarningDialog('https://sessionapp.zendesk.com/hc/en-us', dispatch); + }} + /> + + + ); +} diff --git a/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx b/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx index f8980b0e0..b196c04df 100644 --- a/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx @@ -33,9 +33,9 @@ import { SettingsKey } from '../../../../data/settings-key'; import { SessionUtilUserProfile } from '../../../../session/utils/libsession/libsession_utils_user_profile'; import { getPasswordHash, Storage } from '../../../../util/storage'; import { SpacerXS } from '../../../basic/Text'; -import { PanelWithButtonInline } from '../../../buttons/panel/PanelWithButtonInline'; import { displayPasswordModal } from '../../../settings/SessionSettings'; import { SettingsToggleBasic } from '../components/SettingsToggleBasic'; +import { SettingsPanelButtonInlineBasic } from '../components/SettingsPanelButtonInlineBasic'; type WithPasswordUpdatedCb = { onPasswordUpdated: (action: string) => void }; @@ -113,34 +113,18 @@ function StaticTypingBubble({ width }: { width: string }) { function HasPasswordSubSection(props: WithPasswordUpdatedCb) { return ( - - } - rowDataTestId={'change-password-settings-row'} - buttonDataTestId={'change-password-settings-button'} - onClick={async () => { - displayPasswordModal('change', props.onPasswordUpdated); - }} + displayPasswordModal('change', props.onPasswordUpdated)} buttonColor={SessionButtonColor.Primary} buttonText={tr('change')} /> - - } - rowDataTestId={'remove-password-settings-row'} - buttonDataTestId={'remove-password-settings-button'} + { displayPasswordModal('remove', props.onPasswordUpdated); }} @@ -153,17 +137,10 @@ function HasPasswordSubSection(props: WithPasswordUpdatedCb) { function NoPasswordSubSection(props: WithPasswordUpdatedCb) { return ( - - } - rowDataTestId={'set-password-settings-row'} - buttonDataTestId={'set-password-settings-button'} + { displayPasswordModal('set', props.onPasswordUpdated); }} diff --git a/ts/components/leftpane/LeftPaneSettingSection.tsx b/ts/components/leftpane/LeftPaneSettingSection.tsx index dcf0343aa..ffc20aa8b 100644 --- a/ts/components/leftpane/LeftPaneSettingSection.tsx +++ b/ts/components/leftpane/LeftPaneSettingSection.tsx @@ -84,11 +84,6 @@ const categories: Array = ( title: tr('sessionConversations'), icon: { type: 'lucide', unicode: LUCIDE_ICONS_UNICODE.MESSAGE_SQUARE }, }, - { - id: 'message-requests', - title: tr('sessionMessageRequests'), - icon: { type: 'lucide', unicode: LUCIDE_ICONS_UNICODE.MESSAGE_SQUARE_WARNING }, - }, { id: 'appearance', title: tr('sessionAppearance'), @@ -127,8 +122,6 @@ const LeftPaneSettingsCategoryRow = ({ item }: { item: Categories }) => { padding={'0 var(--margins-xs)'} onClick={() => { switch (id) { - case 'message-requests': - break; default: dispatch(sectionActions.showSettingsSection(id)); } diff --git a/ts/components/settings/SessionSettings.tsx b/ts/components/settings/SessionSettings.tsx index 16e765641..6813f597c 100644 --- a/ts/components/settings/SessionSettings.tsx +++ b/ts/components/settings/SessionSettings.tsx @@ -10,7 +10,6 @@ import { sessionPassword } from '../../state/ducks/modalDialog'; import type { PasswordAction, SessionSettingCategory } from '../../types/ReduxTypes'; import { SettingsCategoryAppearance } from './section/CategoryAppearance'; import { CategoryConversations } from './section/CategoryConversations'; -import { SettingsCategoryHelp } from './section/CategoryHelp'; import { SettingsCategoryPermissions } from './section/CategoryPermissions'; import { SettingsCategoryRecoveryPassword } from './section/CategoryRecoveryPassword'; import { setDebugMode } from '../../state/ducks/debug'; @@ -113,16 +112,10 @@ const SettingInCategory = (props: { category: SessionSettingCategory }) => { return ; case 'appearance': return ; - - case 'help': - return ; case 'permissions': return ; case 'recovery-password': return ; - - // these are just buttons or modals and don't have screens - case 'message-requests': default: return null; } diff --git a/ts/components/settings/SessionSettingsHeader.tsx b/ts/components/settings/SessionSettingsHeader.tsx index bc8322dce..7dc54ad1a 100644 --- a/ts/components/settings/SessionSettingsHeader.tsx +++ b/ts/components/settings/SessionSettingsHeader.tsx @@ -32,19 +32,12 @@ export const SettingsHeader = (props: Props) => { case 'conversations': categoryTitleKey = 'sessionConversations'; break; - case 'help': - categoryTitleKey = 'sessionHelp'; - break; case 'permissions': categoryTitleKey = 'sessionPermissions'; break; case 'recovery-password': categoryTitleKey = 'sessionRecoveryPassword'; break; - // these are modals or other screens - case 'message-requests': - throw new Error(`no header for should be tried to be rendered for "${category}"`); - default: assertUnreachable(category, `SettingsHeader "${category}"`); } diff --git a/ts/components/settings/section/CategoryHelp.tsx b/ts/components/settings/section/CategoryHelp.tsx deleted file mode 100644 index 8e23fa951..000000000 --- a/ts/components/settings/section/CategoryHelp.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { tr } from '../../../localization/localeTools'; -import { saveLogToDesktop } from '../../../util/logger/renderer_process_logging'; -import { SessionButtonShape, SessionButtonType } from '../../basic/SessionButton'; - -import { SessionSettingButtonItem, SessionSettingsTitleWithLink } from '../SessionSettingListItem'; - -export const SettingsCategoryHelp = () => { - return ( - <> - { - void saveLogToDesktop(); - }} - buttonShape={SessionButtonShape.Square} - buttonType={SessionButtonType.Solid} - buttonText={tr('helpReportABugExportLogs')} - title={tr('helpReportABug')} - description={tr('helpReportABugExportLogsSaveToDesktopDescription')} - /> - - - - - - ); -}; diff --git a/ts/react.d.ts b/ts/react.d.ts index 01da47042..cb711f263 100644 --- a/ts/react.d.ts +++ b/ts/react.d.ts @@ -97,7 +97,12 @@ declare module 'react' { type SettingsRadio = `set-notifications-${'message' | 'name' | 'count'}`; type SettingsChevron = `blocked-contacts`; - type SettingsInlineButtons = 'set-password' | 'change-password' | 'remove-password'; + type SettingsInlineButtons = + | 'set-password' + | 'change-password' + | 'remove-password' + | 'export-logs'; + type SettingsExternalLinkButtons = 'faq' | 'translate' | 'support' | 'feedback'; type SettingsMenuItems = | 'message-requests' @@ -237,7 +242,7 @@ declare module 'react' { | 'modal-actions-container' | 'reveal-blocked-user-settings' | `${Sections}-section` - | `${SettingsToggles | SettingsInlineButtons | SettingsRadio | SettingsChevron}-settings-${'text' | 'sub-text' | 'toggle' | 'radio' | 'button' | 'chevron' | 'row'}` + | `${SettingsToggles | SettingsInlineButtons | SettingsRadio | SettingsChevron | SettingsExternalLinkButtons}-settings-${'text' | 'sub-text' | 'toggle' | 'radio' | 'button' | 'chevron' | 'row'}` // Buttons | `${Buttons}-button` diff --git a/ts/types/ReduxTypes.d.ts b/ts/types/ReduxTypes.d.ts index 5066ff8d2..bffa16277 100644 --- a/ts/types/ReduxTypes.d.ts +++ b/ts/types/ReduxTypes.d.ts @@ -7,11 +7,9 @@ export type SessionSettingCategory = | 'conversations' - | 'message-requests' | 'appearance' | 'permissions' - | 'recovery-password' - | 'help'; + | 'recovery-password'; export type PasswordAction = 'set' | 'change' | 'remove' | 'enter'; From 9f5fd85cbb12eb9824ddd34a3679489f514317b4 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Mon, 18 Aug 2025 14:21:16 +1000 Subject: [PATCH 08/18] feat: moved blocked contact to modal --- ts/components/buttons/panel/PanelButton.tsx | 3 +- .../user-settings/UserSettingsDialog.tsx | 6 + .../components/SettingsChevronBasic.tsx | 2 +- .../pages/BlockedContactsSettingsPage.tsx | 130 ++++++++++++++ .../pages/ConversationSettingsPage.tsx | 7 +- .../pages/DefaultSettingsPage.tsx | 2 +- .../pages/NotificationsSettingsPage.tsx | 4 +- .../pages/PreferencesSettingsPage.tsx | 151 ++++++++++++++++ .../user-settings/pages/userSettingsHooks.tsx | 3 + .../leftpane/LeftPaneSettingSection.tsx | 10 -- ts/components/settings/BlockedList.tsx | 169 ------------------ ts/components/settings/SessionSettings.tsx | 7 - .../settings/SessionSettingsHeader.tsx | 6 - .../section/CategoryConversations.tsx | 55 ------ .../settings/section/CategoryPermissions.tsx | 52 ------ ts/react.d.ts | 7 +- ts/session/utils/Toast.tsx | 13 +- ts/state/ducks/modalDialog.tsx | 1 + ts/types/ReduxTypes.d.ts | 6 +- 19 files changed, 314 insertions(+), 320 deletions(-) create mode 100644 ts/components/dialog/user-settings/pages/BlockedContactsSettingsPage.tsx create mode 100644 ts/components/dialog/user-settings/pages/PreferencesSettingsPage.tsx delete mode 100644 ts/components/settings/BlockedList.tsx delete mode 100644 ts/components/settings/section/CategoryConversations.tsx delete mode 100644 ts/components/settings/section/CategoryPermissions.tsx diff --git a/ts/components/buttons/panel/PanelButton.tsx b/ts/components/buttons/panel/PanelButton.tsx index a3ea337fa..b200b1e51 100644 --- a/ts/components/buttons/panel/PanelButton.tsx +++ b/ts/components/buttons/panel/PanelButton.tsx @@ -72,8 +72,9 @@ const StyledRoundedPanelButtonGroup = styled.div` `; const PanelButtonContainer = styled.div` + --panel-button-container-min-height: 50px; overflow: auto; - min-height: 50px; + min-height: var(--panel-button-container-min-height); max-height: 100%; `; diff --git a/ts/components/dialog/user-settings/UserSettingsDialog.tsx b/ts/components/dialog/user-settings/UserSettingsDialog.tsx index 7458b8171..696d15323 100644 --- a/ts/components/dialog/user-settings/UserSettingsDialog.tsx +++ b/ts/components/dialog/user-settings/UserSettingsDialog.tsx @@ -1,8 +1,10 @@ import { type UserSettingsModalState } from '../../../state/ducks/modalDialog'; +import { BlockedContactsSettingsPage } from './pages/BlockedContactsSettingsPage'; import { ConversationSettingsPage } from './pages/ConversationSettingsPage'; import { DefaultSettingPage } from './pages/DefaultSettingsPage'; import { HelpSettingsPage } from './pages/HelpSettingsPage'; import { NotificationsSettingsPage } from './pages/NotificationsSettingsPage'; +import { PreferencesSettingsPage } from './pages/PreferencesSettingsPage'; import { PrivacySettingsPage } from './pages/PrivacySettingsPage'; export const UserSettingsDialog = (modalState: UserSettingsModalState) => { @@ -21,6 +23,10 @@ export const UserSettingsDialog = (modalState: UserSettingsModalState) => { return ; case 'help': return ; + case 'preferences': + return ; + case 'blocked-contacts': + return ; default: return ; } diff --git a/ts/components/dialog/user-settings/components/SettingsChevronBasic.tsx b/ts/components/dialog/user-settings/components/SettingsChevronBasic.tsx index 1d756ac2d..a68211066 100644 --- a/ts/components/dialog/user-settings/components/SettingsChevronBasic.tsx +++ b/ts/components/dialog/user-settings/components/SettingsChevronBasic.tsx @@ -13,7 +13,7 @@ export function SettingsChevronBasic({ textToken: TokenSimpleNoArgs; subTextToken: TokenSimpleNoArgs; baseDataTestId: SettingsChevron; - onClick: () => Promise; + onClick: (() => Promise) | (() => void); }) { return ( { + return ( + + + + ); +}; + +export function BlockedContactsSettingsPage(modalState: UserSettingsModalState) { + const forceUpdate = useUpdate(); + const backAction = useUserSettingsBackAction(modalState); + const closeAction = useUserSettingsCloseAction(modalState); + const title = useUserSettingsTitle(modalState); + const dispatch = useDispatch(); + const [selectedIds, setSelectedIds] = useState>([]); + + async function unBlockThoseUsers() { + if (selectedIds.length) { + dispatch( + updateBlockOrUnblockModal({ + action: 'unblock', + pubkeys: selectedIds, + onConfirmed: () => { + // annoying, but until that BlockedList is in redux, we need to force a refresh of this component when a change is made. + setSelectedIds([]); + forceUpdate(); + }, + }) + ); + } + } + + const blocked = BlockedNumberController.getBlockedNumbers(); + const hasBlocked = blocked.length > 0; + const canUnblock = selectedIds.length > 0; + + return ( + : undefined} + /> + } + onClose={closeAction || undefined} + shouldOverflow={true} + allowOutsideClick={false} + $contentMinWidth={WrapperModalWidth.normal} + > + + {!blocked.length ? ( + + ) : ( + blocked.map(blockedEntry => { + return ( + { + setSelectedIds([...selectedIds, blockedEntry]); + }} + onUnselect={() => { + setSelectedIds(selectedIds.filter(id => id !== blockedEntry)); + }} + disableBg={true} + /> + ); + }) + )} + + {hasBlocked ? ( + + + + + ) : null} + + ); +} diff --git a/ts/components/dialog/user-settings/pages/ConversationSettingsPage.tsx b/ts/components/dialog/user-settings/pages/ConversationSettingsPage.tsx index ccd99a54b..fe6a87b48 100644 --- a/ts/components/dialog/user-settings/pages/ConversationSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/ConversationSettingsPage.tsx @@ -1,7 +1,10 @@ import useUpdate from 'react-use/lib/useUpdate'; import { useDispatch, useSelector } from 'react-redux'; -import { type UserSettingsModalState } from '../../../../state/ducks/modalDialog'; +import { + userSettingsModal, + type UserSettingsModalState, +} from '../../../../state/ducks/modalDialog'; import { PanelButtonGroup, PanelLabelWithDescription } from '../../../buttons/panel/PanelButton'; import { ModalBasicHeader, @@ -111,7 +114,7 @@ export function ConversationSettingsPage(modalState: UserSettingsModalState) { { - throw new Error('Not implemented'); + dispatch(userSettingsModal({ userSettingsPage: 'blocked-contacts' })); }} textToken={'conversationsBlockedContacts'} subTextToken={'blockedContactsManageDescription'} diff --git a/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx b/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx index 5a990d013..4844192e7 100644 --- a/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx @@ -206,7 +206,7 @@ function SettingsSection() { iconElement={} text={tr('preferences')} onClick={() => { - throw new Error('Not implemented'); + dispatch(userSettingsModal({ userSettingsPage: 'preferences' })); }} dataTestId="preferences-settings-menu-item" /> diff --git a/ts/components/dialog/user-settings/pages/NotificationsSettingsPage.tsx b/ts/components/dialog/user-settings/pages/NotificationsSettingsPage.tsx index fea832d73..df0dc7c5b 100644 --- a/ts/components/dialog/user-settings/pages/NotificationsSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/NotificationsSettingsPage.tsx @@ -126,8 +126,8 @@ function NotificationsContent({ } value={value} diff --git a/ts/components/dialog/user-settings/pages/PreferencesSettingsPage.tsx b/ts/components/dialog/user-settings/pages/PreferencesSettingsPage.tsx new file mode 100644 index 000000000..24f9c637f --- /dev/null +++ b/ts/components/dialog/user-settings/pages/PreferencesSettingsPage.tsx @@ -0,0 +1,151 @@ +import useUpdate from 'react-use/lib/useUpdate'; + +import { type UserSettingsModalState } from '../../../../state/ducks/modalDialog'; +import { + PanelButtonGroup, + PanelButtonTextWithSubText, + PanelLabelWithDescription, +} from '../../../buttons/panel/PanelButton'; +import { + ModalBasicHeader, + SessionWrapperModal, + WrapperModalWidth, +} from '../../../SessionWrapperModal'; +import { ModalBackButton } from '../../shared/ModalBackButton'; +import { + useUserSettingsBackAction, + useUserSettingsCloseAction, + useUserSettingsTitle, +} from './userSettingsHooks'; +import { SettingsToggleBasic } from '../components/SettingsToggleBasic'; +import { SettingsKey } from '../../../../data/settings-key'; +import { ToastUtils } from '../../../../session/utils'; +import { tr } from '../../../../localization/localeTools'; +import { PanelRadioButton } from '../../../buttons/panel/PanelRadioButton'; +import { useHasEnterSendEnabled } from '../../../../state/selectors/settings'; + +async function toggleStartInTray() { + try { + const newValue = !(await window.getStartInTray()); + + // make sure to write it here too, as this is the value used on the UI to mark the toggle as true/false + await window.setSettingValue(SettingsKey.settingsStartInTray, newValue); + await window.setStartInTray(newValue); + if (!newValue) { + ToastUtils.pushRestartNeeded(); + } + } catch (e) { + window.log.warn('start in tray change error:', e); + } +} + +function SendWithShiftEnter() { + const initialSetting = useHasEnterSendEnabled(); + const selectedWithSettingTrue = 'enterForNewLine'; + const selectedWithSettingFalse = 'enterForSend'; + const forceUpdate = useUpdate(); + + const selected = initialSetting ? selectedWithSettingTrue : selectedWithSettingFalse; + + const items = [ + { + text: tr('conversationsSendWithEnterKey'), + subText: tr('conversationsSendWithEnterKeyDescription'), + value: selectedWithSettingFalse, + }, + { + text: tr('conversationsSendWithShiftEnter'), + subText: tr('conversationsEnterNewLine'), + value: selectedWithSettingTrue, + }, + ] as const; + + return ( + <> + + + {items.map(({ value, text, subText }) => { + return ( + + } + value={value} + isSelected={selected === value} + // eslint-disable-next-line @typescript-eslint/no-misused-promises + onSelect={async () => { + await window.setSettingValue( + SettingsKey.hasShiftSendEnabled, + value === selectedWithSettingTrue + ); + forceUpdate(); + }} + rowDataTestId={`send-with-${value}-settings-row`} + radioInputDataTestId={`send-with-${value}-settings-radio`} + /> + ); + })} + + + ); +} + +export function PreferencesSettingsPage(modalState: UserSettingsModalState) { + const backAction = useUserSettingsBackAction(modalState); + const closeAction = useUserSettingsCloseAction(modalState); + const title = useUserSettingsTitle(modalState); + const isStartInTrayActive = Boolean(window.getSettingValue(SettingsKey.settingsStartInTray)); + const forceUpdate = useUpdate(); + + return ( + : undefined} + /> + } + onClose={closeAction || undefined} + shouldOverflow={true} + allowOutsideClick={false} + $contentMinWidth={WrapperModalWidth.normal} + > + + + { + const old = Boolean(window.getSettingValue(SettingsKey.settingsAutoUpdate)); + await window.setSettingValue(SettingsKey.settingsAutoUpdate, !old); + forceUpdate(); + }} + active={Boolean(window.getSettingValue(SettingsKey.settingsAutoUpdate))} + /> + + + + { + await toggleStartInTray(); + forceUpdate(); + }} + active={isStartInTrayActive} + /> + + + + ); +} diff --git a/ts/components/dialog/user-settings/pages/userSettingsHooks.tsx b/ts/components/dialog/user-settings/pages/userSettingsHooks.tsx index 0eb20622d..b75e96af0 100644 --- a/ts/components/dialog/user-settings/pages/userSettingsHooks.tsx +++ b/ts/components/dialog/user-settings/pages/userSettingsHooks.tsx @@ -17,6 +17,8 @@ export function useUserSettingsTitle(page: UserSettingsModalState | undefined) { return tr('sessionNotifications'); case 'clear-data': return tr('sessionClearData'); + case 'blocked-contacts': + return tr('conversationsBlockedContacts'); case 'conversations': return tr('sessionConversations'); case 'message-requests': @@ -55,6 +57,7 @@ export function useUserSettingsCloseAction(props: UserSettingsModalState) { case 'help': case 'clear-data': case 'preferences': + case 'blocked-contacts': return () => dispatch(userSettingsModal(null)); default: diff --git a/ts/components/leftpane/LeftPaneSettingSection.tsx b/ts/components/leftpane/LeftPaneSettingSection.tsx index ffc20aa8b..887a1379d 100644 --- a/ts/components/leftpane/LeftPaneSettingSection.tsx +++ b/ts/components/leftpane/LeftPaneSettingSection.tsx @@ -79,21 +79,11 @@ type Categories = { const categories: Array = ( [ - { - id: 'conversations', - title: tr('sessionConversations'), - icon: { type: 'lucide', unicode: LUCIDE_ICONS_UNICODE.MESSAGE_SQUARE }, - }, { id: 'appearance', title: tr('sessionAppearance'), icon: { type: 'lucide', unicode: LUCIDE_ICONS_UNICODE.PAINTBRUSH_VERTICAL }, }, - { - id: 'permissions', - title: tr('sessionPermissions'), - icon: { type: 'lucide', unicode: LUCIDE_ICONS_UNICODE.CIRCLE_CHECK }, - }, ] as const satisfies Array> ).map(m => ({ ...m, diff --git a/ts/components/settings/BlockedList.tsx b/ts/components/settings/BlockedList.tsx deleted file mode 100644 index 5a952d1bc..000000000 --- a/ts/components/settings/BlockedList.tsx +++ /dev/null @@ -1,169 +0,0 @@ -import { useState } from 'react'; -import { useDispatch } from 'react-redux'; -import useUpdate from 'react-use/lib/useUpdate'; -import styled from 'styled-components'; -import { useSet } from '../../hooks/useSet'; -import { updateBlockOrUnblockModal } from '../../state/ducks/modalDialog'; -import { BlockedNumberController } from '../../util'; -import { MemberListItem } from '../MemberListItem'; -import { Localizer } from '../basic/Localizer'; -import { SessionButton, SessionButtonColor } from '../basic/SessionButton'; -import { SpacerLG, SpacerSM } from '../basic/Text'; -import { SessionSettingsItemWrapper, SettingsTitleAndDescription } from './SessionSettingListItem'; -import { SessionLucideIconButton } from '../icon/SessionIconButton'; -import { LUCIDE_ICONS_UNICODE } from '../icon/lucide'; -import { tr } from '../../localization/localeTools'; - -const BlockedEntriesContainer = styled.div` - display: flex; - flex-direction: column; - flex: 1; - width: 100%; -`; - -const BlockedEntriesRoundedContainer = styled.div` - background: var(--background-secondary-color); - border: 1px solid var(--border-color); - border-radius: 16px; - padding: var(--margins-lg); - margin: 0 var(--margins-lg); -`; - -const BlockedContactListTitle = styled.div` - display: flex; - justify-content: space-between; - align-items: center; -`; - -const BlockedContactListTitleButtons = styled.div` - display: flex; - align-items: center; - min-height: 34px; // height of the unblock button -`; - -export const StyledBlockedSettingItem = styled.div<{ clickable: boolean; expanded: boolean }>` - font-size: var(--font-size-md); - cursor: ${props => (props.clickable ? 'pointer' : 'unset')}; - ${props => props.expanded && 'padding-bottom: var(--margins-lg);'} -`; - -const BlockedEntries = (props: { - blockedNumbers: Array; - selectedIds: Array; - addToSelected: (id: string) => void; - removeFromSelected: (id: string) => void; -}) => { - const { addToSelected, blockedNumbers, removeFromSelected, selectedIds } = props; - return ( - - - {blockedNumbers.map(blockedEntry => { - return ( - - ); - })} - - - ); -}; - -const NoBlockedContacts = () => { - return ( -
- -
- ); -}; - -export const BlockedContactsList = () => { - const dispatch = useDispatch(); - const [expanded, setExpanded] = useState(false); - const { - uniqueValues: selectedIds, - addTo: addToSelected, - removeFrom: removeFromSelected, - empty: emptySelected, - } = useSet([]); - - const forceUpdate = useUpdate(); - - const hasAtLeastOneSelected = Boolean(selectedIds.length); - const blockedNumbers = BlockedNumberController.getBlockedNumbers(); - const noBlockedNumbers = !blockedNumbers.length; - - function toggleUnblockList() { - if (blockedNumbers.length) { - setExpanded(!expanded); - } - } - - async function unBlockThoseUsers() { - if (selectedIds.length) { - dispatch( - updateBlockOrUnblockModal({ - action: 'unblock', - pubkeys: selectedIds, - onConfirmed: () => { - // annoying, but until that BlockedList is in redux, we need to force a refresh of this component when a change is made. - emptySelected(); - forceUpdate(); - }, - }) - ); - } - } - - return ( - - - - - {noBlockedNumbers ? ( - - ) : ( - - {hasAtLeastOneSelected && expanded ? ( - - ) : null} - - - - )} - - - {expanded && !noBlockedNumbers ? ( - <> - - - - ) : null} - - ); -}; diff --git a/ts/components/settings/SessionSettings.tsx b/ts/components/settings/SessionSettings.tsx index 6813f597c..1846eeade 100644 --- a/ts/components/settings/SessionSettings.tsx +++ b/ts/components/settings/SessionSettings.tsx @@ -9,8 +9,6 @@ import { SessionIconButton } from '../icon'; import { sessionPassword } from '../../state/ducks/modalDialog'; import type { PasswordAction, SessionSettingCategory } from '../../types/ReduxTypes'; import { SettingsCategoryAppearance } from './section/CategoryAppearance'; -import { CategoryConversations } from './section/CategoryConversations'; -import { SettingsCategoryPermissions } from './section/CategoryPermissions'; import { SettingsCategoryRecoveryPassword } from './section/CategoryRecoveryPassword'; import { setDebugMode } from '../../state/ducks/debug'; import { showLinkVisitWarningDialog } from '../dialog/OpenUrlModal'; @@ -107,13 +105,8 @@ const SettingInCategory = (props: { category: SessionSettingCategory }) => { const { category } = props; switch (category) { - // special case for blocked user - case 'conversations': - return ; case 'appearance': return ; - case 'permissions': - return ; case 'recovery-password': return ; default: diff --git a/ts/components/settings/SessionSettingsHeader.tsx b/ts/components/settings/SessionSettingsHeader.tsx index 7dc54ad1a..827555ebc 100644 --- a/ts/components/settings/SessionSettingsHeader.tsx +++ b/ts/components/settings/SessionSettingsHeader.tsx @@ -29,12 +29,6 @@ export const SettingsHeader = (props: Props) => { case 'appearance': categoryTitleKey = 'sessionAppearance'; break; - case 'conversations': - categoryTitleKey = 'sessionConversations'; - break; - case 'permissions': - categoryTitleKey = 'sessionPermissions'; - break; case 'recovery-password': categoryTitleKey = 'sessionRecoveryPassword'; break; diff --git a/ts/components/settings/section/CategoryConversations.tsx b/ts/components/settings/section/CategoryConversations.tsx deleted file mode 100644 index 808f06d03..000000000 --- a/ts/components/settings/section/CategoryConversations.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { SettingsKey } from '../../../data/settings-key'; -import { useHasEnterSendEnabled } from '../../../state/selectors/settings'; -import { SessionRadioGroup, SessionRadioItems } from '../../basic/SessionRadioGroup'; -import { BlockedContactsList } from '../BlockedList'; -import { SessionSettingsItemWrapper } from '../SessionSettingListItem'; -import { tr } from '../../../localization/localeTools'; - -const EnterKeyFunctionSetting = () => { - const initialSetting = useHasEnterSendEnabled(); - const selectedWithSettingTrue = 'enterForNewLine'; - - const items: SessionRadioItems = [ - { - label: tr('conversationsEnterSends'), - value: 'enterForSend', - inputDataTestId: 'input-enterForSend', - labelDataTestId: 'label-enterForSend', - }, - { - label: tr('conversationsEnterNewLine'), - value: selectedWithSettingTrue, - inputDataTestId: `input-${selectedWithSettingTrue}`, - labelDataTestId: `label-${selectedWithSettingTrue}`, - }, - ]; - - return ( - - { - void window.setSettingValue( - SettingsKey.hasShiftSendEnabled, - selectedRadioValue === selectedWithSettingTrue - ); - }} - /> - - ); -}; - -export const CategoryConversations = () => { - return ( - <> - - - - ); -}; diff --git a/ts/components/settings/section/CategoryPermissions.tsx b/ts/components/settings/section/CategoryPermissions.tsx deleted file mode 100644 index 9737d266a..000000000 --- a/ts/components/settings/section/CategoryPermissions.tsx +++ /dev/null @@ -1,52 +0,0 @@ -/* eslint-disable @typescript-eslint/no-misused-promises */ - -import useUpdate from 'react-use/lib/useUpdate'; -import { SettingsKey } from '../../../data/settings-key'; -import { ToastUtils } from '../../../session/utils'; - -import { SessionToggleWithDescription } from '../SessionSettingListItem'; -import { tr } from '../../../localization/localeTools'; - -async function toggleStartInTray() { - try { - const newValue = !(await window.getStartInTray()); - - // make sure to write it here too, as this is the value used on the UI to mark the toggle as true/false - await window.setSettingValue(SettingsKey.settingsStartInTray, newValue); - await window.setStartInTray(newValue); - if (!newValue) { - ToastUtils.pushRestartNeeded(); - } - } catch (e) { - window.log.warn('start in tray change error:', e); - } -} - -export const SettingsCategoryPermissions = () => { - const forceUpdate = useUpdate(); - const isStartInTrayActive = Boolean(window.getSettingValue(SettingsKey.settingsStartInTray)); - - return ( - <> - { - const old = Boolean(window.getSettingValue(SettingsKey.settingsAutoUpdate)); - await window.setSettingValue(SettingsKey.settingsAutoUpdate, !old); - forceUpdate(); - }} - title={tr('permissionsAutoUpdate')} - description={tr('permissionsAutoUpdateDescription')} - active={Boolean(window.getSettingValue(SettingsKey.settingsAutoUpdate))} - /> - { - await toggleStartInTray(); - forceUpdate(); - }} - title={tr('permissionsKeepInSystemTray')} - description={tr('permissionsKeepInSystemTrayDescription')} - active={isStartInTrayActive} - /> - - ); -}; diff --git a/ts/react.d.ts b/ts/react.d.ts index cb711f263..4c5ce7f76 100644 --- a/ts/react.d.ts +++ b/ts/react.d.ts @@ -92,9 +92,12 @@ declare module 'react' { | 'audio-notifications' | 'audio-message-autoplay' | 'spell-check' - | 'conversation-trimming'; + | 'conversation-trimming' + | 'auto-update'; - type SettingsRadio = `set-notifications-${'message' | 'name' | 'count'}`; + type SettingsRadio = + | `set-notifications-${'message' | 'name' | 'count'}` + | `send-with-${'enterForSend' | 'enterForNewLine'}`; type SettingsChevron = `blocked-contacts`; type SettingsInlineButtons = diff --git a/ts/session/utils/Toast.tsx b/ts/session/utils/Toast.tsx index 92315f983..00d2972bc 100644 --- a/ts/session/utils/Toast.tsx +++ b/ts/session/utils/Toast.tsx @@ -1,8 +1,8 @@ import { toast } from 'react-toastify'; import { SessionToast, SessionToastType } from '../../components/basic/SessionToast'; -import { sectionActions, SectionType } from '../../state/ducks/section'; import { getPromotedGroupUpdateChangeStr } from '../../models/groupUpdate'; import { tStripped, tStrippedWithObj } from '../../localization/localeTools'; +import { userSettingsModal } from '../../state/ducks/modalDialog'; // if you push a toast manually with toast...() be sure to set the type attribute of the SessionToast component export function pushToastError(id: string, description: string) { @@ -113,9 +113,8 @@ export function pushedMissedCall(userName: string) { pushToastInfo('missedCall', tStripped('callsMissedCallFrom', { name: userName })); } -const openPermissionsSettings = () => { - window.inboxStore?.dispatch(sectionActions.showLeftPaneSection(SectionType.Settings)); - window.inboxStore?.dispatch(sectionActions.showSettingsSection('permissions')); +const openPrivacySettings = () => { + window.inboxStore?.dispatch(userSettingsModal({ userSettingsPage: 'privacy' })); }; export function pushedMissedCallCauseOfPermission(conversationName: string) { @@ -126,7 +125,7 @@ export function pushedMissedCallCauseOfPermission(conversationName: string) { name: conversationName, })} type={SessionToastType.Info} - onToastClick={openPermissionsSettings} + onToastClick={openPrivacySettings} />, { toastId: id, updateId: id, autoClose: 10000 } ); @@ -136,7 +135,7 @@ export function pushVideoCallPermissionNeeded() { pushToastInfo( 'videoCallPermissionNeeded', tStripped('callsPermissionsRequiredDescription'), - openPermissionsSettings + openPrivacySettings ); } @@ -144,7 +143,7 @@ export function pushAudioPermissionNeeded() { pushToastInfo( 'audioPermissionNeeded', tStripped('permissionsMicrophoneAccessRequiredDesktop'), - openPermissionsSettings + openPrivacySettings ); } diff --git a/ts/state/ducks/modalDialog.tsx b/ts/state/ducks/modalDialog.tsx index 1248b1f69..043c0e44b 100644 --- a/ts/state/ducks/modalDialog.tsx +++ b/ts/state/ducks/modalDialog.tsx @@ -21,6 +21,7 @@ export type UserSettingsPage = | 'appearance' | 'recovery-password' | 'help' + | 'blocked-contacts' | 'clear-data' | 'preferences'; diff --git a/ts/types/ReduxTypes.d.ts b/ts/types/ReduxTypes.d.ts index bffa16277..d519e0126 100644 --- a/ts/types/ReduxTypes.d.ts +++ b/ts/types/ReduxTypes.d.ts @@ -5,11 +5,7 @@ * e.g. import type { YourTypeHere } from 'path/to/ReduxTypes'; */ -export type SessionSettingCategory = - | 'conversations' - | 'appearance' - | 'permissions' - | 'recovery-password'; +export type SessionSettingCategory = 'appearance' | 'recovery-password'; export type PasswordAction = 'set' | 'change' | 'remove' | 'enter'; From 7f885a17c1589d528897d578b2e4470680d57ad7 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Mon, 18 Aug 2025 14:45:52 +1000 Subject: [PATCH 09/18] chore: refactored how margins in modal buttons work --- ts/components/SessionPasswordPrompt.tsx | 4 +- ts/components/SessionWrapperModal.tsx | 11 +++--- ts/components/calling/IncomingCallDialog.tsx | 2 +- ts/components/dialog/BanOrUnbanUserDialog.tsx | 2 +- ts/components/dialog/DeleteAccountModal.tsx | 2 +- .../dialog/EditProfilePictureModal.tsx | 2 +- ts/components/dialog/EnterPasswordModal.tsx | 2 +- .../dialog/HideRecoveryPasswordDialog.tsx | 2 +- ts/components/dialog/InviteContactsDialog.tsx | 2 +- ts/components/dialog/ModeratorsAddDialog.tsx | 2 +- .../dialog/ModeratorsRemoveDialog.tsx | 2 +- .../dialog/OnionStatusPathDialog.tsx | 2 +- ts/components/dialog/OpenUrlModal.tsx | 2 +- ts/components/dialog/QuitModal.tsx | 2 +- ts/components/dialog/ReactClearAllModal.tsx | 2 +- ts/components/dialog/SessionConfirm.tsx | 2 +- .../dialog/SessionNicknameDialog.tsx | 2 +- ts/components/dialog/SessionProInfoModal.tsx | 1 + .../dialog/SessionSetPasswordDialog.tsx | 2 +- .../dialog/TermsOfServicePrivacyDialog.tsx | 2 +- .../UpdateConversationDetailsDialog.tsx | 2 +- .../dialog/UpdateGroupMembersDialog.tsx | 2 +- ts/components/dialog/UserProfileModal.tsx | 5 ++- .../blockOrUnblock/BlockOrUnblockDialog.tsx | 2 +- .../DisappearingMessagesPage.tsx | 9 ++++- .../pages/notifications/NotificationPage.tsx | 4 +- .../pages/BlockedContactsSettingsPage.tsx | 37 ++++++++----------- 27 files changed, 57 insertions(+), 54 deletions(-) diff --git a/ts/components/SessionPasswordPrompt.tsx b/ts/components/SessionPasswordPrompt.tsx index d6826fdc0..79dd111ab 100644 --- a/ts/components/SessionPasswordPrompt.tsx +++ b/ts/components/SessionPasswordPrompt.tsx @@ -56,7 +56,7 @@ function pushToastError(id: string, description: string) { function ClearDataViewButtons({ onCancel }: { onCancel: () => void }) { return ( - + + {showResetElements && ( { return ( { } buttonChildren={ - + } onClose={onClose} buttonChildren={ - + { onClose={onClickCancelHandler} topAnchor="center" buttonChildren={ - + } buttonChildren={ - + { headerChildren={} $contentMinWidth={WrapperModalWidth.narrow} buttonChildren={ - + } onClose={onClose} buttonChildren={ - + diff --git a/ts/components/dialog/InviteContactsDialog.tsx b/ts/components/dialog/InviteContactsDialog.tsx index ddf1ca5c7..2d86159d6 100644 --- a/ts/components/dialog/InviteContactsDialog.tsx +++ b/ts/components/dialog/InviteContactsDialog.tsx @@ -179,7 +179,7 @@ const InviteContactsDialogInner = (props: Props) => { headerChildren={} modalDataTestId="invite-contacts-dialog" buttonChildren={ - + { headerChildren={} onClose={onClose} buttonChildren={ - + { headerChildren={} onClose={closeDialog} buttonChildren={ - + { topAnchor="25vh" headerChildren={} buttonChildren={ - + + { headerChildren={} onClose={onClickClose} buttonChildren={ - + { onClose={handleClose} headerChildren={} buttonChildren={ - + { topAnchor="35vh" onClose={onClickClose} buttonChildren={ - + { onClose={onClickClose} topAnchor="25vh" buttonChildren={ - + { $contentMinWidth={WrapperModalWidth.narrow} $contentMaxWidth={WrapperModalWidth.narrow} buttonChildren={ - + } onClose={onClose} buttonChildren={ - + } onClose={closeDialog} buttonChildren={ - + { $contentMinWidth={WrapperModalWidth.wide} $contentMaxWidth={WrapperModalWidth.wide} buttonChildren={ - + {weAreAdmin && ( } onClose={closeDialog} buttonChildren={ - + )} diff --git a/ts/components/dialog/blockOrUnblock/BlockOrUnblockDialog.tsx b/ts/components/dialog/blockOrUnblock/BlockOrUnblockDialog.tsx index 3a903f50c..68f2fe4c0 100644 --- a/ts/components/dialog/blockOrUnblock/BlockOrUnblockDialog.tsx +++ b/ts/components/dialog/blockOrUnblock/BlockOrUnblockDialog.tsx @@ -95,7 +95,7 @@ export const BlockOrUnblockDialog = ({ pubkeys, action, onConfirmed }: NonNullab headerChildren={} onClose={closeModal} buttonChildren={ - + + {loading ? ( ) : ( + + + + ) : null + } > {!blocked.length ? ( @@ -113,18 +120,6 @@ export function BlockedContactsSettingsPage(modalState: UserSettingsModalState) }) )} - {hasBlocked ? ( - - - - - ) : null}
); } From fe57721fe24d74e80a5896635146637adfee0dfb Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Tue, 19 Aug 2025 16:18:35 +1000 Subject: [PATCH 10/18] feat: moved appearance section and slider for zoom factor --- package.json | 1 - stylesheets/_session_slider.scss | 260 ---------- stylesheets/manifest.scss | 1 - ts/components/SessionContextMenuContainer.tsx | 16 + ts/components/basic/SessionRadio.tsx | 54 +- .../panel/GenericPanelButtonWithAction.tsx | 5 +- .../calling/DraggableCallContainer.tsx | 10 +- .../conversation/SessionEmojiPanel.tsx | 5 +- .../user-settings/UserSettingsDialog.tsx | 3 + .../pages/AppearanceSettingsPage.tsx | 464 ++++++++++++++++++ .../pages/DefaultSettingsPage.tsx | 2 +- ts/components/leftpane/ActionsPanel.tsx | 20 +- ts/components/settings/SessionSettings.tsx | 3 - .../settings/SessionSettingsHeader.tsx | 3 - .../settings/SettingsThemeSwitcher.tsx | 144 ------ .../settings/ZoomingSessionSlider.tsx | 54 -- .../settings/section/CategoryAppearance.tsx | 51 -- ts/hooks/useZoomingShortcut.ts | 45 ++ ts/react.d.ts | 6 +- ts/session/constants.ts | 7 + ts/state/ducks/modalDialog.tsx | 2 +- ts/state/ducks/section.tsx | 8 - ts/state/selectors/primaryColor.ts | 5 + ts/types/ReduxTypes.d.ts | 2 +- yarn.lock | 26 +- 25 files changed, 567 insertions(+), 630 deletions(-) delete mode 100644 stylesheets/_session_slider.scss create mode 100644 ts/components/dialog/user-settings/pages/AppearanceSettingsPage.tsx delete mode 100644 ts/components/settings/SettingsThemeSwitcher.tsx delete mode 100644 ts/components/settings/ZoomingSessionSlider.tsx delete mode 100644 ts/components/settings/section/CategoryAppearance.tsx create mode 100644 ts/hooks/useZoomingShortcut.ts diff --git a/package.json b/package.json index 63ca154ce..92218de79 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,6 @@ "pino": "^9.6.0", "protobufjs": "^7.4.0", "punycode": "^2.3.1", - "rc-slider": "^11.1.8", "react": "18.3.1", "react-contexify": "^6.0.0", "react-dom": "18.3.1", diff --git a/stylesheets/_session_slider.scss b/stylesheets/_session_slider.scss deleted file mode 100644 index e209cff59..000000000 --- a/stylesheets/_session_slider.scss +++ /dev/null @@ -1,260 +0,0 @@ -.slider { - &-wrapper { - display: flex; - align-items: center; - margin: 20px 10px; - } - - &-info { - display: block; - margin-inline-start: 20px; - text-align: center; - - p { - white-space: nowrap; - } - } -} - -.rc-slider { - position: relative; - height: 14px; - padding: 5px 0; - width: 100%; - border-radius: 6px; - -ms-touch-action: none; - touch-action: none; - box-sizing: border-box; - -webkit-tap-highlight-color: var(--transparent-color); -} -.rc-slider * { - box-sizing: border-box; - -webkit-tap-highlight-color: var(--transparent-color); -} -.rc-slider-rail { - position: absolute; - width: 100%; - background: var(--zoom-bar-track-color); - - height: 8px; - border-radius: 6px; - margin: 0px; -} -.rc-slider-handle { - transition: var(--default-duration); - position: absolute; - width: 6px; - height: 25px; - cursor: pointer; - cursor: -webkit-grab; - margin-top: -9.5px; - cursor: grab; - border-radius: 4px; - background-color: var(--zoom-bar-thumb-color); - -ms-touch-action: pan-x; - touch-action: pan-x; -} -.rc-slider-handle:focus { - border-color: var(--zoom-bar-thumb-color); - box-shadow: none; - outline: none; -} -.rc-slider-handle-click-focused:focus { - border-color: var(--zoom-bar-thumb-color); - box-shadow: unset; -} -.rc-slider-handle:hover { - border-color: var(--zoom-bar-thumb-color); -} -.rc-slider-handle:active { - border-color: var(--zoom-bar-thumb-color); - box-shadow: none; - cursor: -webkit-grabbing; - cursor: grabbing; -} -.rc-slider-mark { - position: absolute; - top: 18px; - left: 0; - width: 100%; - font-size: 12px; -} -.rc-slider-mark-text { - position: absolute; - display: inline-block; - vertical-align: middle; - text-align: center; - cursor: pointer; - color: var(--text-secondary-color); -} -.rc-slider-mark-text-active { - color: var(--text-primary-color); -} -.rc-slider-step { - position: absolute; - width: 100%; - height: 4px; - top: -4px; - background: transparent; - margin-left: -3px; -} -.rc-slider-dot { - position: absolute; - bottom: -2px; - width: 3px; - height: 6px; - background: var(--zoom-bar-interval-color); - margin-left: 3px; - cursor: pointer; - border-radius: 2px; - vertical-align: middle; -} - -.rc-slider-dot-active { - border-color: var(--primary-color); -} - -.rc-slider-disabled { - background-color: var(--zoom-bar-track-color); -} -.rc-slider-disabled .rc-slider-handle, -.rc-slider-disabled .rc-slider-dot { - border-color: var(--zoom-bar-interval-color); - box-shadow: none; - background-color: var(--zoom-bar-interval-color); - cursor: not-allowed; -} -.rc-slider-disabled .rc-slider-mark-text, -.rc-slider-disabled .rc-slider-dot { - cursor: not-allowed !important; -} -.rc-slider-vertical { - width: 14px; - height: 100%; - padding: 0 5px; -} -.rc-slider-vertical .rc-slider-rail { - height: 100%; - width: 4px; -} -.rc-slider-vertical .rc-slider-handle { - margin-left: -5px; - -ms-touch-action: pan-y; - touch-action: pan-y; -} -.rc-slider-vertical .rc-slider-mark { - top: 0; - left: 18px; - height: 100%; -} -.rc-slider-vertical .rc-slider-step { - height: 100%; - width: 4px; -} -.rc-slider-vertical .rc-slider-dot { - left: 2px; - margin-bottom: -4px; -} -.rc-slider-vertical .rc-slider-dot:first-child { - margin-bottom: -4px; -} -.rc-slider-vertical .rc-slider-dot:last-child { - margin-bottom: -4px; -} -.rc-slider-tooltip-zoom-down-enter, -.rc-slider-tooltip-zoom-down-appear { - animation-duration: var(--default-duration); - animation-fill-mode: both; - display: block !important; - animation-play-state: paused; -} -.rc-slider-tooltip-zoom-down-leave { - animation-duration: var(--default-duration); - animation-fill-mode: both; - display: block !important; - animation-play-state: paused; -} -.rc-slider-tooltip-zoom-down-enter.rc-slider-tooltip-zoom-down-enter-active, -.rc-slider-tooltip-zoom-down-appear.rc-slider-tooltip-zoom-down-appear-active { - animation-name: rcSliderTooltipZoomDownIn; - animation-play-state: running; -} -.rc-slider-tooltip-zoom-down-leave.rc-slider-tooltip-zoom-down-leave-active { - animation-name: rcSliderTooltipZoomDownOut; - animation-play-state: running; -} -.rc-slider-tooltip-zoom-down-enter, -.rc-slider-tooltip-zoom-down-appear { - transform: scale(0, 0); - animation-timing-function: cubic-bezier(0.23, 1, 0.32, 1); -} -.rc-slider-tooltip-zoom-down-leave { - animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); -} -@keyframes rcSliderTooltipZoomDownIn { - 0% { - opacity: 0; - transform-origin: 50% 100%; - transform: scale(0, 0); - } - 100% { - transform-origin: 50% 100%; - transform: scale(1, 1); - } -} -@keyframes rcSliderTooltipZoomDownOut { - 0% { - transform-origin: 50% 100%; - transform: scale(1, 1); - } - 100% { - opacity: 0; - transform-origin: 50% 100%; - transform: scale(0, 0); - } -} -.rc-slider-tooltip { - position: absolute; - left: -9999px; - top: -9999px; - visibility: visible; - box-sizing: border-box; - -webkit-tap-highlight-color: var(--transparent-color); -} -.rc-slider-tooltip * { - box-sizing: border-box; - -webkit-tap-highlight-color: var(--transparent-color); -} -.rc-slider-tooltip-hidden { - display: none; -} -.rc-slider-tooltip-placement-top { - padding: 4px 0 8px 0; -} -.rc-slider-tooltip-inner { - padding: 6px 2px; - min-width: 24px; - height: 24px; - font-size: 12px; - line-height: 1; - color: var(--text-primary-color); - text-align: center; - text-decoration: none; - background-color: var(--background-primary-color); - border-radius: 6px; - box-shadow: none; -} -.rc-slider-tooltip-arrow { - position: absolute; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; -} -.rc-slider-tooltip-placement-top .rc-slider-tooltip-arrow { - bottom: 4px; - left: 50%; - margin-left: -4px; - border-width: 4px 4px 0; - border-top-color: var(--background-primary-color); -} diff --git a/stylesheets/manifest.scss b/stylesheets/manifest.scss index 0f45ec873..e8add7f23 100644 --- a/stylesheets/manifest.scss +++ b/stylesheets/manifest.scss @@ -28,5 +28,4 @@ @import 'session_theme'; @import 'session_left_pane'; -@import 'session_slider'; @import 'session_conversation'; diff --git a/ts/components/SessionContextMenuContainer.tsx b/ts/components/SessionContextMenuContainer.tsx index c807754b2..b5caa21f3 100644 --- a/ts/components/SessionContextMenuContainer.tsx +++ b/ts/components/SessionContextMenuContainer.tsx @@ -4,6 +4,8 @@ export const SessionContextMenuContainer = styled.div.attrs({ // custom props })` .contexify { + --contexify-activeItem-bgColor: var(--context-menu-background-hover-color); + --contexify-activeItem-color: var(--context-menu-text-hover-color); // be sure it is more than the one set for the More Information screen of messages z-index: 30; min-width: 200px; @@ -36,3 +38,17 @@ export const SessionContextMenuContainer = styled.div.attrs({ } } `; + +export const SessionContextMenuContainerItemsCentered = styled(SessionContextMenuContainer)` + .contexify { + .contexify_item { + width: 100%; + place-items: center; + } + + .contexify_itemContent { + width: 100%; + justify-content: center; + } + } +`; diff --git a/ts/components/basic/SessionRadio.tsx b/ts/components/basic/SessionRadio.tsx index e73332fd3..642ea280a 100644 --- a/ts/components/basic/SessionRadio.tsx +++ b/ts/components/basic/SessionRadio.tsx @@ -1,4 +1,4 @@ -import { ChangeEvent, SessionDataTestId, type MouseEventHandler } from 'react'; +import { SessionDataTestId, type MouseEventHandler } from 'react'; import styled, { CSSProperties } from 'styled-components'; import { Flex } from './Flex'; @@ -38,7 +38,11 @@ const StyledRadioOuter = styled.div<{ } `; -function RadioButton({ +/** + * The dot part of the radio button. Unless for the Theme switcher, it shouldn't be used directly. + * Instead, use `SessionRadio`. + */ +export function RadioDot({ disabled, onClick, selected, @@ -143,7 +147,7 @@ export const SessionRadio = (props: SessionRadioProps) => { ) : null} - { ); }; - -/** - * This is slightly different that the classic SessionRadio as this one has - * - no padding between the selected background and the border, - * - they all have a background color (even when not selected), but the border is present on the selected one - * - * Keeping it here so we don't have to export - */ -export const SessionRadioPrimaryColors = (props: { - value: string; - active: boolean; - onClick: (value: string) => void; - ariaLabel: string; - color: string; // by default, we use the theme accent color but for the settings screen we need to be able to force it -}) => { - const { value, active, onClick, color, ariaLabel } = props; - - function clickHandler(e: ChangeEvent) { - e.stopPropagation(); - onClick(value); - } - - // this component has no padding between the selected background and the border - const diameterRadioBorder = 26; - - const overriddenColorsVars = { - '--primary-color': color, - '--text-primary-color': active ? undefined : 'transparent', - } as React.CSSProperties; - - return ( - - - - ); -}; diff --git a/ts/components/buttons/panel/GenericPanelButtonWithAction.tsx b/ts/components/buttons/panel/GenericPanelButtonWithAction.tsx index 6dc9730f1..3f5c00218 100644 --- a/ts/components/buttons/panel/GenericPanelButtonWithAction.tsx +++ b/ts/components/buttons/panel/GenericPanelButtonWithAction.tsx @@ -1,4 +1,4 @@ -import type { ReactNode, SessionDataTestId } from 'react'; +import type { MouseEvent, ReactNode, SessionDataTestId } from 'react'; import styled from 'styled-components'; import { useIsDarkTheme } from '../../../state/theme/selectors/theme'; import { StyledPanelButton, StyledContent } from './PanelButton'; @@ -7,13 +7,14 @@ import { StyledPanelButtonSeparator } from './StyledPanelButtonGroupSeparator'; const StyledActionContainer = styled.div` display: flex; align-items: center; + flex-shrink: 0; pointer-events: none; // let the container handle the event (otherwise we get 2 onClick events, cancelling each others) `; export type GenericPanelButtonProps = { textElement: ReactNode; actionElement: ReactNode; - onClick: undefined | (() => void | Promise); + onClick: undefined | ((e: MouseEvent) => void | Promise); rowDataTestId: SessionDataTestId; }; diff --git a/ts/components/calling/DraggableCallContainer.tsx b/ts/components/calling/DraggableCallContainer.tsx index 39ac345e5..5bb390333 100644 --- a/ts/components/calling/DraggableCallContainer.tsx +++ b/ts/components/calling/DraggableCallContainer.tsx @@ -5,9 +5,7 @@ import { useSelector } from 'react-redux'; import styled from 'styled-components'; import { useVideoCallEventsListener } from '../../hooks/useVideoEventListener'; import { openConversationWithMessages } from '../../state/ducks/conversations'; -import { SectionType } from '../../state/ducks/section'; import { getHasOngoingCall, getHasOngoingCallWith } from '../../state/selectors/call'; -import { getSection } from '../../state/selectors/section'; import { useSelectedConversationKey } from '../../state/selectors/selectedConversation'; import { Avatar, AvatarSize } from '../avatar/Avatar'; import { VideoLoadingSpinner } from './InConversationCallContainer'; @@ -60,7 +58,6 @@ export const DraggableCallContainer = () => { const ongoingCallProps = useSelector(getHasOngoingCallWith); const selectedConversationKey = useSelectedConversationKey(); const hasOngoingCall = useSelector(getHasOngoingCall); - const selectedSection = useSelector(getSection); // the draggable container has a width of 12vw, so we just set it's X to a bit more than this const [positionX, setPositionX] = useState(window.innerWidth - (window.innerWidth * 1) / 6); @@ -102,12 +99,7 @@ export const DraggableCallContainer = () => { } }; - if ( - !hasOngoingCall || - !ongoingCallProps || - (ongoingCallPubkey === selectedConversationKey && - selectedSection.focusedSection !== SectionType.Settings) - ) { + if (!hasOngoingCall || !ongoingCallProps || ongoingCallPubkey === selectedConversationKey) { return null; } diff --git a/ts/components/conversation/SessionEmojiPanel.tsx b/ts/components/conversation/SessionEmojiPanel.tsx index d65e05ec2..cbb394c7d 100644 --- a/ts/components/conversation/SessionEmojiPanel.tsx +++ b/ts/components/conversation/SessionEmojiPanel.tsx @@ -1,10 +1,9 @@ import Picker from '@emoji-mart/react'; import { forwardRef } from 'react'; -import { useSelector } from 'react-redux'; import styled from 'styled-components'; import clsx from 'clsx'; -import { getPrimaryColor } from '../../state/selectors/primaryColor'; +import { usePrimaryColor } from '../../state/selectors/primaryColor'; import { useIsDarkTheme, useTheme } from '../../state/theme/selectors/theme'; import { COLORS, THEMES, ThemeStateType, type ColorsType } from '../../themes/constants/colors'; import { FixedBaseEmoji } from '../../types/Reaction'; @@ -93,7 +92,7 @@ const pickerProps = { // eslint-disable-next-line react/display-name export const SessionEmojiPanel = forwardRef((props: Props, ref) => { const { onEmojiClicked, show, isModal = false, onKeyDown } = props; - const _primaryColor = useSelector(getPrimaryColor); + const _primaryColor = usePrimaryColor(); const theme = useTheme(); const isDarkTheme = useIsDarkTheme(); diff --git a/ts/components/dialog/user-settings/UserSettingsDialog.tsx b/ts/components/dialog/user-settings/UserSettingsDialog.tsx index 696d15323..de6248418 100644 --- a/ts/components/dialog/user-settings/UserSettingsDialog.tsx +++ b/ts/components/dialog/user-settings/UserSettingsDialog.tsx @@ -1,4 +1,5 @@ import { type UserSettingsModalState } from '../../../state/ducks/modalDialog'; +import { AppearanceSettingsPage } from './pages/AppearanceSettingsPage'; import { BlockedContactsSettingsPage } from './pages/BlockedContactsSettingsPage'; import { ConversationSettingsPage } from './pages/ConversationSettingsPage'; import { DefaultSettingPage } from './pages/DefaultSettingsPage'; @@ -27,6 +28,8 @@ export const UserSettingsDialog = (modalState: UserSettingsModalState) => { return ; case 'blocked-contacts': return ; + case 'appearance': + return ; default: return ; } diff --git a/ts/components/dialog/user-settings/pages/AppearanceSettingsPage.tsx b/ts/components/dialog/user-settings/pages/AppearanceSettingsPage.tsx new file mode 100644 index 000000000..97b2ce649 --- /dev/null +++ b/ts/components/dialog/user-settings/pages/AppearanceSettingsPage.tsx @@ -0,0 +1,464 @@ +import useUpdate from 'react-use/lib/useUpdate'; +import useInterval from 'react-use/lib/useInterval'; + +import styled from 'styled-components'; +import { useDispatch } from 'react-redux'; +import { isFinite, isNumber, range } from 'lodash'; +import { contextMenu, Menu } from 'react-contexify'; +import { useRef } from 'react'; + +import { type UserSettingsModalState } from '../../../../state/ducks/modalDialog'; +import { + PanelButton, + PanelButtonGroup, + PanelButtonTextWithSubText, + PanelLabelWithDescription, +} from '../../../buttons/panel/PanelButton'; +import { + ModalBasicHeader, + SessionWrapperModal, + WrapperModalWidth, +} from '../../../SessionWrapperModal'; +import { ModalBackButton } from '../../shared/ModalBackButton'; +import { + useUserSettingsBackAction, + useUserSettingsCloseAction, + useUserSettingsTitle, +} from './userSettingsHooks'; +import { SettingsToggleBasic } from '../components/SettingsToggleBasic'; +import { useHasFollowSystemThemeEnabled } from '../../../../state/selectors/settings'; +import { SettingsKey } from '../../../../data/settings-key'; +import { isHideMenuBarSupported } from '../../../../types/Settings'; +import { ensureThemeConsistency } from '../../../../themes/SessionTheme'; +import { + getPrimaryColors, + getThemeColors, + type StyleSessionSwitcher, +} from '../../../../themes/constants/colors'; +import { RadioDot, SessionRadio } from '../../../basic/SessionRadio'; +import { usePrimaryColor } from '../../../../state/selectors/primaryColor'; +import { switchPrimaryColorTo } from '../../../../themes/switchPrimaryColor'; +import { useTheme } from '../../../../state/theme/selectors/theme'; +import { switchThemeTo } from '../../../../themes/switchTheme'; +import { StyledPanelButtonSeparator } from '../../../buttons/panel/StyledPanelButtonGroupSeparator'; +import { GenericPanelButtonWithAction } from '../../../buttons/panel/GenericPanelButtonWithAction'; +import { tr } from '../../../../localization/localeTools'; +import { Flex } from '../../../basic/Flex'; +import { LUCIDE_ICONS_UNICODE } from '../../../icon/lucide'; +import { LucideIcon } from '../../../icon/LucideIcon'; +import { H9 } from '../../../basic/Heading'; +import { getMenuAnimation } from '../../../menu/MenuAnimation'; +import { ItemWithDataTestId } from '../../../menu/items/MenuItemWithDataTestId'; +import { ZOOM_FACTOR } from '../../../../session/constants'; +import { SessionContextMenuContainerItemsCentered } from '../../../SessionContextMenuContainer'; + +const StyledPrimaryColorSwitcherContainer = styled.div` + display: flex; + flex-direction: row; + padding-inline: 20px; + align-items: center; + align-self: center; + width: 100%; + justify-content: space-around; + height: var(--panel-button-container-min-height); +`; + +function PrimaryColorSwitcher() { + const selectedPrimaryColor = usePrimaryColor(); + const dispatch = useDispatch(); + const diameterRadioBorder = 35; + + return ( + + {getPrimaryColors().map(item => { + const overriddenColorsVars = { + '--primary-color': item.color, + '--text-primary-color': item.id === selectedPrimaryColor ? undefined : 'transparent', + } as React.CSSProperties; + return ( + { + void switchPrimaryColorTo(item.id, dispatch); + }} + key={item.id} + disabled={false} + dataTestId={undefined} + diameterRadioBorder={diameterRadioBorder} + style={overriddenColorsVars} + ariaLabel={item.ariaLabel} + /> + ); + })} + + ); +} + +const StyledPreview = styled.svg` + flex-shrink: 0; + height: 58px; +`; + +const ThemeIcon = (props: { style: StyleSessionSwitcher }) => { + return ( + + + + + + ); +}; + +const StyledThemeName = styled.div` + font-size: var(--font-size-h8); + color: var(--text-primary-color); + font-weight: 700; + flex-shrink: 0; +`; + +const Themes = () => { + const themes = getThemeColors(); + const selectedTheme = useTheme(); + const dispatch = useDispatch(); + + return ( + <> + {themes.map(theme => ( + <> + { + void switchThemeTo({ + theme: theme.id, + mainWindow: true, + dispatch, + }); + }} + > +
+ + {theme.title} +
+ +
+ + + ))} + + ); +}; + +function ChatBubblePreview() { + return ( + + + + + + + + + + You + + + What are you doing this week? + + + Going to the beach, what about you? + + + + Oh cool, ill see you there! + + + ); +} + +async function setZoomFactor(value: number, forceUpdate: () => void) { + if (!isNumber(value) || !isFinite(value) || value < 0) { + throw new Error('setZoomFactor: value not valid'); + } + + await window.setSettingValue('zoom-factor-setting', value); + window.updateZoomFactor(); + forceUpdate(); +} + +const zoomFactorMenuId = 'zoom-factor-menu'; + +const zoomFactorValues = range(ZOOM_FACTOR.MIN, ZOOM_FACTOR.MAX, ZOOM_FACTOR.STEP); + +const ZoomFactorMenuPicker = ({ + forceUpdate, + currentZoomFactor, +}: { + forceUpdate: () => void; + currentZoomFactor: number; +}) => { + const selectedRef = useRef(null); + + const handleShow = (isVisible: boolean) => { + if (!isVisible) { + return; + } + requestAnimationFrame(() => { + selectedRef.current?.scrollIntoView({ + block: 'center', + }); + // Note: we can't auto select the starting item of keyboard navigation with react-contexify. + }); + }; + + return ( + + + {zoomFactorValues.map(m => { + return ( + { + void setZoomFactor(m, forceUpdate); + }} + style={{ + backgroundColor: m === currentZoomFactor ? 'var(--primary-color)' : 'unset', + }} + > +
{m}%
+
+ ); + })} +
+
+ ); +}; + +function ZoomFactorPicker({ forceUpdate }: { forceUpdate: () => void }) { + const baseDataTestId = 'zoom-factor'; + useInterval(() => { + // the shortcut can change this value. So let's make this refresh every second when displayed + forceUpdate(); + }, 500); + + const zoomFactorCurrentSetting = + window.getSettingValue('zoom-factor-setting') || ZOOM_FACTOR.DEFAULT; + const containerRef = useRef(null); + + return ( + { + const boundingRect = containerRef.current?.getBoundingClientRect(); + if (!boundingRect) { + return; + } + contextMenu.show({ + id: zoomFactorMenuId, + event: e, + position: { + x: boundingRect.left + boundingRect.width / 2, + y: boundingRect.top + boundingRect.height / 2, + }, + }); + }} + textElement={ + + } + actionElement={ + + + + {zoomFactorCurrentSetting}% + + } + /> + ); +} + +export function AppearanceSettingsPage(modalState: UserSettingsModalState) { + const backAction = useUserSettingsBackAction(modalState); + const closeAction = useUserSettingsCloseAction(modalState); + const title = useUserSettingsTitle(modalState); + const forceUpdate = useUpdate(); + + const isFollowSystemThemeEnabled = useHasFollowSystemThemeEnabled(); + + const themes = getThemeColors(); + const selectedTheme = useTheme(); + const selectedThemeColors = themes.find(theme => theme.id === selectedTheme); + + const isHideMenuBarActive = + window.getSettingValue(SettingsKey.settingsMenuBar) === undefined + ? true + : window.getSettingValue(SettingsKey.settingsMenuBar); + + if (!selectedThemeColors) { + throw new Error('No theme colors found'); + } + + return ( + : undefined} + /> + } + onClose={closeAction || undefined} + shouldOverflow={true} + allowOutsideClick={false} + $contentMinWidth={WrapperModalWidth.normal} + > + + + + + + + + + + + + + + { + const toggledValue = !isFollowSystemThemeEnabled; + await window.setSettingValue(SettingsKey.hasFollowSystemThemeEnabled, toggledValue); + if (!isFollowSystemThemeEnabled) { + await ensureThemeConsistency(); + } + forceUpdate(); + }} + active={isFollowSystemThemeEnabled} + /> + + + + + + {isHideMenuBarSupported() ? ( + <> + + + { + window.toggleMenuBar(); + forceUpdate(); + }} + active={isHideMenuBarActive} + /> + + + ) : null} + + ); +} diff --git a/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx b/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx index 4844192e7..61952cf71 100644 --- a/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx @@ -186,7 +186,7 @@ function SettingsSection() { iconElement={} text={tr('sessionAppearance')} onClick={() => { - throw new Error('Not implemented'); + dispatch(userSettingsModal({ userSettingsPage: 'appearance' })); }} dataTestId="appearance-settings-menu-item" /> diff --git a/ts/components/leftpane/ActionsPanel.tsx b/ts/components/leftpane/ActionsPanel.tsx index 83bc17d5e..2a27c681e 100644 --- a/ts/components/leftpane/ActionsPanel.tsx +++ b/ts/components/leftpane/ActionsPanel.tsx @@ -1,5 +1,5 @@ import { ipcRenderer } from 'electron'; -import { useRef, useState } from 'react'; +import { useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import useInterval from 'react-use/lib/useInterval'; @@ -62,6 +62,7 @@ import { getFileInfoFromFileServer } from '../../session/apis/file_server_api/Fi import { themesArray } from '../../themes/constants/colors'; import { isDebugMode } from '../../shared/env_vars'; import { GearAvatarButton } from '../buttons/avatar/GearAvatarButton'; +import { useZoomShortcuts } from '../../hooks/useZoomingShortcut'; const StyledContainerAvatar = styled.div` padding: var(--margins-lg); @@ -117,11 +118,8 @@ const Section = (props: { type: SectionType }) => { dispatch(sectionActions.resetLeftOverlayMode()); }; - const settingsIconRef = useRef(null); - useHotkey('Escape', () => { - if (type === SectionType.Settings && !isModalVisible) { - settingsIconRef.current?.blur(); + if (!isModalVisible) { dispatch(searchActions.clearSearch()); dispatch(sectionActions.showLeftPaneSection(SectionType.Message)); dispatch(sectionActions.resetLeftOverlayMode()); @@ -165,15 +163,6 @@ const Section = (props: { type: SectionType }) => { {Boolean(unreadToShow) && }
); - case SectionType.Settings: - return ( - - ); case SectionType.DebugMenu: return ( { }); useUpdateBadgeCount(); + // setup our own shortcuts so that it changes show in the appearance tab too + useZoomShortcuts(); useInterval( DecryptedAttachmentsManager.cleanUpOldDecryptedMedias, @@ -372,7 +363,6 @@ export const ActionsPanel = () => {
-
{showDebugMenu &&
}
diff --git a/ts/components/settings/SessionSettings.tsx b/ts/components/settings/SessionSettings.tsx index 1846eeade..bb34840d0 100644 --- a/ts/components/settings/SessionSettings.tsx +++ b/ts/components/settings/SessionSettings.tsx @@ -8,7 +8,6 @@ import { SessionIconButton } from '../icon'; import { sessionPassword } from '../../state/ducks/modalDialog'; import type { PasswordAction, SessionSettingCategory } from '../../types/ReduxTypes'; -import { SettingsCategoryAppearance } from './section/CategoryAppearance'; import { SettingsCategoryRecoveryPassword } from './section/CategoryRecoveryPassword'; import { setDebugMode } from '../../state/ducks/debug'; import { showLinkVisitWarningDialog } from '../dialog/OpenUrlModal'; @@ -105,8 +104,6 @@ const SettingInCategory = (props: { category: SessionSettingCategory }) => { const { category } = props; switch (category) { - case 'appearance': - return ; case 'recovery-password': return ; default: diff --git a/ts/components/settings/SessionSettingsHeader.tsx b/ts/components/settings/SessionSettingsHeader.tsx index 827555ebc..33bda8441 100644 --- a/ts/components/settings/SessionSettingsHeader.tsx +++ b/ts/components/settings/SessionSettingsHeader.tsx @@ -26,9 +26,6 @@ export const SettingsHeader = (props: Props) => { let categoryTitleKey: MergedLocalizerTokens | null = null; switch (category) { - case 'appearance': - categoryTitleKey = 'sessionAppearance'; - break; case 'recovery-password': categoryTitleKey = 'sessionRecoveryPassword'; break; diff --git a/ts/components/settings/SettingsThemeSwitcher.tsx b/ts/components/settings/SettingsThemeSwitcher.tsx deleted file mode 100644 index d1834cbc2..000000000 --- a/ts/components/settings/SettingsThemeSwitcher.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import { useDispatch, useSelector } from 'react-redux'; -import styled from 'styled-components'; -import { getPrimaryColor } from '../../state/selectors/primaryColor'; -import { useTheme } from '../../state/theme/selectors/theme'; -import { - StyleSessionSwitcher, - getPrimaryColors, - getThemeColors, -} from '../../themes/constants/colors'; -import { switchPrimaryColorTo } from '../../themes/switchPrimaryColor'; -import { switchThemeTo } from '../../themes/switchTheme'; -import { SessionRadio, SessionRadioPrimaryColors } from '../basic/SessionRadio'; -import { SpacerLG, SpacerMD } from '../basic/Text'; -import { StyledDescriptionSettingsItem, StyledTitleSettingsItem } from './SessionSettingListItem'; -import { Localizer } from '../basic/Localizer'; - -const StyledSwitcherContainer = styled.div` - font-size: var(--font-size-md); - padding: var(--margins-lg); - margin-bottom: var(--margins-lg); - - background: var(--settings-tab-background-color); - color: var(--settings-tab-text-color); - border-top: 1px solid var(--border-color); - border-bottom: 1px solid var(--border-color); -`; - -const ThemeContainer = styled.button` - background: var(--background-secondary-color); - border: 1px solid var(--border-color); - border-radius: 8px; - padding: var(--margins-sm); - display: flex; - align-items: center; - - width: 285px; - height: 90px; - - transition: var(--default-duration); - - &:hover { - background: var(--settings-tab-background-hover-color); - } -`; - -const ThemesContainer = styled.div` - display: flex; - flex-wrap: wrap; - gap: var(--margins-lg); -`; - -const StyledPreview = styled.svg` - max-height: 100%; -`; - -const ThemePreview = (props: { style: StyleSessionSwitcher }) => { - return ( - - - - - - ); -}; - -const Themes = () => { - const themes = getThemeColors(); - const selectedTheme = useTheme(); - const dispatch = useDispatch(); - - return ( - <> - {themes.map(theme => ( - { - void switchThemeTo({ - theme: theme.id, - mainWindow: true, - dispatch, - }); - }} - > - - - - {theme.title} - - - ))} - - ); -}; - -export const SettingsThemeSwitcher = () => { - const selectedPrimaryColor = useSelector(getPrimaryColor); - const dispatch = useDispatch(); - - return ( - - - - - - - - - - - - - - {getPrimaryColors().map(item => { - return ( - { - void switchPrimaryColorTo(item.id, dispatch); - }} - /> - ); - })} - - - ); -}; diff --git a/ts/components/settings/ZoomingSessionSlider.tsx b/ts/components/settings/ZoomingSessionSlider.tsx deleted file mode 100644 index afb254616..000000000 --- a/ts/components/settings/ZoomingSessionSlider.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import Slider from 'rc-slider'; - -import { isNumber } from 'lodash'; - -import { useState } from 'react'; -import useUpdate from 'react-use/lib/useUpdate'; -import styled from 'styled-components'; -import { Flex } from '../basic/Flex'; -import { SessionSettingsItemWrapper } from './SessionSettingListItem'; -import { tr } from '../../localization/localeTools'; - -const StyledZoomValue = styled.p` - min-width: 40px; - margin-inline-start: var(--margins-lg); -`; - -export const ZoomingSessionSlider = (props: { onSliderChange?: (value: number) => void }) => { - const [value, setValue] = useState(window.getSettingValue('zoom-factor-setting') || 100); - const forceUpdate = useUpdate(); - const handleSlider = async (val: number | Array) => { - const newSetting = isNumber(val) ? val : val?.[0] || 1; - - props?.onSliderChange?.(newSetting); - await window.setSettingValue('zoom-factor-setting', newSetting); - window.updateZoomFactor(); - forceUpdate(); - }; - - return ( - - - ) => { - setValue(isNumber(val) ? val : val?.[0] || 1); - }} - onChangeComplete={e => { - void handleSlider(e); - }} - /> - {value}% - - - ); -}; diff --git a/ts/components/settings/section/CategoryAppearance.tsx b/ts/components/settings/section/CategoryAppearance.tsx deleted file mode 100644 index 7624affdd..000000000 --- a/ts/components/settings/section/CategoryAppearance.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import useUpdate from 'react-use/lib/useUpdate'; -import { SettingsKey } from '../../../data/settings-key'; -import { useHasFollowSystemThemeEnabled } from '../../../state/selectors/settings'; -import { ensureThemeConsistency } from '../../../themes/SessionTheme'; -import { isHideMenuBarSupported } from '../../../types/Settings'; -import { SessionToggleWithDescription } from '../SessionSettingListItem'; -import { SettingsThemeSwitcher } from '../SettingsThemeSwitcher'; -import { ZoomingSessionSlider } from '../ZoomingSessionSlider'; -import { tr } from '../../../localization/localeTools'; - -export const SettingsCategoryAppearance = () => { - const forceUpdate = useUpdate(); - const isFollowSystemThemeEnabled = useHasFollowSystemThemeEnabled(); - - const isHideMenuBarActive = - window.getSettingValue(SettingsKey.settingsMenuBar) === undefined - ? true - : window.getSettingValue(SettingsKey.settingsMenuBar); - - return ( - <> - - - {isHideMenuBarSupported() && ( - { - window.toggleMenuBar(); - forceUpdate(); - }} - title={tr('appearanceHideMenuBar')} - description={tr('hideMenuBarDescription')} - active={isHideMenuBarActive} - /> - )} - { - const toggledValue = !isFollowSystemThemeEnabled; - await window.setSettingValue(SettingsKey.hasFollowSystemThemeEnabled, toggledValue); - if (!isFollowSystemThemeEnabled) { - await ensureThemeConsistency(); - } - }} - title={tr('appearanceAutoDarkMode')} - description={tr('followSystemSettings')} - active={isFollowSystemThemeEnabled} - dataTestId="enable-follow-system-theme" - /> - - ); -}; diff --git a/ts/hooks/useZoomingShortcut.ts b/ts/hooks/useZoomingShortcut.ts new file mode 100644 index 000000000..4293f5973 --- /dev/null +++ b/ts/hooks/useZoomingShortcut.ts @@ -0,0 +1,45 @@ +import useKey from 'react-use/lib/useKey'; +import { ZOOM_FACTOR } from '../session/constants'; + +export function useZoomShortcuts() { + const changeZoom = async ( + change: { typeOfChange: 'delta'; delta: number } | { typeOfChange: 'reset' } + ) => { + let value: number = await window.getSettingValue('zoom-factor-setting'); + if (typeof value !== 'number') { + value = ZOOM_FACTOR.DEFAULT; + } + if (change.typeOfChange === 'reset') { + await window.setSettingValue('zoom-factor-setting', value); + window.updateZoomFactor(); + return; + } + value = Math.min(Math.max(value + change.delta, ZOOM_FACTOR.MIN), ZOOM_FACTOR.MAX); + await window.setSettingValue('zoom-factor-setting', value); + window.updateZoomFactor(); + }; + + useKey( + event => (event.ctrlKey || event.metaKey) && (event.key === '+' || event.key === '='), + event => { + event.preventDefault(); + void changeZoom({ typeOfChange: 'delta', delta: ZOOM_FACTOR.STEP }); + } + ); + + useKey( + event => (event.ctrlKey || event.metaKey) && event.key === '-', + event => { + event.preventDefault(); + void changeZoom({ typeOfChange: 'delta', delta: -ZOOM_FACTOR.STEP }); + } + ); + + useKey( + event => (event.ctrlKey || event.metaKey) && event.key === '0', + event => { + event.preventDefault(); + void changeZoom({ typeOfChange: 'reset' }); + } + ); +} diff --git a/ts/react.d.ts b/ts/react.d.ts index 4c5ce7f76..f7d9116bf 100644 --- a/ts/react.d.ts +++ b/ts/react.d.ts @@ -93,7 +93,9 @@ declare module 'react' { | 'audio-message-autoplay' | 'spell-check' | 'conversation-trimming' - | 'auto-update'; + | 'auto-update' + | 'auto-dark-mode' + | 'hide-menu-bar'; type SettingsRadio = | `set-notifications-${'message' | 'name' | 'count'}` @@ -245,7 +247,7 @@ declare module 'react' { | 'modal-actions-container' | 'reveal-blocked-user-settings' | `${Sections}-section` - | `${SettingsToggles | SettingsInlineButtons | SettingsRadio | SettingsChevron | SettingsExternalLinkButtons}-settings-${'text' | 'sub-text' | 'toggle' | 'radio' | 'button' | 'chevron' | 'row'}` + | `${SettingsToggles | SettingsInlineButtons | SettingsRadio | SettingsChevron | SettingsExternalLinkButtons | 'zoom-factor'}-settings-${'text' | 'sub-text' | 'toggle' | 'radio' | 'button' | 'chevron' | 'row'}` // Buttons | `${Buttons}-button` diff --git a/ts/session/constants.ts b/ts/session/constants.ts index e4af7e5a3..672a6bcc0 100644 --- a/ts/session/constants.ts +++ b/ts/session/constants.ts @@ -64,6 +64,13 @@ export const PROTOCOLS = { HTTPS: 'https:', }; +export const ZOOM_FACTOR = { + STEP: 10, + MIN: 50, + MAX: 200, + DEFAULT: 100, +}; + // User Interface export const CONVERSATION = { DEFAULT_MEDIA_FETCH_COUNT: 50, diff --git a/ts/state/ducks/modalDialog.tsx b/ts/state/ducks/modalDialog.tsx index 043c0e44b..f2ddcb939 100644 --- a/ts/state/ducks/modalDialog.tsx +++ b/ts/state/ducks/modalDialog.tsx @@ -132,7 +132,7 @@ export const initialModalState: ModalState = { groupMembersModal: null, userProfileModal: null, nickNameModal: null, - userSettingsModal: { userSettingsPage: 'privacy' }, + userSettingsModal: { userSettingsPage: 'appearance' }, onionPathModal: null, enterPasswordModal: null, sessionPasswordModal: null, diff --git a/ts/state/ducks/section.tsx b/ts/state/ducks/section.tsx index 605441197..0f1dad455 100644 --- a/ts/state/ducks/section.tsx +++ b/ts/state/ducks/section.tsx @@ -47,14 +47,6 @@ const sectionSlice = createSlice({ initialState: initialSectionState, reducers: { showLeftPaneSection(state, action: PayloadAction) { - if (action.payload === SectionType.Settings) { - // on click on the gear icon: show the 'appearance' tab by default - return { - ...state, - focusedSection: action.payload, - focusedSettingsSection: 'appearance', - }; - } return { ...state, focusedSection: action.payload, diff --git a/ts/state/selectors/primaryColor.ts b/ts/state/selectors/primaryColor.ts index f0f608942..537181c84 100644 --- a/ts/state/selectors/primaryColor.ts +++ b/ts/state/selectors/primaryColor.ts @@ -1,4 +1,9 @@ +import { useSelector } from 'react-redux'; import { PrimaryColorStateType } from '../../themes/constants/colors'; import { StateType } from '../reducer'; export const getPrimaryColor = (state: StateType): PrimaryColorStateType => state.primaryColor; + +export function usePrimaryColor() { + return useSelector(getPrimaryColor); +} diff --git a/ts/types/ReduxTypes.d.ts b/ts/types/ReduxTypes.d.ts index d519e0126..2c0bac131 100644 --- a/ts/types/ReduxTypes.d.ts +++ b/ts/types/ReduxTypes.d.ts @@ -5,7 +5,7 @@ * e.g. import type { YourTypeHere } from 'path/to/ReduxTypes'; */ -export type SessionSettingCategory = 'appearance' | 'recovery-password'; +export type SessionSettingCategory = 'recovery-password'; export type PasswordAction = 'set' | 'change' | 'remove' | 'enter'; diff --git a/yarn.lock b/yarn.lock index dd1fe413a..634212fbb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -45,7 +45,7 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.7.tgz#9a5226f92f0c5c8ead550b750f5608e766c8ce85" integrity sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw== -"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.26.10", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.26.10", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.26.10" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.10.tgz#a07b4d8fa27af131a633d7b3524db803eb4764c2" integrity sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw== @@ -2467,11 +2467,6 @@ ci-info@^3.2.0, ci-info@^3.7.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== -classnames@^2.2.5: - version "2.5.1" - resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b" - integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow== - clean-stack@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" @@ -6458,23 +6453,6 @@ randombytes@^2.1.0: dependencies: safe-buffer "^5.1.0" -rc-slider@^11.1.8: - version "11.1.8" - resolved "https://registry.yarnpkg.com/rc-slider/-/rc-slider-11.1.8.tgz#cf3b30dacac8f98d44f7685f733f6f7da146fc06" - integrity sha512-2gg/72YFSpKP+Ja5AjC5DPL1YnV8DEITDQrcc1eASrUYjl0esptaBVJBh5nLTXCCp15eD8EuGjwezVGSHhs9tQ== - dependencies: - "@babel/runtime" "^7.10.1" - classnames "^2.2.5" - rc-util "^5.36.0" - -rc-util@^5.36.0: - version "5.44.4" - resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.44.4.tgz#89ee9037683cca01cd60f1a6bbda761457dd6ba5" - integrity sha512-resueRJzmHG9Q6rI/DfK6Kdv9/Lfls05vzMs1Sk3M2P+3cJa+MakaZyWY8IPfehVuhPJFKrIY1IK4GqbiaiY5w== - dependencies: - "@babel/runtime" "^7.18.3" - react-is "^18.2.0" - rc@^1.2.7: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" @@ -6528,7 +6506,7 @@ react-intersection-observer@^9.16.0: resolved "https://registry.yarnpkg.com/react-intersection-observer/-/react-intersection-observer-9.16.0.tgz#7376d54edc47293300961010844d53b273ee0fb9" integrity sha512-w9nJSEp+DrW9KmQmeWHQyfaP6b03v+TdXynaoA964Wxt7mdR3An11z4NNCQgL4gKSK7y1ver2Fq+JKH6CWEzUA== -"react-is@^16.12.0 || ^17.0.0 || ^18.0.0", react-is@^18.0.0, react-is@^18.2.0, react-is@^18.3.1: +"react-is@^16.12.0 || ^17.0.0 || ^18.0.0", react-is@^18.0.0, react-is@^18.3.1: version "18.3.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== From 6bd462da2faf43d061be3a9e9ee476a435ec945d Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Tue, 19 Aug 2025 16:57:57 +1000 Subject: [PATCH 11/18] feat: moved to user settings the App version info details also cleanup remaining of the settings state in redux --- ts/components/SessionMainPanel.tsx | 10 - .../pages/DefaultSettingsPage.tsx | 72 ++++++- ts/components/leftpane/LeftPane.tsx | 4 - .../leftpane/LeftPaneSectionHeader.tsx | 4 +- .../leftpane/LeftPaneSettingSection.tsx | 187 ------------------ ts/components/settings/SessionSettings.tsx | 129 +----------- .../settings/SessionSettingsHeader.tsx | 41 ---- ts/state/ducks/section.tsx | 12 -- ts/state/selectors/section.ts | 6 - ts/types/ReduxTypes.d.ts | 2 - 10 files changed, 74 insertions(+), 393 deletions(-) delete mode 100644 ts/components/leftpane/LeftPaneSettingSection.tsx delete mode 100644 ts/components/settings/SessionSettingsHeader.tsx diff --git a/ts/components/SessionMainPanel.tsx b/ts/components/SessionMainPanel.tsx index 4dbf2f38b..88ff5b644 100644 --- a/ts/components/SessionMainPanel.tsx +++ b/ts/components/SessionMainPanel.tsx @@ -1,24 +1,14 @@ -import { useSelector } from 'react-redux'; import { useAppIsFocused } from '../hooks/useAppFocused'; -import { getFocusedSettingsSection } from '../state/selectors/section'; import { SmartSessionConversation } from '../state/smart/SessionConversation'; -import { SessionSettingsView } from './settings/SessionSettings'; import { useHTMLDirection } from '../util/i18n/rtlSupport'; -const FilteredSettingsView = SessionSettingsView as any; - export const SessionMainPanel = () => { - const focusedSettingsSection = useSelector(getFocusedSettingsSection); - const isSettingsView = focusedSettingsSection !== undefined; const htmlDirection = useHTMLDirection(); // even if it looks like this does nothing, this does update the redux store. useAppIsFocused(); - if (isSettingsView) { - return ; - } return (
diff --git a/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx b/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx index 61952cf71..5222bb3ab 100644 --- a/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx @@ -24,7 +24,7 @@ import { ProIconButton } from '../../../buttons/ProButton'; import { type SessionIconProps, SessionIcon } from '../../../icon'; import { LUCIDE_ICONS_UNICODE } from '../../../icon/lucide'; import { type LucideIconProps, LucideIcon } from '../../../icon/LucideIcon'; -import { SessionLucideIconButton } from '../../../icon/SessionIconButton'; +import { SessionIconButton, SessionLucideIconButton } from '../../../icon/SessionIconButton'; import { QRView } from '../../../qrview/QrView'; import { ModalBasicHeader, SessionWrapperModal } from '../../../SessionWrapperModal'; import { showLinkVisitWarningDialog } from '../../OpenUrlModal'; @@ -34,6 +34,7 @@ import { ProfileHeader, ProfileName } from '../components'; import type { ProfileDialogModes } from '../ProfileDialogModes'; import { tr } from '../../../../localization/localeTools'; import { useIsProAvailable } from '../../../../hooks/useIsProAvailable'; +import { setDebugMode } from '../../../../state/ducks/debug'; const handleKeyQRMode = (mode: ProfileDialogModes, setMode: (mode: ProfileDialogModes) => void) => { switch (mode) { @@ -252,6 +253,74 @@ function AdminSection() { ); } +const StyledVersionInfo = styled.div` + display: flex; + align-items: center; + flex-direction: column; + gap: var(--margins-xs); + background: none; + font-size: var(--font-size-sm); +`; + +const StyledSpanSessionInfo = styled.span<{ opacity?: number }>` + opacity: ${props => props.opacity ?? 0.5}; + transition: var(--default-duration); + user-select: text; + cursor: pointer; + + &:hover { + opacity: 1; + } +`; + +const SessionInfo = () => { + const [clickCount, setClickCount] = useState(0); + + const dispatch = useDispatch(); + + return ( + + { + showLinkVisitWarningDialog('https://token.getsession.org/', dispatch); + }} + // disable transition here as the transition does the opposite that usual (hovering makes it more opaque/bright) + style={{ transition: 'none' }} + /> + + { + showLinkVisitWarningDialog( + `https://github.com/session-foundation/session-desktop/releases/tag/v${window.versionInfo.version}`, + dispatch + ); + }} + > + v{window.versionInfo.version} + + { + setClickCount(clickCount + 1); + if (clickCount === 10) { + dispatch(setDebugMode(true)); + setClickCount(0); + } + }} + > + {window.versionInfo.commitHash?.slice(0, 8)} + + + + ); +}; + export const DefaultSettingPage = () => { const dispatch = useDispatch(); @@ -344,6 +413,7 @@ export const DefaultSettingPage = () => { + diff --git a/ts/components/leftpane/LeftPane.tsx b/ts/components/leftpane/LeftPane.tsx index b3c1e47f6..ad37955ca 100644 --- a/ts/components/leftpane/LeftPane.tsx +++ b/ts/components/leftpane/LeftPane.tsx @@ -9,7 +9,6 @@ import { IncomingCallDialog } from '../calling/IncomingCallDialog'; import { ModalContainer } from '../dialog/ModalContainer'; import { ActionsPanel } from './ActionsPanel'; import { LeftPaneMessageSection } from './LeftPaneMessageSection'; -import { LeftPaneSettingSection } from './LeftPaneSettingSection'; import { useIsRtl } from '../../util/i18n/rtlSupport'; export const leftPaneListWidth = 300; // var(--left-panel-width) without the 80px of the action gutter @@ -33,9 +32,6 @@ const LeftPaneSection = () => { return ; } - if (focusedSection === SectionType.Settings) { - return ; - } return null; }; diff --git a/ts/components/leftpane/LeftPaneSectionHeader.tsx b/ts/components/leftpane/LeftPaneSectionHeader.tsx index 0d2efb6f5..94a61c4d9 100644 --- a/ts/components/leftpane/LeftPaneSectionHeader.tsx +++ b/ts/components/leftpane/LeftPaneSectionHeader.tsx @@ -18,6 +18,7 @@ import { searchActions } from '../../state/ducks/search'; import { LUCIDE_ICONS_UNICODE } from '../icon/lucide'; import { SessionLucideIconButton } from '../icon/SessionIconButton'; import { tr } from '../../localization/localeTools'; +import { userSettingsModal } from '../../state/ducks/modalDialog'; const StyledLeftPaneSectionHeader = styled(Flex)` height: var(--main-view-header-height); @@ -114,8 +115,7 @@ export const LeftPaneBanner = () => { const showRecoveryPhraseModal = () => { dispatch(disableRecoveryPhrasePrompt()); - dispatch(sectionActions.showLeftPaneSection(SectionType.Settings)); - dispatch(sectionActions.showSettingsSection('recovery-password')); + dispatch(userSettingsModal({ userSettingsPage: 'recovery-password' })); }; if (section !== SectionType.Message || isSignInWithRecoveryPhrase || hideRecoveryPassword) { diff --git a/ts/components/leftpane/LeftPaneSettingSection.tsx b/ts/components/leftpane/LeftPaneSettingSection.tsx deleted file mode 100644 index 887a1379d..000000000 --- a/ts/components/leftpane/LeftPaneSettingSection.tsx +++ /dev/null @@ -1,187 +0,0 @@ -import { type ReactNode, SessionDataTestId, useMemo } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; -import styled from 'styled-components'; - -import { sectionActions } from '../../state/ducks/section'; -import { getFocusedSettingsSection } from '../../state/selectors/section'; -import { useHideRecoveryPasswordEnabled } from '../../state/selectors/settings'; -import type { SessionSettingCategory } from '../../types/ReduxTypes'; -import { Flex } from '../basic/Flex'; -import { SessionIcon, SessionIconType } from '../icon'; -import { LeftPaneSectionHeader } from './LeftPaneSectionHeader'; -import { Localizer } from '../basic/Localizer'; -import { tr } from '../../localization/localeTools'; -import { LUCIDE_ICONS_UNICODE, type WithLucideUnicode } from '../icon/lucide'; -import { LucideIcon } from '../icon/LucideIcon'; -import { ProIconButton } from '../buttons/ProButton'; - -const StyledSettingsSectionTitle = styled.span<{ - color?: string; - isNew?: boolean; -}>` - font-size: var(--font-size-md); - font-weight: 500; - color: ${props => props.color}; - flex-grow: ${props => !props.isNew && 1}; -`; - -const StyledSettingsListItem = styled(Flex)<{ active: boolean }>` - background-color: ${props => - props.active - ? 'var(--settings-tab-background-selected-color)' - : 'var(--settings-tab-background-color)'}; - color: var(--settings-tab-text-color); - height: 74px; - line-height: 1; - cursor: pointer; - transition: var(--default-duration) !important; - - &:hover { - background: var(--settings-tab-background-hover-color); - } -`; - -const StyledIconContainer = styled.div` - width: 58px; - place-items: center; - text-align: center; -`; - -const StyledNewItem = styled.span` - color: var(--renderer-span-primary-color); - font-size: var(--font-size-sm); - font-weight: 400; - margin-inline-start: var(--margins-xs); -`; - -type CategoryIcon = { color?: string } & ( - | { - type: SessionIconType; - } - | (WithLucideUnicode & { - type: 'lucide'; - }) - | { - type: 'custom'; - content: 'sessionPro'; - } -); - -type Categories = { - id: SessionSettingCategory; - title: ReactNode; - titleColor?: string; - titleColorLightTheme?: string; - dataTestId: SessionDataTestId; - icon: CategoryIcon; - isNew?: boolean; -}; - -const categories: Array = ( - [ - { - id: 'appearance', - title: tr('sessionAppearance'), - icon: { type: 'lucide', unicode: LUCIDE_ICONS_UNICODE.PAINTBRUSH_VERTICAL }, - }, - ] as const satisfies Array> -).map(m => ({ - ...m, - dataTestId: `${m.id}-settings-menu-item` as const, -})) satisfies Array; - -const LeftPaneSettingsCategoryRow = ({ item }: { item: Categories }) => { - const { id, title, titleColor, icon, dataTestId, isNew } = item; - const dispatch = useDispatch(); - const focusedSettingsSection = useSelector(getFocusedSettingsSection); - - const isSelected = useMemo(() => focusedSettingsSection === id, [focusedSettingsSection, id]); - - const iconSize = 'medium'; - - return ( - { - switch (id) { - default: - dispatch(sectionActions.showSettingsSection(id)); - } - }} - data-testid={dataTestId} - > - - {icon.type === 'lucide' ? ( - - ) : icon.type === 'custom' ? ( - - ) : ( - - )} - - - {title} - - - {isNew ? ( - - - - ) : null} - - {isSelected ? ( - - ) : null} - - ); -}; - -const LeftPaneSettingsCategories = () => { - const hideRecoveryPassword = useHideRecoveryPasswordEnabled(); - - const settingsCategories = categories.filter( - category => !hideRecoveryPassword || category.id !== 'recovery-password' - ); - - return ( - <> - {settingsCategories.map(item => { - return ; - })} - - ); -}; -const StyledContentSection = styled.div` - display: flex; - flex-direction: column; - flex: 1; - overflow-y: auto; -`; - -export const LeftPaneSettingSection = () => { - return ( - - - - - - - ); -}; diff --git a/ts/components/settings/SessionSettings.tsx b/ts/components/settings/SessionSettings.tsx index bb34840d0..514dd30a6 100644 --- a/ts/components/settings/SessionSettings.tsx +++ b/ts/components/settings/SessionSettings.tsx @@ -1,16 +1,5 @@ -import { useState } from 'react'; -import styled from 'styled-components'; - -import { useDispatch } from 'react-redux'; -import { SettingsHeader } from './SessionSettingsHeader'; - -import { SessionIconButton } from '../icon'; - import { sessionPassword } from '../../state/ducks/modalDialog'; -import type { PasswordAction, SessionSettingCategory } from '../../types/ReduxTypes'; -import { SettingsCategoryRecoveryPassword } from './section/CategoryRecoveryPassword'; -import { setDebugMode } from '../../state/ducks/debug'; -import { showLinkVisitWarningDialog } from '../dialog/OpenUrlModal'; +import type { PasswordAction } from '../../types/ReduxTypes'; export function displayPasswordModal( passwordAction: PasswordAction, @@ -33,119 +22,3 @@ export function getMediaPermissionsSettings() { export function getCallMediaPermissionsSettings() { return window.getSettingValue('call-media-permissions'); } - -export interface SettingsViewProps { - category: SessionSettingCategory; -} - -const StyledVersionInfo = styled.div` - display: flex; - justify-content: space-between; - align-items: center; - - padding: var(--margins-sm) var(--margins-md); - background: none; - font-size: var(--font-size-xs); -`; - -const StyledSpanSessionInfo = styled.span<{ opacity?: number }>` - opacity: ${props => props.opacity ?? 0.5}; - transition: var(--default-duration); - user-select: text; - cursor: pointer; - - &:hover { - opacity: 1; - } -`; - -const SessionInfo = () => { - const [clickCount, setClickCount] = useState(0); - - const dispatch = useDispatch(); - - return ( - - { - showLinkVisitWarningDialog( - `https://github.com/session-foundation/session-desktop/releases/tag/v${window.versionInfo.version}`, - dispatch - ); - }} - > - v{window.versionInfo.version} - - - { - showLinkVisitWarningDialog('https://token.getsession.org/', dispatch); - }} - /> - - { - setClickCount(clickCount + 1); - if (clickCount === 10) { - dispatch(setDebugMode(true)); - setClickCount(0); - } - }} - > - {window.versionInfo.commitHash} - - - ); -}; - -const SettingInCategory = (props: { category: SessionSettingCategory }) => { - const { category } = props; - - switch (category) { - case 'recovery-password': - return ; - default: - return null; - } -}; - -const StyledSettings = styled.div` - width: var(--main-panel-content-width); - height: 100%; - display: flex; - flex-direction: column; - background-color: var(--background-secondary-color); -`; - -const StyledSettingsView = styled.div` - flex-grow: 1; - display: flex; - flex-direction: column; - justify-content: space-between; - overflow: hidden; -`; - -const StyledSettingsList = styled.div` - overflow-y: auto; - overflow-x: hidden; - display: flex; - flex-direction: column; -`; - -export const SessionSettingsView = (props: SettingsViewProps) => { - const { category } = props; - - return ( - - - - - - - - - - ); -}; diff --git a/ts/components/settings/SessionSettingsHeader.tsx b/ts/components/settings/SessionSettingsHeader.tsx deleted file mode 100644 index 33bda8441..000000000 --- a/ts/components/settings/SessionSettingsHeader.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import styled from 'styled-components'; -import { assertUnreachable } from '../../types/sqlSharedTypes'; -import { SettingsViewProps } from './SessionSettings'; -import { tr, type MergedLocalizerTokens } from '../../localization/localeTools'; - -type Props = Pick; - -const StyledSettingsHeader = styled.div` - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - height: var(--main-view-header-height); -`; - -const StyledHeaderTittle = styled.div` - line-height: var(--main-view-header-height); - font-weight: bold; - font-size: var(--font-size-lg); - text-align: center; - flex-grow: 1; -`; - -export const SettingsHeader = (props: Props) => { - const { category } = props; - - let categoryTitleKey: MergedLocalizerTokens | null = null; - switch (category) { - case 'recovery-password': - categoryTitleKey = 'sessionRecoveryPassword'; - break; - default: - assertUnreachable(category, `SettingsHeader "${category}"`); - } - - return ( - - {categoryTitleKey ? tr(categoryTitleKey) : null} - - ); -}; diff --git a/ts/state/ducks/section.tsx b/ts/state/ducks/section.tsx index 0f1dad455..de42dc745 100644 --- a/ts/state/ducks/section.tsx +++ b/ts/state/ducks/section.tsx @@ -1,12 +1,10 @@ // TODO move into redux slice import { createSlice, type PayloadAction } from '@reduxjs/toolkit'; -import type { SessionSettingCategory } from '../../types/ReduxTypes'; export enum SectionType { Profile, Message, - Settings, ThemeSwitch, DebugMenu, } @@ -28,7 +26,6 @@ export type RightOverlayMode = RightPanelDefaultState | RightPanelMessageInfoSta export const initialSectionState: SectionStateType = { focusedSection: SectionType.Message, - focusedSettingsSection: undefined, isAppFocused: false, leftOverlayMode: undefined, rightOverlayMode: { type: 'default', params: null }, @@ -36,7 +33,6 @@ export const initialSectionState: SectionStateType = { export type SectionStateType = { focusedSection: SectionType; - focusedSettingsSection?: SessionSettingCategory; isAppFocused: boolean; leftOverlayMode: LeftOverlayMode | undefined; rightOverlayMode: RightOverlayMode | undefined; @@ -50,7 +46,6 @@ const sectionSlice = createSlice({ return { ...state, focusedSection: action.payload, - focusedSettingsSection: undefined, }; }, setLeftOverlayMode(state, action: PayloadAction) { @@ -77,13 +72,6 @@ const sectionSlice = createSlice({ rightOverlayMode: undefined, }; }, - showSettingsSection(state, action: PayloadAction) { - return { - ...state, - focusedSettingsSection: action.payload, - focusedSection: SectionType.Settings, - }; - }, setIsAppFocused(state, action: PayloadAction) { return { ...state, diff --git a/ts/state/selectors/section.ts b/ts/state/selectors/section.ts index 59994dad7..a8d267c24 100644 --- a/ts/state/selectors/section.ts +++ b/ts/state/selectors/section.ts @@ -3,7 +3,6 @@ import { createSelector } from '@reduxjs/toolkit'; import { useSelector } from 'react-redux'; import { LeftOverlayMode, SectionStateType, SectionType } from '../ducks/section'; import { StateType } from '../reducer'; -import type { SessionSettingCategory } from '../../types/ReduxTypes'; export const getSection = (state: StateType): SectionStateType => state.section; @@ -20,11 +19,6 @@ export function useIsMessageSection() { return useSelector(getIsMessageSection); } -export const getFocusedSettingsSection = createSelector( - getSection, - (state: SectionStateType): SessionSettingCategory | undefined => state.focusedSettingsSection -); - export const getIsAppFocused = createSelector( getSection, (state: SectionStateType): boolean => state.isAppFocused diff --git a/ts/types/ReduxTypes.d.ts b/ts/types/ReduxTypes.d.ts index 2c0bac131..6cfa64271 100644 --- a/ts/types/ReduxTypes.d.ts +++ b/ts/types/ReduxTypes.d.ts @@ -5,8 +5,6 @@ * e.g. import type { YourTypeHere } from 'path/to/ReduxTypes'; */ -export type SessionSettingCategory = 'recovery-password'; - export type PasswordAction = 'set' | 'change' | 'remove' | 'enter'; export type EditProfilePictureModalProps = { From cac47d7bb60615ff8c29470cbc19d38d473fdd20 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Wed, 20 Aug 2025 15:29:55 +1000 Subject: [PATCH 12/18] chore: move the recovery password settings to modal --- _locales/af/messages.json | 15 +- _locales/ar/messages.json | 15 +- _locales/az/messages.json | 15 +- _locales/bal/messages.json | 15 +- _locales/be/messages.json | 15 +- _locales/bg/messages.json | 15 +- _locales/bn/messages.json | 15 +- _locales/ca/messages.json | 15 +- _locales/cs/messages.json | 15 +- _locales/cy/messages.json | 15 +- _locales/da/messages.json | 15 +- _locales/de/messages.json | 15 +- _locales/el/messages.json | 15 +- _locales/en/messages.json | 18 +- _locales/eo/messages.json | 15 +- _locales/es-419/messages.json | 15 +- _locales/es/messages.json | 15 +- _locales/et/messages.json | 15 +- _locales/eu/messages.json | 15 +- _locales/fa/messages.json | 17 +- _locales/fi/messages.json | 15 +- _locales/fil/messages.json | 15 +- _locales/fr/messages.json | 15 +- _locales/gl/messages.json | 15 +- _locales/ha/messages.json | 15 +- _locales/he/messages.json | 15 +- _locales/hi/messages.json | 15 +- _locales/hr/messages.json | 15 +- _locales/hu/messages.json | 15 +- _locales/hy-AM/messages.json | 17 +- _locales/id/messages.json | 15 +- _locales/it/messages.json | 15 +- _locales/ja/messages.json | 15 +- _locales/ka/messages.json | 15 +- _locales/km/messages.json | 15 +- _locales/kmr/messages.json | 15 +- _locales/kn/messages.json | 17 +- _locales/ko/messages.json | 15 +- _locales/ku/messages.json | 15 +- _locales/lg/messages.json | 15 +- _locales/lo/messages.json | 13 +- _locales/lt/messages.json | 15 +- _locales/lv/messages.json | 15 +- _locales/mk/messages.json | 15 +- _locales/mn/messages.json | 15 +- _locales/ms/messages.json | 15 +- _locales/my/messages.json | 15 +- _locales/nb/messages.json | 15 +- _locales/ne/messages.json | 17 +- _locales/nl/messages.json | 15 +- _locales/nn/messages.json | 15 +- _locales/no/messages.json | 15 +- _locales/ny/messages.json | 15 +- _locales/pa/messages.json | 15 +- _locales/pl/messages.json | 15 +- _locales/ps/messages.json | 15 +- _locales/pt-BR/messages.json | 15 +- _locales/pt-PT/messages.json | 15 +- _locales/ro/messages.json | 15 +- _locales/ru/messages.json | 15 +- _locales/sh/messages.json | 15 +- _locales/si/messages.json | 15 +- _locales/sk/messages.json | 15 +- _locales/sl/messages.json | 17 +- _locales/sq/messages.json | 15 +- _locales/sr-CS/messages.json | 15 +- _locales/sr-SP/messages.json | 17 +- _locales/sv/messages.json | 15 +- _locales/sw/messages.json | 15 +- _locales/ta/messages.json | 15 +- _locales/te/messages.json | 17 +- _locales/th/messages.json | 15 +- _locales/tl/messages.json | 15 +- _locales/tr/messages.json | 15 +- _locales/uk/messages.json | 17 +- _locales/ur/messages.json | 15 +- _locales/uz/messages.json | 15 +- _locales/vi/messages.json | 15 +- _locales/xh/messages.json | 15 +- _locales/zh-CN/messages.json | 15 +- _locales/zh-TW/messages.json | 15 +- ts/components/SessionWrapperModal.tsx | 6 +- ts/components/buttons/panel/PanelButton.tsx | 26 ++- .../buttons/panel/PanelIconButton.tsx | 3 +- .../buttons/panel/PanelWithButtonInline.tsx | 2 + .../header/ConversationHeaderSubtitle.tsx | 6 +- .../header/ConversationHeaderTitle.tsx | 8 +- .../message-info/OverlayMessageInfo.tsx | 10 +- .../dialog/HideRecoveryPasswordDialog.tsx | 3 +- .../conversationSettingsItems.tsx | 49 ++-- .../DisappearingMessagesPage.tsx | 4 +- .../DisappearingModes.tsx | 17 +- .../disappearing-messages/TimeOptions.tsx | 54 ++++- .../pages/notifications/NotificationPage.tsx | 5 +- .../user-settings/UserSettingsDialog.tsx | 12 +- .../components/SettingsChevronBasic.tsx | 15 +- .../components/SettingsExternalLinkBasic.tsx | 15 +- .../SettingsPanelButtonInlineBasic.tsx | 15 +- .../components/SettingsToggleBasic.tsx | 15 +- .../pages/AppearanceSettingsPage.tsx | 15 +- .../pages/ConversationSettingsPage.tsx | 16 +- .../pages/DefaultSettingsPage.tsx | 46 ++-- .../user-settings/pages/HelpSettingsPage.tsx | 20 +- .../pages/NotificationsSettingsPage.tsx | 33 ++- .../pages/PreferencesSettingsPage.tsx | 21 +- .../pages/PrivacySettingsPage.tsx | 36 +-- .../pages/RecoveryPasswordSettingsPage.tsx | 211 ++++++++++++++++++ ts/components/menu/Menu.tsx | 2 +- .../useLocalisedNotificationFor.ts | 9 +- .../settings/SessionSettingListItem.tsx | 203 ----------------- .../section/CategoryRecoveryPassword.tsx | 188 ---------------- ts/hooks/useIconToImageURL.tsx | 17 +- ts/hooks/useParamSelector.ts | 52 +---- ts/react.d.ts | 3 +- .../disappearing_messages/timerOptions.ts | 3 - ts/state/ducks/modalDialog.tsx | 2 +- ts/themes/globals.tsx | 4 + 117 files changed, 1475 insertions(+), 903 deletions(-) create mode 100644 ts/components/dialog/user-settings/pages/RecoveryPasswordSettingsPage.tsx delete mode 100644 ts/components/settings/SessionSettingListItem.tsx delete mode 100644 ts/components/settings/section/CategoryRecoveryPassword.tsx diff --git a/_locales/af/messages.json b/_locales/af/messages.json index 7c05d36da..4677003ee 100644 --- a/_locales/af/messages.json +++ b/_locales/af/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} en {other_name} is bevorder tot Admin.", "andMore": "+{count}", "anonymous": "Anoniem", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Versteek Kieslysbalk", "appearanceLanguage": "Taal", "appearanceLanguageDescription": "Kies jou taalinstelling vir Session. Session sal herbegin wanneer jy jou taalinstelling verander.", @@ -151,7 +153,6 @@ "callsSettings": "Oproepe (Beta)", "callsVoiceAndVideo": "Stem- en video-oproepe", "callsVoiceAndVideoBeta": "Stem- en video-oproepe (Beta)", - "callsVoiceAndVideoModalDescription": "Jou IP is sigbaar vir jou oproepmaat en 'n Oxen Foundation-bediener terwyl beta-oproepe gebruik word.", "callsVoiceAndVideoToggleDescription": "Aktiveer stem- en videoklank aanroep na en van ander gebruikers.", "callsYouCalled": "Jy het {name} gebel", "callsYouMissedCallPermissions": "Jy het 'n oproep gemis van {name} omdat jy nie Stem- en Video-oproepe in Privaatheid-instellings aangeskakel het nie.", @@ -525,6 +526,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Stemboodskap", "messages": "Boodskappe", "minimize": "Minimeer", + "networkName": "Session Network", "next": "Volgende", "nicknameDescription": "Kies 'n bynaam vir {name}. Dit sal vir jou verskyn in jou een-tot-een en groepe gesprekke.", "nicknameEnter": "Voer bynaam in", @@ -598,6 +600,7 @@ "onsErrorUnableToSearch": "Ons kon nie na hierdie ONS soek nie. Probeer asseblief later weer.", "open": "Oop", "other": "Ander", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Wysig Wagwoord", "passwordConfirm": "Bevestig wagwoord", "passwordCurrentIncorrect": "Jou huidige wagwoord is verkeerd.", @@ -706,9 +709,12 @@ "sessionAppearance": "Voorkoms", "sessionClearData": "Vee Data Uit", "sessionConversations": "Gesprekke", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Help", "sessionInviteAFriend": "Nooi 'n Vriend", "sessionMessageRequests": "Boodskap Versoeke", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Kennisgewing", "sessionPermissions": "Toestemmings", "sessionPrivacy": "Privaatheid", @@ -724,12 +730,15 @@ "show": "Wys", "showAll": "Wys almal", "showLess": "Wys minder", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Plakkers", "supportGoTo": "Gaan na Ondersteun Bladsy", "systemInformationDesktop": "Stelsel Inligting: {information}", "theContinue": "Gaan voort", "theDefault": "Verstek", "theError": "Fout", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Probeer Weer", "typingIndicators": "Tik Aanduiders", "typingIndicatorsDescription": "Sien en deel tik aanduiders.", @@ -749,6 +758,7 @@ "urlOpen": "Oop URL", "urlOpenBrowser": "Dit sal in jou blaaier oopmaak.", "urlOpenDescription": "Is jy seker jy wil hierdie URL in jou blaaier oopmaak?

{url}", + "usdNameShort": "USD", "useFastMode": "Gebruik Fast Mode", "video": "Video", "videoErrorPlay": "Kan nie video speel nie.", @@ -758,7 +768,6 @@ "warning": "Waarskuwing", "window": "Venster", "yes": "Ja", - "you": "Jy", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Jy" } diff --git a/_locales/ar/messages.json b/_locales/ar/messages.json index 7869e20f7..4bb188034 100644 --- a/_locales/ar/messages.json +++ b/_locales/ar/messages.json @@ -52,11 +52,13 @@ "appIconEnableIconAndName": "استخدام أيقونة واسم بديل للتطبيق", "appIconSelect": "حدد أيقونة بديلة للتطبيق", "appIconSelectionTitle": "أيقونة", + "appName": "Session", "appNameCalculator": "الآلة الحاسبة", "appNameNews": "الأخبار", "appNameNotes": "الملاحظات", "appNameStocks": "المخزون", "appNameWeather": "الطقس", + "appPro": "Session Pro", "appearanceHideMenuBar": "إخفاء شريط القائمة", "appearanceLanguage": "اللغة", "appearanceLanguageDescription": "اختر إعدادات اللغة الخاصة بك لتطبيق Session. سيعيد Session التشغيل عند تغيير إعدادات اللغة.", @@ -171,7 +173,6 @@ "callsSettings": "المكالمات (نسخة تجريبية)", "callsVoiceAndVideo": "المكالمات الصوتية و المرئية", "callsVoiceAndVideoBeta": "المكالمات الصوتية والمرئية (تجريبي)", - "callsVoiceAndVideoModalDescription": "عنوان IP الخاص بك مرئي لشريك الاتصال وخادم Oxen Foundation أثناء استخدام المكالمات التجريبية.", "callsVoiceAndVideoToggleDescription": "تفعيل المكالمات الصوتية والمرئية من وإلى المستخدمين الآخرين.", "callsYouCalled": "لقد اتصلت بـ {name}", "callsYouMissedCallPermissions": "لقد فاتتك مكالمة من {name} لأنك لم تقم بتمكين المكالمات الصوتية والمرئية في إعدادات الخصوصية.", @@ -571,6 +572,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} رسالة صوتية", "messages": "الرسائل", "minimize": "تصغير", + "networkName": "Session Network", "next": "التالي", "nicknameDescription": "اختر اسم مستعار لـ {name}. سيظهر لك في محادثاتك الفردية والجماعية.", "nicknameEnter": "أدخل اسم مستعار", @@ -647,6 +649,7 @@ "onsErrorUnableToSearch": "لم نتمكن من البحث عن هذا ONS. الرجاء المحاولة مرة أخرى لاحقا.", "open": "فتح", "other": "أخرى", + "oxenFoundation": "Oxen Foundation", "passwordChange": "تغيير كلمة السر", "passwordConfirm": "أَكِد كلمة المرور", "passwordCurrentIncorrect": "كلمة المرور الحالية غير صحيحة.", @@ -770,9 +773,12 @@ "sessionAppearance": "المظهر", "sessionClearData": "مسح البيانات", "sessionConversations": "المحادثات", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "المساعدة", "sessionInviteAFriend": "دعوة صديق", "sessionMessageRequests": "طلبات المُراسلة", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNetworkDescription": "يتم إرسال الرسائل باستخدام Session Network. تتكون الشبكة من عقد محفزة مع Session Token، الذي يحافظ على Session لامركزي وآمن. اعرف المزيد {icon}", "sessionNotifications": "الإشعارات", "sessionPermissions": "الصلاحيات", @@ -789,6 +795,7 @@ "show": "إظهار", "showAll": "إظهار الكل", "showLess": "عرض أقل", + "stakingRewardPool": "Staking Reward Pool", "stickers": "الملصقات", "supportGoTo": "الذهاب لصفحة الدعم", "systemInformationDesktop": "معلومات النظام: {information}", @@ -796,6 +803,8 @@ "theContinue": "استمرار", "theDefault": "افتراضي", "theError": "خطأ", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "حاول مجدداً", "typingIndicators": "مؤشرات الكتابة", "typingIndicatorsDescription": "شاهد وشارك مؤشرات الكتابة.", @@ -816,6 +825,7 @@ "urlOpen": "فتح الرابط", "urlOpenBrowser": "سيتم فتح هذا في متصفحك.", "urlOpenDescription": "هل أنت متأكد من فتح هذا الرابط في متصفحك؟

{url}", + "usdNameShort": "USD", "useFastMode": "استخدم الوضع السريع", "video": "فيديو", "videoErrorPlay": "تعذر تشغيل الفيديو", @@ -825,7 +835,6 @@ "warning": "تحذير", "window": "نافذة", "yes": "نعم", - "you": "أنت", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "أنت" } diff --git a/_locales/az/messages.json b/_locales/az/messages.json index 49c66481b..5f0d340c9 100644 --- a/_locales/az/messages.json +++ b/_locales/az/messages.json @@ -56,12 +56,14 @@ "appIconEnableIconAndName": "Alternativ tətbiq ikonunu və adını istifadə et", "appIconSelect": "Alternativ tətbiq ikonunu seç", "appIconSelectionTitle": "İkon", + "appName": "Session", "appNameCalculator": "Kalkulyator", "appNameMeetingSE": "MeetingSE", "appNameNews": "Xəbərlər", "appNameNotes": "Notlar", "appNameStocks": "Səhmlər", "appNameWeather": "Hava", + "appPro": "Session Pro", "appearanceHideMenuBar": "Menyu çubuğunu gizlət", "appearanceLanguage": "Dil", "appearanceLanguageDescription": "Session üçün dil ayarlarınızı seçin. Dil ayarlarını dəyişdirdikdə Session yenidən başladılacaq.", @@ -180,7 +182,6 @@ "callsSettings": "Zənglər (Beta)", "callsVoiceAndVideo": "Səsli və görüntülü zənglər", "callsVoiceAndVideoBeta": "Səsli və görüntülü zənglər (Beta)", - "callsVoiceAndVideoModalDescription": "Beta zənglərini istifadə edərkən IP ünvanınız zəng tərəfdaşınıza və Oxen Foundation serverinə görünür.", "callsVoiceAndVideoToggleDescription": "Digər istifadəçilərlə səsli və görüntülü zəngləri təmin edir.", "callsYouCalled": "{name} istifadəçisinə zəng etdiniz", "callsYouMissedCallPermissions": "Gizlilik Ayarlarında Səsli və görüntülü zənglər seçimini fəallaşdırmadığınız üçün {name} etdiyi bir zəngi buraxdınız.", @@ -624,6 +625,7 @@ "modalMessageCharacterTooLongTitle": "Mesaj çox uzundur", "modalMessageTooLongDescription": "Lütfən mesajınızı {limit} xarakter və ya daha az qədər qısaldın.", "modalMessageTooLongTitle": "Mesaj çox uzundur", + "networkName": "Session Network", "next": "Növbəti", "nicknameDescription": "{name} üçün bir ləqəb seçin. Bu, təkbətək və qrup danışıqlarınızda sizə görünəcək.", "nicknameEnter": "Ləqəb daxil edin", @@ -702,6 +704,7 @@ "open": "Aç", "openSurvey": "Anketi aç", "other": "Digər", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Parolu dəyişdir", "passwordConfirm": "Parolu təsdiqlə", "passwordCurrentIncorrect": "Hazırkı parolunuz yanlışdır.", @@ -864,10 +867,13 @@ "sessionAppearance": "Görünüş", "sessionClearData": "Veriləri təmizlə", "sessionConversations": "Danışıqlar", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Kömək", "sessionInviteAFriend": "Bir dostu dəvət et", "sessionMessageRequests": "Mesaj tələbləri", "sessionNetworkCurrentPrice": "Hazırkı SESH qiyməti", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNetworkDescription": "Mesajlar Session Network üzərindən göndərilir. Şəbəkə, Session tətbiqini mərkəzsiz və təhlükəsiz saxlamaq üçün Session Token ilə təşviq olunan node-lardan ibarətdir. Ətraflı öyrən {icon}", "sessionNetworkLearnAboutStaking": "Staking barədə ətraflı öyrən", "sessionNetworkMarketCap": "Bazar dəyəri", @@ -896,6 +902,7 @@ "showLess": "Daha az göstər", "showNoteToSelf": "Özünə Qeydi Göstər", "showNoteToSelfDescription": "Söhbət siyahınızda Özünə Qeydi göstərmək istədiyinizə əminsiniz?", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Stikerlər", "supportGoTo": "Dəstək Səhifəsinə get", "systemInformationDesktop": "Sistem məlumatı: {information}", @@ -903,6 +910,8 @@ "theContinue": "Davam", "theDefault": "İlkin", "theError": "Xəta", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tooltipAccountIdVisible": "{name} üçün Hesab ID-si əvvəlki qarşılıqlı əlaqələrə əsasən görünür", "tooltipBlindedIdCommunities": "Kor ID-lər, spamı azaltmaq və məxfiliyi artırmaq üçün icmalarda istifadə olunur", "tryAgain": "Yenidən sına", @@ -935,6 +944,7 @@ "urlOpen": "URL-ni aç", "urlOpenBrowser": "Bu, brauzerinizdə açılacaq.", "urlOpenDescription": "Bu URL-ni brauzerinizdə açmaq istədiyinizə əminsiniz?

{url}", + "usdNameShort": "USD", "useFastMode": "Sürətli rejimi istifadə et", "video": "Video", "videoErrorPlay": "Video oxudula bilmir.", @@ -946,7 +956,6 @@ "warning": "Xəbərdarlıq", "window": "Pəncərə", "yes": "Bəli", - "you": "Siz", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Siz" } diff --git a/_locales/bal/messages.json b/_locales/bal/messages.json index cc415b2d8..2de9fa22f 100644 --- a/_locales/bal/messages.json +++ b/_locales/bal/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} a {other_name} rīhīyā Admin šumār.", "andMore": "+{count}", "anonymous": "گمنام", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "مدارہء مینو ہڑین", "appearanceLanguage": "زبان", "appearanceLanguageDescription": "Session کے لے آپنی زبان کے ترتیب کو منتخب کریں۔ جب آپ اپنی زبان کی ترتیب بدلیں گے، Session دوبارہ شروع ہوگا۔", @@ -150,7 +152,6 @@ "callsSettings": "کالز (بیٹا)", "callsVoiceAndVideo": "وائس اور ویڈیو کالز", "callsVoiceAndVideoBeta": "وائس اور ویڈیو کالز (بیٹا)", - "callsVoiceAndVideoModalDescription": "ما گپ درخواست قبول کردی آپ کہ آئیں طرفه IP پدنی Oxen Foundation کہ سرورے ہ مغامیگیا.", "callsVoiceAndVideoToggleDescription": "دوسرے صارفین کو وائس اور ویڈیو کالز فعال کرتا ہے.", "callsYouCalled": "شمے {name} کال کد", "callsYouMissedCallPermissions": "ما گپ درخواست قبول کردی {name} سے کیونکہ تُ باقیneje ویس اینڈ ویڈیو کوالیں پرائیویسی تنظیمات میں فعال نہ کردی.", @@ -524,6 +525,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} وائس پیغام", "messages": "Messages", "minimize": "Minimize", + "networkName": "Session Network", "next": "گُدام", "nicknameDescription": "برای {name} یک کُرنا نام انتخاب کنے. ایں شما میں آپ ءَ یک به یک ءَ گروهیتی گفتگوئیں ظاہر ببت.", "nicknameEnter": "نک نیم درج بکنا", @@ -597,6 +599,7 @@ "onsErrorUnableToSearch": "ما پشتین اِس ONS سرکنت ناہ‌بی۔ امتحان بیبت ایر افت۔", "open": "گِس", "other": "دیگر", + "oxenFoundation": "Oxen Foundation", "passwordChange": "پاس ورڈ تبدیل کریں", "passwordConfirm": "رمز اے تصدیق کر", "passwordCurrentIncorrect": "تُں حالء پاسکوڈ نادرستیت.", @@ -705,9 +708,12 @@ "sessionAppearance": "ظہور", "sessionClearData": "ڈاٹا صفا کن", "sessionConversations": "گپ وڑانی", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "مدار", "sessionInviteAFriend": "ایک دوست کو دعوت دیں", "sessionMessageRequests": "Message Requests", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "چھوابما", "sessionPermissions": "اجازتاں", "sessionPrivacy": "نجی رہائش", @@ -723,12 +729,15 @@ "show": "نمایشـــی", "showAll": "ســـبے نمایـــش", "showLess": "کمتر نمایـــش", + "stakingRewardPool": "Staking Reward Pool", "stickers": "اسٹیکرز", "supportGoTo": "سپورٹ پیج بوت", "systemInformationDesktop": "System Information: {information}", "theContinue": "وارؤں", "theDefault": "بنیادی", "theError": "غلطی", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "پهر کوشش کریں", "typingIndicators": "ٹائپنگ انڈیکیٹرز", "typingIndicatorsDescription": "تور و اثیند زِمجی انڈیکیٹرز.", @@ -748,6 +757,7 @@ "urlOpen": "URL کھولتی", "urlOpenBrowser": "یہ آپ کے براؤزر میں کھل جائے گا.", "urlOpenDescription": "دم کی لحاظ انت کہ ایی URL براؤزر؟

{url}", + "usdNameShort": "USD", "useFastMode": "فاسٹ موڈ استعمال کریں", "video": "ویڈیو", "videoErrorPlay": "ویڈیو چلانے میں ناکامی۔", @@ -757,7 +767,6 @@ "warning": "انتباہ", "window": "ونڈو", "yes": "ہاں", - "you": "شما", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "شما" } diff --git a/_locales/be/messages.json b/_locales/be/messages.json index 5e332f313..7bdc56a85 100644 --- a/_locales/be/messages.json +++ b/_locales/be/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} і {other_name} былі павышаны да адміністратараў.", "andMore": "+{count}", "anonymous": "Anonymous", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Схаваць панэль меню", "appearanceLanguage": "Мова", "appearanceLanguageDescription": "Абярыце налады мовы для Session. Session перазапусціцца пасля змены налад мовы.", @@ -150,7 +152,6 @@ "callsSettings": "Званкі (бэта)", "callsVoiceAndVideo": "Галасавыя і відэазванкі", "callsVoiceAndVideoBeta": "Галасавыя і відэазванкі (бэта)", - "callsVoiceAndVideoModalDescription": "Ваш IP будзе бачныя вашаму партнёру па званках і серверу Oxen Foundation падчас выкарыстання бэта-званкоў.", "callsVoiceAndVideoToggleDescription": "Дазваляе рабіць галасавыя і відэазванкі іншым карыстальнікам.", "callsYouCalled": "Вы патэлефанавалі {name}", "callsYouMissedCallPermissions": "Вы прапусцілі званок ад {name}, таму што не ўключылі Галасавыя і відэазванкі у наладах прыватнасці.", @@ -524,6 +525,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Галасавое паведамленне", "messages": "Паведамленні", "minimize": "Згарнуць", + "networkName": "Session Network", "next": "Далей", "nicknameDescription": "Абярыце мянушку для {name}. Гэтую мянушку будзеце бачыць толькі вы ў асабістых і групавых размовах.", "nicknameEnter": "Увядзіце псеўданім", @@ -597,6 +599,7 @@ "onsErrorUnableToSearch": "Мы не змаглі зрабіць пошук па гэтым ONS. Калі ласка, паспрабуйце пазней.", "open": "Адкрыць", "other": "Іншае", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Змяніць пароль", "passwordConfirm": "Пацвердзіць пароль", "passwordCurrentIncorrect": "Ваш бягучы пароль няправільны.", @@ -705,9 +708,12 @@ "sessionAppearance": "Знешні выгляд", "sessionClearData": "Сцерці даныя", "sessionConversations": "Размовы", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Дапамога", "sessionInviteAFriend": "Запрасіць сябра", "sessionMessageRequests": "Запыты на паведамленні", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Апавяшчэнні", "sessionPermissions": "Дазволы", "sessionPrivacy": "Прыватнасць", @@ -723,12 +729,15 @@ "show": "Паказаць", "showAll": "Паказаць усё", "showLess": "Згарнуць", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Стыкеры", "supportGoTo": "Перайсці на старонку падтрымкі", "systemInformationDesktop": "Сістэмная інфармацыя: {information}", "theContinue": "Працягнуць", "theDefault": "Па змаўчанні", "theError": "Памылка", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Паспрабаваць зноў", "typingIndicators": "Індыкатары ўвода", "typingIndicatorsDescription": "Глядзіце і перадавайце індыкатар набору.", @@ -748,6 +757,7 @@ "urlOpen": "Адкрыць URL", "urlOpenBrowser": "Гэта адкрыецца ў вашай браўзеры.", "urlOpenDescription": "Вы ўпэўненыя, што жадаеце адкрыць гэты URL у вашым браўзэры?

{url}", + "usdNameShort": "USD", "useFastMode": "Выкарыстоўваць хуткі рэжым", "video": "Відэа", "videoErrorPlay": "Немагчыма прайграць відэа.", @@ -757,7 +767,6 @@ "warning": "Папярэджанне", "window": "Акно", "yes": "Так", - "you": "Вы", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Вы" } diff --git a/_locales/bg/messages.json b/_locales/bg/messages.json index 0684bfe09..e2d0c49ee 100644 --- a/_locales/bg/messages.json +++ b/_locales/bg/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} и {other_name} бяха повишени в Администратор.", "andMore": "+{count}", "anonymous": "Анонимен", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Скрий лентата с менюта", "appearanceLanguage": "Език", "appearanceLanguageDescription": "Изберете езиковите настройки за Session. Session ще се рестартира при промяна на езиковите настройки.", @@ -150,7 +152,6 @@ "callsSettings": "Обаждания (Beta)", "callsVoiceAndVideo": "Гласови и видео разговори", "callsVoiceAndVideoBeta": "Гласови и видеозаписи (Бета)", - "callsVoiceAndVideoModalDescription": "Вашият IP е видим за вашият партньор по време нослужване на beta обаждания и Oxen Foundation сървър.", "callsVoiceAndVideoToggleDescription": "Активира гласови и видеообаждания към и от други потребители.", "callsYouCalled": "Извикахте {name}", "callsYouMissedCallPermissions": "Пропуснахте обаждане от {name} защото не сте активирали Гласови и видео разговори в Настройки за поверителност.", @@ -524,6 +525,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Гласово съобщение", "messages": "Съобщения", "minimize": "Минимизиране", + "networkName": "Session Network", "next": "Следващ", "nicknameDescription": "Изберете прякор за {name}. Това ще се появи при вас в личните и груповите разговори.", "nicknameEnter": "Въведете псевдоним", @@ -597,6 +599,7 @@ "onsErrorUnableToSearch": "Не можахме да търсим този ONS. Моля, опитайте отново по-късно.", "open": "Отвори", "other": "Друг", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Смяна на парола", "passwordConfirm": "Потвърди парола", "passwordCurrentIncorrect": "Вашата текуща парола е неправилна.", @@ -705,9 +708,12 @@ "sessionAppearance": "Външен вид", "sessionClearData": "Изчистване на данните", "sessionConversations": "Разговори", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Помощ", "sessionInviteAFriend": "Покани приятел", "sessionMessageRequests": "Заявки за съобщения", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Известия", "sessionPermissions": "Разрешения", "sessionPrivacy": "Поверителност", @@ -723,12 +729,15 @@ "show": "Показване", "showAll": "Покажи всички", "showLess": "Покажи по-малко", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Стикери", "supportGoTo": "Отворете страницата за поддръжка", "systemInformationDesktop": "Системна информация: {information}", "theContinue": "Продължи", "theDefault": "По подразбиране", "theError": "Грешка", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Опитай отново", "typingIndicators": "Индикатори за писане", "typingIndicatorsDescription": "Виж и сподели индикаторите за писане.", @@ -748,6 +757,7 @@ "urlOpen": "Отвори URL", "urlOpenBrowser": "Това ще се отвори във вашия браузър.", "urlOpenDescription": "Сигурен ли си, че искаш да отвориш този URL във браузъра си?

{url}", + "usdNameShort": "USD", "useFastMode": "Използвайте Бърз Режим", "video": "Видео", "videoErrorPlay": "Неуспешно възпроизвеждане на видео.", @@ -757,7 +767,6 @@ "warning": "Предупреждение", "window": "Прозорец", "yes": "Да", - "you": "Ти", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Ти" } diff --git a/_locales/bn/messages.json b/_locales/bn/messages.json index 3d330c36b..df1eeaac4 100644 --- a/_locales/bn/messages.json +++ b/_locales/bn/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} এবং {other_name} অ্যাডমিন হিসেবে উন্নীত হয়েছে।", "andMore": "+{count}", "anonymous": "অ্যানোনিমাস", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "মেনু বার লুকান", "appearanceLanguage": "ভাষা", "appearanceLanguageDescription": "Session জন্য আপনার ভাষা সেটিং নির্বাচন করুন। আপনার ভাষা সেটিং পরিবর্তন করলে Session পুনরায় শুরু হবে।", @@ -150,7 +152,6 @@ "callsSettings": "কলস (বেটা)", "callsVoiceAndVideo": "ভয়েস এবং ভিডিও কল", "callsVoiceAndVideoBeta": "ভয়েস এবং ভিডিও কল (Beta)", - "callsVoiceAndVideoModalDescription": "বেটা কলগুলি ব্যবহার করার সময় আপনার আইপি আপনার কল পার্টনার এবং একটি Oxen Foundation সার্ভারের কাছে দৃশ্যমান হবে।", "callsVoiceAndVideoToggleDescription": "অন্য ব্যবহারকারীদের সাথে এবং তাদের থেকে ভয়েস এবং ভিডিও কল সক্রিয় করুন।", "callsYouCalled": "You called {name}", "callsYouMissedCallPermissions": "আপনি {name} এর একটি কল মিস করেছেন কারণ আপনি প্রাইভেসি সেটিংসে ভয়েস এবং ভিডিও কল সক্ষম করেননি।", @@ -524,6 +525,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} ভয়েস বার্তা", "messages": "মেসেজ", "minimize": "সর্বনিম্ন", + "networkName": "Session Network", "next": "পরবর্তী", "nicknameDescription": "{name} এর জন্য একটি ডাকনাম নির্বাচন করুন। এটি আপনাকে আপনার এক-তার-এক এবং গ্রুপ কথোপকথনে প্রদর্শিত হবে।", "nicknameEnter": "ডাকনাম লিখুন", @@ -597,6 +599,7 @@ "onsErrorUnableToSearch": "We were unable to search for this ONS. Please try again later.", "open": "ওপেন", "other": "অন্যান্য", + "oxenFoundation": "Oxen Foundation", "passwordChange": "পাসওয়ার্ড পরিবর্তন করুন", "passwordConfirm": "পাসওয়ার্ড নিশ্চিত করুন", "passwordCurrentIncorrect": "আপনার বর্তমান পাসওয়ার্ডটি ভুল।", @@ -705,9 +708,12 @@ "sessionAppearance": "অ্যাপিয়ারেন্স", "sessionClearData": "ডেটা মুছুন", "sessionConversations": "কথোপকথন", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "হেল্প", "sessionInviteAFriend": "একজন বন্ধুকে আমন্ত্রণ জানান", "sessionMessageRequests": "বার্তা অনুরোধ", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "নোটিফিকেশনের সেটিংস", "sessionPermissions": "অনুমতি", "sessionPrivacy": "গোপনীয়তা", @@ -723,12 +729,15 @@ "show": "দেখান", "showAll": "সব দেখান", "showLess": "কিছু দেখান", + "stakingRewardPool": "Staking Reward Pool", "stickers": "স্টিকার্স", "supportGoTo": "সাপোর্ট পেইজে যান", "systemInformationDesktop": "সিস্টেম তথ্য: {information}", "theContinue": "চালিয়ে যান", "theDefault": "পূর্ব-নির্ধারিত", "theError": "ত্রুটি", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "আবার চেষ্টা করুন", "typingIndicators": "টাইপিং নির্দেশিকা", "typingIndicatorsDescription": "টাইপিং ইনডিকেটরগুলি দেখুন এবং শেয়ার করুন।", @@ -748,6 +757,7 @@ "urlOpen": "URL খোল", "urlOpenBrowser": "এটি আপনার ব্রাউজারে খুলবে।", "urlOpenDescription": "আপনি কি এই URL আপনার ব্রাউজারে খুলতে নিশ্চিত?

{url}", + "usdNameShort": "USD", "useFastMode": "ফাস্ট মোড ব্যবহার করুন", "video": "ভিডিও", "videoErrorPlay": "ভিডিও চালাতে অক্ষম।", @@ -757,7 +767,6 @@ "warning": "Warning", "window": "Window", "yes": "হ্যাঁ", - "you": "তুমি", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "তুমি" } diff --git a/_locales/ca/messages.json b/_locales/ca/messages.json index 0cc19c851..8608e7054 100644 --- a/_locales/ca/messages.json +++ b/_locales/ca/messages.json @@ -56,12 +56,14 @@ "appIconEnableIconAndName": "Ús d'una icona i nom alternatiu", "appIconSelect": "Trieu una icona alternativa", "appIconSelectionTitle": "Icona", + "appName": "Session", "appNameCalculator": "Calculadora", "appNameMeetingSE": "MeetingSE", "appNameNews": "Notícies", "appNameNotes": "Notes", "appNameStocks": "Estocks", "appNameWeather": "Temps", + "appPro": "Session Pro", "appearanceHideMenuBar": "Amaga la barra de menú", "appearanceLanguage": "Llengua", "appearanceLanguageDescription": "Trieu la configuració de l'idioma per a Session. Session es reiniciarà quan canvieu la configuració de l'idioma.", @@ -180,7 +182,6 @@ "callsSettings": "Telefonades (Beta)", "callsVoiceAndVideo": "Telefonades de veu i de vídeo", "callsVoiceAndVideoBeta": "Telefonades de veu i de vídeo (Beta)", - "callsVoiceAndVideoModalDescription": "La vostra IP és visible a la vostra parella de trucada i a un servidor de Oxen Foundation mentre utilitzeu trucades beta.", "callsVoiceAndVideoToggleDescription": "Permeteu telefonades de veu i de vídeo a i des d'altres usuaris.", "callsYouCalled": "Heu telefonat a {name}", "callsYouMissedCallPermissions": "Heu rebut una trucada perduda de {name} perquè no heu activat Trucades de veu i vídeo en la Configuració de Privadesa.", @@ -623,6 +624,7 @@ "modalMessageCharacterTooLongTitle": "Missatge massa llarg", "modalMessageTooLongDescription": "Si us plau, escurceu el vostre missatge als {limit} caràcters o menys.", "modalMessageTooLongTitle": "Missatge massa llarg", + "networkName": "Session Network", "next": "Següent", "nicknameDescription": "Trieu un sobrenom per a {name}. Això us apareixerà a les vostres converses individuals i de grup.", "nicknameEnter": "Introdueix una sobrenom", @@ -701,6 +703,7 @@ "open": "Obriu", "openSurvey": "Enquesta oberta", "other": "Altres", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Canvia la contrasenya", "passwordConfirm": "Confirma la contrasenya", "passwordCurrentIncorrect": "La vostra contrasenya actual és incorrecta.", @@ -860,10 +863,13 @@ "sessionAppearance": "Aparença", "sessionClearData": "Esborrar les dades", "sessionConversations": "Converses", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Ajuda", "sessionInviteAFriend": "Convideu un amic", "sessionMessageRequests": "Sol·licituds de missatges", "sessionNetworkCurrentPrice": "Actual SESH preu", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNetworkDescription": "Els missatges s'envien mitjançant el nom de xarxa Session Network. La xarxa està formada per nodes incentivats amb Session Token, que manté Session descentralitzat i segur. Aprendre Més {icon}", "sessionNetworkLearnAboutStaking": "Aprèn sobre participar", "sessionNetworkMarketCap": "Cap de mercat", @@ -892,6 +898,7 @@ "showLess": "Mostreu menys", "showNoteToSelf": "Mostra la Nota a Si Mateix", "showNoteToSelfDescription": "Estàs segur que vols mostrar Nota a Si Mateix a la teva llista de converses?", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Adhesius", "supportGoTo": "Vés a la pàgina de suport", "systemInformationDesktop": "Informació del sistema: {information}", @@ -899,6 +906,8 @@ "theContinue": "Continuar", "theDefault": "Per defecte", "theError": "Error", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tooltipAccountIdVisible": "L'identificador del compte de {name} és visible en funció de les teves interaccions anteriors", "tooltipBlindedIdCommunities": "Els ID cecs s'utilitzen a les comunitats per reduir el correu brossa i augmentar la privadesa", "tryAgain": "Torna a provar", @@ -931,6 +940,7 @@ "urlOpen": "Obriu l'URL", "urlOpenBrowser": "Això s'obrirà en el vostre navegador.", "urlOpenDescription": "Esteu segur que voleu obrir aquest URL al vostre navegador?

{url}", + "usdNameShort": "USD", "useFastMode": "Feu servir el Mode ràpid", "video": "Vídeo", "videoErrorPlay": "No es pot reproduir el vídeo.", @@ -942,7 +952,6 @@ "warning": "Avís", "window": "Finestra", "yes": "Sí", - "you": "Vós", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Vós" } diff --git a/_locales/cs/messages.json b/_locales/cs/messages.json index cdb0991ae..94577520e 100644 --- a/_locales/cs/messages.json +++ b/_locales/cs/messages.json @@ -56,12 +56,14 @@ "appIconEnableIconAndName": "Použít alternativní ikonu a název aplikace", "appIconSelect": "Výběr alternativní ikony aplikace", "appIconSelectionTitle": "Ikona", + "appName": "Session", "appNameCalculator": "Kalkulačka", "appNameMeetingSE": "MeetingSE", "appNameNews": "Zprávy", "appNameNotes": "Poznámky", "appNameStocks": "Akcie", "appNameWeather": "Počasí", + "appPro": "Session Pro", "appearanceHideMenuBar": "Skrýt menu", "appearanceLanguage": "Jazyk", "appearanceLanguageDescription": "Vyberte jazykové nastavení pro Session. Session se restartuje, když změníte jazykové nastavení.", @@ -180,7 +182,6 @@ "callsSettings": "Hovory (Beta)", "callsVoiceAndVideo": "Hlasové a video hovory", "callsVoiceAndVideoBeta": "Hlasové a video hovory (Beta)", - "callsVoiceAndVideoModalDescription": "Vaše IP adresa je při používání beta hovorů viditelná pro vašeho volacího partnera a server Oxen Foundation.", "callsVoiceAndVideoToggleDescription": "Povolí hlasové a video hovory k ostatním uživatelům i od nich.", "callsYouCalled": "Volali jste {name}", "callsYouMissedCallPermissions": "Zmeškali jste hovor od {name}, protože jste neměli povoleny Hlasové a video hovory v nastavení ochrany soukromí.", @@ -624,6 +625,7 @@ "modalMessageCharacterTooLongTitle": "Zpráva je příliš dlouhá", "modalMessageTooLongDescription": "Zkraťte prosím svou zprávu na {limit} znaků nebo méně.", "modalMessageTooLongTitle": "Zpráva je příliš dlouhá", + "networkName": "Session Network", "next": "Další", "nicknameDescription": "Vyberte přezdívku pro {name}. Zobrazí se vám v konverzacích jeden na jednoho a ve skupinách.", "nicknameEnter": "Zadejte přezdívku", @@ -702,6 +704,7 @@ "open": "Otevřít", "openSurvey": "Otevřít dotazník", "other": "Ostatní", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Změnit heslo", "passwordConfirm": "Potvrďte heslo", "passwordCurrentIncorrect": "Vaše aktuální heslo je nesprávné.", @@ -864,10 +867,13 @@ "sessionAppearance": "Vzhled", "sessionClearData": "Vyčistit data", "sessionConversations": "Konverzace", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Nápověda", "sessionInviteAFriend": "Pozvat přátele", "sessionMessageRequests": "Žádosti o komunikaci", "sessionNetworkCurrentPrice": "Aktuální cena SESH", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNetworkDescription": "Zprávy se odesílají pomocí Session Network. Síť se skládá ze serverů, jejichž provozovatelé jsou odměňováni pomocí Session Token, což zajišťuje decentralizaci a bezpečnost Session. Další informace {icon}", "sessionNetworkLearnAboutStaking": "Přečtěte si o stakingu", "sessionNetworkMarketCap": "Tržní kapitalizace", @@ -896,6 +902,7 @@ "showLess": "Zobrazit méně", "showNoteToSelf": "Zobrazit Poznámku sobě", "showNoteToSelfDescription": "Opravdu chcete zobrazit Poznámku sobě ve svém seznamu konverzací?", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Nálepky", "supportGoTo": "Přejít na stránky podpory", "systemInformationDesktop": "Systémové informace: {information}", @@ -903,6 +910,8 @@ "theContinue": "Pokračovat", "theDefault": "Výchozí", "theError": "Chyba", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tooltipAccountIdVisible": "ID účtu {name} je viditelné
v závislosti na vašich předchozích interakcích", "tooltipBlindedIdCommunities": "Maskovaná ID jsou používána v komunitách
ke snížení spamu a zvýšení soukromí", "tryAgain": "Zkusit znovu", @@ -935,6 +944,7 @@ "urlOpen": "Otevřít odkaz", "urlOpenBrowser": "Toto se otevře ve vašem prohlížeči.", "urlOpenDescription": "Opravdu chcete otevřít tuto URL adresu ve vašem prohlížeči?

{url}", + "usdNameShort": "USD", "useFastMode": "Použít rychlý režim", "video": "Video", "videoErrorPlay": "Nelze přehrát video.", @@ -946,7 +956,6 @@ "warning": "Varování", "window": "Okno", "yes": "Ano", - "you": "Vy", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Vy" } diff --git a/_locales/cy/messages.json b/_locales/cy/messages.json index 4968cca5a..d4557dce1 100644 --- a/_locales/cy/messages.json +++ b/_locales/cy/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} y a {other_name} penodwyd i admin.", "andMore": "+{count}", "anonymous": "Dienw", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Cuddio Bar Dewislen", "appearanceLanguage": "Iaith", "appearanceLanguageDescription": "Dewiswch eich gosodiad iaith ar gyfer Session. Bydd Session yn ailgychwyn pan fyddwch chi'n newid eich gosodiad iaith.", @@ -152,7 +154,6 @@ "callsSettings": "Galwadau (Beta)", "callsVoiceAndVideo": "Galwadau Llais a Fideo", "callsVoiceAndVideoBeta": "Galwadau Llais a Fideo (Beta)", - "callsVoiceAndVideoModalDescription": "Mae eich GPS yn weladwy i'ch partner galwad ac i Wasanaeth Node Foundation Oxen wrth ddefnyddio galwadau beta.", "callsVoiceAndVideoToggleDescription": "Yn caniatáu galwadau llais a fideo i ac o ddefnyddwyr eraill.", "callsYouCalled": "Wedi galw {name}", "callsYouMissedCallPermissions": "Buoch yn methu alwad gan {name} oherwydd nad ydych wedi galluogi Galwadau Llais a Fideo yn Gosodiadau Preifatrwydd.", @@ -534,6 +535,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Neges Llais", "messages": "Negeseuon", "minimize": "Lleihau", + "networkName": "Session Network", "next": "Nesaf", "nicknameDescription": "Dewiswch lysenw ar gyfer {name}. Bydd hyn yn ymddangos ichi yn eich sgyrsiau un-i-un a grŵp.", "nicknameEnter": "Rhowch lysenw", @@ -608,6 +610,7 @@ "onsErrorUnableToSearch": "Methwyd chwilio am y ONS hwn. Rhowch gynnig arall arni yn nes ymlaen.", "open": "Agor", "other": "Arall", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Newid Cyfrinair", "passwordConfirm": "Cadarnhau cyfrinair", "passwordCurrentIncorrect": "Mae eich cyfrinair cyfredol yn anghywir.", @@ -716,9 +719,12 @@ "sessionAppearance": "Golwg", "sessionClearData": "Clirio data", "sessionConversations": "Sgyrsiau", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Cymorth", "sessionInviteAFriend": "Gwahodd Ffrind", "sessionMessageRequests": "Ceisiadau Negeseuon", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Hysbysiadau", "sessionPermissions": "Caniatâd", "sessionPrivacy": "Preifatrwydd", @@ -734,12 +740,15 @@ "show": "Dangos", "showAll": "Dangos Pob Un", "showLess": "Dangos Llai", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Sticeri", "supportGoTo": "Ewch i Dudalen Cymorth", "systemInformationDesktop": "Gwybodaeth am y System: {information}", "theContinue": "Parhau", "theDefault": "Rhagosodedig", "theError": "Gwall", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Ceisio eto", "typingIndicators": "Dangosyddion Teipio", "typingIndicatorsDescription": "Gweld a rhannu dangosyddion teipio.", @@ -759,6 +768,7 @@ "urlOpen": "Agor URL", "urlOpenBrowser": "Bydd hyn yn agor yn eich porwr.", "urlOpenDescription": "Ydych chi'n siŵr eich bod am agor y URL hwn yn eich porwr?

{url}", + "usdNameShort": "USD", "useFastMode": "Defnyddiwch Dull Cyflym", "video": "Fideo", "videoErrorPlay": "Methu chwarae fideo.", @@ -768,7 +778,6 @@ "warning": "Rhybudd", "window": "Ffenestr", "yes": "Iawn", - "you": "Chi", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Chi" } diff --git a/_locales/da/messages.json b/_locales/da/messages.json index da5066b92..e020ce32a 100644 --- a/_locales/da/messages.json +++ b/_locales/da/messages.json @@ -51,12 +51,14 @@ "appIconEnableIconAndName": "Brug alternativ app-ikon og -navn", "appIconSelect": "Vælg alternativ app-ikon", "appIconSelectionTitle": "Ikon", + "appName": "Session", "appNameCalculator": "Lommeregner", "appNameMeetingSE": "MødeSE", "appNameNews": "Nyheder", "appNameNotes": "Noter", "appNameStocks": "Aktier", "appNameWeather": "Vejr", + "appPro": "Session Pro", "appearanceHideMenuBar": "Skjul Menulinje", "appearanceLanguage": "Sprog", "appearanceLanguageDescription": "Vælg din sproglige indstilling for Session. Session vil genstarte, når du ændrer dine sprogindstillinger.", @@ -173,7 +175,6 @@ "callsSettings": "Opkald (Beta)", "callsVoiceAndVideo": "Lyd- og videoopkald", "callsVoiceAndVideoBeta": "Lyd- og videoopkald (Beta)", - "callsVoiceAndVideoModalDescription": "Din IP synlig for din opkaldspartner og en Oxen Foundation-server, mens du bruger betaopkald.", "callsVoiceAndVideoToggleDescription": "Aktiverer lyd- og videoopkald til og fra andre brugere.", "callsYouCalled": "Du ringede til {name}", "callsYouMissedCallPermissions": "Du gik glip af et opkald fra {name}, fordi du ikke har aktiveret Stemmen- og videoopkald i privatindstillinger.", @@ -595,6 +596,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Talebesked", "messages": "Beskeder", "minimize": "Minimér", + "networkName": "Session Network", "next": "Næste", "nicknameDescription": "Vælg et kælenavn for {name}. Dette vil blive vist for dig i din en-til-en samtaler og gruppekonversationer.", "nicknameEnter": "Indtast et kaldenavn", @@ -671,6 +673,7 @@ "onsErrorUnableToSearch": "Vi kunne ikke søge efter dette ONS. Prøv igen senere.", "open": "Åben", "other": "Andet", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Skift adgangskode", "passwordConfirm": "Bekræft kodeord", "passwordCurrentIncorrect": "Din nuværende adgangskode er forkert.", @@ -800,9 +803,12 @@ "sessionAppearance": "Udseende", "sessionClearData": "Ryd data", "sessionConversations": "Samtaler", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Hjælp", "sessionInviteAFriend": "Inviter en ven", "sessionMessageRequests": "Beskedanmodninger", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Notifikationer", "sessionPermissions": "Tilladelser", "sessionPrivacy": "Privatliv", @@ -822,6 +828,7 @@ "showLess": "Vis mindre", "showNoteToSelf": "Egen note", "showNoteToSelfDescription": "Er du sikker på, at du vil vise Egen note i din samtaleliste?", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Klistermærker", "supportGoTo": "Gå til supportsiden", "systemInformationDesktop": "Systemoplysninger: {information}", @@ -829,6 +836,8 @@ "theContinue": "Fortsæt", "theDefault": "Standard", "theError": "Fejl", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Prøv igen", "typingIndicators": "Skrive Indicatorer", "typingIndicatorsDescription": "Se og del skrive indikatorer.", @@ -852,6 +861,7 @@ "urlOpen": "Åben URL", "urlOpenBrowser": "Dette åbnes i din browser.", "urlOpenDescription": "Er du sikker på, at du vil åbne denne URL i din browser?

{url}", + "usdNameShort": "USD", "useFastMode": "Brug Hurtig Tilstand", "video": "Video", "videoErrorPlay": "Kan ikke afspille video.", @@ -863,7 +873,6 @@ "warning": "Advarsel", "window": "Vindue", "yes": "Ja", - "you": "Du", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Du" } diff --git a/_locales/de/messages.json b/_locales/de/messages.json index af48e6fb6..9023fed97 100644 --- a/_locales/de/messages.json +++ b/_locales/de/messages.json @@ -56,12 +56,14 @@ "appIconEnableIconAndName": "Alternatives App-Symbol und -Name verwenden", "appIconSelect": "Alternatives App-Symbol auswählen", "appIconSelectionTitle": "Symbol", + "appName": "Session", "appNameCalculator": "Taschenrechner", "appNameMeetingSE": "MeetingSE", "appNameNews": "Neuigkeiten", "appNameNotes": "Notizen", "appNameStocks": "Aktien", "appNameWeather": "Wetterbericht", + "appPro": "Session Pro", "appearanceHideMenuBar": "Menüleiste ausblenden", "appearanceLanguage": "Sprache", "appearanceLanguageDescription": "Wähle deine Spracheinstellung für Session. Session wird neu gestartet, wenn du deine Spracheinstellung änderst.", @@ -180,7 +182,6 @@ "callsSettings": "Anrufe (Beta)", "callsVoiceAndVideo": "Sprach- und Videoanrufe", "callsVoiceAndVideoBeta": "Sprach- und Videoanrufe (Beta)", - "callsVoiceAndVideoModalDescription": "Deine IP ist für deinen Gesprächspartner und einen Oxen Foundation Server sichtbar, während du Beta-Anrufe nutzt.", "callsVoiceAndVideoToggleDescription": "Aktiviert Sprach- und Videoanrufe an und von anderen Benutzern.", "callsYouCalled": "Du hast {name} angerufen", "callsYouMissedCallPermissions": "Du hast einen Anruf von {name} verpasst, weil du Sprach- und Videoanrufe in den Datenschutzeinstellungen nicht aktiviert hast.", @@ -624,6 +625,7 @@ "modalMessageCharacterTooLongTitle": "Nachricht zu lang", "modalMessageTooLongDescription": "Bitte kürze deine Nachricht auf {limit} Zeichen oder weniger.", "modalMessageTooLongTitle": "Nachricht zu lang", + "networkName": "Session Network", "next": "Weiter", "nicknameDescription": "Wähle einen Spitznamen für {name}. Dieser wird dir in deinen Einzel- und Gruppengesprächen angezeigt.", "nicknameEnter": "Spitzname eingeben", @@ -702,6 +704,7 @@ "open": "Öffnen", "openSurvey": "Umfrage starten", "other": "Sonstiges", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Passwort ändern", "passwordConfirm": "Passwort bestätigen", "passwordCurrentIncorrect": "Dein aktuelles Passwort ist nicht korrekt.", @@ -864,10 +867,13 @@ "sessionAppearance": "Darstellung", "sessionClearData": "Daten löschen", "sessionConversations": "Chats", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Hilfe", "sessionInviteAFriend": "Einen Kontakt einladen", "sessionMessageRequests": "Nachrichtenanfragen", "sessionNetworkCurrentPrice": "Aktueller SESH-Preis", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNetworkDescription": "Nachrichten werden über das Session Network gesendet. Das Netzwerk besteht aus Knoten, die mit Session Token incentiviert werden, wodurch Session dezentral und sicher bleibt. Mehr erfahren {icon}", "sessionNetworkLearnAboutStaking": "Mehr über Staking erfahren", "sessionNetworkMarketCap": "Marktkapitalisierung", @@ -896,6 +902,7 @@ "showLess": "Weniger anzeigen", "showNoteToSelf": "»Notiz an mich« anzeigen", "showNoteToSelfDescription": "Möchtest du Notiz an mich wirklich in deiner Unterhaltungsliste anzeigen?", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Sticker", "supportGoTo": "Zum Helpdesk gehen", "systemInformationDesktop": "Systeminformation: {information}", @@ -903,6 +910,8 @@ "theContinue": "Weiter", "theDefault": "Standard", "theError": "Fehler", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tooltipAccountIdVisible": "Die Account-ID von {name} ist basierend auf deinen vorherigen Interaktionen sichtbar", "tooltipBlindedIdCommunities": "Verschleierte IDs werden in Communities verwendet, um Spam zu reduzieren und die Privatsphäre zu erhöhen", "tryAgain": "Erneut versuchen", @@ -935,6 +944,7 @@ "urlOpen": "URL öffnen", "urlOpenBrowser": "Dies wird in deinem Browser geöffnet.", "urlOpenDescription": "Bist du sicher, dass du diese URL in deinem Browser öffnen wollen?

{url}", + "usdNameShort": "USD", "useFastMode": "Schnellen Modus verwenden", "video": "Video", "videoErrorPlay": "Videowiedergabe fehlgeschlagen.", @@ -946,7 +956,6 @@ "warning": "Warnung", "window": "Fenster", "yes": "Ja", - "you": "Du", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Du" } diff --git a/_locales/el/messages.json b/_locales/el/messages.json index fad83fea6..256f4e8a3 100644 --- a/_locales/el/messages.json +++ b/_locales/el/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} και {other_name} προωθήθηκαν στο Admin.", "andMore": "+{count}", "anonymous": "Ανώνυμος", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Απόκρυψη Γραμμής Μενού", "appearanceLanguage": "Γλώσσα", "appearanceLanguageDescription": "Επιλέξτε τις γλωσσικές ρυθμίσεις για το Session. Το Session θα επανεκκινήσει όταν αλλάξετε τις γλωσσικές σας ρυθμίσεις.", @@ -152,7 +154,6 @@ "callsSettings": "Κλήσεις (Beta)", "callsVoiceAndVideo": "Κλήσεις Φωνής και Βίντεο", "callsVoiceAndVideoBeta": "Κλήσεις Φωνής και Βίντεο (Beta)", - "callsVoiceAndVideoModalDescription": "Η διεύθυνση IP σας είναι ορατή στον συνομιλητή σας και σε έναν διακομιστή του Oxen Foundation κατά τη χρήση κλήσεων beta.", "callsVoiceAndVideoToggleDescription": "Επιτρέπει κλήσεις φωνής και βίντεο από και προς άλλους χρήστες.", "callsYouCalled": "Καλέσατε {name}", "callsYouMissedCallPermissions": "Χάσατε μια κλήση από {name} επειδή δεν έχετε ενεργοποιήσει τις Κλήσεις Φωνής και Βίντεο στις Ρυθμίσεις Απορρήτου.", @@ -534,6 +535,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Ηχητικό μήνυμα", "messages": "Μηνύματα", "minimize": "Ελαχιστοποίηση", + "networkName": "Session Network", "next": "Επόμενο", "nicknameDescription": "Επιλέξτε ένα ψευδώνυμο για {name}. Αυτό θα εμφανιστεί σε εσάς στις προσωπικές και ομαδικές συνομιλίες σας.", "nicknameEnter": "Εισαγάγετε ένα ψευδώνυμο", @@ -608,6 +610,7 @@ "onsErrorUnableToSearch": "Δεν μπορέσαμε να αναζητήσουμε αυτό το ONS. Παρακαλώ δοκιμάστε ξανά αργότερα.", "open": "Άνοιγμα", "other": "Άλλο", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Αλλαγή Κωδικού Πρόσβασης", "passwordConfirm": "Επιβεβαίωση κωδικού πρόσβασης", "passwordCurrentIncorrect": "Ο τρέχων κωδικός πρόσβασής σας είναι λανθασμένος.", @@ -716,9 +719,12 @@ "sessionAppearance": "Εμφάνιση", "sessionClearData": "Διαγραφή Δεδομένων", "sessionConversations": "Συνομιλίες", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Βοήθεια", "sessionInviteAFriend": "Προσκλήσεις στα Επαφές", "sessionMessageRequests": "Αιτήματα μηνυμάτων", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Ειδοποιήσεις", "sessionPermissions": "Άδειες", "sessionPrivacy": "Απόρρητο", @@ -734,12 +740,15 @@ "show": "Εμφάνιση", "showAll": "Εμφάνιση Όλων", "showLess": "Εμφάνιση Λιγότερων", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Αυτοκόλλητα", "supportGoTo": "Μετάβαση στη Σελίδα Υποστήριξης", "systemInformationDesktop": "Πληροφορίες Συστήματος: {information}", "theContinue": "Συνέχεια", "theDefault": "Προεπιλογή", "theError": "Σφάλμα", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Προσπαθήστε Ξανά", "typingIndicators": "Δείκτες Πληκτρολόγησης", "typingIndicatorsDescription": "Δείτε και κοινοποιήστε δείκτες πληκτρολόγησης.", @@ -759,6 +768,7 @@ "urlOpen": "Άνοιγμα URL", "urlOpenBrowser": "Αυτό θα ανοίξει στο πρόγραμμα περιήγησής σας.", "urlOpenDescription": "Σίγουρα θέλετε να ανοίξετε αυτό το URL στο πρόγραμμα περιήγησής σας;

{url}", + "usdNameShort": "USD", "useFastMode": "Χρήση Γρήγορης Λειτουργίας", "video": "Βίντεο", "videoErrorPlay": "Αδυναμία αναπαραγωγής βίντεο.", @@ -768,7 +778,6 @@ "warning": "Προειδοποίηση", "window": "Παράθυρο", "yes": "Ναι", - "you": "Εσείς", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Εσείς" } diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 899f04db9..d82e11522 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -56,12 +56,14 @@ "appIconEnableIconAndName": "Use alternate app icon and name", "appIconSelect": "Select alternate app icon", "appIconSelectionTitle": "Icon", + "appName": "Session", "appNameCalculator": "Calculator", "appNameMeetingSE": "MeetingSE", "appNameNews": "News", "appNameNotes": "Notes", "appNameStocks": "Stocks", "appNameWeather": "Weather", + "appPro": "Session Pro", "appearanceAutoDarkMode": "Auto Dark Mode", "appearanceHideMenuBar": "Hide Menu Bar", "appearanceLanguage": "Language", @@ -182,7 +184,7 @@ "callsSettings": "Calls (Beta)", "callsVoiceAndVideo": "Voice and Video Calls", "callsVoiceAndVideoBeta": "Voice and Video Calls (Beta)", - "callsVoiceAndVideoModalDescription": "Your IP is visible to your call partner and a Session Technology Foundation server while using beta calls.", + "callsVoiceAndVideoModalDescription": "Your IP is visible to your call partner and a Session Foundation server while using beta calls.", "callsVoiceAndVideoToggleDescription": "Enables voice and video calls to and from other users.", "callsYouCalled": "You called {name}", "callsYouMissedCallPermissions": "You missed a call from {name} because you haven't enabled Voice and Video Calls in Privacy Settings.", @@ -568,6 +570,7 @@ "linkPreviewsSendModalDescription": "You will not have full metadata protection when sending link previews.", "linkPreviewsTurnedOff": "Link Previews Are Off", "linkPreviewsTurnedOffDescription": "Session must contact linked websites to generate previews of links you send and receive.

You can turn them on in Session's settings.", + "links": "Links", "loadAccount": "Load Account", "loadAccountProgressMessage": "Loading your account", "loading": "Loading...", @@ -580,6 +583,7 @@ "lockAppStatus": "Lock status", "lockAppUnlock": "Tap to unlock", "lockAppUnlocked": "Session is unlocked", + "logs": "Logs", "manageMembers": "Manage Members", "max": "Max", "media": "Media", @@ -648,6 +652,7 @@ "modalMessageCharacterTooLongTitle": "Message Too Long", "modalMessageTooLongDescription": "Please shorten your message to {limit} characters or less.", "modalMessageTooLongTitle": "Message Too Long", + "networkName": "Session Network", "next": "Next", "nicknameDescription": "Choose a nickname for {name}. This will appear to you in your one-to-one and group conversations.", "nicknameEnter": "Enter nickname", @@ -731,6 +736,7 @@ "open": "Open", "openSurvey": "Open Survey", "other": "Other", + "oxenFoundation": "Oxen Foundation", "password": "Password", "passwordChange": "Change Password", "passwordChangeShortDescription": "Change the password required to unlock Session.", @@ -917,10 +923,13 @@ "sessionAppearance": "Appearance", "sessionClearData": "Clear Data", "sessionConversations": "Conversations", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Help", "sessionInviteAFriend": "Invite a Friend", "sessionMessageRequests": "Message Requests", "sessionNetworkCurrentPrice": "Current SESH price", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNetworkDescription": "Messages are sent using the Session Network. The network is comprised of nodes incentivized with Session Token, which keeps Session decentralized and secure. Learn More {icon}", "sessionNetworkLearnAboutStaking": "Learn About Staking", "sessionNetworkMarketCap": "Market Cap", @@ -951,6 +960,7 @@ "showNoteToSelf": "Show Note to Self", "showNoteToSelfDescription": "Are you sure you want to show Note to Self in your conversation list?", "spellChecker": "Spell Checker", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Stickers", "strength": "Strength", "supportDescription": "Having issues? Explore help articles or open a ticket with Session Support.", @@ -961,6 +971,8 @@ "theDefault": "Default", "theError": "Error", "themePreview": "Theme Preview", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tooltipAccountIdVisible": "The Account ID of {name} is visible based on your previous interactions", "tooltipBlindedIdCommunities": "Blinded IDs are used in communities to reduce spam and increase privacy", "translate": "Translate", @@ -999,6 +1011,7 @@ "urlOpen": "Open URL", "urlOpenBrowser": "This will open in your browser.", "urlOpenDescription": "Are you sure you want to open this URL in your browser?

{url}", + "usdNameShort": "USD", "useFastMode": "Use Fast Mode", "video": "Video", "videoErrorPlay": "Unable to play video.", @@ -1013,7 +1026,6 @@ "you": "You", "yourRecoveryPassword": "Your Recovery Password", "zoomFactor": "Zoom Factor", - "zoomFactorDescription": "Adjust the size of text and visual elements.", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "zoomFactorDescription": "Adjust the size of text and visual elements." } diff --git a/_locales/eo/messages.json b/_locales/eo/messages.json index eff9ea4d2..67b597672 100644 --- a/_locales/eo/messages.json +++ b/_locales/eo/messages.json @@ -51,12 +51,14 @@ "appIconEnableIconAndName": "Uzi alternativan piktogramon de aplikaĵo kaj nomon", "appIconSelect": "Elektu alternativan piktogramon de aplikaĵo", "appIconSelectionTitle": "Piktogramo", + "appName": "Session", "appNameCalculator": "Kalkulilo", "appNameMeetingSE": "KunvenoSE", "appNameNews": "Novaĵoj", "appNameNotes": "Notoj", "appNameStocks": "Akcioj", "appNameWeather": "Vetero", + "appPro": "Session Pro", "appearanceHideMenuBar": "Kaŝi Menuan Stangon", "appearanceLanguage": "Lingvo", "appearanceLanguageDescription": "Elektu vian lingv-agordon por Session. Session rekomenciĝos kiam vi ŝanĝos vian lingv-agordon.", @@ -173,7 +175,6 @@ "callsSettings": "Vokoj (Beto)", "callsVoiceAndVideo": "Voĉaj kaj Videaj Vokoj", "callsVoiceAndVideoBeta": "Voĉaj kaj Videaj Vokoj (Beta)", - "callsVoiceAndVideoModalDescription": "Via IP-adreso estas videbla al via vokopartnero kaj al servilo de Oxen Foundation dum vi uzas betajn vokojn.", "callsVoiceAndVideoToggleDescription": "Ebligas voĉajn kaj vidajn vokojn al kaj de aliaj uzantoj.", "callsYouCalled": "Vi alvokis {name}", "callsYouMissedCallPermissions": "Vi maltrafis vokon de {name} ĉar vi ne ebligis Voĉajn kaj Video-Vokojn en la Privateco-Agordoj.", @@ -584,6 +585,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Voĉmesaĝo", "messages": "Mesaĝoj", "minimize": "Plejetigi", + "networkName": "Session Network", "next": "Sekva", "nicknameDescription": "Elektu kromnomon por {name}. Ĉi tio aperos al vi en viaj unu-kontraŭ-unu kaj grupaj konversacioj.", "nicknameEnter": "Entajpu alnomon", @@ -660,6 +662,7 @@ "onsErrorUnableToSearch": "Ni ne povis serĉi ĉi tiun ONS. Bonvolu reprovi poste.", "open": "Malfermi", "other": "Alia", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Ŝanĝi Pasvorton", "passwordConfirm": "Konfirmi pasvorton", "passwordCurrentIncorrect": "Via nuna pasvorto estas malĝusta.", @@ -781,10 +784,13 @@ "sessionAppearance": "Aspekto", "sessionClearData": "Viŝi datumojn", "sessionConversations": "Interparoloj", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Helpo", "sessionInviteAFriend": "Inviti Amikon", "sessionMessageRequests": "Mesaĝpetoj", "sessionNetworkCurrentPrice": "Nuna prezo de SESH", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNetworkNotificationLive": "Session Token estas viva! Esploru la novan sekcion Session Network en Agordoj por lerni kiel Session Token funkciigas Session.", "sessionNetworkSecuredBy": "Reto sekurigita de", "sessionNew": " Nova", @@ -806,6 +812,7 @@ "showAll": "Montri ĉiujn", "showLess": "Montri malpli", "showNoteToSelf": "Montri noton al mi mem", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Glumarkoj", "supportGoTo": "Iri al helppaĝo", "systemInformationDesktop": "Sistemajn Informojn: {information}", @@ -813,6 +820,8 @@ "theContinue": "Daŭrigi", "theDefault": "Defaŭlta", "theError": "Eraro", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Provi Denove", "typingIndicators": "Tajpantaj indikiloj", "typingIndicatorsDescription": "Vidi kaj kunhavigi tajp-indikilojn.", @@ -838,6 +847,7 @@ "urlOpen": "Ĉu Malfermi Retadreson", "urlOpenBrowser": "Ĉi tio malfermiĝos en via retumilo.", "urlOpenDescription": "Ĉu vi certas, ke vi volas malfermi ĉi tiun URL en via retumilo?

{url}", + "usdNameShort": "USD", "useFastMode": "Uzi Rapidan Reĝimon", "video": "Videaĵo", "videoErrorPlay": "Ne eblas ludi videaĵon.", @@ -849,7 +859,6 @@ "warning": "Averto", "window": "Fenestro", "yes": "Jes", - "you": "Vi", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Vi" } diff --git a/_locales/es-419/messages.json b/_locales/es-419/messages.json index 84dbfc4ab..57e615fb3 100644 --- a/_locales/es-419/messages.json +++ b/_locales/es-419/messages.json @@ -56,12 +56,14 @@ "appIconEnableIconAndName": "Usar ícono y nombre alternativos de la app", "appIconSelect": "Seleccionar ícono alternativo de la app", "appIconSelectionTitle": "Ícono", + "appName": "Session", "appNameCalculator": "Calculadora", "appNameMeetingSE": "MeetingSE", "appNameNews": "Noticias", "appNameNotes": "Notas", "appNameStocks": "Acciones", "appNameWeather": "Clima", + "appPro": "Session Pro", "appearanceHideMenuBar": "Ocultar barra de menú", "appearanceLanguage": "Idioma", "appearanceLanguageDescription": "Elige la configuración de idioma para Session. Session se reiniciará cuando cambies tu configuración de idioma.", @@ -180,7 +182,6 @@ "callsSettings": "Llamadas (Beta)", "callsVoiceAndVideo": "Llamadas de voz y video", "callsVoiceAndVideoBeta": "Llamadas de Voz y Video (Beta)", - "callsVoiceAndVideoModalDescription": "Tu IP es visible para tu compañero de llamada y un servidor de la Oxen Foundation mientras usas llamadas beta.", "callsVoiceAndVideoToggleDescription": "Permite las llamadas de voz y video hacia y desde otros usuarios.", "callsYouCalled": "Has llamado a {name}", "callsYouMissedCallPermissions": "Perdiste una llamada de {name} porque no has habilitado Llamadas de Voz y Video en la Configuración de Privacidad.", @@ -624,6 +625,7 @@ "modalMessageCharacterTooLongTitle": "Mensaje demasiado largo", "modalMessageTooLongDescription": "Por favor, acorta tu mensaje a {limit} caracteres o menos.", "modalMessageTooLongTitle": "Mensaje demasiado largo", + "networkName": "Session Network", "next": "Siguiente", "nicknameDescription": "Elige un nombre para {name}. Este aparecerá en tus conversaciones uno a uno y en grupos.", "nicknameEnter": "Escriba un apodo", @@ -702,6 +704,7 @@ "open": "Abrir", "openSurvey": "Abrir encuesta", "other": "Otro", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Cambiar Contraseña", "passwordConfirm": "Confirmar contraseña", "passwordCurrentIncorrect": "Tu contraseña actual es incorrecta.", @@ -864,10 +867,13 @@ "sessionAppearance": "Apariencia", "sessionClearData": "Borrar datos", "sessionConversations": "Conversaciones", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Ayuda", "sessionInviteAFriend": "Invitar a un Amigo", "sessionMessageRequests": "Solicitudes de Mensaje", "sessionNetworkCurrentPrice": "Precio actual de SESH", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNetworkDescription": "Los mensajes se envían utilizando Session Network. La red está compuesta por nodos incentivados con Session Token, lo que mantiene a Session descentralizado y seguro. Más información {icon}", "sessionNetworkLearnAboutStaking": "Aprender sobre staking", "sessionNetworkMarketCap": "Capitalización de mercado", @@ -896,6 +902,7 @@ "showLess": "Mostrar menos", "showNoteToSelf": "Mostrar Nota Personal", "showNoteToSelfDescription": "¿Estás seguro de que deseas mostrar Nota Personal en tu lista de conversaciones?", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Pegatinas (stickers)", "supportGoTo": "Ir a la página de soporte técnico", "systemInformationDesktop": "Información del Sistema: {information}", @@ -903,6 +910,8 @@ "theContinue": "Continuar", "theDefault": "Por defecto", "theError": "Error", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tooltipAccountIdVisible": "El ID de cuenta de {name} es visible basándose en tus interacciones anteriores", "tooltipBlindedIdCommunities": "Los ID cegados se utilizan en las comunidades para reducir el spam y aumentar la privacidad", "tryAgain": "Intentar de nuevo", @@ -935,6 +944,7 @@ "urlOpen": "Abrir URL", "urlOpenBrowser": "Esto se abrirá en tu navegador.", "urlOpenDescription": "¿Estás seguro de que deseas abrir esta URL en tu navegador?

{url}", + "usdNameShort": "USD", "useFastMode": "Usar modo rápido", "video": "Video", "videoErrorPlay": "No se puede reproducir el video.", @@ -946,7 +956,6 @@ "warning": "Advertencia", "window": "Ventana", "yes": "Sí", - "you": "Tú", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Tú" } diff --git a/_locales/es/messages.json b/_locales/es/messages.json index 59700b6aa..ecb37eb9b 100644 --- a/_locales/es/messages.json +++ b/_locales/es/messages.json @@ -56,12 +56,14 @@ "appIconEnableIconAndName": "Usar ícono y nombre alternativos de la app", "appIconSelect": "Seleccionar ícono alternativo de la app", "appIconSelectionTitle": "Ícono", + "appName": "Session", "appNameCalculator": "Calculadora", "appNameMeetingSE": "MeetingSE", "appNameNews": "Noticias", "appNameNotes": "Notas", "appNameStocks": "Acciones", "appNameWeather": "Clima", + "appPro": "Session Pro", "appearanceHideMenuBar": "Esconder barra de menú", "appearanceLanguage": "Idioma", "appearanceLanguageDescription": "Elija su configuración de idioma para Session. Session se reiniciará cuando cambie su configuración de idioma.", @@ -180,7 +182,6 @@ "callsSettings": "Llamadas (beta)", "callsVoiceAndVideo": "Llamadas de voz y video", "callsVoiceAndVideoBeta": "Llamadas de Voz y Video (Beta)", - "callsVoiceAndVideoModalDescription": "Tu IP es visible para tu socio de llamada y un servidor de Oxen Foundation mientras usas las llamadas beta.", "callsVoiceAndVideoToggleDescription": "Permite llamadas de voz y vídeo de y hacia otros usuarios.", "callsYouCalled": "Has llamado a {name}", "callsYouMissedCallPermissions": "Perdiste una llamada de {name} porque no has habilitado Voice and Video Calls en configuraciones de privacidad.", @@ -624,6 +625,7 @@ "modalMessageCharacterTooLongTitle": "Mensaje demasiado largo", "modalMessageTooLongDescription": "Por favor, acorta tu mensaje a {limit} caracteres o menos.", "modalMessageTooLongTitle": "Mensaje demasiado largo", + "networkName": "Session Network", "next": "Siguiente", "nicknameDescription": "Elija un apodo para {name}. Esto aparecerá para ti en tus conversaciones individuales y de grupo.", "nicknameEnter": "Escriba un apodo", @@ -702,6 +704,7 @@ "open": "Abrir", "openSurvey": "Abrir encuesta", "other": "Otro", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Cambiar Contraseña", "passwordConfirm": "Confirmar contraseña", "passwordCurrentIncorrect": "Tu contraseña actual es incorrecta.", @@ -864,10 +867,13 @@ "sessionAppearance": "Apariencia", "sessionClearData": "Borrar datos", "sessionConversations": "Conversaciones", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Ayuda", "sessionInviteAFriend": "Invitar a un Amigo", "sessionMessageRequests": "Solicitudes de mensajes", "sessionNetworkCurrentPrice": "Precio actual de SESH", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNetworkDescription": "Los mensajes se envían utilizando Session Network. La red está compuesta por nodos incentivados con Session Token, lo que mantiene a Session descentralizado y seguro. Más información {icon}", "sessionNetworkLearnAboutStaking": "Aprender sobre staking", "sessionNetworkMarketCap": "Capitalización de mercado", @@ -896,6 +902,7 @@ "showLess": "Mostrar menos", "showNoteToSelf": "Mostrar Nota Personal", "showNoteToSelfDescription": "¿Estás seguro de que deseas mostrar Nota Personal en tu lista de conversaciones?", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Pegatinas (stickers)", "supportGoTo": "Ir a la página de soporte técnico", "systemInformationDesktop": "Información del Sistema: {information}", @@ -903,6 +910,8 @@ "theContinue": "Continuar", "theDefault": "Por defecto", "theError": "Error", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tooltipAccountIdVisible": "El ID de cuenta de {name} es visible basándose en tus interacciones anteriores", "tooltipBlindedIdCommunities": "Los ID cegados se utilizan en las comunidades para reducir el spam y aumentar la privacidad", "tryAgain": "Intentar de nuevo", @@ -935,6 +944,7 @@ "urlOpen": "Abrir URL", "urlOpenBrowser": "Esto se abrirá en tu navegador.", "urlOpenDescription": "¿Estás seguro de que quieres abrir está URL en tu navegador?

{url}", + "usdNameShort": "USD", "useFastMode": "Usar Modo Rápido", "video": "Vídeo", "videoErrorPlay": "No se puede reproducir el vídeo.", @@ -946,7 +956,6 @@ "warning": "Advertencia", "window": "Ventana", "yes": "Sí", - "you": "Tú", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Tú" } diff --git a/_locales/et/messages.json b/_locales/et/messages.json index 42be1dd48..ec8b9e6d4 100644 --- a/_locales/et/messages.json +++ b/_locales/et/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} ja {other_name} määrati adminiks.", "andMore": "+{count}", "anonymous": "Anonüümne", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Peida menüüriba", "appearanceLanguage": "Keel", "appearanceLanguageDescription": "Valige Session keele seade. Session taaskäivitub, kui muudate oma keele seadet.", @@ -150,7 +152,6 @@ "callsSettings": "Kõned (beta)", "callsVoiceAndVideo": "Hääl- ja videokõned", "callsVoiceAndVideoBeta": "Hääl- ja videokõned (Beta)", - "callsVoiceAndVideoModalDescription": "Teie IP on nähtav teie kõnepartnerile ja Oxen Foundation serverile beetakõnede ajal.", "callsVoiceAndVideoToggleDescription": "Võimaldab hääl- ja videokõned teistele kasutajatele ja teistelt kasutajatelt.", "callsYouCalled": "Häälestasite {name}le", "callsYouMissedCallPermissions": "Te ei vastanud kõnele {name}, kuna te ei ole lubanud Voice and Video Calls Privaatsusseadetes.", @@ -524,6 +525,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Häälsõnum", "messages": "Sõnumid", "minimize": "Minimeeri", + "networkName": "Session Network", "next": "Järgmine", "nicknameDescription": "Valige {name} jaoks hüüdnimi. See kuvatakse teile nii ühe-kahe kui ka grupivestlustes.", "nicknameEnter": "Sisestage hüüdnimi", @@ -597,6 +599,7 @@ "onsErrorUnableToSearch": "Me ei suutnud seda ONS-i otsida. Palun proovige hiljem uuesti.", "open": "Ava", "other": "Muu", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Muuda parool", "passwordConfirm": "Kinnita parool", "passwordCurrentIncorrect": "Teie praegune parool on vale.", @@ -705,9 +708,12 @@ "sessionAppearance": "Välimus", "sessionClearData": "Tühjenda andmed", "sessionConversations": "Vestlused", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Spikker", "sessionInviteAFriend": "Kutsu sõber", "sessionMessageRequests": "Sõnumitaotlused", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Teatised", "sessionPermissions": "Õigused", "sessionPrivacy": "Privaatsus", @@ -723,12 +729,15 @@ "show": "Näita", "showAll": "Näita kõiki", "showLess": "Näita vähem", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Kleepsud", "supportGoTo": "Mine kasutajatoelehele", "systemInformationDesktop": "Süsteemi info: {information}", "theContinue": "Jätka", "theDefault": "Vaikimisi", "theError": "Tõrge", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Proovi uuesti", "typingIndicators": "Tippimisnäidikud", "typingIndicatorsDescription": "Näe ja jaga kirjutamisindikaatoreid.", @@ -748,6 +757,7 @@ "urlOpen": "Kas avada URL", "urlOpenBrowser": "See avaneb teie brauseris.", "urlOpenDescription": "Kas soovite avada selle URL-i oma brauseris?

{url}", + "usdNameShort": "USD", "useFastMode": "Kasuta kiirrežiimi", "video": "Video", "videoErrorPlay": "Videot ei saa mängida.", @@ -757,7 +767,6 @@ "warning": "Hoiatus", "window": "Aken", "yes": "Jah", - "you": "Sina", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Sina" } diff --git a/_locales/eu/messages.json b/_locales/eu/messages.json index 9565f1a18..29d06b9fd 100644 --- a/_locales/eu/messages.json +++ b/_locales/eu/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} eta {other_name} Admin izendatu dira.", "andMore": "+{count}", "anonymous": "Anonimoa", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Ezkutatu Menu Barra", "appearanceLanguage": "Hizkuntza", "appearanceLanguageDescription": "Aukeratu zure hizkuntza ezarpena Session rako. Session berrabiaraziko da hizkuntza ezarpena aldatzen duzunean.", @@ -150,7 +152,6 @@ "callsSettings": "Calls (Beta)", "callsVoiceAndVideo": "Ahots eta Bideo Deiak", "callsVoiceAndVideoBeta": "Ahots eta Bideo Deiak (Beta)", - "callsVoiceAndVideoModalDescription": "Zure IPa ikusgai egongo da zure dei-bikotekidearentzako eta Oxen Foundation zerbitzari batentzako, beta-deiak egiten ari bazara.", "callsVoiceAndVideoToggleDescription": "Beste erabiltzaile batzuekin ahots-eta bideo-deiak egiteko aukera ematen du.", "callsYouCalled": "{name} deitu duzu", "callsYouMissedCallPermissions": "{name}-(r)en dei bat galdu duzu, Pribatutasun Ezarpenetan Ahots eta Bideo Deiak ez gaituta dituzulako.", @@ -524,6 +525,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Ahots-mezua", "messages": "Mezuak", "minimize": "Minimizatu", + "networkName": "Session Network", "next": "Hurrengoa", "nicknameDescription": "Choose a nickname for {name}. This will appear to you in your one-to-one and group conversations.", "nicknameEnter": "Sartu ezizena", @@ -597,6 +599,7 @@ "onsErrorUnableToSearch": "Ezin izan dugu ONS hau bilatu. Saiatu berriro geroago.", "open": "Ireki", "other": "Bestea", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Change Password", "passwordConfirm": "Pasahitza berretsi", "passwordCurrentIncorrect": "Zure oraingo pasahitza ez da zuzena.", @@ -705,9 +708,12 @@ "sessionAppearance": "Itxura", "sessionClearData": "Datuak garbitu", "sessionConversations": "Elkarrizketak", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Laguntza", "sessionInviteAFriend": "Laguna gonbidatu", "sessionMessageRequests": "Mezu-eskaerak", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Jakinarazpenak", "sessionPermissions": "Baimenak", "sessionPrivacy": "Pribatutasuna", @@ -723,12 +729,15 @@ "show": "Erakutsi", "showAll": "Denak erakutsi", "showLess": "Gutxiago erakutsi", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Eranskailuak", "supportGoTo": "Joan Laguntza Orriara", "systemInformationDesktop": "Sistemaren Informazioa: {information}", "theContinue": "Jarraitu", "theDefault": "Lehenetsia", "theError": "Errorea", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Saiatu berriro", "typingIndicators": "Idazketa Adierazleak", "typingIndicatorsDescription": "Ikusi eta partekatu idazketa adierazleak.", @@ -748,6 +757,7 @@ "urlOpen": "Ireki URLa", "urlOpenBrowser": "Hau zure arakatzailean irekiko da.", "urlOpenDescription": "Ziur zaude URL hau zure nabigatzailean ireki nahi duzula?

{url}", + "usdNameShort": "USD", "useFastMode": "Erabili Fast Mode", "video": "Bideoa", "videoErrorPlay": "Ezin da bideoa erreproduzitu.", @@ -757,7 +767,6 @@ "warning": "Adierazpena", "window": "Leihoa", "yes": "Bai", - "you": "Zuk", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Zuk" } diff --git a/_locales/fa/messages.json b/_locales/fa/messages.json index e4c9d5d70..c4ea08e2b 100644 --- a/_locales/fa/messages.json +++ b/_locales/fa/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} و {other_name} به مدیر ارتقاء یافتند.", "andMore": "+{count}", "anonymous": "ناشناس", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "پنهان کردن نوار منو", "appearanceLanguage": "زبان", "appearanceLanguageDescription": "تنظیم زبان خود را برای Session انتخاب کنید. هنگامی که تنظیم زبان خود را تغییر دهید، Session مجدداً راه‌اندازی خواهد شد.", @@ -148,7 +150,6 @@ "callsSettings": "تماس‌ها (بتا)", "callsVoiceAndVideo": "تماس‌های صوتی و تصویری", "callsVoiceAndVideoBeta": "تماس‌های صوتی و تصویری (بتا)", - "callsVoiceAndVideoModalDescription": "آدرس IP شما برای مخاطب تماس شما و همچنین سرور Oxen Foundation در هنگام استفاده از تماس آزمایشی مشخص خواهد بود.", "callsVoiceAndVideoToggleDescription": "دریافت و ارسال تماس های صوتی و تصویری به سایر کاربران را فعال کنید.", "callsYouCalled": "تماس شما با {name}", "callsYouMissedCallPermissions": "شما تماسی را از {name} از دست دادید زیرا تماس‌های صوتی و تصویری را در تنظیمات حریم خصوصی فعال نکرده‌اید.", @@ -355,7 +356,7 @@ "files": "فایل‌ها", "from": "از:", "fullScreenToggle": "تاگل فول اسکرین", - "gif": "گیف", + "gif": "GIF", "giphyWarning": "Giphy", "giphyWarningDescription": "Session برای ارائه نتایج جستجو به Giphy متصل می‌شود. هنگام ارسال GIFها، شما محافظت کامل از متاداده نخواهید داشت.", "groupAddMemberMaximum": "گروه‌ها حداکثر 100 عضو دارند", @@ -523,6 +524,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} پیام صوتی", "messages": "پیام‌ها", "minimize": "مینیمایز", + "networkName": "Session Network", "next": "بعدی", "nicknameDescription": "یک اسم مستعار برای {name} انتخاب کنید. این اسم در بخش همتا به همتای شما و مکالمه های گروهی شما ظاهر خواهد شد.", "nicknameEnter": "نام مستعار وارد کنید", @@ -596,6 +598,7 @@ "onsErrorUnableToSearch": "نتوانستیم برای این ONS جستجو کنیم. لطفاً بعداً دوباره تلاش کنید.", "open": "باز کن", "other": "دیگر", + "oxenFoundation": "Oxen Foundation", "passwordChange": "تغییر گذرواژه", "passwordConfirm": "تأیید کلمه‌ی عبور", "passwordCurrentIncorrect": "رمز عبور فعلی شما نادرست است.", @@ -704,9 +707,12 @@ "sessionAppearance": "ظاهر", "sessionClearData": "پاک کردن اطلاعات", "sessionConversations": "مکالمه‌ها", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "کمک", "sessionInviteAFriend": "دعوت از یک دوست", "sessionMessageRequests": "درخواست‌های پیام", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "اعلان‌ها", "sessionPermissions": "دسترسی‌ها", "sessionPrivacy": "حریم خصوصی", @@ -722,12 +728,15 @@ "show": "نمایش", "showAll": "نمایش همه", "showLess": "نمایش کمتر", + "stakingRewardPool": "Staking Reward Pool", "stickers": "استیکرها", "supportGoTo": "رفتن به صفحه پشتیبانی", "systemInformationDesktop": "اطلاعات سیستم: {information}", "theContinue": "ادامه", "theDefault": "پیش‌فرض", "theError": "خطا", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "دوباره تلاش کنید", "typingIndicators": "نشانگرهای تایپ", "typingIndicatorsDescription": "نشانگرهای در حال تایپ رو ببین و به اشتراک بگذار.", @@ -747,6 +756,7 @@ "urlOpen": "باز کردن URL", "urlOpenBrowser": "این در مرورگر شما باز خواهد شد.", "urlOpenDescription": "ایا مطمین هستید می خواهید این ادرس رو در مرورگر خود باز کنید؟

{url}", + "usdNameShort": "USD", "useFastMode": "استفاده از حالت سریع", "video": "ویدیو", "videoErrorPlay": "ناتوان از پخش کردن ویدیو.", @@ -756,7 +766,6 @@ "warning": "هشدار", "window": "پنجره", "yes": "بله", - "you": "شما", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "شما" } diff --git a/_locales/fi/messages.json b/_locales/fi/messages.json index b57149e9f..5ebf49b9d 100644 --- a/_locales/fi/messages.json +++ b/_locales/fi/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} ja {other_name} ylennettiin ylläpitäjiksi.", "andMore": "+{count}", "anonymous": "Anonyymi", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Piilota valikkopalkki", "appearanceLanguage": "Kieli", "appearanceLanguageDescription": "Valitse kielen asetus Session varten. Session käynnistyy uudelleen, kun muutat kieliasetuksesi.", @@ -152,7 +154,6 @@ "callsSettings": "Puhelut (beta)", "callsVoiceAndVideo": "Ääni- ja videopuhelut", "callsVoiceAndVideoBeta": "Ääni- ja videopuhelut (beta)", - "callsVoiceAndVideoModalDescription": "IP-osoitteesi on näkyvissä puhelun aikana vastaanottajalle ja Oxen Foundation palvelimelle, kun käytät beta-puheluita.", "callsVoiceAndVideoToggleDescription": "Mahdollistaa ääni- ja videopuheluiden soiton ja vastaanoton.", "callsYouCalled": "Soitit käyttäjälle {name}", "callsYouMissedCallPermissions": "Missasit puhelun käyttäjältä {name}, koska et ole ottanut käyttöön Ääni ja videopuheluita tietosuoja-asetuksissa.", @@ -535,6 +536,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Ääniviesti", "messages": "Viestit", "minimize": "Pienennä", + "networkName": "Session Network", "next": "Seuraava", "nicknameDescription": "Valitse lempinimi käyttäjälle {name}. Tämä näkyy sinulle kahdenkeskisissä ja ryhmäkeskusteluissa.", "nicknameEnter": "Syötä lempinimi", @@ -609,6 +611,7 @@ "onsErrorUnableToSearch": "Emme pystyneet hakemaan tätä ONS:a. Yritä myöhemmin uudelleen.", "open": "Avaa", "other": "Muu", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Vaihda salasana", "passwordConfirm": "Vahvista salasana", "passwordCurrentIncorrect": "Nykyinen salasanasi on virheellinen.", @@ -717,9 +720,12 @@ "sessionAppearance": "Ulkoasu", "sessionClearData": "Tyhjennä tiedot", "sessionConversations": "Keskustelut", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Tuki", "sessionInviteAFriend": "Kutsu ystäviä", "sessionMessageRequests": "Viestipyynnöt", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Ilmoitukset", "sessionPermissions": "Käyttöoikeudet", "sessionPrivacy": "Yksityisyys", @@ -735,12 +741,15 @@ "show": "Näytä", "showAll": "Näytä kaikki", "showLess": "Näytä vähemmän", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Tarrat", "supportGoTo": "Siirry tukisivulle", "systemInformationDesktop": "Järjestelmän tiedot: {information}", "theContinue": "Jatka", "theDefault": "Oletus", "theError": "Virhe", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Yritä uudelleen", "typingIndicators": "Kirjoitusindikaattorit", "typingIndicatorsDescription": "Näe ja jaa kirjoitusindikaattorit.", @@ -760,6 +769,7 @@ "urlOpen": "Avataanko URL?", "urlOpenBrowser": "Tämä avautuu selaimessasi.", "urlOpenDescription": "Haluatko varmasti avata tämän URL-osoitteen selaimessa?

{url}", + "usdNameShort": "USD", "useFastMode": "Käytä nopeaa tilaa", "video": "Video", "videoErrorPlay": "Videon toisto epäonnistui.", @@ -769,7 +779,6 @@ "warning": "Varoitus", "window": "Ikkuna", "yes": "Kyllä", - "you": "Sinä", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Sinä" } diff --git a/_locales/fil/messages.json b/_locales/fil/messages.json index b12269a7a..2497742d0 100644 --- a/_locales/fil/messages.json +++ b/_locales/fil/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} at {other_name} na-promote sa Admin.", "andMore": "+{count}", "anonymous": "Hindi kilala", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Itago ang Menu Bar", "appearanceLanguage": "Wika", "appearanceLanguageDescription": "Pumili ng setting ng wika para sa Session. Ang Session ay magre-restart kapag binago mo ang setting ng wika.", @@ -150,7 +152,6 @@ "callsSettings": "Mga Tawag (Beta)", "callsVoiceAndVideo": "Mga Voice at Video Call", "callsVoiceAndVideoBeta": "Mga Voice at Video Call (Beta)", - "callsVoiceAndVideoModalDescription": "Ang iyong IP ay nakikita ng iyong kasamahan sa tawag at isang server ng Oxen Foundation habang gumagamit ng beta calls.", "callsVoiceAndVideoToggleDescription": "Ini-enable ang mga voice at video call papunta at mula sa iba pang mga user.", "callsYouCalled": "Tinawag mo si {name}", "callsYouMissedCallPermissions": "Nakamiss ka ng tawag mula kay {name} dahil hindi mo pinagana ang Voice and Video Calls sa Privacy Settings.", @@ -524,6 +525,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Voice Message", "messages": "Mga Mensahe", "minimize": "Paliitin", + "networkName": "Session Network", "next": "Susunod", "nicknameDescription": "Pumili ng palayaw para kay {name}. Ito ay lilitaw sa iyo sa iyong one-to-one at group na mga usapan.", "nicknameEnter": "Ilagay ang palayaw", @@ -597,6 +599,7 @@ "onsErrorUnableToSearch": "Hindi namin ma-search ang ONS na ito. Paki-subukan muli mamaya.", "open": "Buksan", "other": "Iba pa", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Palitan ang Password", "passwordConfirm": "Kumpirmahin ang iyong password", "passwordCurrentIncorrect": "Maling kasalukuyang password mo.", @@ -705,9 +708,12 @@ "sessionAppearance": "Hitsura", "sessionClearData": "Burahin ang Data", "sessionConversations": "Mga usapan", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Tulong", "sessionInviteAFriend": "Imbitahin ang Kaibigan", "sessionMessageRequests": "Mga Kahilingan sa Pagmemensahe", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Mga abiso", "sessionPermissions": "Mga Pahintulot", "sessionPrivacy": "Pribado", @@ -723,12 +729,15 @@ "show": "Ipakita", "showAll": "Ipakita lahat", "showLess": "Magpakita ng Mas Kaunti", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Stickers", "supportGoTo": "Pumunta sa Suporta Page", "systemInformationDesktop": "Impormasyon ng System: {information}", "theContinue": "Ituloy", "theDefault": "Default", "theError": "Error", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Subukang Muli", "typingIndicators": "Mga Indikasyon sa Pag-type", "typingIndicatorsDescription": "Tingnan at ibahagi ang mga indikasyon sa pagta-type.", @@ -748,6 +757,7 @@ "urlOpen": "Buksan ang URL", "urlOpenBrowser": "Bubuksan ito sa iyong browser.", "urlOpenDescription": "Sigurado ka bang nais mong buksan ang URL na ito sa iyong browser?

{url}", + "usdNameShort": "USD", "useFastMode": "Use Fast Mode", "video": "Video", "videoErrorPlay": "Hindi ma-play ang video.", @@ -757,7 +767,6 @@ "warning": "Babala", "window": "Window", "yes": "Oo", - "you": "Ikaw", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Ikaw" } diff --git a/_locales/fr/messages.json b/_locales/fr/messages.json index 38f39b0f6..a23bdaaeb 100644 --- a/_locales/fr/messages.json +++ b/_locales/fr/messages.json @@ -56,12 +56,14 @@ "appIconEnableIconAndName": "Utiliser une autre icône et un autre nom d'application", "appIconSelect": "Sélectionnez une autre icône d'application", "appIconSelectionTitle": "Icônes", + "appName": "Session", "appNameCalculator": "Calculatrice", "appNameMeetingSE": "RéunionSE", "appNameNews": "Actualités", "appNameNotes": "Notes", "appNameStocks": "Bourse", "appNameWeather": "Météo", + "appPro": "Session Pro", "appearanceHideMenuBar": "Cacher la barre de menu", "appearanceLanguage": "Langue", "appearanceLanguageDescription": "Choisissez les paramètres de langue pour Session. Session redémarrera lorsque vous changerez les paramètres de langue.", @@ -180,7 +182,6 @@ "callsSettings": "Appels (Bêta)", "callsVoiceAndVideo": "Appels vocaux et vidéos", "callsVoiceAndVideoBeta": "Appels vocaux et vidéos (Beta)", - "callsVoiceAndVideoModalDescription": "Votre adresse IP est visible par votre interlocuteur et un serveur d'Oxen Foundation pendant que vous utilisez des appels beta.", "callsVoiceAndVideoToggleDescription": "Active les appels vocaux et vidéo vers et depuis d'autres utilisateurs.", "callsYouCalled": "Vous avez appelé {name}", "callsYouMissedCallPermissions": "Vous avez manqué un appel de {name} car vous n'avez pas activé Appels vocaux et vidéo dans les Paramètres de confidentialité.", @@ -624,6 +625,7 @@ "modalMessageCharacterTooLongTitle": "Le message est trop long", "modalMessageTooLongDescription": "Veuillez raccourcir votre message a {limit} caractères ou moins.", "modalMessageTooLongTitle": "Le message est trop long", + "networkName": "Session Network", "next": "Suivant", "nicknameDescription": "Choisissez un pseudo pour {name}. Il apparaîtra dans vos conversations individuelles et de groupe.", "nicknameEnter": "Saisissez un surnom", @@ -702,6 +704,7 @@ "open": "Ouvrir", "openSurvey": "Ouvrir le questionnaire", "other": "Autre", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Changer le mot de passe", "passwordConfirm": "Confirmez le mot de passe", "passwordCurrentIncorrect": "Votre mot de passe actuel est incorrect.", @@ -864,10 +867,13 @@ "sessionAppearance": "Apparence", "sessionClearData": "Effacer les données", "sessionConversations": "Conversations", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Aide", "sessionInviteAFriend": "Inviter un ami", "sessionMessageRequests": "Demandes de message", "sessionNetworkCurrentPrice": "Prix actuel du SESH", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNetworkDescription": "Les messages sont envoyés en utilisant l'Session Network. Le réseau est composé de noeuds stimulés par Session Token, qui permet à Session d'être décentralisée et sécurisée. En savoir plus {icon}", "sessionNetworkLearnAboutStaking": "En savoir plus sur Staking", "sessionNetworkMarketCap": "Capitalisation du marché", @@ -896,6 +902,7 @@ "showLess": "Afficher moins", "showNoteToSelf": "Afficher la note pour soi-même", "showNoteToSelfDescription": "Êtes-vous sûr de vouloir afficher Note pour soi-même dans votre liste de conversations ?", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Autocollants", "supportGoTo": "Accéder à la page d’assistance", "systemInformationDesktop": "Information système : {information}", @@ -903,6 +910,8 @@ "theContinue": "Continuer", "theDefault": "Valeur par défaut", "theError": "Erreur", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tooltipAccountIdVisible": "L’ID de compte de {name} est visible en fonction de vos interactions précédentes", "tooltipBlindedIdCommunities": "Les ID aveuglés sont utilisés dans les communautés pour réduire le spam et renforcer la confidentialité", "tryAgain": "Réessayer", @@ -935,6 +944,7 @@ "urlOpen": "Ouvrir l'URL", "urlOpenBrowser": "Ceci s'ouvrira dans votre navigateur.", "urlOpenDescription": "Êtes-vous sûr de vouloir ouvrir cette adresse URL dans votre navigateur web ?

{url}", + "usdNameShort": "USD", "useFastMode": "Utiliser le mode rapide", "video": "Vidéo", "videoErrorPlay": "Impossible de lire la vidéo.", @@ -946,7 +956,6 @@ "warning": "Attention", "window": "Fenêtre", "yes": "Oui", - "you": "Vous", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Vous" } diff --git a/_locales/gl/messages.json b/_locales/gl/messages.json index 9c5c596a3..63f13212f 100644 --- a/_locales/gl/messages.json +++ b/_locales/gl/messages.json @@ -34,6 +34,8 @@ "adminTwoPromotedToAdmin": "{name} e {other_name} foron ascendidos a Admin.", "andMore": "+{count}", "anonymous": "Anónimo", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Agochar a barra de menú", "appearanceLanguage": "Idioma", "appearanceLanguageDescription": "Elixe a configuración de idioma para Session. Session reiniciarase ao cambiar a configuración de idioma.", @@ -142,7 +144,6 @@ "callsSettings": "Chamadas (Beta)", "callsVoiceAndVideo": "Chamadas de voz e vídeo", "callsVoiceAndVideoBeta": "Chamadas de voz e vídeo (Beta)", - "callsVoiceAndVideoModalDescription": "O teu IP é visible para o teu compañeire de chamada e un servidor da Oxen Foundation mentres utilizas chamadas beta.", "callsYouCalled": "Chamaches a {name}", "callsYouMissedCallPermissions": "Perdiches unha chamada de {name} porque non tes activadas as Chamadas de Voz e Vídeo nos Axustes de Privacidade.", "cameraErrorNotFound": "Non se atopou cámara", @@ -472,6 +473,7 @@ "messageVoiceSlideToCancel": "Desliza para cancelar", "messages": "Mensaxes", "minimize": "Minimizar", + "networkName": "Session Network", "next": "Seguinte", "nicknameEnter": "Introduza un alcume", "nicknameRemove": "Eliminar nome", @@ -536,6 +538,7 @@ "onsErrorUnableToSearch": "Non puidemos buscar este ONS. Por favor, tenta de novo máis tarde.", "open": "Abrir", "other": "Outra", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Cambiar o contrasinal", "passwordConfirm": "Confirmar contrasinal", "passwordCurrentIncorrect": "O teu contrasinal actual é incorrecto.", @@ -634,9 +637,12 @@ "sessionAppearance": "Aparencia", "sessionClearData": "Eliminar datos", "sessionConversations": "Conversas", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Axuda", "sessionInviteAFriend": "Convidar a un amigo", "sessionMessageRequests": "Solicitudes de mensaxes", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Notificacións", "sessionPermissions": "Permisos", "sessionPrivacy": "Privacidade", @@ -650,12 +656,15 @@ "show": "Mostrar", "showAll": "Mostrar Todo", "showLess": "Mostrar menos", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Adhesivos", "supportGoTo": "Ir á páxina de asistencia", "systemInformationDesktop": "Información do sistema: {information}", "theContinue": "Continuar", "theDefault": "Por defecto", "theError": "Erro", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Volver tentar", "typingIndicators": "Indicador de escritura", "undo": "Desfacer", @@ -672,6 +681,7 @@ "urlCopy": "Copiar URL", "urlOpen": "Abrir URL", "urlOpenBrowser": "Isto abrirase no teu navegador.", + "usdNameShort": "USD", "useFastMode": "Usar Fast Mode", "video": "Vídeo", "videoErrorPlay": "Non se pode reproducir o vídeo.", @@ -681,7 +691,6 @@ "warning": "Aviso", "window": "Xanela", "yes": "Si", - "you": "Ti", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Ti" } diff --git a/_locales/ha/messages.json b/_locales/ha/messages.json index e01e841a4..26d1f2c7a 100644 --- a/_locales/ha/messages.json +++ b/_locales/ha/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} da {other_name} an tayar musu zuwa Admin.", "andMore": "+{count}", "anonymous": "Ba a san sunan ba", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Boye Menu Bar", "appearanceLanguage": "Yare", "appearanceLanguageDescription": "Zaɓi saitin yarenku don Session. Session zai sake farawa lokacin da kuka canza saitin yaranku.", @@ -150,7 +152,6 @@ "callsSettings": "Kira (Beta)", "callsVoiceAndVideo": "Kiran Muryar da Bidiyo", "callsVoiceAndVideoBeta": "Kiran Muryar da Bidiyo (Beta)", - "callsVoiceAndVideoModalDescription": "IP ɗinku yana bayyane ga abokin kiran ku da sabar Oxen Foundation yayin amfani da ƙiran beta.", "callsVoiceAndVideoToggleDescription": "Yana ba da kiran murya da bidiyo zuwa da daga wasu masu amfani.", "callsYouCalled": "Ka kira {name}", "callsYouMissedCallPermissions": "Kun rasa kira daga {name} saboda ba ku kunna kiran murya da bidiyo a Saitunan Sirrin ba.", @@ -524,6 +525,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Saƙon Murya", "messages": "Saƙonni", "minimize": "Minimiza", + "networkName": "Session Network", "next": "Na Gaba", "nicknameDescription": "Zaɓi sunan karya wa {name}. Wannan zai bayyana muku a cikin tattaunawar tattaunawarka.", "nicknameEnter": "Shigar da sunan yabo", @@ -597,6 +599,7 @@ "onsErrorUnableToSearch": "Ba mu iya bincika wannan ONS ba. Da fatan za'a sake gwadawa daga baya.", "open": "Bude", "other": "Sauran", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Canza Kalmar Sirri", "passwordConfirm": "Tabbatar da kalmar sirri", "passwordCurrentIncorrect": "Kalmar sirrinka na yanzu ba daidai bane.", @@ -705,9 +708,12 @@ "sessionAppearance": "Bayyanar", "sessionClearData": "Goge Bayanai", "sessionConversations": "Tattaunawa", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Taimako", "sessionInviteAFriend": "Yi Wa Aboki Gayyata", "sessionMessageRequests": "Neman Saƙo", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Sanarwa", "sessionPermissions": "Izini", "sessionPrivacy": "Sirri", @@ -723,12 +729,15 @@ "show": "Nîşan bide", "showAll": "Nîşan bide Dukansu", "showLess": "Nîşan bide Ƙasa", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Stickers", "supportGoTo": "Je zuwa Shafin Tallafi", "systemInformationDesktop": "Bayanin Tsarin: {information}", "theContinue": "Ci gaba", "theDefault": "Jiki", "theError": "Kuskure", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Sake Gwada", "typingIndicators": "Alamomin Rubutu", "typingIndicatorsDescription": "Duba kuma raba alamun rubutu.", @@ -748,6 +757,7 @@ "urlOpen": "Bude URL", "urlOpenBrowser": "Wannan zai buɗe a burauzan ka.", "urlOpenDescription": "Ka tabbata kana so ka buɗe wannan URL a burauzarka?

{url}", + "usdNameShort": "USD", "useFastMode": "Yi amfani da Yanayin Sauri", "video": "Bidiyo", "videoErrorPlay": "Ba za a iya kunna bidiyo ba.", @@ -757,7 +767,6 @@ "warning": "Gargadi", "window": "Window", "yes": "Na'am", - "you": "Kai", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Kai" } diff --git a/_locales/he/messages.json b/_locales/he/messages.json index c7d85fc70..c5ea1fa28 100644 --- a/_locales/he/messages.json +++ b/_locales/he/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name}‏ ו{other_name}‏ קודמו למנהלים.", "andMore": "+{count}", "anonymous": "אנונימי", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "הסתר את סרגל התפריטים", "appearanceLanguage": "שפה", "appearanceLanguageDescription": "בחר את הגדרת השפה שלך עבור Session. Session יופעל מחדש כאשר תשנה את הגדרת השפה שלך.", @@ -150,7 +152,6 @@ "callsSettings": "שיחות (בטא)", "callsVoiceAndVideo": "שיחות קוליות ווידיאו", "callsVoiceAndVideoBeta": "שיחות קוליות ווידיאו (Beta)", - "callsVoiceAndVideoModalDescription": "כתובת ה-IP שלך גלויה לשותפת השיחה שלך ולשרת קרן Oxen בעת שימוש בשיחות בטא.", "callsVoiceAndVideoToggleDescription": "מאפשר שיחות קוליות ווידאו אל משתמשים אחרים ומאתם.", "callsYouCalled": "התקשרת אל {name}", "callsYouMissedCallPermissions": "פספסת שיחה מ{name} כי לא הפעלת שיחות שמע ווידאו בהגדרות פרטיות.", @@ -524,6 +525,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} הודעה קולית", "messages": "הודעות", "minimize": "מזער", + "networkName": "Session Network", "next": "הבא", "nicknameDescription": "בחר כינוי עבור {name}. זה יופיע בשיחות אחד-על-אחד ובקבוצה שלך.", "nicknameEnter": "הזן כינוי", @@ -597,6 +599,7 @@ "onsErrorUnableToSearch": "לא הצלחנו לחפש את ה-ONS הזה. אנא נסה/י שוב מאוחר יותר.", "open": "פתח", "other": "אחר", + "oxenFoundation": "Oxen Foundation", "passwordChange": "שנה סיסמה", "passwordConfirm": "אשר סיסמה", "passwordCurrentIncorrect": "הסיסמה הנוכחית שלך לא נכונה.", @@ -705,9 +708,12 @@ "sessionAppearance": "מראה", "sessionClearData": "נקה נתונים", "sessionConversations": "שיחות", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "עזרה", "sessionInviteAFriend": "הזמן חבר", "sessionMessageRequests": "בקשות הודעה", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "התראות", "sessionPermissions": "הרשאות", "sessionPrivacy": "פרטיות", @@ -723,12 +729,15 @@ "show": "הראה", "showAll": "הראה הכל", "showLess": "הראה פחות", + "stakingRewardPool": "Staking Reward Pool", "stickers": "מדבקות", "supportGoTo": "לך אל דף התמיכה", "systemInformationDesktop": "מידע מערכת: {information}", "theContinue": "המשך", "theDefault": "ברירת מחדל", "theError": "שגיאה", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "נסה שוב", "typingIndicators": "מחווני הקלדה", "typingIndicatorsDescription": "ראה ושתף מחווני הקלדה.", @@ -748,6 +757,7 @@ "urlOpen": "לפתוח קישור", "urlOpenBrowser": "זה ייפתח בדפדפן שלך.", "urlOpenDescription": "האם אתה בטוח שברצונך לפתוח כתובת URL זו בדפדפן שלך?

{url}", + "usdNameShort": "USD", "useFastMode": "השתמש במצב המהיר", "video": "וידיאו", "videoErrorPlay": "לא ניתן להשמיע וידיאו.", @@ -757,7 +767,6 @@ "warning": "אזהרה", "window": "חלון", "yes": "כן", - "you": "את/ה", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "את/ה" } diff --git a/_locales/hi/messages.json b/_locales/hi/messages.json index 3b3b9c2b1..5700187cf 100644 --- a/_locales/hi/messages.json +++ b/_locales/hi/messages.json @@ -56,12 +56,14 @@ "appIconEnableIconAndName": "वैकल्पिक ऐप आइकन और नाम का उपयोग करें", "appIconSelect": "वैकल्पिक ऐप आइकन चुनें", "appIconSelectionTitle": "आइकॉन", + "appName": "Session", "appNameCalculator": "कैलकुलेटर", "appNameMeetingSE": "मीटिंगएसई", "appNameNews": "समाचार", "appNameNotes": "नोट्स", "appNameStocks": "शेयरों", "appNameWeather": "मौसम", + "appPro": "Session Pro", "appearanceHideMenuBar": "मेनू बार छुपाएं", "appearanceLanguage": "भाषा", "appearanceLanguageDescription": "Session के लिए अपनी भाषा सेटिंग चुनें. जब आप अपनी भाषा सेटिंग बदलेंगे तो Session पुनः प्रारंभ हो जाएगा।", @@ -180,7 +182,6 @@ "callsSettings": "कॉल्स (बेटा)", "callsVoiceAndVideo": "वॉइस और वीडियो कॉल", "callsVoiceAndVideoBeta": "वॉइस और वीडियो कॉल (बीटा)", - "callsVoiceAndVideoModalDescription": "अपने खाते में एन्क्रिप्टेड संदेश भेजते समय आपका IP आपके कॉल पार्टनर और Oxen Foundation सर्वर को दिखाई देगा।", "callsVoiceAndVideoToggleDescription": "अन्य उपयोगकर्ताओं से वॉयस और वीडियो कॉल सक्षम करता है।", "callsYouCalled": "आपने {name} को कॉल किया", "callsYouMissedCallPermissions": "आपको प्राइवेसी सेटिंग्स में वॉइस और वीडियो कॉल्स सक्षम नहीं करने के कारण {name} से कॉल छूट गया।", @@ -624,6 +625,7 @@ "modalMessageCharacterTooLongTitle": "संदेश बहुत लंबा है", "modalMessageTooLongDescription": "कृपया अपने संदेश को {limit} वर्णों या कम में छोटा करें।", "modalMessageTooLongTitle": "संदेश बहुत लंबा है", + "networkName": "Session Network", "next": "अगला", "nicknameDescription": "{name} के लिए एक उपनाम चुनें। यह आपके एक-से-एक और समूह वार्तालापों में आपको दिखाई देगा।", "nicknameEnter": "उपनाम दर्ज करें", @@ -702,6 +704,7 @@ "open": "खोलें", "openSurvey": "सर्वेक्षण खोलें", "other": "अन्य", + "oxenFoundation": "Oxen Foundation", "passwordChange": "पासवर्ड बदलें", "passwordConfirm": "पासवर्ड की पुष्टि करें", "passwordCurrentIncorrect": "आपका वर्तमान पासवर्ड गलत है।", @@ -864,10 +867,13 @@ "sessionAppearance": "दिखावट", "sessionClearData": "डेटा हटाएं", "sessionConversations": "संवाद", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "मदद", "sessionInviteAFriend": "किसी मित्र को आमंत्रित करें", "sessionMessageRequests": "संदेश अनुरोध", "sessionNetworkCurrentPrice": "वर्तमान SESH मूल्य", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNetworkDescription": "संदेश Session Network का उपयोग करके भेजे जाते हैं। यह नेटवर्क Session Token से प्रेरित नोड्स से बना है, जो Session को विकेंद्रीकृत और सुरक्षित बनाए रखता है। और जानें {icon}", "sessionNetworkLearnAboutStaking": "स्टेकिंग के बारे में जानें", "sessionNetworkMarketCap": "बाज़ार पूंजीकरण", @@ -896,6 +902,7 @@ "showLess": "कम दिखाएं", "showNoteToSelf": "अपने लिए नोट दिखाएं", "showNoteToSelfDescription": "क्या आप वाकई अपनी वार्तालाप सूची में अपने लिए नोट दिखाना चाहते हैं?", + "stakingRewardPool": "Staking Reward Pool", "stickers": "स्टिकर", "supportGoTo": "सहायता पेज पर जाएँ", "systemInformationDesktop": "सिस्टम सूचना: {information}", @@ -903,6 +910,8 @@ "theContinue": "जारी रखें", "theDefault": "डिफ़ॉल्ट", "theError": "त्रुटि", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tooltipAccountIdVisible": "{name} का Account ID आपकी पिछली इंटरैक्शन के आधार पर दृश्यमान है", "tooltipBlindedIdCommunities": "ब्लाइंडेड ID समुदायों में स्पैम को कम करने और गोपनीयता बढ़ाने के लिए उपयोग की जाती हैं", "tryAgain": "फिर से कोशिश करो", @@ -935,6 +944,7 @@ "urlOpen": "यूआरएल खोलें", "urlOpenBrowser": "यह आपके ब्राउज़र में खुलेगा।", "urlOpenDescription": "क्या आप वाकई इस यूआरएल को अपने ब्राउज़र में खोलना चाहते हैं?

{url}", + "usdNameShort": "USD", "useFastMode": "तीव्र मोड इस्तेमाल करे", "video": "वीडियो", "videoErrorPlay": "वीडियो चलाने में असमर्थ", @@ -946,7 +956,6 @@ "warning": "चेतावनी", "window": "विंडो", "yes": "हाँ", - "you": "आप", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "आप" } diff --git a/_locales/hr/messages.json b/_locales/hr/messages.json index 3fe6136fe..d3245d6f2 100644 --- a/_locales/hr/messages.json +++ b/_locales/hr/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} i {other_name} promovirani su u Admina.", "andMore": "+{count}", "anonymous": "Anoniman", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Sakrij traku izbornika", "appearanceLanguage": "Jezik", "appearanceLanguageDescription": "Odaberite postavku jezika za Session. Session će se ponovno pokrenuti kada promijenite postavku jezika.", @@ -150,7 +152,6 @@ "callsSettings": "Pozivi (Beta)", "callsVoiceAndVideo": "Audio i video pozivi", "callsVoiceAndVideoBeta": "Audio i video pozivi (Beta)", - "callsVoiceAndVideoModalDescription": "Vaš IP je vidljiv vašem sugovorniku i poslužitelju Oxen Foundation dok koristite beta pozive.", "callsVoiceAndVideoToggleDescription": "Omogućava glasovne i video pozive prema i od drugih korisnika.", "callsYouCalled": "Zvali ste {name}", "callsYouMissedCallPermissions": "Propustili ste poziv od {name} jer niste omogućili Glasovne i Video pozive u Postavkama privatnosti.", @@ -524,6 +525,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Glasovna poruka", "messages": "Poruke", "minimize": "Minimiziraj", + "networkName": "Session Network", "next": "Sljedeće", "nicknameDescription": "Odaberite nadimak za {name}. Ovo će vam se prikazati u razgovorima jedan-na-jedan i grupnim razgovorima.", "nicknameEnter": "Unesite nadimak", @@ -597,6 +599,7 @@ "onsErrorUnableToSearch": "Nismo uspjeli pretražiti ovaj ONS. Molimo pokušajte ponovno kasnije.", "open": "Otvori", "other": "Ostalo", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Promijeni lozinku", "passwordConfirm": "Potvrdi lozinku", "passwordCurrentIncorrect": "Vaša trenutna lozinka je netočna.", @@ -705,9 +708,12 @@ "sessionAppearance": "Izgled", "sessionClearData": "Obriši podatke", "sessionConversations": "Razgovori", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Pomoć", "sessionInviteAFriend": "Pozovi prijatelja", "sessionMessageRequests": "Zahtjevi za porukama", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Obavijesti", "sessionPermissions": "Dopuštenja", "sessionPrivacy": "Privatnost", @@ -723,12 +729,15 @@ "show": "Prikaži", "showAll": "Prikaži sve", "showLess": "Prikaži manje", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Naljepnice", "supportGoTo": "Idi na stranicu za podršku", "systemInformationDesktop": "Informacije o sustavu: {information}", "theContinue": "Nastavi", "theDefault": "Zadano", "theError": "Greška", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Pokušaj ponovno", "typingIndicators": "Indikatori tipkanja", "typingIndicatorsDescription": "Pogledajte i podijelite indikatore tipkanja.", @@ -748,6 +757,7 @@ "urlOpen": "Otvori poveznicu", "urlOpenBrowser": "Ovo će se otvoriti u vašem pregledniku.", "urlOpenDescription": "Jeste li sigurni da želite otvoriti ovu URL adresu u pregledniku?

{url}", + "usdNameShort": "USD", "useFastMode": "Koristi brzi način", "video": "Video", "videoErrorPlay": "Nije moguće reproducirati videozapis.", @@ -757,7 +767,6 @@ "warning": "Upozorenje", "window": "Prozor", "yes": "Da", - "you": "Vi", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Vi" } diff --git a/_locales/hu/messages.json b/_locales/hu/messages.json index 25f0db804..926cecdb9 100644 --- a/_locales/hu/messages.json +++ b/_locales/hu/messages.json @@ -56,12 +56,14 @@ "appIconEnableIconAndName": "Alternatív alkalmazásikon és -név használata", "appIconSelect": "Válasszon alternatív alkalmazásikont", "appIconSelectionTitle": "Ikon", + "appName": "Session", "appNameCalculator": "Számológép", "appNameMeetingSE": "Találkozók", "appNameNews": "Hírek", "appNameNotes": "Jegyzetek", "appNameStocks": "Részvények", "appNameWeather": "Időjárás", + "appPro": "Session Pro", "appearanceHideMenuBar": "Menüsor elrejtése", "appearanceLanguage": "Nyelv", "appearanceLanguageDescription": "Válaszd ki a nyelvi beállításaidat a Session alkalmazáshoz. A Session újraindul, amikor megváltoztatod a nyelvi beállítást.", @@ -179,7 +181,6 @@ "callsSettings": "Hívások (béta)", "callsVoiceAndVideo": "Hang és videó hívások", "callsVoiceAndVideoBeta": "Hang és videó hívások (béta)", - "callsVoiceAndVideoModalDescription": "Az IP címed látható a hívópartner és egy Oxen Foundation szerver számára a béta hívások használata közben.", "callsVoiceAndVideoToggleDescription": "Lehetővé teszi a hang- és videohívásokat más felhasználókkal.", "callsYouCalled": "Felhívtad őt: {name}", "callsYouMissedCallPermissions": "Elmulasztottad {name} hívását, mert a hang- és videó hívások funkció nincs engedélyezve az adatvédelmi beállításokban.", @@ -614,6 +615,7 @@ "modalMessageCharacterTooLongTitle": "Az üzenet túl hosszú", "modalMessageTooLongDescription": "Rövidítse le az üzenetét {limit} karakterekre vagy kevesebbre.", "modalMessageTooLongTitle": "Az üzenet túl hosszú", + "networkName": "Session Network", "next": "Tovább", "nicknameDescription": "Válasszon becenevet {name} számára. Ez fog megjelenni az egyéni és csoportos beszélgetésekben.", "nicknameEnter": "Add meg a becenevet", @@ -691,6 +693,7 @@ "onsErrorUnableToSearch": "Az ONS keresése nem sikerült. Próbáld újra később.", "open": "Megnyitás", "other": "Egyéb", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Jelszó megváltoztatása", "passwordConfirm": "Jelszó megerősítése", "passwordCurrentIncorrect": "Az aktuális jelszavad helytelen.", @@ -829,10 +832,13 @@ "sessionAppearance": "Megjelenés", "sessionClearData": "Adataid törlése", "sessionConversations": "Beszélgetések", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Segítség", "sessionInviteAFriend": "Ismerős meghívása", "sessionMessageRequests": "Üzenetkérelmek", "sessionNetworkCurrentPrice": "Jelenlegi SESH ára", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNetworkDescription": "Az üzenetek küldése a(z) Session Network hálózaton keresztül történik. A hálózat a(z) Session Token tokennel ösztönzött csomópontokat tartalmaz, amelyek decentralizálttá és biztonságossá teszik a(z) Session alkalmazást.Tudjon meg többet {icon}", "sessionNetworkLearnAboutStaking": "Ismerje meg a lekötést", "sessionNetworkMarketCap": "Piaci sapka", @@ -861,6 +867,7 @@ "showLess": "Kevesebb mutatása", "showNoteToSelf": "„Jegyzet magamnak” megjelenítése", "showNoteToSelfDescription": "Biztosan meg akarja jeleníteni a Jegyzet magamnak jegyzetet a beszélgetési listában?", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Matricák", "supportGoTo": "Támogatási oldal megnyitása", "systemInformationDesktop": "Rendszerinformáció: {information}", @@ -868,6 +875,8 @@ "theContinue": "Folytatás", "theDefault": "Alapértelmezett", "theError": "Hiba", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Próbáld újra", "typingIndicators": "Gépelés-indikátorok", "typingIndicatorsDescription": "Gépelés-indikátorok küldése és fogadása.", @@ -894,6 +903,7 @@ "urlOpen": "URL megnyitása", "urlOpenBrowser": "Ez a böngésződben fog megnyílni.", "urlOpenDescription": "Biztos, hogy meg szeretnéd nyitni a böngésződben a következő linket?

{url}", + "usdNameShort": "USD", "useFastMode": "Gyors mód használata", "video": "Videó", "videoErrorPlay": "Videó lejátszása sikertelen.", @@ -905,7 +915,6 @@ "warning": "Figyelmeztetés", "window": "Ablak", "yes": "Igen", - "you": "Te", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Te" } diff --git a/_locales/hy-AM/messages.json b/_locales/hy-AM/messages.json index 0ac3dfa41..7cdc1e2d6 100644 --- a/_locales/hy-AM/messages.json +++ b/_locales/hy-AM/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name}֊ը և {other_name} բարձրացվել են որպես ադմին:", "andMore": "+{count}", "anonymous": "Անանուն", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Թաքցնել ընտրացանկը", "appearanceLanguage": "Լեզու", "appearanceLanguageDescription": "Ընտրեք Ձեր լեզվի կարգավորումը Session-ի համար։ Session-ը վերագործարկվելու է, երբ փոխեք Ձեր լեզվի կարգավորումը։", @@ -150,7 +152,6 @@ "callsSettings": "Զանգեր (Բետա)", "callsVoiceAndVideo": "Ձայնային և տեսազանգեր", "callsVoiceAndVideoBeta": "Ձայնային և տեսազանգեր (Beta)", - "callsVoiceAndVideoModalDescription": "Ձեր IP հասցեն տեսանելի է ձեր զանգի գործընկերոջը և մի 'Oxen Foundation' սերվերին ծիծլած օգտագործման ժամանակ։", "callsVoiceAndVideoToggleDescription": "Միացնում է ձայնային և տեսազանգերը դեպի և այլ օգտվողների հետ:", "callsYouCalled": "Դուք զանգահարել եք {name}", "callsYouMissedCallPermissions": "Դուք բաց եք թողել զանգը {name}֊ից, քանի որ չեք միացել ձայնային և տեսազանգեր գաղտնիության կարգավորումներում։", @@ -356,7 +357,7 @@ "files": "Ֆայլեր", "from": "Ուղարկող:", "fullScreenToggle": "Միացնել ամբողջ էկրանը", - "gif": "Գիֆ", + "gif": "GIF", "giphyWarning": "Giphy", "giphyWarningDescription": "Session-ը կմիակցվի Giphy-ին՝ արդյունքներ որոնելու համար: GIF-ներ ուղարկելիս դուք չեն ունենա ամբողջական մեթադատա պաշտպանություն։", "groupAddMemberMaximum": "Խմբին կարող են ունենալ առավելագույնս 100 անդամներ", @@ -524,6 +525,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Ձայնային հաղորդագրություն", "messages": "Հաղորդագրություններ", "minimize": "Փոքրացնել", + "networkName": "Session Network", "next": "Հաջորդը", "nicknameDescription": "Ընտրեք մի մականուն {name}-ի համար: Սա ծրագրում ցուցադրված կլինի ձեր զրույցներում", "nicknameEnter": "Մուտքագրե՛ք կեղծանունը", @@ -597,6 +599,7 @@ "onsErrorUnableToSearch": "Մենք չկարողացանք որոնել այս ONS-ը։ Խնդրում ենք փորձել ևս մեկ անգամ։", "open": "Բացել", "other": "Այլ", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Փոխել գաղտնաբառը", "passwordConfirm": "Հաստատել գաղտնաբառը", "passwordCurrentIncorrect": "Ձեր ներկա գաղտնաբառը սխալ է։", @@ -705,9 +708,12 @@ "sessionAppearance": "Արտաքին տեսք", "sessionClearData": "Զրոյացնել", "sessionConversations": "Զրույցներ", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Աջակցություն", "sessionInviteAFriend": "Հրավիրել ընկերոջը", "sessionMessageRequests": "Հաղորդագրության հարցումներ", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Ծանուցումներ", "sessionPermissions": "Թույլտվություններ", "sessionPrivacy": "Գաղտնիություն", @@ -723,12 +729,15 @@ "show": "Ցուցադրել", "showAll": "Ցուցադրել բոլորը", "showLess": "Ավելի քիչ ցույց տալ", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Պիտակներ", "supportGoTo": "Բացեք աջակցության էջը", "systemInformationDesktop": "Համակարգի տեղեկությունը՝ {information}", "theContinue": "Շարունակել", "theDefault": "Սկզբնական", "theError": "Սխալ", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Փորձել նորից", "typingIndicators": "Գրելու ինդիկատորներ", "typingIndicatorsDescription": "Տեսեք և տարածեք մուտքագրման ցուցիչները.", @@ -748,6 +757,7 @@ "urlOpen": "Բացել URL", "urlOpenBrowser": "Սա կբացվի ձեր զննարկիչում:", "urlOpenDescription": "Վստա՞հ եք, որ ցանկանում եք բացել այս URL-ը ձեր դիտարկիչում?

{url}", + "usdNameShort": "USD", "useFastMode": "Օգտագործել արագ ռեժիմը", "video": "Տեսանյութ", "videoErrorPlay": "Չհաջողվեց նվագարկել տեսանյութը։", @@ -757,7 +767,6 @@ "warning": "Զգուշացում", "window": "Պատուհան", "yes": "Այո", - "you": "Դուք", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Դուք" } diff --git a/_locales/id/messages.json b/_locales/id/messages.json index fb38e6937..5bd658151 100644 --- a/_locales/id/messages.json +++ b/_locales/id/messages.json @@ -50,11 +50,13 @@ "appIconEnableIconAndName": "Gunakan ikon aplikasi alternatif dan nama", "appIconSelect": "Pilih ikon aplikasi alternatif", "appIconSelectionTitle": "Ikon", + "appName": "Session", "appNameCalculator": "Kalkulator", "appNameNews": "Berita", "appNameNotes": "Catatan", "appNameStocks": "Bursa Saham", "appNameWeather": "Cuaca", + "appPro": "Session Pro", "appearanceHideMenuBar": "Sembunyikan Meny Bar", "appearanceLanguage": "Bahasa", "appearanceLanguageDescription": "Pilih pengaturan bahasa Anda untuk Session. Session akan dimulai ulang ketika Anda mengubah pengaturan bahasa.", @@ -170,7 +172,6 @@ "callsSettings": "Panggilan (Beta)", "callsVoiceAndVideo": "Panggilan Suara dan Video", "callsVoiceAndVideoBeta": "Panggilan Suara dan Video (Beta)", - "callsVoiceAndVideoModalDescription": "IP Anda terlihat oleh mitra panggilan Anda dan server Oxen Foundation saat menggunakan panggilan beta.", "callsVoiceAndVideoToggleDescription": "Aktifkan panggilan suara dan video ke atau dari pengguna lain.", "callsYouCalled": "Anda memanggil {name}", "callsYouMissedCallPermissions": "Anda melewatkan panggilan dari {name} karena Anda belum mengaktifkan Panggilan Suara dan Video di Pengaturan Privasi.", @@ -581,6 +582,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Pesan Suara", "messages": "Pesan", "minimize": "Kecilkan", + "networkName": "Session Network", "next": "Selanjutnya", "nicknameDescription": "Pilih nama panggilan untuk {name}. Ini akan muncul untuk Anda dalam percakapan satu-satu dan grup Anda.", "nicknameEnter": "Masukkan nama panggilan", @@ -657,6 +659,7 @@ "onsErrorUnableToSearch": "Kami tidak dapat mencari ONS ini. Harap coba lagi nanti.", "open": "Buka", "other": "Lainnya", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Ubah Kata Sandi", "passwordConfirm": "Konfirmasi kata sandi", "passwordCurrentIncorrect": "Kata sandi anda saat ini salah.", @@ -779,10 +782,13 @@ "sessionAppearance": "Tampilan", "sessionClearData": "Hapus Data", "sessionConversations": "Percakapan", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Bantuan", "sessionInviteAFriend": "Undang Teman", "sessionMessageRequests": "Permintaan Pesan", "sessionNetworkCurrentPrice": "Harga SESH saat ini", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNetworkSecuredBy": "Jaringan aman oleh", "sessionNotifications": "Notifikasi", "sessionPermissions": "Izin", @@ -802,6 +808,7 @@ "showAll": "Tampilkan Semua", "showLess": "Tampilkan Sedikit", "showNoteToSelf": "Lihat Catatan Pribadi", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Stiker", "supportGoTo": "Cek halaman bantuan", "systemInformationDesktop": "Informasi Sistem: {information}", @@ -809,6 +816,8 @@ "theContinue": "Lanjutkan", "theDefault": "Bawaan", "theError": "Kesalahan", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Coba Lagi", "typingIndicators": "Indikator penulisan", "typingIndicatorsDescription": "Lihat dan bagikan indikator mengetik.", @@ -833,6 +842,7 @@ "urlOpen": "Buka URL", "urlOpenBrowser": "Ini akan membuka di peramban Anda.", "urlOpenDescription": "Apakah Anda yakin ingin membuka URL ini di browser?

{url}", + "usdNameShort": "USD", "useFastMode": "Gunakan Fast Mode", "video": "Video", "videoErrorPlay": "Tidak dapat memutar video.", @@ -844,7 +854,6 @@ "warning": "Peringatan", "window": "Jendela", "yes": "Ya", - "you": "Anda", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Anda" } diff --git a/_locales/it/messages.json b/_locales/it/messages.json index 0d12b1c81..d56fbdbb9 100644 --- a/_locales/it/messages.json +++ b/_locales/it/messages.json @@ -56,12 +56,14 @@ "appIconEnableIconAndName": "Usa icona e nome alternativi", "appIconSelect": "Seleziona un'icona alternativa", "appIconSelectionTitle": "Icona", + "appName": "Session", "appNameCalculator": "Calcolatrice", "appNameMeetingSE": "MeetingSE", "appNameNews": "Notizie", "appNameNotes": "Note", "appNameStocks": "Borsa", "appNameWeather": "Meteo", + "appPro": "Session Pro", "appearanceHideMenuBar": "Nascondi la barra dei menu", "appearanceLanguage": "Lingua", "appearanceLanguageDescription": "Scegli la lingua per Session. Session si riavvierà ogni volta che la cambierai.", @@ -180,7 +182,6 @@ "callsSettings": "Chiamate (Beta)", "callsVoiceAndVideo": "Chiamate vocali e video", "callsVoiceAndVideoBeta": "Chiamate vocali e video (Beta)", - "callsVoiceAndVideoModalDescription": "Il tuo IP è visibile all'utente che stai chiamando e a un server di Oxen Foundation durante l'utilizzo delle chiamate beta.", "callsVoiceAndVideoToggleDescription": "Abilita chiamate e videochiamate verso e da altri utenti.", "callsYouCalled": "Hai chiamato {name}", "callsYouMissedCallPermissions": "Hai perso una chiamata da {name} perché non hai abilitato Chiamate vocali e video nelle impostazioni della privacy.", @@ -624,6 +625,7 @@ "modalMessageCharacterTooLongTitle": "Messaggio troppo lungo", "modalMessageTooLongDescription": "Riduci il tuo messaggio a {limit} caratteri o meno.", "modalMessageTooLongTitle": "Messaggio troppo lungo", + "networkName": "Session Network", "next": "Avanti", "nicknameDescription": "Scegli un soprannome per {name}. Apparirà nelle tue conversazioni private e chat di gruppo.", "nicknameEnter": "Inserisci soprannome", @@ -702,6 +704,7 @@ "open": "Apri", "openSurvey": "Apri sondaggio", "other": "Altro", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Cambia password", "passwordConfirm": "Conferma password", "passwordCurrentIncorrect": "La tua password attuale non è corretta.", @@ -864,10 +867,13 @@ "sessionAppearance": "Aspetto", "sessionClearData": "Elimina dati", "sessionConversations": "Conversazioni", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Aiuto", "sessionInviteAFriend": "Invita un amico", "sessionMessageRequests": "Richieste di messaggi", "sessionNetworkCurrentPrice": "Prezzo attuale di SESH", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNetworkDescription": "I messaggi vengono inviati utilizzando la Session Network. La rete è composta da nodi incentivati con Session Token, che mantengono Session decentralizzata e sicura. Scopri di più {icon}", "sessionNetworkLearnAboutStaking": "Scopri lo staking", "sessionNetworkMarketCap": "Capitalizzazione di mercato", @@ -896,6 +902,7 @@ "showLess": "Mostra meno", "showNoteToSelf": "Mostra note personali", "showNoteToSelfDescription": "Sei sicuro di voler mostrare Note to Self nella tua lista di conversazioni?", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Adesivi", "supportGoTo": "Vai alla pagina di supporto", "systemInformationDesktop": "Informazioni di sistema: {information}", @@ -903,6 +910,8 @@ "theContinue": "Continua", "theDefault": "Predefinito", "theError": "Errore", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tooltipAccountIdVisible": "L'Account ID di {name} è visibile in base alle interazioni precedenti", "tooltipBlindedIdCommunities": "Gli ID offuscati vengono utilizzati nelle Community per ridurre lo spam e aumentare la privacy", "tryAgain": "Riprova", @@ -935,6 +944,7 @@ "urlOpen": "Apri link", "urlOpenBrowser": "Questo link si aprirà nel tuo browser.", "urlOpenDescription": "Sei sicuro di voler aprire questo link nel tuo browser?

{url}", + "usdNameShort": "USD", "useFastMode": "Usa la Modalità rapida", "video": "Video", "videoErrorPlay": "Impossibile riprodurre il video.", @@ -946,7 +956,6 @@ "warning": "Attenzione", "window": "Finestra", "yes": "Sì", - "you": "Tu", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Tu" } diff --git a/_locales/ja/messages.json b/_locales/ja/messages.json index f4a923b87..095d648cf 100644 --- a/_locales/ja/messages.json +++ b/_locales/ja/messages.json @@ -56,12 +56,14 @@ "appIconEnableIconAndName": "代替のアプリアイコンと名前を使用", "appIconSelect": "代替アプリアイコンを選択", "appIconSelectionTitle": "アイコン", + "appName": "Session", "appNameCalculator": "電卓", "appNameMeetingSE": "MeetingSE", "appNameNews": "ニュース", "appNameNotes": "メモ", "appNameStocks": "株式", "appNameWeather": "天気", + "appPro": "Session Pro", "appearanceHideMenuBar": "メニューバーを隠す", "appearanceLanguage": "言語", "appearanceLanguageDescription": "Sessionの言語設定を選択してください。言語設定を変更するとSessionが再起動されます。", @@ -180,7 +182,6 @@ "callsSettings": "通話 (ベータ版)", "callsVoiceAndVideo": "音声とビデオ通話", "callsVoiceAndVideoBeta": "音声通話とビデオ通話 (ベータ版)", - "callsVoiceAndVideoModalDescription": "音声通話とビデオ通話の使用中、あなたのIPはあなたの通話相手とOxen Foundationサーバーに表示されます。", "callsVoiceAndVideoToggleDescription": "他のユーザーとの音声通話やビデオ通話を有効にします", "callsYouCalled": "{name} に発信", "callsYouMissedCallPermissions": "{name}さんからの通話を逃しました。プライバシー設定で音声通話とビデオ通話を有効にしていません。", @@ -624,6 +625,7 @@ "modalMessageCharacterTooLongTitle": "メッセージが長すぎます", "modalMessageTooLongDescription": "メッセージを{limit}文字以内に短くしてください。", "modalMessageTooLongTitle": "メッセージが長すぎます", + "networkName": "Session Network", "next": "次", "nicknameDescription": "{name}のニックネームを選んでください。これが1対1およびグループ会話で表示されます。", "nicknameEnter": "ニックネームを入力してください", @@ -702,6 +704,7 @@ "open": "開く", "openSurvey": "アンケートを開く", "other": "その他", + "oxenFoundation": "Oxen Foundation", "passwordChange": "パスワードを変更", "passwordConfirm": "パスワードを再確認", "passwordCurrentIncorrect": "現在のパスワードが間違っています。", @@ -864,10 +867,13 @@ "sessionAppearance": "デザイン設定", "sessionClearData": "データを消去する", "sessionConversations": "会話", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "ヘルプ", "sessionInviteAFriend": "友達を招待", "sessionMessageRequests": "メッセージリクエスト", "sessionNetworkCurrentPrice": "現在の SESH 価格", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNetworkDescription": "メッセージは Session Network を使用して送信されます。このネットワークは Session Token によってインセンティブを受けたノードで構成されており、Session の分散性と安全性を保っています。詳しくはこちら {icon}", "sessionNetworkLearnAboutStaking": "ステーキングについて学ぶ", "sessionNetworkMarketCap": "時価総額", @@ -896,6 +902,7 @@ "showLess": "少なく表示", "showNoteToSelf": "自分用メモを表示", "showNoteToSelfDescription": "自分用メモを会話リストに表示しますか?", + "stakingRewardPool": "Staking Reward Pool", "stickers": "ステッカー", "supportGoTo": "サポートページへ", "systemInformationDesktop": "システム情報: {information}", @@ -903,6 +910,8 @@ "theContinue": "続行", "theDefault": "デフォルト", "theError": "エラー", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tooltipAccountIdVisible": "{name} のAccount IDは、以前のやり取りに基づき表示されます", "tooltipBlindedIdCommunities": "ブラインドIDは、スパムを減らしプライバシーを高めるためにCommunityで利用されます", "tryAgain": "再試行", @@ -935,6 +944,7 @@ "urlOpen": "URLを開く", "urlOpenBrowser": "これをブラウザで開きます。", "urlOpenDescription": "本当にこのURLをブラウザで開きますか?

{url}", + "usdNameShort": "USD", "useFastMode": "高速モードを使用する", "video": "動画", "videoErrorPlay": "動画を再生できません。", @@ -946,7 +956,6 @@ "warning": "警告", "window": "ウィンドウ", "yes": "はい", - "you": "あなた", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "あなた" } diff --git a/_locales/ka/messages.json b/_locales/ka/messages.json index f83cd4776..dea6737cb 100644 --- a/_locales/ka/messages.json +++ b/_locales/ka/messages.json @@ -40,6 +40,8 @@ "andMore": "+{count}", "anonymous": "ანონიმური", "appIcon": "აპის ხატულა", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "მენიუს ზოლში დამალვა", "appearanceLanguage": "ენა", "appearanceLanguageDescription": "შეარჩიეთ თქვენი ენის პარამეტრები Session-ისთვის. Session გადატვირთება საჭირო იქნება ენის პარამეტრებისთვის.", @@ -152,7 +154,6 @@ "callsSettings": "ზარები (Beta)", "callsVoiceAndVideo": "ხმოვანი და ვიდეო ზარები", "callsVoiceAndVideoBeta": "ხმოვანი და ვიდეო ზარები (Beta)", - "callsVoiceAndVideoModalDescription": "თქვენი IP გააშკარავდება თქვენი ზარის პარტნიორს და Oxen Foundation-ის სერვერს, ბეტა ზარების გამოყენებისას.", "callsVoiceAndVideoToggleDescription": "ჩართავს ხმის და ვიდეო ზარებს სხვა მომხმარებლებისთვის დამატებით.", "callsYouCalled": "თქვენ დარეკეთ {name}-ს", "callsYouMissedCallPermissions": "თქვენ გამოტოვეთ ზარი {name}-ისგან რადგან თქვენ არ ჩართეთ ხმა და ვიდეო ზარები კონფიდენციალურობის პარამეტრებში.", @@ -536,6 +537,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Voice Message", "messages": "შეტყობინებები", "minimize": "ჩაკეცვა", + "networkName": "Session Network", "next": "შემდეგი", "nicknameDescription": "აირჩიე ზედმეტსახელი {name}-თვის. ეს გამოგიჩნდება შენს ერთ-ერთ და ჯგუფის საუბრებში.", "nicknameEnter": "შეიყვანეთ მეტსახელი", @@ -609,6 +611,7 @@ "onsErrorUnableToSearch": "ONS ძებნა ვერ მოხერხდა. გთხოვთ სცადოთ მოგვიანებით.", "open": "გახსენით", "other": "სხვა", + "oxenFoundation": "Oxen Foundation", "passwordChange": "პაროლის შეცვლა", "passwordConfirm": "პაროლის დადასტურება", "passwordCurrentIncorrect": "თქვენი ახლანდელი პაროლი არასწორია.", @@ -718,9 +721,12 @@ "sessionAppearance": "გარეგნობა", "sessionClearData": "მონაცემების გასუფთავება", "sessionConversations": "საუბრები", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "დახმარება", "sessionInviteAFriend": "მოწვიე მეგობარი", "sessionMessageRequests": "შეტყობინების მოთხოვნები", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "შეტყობინებები", "sessionPermissions": "უფლებები", "sessionPrivacy": "პირადი", @@ -736,12 +742,15 @@ "show": "ჩვენება", "showAll": "ყველას ჩვენება", "showLess": "ნაკლები ჩვენება", + "stakingRewardPool": "Staking Reward Pool", "stickers": "სტიკერები", "supportGoTo": "გადადით მხარდაჭერის გვერდზე", "systemInformationDesktop": "სისტემის ინფორმაცია: {information}", "theContinue": "გაგრძელება", "theDefault": "ნაგულისხმევი", "theError": "შეცდომა", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "კვლავ სცადეთ", "typingIndicators": "ტიპინგის ინდიკატორები", "typingIndicatorsDescription": "იხილეთ და გააზიარეთ აკრეფის მაჩვენებლები.", @@ -762,6 +771,7 @@ "urlOpen": "გახსენით URL", "urlOpenBrowser": "ეს გაიხსნება თქვენს ბრაუზერში.", "urlOpenDescription": "დარწმუნებული ხართ, რომ გსურთ ამ URL-ის გახსნა თქვენს ბრაუზერში?

{url}", + "usdNameShort": "USD", "useFastMode": "დააპტიურეთ Fast Mode", "video": "ვიდეო", "videoErrorPlay": "ვიდეოს დაკვრა ვერ ხერხდება.", @@ -771,7 +781,6 @@ "warning": "გაფრთხილება", "window": "ფანჯარა", "yes": "Yes", - "you": "თქვენ", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "თქვენ" } diff --git a/_locales/km/messages.json b/_locales/km/messages.json index 8934c3fac..03bb2024a 100644 --- a/_locales/km/messages.json +++ b/_locales/km/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name}‍ និង {other_name}‍ ត្រូវណានបិស្មីជា Admin។", "andMore": "+{count}", "anonymous": "អនាមិក", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "លាក់របារម៉ឺនុយ", "appearanceLanguage": "ភាសា", "appearanceLanguageDescription": "ជ្រើសរើសការកំណត់ភាសាសម្រាប់ Session។ Session នឹងចាប់ផ្តើមឡើងវិញនៅពេលអ្នកផ្លាស់ប្តូរការកំណត់ភាសារបស់អ្នក។", @@ -150,7 +152,6 @@ "callsSettings": "ការហៅ (បេតា)", "callsVoiceAndVideo": "ការហៅជាសំឡេង និងជា​វីដេអូ", "callsVoiceAndVideoBeta": "ការហៅជាសំឡេង និងជា​វីដេអូ (បេតា)", - "callsVoiceAndVideoModalDescription": "IP អ្នក​ត្រូវបាន​លេចឮ​ច្បាស់នៅពេល​អ្នក​ប្រើកិច្ចប្រជុំ Beta ក្នុង Oxen Foundation។", "callsVoiceAndVideoToggleDescription": "បើកការហៅជាសំឡេង និងជាវីដេអូទៅកាន់ និងមកពីអ្នកប្រើផ្សេងទៀត។", "callsYouCalled": "អ្នកបានហៅ {name}", "callsYouMissedCallPermissions": "អ្នក​ធ្វើ​រំលងការហៅពី {name} ដោយសារ​អ្នកមិន​បានបើក ការហៅសំឡេង និងវីដេអូ នៅក្នុងការកំណត់ភាពឯកជន។", @@ -524,6 +525,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} សារជាសំឡេង", "messages": "សារ", "minimize": "បង្រួមតូច", + "networkName": "Session Network", "next": "បន្ទាប់", "nicknameDescription": "ជ្រើសរើសឈ្មោះហៅក្រៅសម្រាប់ {name}។ វានឹងបង្ហាញទៅលើការសន្ទនារបស់អ្នកក្នុងការចែកចាយនិងក្រុម។", "nicknameEnter": "បញ្ចូលឈ្មោះហៅក្រៅ", @@ -597,6 +599,7 @@ "onsErrorUnableToSearch": "យើងមិនអាចស្វែងរក ONS នេះបានទេ។ សូមសាកល្បងម្តងទៀតនៅពេលក្រោយ។", "open": "បើក", "other": "ផ្សេងៗ", + "oxenFoundation": "Oxen Foundation", "passwordChange": "ប្តូរពាក្យសម្ងាត់", "passwordConfirm": "បញ្ជាក់ពាក្យសម្ងាត់", "passwordCurrentIncorrect": "ពាក្យសម្ងាត់​បច្ចុប្បន្នរបស់អ្នក មិនត្រឹមត្រូវទេ។", @@ -705,9 +708,12 @@ "sessionAppearance": "រូបរាង", "sessionClearData": "លុបទិន្នន័យ", "sessionConversations": "ការសន្ទនា", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "ជំនួយ", "sessionInviteAFriend": "អញ្ជើញមិត្តភក្តិម្នាក់", "sessionMessageRequests": "សំណាងល្អនៅមុខបន្ថែម!", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "សារជូនដំណឹង", "sessionPermissions": "ការអនុញ្ញាត", "sessionPrivacy": "ឯកជនភាព", @@ -723,12 +729,15 @@ "show": "បង្ហាញ", "showAll": "បង្ហាញទាំងអស់", "showLess": "បង្ហាញតិចជាង", + "stakingRewardPool": "Staking Reward Pool", "stickers": "ស្ទីកគ័រ", "supportGoTo": "ចូលទៅកាន់ទំព័រគាំទ្រ", "systemInformationDesktop": "ព័ត៌មានប្រព័ន្ធ: {information}", "theContinue": "បន្ត", "theDefault": "លំនាំដើម", "theError": "បញ្ហា", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "សូមព្យាយាម​ម្តង​ទៀត", "typingIndicators": "សូចនាករវាយអក្សរ", "typingIndicatorsDescription": "មើល និងចែករំលែកសញ្ញាបង្ហាញពេលកំពុងវាយអក្សរ។", @@ -748,6 +757,7 @@ "urlOpen": "បើក URL", "urlOpenBrowser": "This will open in your browser.", "urlOpenDescription": "តើអ្នកប្រាកដទេថាអ្នកចង់បើក URL នេះនៅក្នុងកម្មវិធីរុករករបស់អ្នក?

{url}", + "usdNameShort": "USD", "useFastMode": "ប្រើមុខងាររហ័ស", "video": "វីដេអូ", "videoErrorPlay": "មិនអាចរំកិលវីដេអូបានទេ។", @@ -757,7 +767,6 @@ "warning": "ការព្រមាន", "window": "ផ្ទាំងបង្អួច", "yes": "បាទ", - "you": "អ្នក", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "អ្នក" } diff --git a/_locales/kmr/messages.json b/_locales/kmr/messages.json index d4cc42a9f..1cf135489 100644 --- a/_locales/kmr/messages.json +++ b/_locales/kmr/messages.json @@ -40,6 +40,8 @@ "adminTwoPromotedToAdmin": "{name} û {other_name} wekî admîn hatin xwepêşandin.", "andMore": "+{count}", "anonymous": "Anonîm", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Darikê Menuyê Biveşêre", "appearanceLanguage": "Ziman", "appearanceLanguageDescription": "Hilbijartina zimanê xwe ya bo Session bijêre. Session di nava biguherîne leyenda zimanê nava.", @@ -153,7 +155,6 @@ "callsSettings": "Bangên (Beta)", "callsVoiceAndVideo": "Lêgerînên Dengî û Vîdeoyî", "callsVoiceAndVideoBeta": "Lêgerînên Dengî û Vîdeoyî (Beta)", - "callsVoiceAndVideoModalDescription": "Adresa IP̧ya te bi dirising ti paşinspectek an hîn ya Fundaceya Oxen bêyê dîtin.", "callsVoiceAndVideoToggleDescription": "Lêgerînên dengî û vîdeoyî yên li kesên din û ji kesên din aktîv dike.", "callsYouCalled": "Te li {name} geriya", "callsYouMissedCallPermissions": "Ji ber ku te Hest û Têketin li Mîhengekên Peyamezanê neskine, ji {name}ê bangeke hilnasî!", @@ -535,6 +536,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Peyama Dengî", "messages": "Peyam", "minimize": "Biçûk bike", + "networkName": "Session Network", "next": "Yê piştî", "nicknameDescription": "Ji bo {name} nawnêk bijêre. Ev ji te re di nîqaş û komê de xuya dibe.", "nicknameEnter": "Leqebekî binivîse", @@ -608,6 +610,7 @@ "onsErrorUnableToSearch": "Em nakefeni ji vê ONS bibikira. Ji kerema xwe dîsa ceribkine.", "open": "Veke", "other": "Yên din", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Şîfreyê Biguherîne", "passwordConfirm": "Şîfreyê tesdîq bike", "passwordCurrentIncorrect": "Şîfreyê te çewt e.", @@ -719,9 +722,12 @@ "sessionAppearance": "Xuyang", "sessionClearData": "Daneyê paqij bike", "sessionConversations": "Sohbet", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Alîkarî", "sessionInviteAFriend": "Hevalekî Dawet Bike", "sessionMessageRequests": "Daxwazên Peyamê", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Agahdarî", "sessionPermissions": "Îzn", "sessionPrivacy": "Nihênî", @@ -737,12 +743,15 @@ "show": "Nîşan bide", "showAll": "Temamê wan nîşan bide", "showLess": "Kêmtir nîşan bide", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Sanjqlar", "supportGoTo": "Here Rûpela Destekê", "systemInformationDesktop": "Agahiyên Sîstemî: {information}", "theContinue": "Berdewam", "theDefault": "Bawerî", "theError": "Şaşî", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Cardin biceribîne", "typingIndicators": "Îndîkatorên nivîsînê", "typingIndicatorsDescription": "Nîşandan û parvebûna nîşanên nivîsandinê bibinê.", @@ -763,6 +772,7 @@ "urlOpen": "URLê Veke", "urlOpenBrowser": "Ev bibîne di browserê te de.", "urlOpenDescription": "Tu piştrast î ku tu dixwazî vê URLyê di geroka xwe de vekî?

{url}", + "usdNameShort": "USD", "useFastMode": "Bikaranîna Modê Zû", "video": "Vîdeo", "videoErrorPlay": "Nebil bikarane vîdeo bimeşe.", @@ -772,7 +782,6 @@ "warning": "Hişyarî", "window": "Pencere", "yes": "Erê", - "you": "Tu", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Tu" } diff --git a/_locales/kn/messages.json b/_locales/kn/messages.json index 6d74ea7c9..71b92110f 100644 --- a/_locales/kn/messages.json +++ b/_locales/kn/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} ಪ್ರ ಮತ್ತು {other_name} ಪ್ರ ನಿರ್ವಾಹಕರಾಗಿ ಬಡ್ತಿ ಪಡೆದಿದ್ದಾರೆ.", "andMore": "+{count}", "anonymous": "ಅನಾಮಧೇಯ", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "ಮೆನೂ ಬಾರ್ ಅನ್ನು ಮರೆಮಾಡಿ", "appearanceLanguage": "ಭಾಷೆ", "appearanceLanguageDescription": "Sessionಗಾಗಿ ನಿಮ್ಮ ಭಾಷಾ ಸೆಟ್ಟಿಂಗ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ. Session ನಿಮ್ಮ ಭಾಷಾ ಸೆಟ್ಟಿಂಗ್ ಬದಲಾಯಿಸಿದಾಗ ಪುನರಾರಂಭಗೊಳ್ಳುತ್ತದೆ.", @@ -150,7 +152,6 @@ "callsSettings": "ಕಾಲುಗಳು (ಬೀಟಾ)", "callsVoiceAndVideo": "ವಾಯ್ಸ್ ಮತ್ತು ವೀಡಿಯೋ ಕರೆಗಳು", "callsVoiceAndVideoBeta": "ವಾಯ್ಸ್ ಮತ್ತು ವೀಡಿಯೋ ಕರೆಗಳು (ಬೀಟಾ)", - "callsVoiceAndVideoModalDescription": "ಬೇಟ ಕಾಲ್ಲನ್ನು ಬಳಸಿದಾಗ ನಿಮ್ಮ IP ಕರೆ ಸಹವಾಸಿಗೂ ಮತ್ತು Oxen Foundation ಸರ್ವರ್‌ಗೆ ಗೋಚರುತ್ತದೆ.", "callsVoiceAndVideoToggleDescription": "ಇತರ ಬಳಕೆದಾರರಿಂದ ಮತ್ತು ಇತರ ಬಳಕೆದಾರರಿಗೆ ಧ್ವನಿ ಮತ್ತು ವೀಡಿಯೊ ಕರೆಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸುತ್ತದೆ.", "callsYouCalled": "ನೀವು {name} ಗೆ ಕರೆ ಮಾಡಿದ್ದೀರಿ", "callsYouMissedCallPermissions": "ನೀವು {name} ನಿಂದ ಕರೆ ಕಳೆದುಕೊಂಡಿದ್ದೀರಿ ಏಕೆಂದರೆ ನೀವು ಪ್ರೈವೆಸಿ ಸೆಟ್ಟಿಂಗ್ಗಳಲ್ಲಿ ವಾಯ್ಸ್ ಮತ್ತು ವಿಡಿಯೋ ಕಾಲ್‌ಗಳು ನ್ನು ಅನುಮತಿಸಿದಿಲ್ಲ.", @@ -356,7 +357,7 @@ "files": "ಕಡತಗಳು", "from": "ಆ:ನಿಂದ:", "fullScreenToggle": "ಪೂರ್ಣ ಪರದೆ ತೊಗಲ್ ಮಾಡಿ", - "gif": "ಗಿಫ್", + "gif": "GIF", "giphyWarning": "ಗಿಫ್ಫಿ", "giphyWarningDescription": "Session Giphy ಗೆ ಸಂಪರ್ಕಿಸಿ ಶೋಧ ಫಲಿತಾಂಶಗಳನ್ನು ಒದಗಿಸುತ್ತದೆ. GIFಗಳನ್ನು ಕಳುಹಿಸುವಾಗ ನಿಮ್ಮ ಮೆಟಾಡೇಟಾ ಸಂರಕ್ಷಣೆ ಪೂರ್ಣವಾಗುವುದಿಲ್ಲ.", "groupAddMemberMaximum": "ಗುಂಪುಗಳು ಗರಿಷ್ಟ 100 ಸದಸ್ಯರಿರುವುದಿಲ್ಲ", @@ -524,6 +525,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} ವಾಯ್ಸ್ ಸಂದೇಶ", "messages": "ಸಂದೇಶಗಳು", "minimize": "ಕಡಿಮೆ ಮಾಡು", + "networkName": "Session Network", "next": "ಮುಂದಿನ", "nicknameDescription": "{name} ಗಾಗಿ ಮರುಹೆಸರು ಆಯ್ಕೆಮಾಡಿ. ಇದು ನಿಮ್ಮ ಒಬ್ಬೊಬ್ಬ ಅವಧಿಗಳಲ್ಲಿ ಮತ್ತು ಗುಂಪು ಸಂಭಾಷಣೆಯಲ್ಲಿ ಕಾಣಿಸುತ್ತದೆ.", "nicknameEnter": "ಅಡು ಕಂಪನ", @@ -597,6 +599,7 @@ "onsErrorUnableToSearch": "ನಾವು ಈ ONS ಹುಡುಕಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ. ದಯವಿಟ್ಟು ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ.", "open": "ತೆರೆ", "other": "ಇತರೆ", + "oxenFoundation": "Oxen Foundation", "passwordChange": "ಪಾಸ್ವರ್ಡ್ ಬದಲಾಯಿಸಲು", "passwordConfirm": "ಪಾಸ್ವರ್ಡ್ ದೃಡಪಡಿಸಿ", "passwordCurrentIncorrect": "ನಿಮ್ಮ ಪ್ರಸ್ತುತ ಪಾಸ್ಪಾಡ್ ತಪ್ಪಾಗಿದೆ.", @@ -705,9 +708,12 @@ "sessionAppearance": "ಆಕೃತಿ", "sessionClearData": "ಡೆಟಾ ತೆರವು ಮಾಡಿ", "sessionConversations": "ಸಂಭಾಷಣೆಗಳು", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "ಸಹಾಯ", "sessionInviteAFriend": "ಒರ್ವ ಸ್ನೇಹಿತನನ್ನು ಆಮಂತ್ರಿಸಿ", "sessionMessageRequests": "Message Requests", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "ಅಧಿಸೂಚನೆಗಳು", "sessionPermissions": "ಅನುಮಿತಿಗಳು", "sessionPrivacy": "ಖಾಸಗಿತನ", @@ -723,12 +729,15 @@ "show": "ತೋರಿಸು", "showAll": "ಎಲ್ಲ ತೋರಿಸು", "showLess": "ಕಡಿಮೆ ತೋರಿಸು", + "stakingRewardPool": "Staking Reward Pool", "stickers": "ಸ್ಟಿಕರ್‌‌ಗಳು", "supportGoTo": "ಬೆಂಬಲ ಪುಟಕ್ಕೆ ಹೋಗಿ", "systemInformationDesktop": "ಸಿಸ್ಟಮ್ ಮಾಹಿತಿ: {information}", "theContinue": "ಮುಂದುವರಿಯಿರಿ", "theDefault": "ಪೂರ್ವನಿಯೋಜಿತ", "theError": "ದೋಷ", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ", "typingIndicators": "ಟೈಪಿಂಗ್ ಸೂಚಕರು", "typingIndicatorsDescription": "ಟೈಪಿಂಗ್ ಸೂಚಕಗಳನ್ನು ನೋಡಿ ಮತ್ತು ಹಂಚಿಕೊಳ್ಳಿ.", @@ -748,6 +757,7 @@ "urlOpen": "URL ತೆರೆ", "urlOpenBrowser": "ಇವು ನಿಮ್ಮ ಬ್ರೌಸರ್‌ನಲ್ಲಿ ತೆರೆಯಲಾಗುತ್ತದೆ.", "urlOpenDescription": "ನೀವು ನಿಮ್ಮ ಬ್ರೌಸರ್‌ನಲ್ಲಿ ಈ URL ಅನ್ನು ತೆರೆಯಲು ಖಚಿತವಾಗಿ ಬಯಸುವಿರಾ?

{url}", + "usdNameShort": "USD", "useFastMode": "ಫಾಸ್ಟ್ ಮೋಡ್ ಬಳಸಿ", "video": "ವೀಡಿಯೊ", "videoErrorPlay": "ವೀಡಿಯೋ ಆಟವಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ.", @@ -757,7 +767,6 @@ "warning": "ಎಚ್ಚರಿಕೆ", "window": "ಕಿಟಕಿ", "yes": "ಹೌದು", - "you": "ನೀವು", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "ನೀವು" } diff --git a/_locales/ko/messages.json b/_locales/ko/messages.json index 5ffa9a9d9..5f8e84900 100644 --- a/_locales/ko/messages.json +++ b/_locales/ko/messages.json @@ -56,12 +56,14 @@ "appIconEnableIconAndName": "대체 앱 아이콘 및 이름 사용", "appIconSelect": "대체 앱 아이콘을 선택", "appIconSelectionTitle": "아이콘", + "appName": "Session", "appNameCalculator": "계산기", "appNameMeetingSE": "미팅", "appNameNews": "뉴스", "appNameNotes": "노트", "appNameStocks": "주식", "appNameWeather": "날씨", + "appPro": "Session Pro", "appearanceHideMenuBar": "메뉴 바 숨기기", "appearanceLanguage": "언어", "appearanceLanguageDescription": "Session의 언어 설정을 선택하십시오. 언어 설정을 변경하면 Session이 재시작됩니다.", @@ -179,7 +181,6 @@ "callsSettings": "통화 (베타)", "callsVoiceAndVideo": "음성 및 영상 통화", "callsVoiceAndVideoBeta": "음성 및 영상 통화 (Beta)", - "callsVoiceAndVideoModalDescription": "베타 통화를 사용하는 동안 IP가 호출 파트너와 Oxen Foundation 서버에 보입니다.", "callsVoiceAndVideoToggleDescription": "다른 사용자와 음성 및 영상 통화를 할 수 있습니다.", "callsYouCalled": "{name}님에게 전화함", "callsYouMissedCallPermissions": "{name}님으로부터 받은 전화를 놓쳤습니다. 개인 정보 설정에서 음성 및 화상 통화를 활성화하지 않았기 때문입니다.", @@ -606,6 +607,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} 음성 메시지", "messages": "메시지", "minimize": "최소화", + "networkName": "Session Network", "next": "다음", "nicknameDescription": "{name}의 닉네임을 선택하십시오. 일대일 및 그룹 채팅에서 표시됩니다.", "nicknameEnter": "닉네임을 입력하세요.", @@ -683,6 +685,7 @@ "onsErrorUnableToSearch": "이 ONS를 검색할 수 없습니다. 나중에 다시 시도해 주세요.", "open": "열기", "other": "기타", + "oxenFoundation": "Oxen Foundation", "passwordChange": "비밀번호 변경", "passwordConfirm": "비밀번호 확인", "passwordCurrentIncorrect": "현재 비밀번호가 잘못되었습니다.", @@ -815,10 +818,13 @@ "sessionAppearance": "디자인", "sessionClearData": "데이터 삭제", "sessionConversations": "대화", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "도움말", "sessionInviteAFriend": "친구 초대", "sessionMessageRequests": "메시지 요청", "sessionNetworkCurrentPrice": "현재 SESH 가격", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNetworkDescription": "메시지는 Session Network를 통해 전송됩니다. 네트워크는 Session Token으로 인센티브를 받은 노드들로 구성되며, 이 노드들은 Session을 분산되고 안전하게 유지합니다. 더 알아보기 {icon}", "sessionNetworkLearnAboutStaking": "스테이킹에 대해 알아보기", "sessionNetworkMarketCap": "시가 총액", @@ -847,6 +853,7 @@ "showLess": "간략히 보기", "showNoteToSelf": "개인용 메모 표시하기", "showNoteToSelfDescription": "개인용 메모를 대화 리스트에 표시하겠습니까?", + "stakingRewardPool": "Staking Reward Pool", "stickers": "스티커", "supportGoTo": "지원 페이지로 이동", "systemInformationDesktop": "시스템 정보: {information}", @@ -854,6 +861,8 @@ "theContinue": "계속", "theDefault": "기본값", "theError": "에러", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "다시 시도", "typingIndicators": "입력 지시자 깜박임", "typingIndicatorsDescription": "입력 중 아이콘 보고 공유.", @@ -879,6 +888,7 @@ "urlOpen": "URL 열기", "urlOpenBrowser": "이것은 당신의 브라우저에서 열립니다.", "urlOpenDescription": "이 URL을 브라우저에서 여시겠습니까?

{url}", + "usdNameShort": "USD", "useFastMode": "Fast 모드 사용하기", "video": "동영상", "videoErrorPlay": "동영상을 재생할 수 없습니다.", @@ -890,7 +900,6 @@ "warning": "경고", "window": "창", "yes": "예", - "you": "사용자", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "사용자" } diff --git a/_locales/ku/messages.json b/_locales/ku/messages.json index 91d38dc27..e626c8e53 100644 --- a/_locales/ku/messages.json +++ b/_locales/ku/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} و {other_name} بە بەڕێوەبەر هەڵبژێردران.", "andMore": "+{count}", "anonymous": "بێناونیشان", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "شارەوەی منیووبار", "appearanceLanguage": "زمان", "appearanceLanguageDescription": "Session ئەنجومەنی دەبیو بە کراوەکردنی Session بگۆڕە", @@ -151,7 +153,6 @@ "callsSettings": "پەیوەندیدانەکان (بهێڵه‌ی نوێ)", "callsVoiceAndVideo": "پەیوەندیە دەنگی و ڤیدیۆکان", "callsVoiceAndVideoBeta": "پەیوەندیە دەنگی و ڤیدیۆ (Beta)", - "callsVoiceAndVideoModalDescription": "پته‌ی IP ی تۆ بۆ شەریکەکەی تیپە و سێروێری Oxen Foundation پشت بە پشت ڕەنگە بونی بوو بێت کاتێک بەکارهێنانی بەتاکوڵ بوون بوزیەکان.", "callsVoiceAndVideoToggleDescription": "کێیشە دەنگی و ڤیدیۆ ئەو کارانە وەکدی بزانی بۆ وەڵامی دیکە بەکارهێنەران.", "callsYouCalled": "تۆ تێڵەی تەلەفۆنی کردی بۆ {name}", "callsYouMissedCallPermissions": "تۆ تێڵەیەک لە {name}ێت هەڵوتە چونکە دەسەڵاتی پەیوەندی دەنگی و ڤیدیۆ لە رێکخستنی تایبەتی دان نەبەیت.", @@ -525,6 +526,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} نامەی دەنگی", "messages": "نامەکان", "minimize": "بچووککردن", + "networkName": "Session Network", "next": "دواتر", "nicknameDescription": "نازناوەیەکی هەڵبژاردە بۆ {name}. ئەمە دەربادە بۆ کەسەکانی تاکە و گروپەکانت.", "nicknameEnter": "ناوی باوکەل بنووسە", @@ -598,6 +600,7 @@ "onsErrorUnableToSearch": "نەتوانین ئەم ONS-ە بگەڕێینەوە. تکایە دواتر هەوڵبدەرەوە.", "open": "کردنەوە", "other": "ئەوی تر", + "oxenFoundation": "Oxen Foundation", "passwordChange": "وشەی نهێنی بگۆڕە", "passwordConfirm": "پشتڕاستکردنەوەی تێپەڕوشە", "passwordCurrentIncorrect": "تێپەڕەوەی ڕاستە پەیوەندە نەدرێت.", @@ -707,9 +710,12 @@ "sessionAppearance": "نماوە", "sessionClearData": "سڕینەوەی داتا", "sessionConversations": "گفتوگۆکان", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "یارمەتی", "sessionInviteAFriend": "بانێ یارێکی پیرە", "sessionMessageRequests": "داواکارییەکانی نامە", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "ئاگادارکردنەوەکان", "sessionPermissions": "پەیامی دەبێ بەپەی دەستکرد", "sessionPrivacy": "پاراستن", @@ -725,12 +731,15 @@ "show": "پیشان دان بەز.", "showAll": "کۆیە Superior.", "showLess": "P.J. بەمەکەھەرانە.", + "stakingRewardPool": "Staking Reward Pool", "stickers": "ستیکەران", "supportGoTo": "بڕۆ بۆ ڕێکەوتکردنی پشتگیری", "systemInformationDesktop": "زانیاریەکانی سیستەم: {information}", "theContinue": "بەردەوام بوون", "theDefault": "بنەڕەتی", "theError": "هەڵە", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "دوبارە هەوڵبدە", "typingIndicators": "نییه‌کانى تایبەت", "typingIndicatorsDescription": "ببینە و هاوبەش بن تایبەتمەندیەکانی نووسین.", @@ -750,6 +759,7 @@ "urlOpen": "کردنەوەی بەستەر", "urlOpenBrowser": "ئەمە بە فەرمی لە کەناڵەکانی سەیر بەلێنە.", "urlOpenDescription": "دڵنیایت دەتەوێت ئەم URLـە بکەیتەوە لە بڕاوسەڕەکەت.

{url}", + "usdNameShort": "USD", "useFastMode": "بەکارھێنانی Fast Mode", "video": "ڤیدیۆ", "videoErrorPlay": "نەیتوانرێت کار بە ڤیدیۆ بکرێت.", @@ -759,7 +769,6 @@ "warning": "ئاگاداری", "window": "پەنجەرە", "yes": "بەڵێ", - "you": "تۆ", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "تۆ" } diff --git a/_locales/lg/messages.json b/_locales/lg/messages.json index 28457acc0..827e04702 100644 --- a/_locales/lg/messages.json +++ b/_locales/lg/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} ne {other_name} baakyusibwa okufuuka Admin.", "andMore": "+{count}", "anonymous": "Tekimanyiddwa", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Kweka Menu Bar", "appearanceLanguage": "Lungirira Olulimi", "appearanceLanguageDescription": "Choose your language setting for Session. Session will restart when you change your language setting.", @@ -150,7 +152,6 @@ "callsSettings": "Calls (Beta)", "callsVoiceAndVideo": "Emmboozi ne Bidiyo Bye Werezebwa", "callsVoiceAndVideoBeta": "Emmboozi ne Bidiyo Bye Werezebwa (Beta)", - "callsVoiceAndVideoModalDescription": "IP yo efulugettaka mu mateeka ne server ya Oxen Foundation nga okozeza omitting ekikugya ekiriotto.", "callsVoiceAndVideoToggleDescription": "Emidduka n’ebitambise okubira no okuva eri abakozesa abalala.", "callsYouCalled": "Weegambye {name}", "callsYouMissedCallPermissions": "Wanakuba omulilwana {name} kubanga tomeka meka Okubagaane Kw'amakowala n'amacapa mu Settings za Privacy.", @@ -524,6 +525,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Obubaka Obw'eddoboozi", "messages": "Obubaka", "minimize": "Nyeendazo", + "networkName": "Session Network", "next": "Ojikulembaza", "nicknameDescription": "Londa nickname eri {name}. Eno ejja okulabika mu kukozesa emboozi emwenna.", "nicknameEnter": "Yingiza erinnya", @@ -597,6 +599,7 @@ "onsErrorUnableToSearch": "Tetulabiddwenga ku nfuuna gya ONS eno. Mwanguyiza mugikoleko nate.", "open": "Bikkule", "other": "Ebirala", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Change Password", "passwordConfirm": "Kakasa akakufulu", "passwordCurrentIncorrect": "Password Kyo kiri mu nsobi.", @@ -705,9 +708,12 @@ "sessionAppearance": "Okulabika", "sessionClearData": "Jjamu Ebyetaago", "sessionConversations": "Okwekeneenya", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Okuyamba", "sessionInviteAFriend": "Kuyita enjuuyi", "sessionMessageRequests": "Okikusa ekizamanyo", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Okufuna Okutegeera", "sessionPermissions": "Obusobozi", "sessionPrivacy": "Katibako n’ekizindalo", @@ -723,12 +729,15 @@ "show": "Laga", "showAll": "Laga Byonna", "showLess": "Laga Kitono", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Eziteekebwaawo", "supportGoTo": "Genda ku Page ya Support", "systemInformationDesktop": "Akabuuze Akankeesi: {information}", "theContinue": "Komekkereza", "theDefault": "Enkola", "theError": "Ensobi", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Lowooza edaako", "typingIndicators": "Engeri z'okukola okubala mu kwogera", "typingIndicatorsDescription": "Labira n'okugabana eby'okukuba amawulire.", @@ -748,6 +757,7 @@ "urlOpen": "Sumulula URL", "urlOpenBrowser": "Kino kijya kugulika mu browser ymmwe.", "urlOpenDescription": "Oli mukakafu nti oyagala okugulawo URL eno mu browser yo?

{url}", + "usdNameShort": "USD", "useFastMode": "Kozesa Mode Ey'Obwangu", "video": "Vidiyo", "videoErrorPlay": "Tekisobola kuzza vidiyo.", @@ -757,7 +767,6 @@ "warning": "Kyeɛjo", "window": "Enju", "yes": "Nedda", - "you": "Ggwe", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Ggwe" } diff --git a/_locales/lo/messages.json b/_locales/lo/messages.json index 119205bb9..496629970 100644 --- a/_locales/lo/messages.json +++ b/_locales/lo/messages.json @@ -23,6 +23,8 @@ "adminSettings": "ການຕັ້ງຄ່າຂອງ​ຜູ້ຄຸ້ມຄອງ", "adminTwoPromotedToAdmin": "{name} และ{other_name} ໄດ້ຮັບການເລື່ອນຊັ້ນເປັນAdmin.", "anonymous": "ບໍ່ຮູ້ຈັກ", + "appName": "Session", + "appPro": "Session Pro", "appearanceLanguageDescription": "ເລືອກຕັ້ງຄ່າພາສາຂອງທ່ານສຳຫຼັບ Session. Session ຈະຟື້ນຄືນໃໝ່ເມື່ອທ່ານປ່ຽນຕັ້ງຄ່າພາສາ.", "appearanceThemesClassicDark": "Classic Dark", "appearanceThemesClassicLight": "ຄລາສສິກແສງ", @@ -167,6 +169,7 @@ "errorCopyAndQuit": "ເສັກກີ້າບເອີເທິ່ນຫຍັງາ", "errorDatabase": "ຂໍ້ມູນຂອງຖານຂໍ້ມູນຜິດພາດ", "errorUnknown": "ມີຄວາມຜິດພາດທີ່ບໍ່ແມ່ນທີີ່ຮູ້ຈັກເກີດຂຶ້ນ.", + "gif": "GIF", "giphyWarningDescription": "Session ຊື່ທີ່ຊົງກັບ Giphy ເພື່ອໃຫ້ຜະລິດຕອບປະສົດຜ້ອນ. ເຈົ້າຈະບໍ່ມີການປ້ອງກັນ metadata ທີ່ສົມບູນເມື່ອສົ່ງ GIFs.", "groupCreate": "ເກີນໄວນຳເກາບພາຍ", "groupDelete": "ລຶບກຸ່ມ", @@ -205,6 +208,7 @@ "messageRequestsCommunitiesDescription": "ໃຫ້ການຮັບຄຳຂໍຂ່ອງການສົ່ງຂໍ້ຄວາມໃນ Community.", "messageRequestsDelete": "ທ່ານແນ່ໃຈບໍ່ວ່າທ່ານຕ້ອງການລຶບ message request นี้?", "messageRequestsTurnedOff": "{name} has message requests from Community conversations turned off, so you cannot send them a message.", + "networkName": "Session Network", "nicknameEnter": "ປ້ອນຊື່ທີ່ໃຊ້ເທບ", "noteToSelfHideDescription": "ທ່ານແນ່ໃຈບໍ່ວ່າທ່ານຕ້ອງການລຶບ Note to Self?", "notificationsAllMessages": "ຂໍ້ຄວາມທັງໝົດ", @@ -219,6 +223,7 @@ "onionRoutingPathDescription": "Session ປິດບັງທີ່ຢູ່ IP ຂອງທ່ານໂດຍຜ່ານຂໍ້ຄວາມຂອງທ່ານຜ່ານ Service Node ຫລາຍໜ່ວຍຂ່າຍໃນ Session ເປັນຮູບແບບຂອງຂ່າຍອິດສະຫລະ. ນີ້ແມ່ນເສັ້ນທາງປັດຈຸບັນຂອງທ່ານ:", "onionRoutingPathDestination": "ຈຸດໝາຍ", "onionRoutingPathEntryNode": "ເນົດເຂົ້າ", + "oxenFoundation": "Oxen Foundation", "passwordChange": "ປ່ຽນລະຫັດຜ່ານ", "passwordConfirm": "ຢັນໄຮ", "passwordEnter": "ປ້ອນລະຫັດຜ່ານ", @@ -237,15 +242,21 @@ "sessionAppearance": "ຮູບລັກສະນະ", "sessionClearData": "ລ້າງເວດຂໍ້ມູນ", "sessionConversations": "ຫຼາຍເເລກ", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", + "stakingRewardPool": "Staking Reward Pool", "theContinue": "ເຂົ້າໄປ", "theDefault": "ການຕັ້ງຕົ້ນ", "theError": "ມີຂໍ້ຜິດພາດ", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "updateApp": "ອັບເດດແອັບພລິເຄຊັນ", "updateDownloading": "ກຳລັງດາວໂຫລດການປັບປຸງ: {percent_loader}%", "updateError": "ບໍ່ສາມາດອັບເດດໄດ້", "updateNewVersion": "ວິທີໃຫມ່ຂອງ Session ມີໃຫ້, ກົດເພື່ອອັບເດດ", "updateSession": "ອັບເດດ Session", "urlCopy": "ເສັກກີ້າບເອີຢ໇ລໍ້າ", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "usdNameShort": "USD" } diff --git a/_locales/lt/messages.json b/_locales/lt/messages.json index 12e808574..46d685ba2 100644 --- a/_locales/lt/messages.json +++ b/_locales/lt/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} ir {other_name} buvo paskirti adminais.", "andMore": "+{count}", "anonymous": "Anonymous", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Paslėpti meniu juostą", "appearanceLanguage": "Kalba", "appearanceLanguageDescription": "Pasirinkite kalbos nustatymus programėlei Session. Programėlė Session bus paleista iš naujo, kai pakeisite kalbos nustatymus.", @@ -150,7 +152,6 @@ "callsSettings": "Skambučiai (Beta)", "callsVoiceAndVideo": "Balso ir vaizdo skambučiai", "callsVoiceAndVideoBeta": "Balso ir vaizdo skambučiai (Beta)", - "callsVoiceAndVideoModalDescription": "Naudojant beta skambučius, jūsų IP adresas matomas jūsų pašnekovui ir Oxen Foundation serveriui.", "callsVoiceAndVideoToggleDescription": "Įgalina balso ir vaizdo skambučius į ir iš kitų vartotojų.", "callsYouCalled": "Jūs skambinote {name}", "callsYouMissedCallPermissions": "Praleidote skambutį iš {name}, nes Privatumo nustatymuose neįjungėte Balso ir Vaizdo Skambučių.", @@ -526,6 +527,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} balso žinutė", "messages": "Žinutės", "minimize": "Suskleisti", + "networkName": "Session Network", "next": "Kitas", "nicknameDescription": "Pasirinkite slapyvardį {name}. Jis bus matomas jums pokalbiuose vienas prieš vieną ir grupinėse diskusijose.", "nicknameEnter": "Įveskite slapyvardį", @@ -600,6 +602,7 @@ "onsErrorUnableToSearch": "Nepavyko ieškoti šio ONS. Bandykite dar kartą vėliau.", "open": "Atverti", "other": "Kitas", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Keisti slaptažodį", "passwordConfirm": "Patvirtinkite slaptažodį", "passwordCurrentIncorrect": "Jūsų dabartinis slaptažodis yra neteisingas.", @@ -708,9 +711,12 @@ "sessionAppearance": "Išvaizda", "sessionClearData": "Išvalyti duomenis", "sessionConversations": "Pokalbiai", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Pagalba", "sessionInviteAFriend": "Pakviesti draugą", "sessionMessageRequests": "Message Requests", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Pranešimai", "sessionPermissions": "Leidimai", "sessionPrivacy": "Privatumas", @@ -726,12 +732,15 @@ "show": "Rodyti", "showAll": "Rodyti visus", "showLess": "Rodyti mažiau", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Paveiksliukai", "supportGoTo": "Pereiti į palaikymo puslapį", "systemInformationDesktop": "Sistemos informacija: {information}", "theContinue": "Tęsti", "theDefault": "Numatytoji", "theError": "Klaida", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Bandykite dar kartą", "typingIndicators": "Rašymo indikatoriai", "typingIndicatorsDescription": "Matyti ir dalintis rašymo indikatoriais.", @@ -751,6 +760,7 @@ "urlOpen": "Atverti URL nuorodą", "urlOpenBrowser": "Tai atidarys jūsų naršyklėje.", "urlOpenDescription": "Ar tikrai norite atverti šią URL nuorodą naršyklėje?

{url}", + "usdNameShort": "USD", "useFastMode": "Naudoti greitą veikseną", "video": "Vaizdo įrašas", "videoErrorPlay": "Nepavyksta paleisti vaizdo įrašo.", @@ -760,7 +770,6 @@ "warning": "Įspėjimas", "window": "Langas", "yes": "Taip", - "you": "Jūs", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Jūs" } diff --git a/_locales/lv/messages.json b/_locales/lv/messages.json index bd8ce1274..1fa58ed9b 100644 --- a/_locales/lv/messages.json +++ b/_locales/lv/messages.json @@ -35,6 +35,8 @@ "adminTwoPromotedToAdmin": "{name} un {other_name} tika paaugstināti par administrētāju.", "andMore": "+{count}", "anonymous": "Anonīms", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Slēpt izvēlnes joslu", "appearanceLanguage": "Valoda", "appearanceLanguageDescription": "Izvēlieties valodu uzstādījumus Session. Session restartēsies, kad mainīsiet valodas uzstādījumus.", @@ -144,7 +146,6 @@ "callsSettings": "Zvani (Beta)", "callsVoiceAndVideo": "Balss un video zvani", "callsVoiceAndVideoBeta": "Balss un video zvani (Beta)", - "callsVoiceAndVideoModalDescription": "Izmantojot beta zvanus, jūsu IP ir redzams jūsu zvana partnerim un Oxen Foundation serverim.", "callsVoiceAndVideoToggleDescription": "Iespējot balss un video zvanus uz un no citiem lietotājiem.", "callsYouCalled": "Jūs zvanījāt {name}", "callsYouMissedCallPermissions": "Jūs nokavējāt zvanu no {name}, jo jums nav iespējoti Balss un video zvani privātuma iestatījumos.", @@ -487,6 +488,7 @@ "messageVoiceSlideToCancel": "Velc, lai atceltu", "messages": "Ziņojumi", "minimize": "Minimizēt", + "networkName": "Session Network", "next": "Nākamais", "nicknameDescription": "Izvēlieties segvārdu {name}. Tas parādīsies jums vienā pret vienu un grupu sarunās.", "nicknameEnter": "Ievadiet segvārdu", @@ -556,6 +558,7 @@ "onsErrorUnableToSearch": "Mēs nevarējām meklēt šo ONS. Lūdzu, mēģiniet vēlreiz vēlāk.", "open": "Atvērt", "other": "Cits", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Mainīt paroli", "passwordConfirm": "Apstipriniet paroli", "passwordCurrentIncorrect": "Jūsu pašreizējā parole ir nepareiza.", @@ -659,9 +662,12 @@ "sessionAppearance": "Izskats", "sessionClearData": "Izdzēst datus", "sessionConversations": "Sarakstes", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Palīdzība", "sessionInviteAFriend": "Uzaicināt draugu", "sessionMessageRequests": "Ziņu pieprasījumi", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Paziņojumi", "sessionPermissions": "Atļaujas", "sessionPrivacy": "Privātums", @@ -677,11 +683,14 @@ "show": "Parādīt", "showAll": "Parādīt Visus", "showLess": "Parādīt mazāk", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Uzlīmes", "supportGoTo": "Iet uz atbalsta lapu", "theContinue": "Turpināt", "theDefault": "Noklusējums", "theError": "Kļūda", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Mēģiniet vēlreiz", "typingIndicators": "Rakstīšanas indikatori", "typingIndicatorsDescription": "Redzēt un dalīties ar rakstīšanas indikatoriem.", @@ -701,6 +710,7 @@ "urlOpen": "Atvērt URL", "urlOpenBrowser": "Tas tiks atvērts tavam pārlūkā.", "urlOpenDescription": "Vai esat pārliecināts, ka vēlaties atvērt šo URL savā pārlūkprogrammā?

{url}", + "usdNameShort": "USD", "useFastMode": "Lietot ātro režīmu", "video": "Video", "videoErrorPlay": "Nevar atskaņot video.", @@ -710,7 +720,6 @@ "warning": "Brīdinājums", "window": "Logs", "yes": "Jā", - "you": "Jūs", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Jūs" } diff --git a/_locales/mk/messages.json b/_locales/mk/messages.json index f25b67dbe..6c57d518f 100644 --- a/_locales/mk/messages.json +++ b/_locales/mk/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} и {other_name} беа промовирани во Админ.", "andMore": "+{count}", "anonymous": "Анонимен", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Сокриј мени бар", "appearanceLanguage": "Јазик", "appearanceLanguageDescription": "Изберете го јазичното поставување за Session. Session ќе се рестартира кога ќе ги промените јазичните поставувања.", @@ -150,7 +152,6 @@ "callsSettings": "Повици (Бета)", "callsVoiceAndVideo": "Гласовни и видео повици", "callsVoiceAndVideoBeta": "Гласовни и видео повици (Beta)", - "callsVoiceAndVideoModalDescription": "Вашето IP е видливо за вашиот партнер за повик и серверот на Oxen Foundation додека користите бета повици.", "callsVoiceAndVideoToggleDescription": "Овозможува гласовни и видео повици до и од други корисници.", "callsYouCalled": "Го повикавте {name}", "callsYouMissedCallPermissions": "Пропуштивте повик од {name} бидејќи немате овозможено Гласовни и Видео повици во Поставки на приватност.", @@ -524,6 +525,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Гласовна порака", "messages": "Пораки", "minimize": "Минимизирај", + "networkName": "Session Network", "next": "Следно", "nicknameDescription": "Изберете прекар за {name}. Овој ќе се појавува во едностраните и групните разговори.", "nicknameEnter": "Внесете прекар", @@ -597,6 +599,7 @@ "onsErrorUnableToSearch": "Не можевме да пребаруваме за овој ОНС. Ве молиме обидете се повторно подоцна.", "open": "Отвори", "other": "Други", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Смени лозинка", "passwordConfirm": "Потврди лозинка", "passwordCurrentIncorrect": "Вашата тековна лозинка е неточна.", @@ -705,9 +708,12 @@ "sessionAppearance": "Изглед", "sessionClearData": "Исчисти ги податоците", "sessionConversations": "Разговори", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Помош", "sessionInviteAFriend": "Поканете Пријател", "sessionMessageRequests": "Барања за пораки", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Известувања", "sessionPermissions": "Дозволи", "sessionPrivacy": "Приватност", @@ -723,12 +729,15 @@ "show": "Прикажи", "showAll": "Прикажи Сè", "showLess": "Прикажи Помалку", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Стикери", "supportGoTo": "Оди до страницата за поддршка", "systemInformationDesktop": "Информации за систем: {information}", "theContinue": "Продолжи", "theDefault": "Стандарден", "theError": "Грешка", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Обиди се повторно", "typingIndicators": "Индикатори за пишување", "typingIndicatorsDescription": "Види и сподели индикатори за пишување.", @@ -748,6 +757,7 @@ "urlOpen": "Отвори URL", "urlOpenBrowser": "Ова ќе се отвори во вашиот прелистувач.", "urlOpenDescription": "Дали сте сигурни дека сакате да ја отворите оваа URL адреса во вашиот прелистувач?

{url}", + "usdNameShort": "USD", "useFastMode": "Користи Fast Mode", "video": "Видео", "videoErrorPlay": "Не може да се пушти видеото.", @@ -757,7 +767,6 @@ "warning": "Предупредување", "window": "Прозорец", "yes": "Да", - "you": "Вие", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Вие" } diff --git a/_locales/mn/messages.json b/_locales/mn/messages.json index 638539508..f47bdfa20 100644 --- a/_locales/mn/messages.json +++ b/_locales/mn/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} болон {other_name} Админ боллоо.", "andMore": "+{count}", "anonymous": "Нэргүй", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Цэсний самбарыг нуух", "appearanceLanguage": "Хэл", "appearanceLanguageDescription": "Session хэлний тохиргоог сонгоно уу. Хэлний тохиргоог солих үед Session дахин ачаалагдана.", @@ -152,7 +154,6 @@ "callsSettings": "Дуудлага (Beta)", "callsVoiceAndVideo": "Дуу болон видео дуудлага", "callsVoiceAndVideoBeta": "Дуу болон видео дуудлага (Beta)", - "callsVoiceAndVideoModalDescription": "Таны IP хаягийг ярианы хамтрагч болон Oxen Foundation сервер харагдана.", "callsVoiceAndVideoToggleDescription": "Бусад хэрэглэгчдэд дуу хоолой болон видео дуудлага хийхийг идэвхжүүлнэ.", "callsYouCalled": "Та {name}-р дуудсан", "callsYouMissedCallPermissions": "Та {name}-ээс дуудлага алдаж байна, учир нь та Дуу хоолой болон видео дуудлагаг Нууцлалын Тохиргоонд идэвхжүүлээгүй байна.", @@ -534,6 +535,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Дуу Хүсэлт", "messages": "Мессежүүд", "minimize": "Багасгах", + "networkName": "Session Network", "next": "Дараагийн", "nicknameDescription": "{name}-д зориулж хоч сонгоно уу. Энэ нь таны нэг ба бүлгийн ярианд харагдах болно.", "nicknameEnter": "Нэр оруулна уу", @@ -608,6 +610,7 @@ "onsErrorUnableToSearch": "Энэ ONS-г хайж чадсангүй. Дахин оролдоорой.", "open": "Нээх", "other": "Бусад", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Нууц үг өөрчлөх", "passwordConfirm": "Нууц үгийг баталгаажуулах", "passwordCurrentIncorrect": "Таны одоогийн нууц үг буруу байна.", @@ -716,9 +719,12 @@ "sessionAppearance": "Гадаад үзэмж", "sessionClearData": "Өгөгдлийг арилгах", "sessionConversations": "Харилцан ярианууд", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Тусламж", "sessionInviteAFriend": "Найзаа урь", "sessionMessageRequests": "Мессеж хүсэлтүүд", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Мэдэгдэлүүд", "sessionPermissions": "Зөвшөөрөл", "sessionPrivacy": "Нууцлал", @@ -734,12 +740,15 @@ "show": "Харуулах", "showAll": "Бүгдийг харуулах", "showLess": "Бага харуулах", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Наадаг зурагнууд", "supportGoTo": "Дэмжлэгийн хуудсанд очих", "systemInformationDesktop": "Системийн мэдээлэл: {information}", "theContinue": "Үргэлжлүүлэх", "theDefault": "Үндсэн", "theError": "Алдаа", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Дахин оролдоно уу", "typingIndicators": "Бичиж буй индикаторууд", "typingIndicatorsDescription": "Бичих заалтуудыг үзэх, хуваалцах.", @@ -759,6 +768,7 @@ "urlOpen": "URL нээх", "urlOpenBrowser": "Энэ таны хөтөч дээр нээгдэнэ.", "urlOpenDescription": "Та энэхүү URL-г таны хөтөч дээр нээхдээ итгэлтэй байна уу?

{url}", + "usdNameShort": "USD", "useFastMode": "Хурдтай горимыг ашиглах", "video": "Видео", "videoErrorPlay": "Видео тоглуулах боломжгүй байна.", @@ -768,7 +778,6 @@ "warning": "Анхааруулга", "window": "Цонхнууд", "yes": "Тийм", - "you": "Та", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Та" } diff --git a/_locales/ms/messages.json b/_locales/ms/messages.json index d76e66783..e1fb8fda4 100644 --- a/_locales/ms/messages.json +++ b/_locales/ms/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} dan {other_name} dinaikkan ke Admin.", "andMore": "+{count}", "anonymous": "Anonymous", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Sembunyikan Bar Menu", "appearanceLanguage": "Bahasa", "appearanceLanguageDescription": "Pilih tetapan bahasa anda untuk Session. Session akan dimulakan semula apabila anda menukar tetapan bahasa anda.", @@ -152,7 +154,6 @@ "callsSettings": "Panggilan (Beta)", "callsVoiceAndVideo": "Panggilan Suara dan Video", "callsVoiceAndVideoBeta": "Panggilan Suara dan Video (Beta)", - "callsVoiceAndVideoModalDescription": "Alamat IP anda boleh dilihat oleh rakan panggilan anda dan pelayan Oxen Foundation semasa menggunakan panggilan beta.", "callsVoiceAndVideoToggleDescription": "Membolehkan panggilan suara dan video ke dan dari pengguna lain.", "callsYouCalled": "Anda memanggil {name}", "callsYouMissedCallPermissions": "Anda terlepas panggilan daripada {name} kerana anda belum mengaktifkan Panggilan Suara dan Video dalam Tetapan Privasi.", @@ -534,6 +535,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Mesej Suara", "messages": "Mesej", "minimize": "Kecilkan", + "networkName": "Session Network", "next": "Seterusnya", "nicknameDescription": "Pilih nama panggilan untuk {name}. Ini akan muncul kepada anda dalam perbualan satu-satu dan kumpulan anda.", "nicknameEnter": "Masukkan nama samaran", @@ -608,6 +610,7 @@ "onsErrorUnableToSearch": "Kami tidak dapat mencari ONS ini. Sila cuba lagi kemudian.", "open": "Buka", "other": "Lain-lain", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Tukar Kata Laluan", "passwordConfirm": "Sahkan kata laluan", "passwordCurrentIncorrect": "Kata laluan semasa anda tidak betul.", @@ -716,9 +719,12 @@ "sessionAppearance": "Penampilan", "sessionClearData": "Kosongkan Data", "sessionConversations": "Perbualan", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Bantuan", "sessionInviteAFriend": "Jemput Rakan", "sessionMessageRequests": "Permintaan Mesej", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Pemberitahuan", "sessionPermissions": "Kebenaran", "sessionPrivacy": "Privasi", @@ -734,12 +740,15 @@ "show": "Paparkan", "showAll": "Paparkan Semua", "showLess": "Paparkan Kurang", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Pelekat", "supportGoTo": "Pergi ke Laman Sokongan", "systemInformationDesktop": "Maklumat Sistem: {information}", "theContinue": "Teruskan", "theDefault": "Lalai", "theError": "Ralat", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Cuba Lagi", "typingIndicators": "Indikator Taip", "typingIndicatorsDescription": "Lihat dan kongsi petunjuk menaip.", @@ -759,6 +768,7 @@ "urlOpen": "Buka URL", "urlOpenBrowser": "Ini akan dibuka dalam pelayar anda.", "urlOpenDescription": "Adakah anda yakin anda mahu membuka URL ini dalam pelayar anda?

{url}", + "usdNameShort": "USD", "useFastMode": "Guna Fast Mode", "video": "Video", "videoErrorPlay": "Tidak dapat memainkan video.", @@ -768,7 +778,6 @@ "warning": "Amaran", "window": "Tetingkap", "yes": "Ya", - "you": "Anda", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Anda" } diff --git a/_locales/my/messages.json b/_locales/my/messages.json index 86b5bea11..ea407a710 100644 --- a/_locales/my/messages.json +++ b/_locales/my/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} နှင့် {other_name} အုပ်ချုပ်ရေးမှူး အဖြစ်တိုးတက်လာသည်။", "andMore": "+{count}", "anonymous": "အမည်မသိ", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Hide Menu Bar", "appearanceLanguage": "ဘာသာစကား", "appearanceLanguageDescription": "Session ၏ ဘာသာစကား ဆက်တင် ရွေးချယ်ပါ။ ဘာသာစကား ဆက်တင်ပြောင်းလဲပါက Session သည် ပြန်စမည်", @@ -150,7 +152,6 @@ "callsSettings": "ခေါ်ဆိုမှု(Beta)", "callsVoiceAndVideo": "အသံနှင့်ဗီဒီယိုကော", "callsVoiceAndVideoBeta": "အသံနှင့်ဗီဒီယိုကော (Beta)", - "callsVoiceAndVideoModalDescription": "သင့် IP ကို ဖုန်းခေါ်စဉ်တွင် သင်၏ ချိန်းညွှန်းပါတနာများနှင့် Oxen Foundation ဆာဗာကို မြင်ရပါသည်။", "callsVoiceAndVideoToggleDescription": "အသုံးပြုသူများနှင့် အလွယ်တကူ အသံ ဖွင့်ခြင်းနှင့် ဗီဒီယိုခေါ်သည်", "callsYouCalled": "You called {name}", "callsYouMissedCallPermissions": "သင်သည် {name} ၏ ဖုန်းခေါ်ဆိုမှုကို လက်မခံနိုင်ပါနှင့်၊ သို့သော် သင် နှင့် ဖုန်းခေါ်မှု ဖွင့်ထားသော Voice and Video Calls ကို စနစ်ပြင်ဆင်မှုများတွင် ဖွင့်ထားလိုက်ပါ။", @@ -524,6 +525,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} အသံမက်ဆေ့ခ်ျ", "messages": "မက်ဆေ့ချ်များ", "minimize": "စားဝိုင်းမှနေပါတယ်", + "networkName": "Session Network", "next": "ရှေ့သို့", "nicknameDescription": "{name} အတွက် အမည်ဖြစ်စေမည် ထည့်ပါ။ ဤအမည်သည် သင်၏ တစ်ဦးနှင့်တစ်ဦးနှင့် အဖွဲ့စကားပြောမှုများတွင် ပြသမည်ဖြစ်သည်။", "nicknameEnter": "အမည်ပြကွက် မျက်နှာပြင်ထည့်ပါ", @@ -597,6 +599,7 @@ "onsErrorUnableToSearch": "We were unable to search for this ONS. Please try again later.", "open": "ဖွင့်", "other": "အခြား", + "oxenFoundation": "Oxen Foundation", "passwordChange": "လျှို့ဝှက် စကားဝှက် ပြောင်းပါ", "passwordConfirm": "စကားဝှက်ကို အတည်ပြုပါ", "passwordCurrentIncorrect": "သင့်လက်ရှိ စကားဝှက် မှား နေပါသည်။", @@ -705,9 +708,12 @@ "sessionAppearance": "အသွင်အပြင်", "sessionClearData": "ဒေတာများကို ရှင်းလင်းပါ", "sessionConversations": "စကားပြောဆိုမှုများ", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "အကူအညီ", "sessionInviteAFriend": "သူငယ်ချင်းတစ်ဦးကို ဖိတ်ကြားပါ", "sessionMessageRequests": "သင်သည် မက်ဆေ့ချ်လဒ်များ", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "အသိပေးချက်များ", "sessionPermissions": "ခွင့်ပြုချက်များ", "sessionPrivacy": "ကိုယ်ရေးလုံခြုံမှု", @@ -723,12 +729,15 @@ "show": "ပြပါ", "showAll": "အပြည့်အဝ ပြပါ", "showLess": "နည်းနည်းပြမယ်", + "stakingRewardPool": "Staking Reward Pool", "stickers": "စတစ်ကာများ", "supportGoTo": "ပံ့ပိုးမှုပေါ်မှာသွားပါ", "systemInformationDesktop": "စနစ်အချက်အလက်: {information}", "theContinue": "ဆက်လုပ်မည်", "theDefault": "ပုံသေ", "theError": "အမှား", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "ပြန်ကြိုးစားပါလိုအပ်သည်။", "typingIndicators": "စာရိုက်နေသည်ကို ပြထားမှုများ", "typingIndicatorsDescription": "စာရိုက်နေကြောင်းပြသောအချက်ပြများကို ကြည့်ပြီး ဝေမျှပါ", @@ -748,6 +757,7 @@ "urlOpen": "URL ဖွင့်ရန်", "urlOpenBrowser": "ဤသည် သင့် ဘရောက်ဇာတွင် ဖွင့်ပါမည်။", "urlOpenDescription": "ဤ URL ကို သင့်ဘရာ့ဇာတွင် ဖွင့်လိုသည်မှာ သေချာပါသလား?

{url}", + "usdNameShort": "USD", "useFastMode": "အမြန်မုဒ်ကို သုံးပါ", "video": "ဗီဒီယို", "videoErrorPlay": "ဗီဒီယိုဖွင့်၍မရနိုင်ပါ။", @@ -757,7 +767,6 @@ "warning": "Warning", "window": "Window", "yes": "ဟုတ်ကဲ့", - "you": "သင်", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "သင်" } diff --git a/_locales/nb/messages.json b/_locales/nb/messages.json index 06f9fbb04..d4c932a3e 100644 --- a/_locales/nb/messages.json +++ b/_locales/nb/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} og {other_name} ble forfremmet til Admin.", "andMore": "+{count}", "anonymous": "Anonym", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Skjul menylinjen", "appearanceLanguage": "Språk", "appearanceLanguageDescription": "Velg språkinnstilling for Session. Session vil starte på nytt når du endrer språkinnstillingen.", @@ -151,7 +153,6 @@ "callsSettings": "Samtaler (Beta)", "callsVoiceAndVideo": "Lyd- og videosamtaler", "callsVoiceAndVideoBeta": "Lyd- og videosamtaler (Beta)", - "callsVoiceAndVideoModalDescription": "IP-adressen din er synlig for samtalepartneren din og en Oxen Foundation-server mens du bruker betasamtaler.", "callsVoiceAndVideoToggleDescription": "Aktiverer tale- og videosamtaler til og fra andre brukere.", "callsYouCalled": "Du ringte {name}", "callsYouMissedCallPermissions": "Du gikk glipp av en samtale fra {name} fordi du ikke har aktivert Tal & Video-samtaler i Personverninnstillingene.", @@ -527,6 +528,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Talemelding", "messages": "Meldinger", "minimize": "Minimer", + "networkName": "Session Network", "next": "Neste", "nicknameDescription": "Velg et kallenavn for {name}. Dette vil vises for deg i dine en-til-en og gruppekonversasjoner.", "nicknameEnter": "Skriv inn et kallenavn", @@ -600,6 +602,7 @@ "onsErrorUnableToSearch": "Vi klarte ikke å søke etter denne ONS. Vennligst prøv igjen senere.", "open": "Åpne", "other": "Annet", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Forandre passord", "passwordConfirm": "Bekreft passordet", "passwordCurrentIncorrect": "Ditt nåværende passord er feil.", @@ -709,9 +712,12 @@ "sessionAppearance": "Utseende", "sessionClearData": "Fjern data", "sessionConversations": "Samtaler", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Hjelp", "sessionInviteAFriend": "Inviter en venn", "sessionMessageRequests": "Meldingsforespørsler", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Varsler", "sessionPermissions": "Tillatelser", "sessionPrivacy": "Personvern", @@ -727,12 +733,15 @@ "show": "Vis", "showAll": "Vis alle", "showLess": "Vis færre", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Klistremerker", "supportGoTo": "Gå til støttesiden", "systemInformationDesktop": "Systeminformasjon: {information}", "theContinue": "Fortsett", "theDefault": "Forvalgt", "theError": "Feil", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Prøv igjen", "typingIndicators": "Skriver indikatorer", "typingIndicatorsDescription": "Se og del skriveindikatorer.", @@ -752,6 +761,7 @@ "urlOpen": "Åpne URL", "urlOpenBrowser": "Dette vil åpne i nettleseren din.", "urlOpenDescription": "Er du sikker på at du vil åpne denne URL-en i nettleseren din?

{url}", + "usdNameShort": "USD", "useFastMode": "Bruk rask modus", "video": "Video", "videoErrorPlay": "Kan ikke spille av video.", @@ -761,7 +771,6 @@ "warning": "Advarsel", "window": "Vindu", "yes": "Ja", - "you": "Du", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Du" } diff --git a/_locales/ne/messages.json b/_locales/ne/messages.json index d0407b98a..8292d5bef 100644 --- a/_locales/ne/messages.json +++ b/_locales/ne/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name}{other_name}लाई Admin मा बढुवा गरियो।.", "andMore": "+{count}", "anonymous": "गुमनाम", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "मेनु बार लुकाउनुहोस्", "appearanceLanguage": "भाषा", "appearanceLanguageDescription": "Session को लागी तपाइँको भाषा सेटिङ छान्नुहोस्। तपाइँको भाषा सेटिङ परिवर्तन गर्दा Session पुनः सुरु हुनेछ।", @@ -150,7 +152,6 @@ "callsSettings": "कलहरू (बीटा)", "callsVoiceAndVideo": "भ्वाइस र भिडियो कलहरू", "callsVoiceAndVideoBeta": "भ्वाइस र भिडियो कलहरू (बीटा)", - "callsVoiceAndVideoModalDescription": "तपाईंको आइपी तपाईको कल पार्टनर र ओक्सन फाउन्डेसन सर्भरलाई बेटा कलहरू प्रयोग गर्दा देखिनेछ।", "callsVoiceAndVideoToggleDescription": "भ्वाइस र भिडियो कलहरू सक्षम गर्नुहोस् र अरू प्रयोगकर्ताहरूको लागि सक्षम गर्नुहोस्।", "callsYouCalled": "तपाईंले कल गर्नुभयो {name}", "callsYouMissedCallPermissions": "तपाईंले गोपनीयता सेटिङ्समा भ्वाइस र भिडियो कलहरू सक्षम नगर्दा {name} बाट आउने कल छुट्नुभयो।", @@ -355,7 +356,7 @@ "files": "Giphy", "from": "समूह त्रुटि", "fullScreenToggle": "पूर्ण स्क्रीन टगल गर्नुहोस्", - "gif": "समूहका सदस्यहरू", + "gif": "GIF", "giphyWarning": "Giphy", "giphyWarningDescription": "Session GIF पठाउँदा पूर्ण मेटाडेटा सुरक्षा हुनेछैन भनेर जानकारी दिन GIFy लाई जडान गर्नेछ।", "groupAddMemberMaximum": "समूहहरूको अधिकतम १०० सदस्यहरू हुन सक्छन्", @@ -522,6 +523,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} आवाज सन्देशहरू", "messages": "सन्देशहरू", "minimize": "सानो गर्नुहोस्", + "networkName": "Session Network", "next": "अर्को", "nicknameDescription": "{name}को लागी उपनाम छान्नुहोस्। यो तपाईंका एक-देखि-एक र समूह कुराकानीहरूमा तपाइँलाई देखिनेछ।", "nicknameEnter": "निकनेम प्रविष्ट गर्नुहोस्", @@ -595,6 +597,7 @@ "onsErrorUnableToSearch": "हामीले यो ONS खोज्न असमर्थ। कृपया पछि पुन: प्रयास गर्नुहोस्।", "open": "खोल्नुहोस्", "other": "अन्य", + "oxenFoundation": "Oxen Foundation", "passwordChange": "पासवर्ड परिवर्तन गर्नुहोस्", "passwordConfirm": "पासवर्ड निश्चित गर्नुहोस्", "passwordCurrentIncorrect": "तपाईंको हालको पासवर्ड सही छैन।", @@ -703,9 +706,12 @@ "sessionAppearance": "देखावट", "sessionClearData": "डाटा मेटाउनुहोस", "sessionConversations": "वार्ताहरू", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "मद्दत", "sessionInviteAFriend": "मित्रलाई निमन्त्रणा गर्नुहोस्", "sessionMessageRequests": "सन्देश अनुरोधहरू", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "सूचनाहरू", "sessionPermissions": "अनुमतिहरू", "sessionPrivacy": "गोपनीयता", @@ -721,12 +727,15 @@ "show": "देखाउनुहोस्", "showAll": "सबै देखाउनुहोस्", "showLess": "कम देखाउनुहोस्", + "stakingRewardPool": "Staking Reward Pool", "stickers": "स्टिकरहरू", "supportGoTo": "सपोर्ट पेज तिर जानुहोस्", "systemInformationDesktop": "प्रणाली जानकारी: {information}", "theContinue": "जारी राख्नुहोस्", "theDefault": "पूर्वनिर्धारित", "theError": "त्रुटि", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "पुन: प्रयास गर्नुहोस्", "typingIndicators": "टाइपिङ संकेतकहरू", "typingIndicatorsDescription": "टाइपिङ सूचकहरू देख्नुहोस् र साझेदारी गर्नुहोस्।", @@ -746,6 +755,7 @@ "urlOpen": "URL खोल्नुहोस्", "urlOpenBrowser": "यो तपाईंको ब्राउजरमा खुल्ने छ।", "urlOpenDescription": "के तपाईं यो URL आफ्नो ब्राउजरमा खोल्न निश्चित हुनुहुन्छ?

{url}", + "usdNameShort": "USD", "useFastMode": "द्रुत मोड प्रयोग गर्नुहोस्", "video": "भिडियो", "videoErrorPlay": "भिडियो प्ले गर्न असमर्थ।", @@ -755,7 +765,6 @@ "warning": "चेतावनी", "window": "सञ्झ्याल", "yes": "हो", - "you": "तपाईं", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "तपाईं" } diff --git a/_locales/nl/messages.json b/_locales/nl/messages.json index 419779c5e..f17a9626a 100644 --- a/_locales/nl/messages.json +++ b/_locales/nl/messages.json @@ -56,12 +56,14 @@ "appIconEnableIconAndName": "Alternatieve app icoon en naam gebruiken", "appIconSelect": "Alternatief app icoon selecteren", "appIconSelectionTitle": "Icoon", + "appName": "Session", "appNameCalculator": "Rekenmachine", "appNameMeetingSE": "MeetingSE", "appNameNews": "Nieuws", "appNameNotes": "Notities", "appNameStocks": "Aandelen", "appNameWeather": "Weer", + "appPro": "Session Pro", "appearanceHideMenuBar": "Menubalk verbergen", "appearanceLanguage": "Taal", "appearanceLanguageDescription": "Kies je taalinstelling voor Session. Session wordt opnieuw gestart wanneer je je taalinstelling wijzigt.", @@ -180,7 +182,6 @@ "callsSettings": "Gesprekken (Beta)", "callsVoiceAndVideo": "Spraak- en video-oproepen", "callsVoiceAndVideoBeta": "Spraak- en video-oproepen (Beta)", - "callsVoiceAndVideoModalDescription": "Uw IP is zichtbaar voor uw oproep partner en een Oxen Foundation server tijdens het gebruik van bètagesprekken.", "callsVoiceAndVideoToggleDescription": "Inschakelen van spraak- en video-oproepen naar en van andere gebruikers.", "callsYouCalled": "U belde {name}", "callsYouMissedCallPermissions": "U heeft een gemiste oproep van {name} omdat u Geluid- en Video-oproepen niet heeft ingeschakeld in Privacy-instellingen.", @@ -624,6 +625,7 @@ "modalMessageCharacterTooLongTitle": "Bericht te lang", "modalMessageTooLongDescription": "Verkort je bericht tot {limit} tekens of minder.", "modalMessageTooLongTitle": "Bericht te lang", + "networkName": "Session Network", "next": "Volgende", "nicknameDescription": "Kies een bijnaam voor {name}. Dit zal verschijnen in uw één-op-één en groepsgesprekken.", "nicknameEnter": "Bijnaam invoeren", @@ -702,6 +704,7 @@ "open": "Openen", "openSurvey": "Enquête openen", "other": "Overige", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Wachtwoord wijzigen", "passwordConfirm": "Bevestig wachtwoord", "passwordCurrentIncorrect": "Uw huidige wachtwoord is onjuist.", @@ -864,10 +867,13 @@ "sessionAppearance": "Uiterlijk", "sessionClearData": "Gegevens wissen", "sessionConversations": "Gesprekken", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Help", "sessionInviteAFriend": "Nodig een vriend uit", "sessionMessageRequests": "Berichtverzoeken", "sessionNetworkCurrentPrice": "Huidige SESH prijs", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNetworkDescription": "Berichten worden verzonden via de Session Network. Het netwerk bestaat uit nodes die bestaan uit Session Token, wat Session gedecentraliseerd en veilig houdt. Meer Informatie {icon}", "sessionNetworkLearnAboutStaking": "Leer meer over Beleggen", "sessionNetworkMarketCap": "Beurswaarde", @@ -896,6 +902,7 @@ "showLess": "Minder tonen", "showNoteToSelf": "Notitie aan mezelf tonen", "showNoteToSelfDescription": "Ben je zeker dat je Bericht aan Jezelf in je conversatie lijst wilt tonen?", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Stickers", "supportGoTo": "Ga naar ondersteuningspagina", "systemInformationDesktop": "Systeeminformatie: {information}", @@ -903,6 +910,8 @@ "theContinue": "Doorgaan", "theDefault": "Standaard", "theError": "Fout", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tooltipAccountIdVisible": "De Account ID van {name} is zichtbaar op basis van je eerdere interacties", "tooltipBlindedIdCommunities": "Geblindeerde ID's worden in Community's gebruikt om spam te verminderen en de privacy te vergroten", "tryAgain": "Probeer opnieuw", @@ -935,6 +944,7 @@ "urlOpen": "URL openen", "urlOpenBrowser": "Dit wordt in uw browser geopend.", "urlOpenDescription": "Weet u zeker dat u deze URL in uw browser wilt openen?

{url}", + "usdNameShort": "USD", "useFastMode": "Gebruik Snelle Modus", "video": "Video", "videoErrorPlay": "Kan video niet afspelen.", @@ -946,7 +956,6 @@ "warning": "Waarschuwing", "window": "Venster", "yes": "Ja", - "you": "Uw", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Uw" } diff --git a/_locales/nn/messages.json b/_locales/nn/messages.json index 311667c79..0eb88f0e3 100644 --- a/_locales/nn/messages.json +++ b/_locales/nn/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} og {other_name} vart promoterte til admin.", "andMore": "+{count}", "anonymous": "Anonym", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Skjul menylinjen", "appearanceLanguage": "Språk", "appearanceLanguageDescription": "Vel språkinstillinga di for Session. Session vil starte på nytt når du endrar språkinstillinga.", @@ -151,7 +153,6 @@ "callsSettings": "Samtaler (Beta)", "callsVoiceAndVideo": "Lyd- og videosamtaler", "callsVoiceAndVideoBeta": "Lyd- og videosamtaler (Beta)", - "callsVoiceAndVideoModalDescription": "IP-adressa di er synlig for samtalepartnaren din og ein Oxen Foundation-server mens du bruker beta-samtaler.", "callsVoiceAndVideoToggleDescription": "Aktiverer tale- og videosamtaler til og frå andre brukarar.", "callsYouCalled": "Du ringte {name}", "callsYouMissedCallPermissions": "Du missa ein samtale frå {name} fordi du ikkje har aktivert tale- og videosamtalar i personverninnstillingane.", @@ -526,6 +527,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Talemelding", "messages": "Meldingar", "minimize": "Minimer", + "networkName": "Session Network", "next": "Neste", "nicknameDescription": "Vel eit kallenamn for {name}. Dette vil visast for deg i dine 1-1 og gruppe-samtalar.", "nicknameEnter": "Skriv inn eit kallenamn", @@ -599,6 +601,7 @@ "onsErrorUnableToSearch": "Vi kunne ikkje søke opp denne ONS-en. Vennligast prøv igjen seinare.", "open": "Åpne", "other": "Annan", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Endre passord", "passwordConfirm": "Bekreft passordet", "passwordCurrentIncorrect": "Ditt nåværande passord er feil.", @@ -708,9 +711,12 @@ "sessionAppearance": "Utsjåande", "sessionClearData": "Fjern data", "sessionConversations": "Samtalar", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Hjelp", "sessionInviteAFriend": "Inviter en venn", "sessionMessageRequests": "Meldingsforespørsler", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Varsler", "sessionPermissions": "Tillatelser", "sessionPrivacy": "Personvern", @@ -726,12 +732,15 @@ "show": "Vis", "showAll": "Vis alle", "showLess": "Vis færre", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Klistremerke", "supportGoTo": "Gå til støttesiden", "systemInformationDesktop": "Systeminformasjon: {information}", "theContinue": "Hald fram", "theDefault": "Forvald", "theError": "Feil", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Prøv igjen", "typingIndicators": "Inntastingsindikatorer", "typingIndicatorsDescription": "Sjå og del tastevisning.", @@ -751,6 +760,7 @@ "urlOpen": "Åpne URL", "urlOpenBrowser": "Dette åpner i nettleseren din.", "urlOpenDescription": "Er du sikker på at du ønskjer å opne denne URL-en i nettlesaren din?

{url}", + "usdNameShort": "USD", "useFastMode": "Bruk rask modus", "video": "Video", "videoErrorPlay": "Klarte ikkje å spela av video.", @@ -760,7 +770,6 @@ "warning": "Advarsel", "window": "Vindu", "yes": "Ja", - "you": "Du", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Du" } diff --git a/_locales/no/messages.json b/_locales/no/messages.json index b6d56706b..9b051e964 100644 --- a/_locales/no/messages.json +++ b/_locales/no/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} og {other_name} ble forfremmet til Admin.", "andMore": "+{count}", "anonymous": "Anonym", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Skjul menylinjen", "appearanceLanguage": "Språk", "appearanceLanguageDescription": "Velg språket for Session. Session vil starte på nytt når du endrer språket.", @@ -151,7 +153,6 @@ "callsSettings": "Samtaler (Beta)", "callsVoiceAndVideo": "Lyd- og videosamtaler", "callsVoiceAndVideoBeta": "Lyd- og videosamtaler (Beta)", - "callsVoiceAndVideoModalDescription": "Din IP er synlig for samtalepartneren din og en Oxen Foundation-server mens du bruker beta-samtaler.", "callsVoiceAndVideoToggleDescription": "Aktiverer tale- og videosamtaler til og fra andre brukere.", "callsYouCalled": "Du ringte {name}", "callsYouMissedCallPermissions": "Du gikk glipp av en samtale fra {name} fordi du ikke har aktivert Talekall og videosamtaler i Personverninnstillinger.", @@ -526,6 +527,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Talemelding", "messages": "Meldinger", "minimize": "Minimer", + "networkName": "Session Network", "next": "Neste", "nicknameDescription": "Velg et kallenavn for {name}. Dette vil vises for deg i dine en-til-en-samtaler og gruppesamtaler.", "nicknameEnter": "Skriv inn et kallenavn", @@ -599,6 +601,7 @@ "onsErrorUnableToSearch": "Vi klarte ikke å søke etter denne ONS. Vennligst prøv igjen senere.", "open": "Åpne", "other": "Annet", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Endre passord", "passwordConfirm": "Bekreft passordet", "passwordCurrentIncorrect": "Ditt nåværende passord er feil.", @@ -708,9 +711,12 @@ "sessionAppearance": "Utseende", "sessionClearData": "Fjern data", "sessionConversations": "Samtaler", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Hjelp", "sessionInviteAFriend": "Inviter en venn", "sessionMessageRequests": "Meldingsforespørsler", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Varsler", "sessionPermissions": "Tillatelser", "sessionPrivacy": "Personvern", @@ -726,12 +732,15 @@ "show": "Vis", "showAll": "Vis alle", "showLess": "Vis mindre", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Klistremerker", "supportGoTo": "Gå til støttesiden", "systemInformationDesktop": "Systeminformasjon: {information}", "theContinue": "Fortsett", "theDefault": "Forvalgt", "theError": "Feil", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Prøv igjen", "typingIndicators": "Skriverindikatorer", "typingIndicatorsDescription": "Se og del inn indikatorer.", @@ -751,6 +760,7 @@ "urlOpen": "Åpne URL", "urlOpenBrowser": "Dette vil åpne i nettleseren din.", "urlOpenDescription": "Er du sikker på at du ønsker å åpne denne URL-en i nettleseren din?

{url}", + "usdNameShort": "USD", "useFastMode": "Bruk rask modus", "video": "Video", "videoErrorPlay": "Kan ikke spille av video.", @@ -760,7 +770,6 @@ "warning": "Advarsel", "window": "Vindu", "yes": "Ja", - "you": "Du", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Du" } diff --git a/_locales/ny/messages.json b/_locales/ny/messages.json index d6fb0ef2a..fd3df7516 100644 --- a/_locales/ny/messages.json +++ b/_locales/ny/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} ndi {other_name} akwezedwa kukhala Admin.", "andMore": "+{count}", "anonymous": "Osadziwika", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Bisa Menu Bar", "appearanceLanguage": "Luumba", "appearanceLanguageDescription": "Choose your language setting for Session. Session will restart when you change your language setting.", @@ -150,7 +152,6 @@ "callsSettings": "Calls (Beta)", "callsVoiceAndVideo": "Mayankho a Mawu ndi Makanema", "callsVoiceAndVideoBeta": "Mayankho a Mawu ndi Makanema (Beta)", - "callsVoiceAndVideoModalDescription": "IP yanu ikuwoneka kwa mnzake wanu ndi seva ya Oxen Foundation mukamagwiritsa ntchito mayitanidwe ozungulira.", "callsVoiceAndVideoToggleDescription": "Yambitsani mafoni amawu ndi makanema komanso kuchokera kwa ogwiritsa ntchito ena.", "callsYouCalled": "Mwawona {name}", "callsYouMissedCallPermissions": "Munaphonya kuyimbitsa kuchokera kwa {name}. chifukwa simunathandize Mayitidwe ndi Mavidiyo mu Zokonda Zachinsinsi.", @@ -524,6 +525,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Chakwera Chumbe Chokwama", "messages": "Umauthenga", "minimize": "Katsini", + "networkName": "Session Network", "next": "Ena", "nicknameDescription": "Choose a nickname for {name}. This will appear to you in your one-to-one and group conversations.", "nicknameEnter": "Lemberani dzina lotsogola", @@ -597,6 +599,7 @@ "onsErrorUnableToSearch": "Sitinathe kufufuza izi ONS. Chonde yesani kachiwiri pansogolo.", "open": "Amkati", "other": "Zina", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Change Password", "passwordConfirm": "Tsimikizani mawu achinsinsi", "passwordCurrentIncorrect": "Chinsinsi chanu chokhazikika sichili bwino.", @@ -705,9 +708,12 @@ "sessionAppearance": "Maonekedwe", "sessionClearData": "Pukuta Zomwe", "sessionConversations": "Zokambirana", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Thandizo", "sessionInviteAFriend": "Kayachina Wolemba", "sessionMessageRequests": "Kapebangu kachikalata", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Willachikuna", "sessionPermissions": "Zilolezo", "sessionPrivacy": "Zinsinsi", @@ -723,12 +729,15 @@ "show": "Rikuchina", "showAll": "Show All", "showLess": "Show Less", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Llutanakukuna", "supportGoTo": "Pitani ku tsamba la Thandizo", "systemInformationDesktop": "Zambiri za System: {information}", "theContinue": "Pitilizani", "theDefault": "Chakale", "theError": "Cholakwika", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Yesaninso", "typingIndicators": "Zizindikiro Zolemba", "typingIndicatorsDescription": "See and share typing indicators.", @@ -748,6 +757,7 @@ "urlOpen": "Tsegulani URL", "urlOpenBrowser": "Izi zithamangitsidwa mu osatsegulirani wanu.", "urlOpenDescription": "Mukutsimikizika kuti mukufuna kutsegula ulalo uwu mu msakatuli wanu?

{url}", + "usdNameShort": "USD", "useFastMode": "Gwiritsani Ntchito Fast Mode", "video": "Kanema", "videoErrorPlay": "Zinatheka kusewera kanema.", @@ -757,7 +767,6 @@ "warning": "Chenjezo", "window": "Zenera", "yes": "Ari", - "you": "Inu", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Inu" } diff --git a/_locales/pa/messages.json b/_locales/pa/messages.json index 2f001745c..d302ace98 100644 --- a/_locales/pa/messages.json +++ b/_locales/pa/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name}ਅਤੇ{other_name}ਨੂੰ ਪ੍ਰਸ਼ਾਸਕ ਬਣਾ ਦਿੱਤਾ ਗਿਆ ਹੈ।", "andMore": "+{count}", "anonymous": "ਗੁੰਨਾਮ", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "ਮੈਨੂ ਬਾਰ ਥੱਲੇ ਖਿਸਕਾਉ", "appearanceLanguage": "ਪੰਜਾਬੀ", "appearanceLanguageDescription": "Session ਲਈ ਆਪਣੀ ਭਾਸ਼ਾ ਸੈਟਿੰਗ ਚੁਣੋ। ਜਦੋਂ ਤੁਸੀਂ ਆਪਣੀ ਭਾਸ਼ਾ ਸੈਟਿੰਗ ਬਦਲਦੇ ਹੋ ਤਾਂ Session ਮੁੜ ਸ਼ੁਰੂ ਹੋ ਜਾਵੇਗਾ।", @@ -150,7 +152,6 @@ "callsSettings": "ਕਾਲਾਂ (ਬੇਟਾ)", "callsVoiceAndVideo": "ਆਵਾਜ਼ ਅਤੇ ਵਿਡੀਓ ਕਾਲਾਂ", "callsVoiceAndVideoBeta": "ਆਵਾਜ਼ ਅਤੇ ਵਿਡੀਓ ਕਾਲਾਂ (Beta)", - "callsVoiceAndVideoModalDescription": "ਤੁਹਾਡੀ ਕਾਲ ਦੇ ਦੌਰਾਨ ਤੁਹਾਡਾ IP ਸਹਿਯੋਗੀ ਅਤੇ ਇਕ Oxen Foundation ਸਰਵਰ ਨੂੰ ਦੇਖਾਈ ਦੇਵੇਗਾ।", "callsVoiceAndVideoToggleDescription": "ਵਾਜਬ ਧੁਨ ਅਤੇ ਵੀਡੀਓ ਕਾਲਾਂ ਨੂੰ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।", "callsYouCalled": "ਤੁਸੀਂ {name} ਨੂੰ ਕਾਲ ਕੀਤੀ", "callsYouMissedCallPermissions": "ਤੁਸੀਂ {name} ਤੋਂ ਇੱਕ ਕਾਲ ਮਿਸ ਕੀਤੀ ਹੈ ਕਿਉਂਕਿ ਤੁਹਾਨੂੰ ਆਵਾਜ਼ ਅਤੇ ਵੀਡੀਓ ਕਾਲਾਂ ਪ੍ਰਾਈਵੇਸੀ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਐਕਟੀਵੇਟ ਨਹੀਂ ਕੀਤੀਆਂ।", @@ -524,6 +525,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} ਆਵਾਜ਼ ਸੰਦੇਸ਼", "messages": "ਸੁਨੇਹੇ", "minimize": "ਘਟਾਓ", + "networkName": "Session Network", "next": "ਅਗਲਾ", "nicknameDescription": "{name} ਲਈ ਇੱਕ ਉਪਨਾਮ ਚੁਣੋ। ਇਹ ਤੁਹਾਡੀਆਂ ਇੱਕ ਤੋਂ ਇੱਕ ਅਤੇ ਸਮੂਹ ਚਰਚਾਵਾਂ ਵਿੱਚ ਤੁਹਾਨੂੰ ਦਿਸੇਗਾ।", "nicknameEnter": "ਉਪਨਾਮ ਦਰਜ ਕਰੋ", @@ -597,6 +599,7 @@ "onsErrorUnableToSearch": "ਅਸੀਂ ਇਸ ONS ਲਈ ਖੋਜ ਕਰਨ ਲਈ ਅਸਮਰੱਥ ਰਹੇ। ਕਿਰਪਾ ਕਰਕੇ ਬਾਅਦ ਵਿੱਚ ਮੁੜ ਕੋਸ਼ਿਸ਼ ਕਰੋ।", "open": "ਖੋਲ੍ਹੋ", "other": "ਹੋਰ", + "oxenFoundation": "Oxen Foundation", "passwordChange": "ਪਾਸਵਰਡ ਬਦਲੋ", "passwordConfirm": "ਪਾਸਵਰਡ ਪੁਸ਼ਟੀ ਕਰੋ", "passwordCurrentIncorrect": "ਤੁਹਾਡਾ ਮੌਜੂਦਾ ਪਾਸਵਰਡ ਗਲਤ ਹੈ।", @@ -705,9 +708,12 @@ "sessionAppearance": "ਦਿਖਾਵਟ", "sessionClearData": "ਡਾਟਾ ਸਾਫ਼ ਕਰੋ", "sessionConversations": "ਗੱਲਬਾਤਾਂ", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "ਸਹਾਇਤਾ", "sessionInviteAFriend": "ਦੋਸਤ ਨੂੰ ਬੁਲਾਓ", "sessionMessageRequests": "ਸੁਨੇਹਾ ਬੇਨਤੀ", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "ਸੂਚਨਾਵਾਂ", "sessionPermissions": "ਅਨੁਮਤੀਆਂ", "sessionPrivacy": "ਪ੍ਰਾਇਵੇਸੀ", @@ -723,12 +729,15 @@ "show": "ਸ਼ੋਅ ਕਰੋ", "showAll": "ਸਭ ਦਿਖਾਓ", "showLess": "ਘੱਟ ਦਿਖਾਓ", + "stakingRewardPool": "Staking Reward Pool", "stickers": "ਸਟਿੱਕਰਸ", "supportGoTo": "ਸਹਾਇਤਾ ਪੰਨੇ ਤੇ ਜਾਓ", "systemInformationDesktop": "ਸਿਸਟਮ ਜਾਣਕਾਰੀ: {information}", "theContinue": "ਜਾਰੀ ਰੱਖੋ", "theDefault": "ਮੂਲ", "theError": "ਗਲਤੀ", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "ਮੁੜ ਕੋਸ਼ਿਸ਼ ਕਰੋ", "typingIndicators": "ਟਾਈਪਿੰਗ ਸੂਚਕ", "typingIndicatorsDescription": "ਟਾਈਪਿੰਗ ਇੰਡਿਕੇਟਰ ਦੇਖੋ ਅਤੇ ਸਾਂਝੇ ਕਰੋ।", @@ -748,6 +757,7 @@ "urlOpen": "URL ਖੋਲ੍ਹੋ", "urlOpenBrowser": "ਇਹ ਤੁਹਾਡੇ ਬ੍ਰਾਊਜ਼ਰ ਵਿੱਚ ਖੁਲ੍ਹੇਗਾ।", "urlOpenDescription": "ਕੀ ਤੁਸੀਂ ਯਕੀਨਨ ਇਸ URL ਨੂੰ ਆਪਣੇ ਬ੍ਰਾਊਜ਼ਰ ਵਿੱਚ ਖੋਲ੍ਹਣਾ ਚਾਹੁੰਦੇ ਹੋ?

{url}", + "usdNameShort": "USD", "useFastMode": "ਫਾਸਟ ਮੋਡ ਵਰਤੋ", "video": "ਵੀਡੀਓ", "videoErrorPlay": "ਵੀਡੀਓ ਚਲਾਉਣ ਲਈ ਅਸਮਰੱਥ।", @@ -757,7 +767,6 @@ "warning": "ਚੇਤਾਵਨੀ", "window": "ਖਿੜਕੀ", "yes": "ਹਾਂ", - "you": "ਤੁਸੀਂ", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "ਤੁਸੀਂ" } diff --git a/_locales/pl/messages.json b/_locales/pl/messages.json index b5dc0148d..50eef5e96 100644 --- a/_locales/pl/messages.json +++ b/_locales/pl/messages.json @@ -56,12 +56,14 @@ "appIconEnableIconAndName": "Użyj alternatywnej ikony i nazwy aplikacji", "appIconSelect": "Wybierz alternatywną ikonę aplikacji", "appIconSelectionTitle": "Ikona", + "appName": "Session", "appNameCalculator": "Kalkulator", "appNameMeetingSE": "Spotkania", "appNameNews": "Aktualności", "appNameNotes": "Notatki", "appNameStocks": "Akcje", "appNameWeather": "Pogoda", + "appPro": "Session Pro", "appearanceHideMenuBar": "Ukryj pasek menu", "appearanceLanguage": "Język", "appearanceLanguageDescription": "Wybierz ustawienie języka dla aplikacji Session. Po zmianie ustawienia języka aplikacja Session uruchomi się ponownie.", @@ -180,7 +182,6 @@ "callsSettings": "Połączenia (Beta)", "callsVoiceAndVideo": "Połączenia głosowe i wideo", "callsVoiceAndVideoBeta": "Połączenia głosowe i wideo (beta)", - "callsVoiceAndVideoModalDescription": "Podczas korzystania z połączeń w wersji beta Twój adres IP jest widoczny dla partnera rozmowy i serwera Oxen Foundation.", "callsVoiceAndVideoToggleDescription": "Umożliwia wykonywanie połączeń głosowych i wideo do i od innych użytkowników.", "callsYouCalled": "Zadzwoniono do {name}", "callsYouMissedCallPermissions": "Nie odebrano połączenia od użytkownika {name}, ponieważ nie włączono funkcji „Połączenia głosowe i wideo” w ustawieniach prywatności.", @@ -624,6 +625,7 @@ "modalMessageCharacterTooLongTitle": "Wiadomość jest za długa", "modalMessageTooLongDescription": "Skróć wiadomość do {limit} znaków lub mniej.", "modalMessageTooLongTitle": "Wiadomość jest za długa", + "networkName": "Session Network", "next": "Następne", "nicknameDescription": "Wybierz pseudonim dla użytkownika {name}. Będzie on widoczny dla Ciebie w rozmowach prywatnych i grupowych.", "nicknameEnter": "Wprowadź pseudonim", @@ -702,6 +704,7 @@ "open": "Otwórz", "openSurvey": "Otwórz ankietę", "other": "Inne", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Zmień hasło", "passwordConfirm": "Potwierdź hasło", "passwordCurrentIncorrect": "Twoje obecne hasło jest nieprawidłowe.", @@ -864,10 +867,13 @@ "sessionAppearance": "Wygląd", "sessionClearData": "Wyczyść dane", "sessionConversations": "Konwersacje", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Pomoc", "sessionInviteAFriend": "Zaproś znajomego", "sessionMessageRequests": "Prośby o wiadomość", "sessionNetworkCurrentPrice": "Aktualna SESH cena", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNetworkDescription": "Wiadomości są wysyłane za pośrednictwem sieci Session Network. Sieć składa się z węzłów, które są motywowane tokenami Session Token, co zapewnia, że Session pozostaje zdecentralizowana i bezpieczna. Dowiedz się więcej {icon}", "sessionNetworkLearnAboutStaking": "Dowiedz się więcej o stakingu", "sessionNetworkMarketCap": "Kapitalizacja", @@ -896,6 +902,7 @@ "showLess": "Pokaż mniej", "showNoteToSelf": "Pokaż moje notatki", "showNoteToSelfDescription": "Czy na pewno chcesz wyświetlać Moje notatki na liście konwersacji?", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Naklejki", "supportGoTo": "Przejdź do strony wsparcia technicznego", "systemInformationDesktop": "Informacja systemowa: {information}", @@ -903,6 +910,8 @@ "theContinue": "Kontynuuj", "theDefault": "Domyślne", "theError": "Błąd", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tooltipAccountIdVisible": "Identyfikator konta {name} jest widoczny na podstawie wcześniejszych interakcji", "tooltipBlindedIdCommunities": "Zanonimizowane identyfikatory są używane w społecznościach w celu ograniczenia spamu i zwiększenia prywatności", "tryAgain": "Spróbuj ponownie", @@ -935,6 +944,7 @@ "urlOpen": "Otwórz adres URL", "urlOpenBrowser": "Zostanie otwarte w przeglądarce.", "urlOpenDescription": "Czy na pewno chcesz otworzyć ten adres URL w przeglądarce?

{url}", + "usdNameShort": "USD", "useFastMode": "Użyj trybu szybkiego", "video": "Wideo", "videoErrorPlay": "Nie można odtworzyć wideo.", @@ -946,7 +956,6 @@ "warning": "Uwaga", "window": "Okno", "yes": "Tak", - "you": "Ty", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Ty" } diff --git a/_locales/ps/messages.json b/_locales/ps/messages.json index a0d3a8843..741ac5d2f 100644 --- a/_locales/ps/messages.json +++ b/_locales/ps/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} او {other_name} مدیر ته وده ورکړه.", "andMore": "+{count}", "anonymous": "بې نوم", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "د مینو بار پټ کړئ", "appearanceLanguage": "ژبه", "appearanceLanguageDescription": "د Session ژبې تنظیمات غوره کړئ. Session به بیا پیل شي کله چې تاسو خپل ژبې تنظیمات بدل کړئ.", @@ -150,7 +152,6 @@ "callsSettings": "کالونه (بیټا)", "callsVoiceAndVideo": "د زوګ او ویډیو زنګونه", "callsVoiceAndVideoBeta": "زوګ او ویډیو زنګونه (Beta)", - "callsVoiceAndVideoModalDescription": "ستاسو IP ستاسو د زنګ ملګري او یو Oxen Foundation سرور ته ښکاره کیږي کله چې بیتا زنګونه کاروئ.", "callsVoiceAndVideoToggleDescription": "د نورو کاروونکو سره غږ او ویدیو زنګونه فعالوي.", "callsYouCalled": "تاسو{name}. ته زنګ ووهلو", "callsYouMissedCallPermissions": "تاسو له {name} څخه یو زنګ له لاسه ورکړی ځکه چې تاسو په محرمیت تنظیماتو کې د غږ او ویډیو زنګونه فعال نکړي.", @@ -524,6 +525,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} غږ پېغام", "messages": "پیغامونه", "minimize": "کوچنی کول", + "networkName": "Session Network", "next": "بل", "nicknameDescription": "د {name} لپاره یوه نوم وټاکئ. دا به تاسو ته په یو په یو او ډله ایزو خبرو اترو کې څرګند شي.", "nicknameEnter": "خلا کوي ولیکئ", @@ -597,6 +599,7 @@ "onsErrorUnableToSearch": "موږ د دې ONS لټولو لپاره توانمند نه شو. مهرباني وکړئ وروسته بیا هڅه وکړئ.", "open": "خلاص", "other": "نور", + "oxenFoundation": "Oxen Foundation", "passwordChange": "پاسورډ بدل کړئ", "passwordConfirm": "نښلول...", "passwordCurrentIncorrect": "ستاسو اوسنی پاسورډ غلط دی.", @@ -705,9 +708,12 @@ "sessionAppearance": "ظاهر", "sessionClearData": "معلومات له منځه یوسه", "sessionConversations": "کاپي شوی", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "مرسته", "sessionInviteAFriend": "ملګری بلنه", "sessionMessageRequests": "پیغام غوښتنې", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "اعلانونه", "sessionPermissions": "اجازې", "sessionPrivacy": "محرمیت", @@ -723,12 +729,15 @@ "show": "ښودل", "showAll": "ټول ښودل", "showLess": "کم ښودل", + "stakingRewardPool": "Staking Reward Pool", "stickers": "سټيکرونه", "supportGoTo": "د ملاتړ پاڼې ته لاړ شئ", "systemInformationDesktop": "د سیستم معلومات: {information}", "theContinue": "خبرتیا حذف شوی", "theDefault": "ډیفالټ", "theError": "تیر", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "بیا هڅه وکړه", "typingIndicators": "د تایپ شاخصونه", "typingIndicatorsDescription": "د ټایپ کولو شاخصونه وګورئ او شريک کړئ.", @@ -748,6 +757,7 @@ "urlOpen": "یو آر ایل خلاصول", "urlOpenBrowser": "دا به ستاسو په براوزر کې پرانيستل شي.", "urlOpenDescription": "آیا تاسو ډاډه یاست چې غواړئ دا URL په خپل براوزر کې خلاص کړئ؟

{url}", + "usdNameShort": "USD", "useFastMode": "ګړندۍ حالت وکاروئ", "video": "ویډیو", "videoErrorPlay": "ویډیو غږول نشي.", @@ -757,7 +767,6 @@ "warning": "خبرداری", "window": "کړکۍ", "yes": "هو", - "you": "تاسو", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "تاسو" } diff --git a/_locales/pt-BR/messages.json b/_locales/pt-BR/messages.json index 02b0c22c8..72f72ef7a 100644 --- a/_locales/pt-BR/messages.json +++ b/_locales/pt-BR/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} e {other_name} foram promovidos a Administrador.", "andMore": "+{count}", "anonymous": "Anônimo", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Ocultar Barra de Menu", "appearanceLanguage": "Língua", "appearanceLanguageDescription": "Escolha a configuração de idioma para Session. Session reiniciará quando você alterar a configuração de idioma.", @@ -152,7 +154,6 @@ "callsSettings": "Chamadas (Beta)", "callsVoiceAndVideo": "Chamadas de voz e vídeo", "callsVoiceAndVideoBeta": "Chamadas de voz e vídeo (Beta)", - "callsVoiceAndVideoModalDescription": "Seu IP estará visível para seu parceiro de chamada e para um servidor da Oxen Foundation enquanto usa chamadas beta.", "callsVoiceAndVideoToggleDescription": "Permite chamadas de voz e vídeo para e de outros usuários.", "callsYouCalled": "Você ligou para {name}", "callsYouMissedCallPermissions": "Você perdeu uma chamada de {name} porque você não ativou Chamadas de Voz e Vídeo nas Configurações de Privacidade.", @@ -535,6 +536,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Mensagem de voz", "messages": "Mensagens", "minimize": "Minimizar", + "networkName": "Session Network", "next": "Avançar", "nicknameDescription": "Escolha um apelido para {name}. Isso aparecerá para você em suas conversas individuais e em grupo.", "nicknameEnter": "Insira um apelido", @@ -609,6 +611,7 @@ "onsErrorUnableToSearch": "Não foi possível buscar este ONS. Por favor, tente novamente mais tarde.", "open": "Abrir", "other": "Outro", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Alterar Senha", "passwordConfirm": "Confirmar senha", "passwordCurrentIncorrect": "Sua senha atual está incorreta.", @@ -717,9 +720,12 @@ "sessionAppearance": "Aparência", "sessionClearData": "Limpar Dados", "sessionConversations": "Conversas", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Ajuda", "sessionInviteAFriend": "Convide um amigo", "sessionMessageRequests": "Pedidos de mensagem", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Notificações", "sessionPermissions": "Permissões", "sessionPrivacy": "Privacidade", @@ -735,12 +741,15 @@ "show": "Mostrar", "showAll": "Mostrar todas", "showLess": "Mostrar menos", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Figurinhas", "supportGoTo": "Ir para Página de Suporte", "systemInformationDesktop": "Informações do Sistema: {information}", "theContinue": "Continuar", "theDefault": "Padrão", "theError": "Erro", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Tente novamente", "typingIndicators": "Indicadores de digitação", "typingIndicatorsDescription": "Veja e compartilhe indicadores de digitação.", @@ -760,6 +769,7 @@ "urlOpen": "Abrir URL", "urlOpenBrowser": "Isso será aberto no seu navegador.", "urlOpenDescription": "Tem certeza de que deseja abrir esta URL no seu navegador?

{url}", + "usdNameShort": "USD", "useFastMode": "Usar Modo Rápido", "video": "Vídeo", "videoErrorPlay": "Não foi possível reproduzir o vídeo.", @@ -769,7 +779,6 @@ "warning": "Aviso", "window": "Janela", "yes": "Sim", - "you": "Você", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Você" } diff --git a/_locales/pt-PT/messages.json b/_locales/pt-PT/messages.json index b31311fc4..9e3dc9c37 100644 --- a/_locales/pt-PT/messages.json +++ b/_locales/pt-PT/messages.json @@ -56,12 +56,14 @@ "appIconEnableIconAndName": "Usar ícone e nome alternativos da aplicação", "appIconSelect": "Selecionar ícone alternativo da aplicação", "appIconSelectionTitle": "Ícone", + "appName": "Session", "appNameCalculator": "Calculadora", "appNameMeetingSE": "ReuniãoSE", "appNameNews": "Notícias", "appNameNotes": "Notas", "appNameStocks": "Ações", "appNameWeather": "Meteorologia", + "appPro": "Session Pro", "appearanceHideMenuBar": "Ocultar Barra de Menu", "appearanceLanguage": "Idioma", "appearanceLanguageDescription": "Escolha a configuração de idioma para Session. Session reiniciará quando alterar a configuração de idioma.", @@ -180,7 +182,6 @@ "callsSettings": "Chamadas (Beta)", "callsVoiceAndVideo": "Chamadas de Voz/Vídeo", "callsVoiceAndVideoBeta": "Chamadas de Voz/Vídeo (Beta)", - "callsVoiceAndVideoModalDescription": "O seu IP está visível para seu parceiro de chamada e para um servidor Oxen Foundation enquanto usa chamadas beta.", "callsVoiceAndVideoToggleDescription": "Permitir chamadas de voz e vídeo para e a partir de outros utilizadores.", "callsYouCalled": "Ligou para {name}", "callsYouMissedCallPermissions": "Perdeu uma chamada de {name} porque não ativou Chamadas de Voz e Vídeo nas Configurações de Privacidade.", @@ -624,6 +625,7 @@ "modalMessageCharacterTooLongTitle": "Mensagem muito longa", "modalMessageTooLongDescription": "Por favor, reduza a sua mensagem para {limit} caracteres ou menos.", "modalMessageTooLongTitle": "Mensagem muito longa", + "networkName": "Session Network", "next": "Seguinte", "nicknameDescription": "Escolha o nome de utilizador para {name}. Isto vai-lhe aparecer no seu um-para-um e conversas de grupo.", "nicknameEnter": "Introduza uma alcunha", @@ -702,6 +704,7 @@ "open": "Abrir", "openSurvey": "Abrir questionário", "other": "Outro", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Alterar Palavra-passe", "passwordConfirm": "Confirmar palavra-passe", "passwordCurrentIncorrect": "A sua palavra-passe atual está incorreta.", @@ -864,10 +867,13 @@ "sessionAppearance": "Aparência", "sessionClearData": "Limpar Dados", "sessionConversations": "Conversas", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Ajuda", "sessionInviteAFriend": "Convidar um Amigo", "sessionMessageRequests": "Pedidos de Mensagem", "sessionNetworkCurrentPrice": "Preço atual de SESH", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNetworkDescription": "As mensagens são enviadas utilizando a Session Network. A rede é composta por nós incentivados com Session Token, o que mantém o Session descentralizado e seguro. Saiba mais {icon}", "sessionNetworkLearnAboutStaking": "Saiba mais sobre Staking", "sessionNetworkMarketCap": "Capitalização de Mercado", @@ -896,6 +902,7 @@ "showLess": "Mostrar menos", "showNoteToSelf": "Mostrar Nota Pessoal", "showNoteToSelfDescription": "Tem a certeza de que pretende mostrar a Nota Pessoal na sua lista de conversas?", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Autocolantes", "supportGoTo": "Ir para a página de suporte", "systemInformationDesktop": "Informação do Sistema: {information}", @@ -903,6 +910,8 @@ "theContinue": "Continuar", "theDefault": "Pré-definição", "theError": "Erro", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tooltipAccountIdVisible": "O ID da Conta de {name} está visível com base nas suas interações anteriores", "tooltipBlindedIdCommunities": "IDs Ocultos são usados em Comunidades para reduzir spam e aumentar a privacidade", "tryAgain": "Tentar Novamente", @@ -935,6 +944,7 @@ "urlOpen": "Abrir URL", "urlOpenBrowser": "Isso abrirá no seu navegador.", "urlOpenDescription": "Tem a certeza de que quer abrir este URL no seu browser?

{url}", + "usdNameShort": "USD", "useFastMode": "Usar Modo Rápido", "video": "Vídeo", "videoErrorPlay": "Não foi possível reproduzir o vídeo.", @@ -946,7 +956,6 @@ "warning": "Aviso", "window": "Janela", "yes": "Sim", - "you": "Você", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Você" } diff --git a/_locales/ro/messages.json b/_locales/ro/messages.json index c203c8fea..fcb41bd5b 100644 --- a/_locales/ro/messages.json +++ b/_locales/ro/messages.json @@ -56,12 +56,14 @@ "appIconEnableIconAndName": "Folosește pictograma și numele alternative pentru aplicație", "appIconSelect": "Selectează o pictogramă alternativă pentru aplicație", "appIconSelectionTitle": "Pictogramă", + "appName": "Session", "appNameCalculator": "Calculator", "appNameMeetingSE": "MeetingSE", "appNameNews": "Știri", "appNameNotes": "Note", "appNameStocks": "Acțiuni", "appNameWeather": "Vremea", + "appPro": "Session Pro", "appearanceHideMenuBar": "Ascunde bara de meniu", "appearanceLanguage": "Limba", "appearanceLanguageDescription": "Alegeți setarea limbii pentru Session. Session se va reporni atunci când schimbați setarea limbii.", @@ -180,7 +182,6 @@ "callsSettings": "Apeluri (Beta)", "callsVoiceAndVideo": "Apeluri vocale și video", "callsVoiceAndVideoBeta": "Apeluri vocale și video (Beta)", - "callsVoiceAndVideoModalDescription": "IP-ul dumneavoastră este vizibil către partenerul de apel și către un server al Oxen Foundation atunci când utilizați apeluri beta.", "callsVoiceAndVideoToggleDescription": "Activează apelurile vocale și video către și de la alți utilizatori.", "callsYouCalled": "Ai apelat pe {name}", "callsYouMissedCallPermissions": "Ai ratat un apel de la {name} pentru că nu ai activat Apeluri vocale și video în setările de confidențialitate.", @@ -624,6 +625,7 @@ "modalMessageCharacterTooLongTitle": "Mesaj prea lung", "modalMessageTooLongDescription": "Te rugăm să scurtezi mesajul la {limit} caractere sau mai puțin.", "modalMessageTooLongTitle": "Mesaj prea lung", + "networkName": "Session Network", "next": "Următorul", "nicknameDescription": "Alege un pseudonim pentru {name}. Acesta va apărea în conversațiile individuale și de grup.", "nicknameEnter": "Introduceți pseudonimul dorit", @@ -702,6 +704,7 @@ "open": "Deschide", "openSurvey": "Deschide sondajul", "other": "Altele", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Schimbã Parola", "passwordConfirm": "Confirmă parola", "passwordCurrentIncorrect": "Parola actuală este incorectă.", @@ -864,10 +867,13 @@ "sessionAppearance": "Aspect", "sessionClearData": "Șterge datele", "sessionConversations": "Conversații", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Ajutor", "sessionInviteAFriend": "Invită un prieten", "sessionMessageRequests": "Solicitări de mesaje", "sessionNetworkCurrentPrice": "Preț curent SESH", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNetworkDescription": "Mesajele sunt trimise folosind Session Network. Rețeaua este alcătuită din noduri stimulate cu Session Token, ceea ce menține Session descentralizat și sigur. Informații suplimentare {icon}", "sessionNetworkLearnAboutStaking": "Află mai multe despre staking", "sessionNetworkMarketCap": "Capitalizare de piață", @@ -896,6 +902,7 @@ "showLess": "Afișează mai puțin", "showNoteToSelf": "Afișează Notă personală", "showNoteToSelfDescription": "Ești sigur/ă că dorești să afișezi Notă personală în lista de conversații?", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Autocolante", "supportGoTo": "Mergi la Pagina de asistență", "systemInformationDesktop": "Informații de sistem: {information}", @@ -903,6 +910,8 @@ "theContinue": "Continuă", "theDefault": "Implicit", "theError": "Eroare", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tooltipAccountIdVisible": "ID-ul contului {name} este vizibil în baza interacțiunilor anterioare", "tooltipBlindedIdCommunities": "ID-urile cenzurate sunt utilizate în comunități pentru a reduce mesajele spam și a crește confidențialitatea", "tryAgain": "Încercați din nou", @@ -935,6 +944,7 @@ "urlOpen": "Deschide URL", "urlOpenBrowser": "Aceasta se va deschide în browserul tău.", "urlOpenDescription": "Ești sigur/ă că dorești să deschizi acest URL în browserul tău?

{url}", + "usdNameShort": "USD", "useFastMode": "Folosește modul rapid", "video": "Video", "videoErrorPlay": "Videoclipul nu poate fi redat.", @@ -946,7 +956,6 @@ "warning": "Atenţie", "window": "Fereastră", "yes": "Da", - "you": "Tu", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Tu" } diff --git a/_locales/ru/messages.json b/_locales/ru/messages.json index 3ff4e6853..639f480f8 100644 --- a/_locales/ru/messages.json +++ b/_locales/ru/messages.json @@ -56,12 +56,14 @@ "appIconEnableIconAndName": "Использовать альтернативную иконку приложения и имя", "appIconSelect": "Выберите альтернативную иконку приложения", "appIconSelectionTitle": "Иконка", + "appName": "Session", "appNameCalculator": "Калькулятор", "appNameMeetingSE": "MeetingSE", "appNameNews": "Новости", "appNameNotes": "Заметки", "appNameStocks": "Акции", "appNameWeather": "Погода", + "appPro": "Session Pro", "appearanceHideMenuBar": "Спрятать системное меню", "appearanceLanguage": "Язык", "appearanceLanguageDescription": "Выберите языковые настройки для Session. Session будет перезапущен при изменении языковой настройки.", @@ -180,7 +182,6 @@ "callsSettings": "Звонки (бета)", "callsVoiceAndVideo": "Голосовые и видеозвонки", "callsVoiceAndVideoBeta": "Голосовые и видеозвонки (бета)", - "callsVoiceAndVideoModalDescription": "Ваш IP виден вашему собеседнику и серверу Oxen Foundation при использовании бета-вызовов.", "callsVoiceAndVideoToggleDescription": "Включает голосовые и видеозвонки для общения с другими пользователями.", "callsYouCalled": "Вы позвонили {name}", "callsYouMissedCallPermissions": "Вы пропустили звонок от {name}, потому что не включили Голосовые и видеозвонки в настройках конфиденциальности.", @@ -621,6 +622,7 @@ "modalMessageCharacterTooLongTitle": "Сообщение слишком длинное", "modalMessageTooLongDescription": "Пожалуйста, сократите свое сообщение до {limit} символов.", "modalMessageTooLongTitle": "Сообщение слишком длинное", + "networkName": "Session Network", "next": "Далее", "nicknameDescription": "Выберите псевдоним для {name}. Он будет отображаться в индивидуальных и групповых беседах.", "nicknameEnter": "Введите ник", @@ -699,6 +701,7 @@ "open": "Открыть", "openSurvey": "Открытый опрос", "other": "Другое", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Изменить пароль", "passwordConfirm": "Подтвердить пароль", "passwordCurrentIncorrect": "Ваш пароль неверен.", @@ -852,10 +855,13 @@ "sessionAppearance": "Внешний вид", "sessionClearData": "Очистить данные", "sessionConversations": "Беседы", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Помощь", "sessionInviteAFriend": "Пригласить друга", "sessionMessageRequests": "Запросы на переписку", "sessionNetworkCurrentPrice": "Текущая цена SESH", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNetworkDescription": "Сообщения отправляются через Session Network. Сеть состоит из узлов, стимулируемых Session Token, что обеспечивает децентрализацию и безопасность Session. Узнать больше {icon}", "sessionNetworkLearnAboutStaking": "Подробней о стейкинге", "sessionNetworkMarketCap": "Рыночная капитализация", @@ -884,6 +890,7 @@ "showLess": "Свернуть", "showNoteToSelf": "Показать Заметки для Себя", "showNoteToSelfDescription": "Вы уверены, что хотите отобразить Заметку для себя в списке бесед?", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Стикеры", "supportGoTo": "Перейти на страницу поддержки", "systemInformationDesktop": "Информация о системе: {information}", @@ -891,6 +898,8 @@ "theContinue": "Продолжить", "theDefault": "По умолчанию", "theError": "Ошибка", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tooltipAccountIdVisible": "ID аккаунта {name} виден
на основе ваших предыдущих взаимодействий", "tooltipBlindedIdCommunities": "Скрытые ID используются в сообществах
для уменьшения спама и повышения конфиденциальности", "tryAgain": "Повторить", @@ -919,6 +928,7 @@ "urlOpen": "Открыть ссылку", "urlOpenBrowser": "Откроется в вашем браузере.", "urlOpenDescription": "Вы уверены, что хотите открыть эту ссылку в вашем браузере?

{url}", + "usdNameShort": "USD", "useFastMode": "Использовать быстрый режим", "video": "Видео", "videoErrorPlay": "Невозможно воспроизвести видео.", @@ -930,7 +940,6 @@ "warning": "Предупреждение", "window": "Окно", "yes": "Да", - "you": "Вы", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Вы" } diff --git a/_locales/sh/messages.json b/_locales/sh/messages.json index 3ec4d4e39..0f7b36404 100644 --- a/_locales/sh/messages.json +++ b/_locales/sh/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} i {other_name} su unaprijeđeni u Admina.", "andMore": "+{count}", "anonymous": "Anonimno", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Sakrij traku sa menijem", "appearanceLanguage": "Jezik", "appearanceLanguageDescription": "Odaberite postavku jezika za Session. Session će se restartovati kada promenite jezičke postavke.", @@ -150,7 +152,6 @@ "callsSettings": "Pozivi (Beta)", "callsVoiceAndVideo": "Glasovni i video pozivi", "callsVoiceAndVideoBeta": "Glasovni i video pozivi (Beta)", - "callsVoiceAndVideoModalDescription": "Tvoj IP je vidljiv tvom partneru na pozivu i serveru Oxen Foundation dok koristiš beta pozive.", "callsVoiceAndVideoToggleDescription": "Omogućuje glasovne i video pozive od i prema drugim korisnicima.", "callsYouCalled": "Nazvali ste {name}", "callsYouMissedCallPermissions": "Propustio si poziv od {name} jer nisi omogućio Glasovne i Video Pozive u postavkama privatnosti.", @@ -524,6 +525,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Glasovna poruka", "messages": "Poruke", "minimize": "Minimizuj", + "networkName": "Session Network", "next": "Sledeći", "nicknameDescription": "Odaberite nadimak za {name}. Ovo će se prikazati u vašim jedan na jedan i grupnim razgovorima.", "nicknameEnter": "Unesi nadimak", @@ -597,6 +599,7 @@ "onsErrorUnableToSearch": "Nismo mogli pretražiti ovaj ONS. Molimo pokušajte ponovo kasnije.", "open": "Otvori", "other": "Ostalo", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Promeni lozinku", "passwordConfirm": "Potvrdi lozinku", "passwordCurrentIncorrect": "Trenutna lozinka nije ispravna.", @@ -705,9 +708,12 @@ "sessionAppearance": "Izgled", "sessionClearData": "Obriši podatke", "sessionConversations": "Razgovori", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Pomoć", "sessionInviteAFriend": "Pozovi prijatelja", "sessionMessageRequests": "Zahtjevi za poruke", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Notifikacije", "sessionPermissions": "Dozvole", "sessionPrivacy": "Privatnost", @@ -723,12 +729,15 @@ "show": "Prikaži", "showAll": "Prikaži sve", "showLess": "Prikaži manje", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Naljepnice", "supportGoTo": "Idi na stranicu podrške", "systemInformationDesktop": "Sistemske informacije: {information}", "theContinue": "Nastavi", "theDefault": "Zadano", "theError": "Greška", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Pokušajte ponovno", "typingIndicators": "Pokazatelji tipkanja", "typingIndicatorsDescription": "Vidi i podijeli tipkajuće indikatore.", @@ -748,6 +757,7 @@ "urlOpen": "Otvori URL", "urlOpenBrowser": "Ovo će se otvoriti u vašem pregledniku.", "urlOpenDescription": "Jesi li siguran da želiš otvoriti ovaj URL u svom pregledniku?

{url}", + "usdNameShort": "USD", "useFastMode": "Koristite Brzi režim", "video": "Video", "videoErrorPlay": "Nije moguće reprodukovati video.", @@ -757,7 +767,6 @@ "warning": "Upozorenje", "window": "Prozor", "yes": "Da", - "you": "Ti", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Ti" } diff --git a/_locales/si/messages.json b/_locales/si/messages.json index e90304fd9..7c6d38fea 100644 --- a/_locales/si/messages.json +++ b/_locales/si/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} සහ {other_name} පරිපාලක (Admin) තනතුරට උසස් කරන ලදී.", "andMore": "+{count}", "anonymous": "නිර්නාමික", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "මෙනු තීරුව සඟවන්න", "appearanceLanguage": "භාෂාව", "appearanceLanguageDescription": "Session සඳහා ඔබගේ භාෂා සැකසුම තෝරන්න. Session ඔබගේ භාෂා සැකසුම වෙනස් කරන විට නැවත ආරම්භ කිරීමට අවශ්ය වේ.", @@ -150,7 +152,6 @@ "callsSettings": "ඇමතුම් (බීටා)", "callsVoiceAndVideo": "ශ්‍රව්‍ය හා දෘශ්‍ය ඇමතුම්", "callsVoiceAndVideoBeta": "ශ්‍රව්‍ය සහ වීඩියෝ ඇමතුම් (බීටා)", - "callsVoiceAndVideoModalDescription": "ඔබගේ IP වැටීමට වයිස් සහ Oxen Foundation සේවාදායකයකු වෙත දැක්වේදීද පරීක්ෂණ ඇමතුම් භාවිතා කිරීමේදී.", "callsVoiceAndVideoToggleDescription": "වෙනත් පරිශීලකයින් සමඟ හඬ සහ වීඩියෝ ඇමතුම් සබලයි.", "callsYouCalled": "ඔබ {name} ඇමතුවා", "callsYouMissedCallPermissions": "ඔබට පෞද්ගලික වෙතින් හඬ සහ වීඩියෝ ඇමතුම් සක්‍රීය කරන විට {name} වෙතින් ඇමතුමක් කණගාටුයි.", @@ -524,6 +525,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} හඬ පණිවිඩය", "messages": "පණිවිඩ", "minimize": "හකුළන්න", + "networkName": "Session Network", "next": "ඊළඟ", "nicknameDescription": "{name} සඳහා අන්වර්ථ නාමයක් තෝරන්න. මෙය ඔබට ඔබේ එක් එක් හා කාමි සංවාද අතර දක්වනු ඇත.", "nicknameEnter": "අන්වර්ථ නාමයක් ඇතුළත් කරන්න", @@ -597,6 +599,7 @@ "onsErrorUnableToSearch": "අපට මෙම ONS සඳහා සැරසීම කළ නොහැකි විය. කරුණාකර පසුව නැවත උත්සහා කරන්න.", "open": "විවෘත", "other": "වෙනත්", + "oxenFoundation": "Oxen Foundation", "passwordChange": "මුරපදය වෙනස් කරන්න", "passwordConfirm": "මුරපදය තහවුරු කරන්න", "passwordCurrentIncorrect": "ඔබේ වත්මන් මුරපදය නිවැරදි නැත", @@ -705,9 +708,12 @@ "sessionAppearance": "පෙනුම", "sessionClearData": "දත්ත හිස් කරන්න", "sessionConversations": "සංවාද", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "උදව්", "sessionInviteAFriend": "මිතුරෙකුට ආරාධනා කරන්න", "sessionMessageRequests": "පණිවිඩ ඉල්ලීම්", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "දැනුම්දීම්", "sessionPermissions": "අවසර", "sessionPrivacy": "පෞද්ගලිකත්වය", @@ -723,12 +729,15 @@ "show": "පෙන්වන්න", "showAll": "සියල්ල පෙන්වන්න", "showLess": "අඩුවෙන් පෙන්වන්න", + "stakingRewardPool": "Staking Reward Pool", "stickers": "ස්ටිකර්ස්", "supportGoTo": "සහාය පිටුවට යන්න", "systemInformationDesktop": "පද්ධති තොරතුරු: {information}", "theContinue": "ඉදිරියට", "theDefault": "පෙරනිමි", "theError": "දෝෂය", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "නැවත", "typingIndicators": "ලිවීමේ දර්ශකය", "typingIndicatorsDescription": "ටයිප් කිරීමේ දර්ශක බලන්න සහ බෙදාගන්න.", @@ -748,6 +757,7 @@ "urlOpen": "ඒ.ස.නි. විවෘත", "urlOpenBrowser": "මෙය ඔබගේ අතිරික්සුවෙහි විවෘත වේ.", "urlOpenDescription": "ඔබට මෙම URL එක ඔබේ බ්‍රවුසරයේ විවෘත කිරීමට අවශ්‍ය බව විශ්වාසද?

{url}", + "usdNameShort": "USD", "useFastMode": "වේගවත් මාදිලිය භාවිතා කරන්න.", "video": "දෘශ්‍ය", "videoErrorPlay": "වීඩියෝව පවසන්නට නොහැක.", @@ -757,7 +767,6 @@ "warning": "අවවාදයයි", "window": "කවුළුව", "yes": "ඔව්", - "you": "ඔබ", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "ඔබ" } diff --git a/_locales/sk/messages.json b/_locales/sk/messages.json index 60305afbd..cf6571e7f 100644 --- a/_locales/sk/messages.json +++ b/_locales/sk/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} a {other_name} boli povýšení na správcov.", "andMore": "+{count}", "anonymous": "Anonymné", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Skryť panel ponuky", "appearanceLanguage": "Jazyk", "appearanceLanguageDescription": "Vyberte jazykové nastavenie pre Session . Session sa po zmene jazykového nastavenia reštartuje.", @@ -151,7 +153,6 @@ "callsSettings": "Hovory (Beta)", "callsVoiceAndVideo": "Hlasové a video hovory", "callsVoiceAndVideoBeta": "Hlasové a video hovory (Beta)", - "callsVoiceAndVideoModalDescription": "Vaša IP adresa je viditeľná vášmu volajúcemu partnerovi a serveru Oxen Foundation pri používaní beta hovory.", "callsVoiceAndVideoToggleDescription": "Umožňuje hlasové a video hovory s inými používateľmi a od nich.", "callsYouCalled": "Volali ste {name}", "callsYouMissedCallPermissions": "Zmeškali ste hovor od {name}, pretože ste nepovolili Hlasové a video hovory v nastaveniach súkromia.", @@ -525,6 +526,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Hlasová správa", "messages": "Správy", "minimize": "Minimalizovať", + "networkName": "Session Network", "next": "Ďalej", "nicknameDescription": "Vyberte prezývku pre {name}. Zobrazí sa vám v individuálnych a skupinových konverzáciách.", "nicknameEnter": "Zadajte prezývku", @@ -598,6 +600,7 @@ "onsErrorUnableToSearch": "Nepodarilo sa vyhľadať tento ONS. Skúste to znova neskôr.", "open": "Otvoriť", "other": "Iné", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Zmeniť heslo", "passwordConfirm": "Potvrdiť heslo", "passwordCurrentIncorrect": "Vaše aktuálne heslo je nesprávne.", @@ -706,9 +709,12 @@ "sessionAppearance": "Vzhľad", "sessionClearData": "Vyčistiť údaje", "sessionConversations": "Konverzácie", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Pomoc", "sessionInviteAFriend": "Pozvať priateľa", "sessionMessageRequests": "Žiadosti o správu", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Upozornenia", "sessionPermissions": "Povolenia", "sessionPrivacy": "Súkromie", @@ -724,12 +730,15 @@ "show": "Zobraziť", "showAll": "Ukázať všetky", "showLess": "Zobraziť menej", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Nálepky", "supportGoTo": "Navštíviť Stránku Podpory", "systemInformationDesktop": "Systémové informácie: {information}", "theContinue": "Pokračovať", "theDefault": "Predvolené", "theError": "Chyba", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Skúsiť znova", "typingIndicators": "Indikátory písania", "typingIndicatorsDescription": "Zobraziť a zdieľať indikátory písania.", @@ -749,6 +758,7 @@ "urlOpen": "Otvoriť URL", "urlOpenBrowser": "Toto sa otvorí vo vašom prehliadači.", "urlOpenDescription": "Naozaj chcete otvoriť túto URL v prehliadači?

{url}", + "usdNameShort": "USD", "useFastMode": "Použiť rýchly režim", "video": "Video", "videoErrorPlay": "Nie je možné prehrať video.", @@ -758,7 +768,6 @@ "warning": "Varovanie", "window": "Okno", "yes": "Áno", - "you": "Vy", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Vy" } diff --git a/_locales/sl/messages.json b/_locales/sl/messages.json index 17f12e7fb..3a16011c5 100644 --- a/_locales/sl/messages.json +++ b/_locales/sl/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} in {other_name} sta bila promovirana v administratorja.", "andMore": "+{count}", "anonymous": "Anonimno", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Skrij menijsko vrstico", "appearanceLanguage": "Jezik", "appearanceLanguageDescription": "Izberite jezikovne nastavitve za Session. Session se bo ponovno zagnal, ko spremenite jezikovne nastavitve.", @@ -150,7 +152,6 @@ "callsSettings": "Klici (Beta)", "callsVoiceAndVideo": "Glasvni in video klici", "callsVoiceAndVideoBeta": "Glasvni in video klici (Beta)", - "callsVoiceAndVideoModalDescription": "Vaš IP je viden vašemu partnerskemu klicatelju in strežniku Oxen Foundation med uporabo beta klicev.", "callsVoiceAndVideoToggleDescription": "Omogoča glasovne in video klice od in do drugih uporabnikov.", "callsYouCalled": "Klicali ste osebo {name}", "callsYouMissedCallPermissions": "Zmanjkalo je lahko klic iz {name}, ker niste omogočili glasovnih in video klicev v nastavitvah zasebnosti.", @@ -356,7 +357,7 @@ "files": "Datoteke", "from": "Od:", "fullScreenToggle": "Preklopi na Celoten zaslon", - "gif": "GIF-i", + "gif": "GIF", "giphyWarning": "Giphy", "giphyWarningDescription": "Session se bo povezal z Giphy, da zagotovi rezultate iskanja. Pri pošiljanju GIF-ov ne boste imeli popolne zaščite metapodatkov.", "groupAddMemberMaximum": "Skupine lahko imajo največ 100 članov", @@ -524,6 +525,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Glasovno sporočilo", "messages": "Sporočila", "minimize": "Pomanjšaj", + "networkName": "Session Network", "next": "Naslednje", "nicknameDescription": "Izberite vzdevek za {name}. To se bo prikazalo v vaših pogovorih ena-na-ena in skupinskih pogovorih.", "nicknameEnter": "Vnesite vzdevek", @@ -597,6 +599,7 @@ "onsErrorUnableToSearch": "Nismo mogli iskati tega ONS. Poskusite znova pozneje.", "open": "Odpri", "other": "Drugo", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Spremeni geslo", "passwordConfirm": "Potrdi geslo", "passwordCurrentIncorrect": "Vaše trenutno geslo je napačno.", @@ -705,9 +708,12 @@ "sessionAppearance": "Videz", "sessionClearData": "Počisti podatke", "sessionConversations": "Pogovori", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Pomoč", "sessionInviteAFriend": "Povabi prijatelja", "sessionMessageRequests": "Zahteve za sporočila", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Obvestila", "sessionPermissions": "Dovoljenja", "sessionPrivacy": "Zasebnost", @@ -723,12 +729,15 @@ "show": "Prikaži", "showAll": "Prikaži vse", "showLess": "Prikaži manj", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Nalepke", "supportGoTo": "Pojdite na Podporno stran", "systemInformationDesktop": "Sistemske informacije: {information}", "theContinue": "Nadaljuj", "theDefault": "Privzeto", "theError": "Napaka", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Poskusite znova", "typingIndicators": "Indikatorji tipkanja", "typingIndicatorsDescription": "Poglejte in delite indikatorje tipkanja.", @@ -748,6 +757,7 @@ "urlOpen": "Odpri URL", "urlOpenBrowser": "To se bo odprlo v vašem brskalniku.", "urlOpenDescription": "Ali ste prepričani, da želite odpreti ta URL v vašem brskalniku?

{url}", + "usdNameShort": "USD", "useFastMode": "Uporabi Fast Mode", "video": "Video", "videoErrorPlay": "Videoposnetka ni mogoče predvajati.", @@ -757,7 +767,6 @@ "warning": "Opozorilo", "window": "Okno", "yes": "Da", - "you": "Vi", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Vi" } diff --git a/_locales/sq/messages.json b/_locales/sq/messages.json index 2dc9a01a4..676574c87 100644 --- a/_locales/sq/messages.json +++ b/_locales/sq/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} dhe {other_name} u promovuan në Administratorë.", "andMore": "+{count}", "anonymous": "Anonim", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Fshihi shiritin e menusë", "appearanceLanguage": "Gjuhë", "appearanceLanguageDescription": "Zgjidhni cilësimin e gjuhës për Session. Session do të riniset kur të ndryshoni cilësimin e gjuhës.", @@ -150,7 +152,6 @@ "callsSettings": "Thirrje (Beta)", "callsVoiceAndVideo": "Thirrje me Zë dhe Video", "callsVoiceAndVideoBeta": "Thirrje me Zë dhe Video (Beta)", - "callsVoiceAndVideoModalDescription": "IP-ja juaj është e dukshme për partnerin tuaj të thirrjes dhe një server të Fondacionit Oxen gjatë përdorimit të thirrjeve beta.", "callsVoiceAndVideoToggleDescription": "Aktivizon thirrjet me zë dhe video drejt dhe nga përdorues të tjerë.", "callsYouCalled": "Ju thirrët {name}", "callsYouMissedCallPermissions": "Ju keni humbur një telefonatë nga {name} sepse nuk keni aktivizuar Thirrjet me Zë dhe Video në Cilësimet e Privatësisë.", @@ -524,6 +525,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Mesazh Zanor", "messages": "Mesazhe", "minimize": "Minimizoje", + "networkName": "Session Network", "next": "Tutje", "nicknameDescription": "Zgjidhni një nofkë për {name}. Kjo do të shfaqet për ju në bisedat një-me-një dhe në grup.", "nicknameEnter": "Jepni pseudonimin", @@ -597,6 +599,7 @@ "onsErrorUnableToSearch": "Nuk mundëm të kërkonim për këtë ONS. Ju lutemi provoni përsëri më vonë.", "open": "Hap", "other": "Tjetër", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Ndrysho Fjalëkalimin", "passwordConfirm": "Konfirmo fjalëkalimin", "passwordCurrentIncorrect": "Fjalëkalimi juaj aktual është i pasaktë.", @@ -705,9 +708,12 @@ "sessionAppearance": "Dukje", "sessionClearData": "Fshij të dhënat", "sessionConversations": "Biseda", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Ndihmë", "sessionInviteAFriend": "Fto një Mik", "sessionMessageRequests": "Mesazhe Session", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Njoftime", "sessionPermissions": "Leje", "sessionPrivacy": "Privatësi", @@ -723,12 +729,15 @@ "show": "Shfaqe", "showAll": "Shfaqi Krejt", "showLess": "Shfaqi më pak", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Ngjitëse", "supportGoTo": "Kalo te Faqja e Asistencës", "systemInformationDesktop": "Informacionet e Sistemit: {information}", "theContinue": "Vazhdo", "theDefault": "Parazgjedhje", "theError": "Gabim", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Riprovo", "typingIndicators": "Tregues shtypjeje", "typingIndicatorsDescription": "Shihni dhe ndani indikatorët e shtypjes.", @@ -748,6 +757,7 @@ "urlOpen": "Hap URL", "urlOpenBrowser": "Kjo do të hapet në shfletuesin tuaj.", "urlOpenDescription": "A jeni të sigurt që doni ta hapni këtë URL në shfletuesin tuaj?

{url}", + "usdNameShort": "USD", "useFastMode": "Përdorni Fast Mode", "video": "Video", "videoErrorPlay": "Nuk u arrit të luhet video.", @@ -757,7 +767,6 @@ "warning": "Paralajmërim", "window": "Dritare", "yes": "Po", - "you": "Ju", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Ju" } diff --git a/_locales/sr-CS/messages.json b/_locales/sr-CS/messages.json index 98fcc966d..6862c34dd 100644 --- a/_locales/sr-CS/messages.json +++ b/_locales/sr-CS/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} i {other_name} su unapredjeni u admina.", "andMore": "+{count}", "anonymous": "Anonimno", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Sakrij meni", "appearanceLanguage": "Jezik", "appearanceLanguageDescription": "Odaberite jezik za Session. Session će se restartovati kada promenite podešavanje jezika.", @@ -150,7 +152,6 @@ "callsSettings": "Pozivi (Beta)", "callsVoiceAndVideo": "Glasovni i video poziv", "callsVoiceAndVideoBeta": "Glasovni i video poziv (Beta)", - "callsVoiceAndVideoModalDescription": "Vaš IP je vidljiv vašem partneru za poziv i serveru Oxen Foundation dok koristite beta pozive.", "callsVoiceAndVideoToggleDescription": "Omogućava glasovne i video pozive ka i od drugih korisnika.", "callsYouCalled": "Pozvali ste {name}", "callsYouMissedCallPermissions": "Propustili ste poziv od {name} jer niste omogućili Glasovne i Video Pozive u Podešavanjima Privatnosti.", @@ -524,6 +525,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Glasovna poruka", "messages": "Poruke", "minimize": "Minimizuj", + "networkName": "Session Network", "next": "Dalje", "nicknameDescription": "Odaberite nadimak za {name}. Ovo će vam se pojaviti u vašim razgovorima jedan na jedan i grupnim razgovorima.", "nicknameEnter": "Unesite nadimak", @@ -597,6 +599,7 @@ "onsErrorUnableToSearch": "Nismo mogli da pretražimo ovaj ONS. Pokušajte ponovo kasnije.", "open": "Otvori", "other": "Ostalo", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Promeni lozinku", "passwordConfirm": "Potvrda lozinke", "passwordCurrentIncorrect": "Vaša trenutna lozinka je netačna.", @@ -705,9 +708,12 @@ "sessionAppearance": "Izgled", "sessionClearData": "Počisti podatke", "sessionConversations": "Pripiske", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Pomoć", "sessionInviteAFriend": "Pozovite prijatelja", "sessionMessageRequests": "Zahtevi za poruke", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Notifikacije", "sessionPermissions": "Dozvole", "sessionPrivacy": "Privatnost", @@ -723,12 +729,15 @@ "show": "Prikaži", "showAll": "Prikaži sve", "showLess": "Prikaži manje", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Nalepnice", "supportGoTo": "Idite na stranicu za podršku", "systemInformationDesktop": "Sistemske informacije: {information}", "theContinue": "Nastavi", "theDefault": "Podrazumevano", "theError": "Greska", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Pokušajte ponovo", "typingIndicators": "Indikatori pisanja", "typingIndicatorsDescription": "Pregledaj i deli indikatore kucanja.", @@ -748,6 +757,7 @@ "urlOpen": "Otvorite URL", "urlOpenBrowser": "Ovo će se otvoriti u vašem pregledaču.", "urlOpenDescription": "Da li ste sigurni da želite da otvorite ovaj URL u svom internet pregledaču?

{url}", + "usdNameShort": "USD", "useFastMode": "Koristi Fast Mode", "video": "Video", "videoErrorPlay": "Nije moguće reprodukovati video.", @@ -757,7 +767,6 @@ "warning": "Upozorenje", "window": "Prozor", "yes": "Da", - "you": "Ti", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Ti" } diff --git a/_locales/sr-SP/messages.json b/_locales/sr-SP/messages.json index 0323e4cdd..0b8944521 100644 --- a/_locales/sr-SP/messages.json +++ b/_locales/sr-SP/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} и {other_name} су унапређени у администраторе.", "andMore": "+{count}", "anonymous": "Анониман", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Сакријте мени бар", "appearanceLanguage": "Језик", "appearanceLanguageDescription": "Изаберите језичке поставке за Session. Session ће се поново покренути када промените језичке поставке.", @@ -150,7 +152,6 @@ "callsSettings": "Позиви (бета)", "callsVoiceAndVideo": "Гласовни и видео позиви", "callsVoiceAndVideoBeta": "Гласовни и видео позиви (Beta)", - "callsVoiceAndVideoModalDescription": "Ваша IP адреса је видљива вашем сајговорнику и серверу Oxen Foundation док користите бета позиве.", "callsVoiceAndVideoToggleDescription": "Омогућава гласовна и видео ћаскања између других корисника.", "callsYouCalled": "Позвали сте {name}", "callsYouMissedCallPermissions": "Пропустили сте позив од {name} јер нисте омогућили Гласовне и Видео Позиве у Подешавањима Приватности.", @@ -356,7 +357,7 @@ "files": "Фајлови", "from": "Од:", "fullScreenToggle": "Пребаците цео екран", - "gif": "ГИФ", + "gif": "GIF", "giphyWarning": "Giphy", "giphyWarningDescription": "Session ће се повезати са Giphy да би обезбедили резултате претраге. Нећете имати потпуну заштиту метаподатака када шаљете GIF-ове.", "groupAddMemberMaximum": "Групе имају максимално 100 чланова", @@ -524,6 +525,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Гласовна порука", "messages": "Поруке", "minimize": "Минимизуј", + "networkName": "Session Network", "next": "Следеће", "nicknameDescription": "Изаберите надимак за {name}. Ово ће вам се појавити у један-на-један и групним конверзацијама.", "nicknameEnter": "Унесите надимак", @@ -597,6 +599,7 @@ "onsErrorUnableToSearch": "Није могуће претражити овај ONS. Покушајте поново касније.", "open": "Отвори", "other": "Остало", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Промени лозинку", "passwordConfirm": "Потврдите лозинку", "passwordCurrentIncorrect": "Ваша тренутна лозинка је нетачна.", @@ -705,9 +708,12 @@ "sessionAppearance": "Изглед", "sessionClearData": "Очисти податке", "sessionConversations": "Преписке", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Помоћ", "sessionInviteAFriend": "Позови пријатеља", "sessionMessageRequests": "Захтеви за поруке", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Обавештења", "sessionPermissions": "Дозволе", "sessionPrivacy": "Приватност", @@ -723,12 +729,15 @@ "show": "Прикажи", "showAll": "Прикажи све", "showLess": "Прикажи мање", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Налепнице", "supportGoTo": "Идите на Страницу подршке", "systemInformationDesktop": "Системске информације: {information}", "theContinue": "Настави", "theDefault": "Подразумеван", "theError": "Грешка", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Покушај поново", "typingIndicators": "Индикатори куцања", "typingIndicatorsDescription": "Погледај и дели тип индикаторе.", @@ -748,6 +757,7 @@ "urlOpen": "Отвори URL", "urlOpenBrowser": "Ово ће се отворити у вашем прегледачу.", "urlOpenDescription": "Да ли сте сигурни да желите да отворите овај URL у вашем претраживачу?

{url}", + "usdNameShort": "USD", "useFastMode": "Користи Fast Mode", "video": "Видео", "videoErrorPlay": "Није могуће репродуковати видео.", @@ -757,7 +767,6 @@ "warning": "Упозорење", "window": "Прозор", "yes": "Да", - "you": "Ти", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Ти" } diff --git a/_locales/sv/messages.json b/_locales/sv/messages.json index d62574362..dbf17355a 100644 --- a/_locales/sv/messages.json +++ b/_locales/sv/messages.json @@ -56,12 +56,14 @@ "appIconEnableIconAndName": "Använd alternativ app-ikon och namn", "appIconSelect": "Välj en alternativ app-ikon", "appIconSelectionTitle": "Ikon", + "appName": "Session", "appNameCalculator": "Miniräknare", "appNameMeetingSE": "MötenSE", "appNameNews": "Nyheter", "appNameNotes": "Anteckningar", "appNameStocks": "Aktier", "appNameWeather": "Väder", + "appPro": "Session Pro", "appearanceHideMenuBar": "Dölj menyfältet", "appearanceLanguage": "Språk", "appearanceLanguageDescription": "Välj din språkinställning för Session. Session kommer att startas om när du ändrar din språkinställning.", @@ -180,7 +182,6 @@ "callsSettings": "Samtal (Beta)", "callsVoiceAndVideo": "Röst- och videosamtal", "callsVoiceAndVideoBeta": "Röst- och videosamtal (Beta)", - "callsVoiceAndVideoModalDescription": "Din IP är synlig för din samtalspartner och en Oxen Foundation server när du använder beta-samtal.", "callsVoiceAndVideoToggleDescription": "Möjliggör röst- och videosamtal till och från andra användare.", "callsYouCalled": "Du ringde {name}", "callsYouMissedCallPermissions": "Du missade ett samtal från {name} eftersom du inte har aktiverat Röst- och videosamtal i Sekretessinställningar.", @@ -624,6 +625,7 @@ "modalMessageCharacterTooLongTitle": "Meddelandet är för långt", "modalMessageTooLongDescription": "Förkorta ditt meddelande till {limit} tecken eller färre.", "modalMessageTooLongTitle": "Meddelandet är för långt", + "networkName": "Session Network", "next": "Nästa", "nicknameDescription": "Välj ett smeknamn för {name}. Detta kommer att visas för dig i dina en-till-en- och gruppkonversationer.", "nicknameEnter": "Ange smeknamn", @@ -702,6 +704,7 @@ "open": "Öppna", "openSurvey": "Öppna undersökning", "other": "Övrigt", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Ändra lösenord", "passwordConfirm": "Bekräfta lösenord", "passwordCurrentIncorrect": "Ditt nuvarande lösenord är felaktigt.", @@ -863,10 +866,13 @@ "sessionAppearance": "Utseende", "sessionClearData": "Rensa data", "sessionConversations": "Konversationer", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Hjälp", "sessionInviteAFriend": "Bjud in en vän", "sessionMessageRequests": "Meddelandeförfrågningar", "sessionNetworkCurrentPrice": "Nuvarande SESH-pris", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNetworkDescription": "Meddelanden skickas via Session Network. Nätverket består av noder som är incitamenterade med Session Token, vilket håller Session decentraliserad och säker. Läs mer {icon}", "sessionNetworkLearnAboutStaking": "Lär dig mer om staking", "sessionNetworkMarketCap": "Marknadsvärde", @@ -895,6 +901,7 @@ "showLess": "Visa färre", "showNoteToSelf": "Visa Notera till mig själv", "showNoteToSelfDescription": "Är du säker på att du vill visa Notera till mig själv i din konversationslista?", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Klistermärken", "supportGoTo": "Gå till supportsidan", "systemInformationDesktop": "Systeminformation: {information}", @@ -902,6 +909,8 @@ "theContinue": "Fortsätt", "theDefault": "Standard", "theError": "Fel", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tooltipAccountIdVisible": "{name}:s Account ID är synligt baserat på dina tidigare interaktioner", "tooltipBlindedIdCommunities": "Maskerade ID används i Communitys för att minska spam och öka sekretessen", "tryAgain": "Försök igen", @@ -934,6 +943,7 @@ "urlOpen": "Öppna URL", "urlOpenBrowser": "Detta kommer att öppna i din webbläsare.", "urlOpenDescription": "Är du säker på att du vill öppna denna URL i din webbläsare?

{url}", + "usdNameShort": "USD", "useFastMode": "Använd snabbläge", "video": "Video", "videoErrorPlay": "Kunde inte spela upp video.", @@ -945,7 +955,6 @@ "warning": "Varning", "window": "Fönster", "yes": "Ja", - "you": "Du", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Du" } diff --git a/_locales/sw/messages.json b/_locales/sw/messages.json index a7245f228..21c752e32 100644 --- a/_locales/sw/messages.json +++ b/_locales/sw/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} na {other_name} wamepandishwa cheo kuwa Admin.", "andMore": "+{count}", "anonymous": "Anonymous", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Ficha Mwambaa wa Menyu", "appearanceLanguage": "Lugha", "appearanceLanguageDescription": "Chagua mpangilio wa lugha yako kwa Session. Session itaanza tena unapobadilisha mpangilio wa lugha lako.", @@ -151,7 +153,6 @@ "callsSettings": "Simu (Beta)", "callsVoiceAndVideo": "Sauti na Simu za Video", "callsVoiceAndVideoBeta": "Sauti na Simu za Video (Beta)", - "callsVoiceAndVideoModalDescription": "IP yako inaonekana kwa mshirika wako wa simu na seva ya Oxen Foundation wakati unatumia simu za beta.", "callsVoiceAndVideoToggleDescription": "Kuwezesha simu za sauti na video kwa watumiaji wengine.", "callsYouCalled": "Ulimpiga simu {name}", "callsYouMissedCallPermissions": "Ulikosa simu kutoka {name} kwa sababu hujawezesha Sauti na Simu za Video katika Mipangilio ya Faragha.", @@ -525,6 +526,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Ujumbe-Sauti", "messages": "Jumbe", "minimize": "Minimize", + "networkName": "Session Network", "next": "Inayofuata", "nicknameDescription": "Chagua jina la utani kwa {name}. Hii itaonekana kwako katika mazungumzo ya moja kwa moja na ya kikundi.", "nicknameEnter": "Weka jina la utani", @@ -598,6 +600,7 @@ "onsErrorUnableToSearch": "Hatuwezi kutafuta ONS hii. Tafadhali jaribu tena baadaye.", "open": "Fungua", "other": "ingine", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Badilisha Nywila", "passwordConfirm": "Thibitisha nenosiri", "passwordCurrentIncorrect": "Nenosiri lako la sasa sio sahihi.", @@ -706,9 +709,12 @@ "sessionAppearance": "Muonekano", "sessionClearData": "Futa Data", "sessionConversations": "Mazungumzo", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Msaada", "sessionInviteAFriend": "Alika Rafiki", "sessionMessageRequests": "Message Requests", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Arifa", "sessionPermissions": "Ruhusa", "sessionPrivacy": "Faragha", @@ -724,12 +730,15 @@ "show": "Onyesha", "showAll": "Onyesha Zote", "showLess": "Onyesha Chache", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Stika", "supportGoTo": "Nenda kwenye Ukurasa wa Usaidizi", "systemInformationDesktop": "Maelezo ya Mfumo: {information}", "theContinue": "Endelea", "theDefault": "Chaguo Msingi", "theError": "Kosa", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Jaribu tena", "typingIndicators": "Andika viashiria", "typingIndicatorsDescription": "Angalia na shiriki viashiria vya kuandika.", @@ -749,6 +758,7 @@ "urlOpen": "Fungua URL", "urlOpenBrowser": "Hii itafunguliwa kwenye kivinjari chako.", "urlOpenDescription": "Una uhakika unataka kufungua URL hii kwenye kivinjari chako?

{url}", + "usdNameShort": "USD", "useFastMode": "Tumia Hali ya Haraka", "video": "Video", "videoErrorPlay": "Haiwezi kucheza video.", @@ -758,7 +768,6 @@ "warning": "Onyo", "window": "Dirisha", "yes": "Ndio", - "you": "Wewe", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Wewe" } diff --git a/_locales/ta/messages.json b/_locales/ta/messages.json index c181a048c..e54417013 100644 --- a/_locales/ta/messages.json +++ b/_locales/ta/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} மற்றும் {other_name} நிர்வாகியாக உயர்த்தப்பட்டனர்.", "andMore": "+{count}", "anonymous": "ஸ்தனமானவனே", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "மெனு பட்டியை மறை", "appearanceLanguage": "மொழி", "appearanceLanguageDescription": "Session க்கான மொழி அமைப்புகளைத் தேர்ந்தெடுக்கவும். உங்கள் மொழி அமைப்பை மாற்றும் போது Session மீண்டும் தொடங்கும்.", @@ -152,7 +154,6 @@ "callsSettings": "அழைப்புகள் (பீட்டா)", "callsVoiceAndVideo": "குரல் மற்றும் காணொளி அழைப்புகள்", "callsVoiceAndVideoBeta": "குரல் மற்றும் காணொளி அழைப்புகள் (பீட்டா)", - "callsVoiceAndVideoModalDescription": "அழைப்பு பிறையாளர் மற்றும் Oxen Foundation சர்வரில் உங்கள் ஐபி காட்டப்படவும் செய்தி சேவையின்போது.", "callsVoiceAndVideoToggleDescription": "பயனீர்களுக்கிடையே குரல் மற்றும் காணொளி அழைப்புகளை செயல்படுத்துகிறது.", "callsYouCalled": "நீங்கள் {name} ஐ அழைத்துள்ளீர்கள்", "callsYouMissedCallPermissions": "நீங்கள் {name} -ன் அழைப்பை (call) நீங்கள் குரல் மற்றும் வீடியோ அழைப்புகளை பொறிமுறையில் இயல்த்தவில்லை என்பதனால் தவற விட்டீர்கள்.", @@ -529,6 +530,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} குரல் செய்தி", "messages": "செய்திகள்", "minimize": "சிறிதாக்கு", + "networkName": "Session Network", "next": "அடுத்தது", "nicknameDescription": "{name} க்கு ஒரு பெயரைத் தேர்ந்தெடுக்கவும். இது உங்கள் ஒரே நோக்கத்தில் மற்றும் குழு உரையாடலில் நீங்கள் பார்க்கப்படும் பெயராக இருக்கும்.", "nicknameEnter": "புனைப்பெயரை உள்ளிடவும்", @@ -602,6 +604,7 @@ "onsErrorUnableToSearch": "இந்த ONSஐ தேட முடியவில்லை. தயவுசெய்து பின்னர் முயற்சிக்கவும்.", "open": "திற", "other": "பிற", + "oxenFoundation": "Oxen Foundation", "passwordChange": "கடவுச்சொல்லை மாற்றவும்", "passwordConfirm": "கடவுச்சொல்லை உறுதி செய்தல்", "passwordCurrentIncorrect": "உங்கள் நடப்புக் கடவுச்சொல் தவறாக உள்ளது.", @@ -711,9 +714,12 @@ "sessionAppearance": "Session பதிப்பு", "sessionClearData": "தகவலை அழி", "sessionConversations": "உரையாடல்கள்", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "உதவி", "sessionInviteAFriend": "ஒரு நண்பனை அழைக்கவும்", "sessionMessageRequests": "Message Requests", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "அறிவிப்புகள்", "sessionPermissions": "அனுமதிகள்", "sessionPrivacy": "தனியுரிமை", @@ -729,12 +735,15 @@ "show": "காட்டு", "showAll": "எல்லாம் காண்பி", "showLess": "குறைவாக காட்டு", + "stakingRewardPool": "Staking Reward Pool", "stickers": "ஸ்டிக்கர்கள்", "supportGoTo": "ஆதரவு பக்கத்திற்குச் செல்லவும்", "systemInformationDesktop": "சிஸ்டம் தகவல்: {information}", "theContinue": "தொடரு", "theDefault": "முன்னிருப்பு", "theError": "கோலாரு", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "மீண்டும் முயற்சிக்கவும்", "typingIndicators": "தட்டச்சு குறியீடுகள்", "typingIndicatorsDescription": "தட்டச்சு குறிக்கிக்காட்டுகளை காணவும் மற்றும் பகிரவும்.", @@ -754,6 +763,7 @@ "urlOpen": "URL திறக்க", "urlOpenBrowser": "இது எனது உலாவியில் திறக்கும்.", "urlOpenDescription": "இந்த URL ஐ உங்கள் உலாவியில் திறக்க நீங்கள் உறுதியாக உள்ளீர்களா?

{url}", + "usdNameShort": "USD", "useFastMode": "Use Fast Mode", "video": "காணொளி", "videoErrorPlay": "காணொளியை இயக்க முடியவில்லை.", @@ -763,7 +773,6 @@ "warning": "எச்சரிக்கை", "window": "விந்டோ", "yes": "ஆம்", - "you": "நீங்கள்", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "நீங்கள்" } diff --git a/_locales/te/messages.json b/_locales/te/messages.json index b21a05377..459fbdde1 100644 --- a/_locales/te/messages.json +++ b/_locales/te/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} మరియు {other_name} అడ్మిన్ కీ ప్రమోట్ చేయబడ్డారు.", "andMore": "+{count}", "anonymous": "అజ్ఞాతం", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "మెను బార్ దాచు", "appearanceLanguage": "భాష", "appearanceLanguageDescription": "Session కోసం మీ భాష సెట్టింగ్ ఎంచుకోండి. భాష సెట్టింగ్ మార్పినప్పుడు Session రీస్టార్ట్ అవుతుంది.", @@ -151,7 +153,6 @@ "callsSettings": "కాల్స్ (బీటా)", "callsVoiceAndVideo": "వాయిస్ మరియు వీడియో కాల్స్", "callsVoiceAndVideoBeta": "వాయిస్ మరియు వీడియో కాల్స్ (బీటా)", - "callsVoiceAndVideoModalDescription": "బీటా కాల్‌లను ఉపయోగిస్తున్నప్పుడు మీ ఐపి మీ కాల్ భాగస్వామికి మరియు ఒక Oxen Foundation సర్వర్‌కు కనిపిస్తుంది.", "callsVoiceAndVideoToggleDescription": "ఇతర వినియోగదారులకు మరియు వినియోగదారుల నుండి వాయిస్ మరియు వీడియో కాల్స్.", "callsYouCalled": "మీరు {name} కాల్ చేశారు", "callsYouMissedCallPermissions": "మీరు వాయిస్ మరియు వీడియో కాల్స్ను ప్రైవసీ సెట్టింగ్స్‌లో నేడు చెయ్యకపోవడంతో మీరు {name} నుండి కాల్ మిస్ చేశారు.", @@ -357,7 +358,7 @@ "files": "ఫైళ్లు", "from": "ఎవరినుండి:", "fullScreenToggle": "ఫుల్ స్క్రీన్ ని మారుస్తుంది", - "gif": "గిఫ్", + "gif": "GIF", "giphyWarning": "గిఫీ", "giphyWarningDescription": "Session సెర్చ్ ఫలితాలను అందించడానికి గిప్హీకి కనెక్ట్ అవుతుంది. మీరు గిఫ్‌లు పంపినపుడు మీకు పూర్తి మెటాడేటా రక్షణ ఉండదు.", "groupAddMemberMaximum": "సమూహాలు గరిష్టంగా 100 సభ్యులు ఉండవచ్చు", @@ -525,6 +526,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} వాయిస్ సందేశం", "messages": "సందేశాలు", "minimize": "కనిష్ఠ చేయండి", + "networkName": "Session Network", "next": "తర్వాత", "nicknameDescription": "{name} కోసం ఒక నిక్‌నేమ్ ఎంచుకోండి. ఇది మీకి మీ ఒకటి-టికొకటి మరియు గ్రూప్ సంభాషణల్లో చూపబడుతుంది.", "nicknameEnter": "మారుపేరును ఎంటర్ చేయండి", @@ -598,6 +600,7 @@ "onsErrorUnableToSearch": "మేము ఈ ONS కోసం శోధించలేకపోయాము. దయచేసి తర్వాత మళ్లీ ప్రయత్నించండి.", "open": "తెరవండి", "other": "ఇతరులు", + "oxenFoundation": "Oxen Foundation", "passwordChange": "పాస్వర్డ్ మార్చు", "passwordConfirm": "పాస్‌వర్డ్‌ని నిర్ధారించండి", "passwordCurrentIncorrect": "మీ ప్రస్తుత పాస్‌వర్డ్ తప్పు.", @@ -706,9 +709,12 @@ "sessionAppearance": "స్వరూపం", "sessionClearData": "డేటాను క్లియర్ చేయండి", "sessionConversations": "సంభాషణలు", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "సహాయం", "sessionInviteAFriend": "ఒక స్నేహితున్ని ఆహ్వానించండి", "sessionMessageRequests": "సందేశ అభ్యర్ధనలు", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "ప్రకటనలు", "sessionPermissions": "అనుమతులు", "sessionPrivacy": "గోప్యత", @@ -724,12 +730,15 @@ "show": "కనబర్చు", "showAll": "పూర్తిగా చూపించు", "showLess": "తక్కువ కనపరచు", + "stakingRewardPool": "Staking Reward Pool", "stickers": "స్టిక్కర్లు", "supportGoTo": "సహాయ పేజీకి వెళ్ళండి", "systemInformationDesktop": "సిస్టమ్ సమాచారం: {information}", "theContinue": "కొనసాగించు", "theDefault": "అప్రమేయ", "theError": "లోపం", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "మళ్ళీ ప్రయత్నించండి", "typingIndicators": "టైపింగ్ సూచికలు", "typingIndicatorsDescription": "టైపింగ్ సూచనలను చూడండి మరియు పంచుకోండి.", @@ -749,6 +758,7 @@ "urlOpen": "URL తెరువు", "urlOpenBrowser": "ఇది మీ బ్రౌజర్ లో ఓపెన్ అవుతుంది.", "urlOpenDescription": "మీరు మీ బ్రౌజర్‌లో ఈ URL ను తెరవాలనుకుంటున్నారా?

{url}", + "usdNameShort": "USD", "useFastMode": "ఫాస్ట్ మోడ్ వాడండి", "video": "వీడియో", "videoErrorPlay": "వీడియో ప్లే చేయడం సాధ్యపడదు.", @@ -758,7 +768,6 @@ "warning": "హెచ్చరిక", "window": "విండో", "yes": "అవును", - "you": "మీరు", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "మీరు" } diff --git a/_locales/th/messages.json b/_locales/th/messages.json index 5f7200117..6d2801f35 100644 --- a/_locales/th/messages.json +++ b/_locales/th/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} และ {other_name} ได้รับการเลื่อนตำแหน่งเป็นผู้ดูแลระบบ", "andMore": "+{count}", "anonymous": "ถูกปิดบัง", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "ซ่อนแถบเมนู", "appearanceLanguage": "ภาษา", "appearanceLanguageDescription": "เลือกการตั้งค่าภาษาสำหรับ Session Session จะรีสตาร์ทเมื่อเปลี่ยนการตั้งค่าภาษา", @@ -151,7 +153,6 @@ "callsSettings": "การโทร (เบต้า)", "callsVoiceAndVideo": "การโทรด้วยเสียงและวิดีโอ.", "callsVoiceAndVideoBeta": "การโทรด้วยเสียงและวิดีโอ (Beta).", - "callsVoiceAndVideoModalDescription": "IP ของคุณจะสามารถมองเห็นได้โดยคู่สายของคุณและเซิร์ฟเวอร์ของ Oxen Foundation ในขณะที่ใช้เบต้าการโทร", "callsVoiceAndVideoToggleDescription": "เปิดการโทรด้วยเสียงและวิดีโอไปยังและจากผู้ใช้รายอื่น", "callsYouCalled": "คุณได้โทรหา {name}", "callsYouMissedCallPermissions": "คุณพลาดสายจาก {name}​ เพราะคุณไม่ได้เปิดใช้งาน การโทรด้วยเสียงและวิดีโอ ในการตั้งค่าความเป็นส่วนตัว", @@ -525,6 +526,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} ข้อความเสียง", "messages": "ข้อความ", "minimize": "ย่อลง", + "networkName": "Session Network", "next": "ถัดไป", "nicknameDescription": "เลือกชื่อเล่นสำหรับ {name} จะปรากฏในการสนทนาหนึ่งต่อหนึ่งและกลุ่ม", "nicknameEnter": "ป้อนชื่อเล่น", @@ -598,6 +600,7 @@ "onsErrorUnableToSearch": "เราไม่สามารถค้นหาระบบ ONS นี้ได้ กรุณาลองอีกครั้งในภายหลัง", "open": "เปิด", "other": "ที่อื่น", + "oxenFoundation": "Oxen Foundation", "passwordChange": "เปลี่ยนรหัสผ่าน", "passwordConfirm": "Confirm password", "passwordCurrentIncorrect": "รหัสผ่านปัจจุบันของคุณไม่ถูกต้อง", @@ -706,9 +709,12 @@ "sessionAppearance": "ลักษณะที่ปรากฎ", "sessionClearData": "ลบข้อมูล", "sessionConversations": "การสนทนา", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "ช่วยเหลือ", "sessionInviteAFriend": "เชิญเพื่อน", "sessionMessageRequests": "ข้อความร้องขอ", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "การแจ้งเตือน", "sessionPermissions": "สิทธิ์", "sessionPrivacy": "ความเป็นส่วนตัว", @@ -724,12 +730,15 @@ "show": "แสดง", "showAll": "แสดงทั้งหมด", "showLess": "แสดงน้อยลง", + "stakingRewardPool": "Staking Reward Pool", "stickers": "สติกเกอร์", "supportGoTo": "ไปที่หน้าการสนับสนุน", "systemInformationDesktop": "ข้อมูลระบบ: {information}", "theContinue": "ไปต่อ", "theDefault": "ค่าเริ่มต้น", "theError": "ข้อผิดพลาด", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "ลองอีกครั้ง", "typingIndicators": "บ่งชี้การพิมพ์", "typingIndicatorsDescription": "ดูและแชร์ตัวบ่งชี้การพิมพ์", @@ -749,6 +758,7 @@ "urlOpen": "เปิด URL", "urlOpenBrowser": "สิ่งนี้จะเปิดในเบราว์เซอร์ของคุณ", "urlOpenDescription": "คุณแน่ใจหรือไม่ว่าต้องการเปิด URL นี้ในเบราว์เซอร์ของคุณ?

{url}", + "usdNameShort": "USD", "useFastMode": "ใช้โหมดเร็ว.", "video": "วิดีโอ.", "videoErrorPlay": "เล่นวิดีโอไม่ได้.", @@ -758,7 +768,6 @@ "warning": "คำเตือน", "window": "หน้าต่าง", "yes": "ใช่", - "you": "คุณ", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "คุณ" } diff --git a/_locales/tl/messages.json b/_locales/tl/messages.json index 461375e1b..f67bf2921 100644 --- a/_locales/tl/messages.json +++ b/_locales/tl/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} at {other_name} ay na-promote na Admin.", "andMore": "+{count}", "anonymous": "Anonymous", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Itago ang Menu Bar", "appearanceLanguage": "Wika", "appearanceLanguageDescription": "Pumili ng language setting para sa Session. Magsisimula muli ang Session kapag binago mo ang language setting.", @@ -151,7 +153,6 @@ "callsSettings": "Mga Tawag (Beta)", "callsVoiceAndVideo": "Mga Voice at Video Call", "callsVoiceAndVideoBeta": "Mga Voice at Video Call (Beta)", - "callsVoiceAndVideoModalDescription": "Nakikita ang iyong IP sa iyong kasama sa tawag at sa server ng Oxen Foundation habang gumagamit ng beta calls.", "callsVoiceAndVideoToggleDescription": "Ini-enable ang mga voice at video call papunta at mula sa iba pang mga user.", "callsYouCalled": "Tinawagan mo si {name}", "callsYouMissedCallPermissions": "Namiss mo ang tawag mula kay {name} dahil hindi mo pinagana ang Mga Tawag sa Boses at Video sa Privacy Settings.", @@ -525,6 +526,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Mensahe ng Boses", "messages": "Mga mensahe", "minimize": "Paliitin", + "networkName": "Session Network", "next": "Susunod", "nicknameDescription": "Pumili ng palayaw para kay {name}. Ito ay lalabas sa one-to-one at mga pag-uusap sa grupo.", "nicknameEnter": "Maglagay ng nickname", @@ -598,6 +600,7 @@ "onsErrorUnableToSearch": "Hindi namin mahanap ang ONS na ito. Paki-subukan muli mamaya.", "open": "Buksan", "other": "Iba pa", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Palitan ang Password", "passwordConfirm": "Kumpirmahin ang password", "passwordCurrentIncorrect": "Mali ang iyong kasalukuyang password.", @@ -706,9 +709,12 @@ "sessionAppearance": "Hitsura", "sessionClearData": "Burahin ang Data", "sessionConversations": "Mga Usapan", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Tulong", "sessionInviteAFriend": "Mag-imbita ng Kaibigan", "sessionMessageRequests": "Mga Kahilingan sa Pagmemensahe", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Mga Notipikasyon", "sessionPermissions": "Mga Pahintulot", "sessionPrivacy": "Privacy", @@ -724,12 +730,15 @@ "show": "Ipakita", "showAll": "Ipakita ang Lahat", "showLess": "Magpakita ng mas kaunti", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Mga Sticker", "supportGoTo": "Pumunta sa Pahina ng Suporta", "systemInformationDesktop": "Impormasyon ng Sistema: {information}", "theContinue": "Magpatuloy", "theDefault": "Default", "theError": "Error", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Try Again", "typingIndicators": "Mga Indikasyon ng Pag-type", "typingIndicatorsDescription": "Tingnan at i-share ang mga indikasyon ng pag-type sa mga one-to-one na chat.", @@ -749,6 +758,7 @@ "urlOpen": "Buksan ang URL", "urlOpenBrowser": "Ito ay magbubukas sa iyong browser.", "urlOpenDescription": "Sigurado ka bang gusto mong buksan ang URL na ito sa iyong browser?

{url}", + "usdNameShort": "USD", "useFastMode": "Gamitin ang Fast Mode", "video": "Video", "videoErrorPlay": "Hindi ma-play ang video.", @@ -758,7 +768,6 @@ "warning": "Babala", "window": "Window", "yes": "Oo", - "you": "Ikaw", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Ikaw" } diff --git a/_locales/tr/messages.json b/_locales/tr/messages.json index b8ec69acb..ab68e011a 100644 --- a/_locales/tr/messages.json +++ b/_locales/tr/messages.json @@ -56,12 +56,14 @@ "appIconEnableIconAndName": "Alternatif uygulama ikonu ve ismi kullan", "appIconSelect": "Alternatif uygulama ikonu seç", "appIconSelectionTitle": "İkon", + "appName": "Session", "appNameCalculator": "Hesap makinesi", "appNameMeetingSE": "MeetingSE", "appNameNews": "Haberler", "appNameNotes": "Notlar", "appNameStocks": "Borsa", "appNameWeather": "Hava Durumu", + "appPro": "Session Pro", "appearanceHideMenuBar": "Menü Çubuğunu Gizle", "appearanceLanguage": "Dil", "appearanceLanguageDescription": "Session dil ayarınızı seçin. Dil ayarınızı değiştirdiğinizde Session yeniden başlatılacak.", @@ -180,7 +182,6 @@ "callsSettings": "Aramalar (Beta)", "callsVoiceAndVideo": "Sesli ve Görüntülü Aramalar", "callsVoiceAndVideoBeta": "Sesli ve Görüntülü Aramalar (Deneme Aşamasında)", - "callsVoiceAndVideoModalDescription": "Deneme aramaları sırasında IP adresiniz arama ortağınıza ve Oxen Foundation sunucusuna görünür olacaktır.", "callsVoiceAndVideoToggleDescription": "Diğer kullanıcılara ve diğer kullanıcılardan sesli ve görüntülü arama yapılmasını sağlar.", "callsYouCalled": "{name} kullanıcısını aradınız", "callsYouMissedCallPermissions": "{name} kişisinden gelen bir çağrıyı, Ses ve Video Görüşmeleri özelliğini Gizlilik Ayarlarında etkinleştirmediğiniz için kaçırdınız.", @@ -615,6 +616,7 @@ "modalMessageCharacterTooLongTitle": "Mesaj çok uzun", "modalMessageTooLongDescription": "Lütfen mesajınızı {limit} karakter veya daha az olacak şekilde kısaltın.", "modalMessageTooLongTitle": "Mesaj çok uzun", + "networkName": "Session Network", "next": "İleri", "nicknameDescription": "{name} için bir takma ad seçin. Bu, bire bir ve grup sohbetlerinizde size görünecektir.", "nicknameEnter": "Bir kullanıcı adı girin", @@ -692,6 +694,7 @@ "onsErrorUnableToSearch": "Bu ONS'u arayamadık. Lütfen daha sonra tekrar deneyin.", "open": "Aç", "other": "Diğer", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Parolayı Değiştir", "passwordConfirm": "Şifreyi Doğrula", "passwordCurrentIncorrect": "Mevcut şifreniz yanlış.", @@ -840,10 +843,13 @@ "sessionAppearance": "Görünüm", "sessionClearData": "Verileri Temizle", "sessionConversations": "Sohbetler", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Yardım", "sessionInviteAFriend": "Bir Arkadaş Davet Et", "sessionMessageRequests": "İleti İstekleri", "sessionNetworkCurrentPrice": "Güncel SESH fiyatı", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNetworkDescription": "Mesajlar, Session Network kullanılarak gönderilir. Ağ, Session Token ile teşvik edilen düğümlerden oluşur; bu da Session uygulamasını merkeziyetsiz ve güvenli tutar. Daha Fazla Bilgi {icon}", "sessionNetworkLearnAboutStaking": "Staking Hakkında Bilgi Edinin", "sessionNetworkMarketCap": "Piyasa Değeri", @@ -872,6 +878,7 @@ "showLess": "Daha az göster", "showNoteToSelf": "Kendime Notu Göster", "showNoteToSelfDescription": "Kendime Not'u sohbet listenizde göstermek istediğinizden emin misiniz?", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Çıkartmalar", "supportGoTo": "Destek Sayfasına Git", "systemInformationDesktop": "Sistem Bilgisi: {information}", @@ -879,6 +886,8 @@ "theContinue": "Devam et", "theDefault": "Varsayılan", "theError": "Hata", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tooltipAccountIdVisible": "{name} adlı kişinin Hesap Kimliği, önceki etkileşimlerinize dayanarak görünür durumdadır", "tooltipBlindedIdCommunities": "Körleştirilmiş Kimlikler, istenmeyen mesajları (spam) azaltmak ve gizliliği artırmak için topluluklarda kullanılır", "tryAgain": "Tekrar Dene", @@ -907,6 +916,7 @@ "urlOpen": "URL açılsın mı", "urlOpenBrowser": "Bu tarayıcınızda açılacak.", "urlOpenDescription": "Bu URL'yi tarayıcınızda açmak istediğinizden emin misiniz?

{url}", + "usdNameShort": "USD", "useFastMode": "Hızlı Modu Kullan", "video": "Video", "videoErrorPlay": "Video oynatılamıyor.", @@ -918,7 +928,6 @@ "warning": "Uyarı", "window": "Pencere", "yes": "Evet", - "you": "Siz", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Siz" } diff --git a/_locales/uk/messages.json b/_locales/uk/messages.json index 95f30b7bf..27a195fa5 100644 --- a/_locales/uk/messages.json +++ b/_locales/uk/messages.json @@ -56,12 +56,14 @@ "appIconEnableIconAndName": "Використовувати альтернативний значок застосунку та назву", "appIconSelect": "Обрати альтернативний значок застосунку", "appIconSelectionTitle": "Значок", + "appName": "Session", "appNameCalculator": "Калькулятор", "appNameMeetingSE": "MeetingSE", "appNameNews": "Новини", "appNameNotes": "Нотатки", "appNameStocks": "Акції", "appNameWeather": "Погода", + "appPro": "Session Pro", "appearanceHideMenuBar": "Сховати панель меню", "appearanceLanguage": "Мова", "appearanceLanguageDescription": "Виберіть мовні налаштування для Session. Session перезапуститься при зміні мовного налаштування.", @@ -180,7 +182,6 @@ "callsSettings": "Дзвінки (Beta)", "callsVoiceAndVideo": "Голосові та відеодзвінки", "callsVoiceAndVideoBeta": "Голосові та відеодзвінки (бета-версія)", - "callsVoiceAndVideoModalDescription": "Ваша IP-адреса видима вашому партнеру по дзвінку та серверу Oxen Foundation при використанні бета-дзвінків.", "callsVoiceAndVideoToggleDescription": "Дозволяє голосові та відеодзвінки з іншими користувачами.", "callsYouCalled": "Ви дзвонили {name}", "callsYouMissedCallPermissions": "Ви пропустили дзвінок від {name}, бо не увімкнули Голосові та відеодзвінки у налаштуваннях конфіденційності.", @@ -414,7 +415,7 @@ "forever": "Завжди", "from": "Від:", "fullScreenToggle": "Увійти до повноекранного режиму", - "gif": "ГІФ", + "gif": "GIF", "giphyWarning": "Giphy", "giphyWarningDescription": "Session під'єднається до Giphy для надання результатів пошуку. У вас не буде повного захисту метаданих при відправленні GIF-файлів.", "giveFeedback": "Залишити відгук?", @@ -621,6 +622,7 @@ "modalMessageCharacterTooLongTitle": "Задовге повідомлення", "modalMessageTooLongDescription": "Будь ласка, скоротіть повідомлення до {limit} символів або менше.", "modalMessageTooLongTitle": "Задовге повідомлення", + "networkName": "Session Network", "next": "Далі", "nicknameDescription": "Виберіть псевдонім для {name}. Він з'являтиметься в особистих та групових розмовах.", "nicknameEnter": "Введіть псевдонім", @@ -699,6 +701,7 @@ "open": "Відкрити", "openSurvey": "Пройти опитування", "other": "Інші", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Змінити пароль", "passwordConfirm": "Підтвердіть пароль", "passwordCurrentIncorrect": "Ваш поточний пароль невірний.", @@ -860,10 +863,13 @@ "sessionAppearance": "Зовнішній вигляд", "sessionClearData": "Очистити дані", "sessionConversations": "Розмови", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Допомога", "sessionInviteAFriend": "Запросити друга", "sessionMessageRequests": "Запити на повідомлення", "sessionNetworkCurrentPrice": "Поточна ціна SESH", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNetworkDescription": "Повідомлення надсилаються за допомогою Session Network. Мережа складається з вузлів, заохочуваних Session Token, що забезпечує децентралізацію та безпеку Session. Дізнатися більше {icon}", "sessionNetworkLearnAboutStaking": "Дізнайтеся про стейкінг", "sessionNetworkMarketCap": "Ринкова капіталізація", @@ -892,6 +898,7 @@ "showLess": "Показати менше", "showNoteToSelf": "Показати нотатку для себе", "showNoteToSelfDescription": "Ви впевнені, що хочете показувати Нотатку для себе у вашому списку розмов?", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Стікери", "supportGoTo": "Перейти на сторінку підтримки", "systemInformationDesktop": "Про систему: {information}", @@ -899,6 +906,8 @@ "theContinue": "Продовжити", "theDefault": "За Замовчуванням", "theError": "Помилка", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tooltipAccountIdVisible": "Account ID {name} видимий через вашу попередню взаємодію", "tooltipBlindedIdCommunities": "Знеособлені ID використовуються у спільнотах задля зменшення кількості небажаних повідомлень та підвищення приватності", "tryAgain": "Спробуйте ще", @@ -927,6 +936,7 @@ "urlOpen": "Відкрити URL-адресу", "urlOpenBrowser": "Це відкриється у вашому браузері.", "urlOpenDescription": "Ви впевнені, що хочете відкрити цю URL-адресу у своєму браузері?

{url}", + "usdNameShort": "USD", "useFastMode": "Використовувати швидкий режим", "video": "Відео", "videoErrorPlay": "Не вдається відтворити відео.", @@ -938,7 +948,6 @@ "warning": "Попередження", "window": "Вікно", "yes": "Так", - "you": "Ви", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Ви" } diff --git a/_locales/ur/messages.json b/_locales/ur/messages.json index f0223398a..28ef096bc 100644 --- a/_locales/ur/messages.json +++ b/_locales/ur/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} اور {other_name} کو ایڈمن مقرر کیا گیا۔", "andMore": "+{count}", "anonymous": "گمنام", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "مینیو بار چھپائیں", "appearanceLanguage": "زبان", "appearanceLanguageDescription": "Session کے لیے اپنی زبان کی ترتیب منتخب کریں۔ جب آپ اپنی زبان کی ترتیب تبدیل کریں گے تو Session دوبارہ شروع ہو جائے گا۔", @@ -148,7 +150,6 @@ "callsSettings": "کالز (بیٹا)", "callsVoiceAndVideo": "وائس اور ویڈیو کالز", "callsVoiceAndVideoBeta": "وائس اور ویڈیو کالز (بیٹا)", - "callsVoiceAndVideoModalDescription": "بیٹا کالز استعمال کرتے وقت آپ کا آئی پی آپ کے کال پارٹنر اور ایک اوکسن فاؤنڈیشن سرور کو نظر آئے گا۔", "callsVoiceAndVideoToggleDescription": "دیگر صارفین کے ساتھ وائس اور ویڈیو کالز کو فعال کریں.", "callsYouCalled": "آپ نے {name} کو کال کی", "callsYouMissedCallPermissions": "آپ نے ایک کال یاد کر دی {name} کی وجہ سے کیونکہ آپ نے وائس اور ویڈیو کالز کو پرائیویسی سیٹنگز میں فعال نہیں کیا ہے۔", @@ -529,6 +530,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Voice Message", "messages": "پیغامات", "minimize": "منیمائز کریں", + "networkName": "Session Network", "next": "اگلا", "nicknameDescription": "{name} کے لئے ایک عرفی نام منتخب کریں۔ یہ آپ کو آپ کی ایک سے ایک اور گروپ گفتگو میں ظاہر ہوگا۔", "nicknameEnter": "عرفیت درج کریں", @@ -603,6 +605,7 @@ "onsErrorUnableToSearch": "ہم اس ONS کے لیے تلاش کرنے میں ناکام رہے۔ براہ کرم بعد میں دوبارہ کوشش کریں۔", "open": "کھولیں", "other": "دیگر", + "oxenFoundation": "Oxen Foundation", "passwordChange": "پاس ورڈ تبدیل کریں", "passwordConfirm": "پاس ورڈ کی تصدیق کریں", "passwordCurrentIncorrect": "آپ کا موجودہ پاس ورڈ غلط ہے۔", @@ -711,9 +714,12 @@ "sessionAppearance": "حضور", "sessionClearData": "ڈیٹا صاف کریں", "sessionConversations": "مکالمات", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "مدد", "sessionInviteAFriend": "دوست کو مدعو کریں", "sessionMessageRequests": "پیغام کی درخواستیں", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "اطلاعات", "sessionPermissions": "اجازتیں", "sessionPrivacy": "پرائیویسی", @@ -729,12 +735,15 @@ "show": "دکھائیں", "showAll": "سب دکھائیں", "showLess": "کم دکھائیں", + "stakingRewardPool": "Staking Reward Pool", "stickers": "اسٹیکرز", "supportGoTo": "سپورٹ پیج پر جائیں", "systemInformationDesktop": "سسٹم معلومات: {information}", "theContinue": "جاری رکھیں", "theDefault": "ڈیفالٹ", "theError": "غلطی", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "دوبارہ کوشش کریں", "typingIndicators": "ٹائپ کرنے کے اشارے", "typingIndicatorsDescription": "ٹائپنگ کے اشارے دیکھیں اور شیئر کریں.", @@ -754,6 +763,7 @@ "urlOpen": "یو آر ایل کھولیں", "urlOpenBrowser": "یہ آپ کے براؤزر میں کھلے گا۔", "urlOpenDescription": "کیا آپ واقعی اس لنک کو اپنے براؤزر میں کھولنا چاہتے ہیں؟

{url}", + "usdNameShort": "USD", "useFastMode": "فاسٹ موڈ استعمال کریں", "video": "ویڈیو", "videoErrorPlay": "ویڈیو چلانے سے قاصر.", @@ -763,7 +773,6 @@ "warning": "انتباہ", "window": "ونڈو", "yes": "جی ہاں", - "you": "آپ", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "آپ" } diff --git a/_locales/uz/messages.json b/_locales/uz/messages.json index 4c9791d3c..be44fbdf7 100644 --- a/_locales/uz/messages.json +++ b/_locales/uz/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} va {other_name} Administrator darajasiga ko'tarildi.", "andMore": "+{count}", "anonymous": "Anonim", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Menyu panelini yashirish", "appearanceLanguage": "Til", "appearanceLanguageDescription": "Session uchun til sozlamangizni tanlang. Tilingizni o'zgartirganingizda Session qayta ishga tushadi.", @@ -151,7 +153,6 @@ "callsSettings": "Qo'ng'iroqlar (Beta)", "callsVoiceAndVideo": "Ovozli va video qo'ng'iroqlar", "callsVoiceAndVideoBeta": "Ovozli va video qo'ng'iroqlar (Beta)", - "callsVoiceAndVideoModalDescription": "Hozirgi parolingiz noto'g'ri.", "callsVoiceAndVideoToggleDescription": "Boshqa foydalanuvchilar bilan ovozli va video qo'ng'iroqlarni amalga oshirish imkonini beradi.", "callsYouCalled": "Siz {name}ga qo'ng'iroq qildingiz", "callsYouMissedCallPermissions": "Sizdan {name} dan qo'ng'iroqni o'tkazib yubordingiz, chunki Xavfsizlik sozlamalarida Ovozli va video qo'ng'iroqlar ni yoqmagansiz.", @@ -525,6 +526,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Ovozli xabar", "messages": "Xabarlar", "minimize": "Ihchamlahstirish", + "networkName": "Session Network", "next": "Keyingi", "nicknameDescription": "{name} uchun bir taxallus tanlang. Bu, sizning bir-birli va guruh suhbatlaringizda ko'rinadi.", "nicknameEnter": "Taxallusni kiritish", @@ -598,6 +600,7 @@ "onsErrorUnableToSearch": "Biz bu ONSni qidirib topa olmadik. Iltimos keyinroq qayta urinib ko'ring.", "open": "Ochish", "other": "Boshqa", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Parolni o'zgartirish", "passwordConfirm": "Parolni tasdiqlash", "passwordCurrentIncorrect": "Sizning joriy parolingiz noto'g'ri.", @@ -706,9 +709,12 @@ "sessionAppearance": "Ko'rinish", "sessionClearData": "Ma'lumotlarni tozalash", "sessionConversations": "Suhbatlar", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Yordam", "sessionInviteAFriend": "Do'stni taklif qilish", "sessionMessageRequests": "Xabar So'rovlari", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Bildirishnomalar", "sessionPermissions": "Ruxsatlar", "sessionPrivacy": "Maxfiylik", @@ -724,12 +730,15 @@ "show": "Ochish", "showAll": "Barchasini ko'rsatish", "showLess": "Kamroq ko'rsatish", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Stikerlar", "supportGoTo": "Yordamchilar sahifasini och", "systemInformationDesktop": "Tizim ma'lumotlari: {information}", "theContinue": "Davom etish", "theDefault": "Standart", "theError": "Xato", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Qayta urinish", "typingIndicators": "Yozish ko'rsatkichlari", "typingIndicatorsDescription": "Yozish ko'rsatkichlarini ko'rish va ulashish.", @@ -749,6 +758,7 @@ "urlOpen": "URLni ochish", "urlOpenBrowser": "Bu brauzeringizda ochiladi.", "urlOpenDescription": "Haqiqatan ham ushbu URLni brauzeringizda ochmoqchimisiz?

{url}", + "usdNameShort": "USD", "useFastMode": "Tez rejimdan foydalanish", "video": "Video", "videoErrorPlay": "Videoni ijro eta olmayman.", @@ -758,7 +768,6 @@ "warning": "Ogohlantirish", "window": "Oyna", "yes": "Ha", - "you": "Siz", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Siz" } diff --git a/_locales/vi/messages.json b/_locales/vi/messages.json index bed6363a7..670694361 100644 --- a/_locales/vi/messages.json +++ b/_locales/vi/messages.json @@ -49,11 +49,13 @@ "appIconEnableIconAndName": "Sử dụng biểu tượng và tên thay thế cho ứng dụng", "appIconSelect": "Chọn biểu tượng ứng dụng thay thế", "appIconSelectionTitle": "Biểu tượng", + "appName": "Session", "appNameCalculator": "Máy tính", "appNameNews": "Tin tức", "appNameNotes": "Ghi chú", "appNameStocks": "Chứng khoán", "appNameWeather": "Thời tiết", + "appPro": "Session Pro", "appearanceHideMenuBar": "Ẩn thanh Menu", "appearanceLanguage": "Ngôn ngữ", "appearanceLanguageDescription": "Chọn cài đặt ngôn ngữ của bạn cho Session. Session sẽ khởi động lại khi bạn thay đổi cài đặt ngôn ngữ.", @@ -167,7 +169,6 @@ "callsSettings": "Cuộc gọi (Beta)", "callsVoiceAndVideo": "Cuộc gọi thoại và video", "callsVoiceAndVideoBeta": "Các cuộc gọi giọng nói và video (Beta)", - "callsVoiceAndVideoModalDescription": "Địa chỉ IP của bạn hiển thị với đối tác cuộc gọi và máy chủ Oxen Foundation trong khi sử dụng cuộc gọi beta.", "callsVoiceAndVideoToggleDescription": "Cho phép thực hiện cuộc gọi giọng nói và video với người dùng khác.", "callsYouCalled": "Bạn đã gọi {name}", "callsYouMissedCallPermissions": "Bạn đã bỏ lỡ cuộc gọi từ {name} vì bạn chưa bật Cuộc gọi Điện thoại và Video trong Cài đặt Quyền riêng tư.", @@ -577,6 +578,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Tin nhắn thoại", "messages": "Tin nhắn", "minimize": "Thu nhỏ", + "networkName": "Session Network", "next": "Tiếp", "nicknameDescription": "Chọn một biệt danh cho {name}. Điều này sẽ xuất hiện với bạn trong các cuộc trò chuyện một-một và nhóm.", "nicknameEnter": "Nhập biệt danh", @@ -652,6 +654,7 @@ "onsErrorUnableToSearch": "Chúng tôi không thể tìm kiếm ONS này. Vui lòng thử lại sau.", "open": "Mở", "other": "Khác", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Đổi mật khẩu", "passwordConfirm": "Xác nhận mật khẩu", "passwordCurrentIncorrect": "Mật khẩu hiện tại của bạn không chính xác.", @@ -770,9 +773,12 @@ "sessionAppearance": "Diện mạo", "sessionClearData": "Xóa dữ liệu", "sessionConversations": "Chuyện trò", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Trợ giúp", "sessionInviteAFriend": "Mời bạn", "sessionMessageRequests": "Các yêu cầu tin nhắn", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Thông báo", "sessionPermissions": "Quyền", "sessionPrivacy": "Riêng tư", @@ -789,6 +795,7 @@ "show": "Hiển thị", "showAll": "Hiển thị tất cả", "showLess": "Hiển thị ít hơn", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Hình dán", "supportGoTo": "Đi đến trang Hỗ trợ", "systemInformationDesktop": "Thông tin hệ thống: {information}", @@ -796,6 +803,8 @@ "theContinue": "Tiếp tục", "theDefault": "Mặc định", "theError": "Lỗi", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Thử lại", "typingIndicators": "Chỉ báo nhập văn bản", "typingIndicatorsDescription": "Xem và chia sẻ các chỉ báo đang gõ.", @@ -817,6 +826,7 @@ "urlOpen": "Mở URL", "urlOpenBrowser": "Điều này sẽ mở trong trình duyệt của bạn.", "urlOpenDescription": "Bạn có chắc chắn rằng bạn muốn mở URL này trong trình duyệt của bạn?

{url}", + "usdNameShort": "USD", "useFastMode": "Sử dụng Chế độ Nhanh", "video": "Video", "videoErrorPlay": "Không thể phát video.", @@ -826,7 +836,6 @@ "warning": "Cảnh báo", "window": "Cửa sổ", "yes": "Có", - "you": "Bạn", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Bạn" } diff --git a/_locales/xh/messages.json b/_locales/xh/messages.json index 4ead10beb..a61fa06c0 100644 --- a/_locales/xh/messages.json +++ b/_locales/xh/messages.json @@ -39,6 +39,8 @@ "adminTwoPromotedToAdmin": "{name} kunye {other_name} banyuselwe kubu-Admin.", "andMore": "+{count}", "anonymous": "Ogama lingaziwayo", + "appName": "Session", + "appPro": "Session Pro", "appearanceHideMenuBar": "Fihla iiMenyu Bar", "appearanceLanguage": "Ulwimi", "appearanceLanguageDescription": "Khetha useto lolwimi lwakho lwe-Session. Session iya kuqalisa kwakhona xa utshintsha useto lolwimi lwakho.", @@ -151,7 +153,6 @@ "callsSettings": "Iitsalela (Beta)", "callsVoiceAndVideo": "Iifowuni zeSandi neeVidiyo", "callsVoiceAndVideoBeta": "Iifowuni zeSandi neeVidiyo (Beta)", - "callsVoiceAndVideoModalDescription": "I-IP yakho iyabonakala komnxibelele wakho nakwiOxen Foundation Server ngelixa usebenzisa i-beta calls.", "callsVoiceAndVideoToggleDescription": "Vumela i-voice ne-video calls ukuba zithumeletyayanayo nabanye abasebenzisi.", "callsYouCalled": "Wakubidde {name}", "callsYouMissedCallPermissions": "Uphoswe ngumnxeba ovela ku {name} kuba awuvulanga iVoice and Video Calls kuSeto loBukeko Olwahlukileyo.", @@ -525,6 +526,7 @@ "messageVoiceSnippetGroup": "{author}: {emoji} Umyalezo weSandi", "messages": "Imiyalezo", "minimize": "Minimize", + "networkName": "Session Network", "next": "Okulandelayo", "nicknameDescription": "Khetha igama lesidlaliso ku {name}. Oku kuya kubonakala kuwe kwiincoko zakho zijongene nezimbini.", "nicknameEnter": "Ngenisa i-nickname", @@ -598,6 +600,7 @@ "onsErrorUnableToSearch": "Asikwazanga ukufuna le ONS. Nceda uzame kwakhona kamva.", "open": "Vula", "other": "Okunye", + "oxenFoundation": "Oxen Foundation", "passwordChange": "Tshintsha Ipassword", "passwordConfirm": "Qinisekisa iphasiwedi", "passwordCurrentIncorrect": "Iphasiwedi yakho yangoku ayichaneki.", @@ -706,9 +709,12 @@ "sessionAppearance": "Ndabika", "sessionClearData": "Coca Idatha", "sessionConversations": "Iincoko", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "Uncedo", "sessionInviteAFriend": "Mema umhlobo", "sessionMessageRequests": "Izicelo zoMyalezo", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNotifications": "Izaziso", "sessionPermissions": "Izimvume", "sessionPrivacy": "Ubumfihlo", @@ -724,12 +730,15 @@ "show": "Show", "showAll": "Show All", "showLess": "Show Less", + "stakingRewardPool": "Staking Reward Pool", "stickers": "Stickers", "supportGoTo": "Yiya ku Iphepha leNkxaso", "systemInformationDesktop": "Ulwazi lweNkqubo: {information}", "theContinue": "Qhubeka", "theDefault": "Okungagqibekanga", "theError": "Impazamo", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tryAgain": "Zama kwakhona", "typingIndicators": "Iimpawu zokuChwetheza", "typingIndicatorsDescription": "Jonga kwaye wabelane ngezikhombisi zokuchwetheza.", @@ -749,6 +758,7 @@ "urlOpen": "Vula i-URL", "urlOpenBrowser": "Oku kuya kuvula kwisikhangeli sakho.", "urlOpenDescription": "Uqinisekile ukuba ufuna ukuvula le URL kwisikhangeli sakho?

{url}", + "usdNameShort": "USD", "useFastMode": "Sebenzisa Imowudi Ekhawulezayo", "video": "Vidiyo", "videoErrorPlay": "Ayikwazi ukudlala ividiyo.", @@ -758,7 +768,6 @@ "warning": "Isilumkiso", "window": "Window", "yes": "Ewe", - "you": "Gwe", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "Gwe" } diff --git a/_locales/zh-CN/messages.json b/_locales/zh-CN/messages.json index 3e3d7b814..7e8d45951 100644 --- a/_locales/zh-CN/messages.json +++ b/_locales/zh-CN/messages.json @@ -56,12 +56,14 @@ "appIconEnableIconAndName": "使用替代的应用图标与应用名", "appIconSelect": "选择替代的应用图标", "appIconSelectionTitle": "图标", + "appName": "Session", "appNameCalculator": "计算器", "appNameMeetingSE": "SE云会议", "appNameNews": "新闻", "appNameNotes": "笔记", "appNameStocks": "股票", "appNameWeather": "天气", + "appPro": "Session Pro", "appearanceHideMenuBar": "隐藏菜单栏", "appearanceLanguage": "语言", "appearanceLanguageDescription": "选择Session的语言设置。更改语言设置后Session将重新启动。", @@ -180,7 +182,6 @@ "callsSettings": "语音通话 (测试版)", "callsVoiceAndVideo": "语音和视频通话", "callsVoiceAndVideoBeta": "语音和视频通话(测试版)", - "callsVoiceAndVideoModalDescription": "在使用测试版通话时,您的IP会暴露给您的通话对象和Oxen Foundation服务器。", "callsVoiceAndVideoToggleDescription": "允许来自其它用户的语音和视频通话。", "callsYouCalled": "您呼叫了{name}", "callsYouMissedCallPermissions": "您未在隐私设置中启用语音和视频通话,因此错过了来自{name}的通话。", @@ -623,6 +624,7 @@ "modalMessageCharacterTooLongTitle": "消息太长", "modalMessageTooLongDescription": "请将消息缩短至 {limit} 个字符或更少。", "modalMessageTooLongTitle": "消息太长", + "networkName": "Session Network", "next": "下一步", "nicknameDescription": "为 {name}选择一个昵称。该昵称将在您的一对一和群组对话中显示。", "nicknameEnter": "输入昵称", @@ -701,6 +703,7 @@ "open": "打开", "openSurvey": "打开调查问卷", "other": "其它", + "oxenFoundation": "Oxen Foundation", "passwordChange": "更改密码", "passwordConfirm": "确认密码", "passwordCurrentIncorrect": "您当前的密码不正确。", @@ -863,10 +866,13 @@ "sessionAppearance": "外观", "sessionClearData": "清除数据", "sessionConversations": "会话", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "帮助", "sessionInviteAFriend": "邀请好友", "sessionMessageRequests": "消息请求", "sessionNetworkCurrentPrice": "当前 SESH 价格", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNetworkDescription": "消息通过 Session Network 发送。该网络由通过 Session Token 激励的节点组成,使 Session 实现去中心化并保持安全。了解更多 {icon}", "sessionNetworkLearnAboutStaking": "了解 Staking", "sessionNetworkMarketCap": "市值", @@ -895,6 +901,7 @@ "showLess": "收起", "showNoteToSelf": "显示备忘录", "showNoteToSelfDescription": "你确定要在对话列表中显示 Note to Self吗?", + "stakingRewardPool": "Staking Reward Pool", "stickers": "贴图", "supportGoTo": "跳转到支持页面", "systemInformationDesktop": "系统信息:{information}", @@ -902,6 +909,8 @@ "theContinue": "继续", "theDefault": "默认", "theError": "错误", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tooltipAccountIdVisible": "基于您与 {name} 之前的互动,其 Account ID 对您可见", "tooltipBlindedIdCommunities": "盲化 ID 在社区中用于减少垃圾信息并提高隐私性", "tryAgain": "重试", @@ -934,6 +943,7 @@ "urlOpen": "打开链接", "urlOpenBrowser": "该链接将在您的浏览器中打开。", "urlOpenDescription": "您确定要在浏览器中打开此链接吗?

{url}", + "usdNameShort": "USD", "useFastMode": "使用快速模式", "video": "视频", "videoErrorPlay": "无法播放视频。", @@ -945,7 +955,6 @@ "warning": "警告", "window": "窗口", "yes": "是", - "you": "您", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "您" } diff --git a/_locales/zh-TW/messages.json b/_locales/zh-TW/messages.json index 7ec4ab0e6..f0738ee9b 100644 --- a/_locales/zh-TW/messages.json +++ b/_locales/zh-TW/messages.json @@ -56,12 +56,14 @@ "appIconEnableIconAndName": "使用替代的應用程式圖示與名稱", "appIconSelect": "選擇替代的應用程式圖示", "appIconSelectionTitle": "圖示", + "appName": "Session", "appNameCalculator": "計算機", "appNameMeetingSE": "MeetingSE", "appNameNews": "新聞", "appNameNotes": "筆記", "appNameStocks": "股票", "appNameWeather": "天氣", + "appPro": "Session Pro", "appearanceHideMenuBar": "隱藏選單列", "appearanceLanguage": "語言", "appearanceLanguageDescription": "選擇您的語言設定 Session。更改語言設置後 Session 會重新啟動。", @@ -180,7 +182,6 @@ "callsSettings": "通話 (Beta)", "callsVoiceAndVideo": "語音和視訊通話", "callsVoiceAndVideoBeta": "語音和視訊通話 (Beta)", - "callsVoiceAndVideoModalDescription": "您在使用測試版通話時,您的 IP 將會被通話夥伴和 Oxen Foundation 伺服器看到。", "callsVoiceAndVideoToggleDescription": "啟用語音通話和視像通話功能。", "callsYouCalled": "您撥打給 {name}", "callsYouMissedCallPermissions": "您錯過了{name} 的一個通話,因為您沒有在隱私設定中啟用語音和視頻通話。", @@ -624,6 +625,7 @@ "modalMessageCharacterTooLongTitle": "訊息過長", "modalMessageTooLongDescription": "請將您的訊息縮短至 {limit} 個字元或更少。", "modalMessageTooLongTitle": "訊息過長", + "networkName": "Session Network", "next": "下一步", "nicknameDescription": "為 {name} 選擇一個暱稱。這將在您的一對一和群組對話中顯示。", "nicknameEnter": "輸入暱稱", @@ -702,6 +704,7 @@ "open": "開啟", "openSurvey": "開啟問卷", "other": "其他", + "oxenFoundation": "Oxen Foundation", "passwordChange": "變更密碼", "passwordConfirm": "確認密碼", "passwordCurrentIncorrect": "您目前的密碼不正確。", @@ -864,10 +867,13 @@ "sessionAppearance": "外觀", "sessionClearData": "清除資料", "sessionConversations": "對話", + "sessionDownloadUrl": "https://getsession.org/download", + "sessionFoundation": "Session Foundation", "sessionHelp": "幫助", "sessionInviteAFriend": "邀請好友", "sessionMessageRequests": "訊息請求", "sessionNetworkCurrentPrice": "目前 SESH 價格", + "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}", "sessionNetworkDescription": "訊息是透過 Session Network 傳送。該網路由透過 Session Token 提供激勵的節點所組成,這確保了 Session 的去中心化與安全性。了解更多 {icon}", "sessionNetworkLearnAboutStaking": "了解質押", "sessionNetworkMarketCap": "市值", @@ -896,6 +902,7 @@ "showLess": "顯示較少", "showNoteToSelf": "顯示小筆記", "showNoteToSelfDescription": "您確定要在對話列表中顯示 小筆記 嗎?", + "stakingRewardPool": "Staking Reward Pool", "stickers": "貼圖", "supportGoTo": "前往支援頁面", "systemInformationDesktop": "系統資訊:{information}", @@ -903,6 +910,8 @@ "theContinue": "繼續", "theDefault": "預設", "theError": "錯誤", + "tokenNameLong": "Session Token", + "tokenNameShort": "SESH", "tooltipAccountIdVisible": "{name} 的 Account ID 因先前的互動而可見", "tooltipBlindedIdCommunities": "在 Community 中使用隱藏 ID 可減少垃圾訊息並提升隱私", "tryAgain": "再試一次", @@ -935,6 +944,7 @@ "urlOpen": "開啟連結", "urlOpenBrowser": "這將在您的瀏覽器中打開。", "urlOpenDescription": "您確定要在瀏覽器中打開此連結嗎?

{url}", + "usdNameShort": "USD", "useFastMode": "使用快速模式", "video": "影片", "videoErrorPlay": "無法播放影片。", @@ -946,7 +956,6 @@ "warning": "警告", "window": "視窗", "yes": "是", - "you": "你", - "sessionNetworkDataPrice": "Price data powered by CoinGecko
Accurate at {date_time}" + "you": "你" } diff --git a/ts/components/SessionWrapperModal.tsx b/ts/components/SessionWrapperModal.tsx index 99cbdbfc2..714e82b2d 100644 --- a/ts/components/SessionWrapperModal.tsx +++ b/ts/components/SessionWrapperModal.tsx @@ -184,7 +184,7 @@ export const ModalActionsContainer = ({ /** * In the modal, the bottom actions sometimes have a border. - * When they do, they all share the same styling (minWidth 125px) so this component is here to reuse that logic. + * When they do, they all share the same styling (minWidth --modal-actions-outline-min-width) so this component is here to reuse that logic. */ export function ModalBottomButtonWithBorder({ text, @@ -204,9 +204,9 @@ export function ModalBottomButtonWithBorder({ text={text} onClick={onClick} disabled={disabled} - buttonColor={buttonColor ?? SessionButtonColor.PrimaryDark} + buttonColor={buttonColor} dataTestId={dataTestId} - style={{ minWidth: '125px' }} + style={{ minWidth: 'var(--modal-actions-outline-min-width)' }} /> ); } diff --git a/ts/components/buttons/panel/PanelButton.tsx b/ts/components/buttons/panel/PanelButton.tsx index b200b1e51..3d092e84b 100644 --- a/ts/components/buttons/panel/PanelButton.tsx +++ b/ts/components/buttons/panel/PanelButton.tsx @@ -76,6 +76,9 @@ const PanelButtonContainer = styled.div` overflow: auto; min-height: var(--panel-button-container-min-height); max-height: 100%; + display: flex; + flex-direction: column; + overflow: hidden; `; type PanelButtonGroupProps = { @@ -83,11 +86,13 @@ type PanelButtonGroupProps = { style?: CSSProperties; }; -export const PanelButtonGroup = (props: PanelButtonGroupProps) => { - const { children, style } = props; +export const PanelButtonGroup = ( + props: PanelButtonGroupProps & { containerStyle?: CSSProperties } +) => { + const { children, style, containerStyle } = props; return ( - {children} + {children} ); }; @@ -167,13 +172,12 @@ const StyledSubtitle = styled.p<{ color?: string }>` * If a subtitle is provided, it's dataTestId is required too. */ type PanelButtonTextBaseProps = { - text: string; textDataTestId: SessionDataTestId; color?: string; -}; +} & ({ text: TrArgs } | { label: string }); export type PanelButtonSubtextProps = { - subText: string; + subText: TrArgs; subTextDataTestId: SessionDataTestId; }; @@ -197,7 +201,7 @@ function TextOnly(props: PanelButtonTextBaseProps) { - {props.text} + {'text' in props ? : props.label} ); } @@ -218,10 +222,10 @@ export const PanelButtonTextWithSubText = ( ) => { return ( - + - {props.subText} + {props.extraSubTextNode} @@ -231,7 +235,7 @@ export const PanelButtonTextWithSubText = ( export const PanelButtonText = (props: PanelButtonTextBaseProps) => { return ( - + ); }; diff --git a/ts/components/buttons/panel/PanelIconButton.tsx b/ts/components/buttons/panel/PanelIconButton.tsx index b2b219ebf..e1be76afe 100644 --- a/ts/components/buttons/panel/PanelIconButton.tsx +++ b/ts/components/buttons/panel/PanelIconButton.tsx @@ -14,11 +14,12 @@ import { SessionIcon } from '../../icon/SessionIcon'; import type { SessionIconType } from '../../icon'; import type { WithLucideUnicode } from '../../icon/lucide'; import { StyledPanelButtonSeparator } from './StyledPanelButtonGroupSeparator'; +import type { TrArgs } from '../../../localization/localeTools'; type PanelIconButtonProps = Omit & { - text: string; iconElement: ReactNode; color?: string; + text: TrArgs; }; const IconContainer = styled.div` diff --git a/ts/components/buttons/panel/PanelWithButtonInline.tsx b/ts/components/buttons/panel/PanelWithButtonInline.tsx index f444e7f14..75138b40d 100644 --- a/ts/components/buttons/panel/PanelWithButtonInline.tsx +++ b/ts/components/buttons/panel/PanelWithButtonInline.tsx @@ -39,6 +39,8 @@ export const PanelWithButtonInline = (props: PanelWithButtonInlineProps) => { dataTestId={buttonDataTestId} text={buttonText} buttonColor={buttonColor} + // we need this so that the hover effect work (even if the button does not do the onClick itself) + style={{ pointerEvents: 'all' }} /> } /> diff --git a/ts/components/conversation/header/ConversationHeaderSubtitle.tsx b/ts/components/conversation/header/ConversationHeaderSubtitle.tsx index 7dbd57c8d..524f12ce8 100644 --- a/ts/components/conversation/header/ConversationHeaderSubtitle.tsx +++ b/ts/components/conversation/header/ConversationHeaderSubtitle.tsx @@ -4,6 +4,8 @@ import { SessionIconButton } from '../../icon'; import { SubtitleStringsType } from './ConversationHeaderTitle'; import { SessionLucideIconButton } from '../../icon/SessionIconButton'; import { LUCIDE_ICONS_UNICODE } from '../../icon/lucide'; +import type { TrArgs } from '../../../localization/localeTools'; +import { Localizer } from '../../basic/Localizer'; function loadDataTestId(currentSubtitle: SubtitleStringsType) { if (currentSubtitle === 'disappearingMessages') { @@ -66,7 +68,7 @@ export const SubtitleDotMenu = ({ ); -export type SubTitleArray = Array<{ type: SubtitleStringsType; label: string | null }>; +export type SubTitleArray = Array<{ type: SubtitleStringsType } & TrArgs>; type CycleDirection = 1 | -1; @@ -154,7 +156,7 @@ export const ConversationHeaderSubtitle = (props: ConversationHeaderSubtitleProp tabIndex={0} data-testid={loadDataTestId(currentSubtitle.type)} > - {currentSubtitle.label} + diff --git a/ts/components/conversation/header/ConversationHeaderTitle.tsx b/ts/components/conversation/header/ConversationHeaderTitle.tsx index 5642f636d..f344efbb6 100644 --- a/ts/components/conversation/header/ConversationHeaderTitle.tsx +++ b/ts/components/conversation/header/ConversationHeaderTitle.tsx @@ -63,7 +63,7 @@ function useSubtitleArray(convoId?: string) { } if (isGroup && count > 0 && !isKickedFromGroup) { - return tr(isPublic ? 'membersActive' : 'members', { count }); + return { token: isPublic ? 'membersActive' : 'members', count } as const; } return null; @@ -74,16 +74,16 @@ function useSubtitleArray(convoId?: string) { if (disappearingMessageSubtitle.id !== 'off') { innerSubtitleArray.push({ type: 'disappearingMessages', - label: disappearingMessageSubtitle.label, + ...disappearingMessageSubtitle, }); } if (notificationSubtitle) { - innerSubtitleArray.push({ type: 'notifications', label: notificationSubtitle }); + innerSubtitleArray.push({ type: 'notifications', token: notificationSubtitle }); } if (memberCountSubtitle) { - innerSubtitleArray.push({ type: 'members', label: memberCountSubtitle }); + innerSubtitleArray.push({ type: 'members', ...memberCountSubtitle }); } return innerSubtitleArray; }, [disappearingMessageSubtitle, notificationSubtitle, memberCountSubtitle]); diff --git a/ts/components/conversation/right-panel/overlay/message-info/OverlayMessageInfo.tsx b/ts/components/conversation/right-panel/overlay/message-info/OverlayMessageInfo.tsx index bf08e00da..13390246e 100644 --- a/ts/components/conversation/right-panel/overlay/message-info/OverlayMessageInfo.tsx +++ b/ts/components/conversation/right-panel/overlay/message-info/OverlayMessageInfo.tsx @@ -201,7 +201,7 @@ function CopyMessageBodyButton({ messageId }: WithMessageIdOpt) { } return ( } onClick={() => { clipboard.writeText(messageBody || ''); @@ -219,7 +219,7 @@ function ReplyToMessageButton({ messageId }: WithMessageIdOpt) { } return ( } onClick={() => { // eslint-disable-next-line more/no-then @@ -350,7 +350,7 @@ export const OverlayMessageInfo = () => { {!isLegacyGroup && } {hasErrors && !isLegacyGroup && direction === 'outgoing' && ( } onClick={() => { void resendMessage(messageId); @@ -364,7 +364,7 @@ export const OverlayMessageInfo = () => { {/* Saving attachments sends a data extraction message so it must be disabled for message requests. */} {hasAttachments && !isIncomingMessageRequest && ( } @@ -385,7 +385,7 @@ export const OverlayMessageInfo = () => { {/* Deleting messages sends a "delete message" message so it must be disabled for message requests. */} {isDeletable && !isLegacyGroup && !isIncomingMessageRequest && ( } color={'var(--danger-color)'} dataTestId="delete-from-details" diff --git a/ts/components/dialog/HideRecoveryPasswordDialog.tsx b/ts/components/dialog/HideRecoveryPasswordDialog.tsx index 408bfecdd..cf12c2437 100644 --- a/ts/components/dialog/HideRecoveryPasswordDialog.tsx +++ b/ts/components/dialog/HideRecoveryPasswordDialog.tsx @@ -27,9 +27,10 @@ export function HideRecoveryPasswordDialog(props: HideRecoveryPasswordDialogProp }; const onConfirmation = async () => { + dispatch(userSettingsModal({ userSettingsPage: 'default' })); + await window.setSettingValue(SettingsKey.hideRecoveryPassword, true); onClose(); - dispatch(userSettingsModal({ userSettingsPage: 'privacy' })); }; if (isEmpty(state)) { diff --git a/ts/components/dialog/conversationSettings/conversationSettingsItems.tsx b/ts/components/dialog/conversationSettings/conversationSettingsItems.tsx index 662ddb1ac..c39397503 100644 --- a/ts/components/dialog/conversationSettings/conversationSettingsItems.tsx +++ b/ts/components/dialog/conversationSettings/conversationSettingsItems.tsx @@ -8,7 +8,6 @@ import { useWeAreAdmin, } from '../../../hooks/useParamSelector'; import { showUpdateGroupMembersByConvoId } from '../../../interactions/conversationInteractions'; -import { tr } from '../../../localization/localeTools'; import type { ConversationNotificationSettingType } from '../../../models/conversationAttributes'; import { PanelIconButton } from '../../buttons'; import { @@ -54,7 +53,7 @@ export const LeaveCommunityPanelButton = ({ conversationId }: WithConvoId) => { return ( { return ( { return ( { return ( } - text={tr('sessionNotifications')} + text={{ token: 'sessionNotifications' }} onClick={() => { showConvoSettingsCb({ settingsModalPage: 'notifications', standalonePage: false, }); }} - subText={subText} + subText={{ token: subText }} subTextDataTestId="notifications-details-menu-option" dataTestId="notifications-menu-option" /> @@ -149,7 +148,7 @@ export const AttachmentsButton = (_props: WithConvoId) => { return ( } - text={tr('attachments')} + text={{ token: 'attachments' }} onClick={showAttachmentsCb} dataTestId="attachments-menu-option" /> @@ -166,7 +165,7 @@ export const CopyAccountIdButton = ({ conversationId }: WithConvoId) => { return ( } - text={tr('accountIDCopy')} + text={{ token: 'accountIDCopy' }} onClick={showCopyAccountId} dataTestId="copy-account-id-menu-option" /> @@ -188,7 +187,7 @@ export const PinUnpinButton = ({ conversationId }: WithConvoId) => { unicode={isPinned ? LUCIDE_ICONS_UNICODE.PIN_OFF : LUCIDE_ICONS_UNICODE.PIN} /> } - text={tr(isPinned ? 'pinUnpinConversation' : 'pinConversation')} + text={{ token: isPinned ? 'pinUnpinConversation' : 'pinConversation' }} onClick={togglePinConversation} dataTestId="pin-conversation-menu-option" /> @@ -219,7 +218,7 @@ export function UpdateGroupMembersButton({ return ( } - text={asAdmin ? tr('manageMembers') : tr('groupMembers')} + text={{ token: asAdmin ? 'manageMembers' : 'groupMembers' }} onClick={() => { void showUpdateGroupMembersByConvoId(conversationId); }} @@ -266,8 +265,8 @@ export function UpdateDisappearingMessagesButton({ return ( } - text={tr('disappearingMessages')} - subText={disappearingMessagesSubtitle.label} + text={{ token: 'disappearingMessages' }} + subText={disappearingMessagesSubtitle} dataTestId="disappearing-messages-menu-option" onClick={() => { showConvoSettingsCb?.({ settingsModalPage: 'disappearing_message', standalonePage: false }); @@ -290,7 +289,7 @@ export function AddAdminCommunityButton({ conversationId }: WithConvoId) { iconColor="var(--text-primary-color" /> } - text={tr('addAdmins')} + text={{ token: 'addAdmins' }} onClick={cb} dataTestId="add-admins-menu-option" /> @@ -310,7 +309,7 @@ export function RemoveAdminCommunityButton({ conversationId }: WithConvoId) { iconColor="var(--text-primary-color" /> } - text={tr('adminRemove')} + text={{ token: 'adminRemove' }} onClick={cb} dataTestId="remove-admins-menu-option" /> @@ -326,7 +325,7 @@ export function BanFromCommunityButton({ conversationId }: WithConvoId) { return ( } - text={tr('banUser')} + text={{ token: 'banUser' }} onClick={showBanUserCb} dataTestId="ban-user-menu-option" /> @@ -342,7 +341,7 @@ export function UnbanFromCommunityButton({ conversationId }: WithConvoId) { return ( } - text={tr('banUnbanUser')} + text={{ token: 'banUnbanUser' }} onClick={showUnbanUserCb} dataTestId="unban-user-menu-option" /> @@ -358,7 +357,7 @@ export function InviteContactsToCommunityButton({ conversationId }: WithConvoId) return ( } - text={tr('membersInvite')} + text={{ token: 'membersInvite' }} onClick={showInviteContactCb} dataTestId="invite-contacts-menu-option" /> @@ -374,7 +373,7 @@ export function CopyCommunityUrlButton({ conversationId }: WithConvoId) { return ( } - text={tr('communityUrlCopy')} + text={{ token: 'communityUrlCopy' }} onClick={copyCommunityUrlCb} dataTestId="copy-community-url-menu-option" /> @@ -390,7 +389,7 @@ export function InviteContactsToGroupV2Button({ conversationId }: WithConvoId) { return ( } - text={tr('membersInvite')} + text={{ token: 'membersInvite' }} onClick={showInviteContactToGroupCb} dataTestId="invite-contacts-menu-option" /> @@ -408,7 +407,7 @@ export function ClearAllMessagesButton({ conversationId }: WithConvoId) { iconElement={ } - text={tr('clearMessages')} + text={{ token: 'clearMessages' }} onClick={clearAllMessagesCb} dataTestId="clear-all-messages-menu-option" color="var(--danger-color)" @@ -426,7 +425,7 @@ export function DeletePrivateConversationButton({ conversationId }: WithConvoId) return ( } - text={tr('conversationsDelete')} + text={{ token: 'conversationsDelete' }} onClick={showDeleteConversationContactCb} dataTestId="delete-conversation-menu-option" color="var(--danger-color)" @@ -444,7 +443,7 @@ export function HideNoteToSelfButton({ conversationId }: WithConvoId) { return ( } - text={tr('noteToSelfHide')} + text={{ token: 'noteToSelfHide' }} onClick={showHideNoteToSelfCb} dataTestId="hide-nts-menu-option" color="var(--danger-color)" @@ -462,7 +461,7 @@ export function ShowNoteToSelfButton({ conversationId }: WithConvoId) { return ( } - text={tr('showNoteToSelf')} + text={{ token: 'showNoteToSelf' }} onClick={showShowNoteToSelfCb} dataTestId="show-nts-menu-option" /> @@ -481,7 +480,7 @@ export function DeletePrivateContactButton({ conversationId }: WithConvoId) { iconElement={ } - text={tr('contactDelete')} + text={{ token: 'contactDelete' }} onClick={showDeletePrivateContactCb} dataTestId="delete-contact-menu-option" color="var(--danger-color)" @@ -499,7 +498,7 @@ export function BlockUnblockButton({ conversationId }: WithConvoId) { return ( } - text={tr(showBlockUnblock.token)} + text={{ token: showBlockUnblock.token }} // eslint-disable-next-line @typescript-eslint/no-misused-promises onClick={showBlockUnblock.cb} dataTestId="block-user-menu-option" diff --git a/ts/components/dialog/conversationSettings/pages/disappearing-messages/DisappearingMessagesPage.tsx b/ts/components/dialog/conversationSettings/pages/disappearing-messages/DisappearingMessagesPage.tsx index 3c6c913c3..4bdc69c71 100644 --- a/ts/components/dialog/conversationSettings/pages/disappearing-messages/DisappearingMessagesPage.tsx +++ b/ts/components/dialog/conversationSettings/pages/disappearing-messages/DisappearingMessagesPage.tsx @@ -1,7 +1,6 @@ import { useEffect, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import styled from 'styled-components'; -import { useTimerOptionsByMode } from '../../../../../hooks/useParamSelector'; import { setDisappearingMessagesByConvoId } from '../../../../../interactions/conversationInteractions'; import { TimerOptions } from '../../../../../session/disappearing_messages/timerOptions'; import { DisappearingMessageConversationModeType } from '../../../../../session/disappearing_messages/types'; @@ -102,7 +101,6 @@ export const DisappearingMessagesForConversationModal = (props: ConversationSett ); const [timeSelected, setTimeSelected] = useState(expireTimer || 0); - const timerOptions = useTimerOptionsByMode(modeSelected, hasOnlyOneMode); const isStandalone = useConversationSettingsModalIsStandalone(); const [loading, setLoading] = useState(false); @@ -213,7 +211,7 @@ export const DisappearingMessagesForConversationModal = (props: ConversationSett {(hasOnlyOneMode || modeSelected !== 'off') && ( <> { const mode = _mode as DisappearingMessageConversationModeType; const optionI18n = mode === 'deleteAfterRead' - ? tr('disappearingMessagesDisappearAfterRead') + ? 'disappearingMessagesDisappearAfterRead' : mode === 'deleteAfterSend' - ? tr('disappearingMessagesDisappearAfterSend') - : tr('off'); + ? 'disappearingMessagesDisappearAfterSend' + : 'off'; const subtitleI18n = mode === 'deleteAfterRead' - ? tr('disappearingMessagesDisappearAfterReadDescription') + ? 'disappearingMessagesDisappearAfterReadDescription' : mode === 'deleteAfterSend' - ? tr('disappearingMessagesDisappearAfterSendDescription') + ? 'disappearingMessagesDisappearAfterSendDescription' : undefined; const parentDataTestId = toDataTestId(mode); @@ -72,14 +71,14 @@ export const DisappearingModes = (props: DisappearingModesProps) => { textElement={ subtitleI18n ? ( ) : ( ) diff --git a/ts/components/dialog/conversationSettings/pages/disappearing-messages/TimeOptions.tsx b/ts/components/dialog/conversationSettings/pages/disappearing-messages/TimeOptions.tsx index 8d6a10a23..a1b720d75 100644 --- a/ts/components/dialog/conversationSettings/pages/disappearing-messages/TimeOptions.tsx +++ b/ts/components/dialog/conversationSettings/pages/disappearing-messages/TimeOptions.tsx @@ -1,8 +1,9 @@ +import type { DisappearingMessageConversationModeType } from 'libsession_util_nodejs'; import { isEmpty } from 'lodash'; import { DisappearTimeOptionDataTestId } from 'react'; import { - TimerOptionsArray, + TimerOptions, TimerSeconds, } from '../../../../../session/disappearing_messages/timerOptions'; import { @@ -12,15 +13,54 @@ import { } from '../../../../buttons/panel/PanelButton'; import { PanelRadioButton } from '../../../../buttons/panel/PanelRadioButton'; import { assertUnreachable } from '../../../../../types/sqlSharedTypes'; +import { tr } from '../../../../../localization/localeTools'; + +// Note: label cannot be a trArgs as it is dynamic based on the timer set (using date-fns) +type TimerOptionsEntry = { value: TimerSeconds; label: string }; +type TimerOptionsArray = Array; type TimerOptionsProps = { - options: TimerOptionsArray | null; + modeSelected: DisappearingMessageConversationModeType; selected: number; setSelected: (value: number) => void; hasOnlyOneMode?: boolean; disabled?: boolean; }; +function useTimerOptionsByMode( + disappearingMessageMode: DisappearingMessageConversationModeType, + hasOnlyOneMode: boolean +) { + const options: TimerOptionsArray = []; + if (hasOnlyOneMode) { + options.push({ + label: tr('off'), + value: TimerOptions.VALUES[0], + }); + } + switch (disappearingMessageMode) { + case 'deleteAfterRead': + options.push( + ...TimerOptions.DELETE_AFTER_READ.map(option => ({ + label: TimerOptions.getName(option), + value: option, + })) + ); + break; + case 'deleteAfterSend': + options.push( + ...TimerOptions.DELETE_AFTER_SEND.map(option => ({ + label: TimerOptions.getName(option), + value: option, + })) + ); + break; + default: + return []; + } + return options; +} + function toMinutes(seconds: Extract) { const ret = Math.floor(seconds / 60); if (ret !== 5 && ret !== 30) { @@ -72,7 +112,9 @@ function getDataTestIdFromTimerSeconds(seconds: TimerSeconds): DisappearTimeOpti } export const TimeOptions = (props: TimerOptionsProps) => { - const { options, selected, setSelected, hasOnlyOneMode, disabled } = props; + const { modeSelected, selected, setSelected, hasOnlyOneMode, disabled } = props; + + const options = useTimerOptionsByMode(modeSelected, hasOnlyOneMode ?? false); if (!options || isEmpty(options)) { return null; @@ -90,14 +132,14 @@ export const TimeOptions = (props: TimerOptionsProps) => { return ( } - value={option.name} + value={option.value} isSelected={selected === option.value} onSelect={() => { setSelected(option.value); diff --git a/ts/components/dialog/conversationSettings/pages/notifications/NotificationPage.tsx b/ts/components/dialog/conversationSettings/pages/notifications/NotificationPage.tsx index 66779661f..2ab815401 100644 --- a/ts/components/dialog/conversationSettings/pages/notifications/NotificationPage.tsx +++ b/ts/components/dialog/conversationSettings/pages/notifications/NotificationPage.tsx @@ -147,7 +147,10 @@ export function NotificationForConversationModal(props: Required + } value={option} isSelected={notificationSelected === option.value} diff --git a/ts/components/dialog/user-settings/UserSettingsDialog.tsx b/ts/components/dialog/user-settings/UserSettingsDialog.tsx index de6248418..84a8582d4 100644 --- a/ts/components/dialog/user-settings/UserSettingsDialog.tsx +++ b/ts/components/dialog/user-settings/UserSettingsDialog.tsx @@ -1,4 +1,5 @@ import { type UserSettingsModalState } from '../../../state/ducks/modalDialog'; +import { assertUnreachable } from '../../../types/sqlSharedTypes'; import { AppearanceSettingsPage } from './pages/AppearanceSettingsPage'; import { BlockedContactsSettingsPage } from './pages/BlockedContactsSettingsPage'; import { ConversationSettingsPage } from './pages/ConversationSettingsPage'; @@ -7,6 +8,7 @@ import { HelpSettingsPage } from './pages/HelpSettingsPage'; import { NotificationsSettingsPage } from './pages/NotificationsSettingsPage'; import { PreferencesSettingsPage } from './pages/PreferencesSettingsPage'; import { PrivacySettingsPage } from './pages/PrivacySettingsPage'; +import { RecoveryPasswordSettingsPage } from './pages/RecoveryPasswordSettingsPage'; export const UserSettingsDialog = (modalState: UserSettingsModalState) => { if (!modalState?.userSettingsPage) { @@ -30,7 +32,15 @@ export const UserSettingsDialog = (modalState: UserSettingsModalState) => { return ; case 'appearance': return ; + case 'recovery-password': + return ; + case 'message-requests': + // the `message-request` is not a page of the user settings page, but a page in the left pane header currently. + return null; default: - return ; + return assertUnreachable( + modalState.userSettingsPage, + `Unknown user settings page: ${modalState.userSettingsPage}` + ); } }; diff --git a/ts/components/dialog/user-settings/components/SettingsChevronBasic.tsx b/ts/components/dialog/user-settings/components/SettingsChevronBasic.tsx index a68211066..a31f8f619 100644 --- a/ts/components/dialog/user-settings/components/SettingsChevronBasic.tsx +++ b/ts/components/dialog/user-settings/components/SettingsChevronBasic.tsx @@ -1,17 +1,16 @@ import type { SettingsChevron } from 'react'; -import type { TokenSimpleNoArgs } from '../../../../localization/locales'; import { PanelButtonTextWithSubText } from '../../../buttons/panel/PanelButton'; -import { tr } from '../../../../localization/localeTools'; import { PanelChevronButton } from '../../../buttons/panel/PanelChevronButton'; +import type { TrArgs } from '../../../../localization/localeTools'; export function SettingsChevronBasic({ baseDataTestId, onClick, - textToken, - subTextToken, + text, + subText, }: { - textToken: TokenSimpleNoArgs; - subTextToken: TokenSimpleNoArgs; + text: TrArgs; + subText: TrArgs; baseDataTestId: SettingsChevron; onClick: (() => Promise) | (() => void); }) { @@ -19,8 +18,8 @@ export function SettingsChevronBasic({ diff --git a/ts/components/dialog/user-settings/components/SettingsExternalLinkBasic.tsx b/ts/components/dialog/user-settings/components/SettingsExternalLinkBasic.tsx index e77fda20f..873a3c901 100644 --- a/ts/components/dialog/user-settings/components/SettingsExternalLinkBasic.tsx +++ b/ts/components/dialog/user-settings/components/SettingsExternalLinkBasic.tsx @@ -1,13 +1,12 @@ import type { SettingsExternalLinkButtons } from 'react'; -import type { TokenSimpleNoArgs } from '../../../../localization/locales'; import { PanelButtonTextWithSubText } from '../../../buttons/panel/PanelButton'; -import { tr } from '../../../../localization/localeTools'; import { GenericPanelButtonWithAction, type GenericPanelButtonProps, } from '../../../buttons/panel/GenericPanelButtonWithAction'; import { SessionLucideIconButton } from '../../../icon/SessionIconButton'; import { LUCIDE_ICONS_UNICODE } from '../../../icon/lucide'; +import type { TrArgs } from '../../../../localization/localeTools'; const PanelExternalLinkButton = ( props: Pick & { @@ -38,11 +37,11 @@ const PanelExternalLinkButton = ( export function SettingsExternalLinkBasic({ baseDataTestId, onClick, - textToken, - subTextToken, + text, + subText, }: { - textToken: TokenSimpleNoArgs; - subTextToken: TokenSimpleNoArgs; + text: TrArgs; + subText: TrArgs; baseDataTestId: SettingsExternalLinkButtons; onClick: () => Promise; }) { @@ -50,8 +49,8 @@ export function SettingsExternalLinkBasic({ diff --git a/ts/components/dialog/user-settings/components/SettingsPanelButtonInlineBasic.tsx b/ts/components/dialog/user-settings/components/SettingsPanelButtonInlineBasic.tsx index 589d8e82a..bc7a03fbb 100644 --- a/ts/components/dialog/user-settings/components/SettingsPanelButtonInlineBasic.tsx +++ b/ts/components/dialog/user-settings/components/SettingsPanelButtonInlineBasic.tsx @@ -1,7 +1,6 @@ import type { SettingsInlineButtons } from 'react'; -import type { TokenSimpleNoArgs } from '../../../../localization/locales'; import { PanelButtonTextWithSubText } from '../../../buttons/panel/PanelButton'; -import { tr } from '../../../../localization/localeTools'; +import { type TrArgs } from '../../../../localization/localeTools'; import { PanelWithButtonInline, type PanelWithButtonInlineProps, @@ -10,22 +9,22 @@ import { export function SettingsPanelButtonInlineBasic({ baseDataTestId, onClick, - textToken, - subTextToken, + text, + subText, buttonColor, buttonText, disabled, }: { - textToken: TokenSimpleNoArgs; - subTextToken: TokenSimpleNoArgs; + text: TrArgs; + subText: TrArgs; baseDataTestId: SettingsInlineButtons; } & Pick) { return ( diff --git a/ts/components/dialog/user-settings/components/SettingsToggleBasic.tsx b/ts/components/dialog/user-settings/components/SettingsToggleBasic.tsx index db98fc539..6540e642e 100644 --- a/ts/components/dialog/user-settings/components/SettingsToggleBasic.tsx +++ b/ts/components/dialog/user-settings/components/SettingsToggleBasic.tsx @@ -1,18 +1,17 @@ import type { SettingsToggles } from 'react'; -import type { TokenSimpleNoArgs } from '../../../../localization/locales'; import { PanelButtonTextWithSubText } from '../../../buttons/panel/PanelButton'; import { PanelToggleButton } from '../../../buttons/panel/PanelToggleButton'; -import { tr } from '../../../../localization/localeTools'; +import { type TrArgs } from '../../../../localization/localeTools'; export function SettingsToggleBasic({ active, baseDataTestId, onClick, - textToken, - subTextToken, + text, + subText, }: { - textToken: TokenSimpleNoArgs; - subTextToken: TokenSimpleNoArgs; + text: TrArgs; + subText: TrArgs; baseDataTestId: SettingsToggles; active: boolean; onClick: () => Promise; @@ -21,8 +20,8 @@ export function SettingsToggleBasic({ diff --git a/ts/components/dialog/user-settings/pages/AppearanceSettingsPage.tsx b/ts/components/dialog/user-settings/pages/AppearanceSettingsPage.tsx index 97b2ce649..fa8e56329 100644 --- a/ts/components/dialog/user-settings/pages/AppearanceSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/AppearanceSettingsPage.tsx @@ -42,7 +42,6 @@ import { useTheme } from '../../../../state/theme/selectors/theme'; import { switchThemeTo } from '../../../../themes/switchTheme'; import { StyledPanelButtonSeparator } from '../../../buttons/panel/StyledPanelButtonGroupSeparator'; import { GenericPanelButtonWithAction } from '../../../buttons/panel/GenericPanelButtonWithAction'; -import { tr } from '../../../../localization/localeTools'; import { Flex } from '../../../basic/Flex'; import { LUCIDE_ICONS_UNICODE } from '../../../icon/lucide'; import { LucideIcon } from '../../../icon/LucideIcon'; @@ -336,14 +335,14 @@ function ZoomFactorPicker({ forceUpdate }: { forceUpdate: () => void }) { event: e, position: { x: boundingRect.left + boundingRect.width / 2, - y: boundingRect.top + boundingRect.height / 2, + y: boundingRect.top + boundingRect.height / 2 - 75, }, }); }} textElement={ @@ -425,8 +424,8 @@ export function AppearanceSettingsPage(modalState: UserSettingsModalState) { { const toggledValue = !isFollowSystemThemeEnabled; await window.setSettingValue(SettingsKey.hasFollowSystemThemeEnabled, toggledValue); @@ -448,8 +447,8 @@ export function AppearanceSettingsPage(modalState: UserSettingsModalState) { { window.toggleMenuBar(); forceUpdate(); diff --git a/ts/components/dialog/user-settings/pages/ConversationSettingsPage.tsx b/ts/components/dialog/user-settings/pages/ConversationSettingsPage.tsx index fe6a87b48..1b071a301 100644 --- a/ts/components/dialog/user-settings/pages/ConversationSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/ConversationSettingsPage.tsx @@ -78,8 +78,8 @@ export function ConversationSettingsPage(modalState: UserSettingsModalState) { await toggleCommunitiesPruning(); forceUpdate(); }} - textToken={'conversationsMessageTrimmingTrimCommunities'} - subTextToken={'conversationsMessageTrimmingTrimCommunitiesDescription'} + text={{ token: 'conversationsMessageTrimmingTrimCommunities' }} + subText={{ token: 'conversationsMessageTrimmingTrimCommunitiesDescription' }} /> @@ -91,8 +91,8 @@ export function ConversationSettingsPage(modalState: UserSettingsModalState) { window.toggleSpellCheck(); forceUpdate(); }} - textToken={'conversationsSpellCheck'} - subTextToken={'conversationsSpellCheckDescription'} + text={{ token: 'conversationsSpellCheck' }} + subText={{ token: 'conversationsSpellCheckDescription' }} /> @@ -104,8 +104,8 @@ export function ConversationSettingsPage(modalState: UserSettingsModalState) { dispatch(toggleAudioAutoplay()); forceUpdate(); }} - textToken={'conversationsAutoplayAudioMessage'} - subTextToken={'conversationsAutoplayAudioMessageDescription'} + text={{ token: 'conversationsAutoplayAudioMessage' }} + subText={{ token: 'conversationsAutoplayAudioMessageDescription' }} /> @@ -116,8 +116,8 @@ export function ConversationSettingsPage(modalState: UserSettingsModalState) { onClick={() => { dispatch(userSettingsModal({ userSettingsPage: 'blocked-contacts' })); }} - textToken={'conversationsBlockedContacts'} - subTextToken={'blockedContactsManageDescription'} + text={{ token: 'conversationsBlockedContacts' }} + subText={{ token: 'blockedContactsManageDescription' }} /> diff --git a/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx b/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx index 5222bb3ab..a7ea7471b 100644 --- a/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx @@ -3,7 +3,6 @@ import { useDispatch } from 'react-redux'; import styled from 'styled-components'; import { useHotkey } from '../../../../hooks/useHotkey'; import { useOurConversationUsername, useOurAvatarPath } from '../../../../hooks/useParamSelector'; -import { LOCALE_DEFAULTS } from '../../../../localization/constants'; import { UserUtils, ToastUtils } from '../../../../session/utils'; import { resetConversationExternal } from '../../../../state/ducks/conversations'; import { @@ -35,6 +34,7 @@ import type { ProfileDialogModes } from '../ProfileDialogModes'; import { tr } from '../../../../localization/localeTools'; import { useIsProAvailable } from '../../../../hooks/useIsProAvailable'; import { setDebugMode } from '../../../../state/ducks/debug'; +import { useHideRecoveryPasswordEnabled } from '../../../../state/selectors/settings'; const handleKeyQRMode = (mode: ProfileDialogModes, setMode: (mode: ProfileDialogModes) => void) => { switch (mode) { @@ -104,7 +104,7 @@ function SessionProSection() {
} - text={LOCALE_DEFAULTS.app_pro} + text={{ token: 'appPro' }} onClick={() => { dispatch(updateSessionProInfoModal({ variant: SessionProInfoVariant.GENERIC })); }} @@ -126,7 +126,7 @@ function MiscSection() { unicode={LUCIDE_ICONS_UNICODE.HEART} /> } - text={tr('donate')} + text={{ token: 'donate' }} onClick={() => { showLinkVisitWarningDialog('https://session.foundation/donate#app', dispatch); }} @@ -134,7 +134,7 @@ function MiscSection() { /> } - text={tr('onionRoutingPath')} + text={{ token: 'onionRoutingPath' }} onClick={() => { dispatch(onionPathModal({})); }} @@ -142,7 +142,7 @@ function MiscSection() { /> } - text={LOCALE_DEFAULTS.network_name} + text={{ token: 'networkName' }} onClick={() => { // do a refresh request on open dispatch(networkDataActions.refreshInfoFromSeshServer() as any); @@ -161,7 +161,7 @@ function SettingsSection() { } - text={tr('sessionPrivacy')} + text={{ token: 'sessionPrivacy' }} onClick={() => { dispatch(userSettingsModal({ userSettingsPage: 'privacy' })); }} @@ -169,7 +169,7 @@ function SettingsSection() { /> } - text={tr('sessionNotifications')} + text={{ token: 'sessionNotifications' }} onClick={() => { dispatch(userSettingsModal({ userSettingsPage: 'notifications' })); }} @@ -177,7 +177,7 @@ function SettingsSection() { /> } - text={tr('sessionConversations')} + text={{ token: 'sessionConversations' }} onClick={() => { dispatch(userSettingsModal({ userSettingsPage: 'conversations' })); }} @@ -185,7 +185,7 @@ function SettingsSection() { /> } - text={tr('sessionAppearance')} + text={{ token: 'sessionAppearance' }} onClick={() => { dispatch(userSettingsModal({ userSettingsPage: 'appearance' })); }} @@ -195,7 +195,7 @@ function SettingsSection() { iconElement={ } - text={tr('sessionMessageRequests')} + text={{ token: 'sessionMessageRequests' }} onClick={() => { dispatch(sectionActions.setLeftOverlayMode('message-requests')); dispatch(userSettingsModal(null)); @@ -205,7 +205,7 @@ function SettingsSection() { /> } - text={tr('preferences')} + text={{ token: 'preferences' }} onClick={() => { dispatch(userSettingsModal({ userSettingsPage: 'preferences' })); }} @@ -217,19 +217,23 @@ function SettingsSection() { function AdminSection() { const dispatch = useDispatch(); + const recoveryPasswordHidden = useHideRecoveryPasswordEnabled(); + return ( - } - text={tr('sessionRecoveryPassword')} - onClick={() => { - throw new Error('Not implemented'); - }} - dataTestId="recovery-password-settings-menu-item" - /> + {!recoveryPasswordHidden ? ( + } + text={{ token: 'sessionRecoveryPassword' }} + onClick={() => { + dispatch(userSettingsModal({ userSettingsPage: 'recovery-password' })); + }} + dataTestId="recovery-password-settings-menu-item" + /> + ) : null} } - text={tr('sessionHelp')} + text={{ token: 'sessionHelp' }} onClick={() => { dispatch(userSettingsModal({ userSettingsPage: 'help' })); }} @@ -242,7 +246,7 @@ function AdminSection() { iconColor="var(--danger-color)" /> } - text={tr('sessionClearData')} + text={{ token: 'sessionClearData' }} onClick={() => { dispatch(updateDeleteAccountModal({})); }} diff --git a/ts/components/dialog/user-settings/pages/HelpSettingsPage.tsx b/ts/components/dialog/user-settings/pages/HelpSettingsPage.tsx index 7247003ed..74d6eba3e 100644 --- a/ts/components/dialog/user-settings/pages/HelpSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/HelpSettingsPage.tsx @@ -46,8 +46,8 @@ export function HelpSettingsPage(modalState: UserSettingsModalState) { saveLogToDesktop()} buttonColor={SessionButtonColor.Primary} buttonText={tr('helpReportABugExportLogs')} @@ -57,16 +57,16 @@ export function HelpSettingsPage(modalState: UserSettingsModalState) { { showLinkVisitWarningDialog('https://getsession.org/faq', dispatch); }} /> { showLinkVisitWarningDialog('https://getsession.org/translate', dispatch); }} @@ -74,16 +74,16 @@ export function HelpSettingsPage(modalState: UserSettingsModalState) { { showLinkVisitWarningDialog('https://getsession.org/survey', dispatch); }} /> { showLinkVisitWarningDialog('https://sessionapp.zendesk.com/hc/en-us', dispatch); }} diff --git a/ts/components/dialog/user-settings/pages/NotificationsSettingsPage.tsx b/ts/components/dialog/user-settings/pages/NotificationsSettingsPage.tsx index df0dc7c5b..9d4bf8b12 100644 --- a/ts/components/dialog/user-settings/pages/NotificationsSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/NotificationsSettingsPage.tsx @@ -51,35 +51,32 @@ function NotificationsContent({ const options = [ { - text: tr('notificationsContentShowNameAndContent'), - subText: tr('notificationSenderNameAndPreview'), + text: { token: 'notificationsContentShowNameAndContent' }, + subText: { token: 'notificationSenderNameAndPreview' }, value: NotificationType.message, }, { - text: tr('notificationsContentShowNameOnly'), - subText: tr('notificationSenderNameOnly'), + text: { token: 'notificationsContentShowNameOnly' }, + subText: { token: 'notificationSenderNameOnly' }, value: NotificationType.name, }, { - text: tr('notificationsContentShowNoNameOrContent'), - subText: tr('notificationsGenericOnly'), + text: { token: 'notificationsContentShowNoNameOrContent' }, + subText: { token: 'notificationsGenericOnly' }, value: NotificationType.count, }, ] as const; - const items = options.map(m => ({ - text: m.text, - subText: m.subText, - value: m.value, - })); - const onClickPreview = () => { if (!notificationsAreEnabled) { return; } + const foundEntry = options.find(m => m.value === initialNotificationEnabled)?.text; + const message = foundEntry ? tr(foundEntry.token) : 'Message body'; + Notifications.addPreviewNotification({ conversationId: `preview-notification-${Date.now()}`, - message: items.find(m => m.value === initialNotificationEnabled)?.text || 'Message body', + message, title: tr('preview'), isExpiringMessage: false, }); @@ -106,8 +103,8 @@ function NotificationsContent({ ); forceUpdate(); }} - textToken="notificationsSoundDesktop" - subTextToken="notificationsMakeSound" + text={{ token: 'notificationsSoundDesktop' }} + subText={{ token: 'notificationsMakeSound' }} /> @@ -118,7 +115,7 @@ function NotificationsContent({ description={{ token: 'contentNotificationDescription' }} /> - {items.map(({ value, text, subText }) => { + {options.map(({ value, text, subText }) => { return ( @@ -122,8 +121,8 @@ export function PreferencesSettingsPage(modalState: UserSettingsModalState) { { const old = Boolean(window.getSettingValue(SettingsKey.settingsAutoUpdate)); await window.setSettingValue(SettingsKey.settingsAutoUpdate, !old); @@ -136,8 +135,8 @@ export function PreferencesSettingsPage(modalState: UserSettingsModalState) { { await toggleStartInTray(); forceUpdate(); diff --git a/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx b/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx index b196c04df..7baa08c66 100644 --- a/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx @@ -115,16 +115,16 @@ function HasPasswordSubSection(props: WithPasswordUpdatedCb) { displayPasswordModal('change', props.onPasswordUpdated)} buttonColor={SessionButtonColor.Primary} buttonText={tr('change')} /> { displayPasswordModal('remove', props.onPasswordUpdated); }} @@ -139,8 +139,8 @@ function NoPasswordSubSection(props: WithPasswordUpdatedCb) { { displayPasswordModal('set', props.onPasswordUpdated); }} @@ -205,8 +205,8 @@ export function PrivacySettingsPage(modalState: UserSettingsModalState) { await toggleCallMediaPermissions(forceUpdate); forceUpdate(); }} - textToken="callsVoiceAndVideoBeta" - subTextToken="callsVoiceAndVideoToggleDescription" + text={{ token: 'callsVoiceAndVideoBeta' }} + subText={{ token: 'callsVoiceAndVideoToggleDescription' }} /> @@ -232,8 +232,8 @@ export function PrivacySettingsPage(modalState: UserSettingsModalState) { ); forceUpdate(); }} - textToken="messageRequestsCommunities" - subTextToken="messageRequestsCommunitiesDescription" + text={{ token: 'messageRequestsCommunities' }} + subText={{ token: 'messageRequestsCommunitiesDescription' }} /> @@ -246,8 +246,8 @@ export function PrivacySettingsPage(modalState: UserSettingsModalState) { await window.setSettingValue(SettingsKey.settingsReadReceipt, !old); forceUpdate(); }} - textToken="readReceipts" - subTextToken="readReceiptsDescription" + text={{ token: 'readReceipts' }} + subText={{ token: 'readReceiptsDescription' }} /> @@ -255,8 +255,8 @@ export function PrivacySettingsPage(modalState: UserSettingsModalState) { { void toggleLinkPreviews(isLinkPreviewsOn, forceUpdate); }} - textToken="linkPreviewsSend" - subTextToken="linkPreviewsDescription" + text={{ token: 'linkPreviewsSend' }} + subText={{ token: 'linkPreviewsDescription' }} /> diff --git a/ts/components/dialog/user-settings/pages/RecoveryPasswordSettingsPage.tsx b/ts/components/dialog/user-settings/pages/RecoveryPasswordSettingsPage.tsx new file mode 100644 index 000000000..07521e78d --- /dev/null +++ b/ts/components/dialog/user-settings/pages/RecoveryPasswordSettingsPage.tsx @@ -0,0 +1,211 @@ +import { useDispatch, useSelector } from 'react-redux'; +import styled from 'styled-components'; +import { useState } from 'react'; + +import { + updateHideRecoveryPasswordModal, + updateLightBoxOptions, + userSettingsModal, + type UserSettingsModalState, +} from '../../../../state/ducks/modalDialog'; +import { + PanelButtonGroup, + PanelButtonTextWithSubText, + PanelLabelWithDescription, +} from '../../../buttons/panel/PanelButton'; +import { + ModalBasicHeader, + SessionWrapperModal, + WrapperModalWidth, +} from '../../../SessionWrapperModal'; +import { ModalBackButton } from '../../shared/ModalBackButton'; +import { + useUserSettingsBackAction, + useUserSettingsCloseAction, + useUserSettingsTitle, +} from './userSettingsHooks'; +import { SettingsPanelButtonInlineBasic } from '../components/SettingsPanelButtonInlineBasic'; +import { useHideRecoveryPasswordEnabled } from '../../../../state/selectors/settings'; +import { tr } from '../../../../localization/localeTools'; +import { SessionButton, SessionButtonColor, SessionButtonType } from '../../../basic/SessionButton'; +import { useHotkey } from '../../../../hooks/useHotkey'; +import { useIconToImageURL } from '../../../../hooks/useIconToImageURL'; +import { usePasswordModal } from '../../../../hooks/usePasswordModal'; +import { mnDecode } from '../../../../session/crypto/mnemonic'; +import { getIsModalVisible } from '../../../../state/selectors/modal'; +import { THEME_GLOBALS } from '../../../../themes/globals'; +import { prepareQRCodeForLightBox } from '../../../../util/qrCodes'; +import { getCurrentRecoveryPhrase } from '../../../../util/storage'; +import { SessionQRCode, type QRCodeLogoProps } from '../../../SessionQRCode'; + +import { AnimatedFlex, Flex } from '../../../basic/Flex'; +import { CopyToClipboardButton } from '../../../buttons'; + +const StyledRecoveryPassword = styled(AnimatedFlex)<{ color: string }>` + font-family: var(--font-mono); + font-size: var(--font-size-sm); + text-align: justify; + user-select: text; + border: 2px solid var(--text-secondary-color); + border-radius: 11px; + padding: var(--margins-sm) var(--margins-sm) var(--margins-sm) var(--margins-md); + margin: 0; + max-width: fit-content; + color: ${props => props.color}; +`; + +const qrLogoProps: QRCodeLogoProps = { + iconType: 'shield', + iconSize: 56, +}; + +export function RecoveryPasswordSettingsPage(modalState: UserSettingsModalState) { + const backAction = useUserSettingsBackAction(modalState); + const closeAction = useUserSettingsCloseAction(modalState); + const title = useUserSettingsTitle(modalState); + const recoveryPasswordHidden = useHideRecoveryPasswordEnabled(); + + const recoveryPhrase = getCurrentRecoveryPhrase(); + if (!recoveryPhrase) { + throw new Error('SettingsCategoryRecoveryPassword recovery seed is empty'); + } + const hexEncodedSeed = mnDecode(recoveryPhrase, 'english'); + const [isQRVisible, setIsQRVisible] = useState(false); + + const isModalVisible = useSelector(getIsModalVisible); + + const { dataURL, iconSize, iconColor, backgroundColor, loading } = useIconToImageURL(qrLogoProps); + + const dispatch = useDispatch(); + + const { hasPassword, passwordValid } = usePasswordModal({ + onClose: () => { + dispatch(userSettingsModal({ userSettingsPage: 'privacy' })); + }, + }); + + if (recoveryPasswordHidden) { + throw new Error('SettingsCategoryRecoveryPassword recovery password is hidden'); + } + + useHotkey( + 'v', + () => { + if (!isModalVisible) { + setIsQRVisible(!isQRVisible); + } + }, + hasPassword && !passwordValid + ); + + if (hasPassword && !passwordValid) { + return null; + } + + return ( + : undefined} + /> + } + onClose={closeAction || undefined} + shouldOverflow={true} + allowOutsideClick={false} + $contentMinWidth={WrapperModalWidth.normal} + > + + + + {isQRVisible ? ( + { + const lightBoxOptions = prepareQRCodeForLightBox(fileName, dataUrl); + dispatch(updateLightBoxOptions(lightBoxOptions)); + }} + ariaLabel={'Recovery Password QR Code'} + dataTestId={'session-recovery-password'} + style={{ alignSelf: 'center' }} + /> + ) : ( + + + {recoveryPhrase} + + + )} + + + {!isQRVisible && ( + + )} + { + setIsQRVisible(!isQRVisible); + }} + style={{ + minWidth: 'var(--modal-actions-outline-min-width)', + }} + > + {isQRVisible ? tr('recoveryPasswordView') : tr('qrView')} + + + + {!recoveryPasswordHidden ? ( + <> + + + { + dispatch(updateHideRecoveryPasswordModal({ state: 'firstWarning' })); + }} + buttonText={tr('hide')} + buttonColor={SessionButtonColor.Danger} + /> + + + ) : null} + + ); +} diff --git a/ts/components/menu/Menu.tsx b/ts/components/menu/Menu.tsx index 8a71a717e..91c8ca3ae 100644 --- a/ts/components/menu/Menu.tsx +++ b/ts/components/menu/Menu.tsx @@ -402,7 +402,7 @@ export const NotificationForConvoMenuItem = (): JSX.Element | null => { }} disabled={disabled} > - {item.name} + {tr(item.token)} ); })} diff --git a/ts/components/menuAndSettingsHooks/useLocalisedNotificationFor.ts b/ts/components/menuAndSettingsHooks/useLocalisedNotificationFor.ts index 35f4db10d..b25ea0d44 100644 --- a/ts/components/menuAndSettingsHooks/useLocalisedNotificationFor.ts +++ b/ts/components/menuAndSettingsHooks/useLocalisedNotificationFor.ts @@ -1,5 +1,4 @@ import { useMemo } from 'react'; -import { tr } from '../../localization/localeTools'; import { ConversationNotificationSetting, type ConversationNotificationSettingType, @@ -45,7 +44,7 @@ export const useLocalisedNotificationOptions = (context: Context) => { return ConversationNotificationSetting.map((n: ConversationNotificationSettingType) => { const token = tokenForContextAndNotification(context, n); - return { value: n, name: tr(token) }; + return { value: n, token }; }); }, [context]); }; @@ -55,9 +54,9 @@ export const useLocalisedNotificationOf = ( context: Context ) => { const localisedNotificationOptions = useLocalisedNotificationOptions(context); - const name = localisedNotificationOptions.find(m => m.value === notification)?.name; - if (!name) { + const token = localisedNotificationOptions.find(m => m.value === notification)?.token; + if (!token) { throw new Error('useLocalisedNotificationOf() called with an invalid notification type'); } - return name; + return token; }; diff --git a/ts/components/settings/SessionSettingListItem.tsx b/ts/components/settings/SessionSettingListItem.tsx deleted file mode 100644 index a5934c704..000000000 --- a/ts/components/settings/SessionSettingListItem.tsx +++ /dev/null @@ -1,203 +0,0 @@ -import styled from 'styled-components'; - -import { shell } from 'electron'; -import { isEmpty, pick } from 'lodash'; -import { ReactNode, type SessionDataTestId } from 'react'; -import { Flex } from '../basic/Flex'; -import { - SessionButton, - SessionButtonColor, - SessionButtonShape, - SessionButtonType, -} from '../basic/SessionButton'; -import { SessionToggle } from '../basic/SessionToggle'; -import { SpacerSM } from '../basic/Text'; -import { SessionIcon, SessionIconProps } from '../icon'; -import { SessionLucideIconButton } from '../icon/SessionIconButton'; -import { LUCIDE_ICONS_UNICODE } from '../icon/lucide'; - -type ButtonSettingsProps = { - title?: string; - description?: string; - buttonColor?: SessionButtonColor; - buttonType?: SessionButtonType; - buttonShape?: SessionButtonShape; - buttonText: string; - dataTestId?: SessionDataTestId; - onClick: () => void; -}; - -export const StyledDescriptionSettingsItem = styled.div` - font-family: var(--font-default); - font-size: var(--font-size-sm); - font-weight: 400; -`; - -export const StyledTitleSettingsItem = styled.div` - line-height: 1.7; - font-size: var(--font-size-lg); - font-weight: bold; -`; - -const StyledInfo = styled.div` - padding-inline-end: var(--margins-lg); -`; - -const StyledDescriptionContainer = styled(StyledDescriptionSettingsItem)` - display: flex; - align-items: center; -`; - -export const StyledSettingItem = styled.div` - font-size: var(--font-size-md); - padding: var(--margins-lg); - margin-bottom: var(--margins-lg); - - background: var(--settings-tab-background-color); - color: var(--settings-tab-text-color); - border-top: 1px solid var(--border-color); - border-bottom: 1px solid var(--border-color); -`; - -const StyledSettingItemInline = styled(StyledSettingItem)` - display: flex; - align-items: center; - justify-content: space-between; - transition: var(--default-duration); - button { - flex-shrink: 0; - } -`; - -const StyledSettingItemClickable = styled(StyledSettingItemInline)` - cursor: pointer; - &:hover { - background: var(--settings-tab-background-hover-color); - } - &:active { - background: var(--settings-tab-background-selected-color); - } -`; - -export const SettingsTitleAndDescription = (props: { - title?: ReactNode; - description?: ReactNode; - childrenDescription?: ReactNode; - icon?: SessionIconProps; -}) => { - const { description, childrenDescription, title, icon } = props; - return ( - - - {title} - {!isEmpty(icon) ? ( - <> - - - - ) : null} - - - {description && ( - {description} - )} - <>{childrenDescription} - - - ); -}; - -export const SessionSettingsItemWrapper = (props: { - inline: boolean; - title?: ReactNode; - icon?: SessionIconProps; - description?: ReactNode; - children?: ReactNode; - childrenDescription?: ReactNode; -}) => { - const { inline, children, description, title, childrenDescription, icon } = props; - const ComponentToRender = inline ? StyledSettingItemInline : StyledSettingItem; - return ( - - - {children} - - ); -}; - -export const SessionSettingsTitleWithLink = (props: { title: string; link: string }) => { - const { title, link } = props; - return ( - { - void shell.openExternal(link); - }} - > - - - - ); -}; - -export const SessionToggleWithDescription = (props: { - title?: string; - description?: string; - active: boolean; - onClickToggle: () => void; - childrenDescription?: ReactNode; // if set, those elements will be appended next to description field (only used for typing message settings as of now) - dataTestId?: SessionDataTestId; -}) => { - const { title, description, active, onClickToggle, childrenDescription, dataTestId } = props; - - return ( - - - - ); -}; - -export const SessionSettingButtonItem = (props: ButtonSettingsProps) => { - const { - title, - description, - buttonColor, - buttonType, - buttonShape, - buttonText, - dataTestId, - onClick, - } = props; - - return ( - - - - ); -}; diff --git a/ts/components/settings/section/CategoryRecoveryPassword.tsx b/ts/components/settings/section/CategoryRecoveryPassword.tsx deleted file mode 100644 index 59c8ad005..000000000 --- a/ts/components/settings/section/CategoryRecoveryPassword.tsx +++ /dev/null @@ -1,188 +0,0 @@ -import { useState } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; -import styled from 'styled-components'; -import { useHotkey } from '../../../hooks/useHotkey'; -import { useIconToImageURL } from '../../../hooks/useIconToImageURL'; -import { usePasswordModal } from '../../../hooks/usePasswordModal'; -import { mnDecode } from '../../../session/crypto/mnemonic'; -import { - updateHideRecoveryPasswordModal, - updateLightBoxOptions, - userSettingsModal, -} from '../../../state/ducks/modalDialog'; -import { getIsModalVisible } from '../../../state/selectors/modal'; -import { useHideRecoveryPasswordEnabled } from '../../../state/selectors/settings'; -import { THEME_GLOBALS } from '../../../themes/globals'; -import { prepareQRCodeForLightBox } from '../../../util/qrCodes'; -import { getCurrentRecoveryPhrase } from '../../../util/storage'; -import { QRCodeLogoProps, SessionQRCode } from '../../SessionQRCode'; -import { AnimatedFlex } from '../../basic/Flex'; -import { Localizer } from '../../basic/Localizer'; -import { SessionButton, SessionButtonColor } from '../../basic/SessionButton'; -import { SpacerMD, SpacerSM } from '../../basic/Text'; -import { CopyToClipboardIcon } from '../../buttons/CopyToClipboardButton'; -import { - SessionSettingButtonItem, - SessionSettingsItemWrapper, - StyledSettingItem, -} from '../SessionSettingListItem'; -import { tr } from '../../../localization/localeTools'; - -const StyledSettingsItemContainer = styled.div` - p { - font-size: var(--font-size-md); - line-height: 30px; - margin: 0; - } - - button[data-testid='hide-recovery-password-button'] { - width: 130px; - } - - ${StyledSettingItem} { - svg { - margin-top: -2px; - } - } -`; - -const StyledRecoveryPassword = styled(AnimatedFlex)<{ color: string }>` - font-family: var(--font-mono); - font-size: var(--font-size-sm); - text-align: justify; - user-select: text; - border: 2px solid var(--text-secondary-color); - border-radius: 11px; - padding: var(--margins-sm) var(--margins-sm) var(--margins-sm) var(--margins-md); - margin: 0; - max-width: fit-content; - color: ${props => props.color}; -`; - -const qrLogoProps: QRCodeLogoProps = { - iconType: 'shield', - iconSize: 56, -}; - -export const SettingsCategoryRecoveryPassword = () => { - const recoveryPhrase = getCurrentRecoveryPhrase(); - if (!recoveryPhrase) { - throw new Error('SettingsCategoryRecoveryPassword recovery seed is empty'); - } - const hexEncodedSeed = mnDecode(recoveryPhrase, 'english'); - const [isQRVisible, setIsQRVisible] = useState(false); - - const hideRecoveryPassword = useHideRecoveryPasswordEnabled(); - const isModalVisible = useSelector(getIsModalVisible); - - const { dataURL, iconSize, iconColor, backgroundColor, loading } = useIconToImageURL(qrLogoProps); - - const dispatch = useDispatch(); - - const { hasPassword, passwordValid } = usePasswordModal({ - onClose: () => { - dispatch(userSettingsModal({ userSettingsPage: 'privacy' })); - }, - }); - - useHotkey( - 'v', - () => { - if (!isModalVisible) { - setIsQRVisible(!isQRVisible); - } - }, - (hasPassword && !passwordValid) || hideRecoveryPassword - ); - - if ((hasPassword && !passwordValid) || hideRecoveryPassword) { - return null; - } - - return ( - - } - inline={false} - > - - {isQRVisible ? ( - { - const lightBoxOptions = prepareQRCodeForLightBox(fileName, dataUrl); - dispatch(updateLightBoxOptions(lightBoxOptions)); - }} - ariaLabel={'Recovery Password QR Code'} - dataTestId={'session-recovery-password'} - /> - ) : ( - - {recoveryPhrase} - - - - )} - - - { - setIsQRVisible(!isQRVisible); - }} - style={{ - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center', - gap: isQRVisible ? undefined : 'var(--margins-xs)', - marginLeft: isQRVisible ? '-8px' : undefined, - }} - > - {isQRVisible ? tr('recoveryPasswordView') : tr('qrView')} - - - {!hideRecoveryPassword ? ( - { - dispatch(updateHideRecoveryPasswordModal({ state: 'firstWarning' })); - }} - buttonText={tr('hide')} - buttonColor={SessionButtonColor.Danger} - dataTestId={'hide-recovery-password-button'} - /> - ) : null} - - ); -}; diff --git a/ts/hooks/useIconToImageURL.tsx b/ts/hooks/useIconToImageURL.tsx index cb41840dd..3c3053358 100644 --- a/ts/hooks/useIconToImageURL.tsx +++ b/ts/hooks/useIconToImageURL.tsx @@ -10,27 +10,24 @@ const chooseIconColors = ( defaultColor: ThemeKeys, darkColor?: ThemeKeys, lightColor?: ThemeKeys, - isThemed?: boolean, isDarkTheme?: boolean ) => { return getThemeValue( - isThemed && darkColor && lightColor ? (isDarkTheme ? darkColor : lightColor) : defaultColor + darkColor && lightColor ? (isDarkTheme ? darkColor : lightColor) : defaultColor ); }; export const convertIconToImageURL = async ( props: Pick & { - isThemed?: boolean; isDarkTheme?: boolean; } ): Promise<{ dataUrl: string; bgColor: string; fgColor: string }> => { - const { iconType, iconSize, isThemed, isDarkTheme } = props; + const { iconType, iconSize, isDarkTheme } = props; const fgColor = chooseIconColors( '--black-color', '--background-primary-color', '--text-primary-color', - isThemed, isDarkTheme ); @@ -38,7 +35,6 @@ export const convertIconToImageURL = async ( '--white-color', '--text-primary-color', '--background-primary-color', - isThemed, isDarkTheme ); @@ -76,11 +72,9 @@ export const convertIconToImageURL = async ( export const useIconToImageURL = ({ iconType, iconSize, - isThemed = true, }: { iconType: SessionIconType; iconSize: number; - isThemed?: boolean; }) => { const isDarkTheme = useIsDarkTheme(); const [dataURL, setDataURL] = useState(''); @@ -102,7 +96,6 @@ export const useIconToImageURL = ({ } = await convertIconToImageURL({ iconType, iconSize, - isThemed, isDarkTheme, }); @@ -122,17 +115,17 @@ export const useIconToImageURL = ({ } catch (error) { window.log.error('[useIconToImageURL] Error fetching icon data url', error); } - }, [iconSize, iconType, isDarkTheme, isThemed, mounted]); + }, [iconSize, iconType, isDarkTheme, mounted]); useMount(() => { void loadURL(); }); useEffect(() => { - if (!loading && mounted && isThemed && isDarkTheme !== inDarkTheme) { + if (!loading && mounted && isDarkTheme !== inDarkTheme) { void loadURL(); } - }, [inDarkTheme, isDarkTheme, isThemed, loadURL, loading, mounted]); + }, [inDarkTheme, isDarkTheme, loadURL, loading, mounted]); return { dataURL, iconSize, iconColor, backgroundColor, loading }; }; diff --git a/ts/hooks/useParamSelector.ts b/ts/hooks/useParamSelector.ts index 2ee9eecaa..c219d0d46 100644 --- a/ts/hooks/useParamSelector.ts +++ b/ts/hooks/useParamSelector.ts @@ -1,7 +1,6 @@ import { createSelector } from '@reduxjs/toolkit'; import { PubkeyType, type GroupPubkeyType } from 'libsession_util_nodejs'; import { compact, isEmpty, isFinite, isNumber, pick } from 'lodash'; -import { useMemo } from 'react'; import { useSelector } from 'react-redux'; import { hasValidIncomingRequestValues, @@ -9,7 +8,7 @@ import { } from '../models/conversation'; import { ConversationTypeEnum } from '../models/types'; import { isUsAnySogsFromCache } from '../session/apis/open_group_api/sogsv3/knownBlindedkeys'; -import { TimerOptions, TimerOptionsArray } from '../session/disappearing_messages/timerOptions'; +import { TimerOptions } from '../session/disappearing_messages/timerOptions'; import { PubKey } from '../session/types'; import { UserUtils } from '../session/utils'; import { PropsForExpiringMessage } from '../state/ducks/conversations'; @@ -437,39 +436,6 @@ export function useMessageExpirationPropsById(messageId?: string) { }); } -export function useTimerOptionsByMode(disappearingMessageMode?: string, hasOnlyOneMode?: boolean) { - return useMemo(() => { - const options: TimerOptionsArray = []; - if (hasOnlyOneMode) { - options.push({ - name: TimerOptions.getName(TimerOptions.VALUES[0]), - value: TimerOptions.VALUES[0], - }); - } - switch (disappearingMessageMode) { - case 'deleteAfterRead': - options.push( - ...TimerOptions.DELETE_AFTER_READ.map(option => ({ - name: TimerOptions.getName(option), - value: option, - })) - ); - break; - case 'deleteAfterSend': - options.push( - ...TimerOptions.DELETE_AFTER_SEND.map(option => ({ - name: TimerOptions.getName(option), - value: option, - })) - ); - break; - default: - return []; - } - return options; - }, [disappearingMessageMode, hasOnlyOneMode]); -} - export function useQuoteAuthorName(authorId?: string): { authorName: string | undefined; isMe: boolean; @@ -522,7 +488,7 @@ export function useSortedGroupMembers(convoId: string | undefined): Array; - // prettier-ignore const VALUES: Array = [ /** off */ diff --git a/ts/state/ducks/modalDialog.tsx b/ts/state/ducks/modalDialog.tsx index f2ddcb939..24f97734b 100644 --- a/ts/state/ducks/modalDialog.tsx +++ b/ts/state/ducks/modalDialog.tsx @@ -132,7 +132,7 @@ export const initialModalState: ModalState = { groupMembersModal: null, userProfileModal: null, nickNameModal: null, - userSettingsModal: { userSettingsPage: 'appearance' }, + userSettingsModal: null, onionPathModal: null, enterPasswordModal: null, sessionPasswordModal: null, diff --git a/ts/themes/globals.tsx b/ts/themes/globals.tsx index 78aca1e6e..05d4423a3 100644 --- a/ts/themes/globals.tsx +++ b/ts/themes/globals.tsx @@ -135,6 +135,8 @@ type ThemeGlobals = { /* Used for Quote References Not Found */ '--message-link-preview-background-color': string; + '--modal-actions-outline-min-width': string; + /* Right Panel */ '--right-panel-width': string; '--right-panel-height': string; @@ -269,6 +271,8 @@ export const THEME_GLOBALS: ThemeGlobals = { '--message-link-preview-background-color': `rgba(${hexColorToRGB(COLORS.BLACK)}, 0.06)`, + '--modal-actions-outline-min-width': '125px', + '--right-panel-width': '420px', '--right-panel-height': '100%', '--right-panel-attachment-width': 'calc(var(--right-panel-width) - 2 * var(--margins-2xl) - 7px)', From 1bb608a8e97cc3c7281805fc34a3cf8cd8ae9cab Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Thu, 21 Aug 2025 10:54:24 +1000 Subject: [PATCH 13/18] chore: updated crowdin strings --- _locales/af/messages.json | 1 + _locales/ar/messages.json | 1 + _locales/az/messages.json | 1 + _locales/bal/messages.json | 1 + _locales/be/messages.json | 1 + _locales/bg/messages.json | 1 + _locales/bn/messages.json | 1 + _locales/ca/messages.json | 1 + _locales/cs/messages.json | 1 + _locales/cy/messages.json | 1 + _locales/da/messages.json | 1 + _locales/de/messages.json | 1 + _locales/el/messages.json | 1 + _locales/en/messages.json | 3 +++ _locales/eo/messages.json | 1 + _locales/es-419/messages.json | 1 + _locales/es/messages.json | 1 + _locales/et/messages.json | 1 + _locales/eu/messages.json | 1 + _locales/fa/messages.json | 1 + _locales/fi/messages.json | 1 + _locales/fil/messages.json | 1 + _locales/fr/messages.json | 1 + _locales/gl/messages.json | 1 + _locales/ha/messages.json | 1 + _locales/he/messages.json | 1 + _locales/hi/messages.json | 1 + _locales/hr/messages.json | 1 + _locales/hu/messages.json | 1 + _locales/hy-AM/messages.json | 1 + _locales/id/messages.json | 1 + _locales/it/messages.json | 1 + _locales/ja/messages.json | 1 + _locales/ka/messages.json | 1 + _locales/km/messages.json | 1 + _locales/kmr/messages.json | 1 + _locales/kn/messages.json | 1 + _locales/ko/messages.json | 1 + _locales/ku/messages.json | 1 + _locales/lg/messages.json | 1 + _locales/lo/messages.json | 1 + _locales/lt/messages.json | 1 + _locales/lv/messages.json | 1 + _locales/mk/messages.json | 1 + _locales/mn/messages.json | 1 + _locales/ms/messages.json | 1 + _locales/my/messages.json | 1 + _locales/nb/messages.json | 1 + _locales/ne/messages.json | 1 + _locales/nl/messages.json | 1 + _locales/nn/messages.json | 1 + _locales/no/messages.json | 1 + _locales/ny/messages.json | 1 + _locales/pa/messages.json | 1 + _locales/pl/messages.json | 1 + _locales/ps/messages.json | 1 + _locales/pt-BR/messages.json | 1 + _locales/pt-PT/messages.json | 1 + _locales/ro/messages.json | 1 + _locales/ru/messages.json | 1 + _locales/sh/messages.json | 1 + _locales/si/messages.json | 1 + _locales/sk/messages.json | 1 + _locales/sl/messages.json | 1 + _locales/sq/messages.json | 1 + _locales/sr-CS/messages.json | 1 + _locales/sr-SP/messages.json | 1 + _locales/sv/messages.json | 1 + _locales/sw/messages.json | 1 + _locales/ta/messages.json | 1 + _locales/te/messages.json | 1 + _locales/th/messages.json | 1 + _locales/tl/messages.json | 1 + _locales/tr/messages.json | 1 + _locales/uk/messages.json | 1 + _locales/ur/messages.json | 1 + _locales/uz/messages.json | 1 + _locales/vi/messages.json | 1 + _locales/xh/messages.json | 1 + _locales/zh-CN/messages.json | 1 + _locales/zh-TW/messages.json | 1 + 81 files changed, 83 insertions(+) diff --git a/_locales/af/messages.json b/_locales/af/messages.json index 4677003ee..500655ac6 100644 --- a/_locales/af/messages.json +++ b/_locales/af/messages.json @@ -639,6 +639,7 @@ "pinUnpin": "Losmaak", "pinUnpinConversation": "Maak Gesprek Los", "preview": "Voorskou", + "pro": "Pro", "profile": "Profiel", "profileDisplayPicture": "Vertoon Prent", "profileDisplayPictureRemoveError": "Kon nie vertoonbeeld verwyder nie.", diff --git a/_locales/ar/messages.json b/_locales/ar/messages.json index 4bb188034..ecc636c72 100644 --- a/_locales/ar/messages.json +++ b/_locales/ar/messages.json @@ -697,6 +697,7 @@ "pinUnpin": "إلغاء التثبيت", "pinUnpinConversation": "إلغاء تثبيت المحادثة", "preview": "معاينة", + "pro": "Pro", "profile": "الملف الشخصي", "profileDisplayPicture": "صورة العرض", "profileDisplayPictureRemoveError": "فشل في إزالة صورة العرض.", diff --git a/_locales/az/messages.json b/_locales/az/messages.json index 5f0d340c9..22afeaa4d 100644 --- a/_locales/az/messages.json +++ b/_locales/az/messages.json @@ -757,6 +757,7 @@ "pinUnpin": "Sancağı götür", "pinUnpinConversation": "Danışıq sancağını götür", "preview": "Önizləmə", + "pro": "Pro", "proActivated": "Aktivləşdirildi", "proAlreadyPurchased": "Artıq yüksəltdiniz", "proAnimatedDisplayPicture": "Getdik və ekran şəkliniz üçün GIF-lər və animasiyalı WebP təsvirləri yükləyin!", diff --git a/_locales/bal/messages.json b/_locales/bal/messages.json index 2de9fa22f..a16e511e5 100644 --- a/_locales/bal/messages.json +++ b/_locales/bal/messages.json @@ -638,6 +638,7 @@ "pinUnpin": "پن ہٹائیں", "pinUnpinConversation": "بات چیت کو انپِن کریں", "preview": "پیش نمایش", + "pro": "Pro", "profile": "پروفائل", "profileDisplayPicture": "تصویر دکھائیں", "profileDisplayPictureRemoveError": "ڈسپلے تصویر کو ہٹانے میں ناکامی", diff --git a/_locales/be/messages.json b/_locales/be/messages.json index 7bdc56a85..18711e71e 100644 --- a/_locales/be/messages.json +++ b/_locales/be/messages.json @@ -638,6 +638,7 @@ "pinUnpin": "Адмацаваць", "pinUnpinConversation": "Адмацаваць размову", "preview": "Перадпрагляд", + "pro": "Pro", "profile": "Профіль", "profileDisplayPicture": "Выява для адлюстравання", "profileDisplayPictureRemoveError": "Не атрымалася выдаліць выяву.", diff --git a/_locales/bg/messages.json b/_locales/bg/messages.json index e2d0c49ee..eec9de0c5 100644 --- a/_locales/bg/messages.json +++ b/_locales/bg/messages.json @@ -638,6 +638,7 @@ "pinUnpin": "Откачи", "pinUnpinConversation": "Откачване на разговор", "preview": "Преглед", + "pro": "Pro", "profile": "Профил", "profileDisplayPicture": "Профилна снимка", "profileDisplayPictureRemoveError": "Неуспешно премахване на картината за показване.", diff --git a/_locales/bn/messages.json b/_locales/bn/messages.json index df1eeaac4..3024e80fa 100644 --- a/_locales/bn/messages.json +++ b/_locales/bn/messages.json @@ -638,6 +638,7 @@ "pinUnpin": "আনপিন", "pinUnpinConversation": "কনভারসেশন আনপিন করুন", "preview": "পূর্বরূপ", + "pro": "Pro", "profile": "প্রোফাইল", "profileDisplayPicture": "প্রদর্শনী ছবি", "profileDisplayPictureRemoveError": "প্রদর্শন ছবি সরাতে ব্যর্থ হয়েছে।", diff --git a/_locales/ca/messages.json b/_locales/ca/messages.json index 8608e7054..524a09e86 100644 --- a/_locales/ca/messages.json +++ b/_locales/ca/messages.json @@ -756,6 +756,7 @@ "pinUnpin": "Desancoreu", "pinUnpinConversation": "Desancorar la conversa", "preview": "Vista prèvia", + "pro": "Pro", "proAlreadyPurchased": "Ja ho tens", "proAnimatedDisplayPicture": "Endavant i penja GIFs i imatges del webp animat per a la teva imatge de visualització!", "proAnimatedDisplayPictureCallToActionDescription": "Obteniu imatges de visualització animada i desbloquegeu funcions premium amb Session Pro", diff --git a/_locales/cs/messages.json b/_locales/cs/messages.json index 94577520e..75e91c0c4 100644 --- a/_locales/cs/messages.json +++ b/_locales/cs/messages.json @@ -757,6 +757,7 @@ "pinUnpin": "Odepnout", "pinUnpinConversation": "Odepnout konverzaci", "preview": "Náhled", + "pro": "Pro", "proActivated": "Aktivováno", "proAlreadyPurchased": "Už máte", "proAnimatedDisplayPicture": "Jako váš zobrazovaný profilový obrázek nastavte animovaný GIF nebo WebP!", diff --git a/_locales/cy/messages.json b/_locales/cy/messages.json index d4557dce1..a22b7499c 100644 --- a/_locales/cy/messages.json +++ b/_locales/cy/messages.json @@ -649,6 +649,7 @@ "pinUnpin": "Datgloi Sgwrs", "pinUnpinConversation": "Datgloi Sgwrs", "preview": "Rhagolwg", + "pro": "Pro", "profile": "Proffil", "profileDisplayPicture": "Dangos llun", "profileDisplayPictureRemoveError": "Methwyd tynnu'r llun arddangos.", diff --git a/_locales/da/messages.json b/_locales/da/messages.json index e020ce32a..9f75119f0 100644 --- a/_locales/da/messages.json +++ b/_locales/da/messages.json @@ -724,6 +724,7 @@ "pinUnpin": "Frigør", "pinUnpinConversation": "Frigør samtale", "preview": "Forhåndsvisning", + "pro": "Pro", "profile": "Profil", "profileDisplayPicture": "Display Picture", "profileDisplayPictureRemoveError": "Kunne ikke fjerne displaybillede.", diff --git a/_locales/de/messages.json b/_locales/de/messages.json index 9023fed97..a13bfb166 100644 --- a/_locales/de/messages.json +++ b/_locales/de/messages.json @@ -757,6 +757,7 @@ "pinUnpin": "Lösen", "pinUnpinConversation": "Unterhaltung lösen", "preview": "Vorschau", + "pro": "Pro", "proActivated": "Aktiviert", "proAlreadyPurchased": "Du hast bereits", "proAnimatedDisplayPicture": "Lade GIF- und animierte WebP-Bilder als Profilbild hoch!", diff --git a/_locales/el/messages.json b/_locales/el/messages.json index 256f4e8a3..2b4fa2581 100644 --- a/_locales/el/messages.json +++ b/_locales/el/messages.json @@ -649,6 +649,7 @@ "pinUnpin": "Ξεκαρφίτσωμα", "pinUnpinConversation": "Ξεκαρφίτσωμα Συνομιλίας", "preview": "Προεπισκόπηση", + "pro": "Pro", "profile": "Προφίλ", "profileDisplayPicture": "Display Picture", "profileDisplayPictureRemoveError": "Αποτυχία κατάργησης εικόνας εμφάνισης.", diff --git a/_locales/en/messages.json b/_locales/en/messages.json index d82e11522..3b305e3f7 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -298,6 +298,7 @@ "copy": "Copy", "create": "Create", "creatingCall": "Creating Call", + "currentPassword": "Current Password", "cut": "Cut", "darkMode": "Dark Mode", "databaseErrorClearDataWarning": "Are you sure you want to delete all messages, attachments, and account data from this device and create a new account?", @@ -653,6 +654,7 @@ "modalMessageTooLongDescription": "Please shorten your message to {limit} characters or less.", "modalMessageTooLongTitle": "Message Too Long", "networkName": "Session Network", + "newPassword": "New Password", "next": "Next", "nicknameDescription": "Choose a nickname for {name}. This will appear to you in your one-to-one and group conversations.", "nicknameEnter": "Enter nickname", @@ -809,6 +811,7 @@ "preferences": "Preferences", "preview": "Preview", "previewNotification": "Preview Notification", + "pro": "Pro", "proActivated": "Activated", "proAlreadyPurchased": "You’ve already got", "proAnimatedDisplayPicture": "Go ahead and upload GIFs and animated WebP images for your display picture!", diff --git a/_locales/eo/messages.json b/_locales/eo/messages.json index 67b597672..5d5ff839f 100644 --- a/_locales/eo/messages.json +++ b/_locales/eo/messages.json @@ -708,6 +708,7 @@ "pinUnpin": "Depingli", "pinUnpinConversation": "Depingli Konversacion", "preview": "Antaŭrigardo", + "pro": "Pro", "profile": "Profilo", "profileDisplayPicture": "Montrata Bildo", "profileDisplayPictureRemoveError": "Malsukcesis forigi montrotan bildon.", diff --git a/_locales/es-419/messages.json b/_locales/es-419/messages.json index 57e615fb3..f415366ce 100644 --- a/_locales/es-419/messages.json +++ b/_locales/es-419/messages.json @@ -757,6 +757,7 @@ "pinUnpin": "Desfijar", "pinUnpinConversation": "Desfijar conversación", "preview": "Vista Previa", + "pro": "Pro", "proActivated": "Activado", "proAlreadyPurchased": "Ya tienes", "proAnimatedDisplayPicture": "¡Adelante, sube GIFs e imágenes WebP animadas para tu imagen de perfil!", diff --git a/_locales/es/messages.json b/_locales/es/messages.json index ecb37eb9b..3784df5f0 100644 --- a/_locales/es/messages.json +++ b/_locales/es/messages.json @@ -757,6 +757,7 @@ "pinUnpin": "Desfijar", "pinUnpinConversation": "Desanclar conversación", "preview": "Previsualizar", + "pro": "Pro", "proActivated": "Activado", "proAlreadyPurchased": "Ya tienes", "proAnimatedDisplayPicture": "¡Adelante, sube GIFs e imágenes WebP animadas para tu imagen de perfil!", diff --git a/_locales/et/messages.json b/_locales/et/messages.json index ec8b9e6d4..738cbbb43 100644 --- a/_locales/et/messages.json +++ b/_locales/et/messages.json @@ -638,6 +638,7 @@ "pinUnpin": "Vabasta", "pinUnpinConversation": "Vabasta vestlus", "preview": "Eelvaade", + "pro": "Pro", "profile": "Profiil", "profileDisplayPicture": "Kuvapilt", "profileDisplayPictureRemoveError": "Kuvapildi eemaldamine ebaõnnestus.", diff --git a/_locales/eu/messages.json b/_locales/eu/messages.json index 29d06b9fd..9195a7cec 100644 --- a/_locales/eu/messages.json +++ b/_locales/eu/messages.json @@ -638,6 +638,7 @@ "pinUnpin": "Despintatu", "pinUnpinConversation": "Despintatu Elkarrizketa", "preview": "Aurreikusi", + "pro": "Pro", "profile": "Profil", "profileDisplayPicture": "Erakutsi Irudia", "profileDisplayPictureRemoveError": "Ez da posible izan erakusizko irudia kentzea.", diff --git a/_locales/fa/messages.json b/_locales/fa/messages.json index c4ea08e2b..7429bd61d 100644 --- a/_locales/fa/messages.json +++ b/_locales/fa/messages.json @@ -637,6 +637,7 @@ "pinUnpin": "برداشتن سنجاق", "pinUnpinConversation": "گفتگو را از حالت پین خارج کنید", "preview": "پیش نمایش", + "pro": "Pro", "profile": "نمایه", "profileDisplayPicture": "نمایش تصویر نمایه", "profileDisplayPictureRemoveError": "حذف تصویر نمایشی ناموفق بود.", diff --git a/_locales/fi/messages.json b/_locales/fi/messages.json index 5ebf49b9d..f790badf1 100644 --- a/_locales/fi/messages.json +++ b/_locales/fi/messages.json @@ -650,6 +650,7 @@ "pinUnpin": "Irrota", "pinUnpinConversation": "Irroita keskustelu", "preview": "Esikatselu", + "pro": "Pro", "profile": "Profiili", "profileDisplayPicture": "Näyttökuva", "profileDisplayPictureRemoveError": "Näyttökuvan poisto ei onnistunut.", diff --git a/_locales/fil/messages.json b/_locales/fil/messages.json index 2497742d0..d5ed7719c 100644 --- a/_locales/fil/messages.json +++ b/_locales/fil/messages.json @@ -638,6 +638,7 @@ "pinUnpin": "I-unpin", "pinUnpinConversation": "I-unpin ang Usapan", "preview": "Preview", + "pro": "Pro", "profile": "Profile", "profileDisplayPicture": "Display Picture", "profileDisplayPictureRemoveError": "Nabigo sa pag-alis ng display picture.", diff --git a/_locales/fr/messages.json b/_locales/fr/messages.json index a23bdaaeb..c6cd29614 100644 --- a/_locales/fr/messages.json +++ b/_locales/fr/messages.json @@ -757,6 +757,7 @@ "pinUnpin": "Désépingler", "pinUnpinConversation": "Désépingler la conversation", "preview": "Aperçu", + "pro": "Pro", "proActivated": "Activé", "proAlreadyPurchased": "Vous avez déjà", "proAnimatedDisplayPicture": "Téléchargez des GIF et des images WebP animées pour votre photo de profil !", diff --git a/_locales/gl/messages.json b/_locales/gl/messages.json index 63f13212f..18da9fba3 100644 --- a/_locales/gl/messages.json +++ b/_locales/gl/messages.json @@ -569,6 +569,7 @@ "pinUnpin": "Desfixar", "pinUnpinConversation": "Desfixar conversa", "preview": "Previsualización", + "pro": "Pro", "profile": "Perfil", "profileDisplayPicture": "Imaxe de perfil", "profileDisplayPictureRemoveError": "Non se puido eliminar a imaxe de perfil.", diff --git a/_locales/ha/messages.json b/_locales/ha/messages.json index 26d1f2c7a..ad135b728 100644 --- a/_locales/ha/messages.json +++ b/_locales/ha/messages.json @@ -638,6 +638,7 @@ "pinUnpin": "Cire pin", "pinUnpinConversation": "Cire pin saduwa", "preview": "Duba", + "pro": "Pro", "profile": "Bayanin kai", "profileDisplayPicture": "Hoto na Nuna Fuska", "profileDisplayPictureRemoveError": "An kasa cire hoton nunawa.", diff --git a/_locales/he/messages.json b/_locales/he/messages.json index c5ea1fa28..7133ab054 100644 --- a/_locales/he/messages.json +++ b/_locales/he/messages.json @@ -638,6 +638,7 @@ "pinUnpin": "בטל נעיצה", "pinUnpinConversation": "בטל נעיצה של שיחה", "preview": "תצוגה מקדימה", + "pro": "Pro", "profile": "פרופיל", "profileDisplayPicture": "תמונת תצוגה", "profileDisplayPictureRemoveError": "נכשל הסרת תמונת הצגה.", diff --git a/_locales/hi/messages.json b/_locales/hi/messages.json index 5700187cf..3a55ab428 100644 --- a/_locales/hi/messages.json +++ b/_locales/hi/messages.json @@ -757,6 +757,7 @@ "pinUnpin": "अनपिन करें", "pinUnpinConversation": "वार्तालाप अनपिन करें", "preview": "Preview", + "pro": "Pro", "proActivated": "सक्रिय किया गया", "proAlreadyPurchased": "आपके पास पहले से ही है", "proAnimatedDisplayPicture": "आगे बढ़ें और अपनी डिस्प्ले तस्वीर के लिए GIF और एनिमेटेड WebP इमेज अपलोड करें!", diff --git a/_locales/hr/messages.json b/_locales/hr/messages.json index d3245d6f2..aa7946174 100644 --- a/_locales/hr/messages.json +++ b/_locales/hr/messages.json @@ -638,6 +638,7 @@ "pinUnpin": "Otkvači", "pinUnpinConversation": "Otkvači razgovor", "preview": "Pregled", + "pro": "Pro", "profile": "Profil", "profileDisplayPicture": "Slika za prikaz", "profileDisplayPictureRemoveError": "Uklanjanje slike za prikaz nije uspjelo.", diff --git a/_locales/hu/messages.json b/_locales/hu/messages.json index 926cecdb9..fdb810f10 100644 --- a/_locales/hu/messages.json +++ b/_locales/hu/messages.json @@ -745,6 +745,7 @@ "pinUnpin": "Kitűzés eltávolítása", "pinUnpinConversation": "Beszélgetés kitűzésének eltávolítása", "preview": "Előnézet", + "pro": "Pro", "proCallToActionLongerMessages": "Szeretne hosszabb üzeneteket küldeni? Küldjön több szöveget és oldja fel a prémium funkciókat a Session Pro szolgáltatással", "proFeatureListLargerGroups": "Nagyobb csoportos beszélgetések akár 300 taggal", "proFeatureListLoadsMore": "Plusz még több exkluzív funkció", diff --git a/_locales/hy-AM/messages.json b/_locales/hy-AM/messages.json index 7cdc1e2d6..9a8dff108 100644 --- a/_locales/hy-AM/messages.json +++ b/_locales/hy-AM/messages.json @@ -638,6 +638,7 @@ "pinUnpin": "Արձակել", "pinUnpinConversation": "Ապամրացնել զրույցը", "preview": "Նախադիտում", + "pro": "Pro", "profile": "Հաշիվ", "profileDisplayPicture": "Ցուցադրվող գլուխ", "profileDisplayPictureRemoveError": "Չհաջողվեց հեռացնել ցուցադրվող լուսանկարը։", diff --git a/_locales/id/messages.json b/_locales/id/messages.json index 5bd658151..e2f925103 100644 --- a/_locales/id/messages.json +++ b/_locales/id/messages.json @@ -703,6 +703,7 @@ "pinUnpin": "Lepas sematan", "pinUnpinConversation": "Lepas Semat Percakapan", "preview": "Pratinjau", + "pro": "Pro", "profile": "Profil", "profileDisplayPicture": "Tampilan Gambar", "profileDisplayPictureRemoveError": "Gagal menghapus gambar profil.", diff --git a/_locales/it/messages.json b/_locales/it/messages.json index d56fbdbb9..eee3cde32 100644 --- a/_locales/it/messages.json +++ b/_locales/it/messages.json @@ -757,6 +757,7 @@ "pinUnpin": "Non mettere in evidenza", "pinUnpinConversation": "Non mettere in evidenza la chat", "preview": "Anteprima", + "pro": "Pro", "proActivated": "Attivato", "proAlreadyPurchased": "Hai già attivato", "proAnimatedDisplayPicture": "Carica GIF e immagini WebP animate per la tua immagine del profilo!", diff --git a/_locales/ja/messages.json b/_locales/ja/messages.json index 095d648cf..a8db30fb4 100644 --- a/_locales/ja/messages.json +++ b/_locales/ja/messages.json @@ -757,6 +757,7 @@ "pinUnpin": "ピン留めを外す", "pinUnpinConversation": "会話のピン留めを外す", "preview": "プレビュー", + "pro": "Pro", "proActivated": "アクティベート済み", "proAlreadyPurchased": "すでにご利用中です", "proAnimatedDisplayPicture": "ディスプレイ画像としてGIFやアニメーションWebP画像をアップロードできます!", diff --git a/_locales/ka/messages.json b/_locales/ka/messages.json index dea6737cb..2e2dacd2c 100644 --- a/_locales/ka/messages.json +++ b/_locales/ka/messages.json @@ -650,6 +650,7 @@ "pinUnpin": "პიმის მოხსნა", "pinUnpinConversation": "საუბრის პიმის მოხსნა", "preview": "ჩვენება", + "pro": "Pro", "profile": "პროფილი", "profileDisplayPicture": "პროფილის სურათი", "profileDisplayPictureRemoveError": "ვერ შევძელიში სურათის გამოღების მოცილება", diff --git a/_locales/km/messages.json b/_locales/km/messages.json index 03bb2024a..7e3543771 100644 --- a/_locales/km/messages.json +++ b/_locales/km/messages.json @@ -638,6 +638,7 @@ "pinUnpin": "ដកខ្ទាស់", "pinUnpinConversation": "បិតខ្ទាស់ការសន្ទនា", "preview": "មើលជាមុន", + "pro": "Pro", "profile": "ប្រវត្តិរូប", "profileDisplayPicture": "បង្ហាញរូបភាព", "profileDisplayPictureRemoveError": "បរាជ័យក្នុងការដករូបតំណាងបង្ហាញចេញ។", diff --git a/_locales/kmr/messages.json b/_locales/kmr/messages.json index 1cf135489..e6a9a1798 100644 --- a/_locales/kmr/messages.json +++ b/_locales/kmr/messages.json @@ -649,6 +649,7 @@ "pinUnpin": "Pulina bikarînî", "pinUnpinConversation": "Pulina Peyven", "preview": "Pêşdîtin", + "pro": "Pro", "profile": "Profîl", "profileDisplayPicture": "Resmê Xuya bike", "profileDisplayPictureRemoveError": "Rûberê profîlê remove têbîne", diff --git a/_locales/kn/messages.json b/_locales/kn/messages.json index 71b92110f..be0766d71 100644 --- a/_locales/kn/messages.json +++ b/_locales/kn/messages.json @@ -638,6 +638,7 @@ "pinUnpin": "ಅನ್‌ಪಿನ್ ಮಾಡಿ", "pinUnpinConversation": "ಸಂಭಾಷಣೆಯನ್ನು ಅನ್‌ಪಿನ್ ಮಾಡಿ", "preview": "ಮುನ್ನೋಟ", + "pro": "Pro", "profile": "ಪ್ರೊಫೈಲ್", "profileDisplayPicture": "ಪ್ರದರ್ಶನ ಚಿತ್ರ", "profileDisplayPictureRemoveError": "ಪ್ರದರ್ಶನ ಚಿತ್ರವನ್ನು ತೆಗೆದುಹಾಕಲು ವಿಫಲವಾಗಿದೆ.", diff --git a/_locales/ko/messages.json b/_locales/ko/messages.json index 5f8e84900..560fd7da0 100644 --- a/_locales/ko/messages.json +++ b/_locales/ko/messages.json @@ -737,6 +737,7 @@ "pinUnpin": "고정 해제", "pinUnpinConversation": "대화 고정 취소", "preview": "미리보기", + "pro": "Pro", "profile": "프로필", "profileDisplayPicture": "프로필 사진 설정", "profileDisplayPictureRemoveError": "표시 사진을 제거하지 못했습니다.", diff --git a/_locales/ku/messages.json b/_locales/ku/messages.json index e626c8e53..d013d4667 100644 --- a/_locales/ku/messages.json +++ b/_locales/ku/messages.json @@ -639,6 +639,7 @@ "pinUnpin": "لابران", "pinUnpinConversation": "لابردنی گفتوگۆ", "preview": "پێشاندان", + "pro": "Pro", "profile": "پرۆفایل", "profileDisplayPicture": "پیشاندانی وێنە", "profileDisplayPictureRemoveError": "شکستی پاشەکەوتکردنی وێنەی پەیپەر", diff --git a/_locales/lg/messages.json b/_locales/lg/messages.json index 827e04702..ee47f673e 100644 --- a/_locales/lg/messages.json +++ b/_locales/lg/messages.json @@ -638,6 +638,7 @@ "pinUnpin": "Gulaaga", "pinUnpinConversation": "Gulaaga Mukwokulabanka", "preview": "Laba Omuweereza", + "pro": "Pro", "profile": "Shift", "profileDisplayPicture": "Ekifananyi Kyongezebwa", "profileDisplayPictureRemoveError": "Ensobi okwogolola ekifo ky'ebifaananyi.", diff --git a/_locales/lo/messages.json b/_locales/lo/messages.json index 496629970..2f1d311a1 100644 --- a/_locales/lo/messages.json +++ b/_locales/lo/messages.json @@ -235,6 +235,7 @@ "permissionsStorageSave": "Session ຕ້ອງການເຂົ້າເຖິງຟາຍເພື່ອບັນທຶກຢາງແລະວິດີໂອ.", "permissionsStorageSaveDenied": "Session ຕ້ອງການເຂົ້າເຖິງຟາຍເພື່ອບັນທຶກຮູບແລະວິດີໂອ, ແຕ່ເຄື່ອງຫນຶ້ງເຂົ້າໄປອັນດີໂຕຍປະຫຍັດ. ກະລູນາຄົນທີ່ຕັ້ງຄ່າປຣະກາດສົມບູນ, ເລືອກ \"ການອະນຸຍາດ\", ແລະເປີດ \"ຍາງ\".", "permissionsStorageSend": "Session ຕ້ອງການເຂົ້າເຖິງຟາຍເພື່ອສົ່ງຮູບແລະວິດີໂອ.", + "pro": "Pro", "profileDisplayPicture": "ຮູບພາບສະແດງ", "recoveryPasswordEnter": "ປ້ອນລະຫັດການຟື້ນຄືນຂອງທ່ານ", "recoveryPasswordRestoreDescription": "ປ້ອນລະຫັດການຟື້ນຄືນຂອງທ່ານເພື່ອດາວໂຫຼດບັນດານຂອງທ່ານ. ຖ້າທ່ານຍັງບໍ່ໄດ້ຟອມມັນ, ທ່ານສາມາດຫາມັນໄດ້ໃນການຕັ້ງຄ່າແອັບຂອງທ່ານ.", diff --git a/_locales/lt/messages.json b/_locales/lt/messages.json index 46d685ba2..9bceee0cc 100644 --- a/_locales/lt/messages.json +++ b/_locales/lt/messages.json @@ -641,6 +641,7 @@ "pinUnpin": "Atsegti", "pinUnpinConversation": "Atsegti pokalbį", "preview": "Peržiūra", + "pro": "Pro", "profile": "Profilis", "profileDisplayPicture": "Rodomas paveikslas", "profileDisplayPictureRemoveError": "Nepavyko pašalinti profilio paveiksliuko.", diff --git a/_locales/lv/messages.json b/_locales/lv/messages.json index 1fa58ed9b..69e4d8e3a 100644 --- a/_locales/lv/messages.json +++ b/_locales/lv/messages.json @@ -592,6 +592,7 @@ "pinUnpin": "Atspraust", "pinUnpinConversation": "Atspraust sarunu", "preview": "Priekšskatījums", + "pro": "Pro", "profile": "Profils", "profileDisplayPicture": "Atainojamais attēls", "profileDisplayPictureRemoveError": "Neizdevās noņemt profila attēlu.", diff --git a/_locales/mk/messages.json b/_locales/mk/messages.json index 6c57d518f..f2509d923 100644 --- a/_locales/mk/messages.json +++ b/_locales/mk/messages.json @@ -638,6 +638,7 @@ "pinUnpin": "Откачи", "pinUnpinConversation": "Откачи разговор", "preview": "Преглед", + "pro": "Pro", "profile": "Профил", "profileDisplayPicture": "Слика за прикажување", "profileDisplayPictureRemoveError": "Неуспешно отстранување на слика за профил.", diff --git a/_locales/mn/messages.json b/_locales/mn/messages.json index f47bdfa20..9aecb66c8 100644 --- a/_locales/mn/messages.json +++ b/_locales/mn/messages.json @@ -649,6 +649,7 @@ "pinUnpin": "Түгжээс салгах", "pinUnpinConversation": "Яриа түгжээс салгах", "preview": "Урьдчилан харах", + "pro": "Pro", "profile": "Профайл", "profileDisplayPicture": "Дүр зураг", "profileDisplayPictureRemoveError": "Харагдах зургыг устгахад алдаа гарлаа.", diff --git a/_locales/ms/messages.json b/_locales/ms/messages.json index e1fb8fda4..6b4c24bbd 100644 --- a/_locales/ms/messages.json +++ b/_locales/ms/messages.json @@ -649,6 +649,7 @@ "pinUnpin": "Nyah pin", "pinUnpinConversation": "Nyah Pin Perbualan", "preview": "Pratonton", + "pro": "Pro", "profile": "Profil", "profileDisplayPicture": "Paparan Gambar", "profileDisplayPictureRemoveError": "Gagal mengeluarkan gambar paparan.", diff --git a/_locales/my/messages.json b/_locales/my/messages.json index ea407a710..c8387e938 100644 --- a/_locales/my/messages.json +++ b/_locales/my/messages.json @@ -638,6 +638,7 @@ "pinUnpin": "ပင်ဖြစ်သည့် စကားပြောပါမည်", "pinUnpinConversation": "စကားပြောရန် စကားပြောပါမည်", "preview": "အစမ်းကြည့်ရှု", + "pro": "Pro", "profile": "ကိုယ်ရေး", "profileDisplayPicture": "ပုံပြပါမည့်ဓာတ်ပုံ", "profileDisplayPictureRemoveError": "ပြထားသောပုံကို ဖယ်ရန် မဖြစ်နိုင်ပါ", diff --git a/_locales/nb/messages.json b/_locales/nb/messages.json index d4c932a3e..121021d6b 100644 --- a/_locales/nb/messages.json +++ b/_locales/nb/messages.json @@ -641,6 +641,7 @@ "pinUnpin": "Løsne", "pinUnpinConversation": "Løsne samtale", "preview": "Forhåndsvisning", + "pro": "Pro", "profile": "Profil", "profileDisplayPicture": "Visningsbilde", "profileDisplayPictureRemoveError": "Kunne ikke fjerne profilbilde.", diff --git a/_locales/ne/messages.json b/_locales/ne/messages.json index 8292d5bef..6ce71a561 100644 --- a/_locales/ne/messages.json +++ b/_locales/ne/messages.json @@ -636,6 +636,7 @@ "pinUnpin": "अनपिन", "pinUnpinConversation": "वार्तालाप अनपिन गर्नुहोस्", "preview": "पूर्वावलोकन", + "pro": "Pro", "profile": "प्रोफाइल", "profileDisplayPicture": "प्रदर्शन तस्वीर", "profileDisplayPictureRemoveError": "प्रदर्शन तस्वीर हटाउन असफल", diff --git a/_locales/nl/messages.json b/_locales/nl/messages.json index f17a9626a..0cc8fbcac 100644 --- a/_locales/nl/messages.json +++ b/_locales/nl/messages.json @@ -757,6 +757,7 @@ "pinUnpin": "Losmaken", "pinUnpinConversation": "Gesprek losmaken", "preview": "Voorbeeld", + "pro": "Pro", "proActivated": "Geactiveerd", "proAlreadyPurchased": "Je hebt al", "proAnimatedDisplayPicture": "Upload nu GIF's en geanimeerde WebP-afbeeldingen voor je profielfoto!", diff --git a/_locales/nn/messages.json b/_locales/nn/messages.json index 0eb88f0e3..d8955a90f 100644 --- a/_locales/nn/messages.json +++ b/_locales/nn/messages.json @@ -640,6 +640,7 @@ "pinUnpin": "Løsne", "pinUnpinConversation": "Løsne samtale", "preview": "Forhåndsvisning", + "pro": "Pro", "profile": "Profil", "profileDisplayPicture": "Visingsbilde", "profileDisplayPictureRemoveError": "Klarte ikkje fjerna visningsbilete.", diff --git a/_locales/no/messages.json b/_locales/no/messages.json index 9b051e964..c9f4ab544 100644 --- a/_locales/no/messages.json +++ b/_locales/no/messages.json @@ -640,6 +640,7 @@ "pinUnpin": "Løsne", "pinUnpinConversation": "Løsne samtale", "preview": "Forhåndsvisning", + "pro": "Pro", "profile": "Profil", "profileDisplayPicture": "Display Picture", "profileDisplayPictureRemoveError": "Kunne ikke fjerne visningsbildet.", diff --git a/_locales/ny/messages.json b/_locales/ny/messages.json index fd3df7516..bcb06d069 100644 --- a/_locales/ny/messages.json +++ b/_locales/ny/messages.json @@ -638,6 +638,7 @@ "pinUnpin": "Chotsani", "pinUnpinConversation": "Chotsani Kukambirana", "preview": "Chithunzithunzi", + "pro": "Pro", "profile": "Mbiri", "profileDisplayPicture": "Chithunzi Chowonetsera", "profileDisplayPictureRemoveError": "Zalephera kuchotsa chithunzi chowonetsera.", diff --git a/_locales/pa/messages.json b/_locales/pa/messages.json index d302ace98..05dd9704b 100644 --- a/_locales/pa/messages.json +++ b/_locales/pa/messages.json @@ -638,6 +638,7 @@ "pinUnpin": "ਅਨਪਿਨ ਕਰੋ", "pinUnpinConversation": "ਗੱਲਬਾਤ ਅਨਪਿਨ ਕਰੋ", "preview": "ਪ੍ਰੀਵਿਊ", + "pro": "Pro", "profile": "ਪ੍ਰੋਫਾਈਲ", "profileDisplayPicture": "ਪ੍ਰਦਰਸ਼ਨ ਚਿੱਤਰ", "profileDisplayPictureRemoveError": "ਡਿਸਪਲੇ ਚਿੱਤਰ ਨੂੰ ਹਟਾਉਣ ਵਿੱਚ ਅਸਫਲ", diff --git a/_locales/pl/messages.json b/_locales/pl/messages.json index 50eef5e96..d2292fca9 100644 --- a/_locales/pl/messages.json +++ b/_locales/pl/messages.json @@ -757,6 +757,7 @@ "pinUnpin": "Odepnij", "pinUnpinConversation": "Odepnij konwersację", "preview": "Podgląd", + "pro": "Pro", "proActivated": "Aktywowano", "proAlreadyPurchased": "Masz już", "proAnimatedDisplayPicture": "Możesz przesyłać GIF-y i animowane obrazy WebP jako swoje zdjęcie profilowe!", diff --git a/_locales/ps/messages.json b/_locales/ps/messages.json index 741ac5d2f..c13850d40 100644 --- a/_locales/ps/messages.json +++ b/_locales/ps/messages.json @@ -638,6 +638,7 @@ "pinUnpin": "له اول نمبر لیست څخه انپین کړئ", "pinUnpinConversation": "خبرواترو څخه انپین وکړئ", "preview": "پیش منظر", + "pro": "Pro", "profile": "پروفایل", "profileDisplayPicture": "د نندارې انځور", "profileDisplayPictureRemoveError": "د نمایش انځور لرې کولو کې ناکام", diff --git a/_locales/pt-BR/messages.json b/_locales/pt-BR/messages.json index 72f72ef7a..2a7ada45e 100644 --- a/_locales/pt-BR/messages.json +++ b/_locales/pt-BR/messages.json @@ -650,6 +650,7 @@ "pinUnpin": "Desafixar", "pinUnpinConversation": "Desafixar Conversa", "preview": "Pré-visualizar", + "pro": "Pro", "profile": "Perfil", "profileDisplayPicture": "Imagem de Exibição", "profileDisplayPictureRemoveError": "Falha ao remover a imagem de exibição.", diff --git a/_locales/pt-PT/messages.json b/_locales/pt-PT/messages.json index 9e3dc9c37..e994cb917 100644 --- a/_locales/pt-PT/messages.json +++ b/_locales/pt-PT/messages.json @@ -757,6 +757,7 @@ "pinUnpin": "Desafixar", "pinUnpinConversation": "Desafixar Conversa", "preview": "Pré-visualizar", + "pro": "Pro", "proActivated": "Ativado", "proAlreadyPurchased": "Já tem", "proAnimatedDisplayPicture": "Agora pode enviar GIFs e imagens WebP animadas para a sua imagem de exibição!", diff --git a/_locales/ro/messages.json b/_locales/ro/messages.json index fcb41bd5b..2c628fc16 100644 --- a/_locales/ro/messages.json +++ b/_locales/ro/messages.json @@ -757,6 +757,7 @@ "pinUnpin": "Anulați fixarea", "pinUnpinConversation": "Anulați fixarea conversației", "preview": "Previzualizare", + "pro": "Pro", "proActivated": "Activat", "proAlreadyPurchased": "Deja ai", "proAnimatedDisplayPicture": "Mergi mai departe și încarcă GIF-uri și imagini WebP animate pentru imaginea ta de profil!", diff --git a/_locales/ru/messages.json b/_locales/ru/messages.json index 639f480f8..74da8a3f1 100644 --- a/_locales/ru/messages.json +++ b/_locales/ru/messages.json @@ -753,6 +753,7 @@ "pinUnpin": "Открепить", "pinUnpinConversation": "Открепить беседу", "preview": "Предварительный просмотр", + "pro": "Pro", "proActivated": "Активирован", "proAlreadyPurchased": "У вас уже есть", "proAnimatedDisplayPicture": "Вперёд! И загружай анимированные GIF и WebP для вашего изображения!", diff --git a/_locales/sh/messages.json b/_locales/sh/messages.json index 0f7b36404..605a69323 100644 --- a/_locales/sh/messages.json +++ b/_locales/sh/messages.json @@ -638,6 +638,7 @@ "pinUnpin": "Otpini", "pinUnpinConversation": "Otpini razgovor", "preview": "Pregled", + "pro": "Pro", "profile": "Profil", "profileDisplayPicture": "Prikaz slike", "profileDisplayPictureRemoveError": "Nije uspjelo uklanjanje prikazne slike.", diff --git a/_locales/si/messages.json b/_locales/si/messages.json index 7c6d38fea..e77b3e96a 100644 --- a/_locales/si/messages.json +++ b/_locales/si/messages.json @@ -638,6 +638,7 @@ "pinUnpin": "ගළවන්න", "pinUnpinConversation": "සංවාදය ඉවත් කරන්න", "preview": "පෙරදසුන", + "pro": "Pro", "profile": "පැතිකඩ", "profileDisplayPicture": "ප්‍රදර්ශන ඡායාරූපය", "profileDisplayPictureRemoveError": "පේෂණ ඡායාරූපය ඉවත් කිරීමට අසමත් විය.", diff --git a/_locales/sk/messages.json b/_locales/sk/messages.json index cf6571e7f..19a974d1c 100644 --- a/_locales/sk/messages.json +++ b/_locales/sk/messages.json @@ -639,6 +639,7 @@ "pinUnpin": "Zrušiť pripnutie", "pinUnpinConversation": "Odopnúť konverzáciu", "preview": "Náhľad", + "pro": "Pro", "profile": "Profil", "profileDisplayPicture": "Profilový obrázok", "profileDisplayPictureRemoveError": "Nepodarilo sa odstrániť profilový obrázok.", diff --git a/_locales/sl/messages.json b/_locales/sl/messages.json index 3a16011c5..1493cc29a 100644 --- a/_locales/sl/messages.json +++ b/_locales/sl/messages.json @@ -638,6 +638,7 @@ "pinUnpin": "Odpni", "pinUnpinConversation": "Odpni pogovor", "preview": "Predogled", + "pro": "Pro", "profile": "Profil", "profileDisplayPicture": "Prikazna slika", "profileDisplayPictureRemoveError": "Ni uspelo odstraniti prikazne slike.", diff --git a/_locales/sq/messages.json b/_locales/sq/messages.json index 676574c87..275d82250 100644 --- a/_locales/sq/messages.json +++ b/_locales/sq/messages.json @@ -638,6 +638,7 @@ "pinUnpin": "Çngulit", "pinUnpinConversation": "Çngulit Bisedën", "preview": "Paraparje", + "pro": "Pro", "profile": "Profil", "profileDisplayPicture": "Fotografi për ekran", "profileDisplayPictureRemoveError": "Dështoi heqja e figurës së paraqitjes.", diff --git a/_locales/sr-CS/messages.json b/_locales/sr-CS/messages.json index 6862c34dd..2fe6fe7f4 100644 --- a/_locales/sr-CS/messages.json +++ b/_locales/sr-CS/messages.json @@ -638,6 +638,7 @@ "pinUnpin": "Otkači", "pinUnpinConversation": "Otkači konverzaciju sa vrha", "preview": "Pregled", + "pro": "Pro", "profile": "Profil", "profileDisplayPicture": "Prikaz slike", "profileDisplayPictureRemoveError": "Neuspelo uklanjanje slike profila.", diff --git a/_locales/sr-SP/messages.json b/_locales/sr-SP/messages.json index 0b8944521..2091895a0 100644 --- a/_locales/sr-SP/messages.json +++ b/_locales/sr-SP/messages.json @@ -638,6 +638,7 @@ "pinUnpin": "Откачи", "pinUnpinConversation": "Откачи преписку", "preview": "Преглед", + "pro": "Pro", "profile": "Профил", "profileDisplayPicture": "Слика за приказ", "profileDisplayPictureRemoveError": "Неуспех у уклањању слике профила", diff --git a/_locales/sv/messages.json b/_locales/sv/messages.json index dbf17355a..2b805ea63 100644 --- a/_locales/sv/messages.json +++ b/_locales/sv/messages.json @@ -757,6 +757,7 @@ "pinUnpin": "Lossa", "pinUnpinConversation": "Lossa konversation", "preview": "Förhandsgranska", + "pro": "Pro", "proActivated": "Aktiverat", "proAlreadyPurchased": "Du har redan", "proAnimatedDisplayPicture": "Fortsätt och ladda upp GIF:ar och animerade WebP-bilder som visningsbild!", diff --git a/_locales/sw/messages.json b/_locales/sw/messages.json index 21c752e32..d74a53a96 100644 --- a/_locales/sw/messages.json +++ b/_locales/sw/messages.json @@ -639,6 +639,7 @@ "pinUnpin": "Ondoa", "pinUnpinConversation": "Ondoa Mazungumzo", "preview": "Hakiki", + "pro": "Pro", "profile": "Profaili", "profileDisplayPicture": "Picha ya Onyesho", "profileDisplayPictureRemoveError": "Imeshindikana kuondoa picha ya kuonyesha.", diff --git a/_locales/ta/messages.json b/_locales/ta/messages.json index e54417013..009f9846a 100644 --- a/_locales/ta/messages.json +++ b/_locales/ta/messages.json @@ -643,6 +643,7 @@ "pinUnpin": "பின்னூட்டம் நீக்கு", "pinUnpinConversation": "உரையாடலை நீக்கு", "preview": "முன் நோக்கு", + "pro": "Pro", "profile": "சுயவிவரம்", "profileDisplayPicture": "அடுத்தப்படியாக", "profileDisplayPictureRemoveError": "காட்சி படம் நீக்க முடியவில்லை.", diff --git a/_locales/te/messages.json b/_locales/te/messages.json index 459fbdde1..652cc1ddd 100644 --- a/_locales/te/messages.json +++ b/_locales/te/messages.json @@ -639,6 +639,7 @@ "pinUnpin": "అన్స్టిక్ చేయి", "pinUnpinConversation": "సంభాషణను అన్స్టిక్ చేయి", "preview": "ప్రివ్యూ", + "pro": "Pro", "profile": "ప్రొఫైల్", "profileDisplayPicture": "ప్రదర్శన చిత్రం", "profileDisplayPictureRemoveError": "ప్రదర్శన చిత్రాన్ని తొలగించడంలో విఫలమైంది.", diff --git a/_locales/th/messages.json b/_locales/th/messages.json index 6d2801f35..5bac5a5cb 100644 --- a/_locales/th/messages.json +++ b/_locales/th/messages.json @@ -639,6 +639,7 @@ "pinUnpin": "ยกเลิกปักหมุด.", "pinUnpinConversation": "ยกเลิกปักหมุดการสนทนา.", "preview": "พรีวิว", + "pro": "Pro", "profile": "โปรไฟล์", "profileDisplayPicture": "รูปภาพที่แสดง", "profileDisplayPictureRemoveError": "การลบรูปโปรไฟล์ล้มเหลว", diff --git a/_locales/tl/messages.json b/_locales/tl/messages.json index f67bf2921..2c316a4d5 100644 --- a/_locales/tl/messages.json +++ b/_locales/tl/messages.json @@ -639,6 +639,7 @@ "pinUnpin": "I-unpin", "pinUnpinConversation": "I-unpin ang Usapan", "preview": "I-preview", + "pro": "Pro", "profile": "Profile", "profileDisplayPicture": "Display Picture", "profileDisplayPictureRemoveError": "Nabigong alisin ang display picture.", diff --git a/_locales/tr/messages.json b/_locales/tr/messages.json index ab68e011a..618db270e 100644 --- a/_locales/tr/messages.json +++ b/_locales/tr/messages.json @@ -746,6 +746,7 @@ "pinUnpin": "Sabitlemeyi Kaldır", "pinUnpinConversation": "Sohbetin Sabitlemesini Kaldır", "preview": "Ön İzleme", + "pro": "Pro", "proActivated": "Etkinleştirildi", "proAlreadyPurchased": "Zaten sahipsiniz", "proAnimatedDisplayPicture": "Hadi, profil resminiz için GIF'ler ve animasyonlu WebP görselleri yükleyin!", diff --git a/_locales/uk/messages.json b/_locales/uk/messages.json index 27a195fa5..bf9f9d831 100644 --- a/_locales/uk/messages.json +++ b/_locales/uk/messages.json @@ -753,6 +753,7 @@ "pinUnpin": "Відкріпити", "pinUnpinConversation": "Відкріпити розмову", "preview": "Попередній перегляд", + "pro": "Pro", "proActivated": "активовано", "proAlreadyPurchased": "У вас вже є", "proAnimatedDisplayPicture": "Не зволікайте і завантажуйте GIF та анімовані WebP картинки для свого аватара!", diff --git a/_locales/ur/messages.json b/_locales/ur/messages.json index 28ef096bc..bc56c6797 100644 --- a/_locales/ur/messages.json +++ b/_locales/ur/messages.json @@ -644,6 +644,7 @@ "pinUnpin": "انپن کریں", "pinUnpinConversation": "مکالمہ کو انپن کریں", "preview": "پیش نظارہ", + "pro": "Pro", "profile": "پروفائل", "profileDisplayPicture": "ڈسپلے تصویر", "profileDisplayPictureRemoveError": "ڈسپلے تصویر ہٹانے میں ناکام", diff --git a/_locales/uz/messages.json b/_locales/uz/messages.json index be44fbdf7..00aca8904 100644 --- a/_locales/uz/messages.json +++ b/_locales/uz/messages.json @@ -639,6 +639,7 @@ "pinUnpin": "Mahkamlanmagan", "pinUnpinConversation": "Suhbatni mahkamlamaslik", "preview": "Belgilar", + "pro": "Pro", "profile": "Profil", "profileDisplayPicture": "Displey rasm", "profileDisplayPictureRemoveError": "Displey rasmini olib tashlashda muammo chiqdi.", diff --git a/_locales/vi/messages.json b/_locales/vi/messages.json index 670694361..6fdef6679 100644 --- a/_locales/vi/messages.json +++ b/_locales/vi/messages.json @@ -696,6 +696,7 @@ "pinUnpin": "Bỏ ghim", "pinUnpinConversation": "Bỏ ghim cuộc trò chuyện", "preview": "Xem trước", + "pro": "Pro", "profile": "Hồ sơ cá nhân", "profileDisplayPicture": "Display Picture", "profileDisplayPictureRemoveError": "Không thể xóa hình đại diện.", diff --git a/_locales/xh/messages.json b/_locales/xh/messages.json index a61fa06c0..c1ef4a7ce 100644 --- a/_locales/xh/messages.json +++ b/_locales/xh/messages.json @@ -639,6 +639,7 @@ "pinUnpin": "Susa Ukukhonkxa", "pinUnpinConversation": "Susa ukukhonkxa incoko", "preview": "Ukuqhaynqa", + "pro": "Pro", "profile": "Iprofayile", "profileDisplayPicture": "Umfanekiso Okhombisa Ubuso", "profileDisplayPictureRemoveError": "Koyekile ukususa umfanekiso wokubonisa.", diff --git a/_locales/zh-CN/messages.json b/_locales/zh-CN/messages.json index 7e8d45951..072ab2f7b 100644 --- a/_locales/zh-CN/messages.json +++ b/_locales/zh-CN/messages.json @@ -756,6 +756,7 @@ "pinUnpin": "取消置顶", "pinUnpinConversation": "取消置顶会话", "preview": "通知效果预览", + "pro": "Pro", "proActivated": "已激活", "proAlreadyPurchased": "您已拥有", "proAnimatedDisplayPicture": "快去为头像上传 GIF 或动画 WebP 图片吧!", diff --git a/_locales/zh-TW/messages.json b/_locales/zh-TW/messages.json index f0738ee9b..651341e45 100644 --- a/_locales/zh-TW/messages.json +++ b/_locales/zh-TW/messages.json @@ -757,6 +757,7 @@ "pinUnpin": "取消置頂", "pinUnpinConversation": "取消置頂", "preview": "預覽", + "pro": "Pro", "proActivated": "已啟用", "proAlreadyPurchased": "您已擁有", "proAnimatedDisplayPicture": "您可以為您的顯示圖片上傳 GIF 或動畫 WebP 圖片了!", From e1a2163dc850daee860c346f57203120b1893b9d Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Thu, 21 Aug 2025 11:00:28 +1000 Subject: [PATCH 14/18] feat: moved the password set/change/remove logic to userSettings --- ts/components/dialog/ModalContainer.tsx | 4 - .../dialog/SessionSetPasswordDialog.tsx | 398 ------------------ .../user-settings/UserSettingsDialog.tsx | 15 +- .../pages/BlockedContactsSettingsPage.tsx | 1 + .../pages/EditPasswordSettingsPage.tsx | 382 +++++++++++++++++ .../pages/PrivacySettingsPage.tsx | 43 +- .../pages/RecoveryPasswordSettingsPage.tsx | 2 +- .../user-settings/pages/userSettingsHooks.tsx | 49 ++- ts/components/settings/SessionSettings.tsx | 17 - ts/state/ducks/modalDialog.tsx | 18 +- ts/state/selectors/modal.ts | 2 - ts/types/ReduxTypes.d.ts | 2 +- 12 files changed, 463 insertions(+), 470 deletions(-) delete mode 100644 ts/components/dialog/SessionSetPasswordDialog.tsx create mode 100644 ts/components/dialog/user-settings/pages/EditPasswordSettingsPage.tsx diff --git a/ts/components/dialog/ModalContainer.tsx b/ts/components/dialog/ModalContainer.tsx index 8c4c5cc8f..aab1f0799 100644 --- a/ts/components/dialog/ModalContainer.tsx +++ b/ts/components/dialog/ModalContainer.tsx @@ -21,7 +21,6 @@ import { getReactListDialog, getRemoveModeratorsModal, getSessionNetworkModalState, - getSessionPasswordDialog, getUpdateGroupMembersModal, getUserProfileModal, getLocalizedPopupDialogState, @@ -40,7 +39,6 @@ import { OnionPathModal } from './OnionStatusPathDialog'; import { ReactClearAllModal } from './ReactClearAllModal'; import { ReactListModal } from './ReactListModal'; import { SessionNicknameDialog } from './SessionNicknameDialog'; -import { SessionSetPasswordDialog } from './SessionSetPasswordDialog'; import { UpdateGroupMembersDialog } from './UpdateGroupMembersDialog'; import { UpdateConversationDetailsDialog } from './UpdateConversationDetailsDialog'; import { UserProfileModal } from './UserProfileModal'; @@ -66,7 +64,6 @@ export const ModalContainer = () => { const userSettingsModalState = useSelector(getUserSettingsModal); const onionPathModalState = useSelector(getOnionPathDialog); const enterPasswordModalState = useSelector(getEnterPasswordModalState); - const sessionPasswordModalState = useSelector(getSessionPasswordDialog); const deleteAccountModalState = useSelector(getDeleteAccountModalState); const banOrUnbanUserModalState = useSelector(getBanOrUnbanUserModalState); const blockOrUnblockModalState = useSelector(getBlockOrUnblockUserModalState); @@ -90,7 +87,6 @@ export const ModalContainer = () => { {conversationSettingsModalState && ( )} - {sessionPasswordModalState && } {sessionNetworkModalState && } {onionPathModalState && } {reactListModalState && } diff --git a/ts/components/dialog/SessionSetPasswordDialog.tsx b/ts/components/dialog/SessionSetPasswordDialog.tsx deleted file mode 100644 index 78af07a7b..000000000 --- a/ts/components/dialog/SessionSetPasswordDialog.tsx +++ /dev/null @@ -1,398 +0,0 @@ -/* eslint-disable @typescript-eslint/no-misused-promises */ - -import autoBind from 'auto-bind'; -import { isEmpty } from 'lodash'; -import { Component } from 'react'; -import { ToastUtils } from '../../session/utils'; -import { sessionPassword } from '../../state/ducks/modalDialog'; -import type { PasswordAction } from '../../types/ReduxTypes'; -import { assertUnreachable } from '../../types/sqlSharedTypes'; -import { matchesHash, validatePassword } from '../../util/passwordUtils'; -import { getPasswordHash, Storage } from '../../util/storage'; -import { SessionButton, SessionButtonColor, SessionButtonType } from '../basic/SessionButton'; -import { tr, tStripped } from '../../localization/localeTools'; -import { - ModalBasicHeader, - ModalActionsContainer, - SessionWrapperModal, - WrapperModalWidth, -} from '../SessionWrapperModal'; -import { SimpleSessionInput } from '../inputs/SessionInput'; -import { ModalFlexContainer } from './shared/ModalFlexContainer'; -import { SpacerSM } from '../basic/Text'; - -interface Props { - passwordAction: PasswordAction; - onOk: () => void; -} - -interface State { - error: string | null; - currentPasswordEntered: string | null; - currentPasswordConfirmEntered: string | null; - currentPasswordRetypeEntered: string | null; -} - -export class SessionSetPasswordDialog extends Component { - constructor(props: Props) { - super(props); - - this.state = { - error: null, - currentPasswordEntered: null, - currentPasswordConfirmEntered: null, - currentPasswordRetypeEntered: null, - }; - - autoBind(this); - } - - public render() { - const { passwordAction } = this.props; - const { currentPasswordEntered } = this.state; - let placeholders: Array = []; - switch (passwordAction) { - case 'change': - placeholders = [tr('passwordEnterCurrent'), tr('passwordEnterNew'), tr('passwordConfirm')]; - break; - case 'remove': - placeholders = [tr('passwordRemove')]; - break; - case 'enter': - placeholders = [tr('passwordCreate')]; - break; - default: - placeholders = [tr('passwordCreate'), tr('passwordConfirm')]; - } - - const confirmButtonText = passwordAction === 'remove' ? tr('remove') : tr('save'); - - const titleString = () => { - switch (passwordAction) { - case 'change': - return tr('passwordChange'); - case 'remove': - return tr('passwordRemove'); - case 'enter': - return tr('passwordEnter'); - default: - return tr('passwordSet'); - } - }; - - const sharedInputProps = { - type: 'password', - padding: 'var(--margins-sm) var(--margins-md)', - errorDataTestId: 'error-message', - providedError: undefined, - textSize: 'md', - onEnterPressed: () => { - void this.setPassword(); - }, - } as const; - - return ( - } - onClose={this.closeDialog} - topAnchor="35vh" - $contentMinWidth={WrapperModalWidth.narrow} - $contentMaxWidth={WrapperModalWidth.narrow} - buttonChildren={ - - - {passwordAction !== 'enter' && ( - - )} - - } - > - - - {passwordAction !== 'enter' && passwordAction !== 'remove' && ( - - )} - {passwordAction === 'change' && ( - - )} - - - - ); - } - - public validatePasswordHash(password: string | null) { - // Check if the password matches the hash we have stored - const hash = getPasswordHash(); - if (hash && !matchesHash(password, hash)) { - return false; - } - - return true; - } - - private showError() { - if (this.state.error) { - ToastUtils.pushToastError('enterPasswordErrorToast', this.state.error); - } - } - - /** - * Returns false and set the state error field in the input is not a valid password - * or returns true - */ - private validatePassword(enteredPassword: string) { - if (isEmpty(enteredPassword)) { - // Note, we don't want to display an error when the password is empty, but just drop the action - window.log.info('validatePassword needs a password to be given'); - return false; - } - // if user did not fill the first password field, we can't do anything - const errorFirstInput = validatePassword(enteredPassword); - if (errorFirstInput !== null) { - this.setState( - { - error: errorFirstInput, - }, - () => this.showError() - ); - return false; - } - return true; - } - - private async handleActionSet(enteredPassword: string, enteredPasswordConfirm: string) { - // be sure both password are valid - if (!this.validatePassword(enteredPassword)) { - return; - } - // no need to validate second password. we just need to check that enteredPassword is valid, and that both password matches - - if (enteredPassword !== enteredPasswordConfirm) { - this.setState({ - error: tr('passwordErrorMatch'), - }); - this.showError(); - return; - } - try { - const updatedHash = await window.setPassword(enteredPassword, null); - if (!updatedHash) { - throw new Error('window.setPassword expected updatedHash to be set for actionSet'); - } - await Storage.put('passHash', updatedHash); - - ToastUtils.pushToastSuccess( - 'setPasswordSuccessToast', - tStripped('passwordSetDescriptionToast') - ); - - this.props.onOk(); - this.closeDialog(); - } catch (err) { - window.log.error(err); - this.setState({ - error: tr('passwordFailed'), - }); - this.showError(); - } - } - - private async handleActionChange( - oldPassword: string, - newPassword: string, - newConfirmedPassword: string - ) { - // We don't validate oldPassword on change: this is validate on the validatePasswordHash below - // we only validate the newPassword here - if (!this.validatePassword(newPassword)) { - return; - } - - // Check the retyped password matches the new password - if (newPassword !== newConfirmedPassword) { - this.setState({ - error: tr('passwordErrorMatch'), - }); - this.showError(); - return; - } - - const isValidWithStoredInDB = this.validatePasswordHash(oldPassword); - if (!isValidWithStoredInDB) { - this.setState({ - error: tr('passwordCurrentIncorrect'), - }); - this.showError(); - return; - } - - try { - const updatedHash = await window.setPassword(newPassword, oldPassword); - if (!updatedHash) { - throw new Error('window.setPassword expected updatedHash to be set for actionChange'); - } - await Storage.put('passHash', updatedHash); - - ToastUtils.pushToastSuccess( - 'setPasswordSuccessToast', - tStripped('passwordChangedDescriptionToast') - ); - - this.props.onOk(); - this.closeDialog(); - } catch (err) { - window.log.error(err); - this.setState({ - error: tr('changePasswordFail'), - }); - this.showError(); - } - } - - private async handleActionRemove(oldPassword: string) { - if (isEmpty(oldPassword)) { - // Note, we want to drop "Enter" when no passwords are entered. - window.log.info('handleActionRemove: no password given. dropping'); - return; - } - // We don't validate oldPassword on change: this is validate on the validatePasswordHash below - const isValidWithStoredInDB = this.validatePasswordHash(oldPassword); - if (!isValidWithStoredInDB) { - this.setState({ - error: tr('passwordIncorrect'), - }); - this.showError(); - return; - } - - try { - const updatedHash = await window.setPassword(null, oldPassword); - if (updatedHash) { - throw new Error('window.setPassword expected updatedHash to be unset for actionRemove'); - } - await Storage.remove('passHash'); - - ToastUtils.pushToastWarning( - 'setPasswordSuccessToast', - tStripped('passwordRemovedDescriptionToast') - ); - - this.props.onOk(); - this.closeDialog(); - } catch (err) { - window.log.error(err); - this.setState({ - error: tr('removePasswordFail'), - }); - this.showError(); - } - } - - private async handleActionEnter(enteredPassword: string) { - // be sure the password is valid - if (!this.validatePassword(enteredPassword)) { - return; - } - - const isValidWithStoredInDB = this.validatePasswordHash(enteredPassword); - if (!isValidWithStoredInDB) { - this.setState({ - error: tr('passwordIncorrect'), - }); - this.showError(); - return; - } - - this.props.onOk(); - this.closeDialog(); - } - - private async setPassword() { - const { passwordAction } = this.props; - const { currentPasswordEntered, currentPasswordConfirmEntered, currentPasswordRetypeEntered } = - this.state; - - // Note: don't trim anything. If the user entered a space as a first/last - // char and saved it as is in his password manager, so be it. - const firstPasswordEntered = currentPasswordEntered || ''; - const secondPasswordEntered = currentPasswordConfirmEntered || ''; - const thirdPasswordEntered = currentPasswordRetypeEntered || ''; - - switch (passwordAction) { - case 'set': { - await this.handleActionSet(firstPasswordEntered, secondPasswordEntered); - return; - } - case 'change': { - await this.handleActionChange( - firstPasswordEntered, - secondPasswordEntered, - thirdPasswordEntered - ); - return; - } - case 'remove': { - await this.handleActionRemove(firstPasswordEntered); - return; - } - case 'enter': { - await this.handleActionEnter(firstPasswordEntered); - return; - } - default: - assertUnreachable(passwordAction, 'passwordAction'); - } - } - - private closeDialog() { - window.inboxStore?.dispatch(sessionPassword(null)); - } - - private onPasswordInput(value: string) { - const currentPasswordEntered = value; - this.setState({ currentPasswordEntered }); - } - - private onPasswordConfirmInput(value: string) { - const currentPasswordConfirmEntered = value; - this.setState({ currentPasswordConfirmEntered }); - } - - private onPasswordRetypeInput(value: string) { - const currentPasswordRetypeEntered = value; - this.setState({ currentPasswordRetypeEntered }); - } -} diff --git a/ts/components/dialog/user-settings/UserSettingsDialog.tsx b/ts/components/dialog/user-settings/UserSettingsDialog.tsx index 84a8582d4..3aa320d87 100644 --- a/ts/components/dialog/user-settings/UserSettingsDialog.tsx +++ b/ts/components/dialog/user-settings/UserSettingsDialog.tsx @@ -4,6 +4,7 @@ import { AppearanceSettingsPage } from './pages/AppearanceSettingsPage'; import { BlockedContactsSettingsPage } from './pages/BlockedContactsSettingsPage'; import { ConversationSettingsPage } from './pages/ConversationSettingsPage'; import { DefaultSettingPage } from './pages/DefaultSettingsPage'; +import { EditPasswordSettingsPage } from './pages/EditPasswordSettingsPage'; import { HelpSettingsPage } from './pages/HelpSettingsPage'; import { NotificationsSettingsPage } from './pages/NotificationsSettingsPage'; import { PreferencesSettingsPage } from './pages/PreferencesSettingsPage'; @@ -15,7 +16,9 @@ export const UserSettingsDialog = (modalState: UserSettingsModalState) => { return null; } - switch (modalState.userSettingsPage) { + const { userSettingsPage } = modalState; + + switch (userSettingsPage) { case 'default': return ; case 'privacy': @@ -34,13 +37,15 @@ export const UserSettingsDialog = (modalState: UserSettingsModalState) => { return ; case 'recovery-password': return ; + case 'password': + return ; case 'message-requests': // the `message-request` is not a page of the user settings page, but a page in the left pane header currently. return null; + case 'clear-data': + // the `clear-data` is not a page of the user settings page, but a separate dialog. + return null; default: - return assertUnreachable( - modalState.userSettingsPage, - `Unknown user settings page: ${modalState.userSettingsPage}` - ); + return assertUnreachable(userSettingsPage, `Unknown user settings page: ${userSettingsPage}`); } }; diff --git a/ts/components/dialog/user-settings/pages/BlockedContactsSettingsPage.tsx b/ts/components/dialog/user-settings/pages/BlockedContactsSettingsPage.tsx index 984d0af07..88e18e052 100644 --- a/ts/components/dialog/user-settings/pages/BlockedContactsSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/BlockedContactsSettingsPage.tsx @@ -31,6 +31,7 @@ const StyledNoBlockedContactsContainer = styled.div` // not pretty, but the only other way I found is to change the style of PanelButtonContainer itself, which I'd like to avoid height: var(--panel-button-container-min-height); align-content: center; + align-self: center; `; const NoBlockedContacts = () => { diff --git a/ts/components/dialog/user-settings/pages/EditPasswordSettingsPage.tsx b/ts/components/dialog/user-settings/pages/EditPasswordSettingsPage.tsx new file mode 100644 index 000000000..69a2a21bb --- /dev/null +++ b/ts/components/dialog/user-settings/pages/EditPasswordSettingsPage.tsx @@ -0,0 +1,382 @@ +import { useState } from 'react'; +import { isEmpty } from 'lodash'; + +import { + PanelButtonGroup, + PanelButtonTextWithSubText, + PanelLabelWithDescription, +} from '../../../buttons/panel/PanelButton'; +import { + ModalActionsContainer, + ModalBasicHeader, + SessionWrapperModal, + WrapperModalWidth, +} from '../../../SessionWrapperModal'; +import { ModalBackButton } from '../../shared/ModalBackButton'; +import { + useUserSettingsBackAction, + useUserSettingsCloseAction, + useUserSettingsTitle, +} from './userSettingsHooks'; + +import { Flex } from '../../../basic/Flex'; +import type { PasswordAction } from '../../../../types/ReduxTypes'; +import { SimpleSessionInput } from '../../../inputs/SessionInput'; +import { tr, tStripped, type WithTrArgs } from '../../../../localization/localeTools'; +import { SessionButton, SessionButtonColor, SessionButtonType } from '../../../basic/SessionButton'; +import { LucideIcon } from '../../../icon/LucideIcon'; +import { LUCIDE_ICONS_UNICODE } from '../../../icon/lucide'; +import { Localizer } from '../../../basic/Localizer'; +import { useTheme } from '../../../../state/theme/selectors/theme'; +import { ToastUtils } from '../../../../session/utils'; +import { assertUnreachable } from '../../../../types/sqlSharedTypes'; +import { getPasswordHash, Storage } from '../../../../util/storage'; +import { matchesHash, validatePassword } from '../../../../util/passwordUtils'; + +function StrengthCriteria(opts: { isMet: boolean } & WithTrArgs) { + const theme = useTheme(); + const criteriaMetColor = theme.includes('classic') ? 'var(--green-color)' : 'var(--blue-color)'; + return ( + + + + + ); +} + +function showError(error: string | null) { + if (!error) { + return; + } + ToastUtils.pushToastError('enterPasswordErrorToast', error); +} + +function validatePasswordHash(password: string | null) { + // Check if the password matches the hash we have stored + const hash = getPasswordHash(); + if (hash && !matchesHash(password, hash)) { + return false; + } + + return true; +} +/** + * Returns false and set the state error field in the input is not a valid password + * or returns true + */ +function validatePasswordLocal(enteredPassword: string) { + if (isEmpty(enteredPassword)) { + // Note: we don't want to display an error when the password is empty, but just drop the action + window.log.info('validatePassword needs a password to be given'); + return false; + } + // if user did not fill the first password field, we can't do anything + const errorFirstInput = validatePassword(enteredPassword); + if (errorFirstInput !== null) { + showError(errorFirstInput); + return false; + } + return true; +} + +async function handleActionSet( + enteredPassword: string, + enteredPasswordConfirm: string, + onDone?: () => void +) { + // be sure both password are valid + if (!validatePasswordLocal(enteredPassword)) { + return; + } + // no need to validate second password. we just need to check that enteredPassword is valid, and that both password matches + + if (enteredPassword !== enteredPasswordConfirm) { + showError(tr('passwordErrorMatch')); + return; + } + try { + const updatedHash = await window.setPassword(enteredPassword, null); + if (!updatedHash) { + throw new Error('window.setPassword expected updatedHash to be set for actionSet'); + } + await Storage.put('passHash', updatedHash); + + ToastUtils.pushToastSuccess( + 'setPasswordSuccessToast', + tStripped('passwordSetDescriptionToast') + ); + + onDone?.(); + } catch (err) { + window.log.error(err); + + showError(tr('passwordFailed')); + } +} + +async function handleActionChange( + oldPassword: string, + newPassword: string, + newConfirmedPassword: string, + onDone?: () => void +) { + // We don't validate oldPassword on change: this is validate on the validatePasswordHash below + // we only validate the newPassword here + if (!validatePasswordLocal(newPassword)) { + return; + } + + // Check the retyped password matches the new password + if (newPassword !== newConfirmedPassword) { + showError(tr('passwordErrorMatch')); + return; + } + + const isValidWithStoredInDB = validatePasswordHash(oldPassword); + if (!isValidWithStoredInDB) { + showError(tr('passwordCurrentIncorrect')); + return; + } + + try { + const updatedHash = await window.setPassword(newPassword, oldPassword); + if (!updatedHash) { + throw new Error('window.setPassword expected updatedHash to be set for actionChange'); + } + await Storage.put('passHash', updatedHash); + + ToastUtils.pushToastSuccess( + 'setPasswordSuccessToast', + tStripped('passwordChangedDescriptionToast') + ); + + onDone?.(); + } catch (err) { + window.log.error(err); + + showError(tr('changePasswordFail')); + } +} + +async function handleActionRemove(oldPassword: string, onDone?: () => void) { + if (isEmpty(oldPassword)) { + // Note, we want to drop "Enter" when no passwords are entered. + window.log.info('handleActionRemove: no password given. dropping'); + return; + } + // We don't validate oldPassword on change: this is validate on the validatePasswordHash below + const isValidWithStoredInDB = validatePasswordHash(oldPassword); + if (!isValidWithStoredInDB) { + showError(tr('passwordIncorrect')); + return; + } + + try { + const updatedHash = await window.setPassword(null, oldPassword); + if (updatedHash) { + throw new Error('window.setPassword expected updatedHash to be unset for actionRemove'); + } + await Storage.remove('passHash'); + + ToastUtils.pushToastWarning( + 'setPasswordSuccessToast', + tStripped('passwordRemovedDescriptionToast') + ); + + onDone?.(); + } catch (err) { + window.log.error(err); + + showError(tr('removePasswordFail')); + } +} + +export function EditPasswordSettingsPage(modalState: { + userSettingsPage: 'password'; + passwordAction: PasswordAction; +}) { + const backAction = useUserSettingsBackAction(modalState); + const closeAction = useUserSettingsCloseAction(modalState); + const title = useUserSettingsTitle(modalState); + + const isSet = modalState.passwordAction === 'set'; + const isChange = modalState.passwordAction === 'change'; + const isRemove = modalState.passwordAction === 'remove'; + + const [firstPassword, setFirstPassword] = useState(''); + const [secondPassword, setSecondPassword] = useState(''); + const [thirdPassword, setThirdPassword] = useState(''); + + const hasLengthStrength = firstPassword.length > 12; + const hasNumber = !!firstPassword.match(/[0-9]/); + const hasUppercase = !!firstPassword.match(/[A-Z]/); + const hasLowercase = !!firstPassword.match(/[a-z]/); + const hasLetter = hasUppercase || hasLowercase; + + const sharedInputProps = { + type: 'password', + padding: 'var(--margins-sm) var(--margins-md)', + errorDataTestId: 'error-message', + providedError: undefined, + textSize: 'md', + onEnterPressed: doChange, + } as const; + + async function doChange() { + switch (modalState.passwordAction) { + case 'set': + await handleActionSet(firstPassword, secondPassword, backAction ?? undefined); + break; + case 'change': + await handleActionChange( + firstPassword, + secondPassword, + thirdPassword, + backAction ?? undefined + ); + break; + case 'remove': + await handleActionRemove(firstPassword, backAction ?? undefined); + break; + default: + assertUnreachable(modalState.passwordAction, 'passwordAction'); + } + } + + return ( + : undefined} + /> + } + onClose={closeAction || undefined} + shouldOverflow={true} + allowOutsideClick={false} + $contentMinWidth={WrapperModalWidth.normal} + buttonChildren={ + + + + } + > + + + + + + + {!isRemove && ( + + )} + {isChange && ( + + )} + + + + {!isRemove && ( + <> + + + + + + + + + + + + + )} + + ); +} diff --git a/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx b/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx index 7baa08c66..59dd409d8 100644 --- a/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/PrivacySettingsPage.tsx @@ -1,9 +1,10 @@ -import { useState } from 'react'; -import useMount from 'react-use/lib/useMount'; import useUpdate from 'react-use/lib/useUpdate'; +import { useDispatch } from 'react-redux'; + import { tr } from '../../../../localization/localeTools'; import { updateConfirmModal, + userSettingsModal, type UserSettingsModalState, } from '../../../../state/ducks/modalDialog'; import { @@ -33,12 +34,9 @@ import { SettingsKey } from '../../../../data/settings-key'; import { SessionUtilUserProfile } from '../../../../session/utils/libsession/libsession_utils_user_profile'; import { getPasswordHash, Storage } from '../../../../util/storage'; import { SpacerXS } from '../../../basic/Text'; -import { displayPasswordModal } from '../../../settings/SessionSettings'; import { SettingsToggleBasic } from '../components/SettingsToggleBasic'; import { SettingsPanelButtonInlineBasic } from '../components/SettingsPanelButtonInlineBasic'; -type WithPasswordUpdatedCb = { onPasswordUpdated: (action: string) => void }; - const toggleCallMediaPermissions = async (triggerUIUpdate: () => void) => { const currentValue = window.getCallMediaPermissions(); const onClose = () => window.inboxStore?.dispatch(updateConfirmModal(null)); @@ -110,14 +108,17 @@ function StaticTypingBubble({ width }: { width: string }) { ); } -function HasPasswordSubSection(props: WithPasswordUpdatedCb) { +function HasPasswordSubSection() { + const dispatch = useDispatch(); return ( displayPasswordModal('change', props.onPasswordUpdated)} + onClick={async () => { + dispatch(userSettingsModal({ userSettingsPage: 'password', passwordAction: 'change' })); + }} buttonColor={SessionButtonColor.Primary} buttonText={tr('change')} /> @@ -126,7 +127,7 @@ function HasPasswordSubSection(props: WithPasswordUpdatedCb) { text={{ token: 'passwordRemove' }} subText={{ token: 'passwordRemoveShortDescription' }} onClick={async () => { - displayPasswordModal('remove', props.onPasswordUpdated); + dispatch(userSettingsModal({ userSettingsPage: 'password', passwordAction: 'remove' })); }} buttonColor={SessionButtonColor.Danger} buttonText={tr('remove')} @@ -134,7 +135,9 @@ function HasPasswordSubSection(props: WithPasswordUpdatedCb) { ); } -function NoPasswordSubSection(props: WithPasswordUpdatedCb) { +function NoPasswordSubSection() { + const dispatch = useDispatch(); + return ( { - displayPasswordModal('set', props.onPasswordUpdated); + dispatch(userSettingsModal({ userSettingsPage: 'password', passwordAction: 'set' })); }} buttonColor={SessionButtonColor.Primary} buttonText={tr('set')} @@ -152,24 +155,10 @@ function NoPasswordSubSection(props: WithPasswordUpdatedCb) { } function PasswordSubSection() { - const [hasPassword, setHasPassword] = useState(true); - useMount(() => { - const hash = getPasswordHash(); - setHasPassword(!!hash); - }); - - function onPasswordUpdated(action: string) { - if (action === 'set' || action === 'change') { - setHasPassword(true); - } else if (action === 'remove') { - setHasPassword(false); - } - } - - if (hasPassword) { - return ; + if (getPasswordHash()) { + return ; } - return ; + return ; } export function PrivacySettingsPage(modalState: UserSettingsModalState) { diff --git a/ts/components/dialog/user-settings/pages/RecoveryPasswordSettingsPage.tsx b/ts/components/dialog/user-settings/pages/RecoveryPasswordSettingsPage.tsx index 07521e78d..519ecc54b 100644 --- a/ts/components/dialog/user-settings/pages/RecoveryPasswordSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/RecoveryPasswordSettingsPage.tsx @@ -80,7 +80,7 @@ export function RecoveryPasswordSettingsPage(modalState: UserSettingsModalState) const { hasPassword, passwordValid } = usePasswordModal({ onClose: () => { - dispatch(userSettingsModal({ userSettingsPage: 'privacy' })); + dispatch(userSettingsModal({ userSettingsPage: 'default' })); }, }); diff --git a/ts/components/dialog/user-settings/pages/userSettingsHooks.tsx b/ts/components/dialog/user-settings/pages/userSettingsHooks.tsx index b75e96af0..778292d36 100644 --- a/ts/components/dialog/user-settings/pages/userSettingsHooks.tsx +++ b/ts/components/dialog/user-settings/pages/userSettingsHooks.tsx @@ -3,6 +3,7 @@ import { tr } from '../../../../localization/localeTools'; import { userSettingsModal, type UserSettingsModalState, + type UserSettingsPage, } from '../../../../state/ducks/modalDialog'; import { assertUnreachable } from '../../../../types/sqlSharedTypes'; @@ -10,7 +11,8 @@ export function useUserSettingsTitle(page: UserSettingsModalState | undefined) { if (!page) { return tr('sessionSettings'); } - switch (page.userSettingsPage) { + const { userSettingsPage } = page; + switch (userSettingsPage) { case 'appearance': return tr('sessionAppearance'); case 'notifications': @@ -31,11 +33,17 @@ export function useUserSettingsTitle(page: UserSettingsModalState | undefined) { return tr('sessionHelp'); case 'preferences': return tr('preferences'); + case 'password': + return page.passwordAction === 'remove' + ? tr('passwordRemove') + : page.passwordAction === 'change' + ? tr('passwordChange') + : tr('passwordSet'); case 'default': case undefined: return tr('sessionSettings'); default: - assertUnreachable(page.userSettingsPage, "useTitleFromPage doesn't support this page"); + assertUnreachable(userSettingsPage, "useTitleFromPage doesn't support this page"); throw new Error('useTitleFromPage does not support this page'); } } @@ -46,7 +54,9 @@ export function useUserSettingsCloseAction(props: UserSettingsModalState) { return null; } - switch (props.userSettingsPage) { + const { userSettingsPage } = props; + + switch (userSettingsPage) { case 'default': case 'notifications': case 'appearance': @@ -58,10 +68,11 @@ export function useUserSettingsCloseAction(props: UserSettingsModalState) { case 'clear-data': case 'preferences': case 'blocked-contacts': + case 'password': return () => dispatch(userSettingsModal(null)); default: - assertUnreachable(props.userSettingsPage, 'useCloseActionFromPage: invalid userSettingsPage'); + assertUnreachable(userSettingsPage, 'useCloseActionFromPage: invalid userSettingsPage'); throw new Error('useCloseActionFromPage: invalid userSettingsPage'); } } @@ -73,10 +84,38 @@ export function useUserSettingsBackAction(modalState: UserSettingsModalState) { return undefined; } + let settingsPageToDisplayOnBack: UserSettingsPage = 'default'; + const { userSettingsPage } = modalState; + + switch (userSettingsPage) { + case 'blocked-contacts': + settingsPageToDisplayOnBack = 'conversations'; + break; + case 'password': + settingsPageToDisplayOnBack = 'privacy'; + break; + case 'message-requests': + // message requests is not a page of the user settings page, but a page in the left pane header currently. + break; + case 'recovery-password': + case 'appearance': + case 'clear-data': + case 'conversations': + case 'help': + case 'notifications': + case 'privacy': + case 'preferences': + settingsPageToDisplayOnBack = 'default'; + break; + default: + assertUnreachable(userSettingsPage, 'useBackActionFromPage: invalid userSettingsPage'); + throw new Error('useBackActionFromPage: invalid userSettingsPage'); + } + return () => { dispatch( userSettingsModal({ - userSettingsPage: 'default', + userSettingsPage: settingsPageToDisplayOnBack, }) ); }; diff --git a/ts/components/settings/SessionSettings.tsx b/ts/components/settings/SessionSettings.tsx index 514dd30a6..b235eafaf 100644 --- a/ts/components/settings/SessionSettings.tsx +++ b/ts/components/settings/SessionSettings.tsx @@ -1,20 +1,3 @@ -import { sessionPassword } from '../../state/ducks/modalDialog'; -import type { PasswordAction } from '../../types/ReduxTypes'; - -export function displayPasswordModal( - passwordAction: PasswordAction, - onPasswordUpdated: (action: string) => void -) { - window.inboxStore?.dispatch( - sessionPassword({ - passwordAction, - onOk: () => { - onPasswordUpdated(passwordAction); - }, - }) - ); -} - export function getMediaPermissionsSettings() { return window.getSettingValue('media-permissions'); } diff --git a/ts/state/ducks/modalDialog.tsx b/ts/state/ducks/modalDialog.tsx index 24f97734b..2ce5c8461 100644 --- a/ts/state/ducks/modalDialog.tsx +++ b/ts/state/ducks/modalDialog.tsx @@ -23,9 +23,15 @@ export type UserSettingsPage = | 'help' | 'blocked-contacts' | 'clear-data' + | 'password' | 'preferences'; -export type WithUserSettingsPage = { userSettingsPage: UserSettingsPage }; +export type WithUserSettingsPage = + | { userSettingsPage: Exclude } + | { + userSettingsPage: 'password'; + passwordAction: PasswordAction; + }; export type ConfirmModalState = SessionConfirmDialogProps | null; @@ -52,8 +58,6 @@ export type LocalizedPopupDialogState = { } | null; export type SessionProInfoState = { variant: SessionProInfoVariant } | null; -export type SessionPasswordModalState = { passwordAction: PasswordAction; onOk: () => void } | null; - export type UserProfileModalState = { /** this can be blinded or not */ conversationId: string; @@ -106,7 +110,6 @@ export type ModalState = { userSettingsModal: UserSettingsModalState; onionPathModal: OnionPathModalState; enterPasswordModal: EnterPasswordModalState; - sessionPasswordModal: SessionPasswordModalState; deleteAccountModal: DeleteAccountModalState; reactListModalState: ReactModalsState; reactClearAllModalState: ReactModalsState; @@ -132,10 +135,9 @@ export const initialModalState: ModalState = { groupMembersModal: null, userProfileModal: null, nickNameModal: null, - userSettingsModal: null, + userSettingsModal: { userSettingsPage: 'privacy' }, onionPathModal: null, enterPasswordModal: null, - sessionPasswordModal: null, deleteAccountModal: null, reactListModalState: null, reactClearAllModalState: null, @@ -196,9 +198,6 @@ const ModalSlice = createSlice({ updateEnterPasswordModal(state, action: PayloadAction) { return { ...state, enterPasswordModal: action.payload }; }, - sessionPassword(state, action: PayloadAction) { - return { ...state, sessionPasswordModal: action.payload }; - }, updateDeleteAccountModal(state, action: PayloadAction) { return { ...state, deleteAccountModal: action.payload }; }, @@ -265,7 +264,6 @@ export const { userSettingsModal, onionPathModal, updateEnterPasswordModal, - sessionPassword, updateDeleteAccountModal, updateBanOrUnbanUserModal, updateBlockOrUnblockModal, diff --git a/ts/state/selectors/modal.ts b/ts/state/selectors/modal.ts index b0d786c90..fce9e0557 100644 --- a/ts/state/selectors/modal.ts +++ b/ts/state/selectors/modal.ts @@ -48,8 +48,6 @@ export const getOnionPathDialog = (state: StateType) => getModal(state).onionPat export const getEnterPasswordModalState = (state: StateType) => getModal(state).enterPasswordModal; -export const getSessionPasswordDialog = (state: StateType) => getModal(state).sessionPasswordModal; - export const getDeleteAccountModalState = (state: StateType) => getModal(state).deleteAccountModal; export const getReactListDialog = (state: StateType) => getModal(state).reactListModalState; diff --git a/ts/types/ReduxTypes.d.ts b/ts/types/ReduxTypes.d.ts index 6cfa64271..3824cac06 100644 --- a/ts/types/ReduxTypes.d.ts +++ b/ts/types/ReduxTypes.d.ts @@ -5,7 +5,7 @@ * e.g. import type { YourTypeHere } from 'path/to/ReduxTypes'; */ -export type PasswordAction = 'set' | 'change' | 'remove' | 'enter'; +export type PasswordAction = 'set' | 'change' | 'remove'; export type EditProfilePictureModalProps = { conversationId: string; From b3cc3704e2b7b1df54773483832aa5f50d3039c1 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Thu, 21 Aug 2025 12:06:03 +1000 Subject: [PATCH 15/18] feat: show profile pic upload failed for user avatar change --- ts/components/SessionInboxView.tsx | 1 + .../dialog/EditProfilePictureModal.tsx | 22 +++++++++++++++++-- .../UpdateConversationDetailsDialog.tsx | 18 +++++++++++++++ .../pages/DefaultSettingsPage.tsx | 2 -- ts/session/profile_manager/ProfileManager.ts | 2 +- ts/state/ducks/user.ts | 13 +++++++---- ts/state/selectors/user.ts | 4 ++++ 7 files changed, 53 insertions(+), 9 deletions(-) diff --git a/ts/components/SessionInboxView.tsx b/ts/components/SessionInboxView.tsx index 9bce39cae..3449b6c16 100644 --- a/ts/components/SessionInboxView.tsx +++ b/ts/components/SessionInboxView.tsx @@ -78,6 +78,7 @@ async function createSessionInboxStore() { ourDisplayNameInProfile: UserUtils.getOurProfile()?.displayName || '', ourNumber: UserUtils.getOurPubKeyStrFromCache(), uploadingNewAvatarCurrentUser: false, + uploadingNewAvatarCurrentUserFailed: false, }, section: initialSectionState, defaultRooms: initialDefaultRoomState, diff --git a/ts/components/dialog/EditProfilePictureModal.tsx b/ts/components/dialog/EditProfilePictureModal.tsx index a4874a3ad..827f41539 100644 --- a/ts/components/dialog/EditProfilePictureModal.tsx +++ b/ts/components/dialog/EditProfilePictureModal.tsx @@ -22,7 +22,7 @@ import { groupInfoActions } from '../../state/ducks/metaGroups'; import { useGroupAvatarChangeFromUIPending } from '../../state/selectors/groups'; import { userActions } from '../../state/ducks/user'; import { ReduxSogsRoomInfos } from '../../state/ducks/sogsRoomInfo'; -import { useOurAvatarIsUploading } from '../../state/selectors/user'; +import { useOurAvatarIsUploading, useOurAvatarUploadFailed } from '../../state/selectors/user'; import { useAvatarOfRoomIsUploading } from '../../state/selectors/sogsRoomInfo'; import { ModalActionsContainer, @@ -41,6 +41,9 @@ import { useProBadgeOnClickCb } from '../menuAndSettingsHooks/useProBadgeOnClick import { useUserHasPro } from '../../hooks/useHasPro'; import { Localizer } from '../basic/Localizer'; import { UploadFirstImageButton } from '../buttons/avatar/UploadFirstImageButton'; +import { Flex } from '../basic/Flex'; +import { LucideIcon } from '../icon/LucideIcon'; +import { LUCIDE_ICONS_UNICODE } from '../icon/lucide'; const StyledAvatarContainer = styled.div` cursor: pointer; @@ -142,6 +145,7 @@ export const EditProfilePictureModal = ({ conversationId }: EditProfilePictureMo const groupAvatarChangePending = useGroupAvatarChangeFromUIPending(); const ourAvatarIsUploading = useOurAvatarIsUploading(); + const ourAvatarUploadFailed = useOurAvatarUploadFailed(); const sogsAvatarIsUploading = useAvatarOfRoomIsUploading(conversationId); const [newAvatarObjectUrl, setNewAvatarObjectUrl] = useState(avatarPath); @@ -312,7 +316,21 @@ export const EditProfilePictureModal = ({ conversationId }: EditProfilePictureMo )} - {} + {ourAvatarUploadFailed && isMe ? ( + + + + + ) : null} {loading ? ( <> diff --git a/ts/components/dialog/UpdateConversationDetailsDialog.tsx b/ts/components/dialog/UpdateConversationDetailsDialog.tsx index a098c2c25..7dbe27278 100644 --- a/ts/components/dialog/UpdateConversationDetailsDialog.tsx +++ b/ts/components/dialog/UpdateConversationDetailsDialog.tsx @@ -3,6 +3,7 @@ import { useState } from 'react'; import { useDispatch } from 'react-redux'; import useKey from 'react-use/lib/useKey'; import useMount from 'react-use/lib/useMount'; +import { isEmpty } from 'lodash'; import { useAvatarPath, @@ -42,6 +43,8 @@ import { import { ReduxSogsRoomInfos } from '../../state/ducks/sogsRoomInfo'; import type { WithConvoId } from '../../session/types/with'; import { UploadFirstImageButton } from '../buttons/avatar/UploadFirstImageButton'; +import { sanitizeDisplayNameOrToast } from '../registration/utils'; +import { ProfileManager } from '../../session/profile_manager/ProfileManager'; function useNameErrorString({ isMe, @@ -164,6 +167,21 @@ export function UpdateConversationDetailsDialog(props: WithConvoId) { } if (trimmedGroupName !== nameOnOpen || trimmedGroupDescription !== descriptionOnOpen) { + if (isMe) { + const sanitizedName = sanitizeDisplayNameOrToast(trimmedGroupName); + + // this should never happen, but just in case + if (isEmpty(sanitizedName)) { + return; + } + + // this truncates if the display name is too long + // Note: this not doing any network calls. No need for a loader in this case + void ProfileManager.updateOurProfileDisplayName(sanitizedName); + closeDialog(); + + return; + } if (isPublic) { const updateDetailsAction = ReduxSogsRoomInfos.roomDetailsChange({ conversationId, diff --git a/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx b/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx index a7ea7471b..1f5733cd9 100644 --- a/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx @@ -385,8 +385,6 @@ export const DefaultSettingPage = () => { conversationId={us} onPlusAvatarClick={null} dataTestId="avatar-edit-profile-dialog" - // no qr click here as a button is already doing that action (and the qr button looks bad when the small size as the +) - // Note: this changes with the new Settings design onQRClick={() => setMode('qr')} enlargedImage={enlargedImage} toggleEnlargedImage={() => setEnlargedImage(!enlargedImage)} diff --git a/ts/session/profile_manager/ProfileManager.ts b/ts/session/profile_manager/ProfileManager.ts index 37cc1fdad..6196383d1 100644 --- a/ts/session/profile_manager/ProfileManager.ts +++ b/ts/session/profile_manager/ProfileManager.ts @@ -161,7 +161,7 @@ async function updateOurProfileDisplayName(newName: string) { // might be good to not trigger a sync if the name did not change await conversation.commit(); - await SyncUtils.forceSyncConfigurationNowIfNeeded(true); + void SyncUtils.forceSyncConfigurationNowIfNeeded(true); return truncatedName; } diff --git a/ts/state/ducks/user.ts b/ts/state/ducks/user.ts index 5d4731d40..fdb9ccda0 100644 --- a/ts/state/ducks/user.ts +++ b/ts/state/ducks/user.ts @@ -11,12 +11,14 @@ export type UserStateType = { ourDisplayNameInProfile: string; ourNumber: string; uploadingNewAvatarCurrentUser: boolean; + uploadingNewAvatarCurrentUserFailed: boolean; }; export const initialUserState: UserStateType = { ourDisplayNameInProfile: '', ourNumber: 'missing', uploadingNewAvatarCurrentUser: false, + uploadingNewAvatarCurrentUserFailed: false, }; /** @@ -43,9 +45,10 @@ const updateOurAvatar = createAsyncThunk( profileKey, }); - window.inboxStore?.dispatch(updateEditProfilePictureModal(null)); - window.inboxStore?.dispatch(userSettingsModal({ userSettingsPage: 'default' })); - + if (res) { + window.inboxStore?.dispatch(updateEditProfilePictureModal(null)); + window.inboxStore?.dispatch(userSettingsModal({ userSettingsPage: 'default' })); + } return res; } ); @@ -111,16 +114,18 @@ const userSlice = createSlice({ window.log.info('a updateOurAvatar was fulfilled with:', action.payload); state.uploadingNewAvatarCurrentUser = false; + state.uploadingNewAvatarCurrentUserFailed = !action.payload; return state; }); builder.addCase(updateOurAvatar.rejected, (state, action) => { window.log.error('a updateOurAvatar was rejected', action.error); state.uploadingNewAvatarCurrentUser = false; + state.uploadingNewAvatarCurrentUserFailed = true; return state; }); builder.addCase(updateOurAvatar.pending, (state, _action) => { state.uploadingNewAvatarCurrentUser = true; - + state.uploadingNewAvatarCurrentUserFailed = false; window.log.debug('a updateOurAvatar is pending'); return state; }); diff --git a/ts/state/selectors/user.ts b/ts/state/selectors/user.ts index 6e518d331..246fe2c34 100644 --- a/ts/state/selectors/user.ts +++ b/ts/state/selectors/user.ts @@ -25,3 +25,7 @@ export function useOurPkStr() { export function useOurAvatarIsUploading() { return useSelector((state: StateType) => getUser(state).uploadingNewAvatarCurrentUser); } + +export function useOurAvatarUploadFailed() { + return useSelector((state: StateType) => getUser(state).uploadingNewAvatarCurrentUserFailed); +} From 5f41099e214393bb25757cc575de712f428fda45 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Thu, 21 Aug 2025 14:28:16 +1000 Subject: [PATCH 16/18] chore: remove Message section and link back buttons in leftpane --- .../buttons/avatar/GearAvatarButton.tsx | 2 +- .../pages/EditPasswordSettingsPage.tsx | 11 ++++-- ts/components/icon/lucide.ts | 1 + ts/components/leftpane/ActionsPanel.tsx | 26 ++------------ ts/components/leftpane/LeftPane.tsx | 11 +----- .../leftpane/LeftPaneSectionHeader.tsx | 35 ++++++++++++------- .../conversation-list-item/HeaderItem.tsx | 9 +---- ts/components/menu/Menu.tsx | 12 ++----- .../UseTogglePinConversationHandler.tsx | 10 ++---- .../menuAndSettingsHooks/usePinUnpin.ts | 10 ++---- ts/state/ducks/section.tsx | 11 +----- ts/state/selectors/section.ts | 18 ++-------- 12 files changed, 46 insertions(+), 110 deletions(-) diff --git a/ts/components/buttons/avatar/GearAvatarButton.tsx b/ts/components/buttons/avatar/GearAvatarButton.tsx index d34e2c090..14b261a80 100644 --- a/ts/components/buttons/avatar/GearAvatarButton.tsx +++ b/ts/components/buttons/avatar/GearAvatarButton.tsx @@ -10,7 +10,7 @@ export const GearAvatarButton = () => { @@ -268,7 +268,14 @@ export function EditPasswordSettingsPage(modalState: { buttonType={SessionButtonType.Outline} onClick={doChange} buttonColor={isRemove ? SessionButtonColor.Danger : SessionButtonColor.Primary} - disabled={!firstPassword} + disabled={ + // to set a password, we need both passwords (new & confirm) + (isSet && (!firstPassword || !secondPassword)) || + // to change a password, we need all 3 passwords (current, new & confirm ) + (isChange && (!firstPassword || !secondPassword || !thirdPassword)) || + // to remove a password, we need the current password + (isRemove && !firstPassword) + } /> } diff --git a/ts/components/icon/lucide.ts b/ts/components/icon/lucide.ts index 0bee0bd58..5e5b81973 100644 --- a/ts/components/icon/lucide.ts +++ b/ts/components/icon/lucide.ts @@ -14,6 +14,7 @@ export enum LUCIDE_ICONS_UNICODE { CIRCLE_ELLIPSES = '', CIRCLE_HELP = '', CIRCLE_PLUS = '', + CIRCLE_X = '', CLAPERBOARD = '', COPY = '', DOWNLOAD = '', diff --git a/ts/components/leftpane/ActionsPanel.tsx b/ts/components/leftpane/ActionsPanel.tsx index 2a27c681e..f82c44d58 100644 --- a/ts/components/leftpane/ActionsPanel.tsx +++ b/ts/components/leftpane/ActionsPanel.tsx @@ -16,7 +16,6 @@ import { getOurPrimaryConversation, useGlobalUnreadMessageCount, } from '../../state/selectors/conversations'; -import { getFocusedSection } from '../../state/selectors/section'; import { getOurNumber } from '../../state/selectors/user'; import { DecryptedAttachmentsManager } from '../../session/crypto/DecryptedAttachmentsManager'; @@ -46,7 +45,6 @@ import { useHotkey } from '../../hooks/useHotkey'; import { useIsDarkTheme } from '../../state/theme/selectors/theme'; import { switchThemeTo } from '../../themes/switchTheme'; import { getOppositeTheme } from '../../util/theme'; -import { SessionNotificationCount } from '../icon/SessionNotificationCount'; import { getIsModalVisible } from '../../state/selectors/modal'; import { MessageQueue } from '../../session/sending'; @@ -89,14 +87,11 @@ function handleThemeSwitch() { const Section = (props: { type: SectionType }) => { const ourNumber = useSelector(getOurNumber); - const globalUnreadMessageCount = useGlobalUnreadMessageCount(); const dispatch = useDispatch(); const { type } = props; const isModalVisible = useSelector(getIsModalVisible); const isDarkTheme = useIsDarkTheme(); - const focusedSection = useSelector(getFocusedSection); - const isSelected = focusedSection === type; const handleClick = () => { if (type === SectionType.DebugMenu) { @@ -114,14 +109,12 @@ const Section = (props: { type: SectionType }) => { } // message section dispatch(searchActions.clearSearch()); - dispatch(sectionActions.showLeftPaneSection(type)); dispatch(sectionActions.resetLeftOverlayMode()); }; useHotkey('Escape', () => { if (!isModalVisible) { dispatch(searchActions.clearSearch()); - dispatch(sectionActions.showLeftPaneSection(SectionType.Message)); dispatch(sectionActions.resetLeftOverlayMode()); } }); @@ -140,29 +133,14 @@ const Section = (props: { type: SectionType }) => { ); } - const unreadToShow = type === SectionType.Message ? globalUnreadMessageCount : undefined; - const buttonProps = { iconSize: 'medium', padding: 'var(--margins-lg)', onClick: handleClick, - isSelected, + isSelected: false, } satisfies Omit; switch (type) { - case SectionType.Message: - return ( - - {Boolean(unreadToShow) && } - - ); case SectionType.DebugMenu: return ( { return ( @@ -362,7 +341,6 @@ export const ActionsPanel = () => { <>
-
{showDebugMenu &&
}
diff --git a/ts/components/leftpane/LeftPane.tsx b/ts/components/leftpane/LeftPane.tsx index ad37955ca..b2178e690 100644 --- a/ts/components/leftpane/LeftPane.tsx +++ b/ts/components/leftpane/LeftPane.tsx @@ -1,7 +1,4 @@ -import { useSelector } from 'react-redux'; import styled from 'styled-components'; -import { SectionType } from '../../state/ducks/section'; -import { getFocusedSection } from '../../state/selectors/section'; import { SessionToastContainer } from '../SessionToastContainer'; import { CallInFullScreenContainer } from '../calling/CallInFullScreenContainer'; import { DraggableCallContainer } from '../calling/DraggableCallContainer'; @@ -26,13 +23,7 @@ const StyledLeftPane = styled.div<{ isRtl: boolean }>` `; const LeftPaneSection = () => { - const focusedSection = useSelector(getFocusedSection); - - if (focusedSection === SectionType.Message) { - return ; - } - - return null; + return ; }; const CallContainer = () => { diff --git a/ts/components/leftpane/LeftPaneSectionHeader.tsx b/ts/components/leftpane/LeftPaneSectionHeader.tsx index 94a61c4d9..e30aa3eef 100644 --- a/ts/components/leftpane/LeftPaneSectionHeader.tsx +++ b/ts/components/leftpane/LeftPaneSectionHeader.tsx @@ -1,8 +1,8 @@ import { useDispatch, useSelector } from 'react-redux'; import styled from 'styled-components'; -import { LeftOverlayMode, sectionActions, SectionType } from '../../state/ducks/section'; +import { LeftOverlayMode, sectionActions } from '../../state/ducks/section'; import { disableRecoveryPhrasePrompt } from '../../state/ducks/userConfig'; -import { getFocusedSection, useLeftOverlayMode } from '../../state/selectors/section'; +import { useLeftOverlayMode } from '../../state/selectors/section'; import { useHideRecoveryPasswordEnabled } from '../../state/selectors/settings'; import { useIsDarkTheme } from '../../state/theme/selectors/theme'; import { getShowRecoveryPhrasePrompt } from '../../state/selectors/userConfig'; @@ -107,7 +107,6 @@ function getLeftPaneHeaderLabel(leftOverlayMode: LeftOverlayMode | undefined): s export const LeftPaneBanner = () => { const isDarkTheme = useIsDarkTheme(); - const section = useSelector(getFocusedSection); const isSignInWithRecoveryPhrase = isSignWithRecoveryPhrase(); const hideRecoveryPassword = useHideRecoveryPasswordEnabled(); @@ -118,7 +117,7 @@ export const LeftPaneBanner = () => { dispatch(userSettingsModal({ userSettingsPage: 'recovery-password' })); }; - if (section !== SectionType.Message || isSignInWithRecoveryPhrase || hideRecoveryPassword) { + if (isSignInWithRecoveryPhrase || hideRecoveryPassword) { return null; } @@ -160,19 +159,28 @@ export const LeftPaneBanner = () => { export const LeftPaneSectionHeader = () => { const showRecoveryPhrasePrompt = useSelector(getShowRecoveryPhrasePrompt); - const focusedSection = useSelector(getFocusedSection); const leftOverlayMode = useLeftOverlayMode(); const dispatch = useDispatch(); - const returnToActionChooser = () => { + const goBack = () => { + if (!leftOverlayMode) { + return; + } + if (leftOverlayMode === 'choose-action') { + dispatch(sectionActions.resetLeftOverlayMode()); + + return; + } if (leftOverlayMode === 'closed-group') { dispatch(searchActions.clearSearch()); + dispatch(sectionActions.setLeftOverlayMode('choose-action')); + + return; } dispatch(sectionActions.setLeftOverlayMode('choose-action')); }; const label = getLeftPaneHeaderLabel(leftOverlayMode); - const isMessageSection = focusedSection === SectionType.Message; return ( @@ -182,21 +190,22 @@ export const LeftPaneSectionHeader = () => { $justifyContent="space-between" $alignItems="center" > - {leftOverlayMode && - leftOverlayMode !== 'choose-action' && - leftOverlayMode !== 'message-requests' ? ( + {leftOverlayMode ? ( ) : ( )} - {label} - {isMessageSection && } + + {label} + + {!leftOverlayMode && } {showRecoveryPhrasePrompt && } diff --git a/ts/components/leftpane/conversation-list-item/HeaderItem.tsx b/ts/components/leftpane/conversation-list-item/HeaderItem.tsx index ac6db8284..310050551 100644 --- a/ts/components/leftpane/conversation-list-item/HeaderItem.tsx +++ b/ts/components/leftpane/conversation-list-item/HeaderItem.tsx @@ -18,21 +18,15 @@ import { openConversationWithMessages, } from '../../../state/ducks/conversations'; import { useIsSearchingForType } from '../../../state/selectors/search'; -import { useIsMessageSection } from '../../../state/selectors/section'; import { Timestamp } from '../../conversation/Timestamp'; import { SessionIcon } from '../../icon'; import { UserItem } from './UserItem'; import type { WithConvoId } from '../../../session/types/with'; const NotificationSettingIcon = () => { - const isMessagesSection = useIsMessageSection(); const convoId = useConvoIdFromContext(); const convoSetting = useNotificationSetting(convoId); - if (!isMessagesSection) { - return null; - } - switch (convoSetting) { case 'all': return null; @@ -66,10 +60,9 @@ const StyledConversationListItemIconWrapper = styled.div` const PinIcon = () => { const conversationId = useConvoIdFromContext(); - const isMessagesSection = useIsMessageSection(); const isPinned = useIsPinned(conversationId); - return isMessagesSection && isPinned ? ( + return isPinned ? ( ) : null; }; diff --git a/ts/components/menu/Menu.tsx b/ts/components/menu/Menu.tsx index 91c8ca3ae..2ee8fdb24 100644 --- a/ts/components/menu/Menu.tsx +++ b/ts/components/menu/Menu.tsx @@ -15,10 +15,7 @@ import { import { ConvoHub } from '../../session/conversations'; import { PubKey } from '../../session/types'; import { useConversationIdOrigin } from '../../state/selectors/conversations'; -import { - useIsMessageRequestOverlayShown, - useIsMessageSection, -} from '../../state/selectors/section'; +import { useIsMessageRequestOverlayShown } from '../../state/selectors/section'; import { useSelectedConversationKey } from '../../state/selectors/selectedConversation'; import { ItemWithDataTestId } from './items/MenuItemWithDataTestId'; import { NetworkTime } from '../../util/NetworkTime'; @@ -57,16 +54,11 @@ export const InviteContactMenuItem = (): JSX.Element | null => { export const MarkConversationUnreadMenuItem = (): JSX.Element | null => { const conversationId = useConvoIdFromContext(); - const isMessagesSection = useIsMessageSection(); const isPrivate = useIsPrivate(conversationId); const isPrivateAndFriend = useIsPrivateAndFriend(conversationId); const isMessageRequestShown = useIsMessageRequestOverlayShown(); - if ( - isMessagesSection && - !isMessageRequestShown && - (!isPrivate || (isPrivate && isPrivateAndFriend)) - ) { + if (!isMessageRequestShown && (!isPrivate || (isPrivate && isPrivateAndFriend))) { const conversation = ConvoHub.use().get(conversationId); const markUnread = () => { diff --git a/ts/components/menuAndSettingsHooks/UseTogglePinConversationHandler.tsx b/ts/components/menuAndSettingsHooks/UseTogglePinConversationHandler.tsx index 06a6c2c86..ca4259445 100644 --- a/ts/components/menuAndSettingsHooks/UseTogglePinConversationHandler.tsx +++ b/ts/components/menuAndSettingsHooks/UseTogglePinConversationHandler.tsx @@ -14,14 +14,10 @@ import { } from '../dialog/SessionProInfoModal'; import { Constants } from '../../session'; import { getPinnedConversationsCount } from '../../state/selectors/conversations'; -import { - useIsMessageRequestOverlayShown, - useIsMessageSection, -} from '../../state/selectors/section'; +import { useIsMessageRequestOverlayShown } from '../../state/selectors/section'; import { useCurrentUserHasPro } from '../../hooks/useHasPro'; function useShowPinUnpin(conversationId: string) { - const isMessagesSection = useIsMessageSection(); const isPrivateAndFriend = useIsPrivateAndFriend(conversationId); const isPrivate = useIsPrivate(conversationId); const isMessageRequest = useIsMessageRequestOverlayShown(); @@ -39,9 +35,7 @@ function useShowPinUnpin(conversationId: string) { return false; } - return ( - isMessagesSection && !isMessageRequest && (!isPrivate || (isPrivate && isPrivateAndFriend)) - ); + return !isMessageRequest && (!isPrivate || (isPrivate && isPrivateAndFriend)); } export function useTogglePinConversationHandler(id: string) { diff --git a/ts/components/menuAndSettingsHooks/usePinUnpin.ts b/ts/components/menuAndSettingsHooks/usePinUnpin.ts index 35c301404..a12bad683 100644 --- a/ts/components/menuAndSettingsHooks/usePinUnpin.ts +++ b/ts/components/menuAndSettingsHooks/usePinUnpin.ts @@ -5,13 +5,9 @@ import { useIsPrivate, useIsPrivateAndFriend, } from '../../hooks/useParamSelector'; -import { - useIsMessageRequestOverlayShown, - useIsMessageSection, -} from '../../state/selectors/section'; +import { useIsMessageRequestOverlayShown } from '../../state/selectors/section'; export function useShowPinUnpin(conversationId: string) { - const isMessagesSection = useIsMessageSection(); const isPrivateAndFriend = useIsPrivateAndFriend(conversationId); const isPrivate = useIsPrivate(conversationId); const isMessageRequest = useIsMessageRequestOverlayShown(); @@ -29,7 +25,5 @@ export function useShowPinUnpin(conversationId: string) { return false; } - return ( - isMessagesSection && !isMessageRequest && (!isPrivate || (isPrivate && isPrivateAndFriend)) - ); + return !isMessageRequest && (!isPrivate || (isPrivate && isPrivateAndFriend)); } diff --git a/ts/state/ducks/section.tsx b/ts/state/ducks/section.tsx index de42dc745..61462567a 100644 --- a/ts/state/ducks/section.tsx +++ b/ts/state/ducks/section.tsx @@ -4,9 +4,8 @@ import { createSlice, type PayloadAction } from '@reduxjs/toolkit'; export enum SectionType { Profile, - Message, - ThemeSwitch, DebugMenu, + ThemeSwitch, } export type LeftOverlayMode = @@ -25,14 +24,12 @@ type RightPanelMessageInfoState = { export type RightOverlayMode = RightPanelDefaultState | RightPanelMessageInfoState; export const initialSectionState: SectionStateType = { - focusedSection: SectionType.Message, isAppFocused: false, leftOverlayMode: undefined, rightOverlayMode: { type: 'default', params: null }, }; export type SectionStateType = { - focusedSection: SectionType; isAppFocused: boolean; leftOverlayMode: LeftOverlayMode | undefined; rightOverlayMode: RightOverlayMode | undefined; @@ -42,12 +39,6 @@ const sectionSlice = createSlice({ name: 'sectionSlice', initialState: initialSectionState, reducers: { - showLeftPaneSection(state, action: PayloadAction) { - return { - ...state, - focusedSection: action.payload, - }; - }, setLeftOverlayMode(state, action: PayloadAction) { return { ...state, diff --git a/ts/state/selectors/section.ts b/ts/state/selectors/section.ts index a8d267c24..d67aad37d 100644 --- a/ts/state/selectors/section.ts +++ b/ts/state/selectors/section.ts @@ -1,24 +1,11 @@ import { createSelector } from '@reduxjs/toolkit'; import { useSelector } from 'react-redux'; -import { LeftOverlayMode, SectionStateType, SectionType } from '../ducks/section'; +import { LeftOverlayMode, SectionStateType } from '../ducks/section'; import { StateType } from '../reducer'; export const getSection = (state: StateType): SectionStateType => state.section; -export const getFocusedSection = createSelector( - getSection, - (state: SectionStateType): SectionType => state.focusedSection -); - -export const getIsMessageSection = (state: StateType) => { - return state.section.focusedSection === SectionType.Message; -}; - -export function useIsMessageSection() { - return useSelector(getIsMessageSection); -} - export const getIsAppFocused = createSelector( getSection, (state: SectionStateType): boolean => state.isAppFocused @@ -38,10 +25,9 @@ export const getRightOverlayMode = (state: StateType) => { }; const getIsMessageRequestOverlayShown = (state: StateType) => { - const focusedSection = getFocusedSection(state); const leftOverlayMode = getLeftOverlayMode(state); - return focusedSection === SectionType.Message && leftOverlayMode === 'message-requests'; + return leftOverlayMode === 'message-requests'; }; export function useIsMessageRequestOverlayShown() { From d9e66eec464f83dff6ac37c63dfb2809913ecb22 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Thu, 21 Aug 2025 14:59:07 +1000 Subject: [PATCH 17/18] chore: cosmetic changes for usersettingsmodal --- ts/components/basic/SessionToggle.tsx | 2 +- ts/components/dialog/EnterPasswordModal.tsx | 2 +- .../pages/AppearanceSettingsPage.tsx | 8 +++-- .../pages/DefaultSettingsPage.tsx | 6 +++- .../pages/EditPasswordSettingsPage.tsx | 15 ++++++---- ts/components/leftpane/ActionsPanel.tsx | 5 ++-- ts/hooks/useZoomingShortcut.ts | 30 +++++++++---------- ts/localization/localeTools.ts | 2 +- ts/state/ducks/modalDialog.tsx | 2 +- 9 files changed, 41 insertions(+), 31 deletions(-) diff --git a/ts/components/basic/SessionToggle.tsx b/ts/components/basic/SessionToggle.tsx index 4a25a6cbb..d91f3b70d 100644 --- a/ts/components/basic/SessionToggle.tsx +++ b/ts/components/basic/SessionToggle.tsx @@ -52,7 +52,7 @@ export const SessionToggle = ({ }: { active: boolean; /** - * in undefined, the toggle won't be clickable and disabled + * if `onClick` is undefined, the toggle won't be clickable and disabled */ onClick?: () => void; dataTestId?: SessionDataTestId; diff --git a/ts/components/dialog/EnterPasswordModal.tsx b/ts/components/dialog/EnterPasswordModal.tsx index 9ccc7f1ce..3f5bfa3b5 100644 --- a/ts/components/dialog/EnterPasswordModal.tsx +++ b/ts/components/dialog/EnterPasswordModal.tsx @@ -73,7 +73,7 @@ export const EnterPasswordModal = (props: EnterPasswordModalProps) => { buttonChildren={ void) { const zoomFactorMenuId = 'zoom-factor-menu'; -const zoomFactorValues = range(ZOOM_FACTOR.MIN, ZOOM_FACTOR.MAX, ZOOM_FACTOR.STEP); +const zoomFactorValues = range( + ZOOM_FACTOR.MIN, + ZOOM_FACTOR.MAX + ZOOM_FACTOR.STEP, // just so the upper end is an option + ZOOM_FACTOR.STEP +); const ZoomFactorMenuPicker = ({ forceUpdate, @@ -314,7 +318,7 @@ const ZoomFactorMenuPicker = ({ function ZoomFactorPicker({ forceUpdate }: { forceUpdate: () => void }) { const baseDataTestId = 'zoom-factor'; useInterval(() => { - // the shortcut can change this value. So let's make this refresh every second when displayed + // the keyboard shortcuts can change this value. So let's make this refresh often when visible forceUpdate(); }, 500); diff --git a/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx b/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx index 1f5733cd9..576cbb3fb 100644 --- a/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/DefaultSettingsPage.tsx @@ -407,7 +407,11 @@ export const DefaultSettingPage = () => { onClick={copyAccountIdToClipboard} /> } - style={{ color: 'var(--text-primary-color)' }} + style={{ + color: 'var(--text-primary-color)', + fontSize: 'var(--font-size-h8)', + lineHeight: 1.1, + }} onClick={copyAccountIdToClipboard} /> diff --git a/ts/components/dialog/user-settings/pages/EditPasswordSettingsPage.tsx b/ts/components/dialog/user-settings/pages/EditPasswordSettingsPage.tsx index c1afcded3..ec260fd15 100644 --- a/ts/components/dialog/user-settings/pages/EditPasswordSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/EditPasswordSettingsPage.tsx @@ -38,7 +38,7 @@ function StrengthCriteria(opts: { isMet: boolean } & WithTrArgs) { const criteriaMetColor = theme.includes('classic') ? 'var(--green-color)' : 'var(--blue-color)'; return ( - + + - diff --git a/ts/components/leftpane/ActionsPanel.tsx b/ts/components/leftpane/ActionsPanel.tsx index f82c44d58..87cfec041 100644 --- a/ts/components/leftpane/ActionsPanel.tsx +++ b/ts/components/leftpane/ActionsPanel.tsx @@ -61,6 +61,7 @@ import { themesArray } from '../../themes/constants/colors'; import { isDebugMode } from '../../shared/env_vars'; import { GearAvatarButton } from '../buttons/avatar/GearAvatarButton'; import { useZoomShortcuts } from '../../hooks/useZoomingShortcut'; +import { assertUnreachable } from '../../types/sqlSharedTypes'; const StyledContainerAvatar = styled.div` padding: var(--margins-lg); @@ -107,9 +108,7 @@ const Section = (props: { type: SectionType }) => { dispatch(userSettingsModal({ userSettingsPage: 'default' })); return; } - // message section - dispatch(searchActions.clearSearch()); - dispatch(sectionActions.resetLeftOverlayMode()); + assertUnreachable(type, `handleClick: unhandled case "${type}"`); }; useHotkey('Escape', () => { diff --git a/ts/hooks/useZoomingShortcut.ts b/ts/hooks/useZoomingShortcut.ts index 4293f5973..a73f0272f 100644 --- a/ts/hooks/useZoomingShortcut.ts +++ b/ts/hooks/useZoomingShortcut.ts @@ -1,24 +1,24 @@ import useKey from 'react-use/lib/useKey'; import { ZOOM_FACTOR } from '../session/constants'; -export function useZoomShortcuts() { - const changeZoom = async ( - change: { typeOfChange: 'delta'; delta: number } | { typeOfChange: 'reset' } - ) => { - let value: number = await window.getSettingValue('zoom-factor-setting'); - if (typeof value !== 'number') { - value = ZOOM_FACTOR.DEFAULT; - } - if (change.typeOfChange === 'reset') { - await window.setSettingValue('zoom-factor-setting', value); - window.updateZoomFactor(); - return; - } - value = Math.min(Math.max(value + change.delta, ZOOM_FACTOR.MIN), ZOOM_FACTOR.MAX); +const changeZoom = async ( + change: { typeOfChange: 'delta'; delta: number } | { typeOfChange: 'reset' } +) => { + let value: number = await window.getSettingValue('zoom-factor-setting'); + if (typeof value !== 'number') { + value = ZOOM_FACTOR.DEFAULT; + } + if (change.typeOfChange === 'reset') { await window.setSettingValue('zoom-factor-setting', value); window.updateZoomFactor(); - }; + return; + } + value = Math.min(Math.max(value + change.delta, ZOOM_FACTOR.MIN), ZOOM_FACTOR.MAX); + await window.setSettingValue('zoom-factor-setting', value); + window.updateZoomFactor(); +}; +export function useZoomShortcuts() { useKey( event => (event.ctrlKey || event.metaKey) && (event.key === '+' || event.key === '='), event => { diff --git a/ts/localization/localeTools.ts b/ts/localization/localeTools.ts index 50ae7d9f2..b34a7b63b 100644 --- a/ts/localization/localeTools.ts +++ b/ts/localization/localeTools.ts @@ -137,7 +137,7 @@ export type GetMessageArgs = T extends MergedLo export type TrArgs = GetMessageArgs; -export type WithTrArgs = { tr: TrArgs }; +export type WithTrArgs = { trArgs: TrArgs }; export function tStrippedWithObj(opts: GetMessageArgs): string { const builder = new LocalizedStringBuilder(opts.token as T, localeInUse).stripIt(); diff --git a/ts/state/ducks/modalDialog.tsx b/ts/state/ducks/modalDialog.tsx index 2ce5c8461..92e33f1d1 100644 --- a/ts/state/ducks/modalDialog.tsx +++ b/ts/state/ducks/modalDialog.tsx @@ -135,7 +135,7 @@ export const initialModalState: ModalState = { groupMembersModal: null, userProfileModal: null, nickNameModal: null, - userSettingsModal: { userSettingsPage: 'privacy' }, + userSettingsModal: null, onionPathModal: null, enterPasswordModal: null, deleteAccountModal: null, From fdf5ed2aeb7da01a9b9ec507dacb098fa3fcb38c Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Mon, 25 Aug 2025 12:12:12 +1000 Subject: [PATCH 18/18] chore: address PR feedback --- ts/components/basic/SessionToggle.tsx | 1 - ts/components/buttons/panel/PanelButton.tsx | 15 +++++++++------ .../user-settings/pages/HelpSettingsPage.tsx | 2 +- ts/themes/globals.tsx | 4 ++++ 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/ts/components/basic/SessionToggle.tsx b/ts/components/basic/SessionToggle.tsx index d91f3b70d..889bd2c67 100644 --- a/ts/components/basic/SessionToggle.tsx +++ b/ts/components/basic/SessionToggle.tsx @@ -26,7 +26,6 @@ const StyledKnob = styled.div<{ active: boolean }>` const StyledSessionToggle = styled.div<{ active: boolean; disabled: boolean }>` width: 51px; height: 25px; - background-color: (--toggle-switch-off-background-color); border: 1px solid var(--toggle-switch-off-border-color); border-radius: 16px; position: relative; diff --git a/ts/components/buttons/panel/PanelButton.tsx b/ts/components/buttons/panel/PanelButton.tsx index 3d092e84b..604d0a953 100644 --- a/ts/components/buttons/panel/PanelButton.tsx +++ b/ts/components/buttons/panel/PanelButton.tsx @@ -72,7 +72,6 @@ const StyledRoundedPanelButtonGroup = styled.div` `; const PanelButtonContainer = styled.div` - --panel-button-container-min-height: 50px; overflow: auto; min-height: var(--panel-button-container-min-height); max-height: 100%; @@ -116,11 +115,15 @@ export const StyledPanelButton = styled.button<{ padding-block: var(--margins-sm); &:hover { - background-color: ${props => - !props.disabled && - (props.isDarkTheme - ? 'var(--background-primary-color)' - : 'var(--background-secondary-color)')}; + background-color: ${props => { + if (props.disabled) { + return 'transparent'; // let the PanelButtonGroup background be visible + } + if (props.isDarkTheme) { + return 'color-mix(in srgb, var(--background-tertiary-color) 95%, white)'; + } + return 'color-mix(in srgb, var(--background-tertiary-color) 95%, black)'; + }}; } `; diff --git a/ts/components/dialog/user-settings/pages/HelpSettingsPage.tsx b/ts/components/dialog/user-settings/pages/HelpSettingsPage.tsx index 74d6eba3e..257279164 100644 --- a/ts/components/dialog/user-settings/pages/HelpSettingsPage.tsx +++ b/ts/components/dialog/user-settings/pages/HelpSettingsPage.tsx @@ -85,7 +85,7 @@ export function HelpSettingsPage(modalState: UserSettingsModalState) { text={{ token: 'helpSupport' }} subText={{ token: 'supportDescription' }} onClick={async () => { - showLinkVisitWarningDialog('https://sessionapp.zendesk.com/hc/en-us', dispatch); + showLinkVisitWarningDialog('https://getsession.org/support', dispatch); }} /> diff --git a/ts/themes/globals.tsx b/ts/themes/globals.tsx index 05d4423a3..8515fa225 100644 --- a/ts/themes/globals.tsx +++ b/ts/themes/globals.tsx @@ -80,6 +80,9 @@ type ThemeGlobals = { '--main-view-header-height': string; '--composition-container-height': string; '--search-input-height': string; + // The min height of the panel button container. + // Used to make sure all the types of panel items have the same height, even if only text is displayed + '--panel-button-container-min-height': string; /* Durations */ '--default-duration': string; @@ -227,6 +230,7 @@ export const THEME_GLOBALS: ThemeGlobals = { '--main-view-header-height': '68px', '--composition-container-height': '60px', '--search-input-height': '34px', + '--panel-button-container-min-height': '50px', '--default-duration': setDuration('0.25s'), '--default-duration-seconds': setDuration(0.25), // framer-motion requires a number