2021-08-01 19:30:35 +05:30
import React , { useState } from 'react' ;
2021-07-28 18:45:52 +05:30
import PropTypes from 'prop-types' ;
import './Settings.scss' ;
2021-07-31 13:51:19 +05:30
import initMatrix from '../../../client/initMatrix' ;
2021-11-06 15:15:35 +05:30
import cons from '../../../client/state/cons' ;
2021-07-28 18:45:52 +05:30
import settings from '../../../client/state/settings' ;
2022-01-29 15:20:51 +01:00
import {
toggleSystemTheme , toggleMarkdown , toggleMembershipEvents , toggleNickAvatarEvents ,
toggleNotifications ,
} from '../../../client/action/settings' ;
2021-12-19 20:05:13 +05:30
import logout from '../../../client/action/logout' ;
2022-01-29 15:20:51 +01:00
import { usePermission } from '../../hooks/usePermission' ;
2021-07-28 18:45:52 +05:30
import Text from '../../atoms/text/Text' ;
import IconButton from '../../atoms/button/IconButton' ;
2021-07-31 21:50:15 +05:30
import Button from '../../atoms/button/Button' ;
2021-08-11 13:11:55 +05:30
import Toggle from '../../atoms/button/Toggle' ;
2021-07-28 18:45:52 +05:30
import SegmentedControls from '../../atoms/segmented-controls/SegmentedControls' ;
2021-07-31 19:53:08 +05:30
import PopupWindow , { PWContentSelector } from '../../molecules/popup-window/PopupWindow' ;
2021-07-28 18:45:52 +05:30
import SettingTile from '../../molecules/setting-tile/SettingTile' ;
2021-12-06 10:22:45 +05:30
import ImportE2ERoomKeys from '../../molecules/import-export-e2e-room-keys/ImportE2ERoomKeys' ;
import ExportE2ERoomKeys from '../../molecules/import-export-e2e-room-keys/ExportE2ERoomKeys' ;
2021-07-28 18:45:52 +05:30
2021-09-12 22:25:58 -05:00
import ProfileEditor from '../profile-editor/ProfileEditor' ;
import SettingsIC from '../../../../public/res/ic/outlined/settings.svg' ;
2021-07-31 19:53:08 +05:30
import SunIC from '../../../../public/res/ic/outlined/sun.svg' ;
import LockIC from '../../../../public/res/ic/outlined/lock.svg' ;
2022-01-29 15:20:51 +01:00
import BellIC from '../../../../public/res/ic/outlined/bell.svg' ;
2021-07-31 19:53:08 +05:30
import InfoIC from '../../../../public/res/ic/outlined/info.svg' ;
2021-12-19 20:05:13 +05:30
import PowerIC from '../../../../public/res/ic/outlined/power.svg' ;
2021-07-28 18:45:52 +05:30
import CrossIC from '../../../../public/res/ic/outlined/cross.svg' ;
2021-07-31 21:50:15 +05:30
import CinnySVG from '../../../../public/res/svg/cinny.svg' ;
2021-09-09 00:47:26 -05:00
function GeneralSection ( ) {
return (
< div className = "settings-content" >
< SettingTile
2021-09-13 12:27:55 +05:30
title = ""
2021-09-09 00:47:26 -05:00
content = { (
< ProfileEditor userId = { initMatrix . matrixClient . getUserId ( ) } / >
) }
/ >
< / div >
) ;
}
2021-07-31 19:53:08 +05:30
function AppearanceSection ( ) {
2021-08-11 13:11:55 +05:30
const [ , updateState ] = useState ( { } ) ;
2021-07-31 19:53:08 +05:30
return (
< div className = "settings-content" >
< SettingTile
2022-01-03 06:16:43 -07:00
title = "Follow system theme"
options = { (
< Toggle
isActive = { settings . useSystemTheme }
onToggle = { ( ) => { toggleSystemTheme ( ) ; updateState ( { } ) ; } }
2021-07-31 19:53:08 +05:30
/ >
) }
2022-01-03 06:16:43 -07:00
content = { < Text variant = "b3" > Use light or dark mode based on the system 's settings.</Text>}
2021-07-31 19:53:08 +05:30
/>
2022-01-03 06:16:43 -07:00
{(() => {
if (!settings.useSystemTheme) {
2022-01-29 15:20:51 +01:00
return (
<SettingTile
title="Theme"
content={(
<SegmentedControls
selected={settings.getThemeIndex()}
segments={[
{ text: ' Light ' },
{ text: ' Silver ' },
{ text: ' Dark ' },
{ text: ' Butter ' },
]}
onSelect={(index) => settings.setTheme(index)}
/>
2022-01-03 06:16:43 -07:00
)}
2022-01-29 15:20:51 +01:00
/>
);
2022-01-03 06:16:43 -07:00
}
})()}
2021-08-11 13:11:55 +05:30
<SettingTile
title="Markdown formatting"
options={(
<Toggle
isActive={settings.isMarkdown}
2021-12-12 20:53:32 +05:30
onToggle={() => { toggleMarkdown(); updateState({}); }}
2021-08-11 13:11:55 +05:30
/>
)}
content={<Text variant="b3">Format messages with markdown syntax before sending.</Text>}
/>
2021-12-12 20:53:32 +05:30
<SettingTile
title="Hide membership events"
options={(
<Toggle
isActive={settings.hideMembershipEvents}
onToggle={() => { toggleMembershipEvents(); updateState({}); }}
/>
)}
content={<Text variant="b3">Hide membership change messages from room timeline. (Join, Leave, Invite, Kick and Ban)</Text>}
/>
<SettingTile
title="Hide nick/avatar events"
options={(
<Toggle
isActive={settings.hideNickAvatarEvents}
onToggle={() => { toggleNickAvatarEvents(); updateState({}); }}
/>
)}
content={<Text variant="b3">Hide nick and avatar change messages from room timeline.</Text>}
/>
2021-07-31 19:53:08 +05:30
</div>
);
}
2022-01-29 15:20:51 +01:00
function NotificationsSection() {
const [permission, setPermission] = usePermission(' notifications ', window.Notification?.permission);
const [, updateState] = useState({});
const renderOptions = () => {
if (window.Notification === undefined) {
return <Text className="set-notifications__not-supported">Not supported in this browser.</Text>;
}
if (permission === ' granted ') {
return (
<Toggle
isActive={settings._showNotifications}
onToggle={() => {
toggleNotifications();
setPermission(window.Notification?.permission);
updateState({});
}}
/>
);
}
return (
<Button
variant="primary"
onClick={() => window.Notification.requestPermission().then(setPermission)}
>
Request permission
</Button>
);
};
return (
<div className="set-notifications settings-content">
<SettingTile
title="Show desktop notifications"
options={renderOptions()}
content={<Text variant="b3">Show notifications when new messages arrive.</Text>}
/>
</div>
);
}
2021-07-31 19:53:08 +05:30
function SecuritySection() {
2021-07-31 21:50:15 +05:30
return (
2021-08-01 19:30:35 +05:30
<div className="set-security settings-content">
<SettingTile
title={`Device ID: ${initMatrix.matrixClient.getDeviceId()}`}
2021-08-19 22:24:09 +05:30
/>
<SettingTile
title={`Device key: ${initMatrix.matrixClient.getDeviceEd25519Key().match(/.{1,4}/g).join(' ')}`}
content={<Text variant="b3">Use this device ID-key combo to verify or manage this session from Element client.</Text>}
2021-08-01 19:30:35 +05:30
/>
2021-12-06 10:22:45 +05:30
<SettingTile
title="Export E2E room keys"
content={(
<>
<Text variant="b3">Export end-to-end encryption room keys to decrypt old messages in other session. In order to encrypt keys you need to set a password, which will be used while importing.</Text>
<ExportE2ERoomKeys />
</>
)}
/>
2021-08-01 19:30:35 +05:30
<SettingTile
title="Import E2E room keys"
content={(
<>
2021-08-07 01:05:10 +00:00
<Text variant="b3">{' To decrypt older messages , Export E2EE room keys from Element ( Settings > Security & Privacy > Encryption > Cryptography ) and import them here . Imported keys are encrypted so you \ 'll have to enter the password you set in order to decrypt it.' } < / Text >
2021-08-01 19:30:35 +05:30
< ImportE2ERoomKeys / >
< / >
) }
/ >
2021-07-31 21:50:15 +05:30
< / div >
) ;
2021-07-31 19:53:08 +05:30
}
function AboutSection ( ) {
return (
2021-07-31 21:50:15 +05:30
< div className = "settings-content settings__about" >
2021-08-01 19:30:35 +05:30
< div className = "set-about__branding" >
2021-07-31 21:50:15 +05:30
< img width = "60" height = "60" src = { CinnySVG } alt = "Cinny logo" / >
< div >
< Text variant = "h2" >
Cinny
2021-11-06 15:15:35 +05:30
< span className = "text text-b3" style = { { margin : '0 var(--sp-extra-tight)' } } > { ` v ${ cons . version } ` } < / span >
2021-07-31 21:50:15 +05:30
< / Text >
< Text > Yet another matrix client < / Text >
2021-08-01 19:30:35 +05:30
< div className = "set-about__btns" >
2021-07-31 21:50:15 +05:30
< Button onClick = { ( ) => window . open ( 'https://github.com/ajbura/cinny' ) } > Source code < / Button >
2021-10-06 13:48:30 +05:30
< Button onClick = { ( ) => window . open ( 'https://cinny.in/#sponsor' ) } > Support < / Button >
2021-07-31 21:50:15 +05:30
< / div >
< / div >
< / div >
2021-07-31 19:53:08 +05:30
< / div >
) ;
}
2021-07-28 18:45:52 +05:30
function Settings ( { isOpen , onRequestClose } ) {
2021-07-31 19:53:08 +05:30
const settingSections = [ {
2021-09-09 00:47:26 -05:00
name : 'General' ,
2021-09-12 22:25:58 -05:00
iconSrc : SettingsIC ,
2021-09-09 00:47:26 -05:00
render ( ) {
return < GeneralSection / > ;
} ,
} , {
2021-07-31 19:53:08 +05:30
name : 'Appearance' ,
iconSrc : SunIC ,
render ( ) {
return < AppearanceSection / > ;
} ,
2022-01-29 15:20:51 +01:00
} , {
name : 'Notifications' ,
iconSrc : BellIC ,
render ( ) {
return < NotificationsSection / > ;
} ,
2021-07-31 19:53:08 +05:30
} , {
name : 'Security & Privacy' ,
iconSrc : LockIC ,
render ( ) {
return < SecuritySection / > ;
} ,
} , {
name : 'Help & About' ,
iconSrc : InfoIC ,
render ( ) {
return < AboutSection / > ;
} ,
} ] ;
const [ selectedSection , setSelectedSection ] = useState ( settingSections [ 0 ] ) ;
2021-12-19 20:05:13 +05:30
const handleLogout = ( ) => {
if ( confirm ( 'Confirm logout' ) ) logout ( ) ;
} ;
2021-07-28 18:45:52 +05:30
return (
< PopupWindow
className = "settings-window"
isOpen = { isOpen }
onRequestClose = { onRequestClose }
title = "Settings"
2021-07-31 19:53:08 +05:30
contentTitle = { selectedSection . name }
2021-12-19 20:05:13 +05:30
drawer = { (
< >
{
settingSections . map ( ( section ) => (
< PWContentSelector
key = { section . name }
selected = { selectedSection . name === section . name }
onClick = { ( ) => setSelectedSection ( section ) }
iconSrc = { section . iconSrc }
>
{ section . name }
< / PWContentSelector >
) )
}
2021-07-31 19:53:08 +05:30
< PWContentSelector
2021-12-19 20:05:13 +05:30
variant = "danger"
onClick = { handleLogout }
iconSrc = { PowerIC }
2021-07-31 19:53:08 +05:30
>
2021-12-19 20:05:13 +05:30
Logout
2021-07-31 19:53:08 +05:30
< / PWContentSelector >
2021-12-19 20:05:13 +05:30
< / >
) }
2021-07-28 18:45:52 +05:30
contentOptions = { < IconButton src = { CrossIC } onClick = { onRequestClose } tooltip = "Close" / > }
>
2021-07-31 19:53:08 +05:30
{ selectedSection . render ( ) }
2021-07-28 18:45:52 +05:30
< / PopupWindow >
) ;
}
Settings . propTypes = {
isOpen : PropTypes . bool . isRequired ,
onRequestClose : PropTypes . func . isRequired ,
} ;
export default Settings ;