2021-08-01 16:00:35 +02:00
import React , { useState } from 'react' ;
2021-07-28 15:15:52 +02:00
import PropTypes from 'prop-types' ;
import './Settings.scss' ;
2021-07-31 10:21:19 +02:00
import initMatrix from '../../../client/initMatrix' ;
2021-11-06 10:45:35 +01:00
import cons from '../../../client/state/cons' ;
2021-07-28 15:15:52 +02:00
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 15:35:13 +01:00
import logout from '../../../client/action/logout' ;
2022-01-29 15:20:51 +01:00
import { usePermission } from '../../hooks/usePermission' ;
2021-07-28 15:15:52 +02:00
import Text from '../../atoms/text/Text' ;
import IconButton from '../../atoms/button/IconButton' ;
2021-07-31 18:20:15 +02:00
import Button from '../../atoms/button/Button' ;
2021-08-11 09:41:55 +02:00
import Toggle from '../../atoms/button/Toggle' ;
2021-07-28 15:15:52 +02:00
import SegmentedControls from '../../atoms/segmented-controls/SegmentedControls' ;
2021-07-31 16:23:08 +02:00
import PopupWindow , { PWContentSelector } from '../../molecules/popup-window/PopupWindow' ;
2021-07-28 15:15:52 +02:00
import SettingTile from '../../molecules/setting-tile/SettingTile' ;
2021-12-06 05:52:45 +01:00
import ImportE2ERoomKeys from '../../molecules/import-export-e2e-room-keys/ImportE2ERoomKeys' ;
import ExportE2ERoomKeys from '../../molecules/import-export-e2e-room-keys/ExportE2ERoomKeys' ;
2021-07-28 15:15:52 +02:00
2021-09-13 05:25:58 +02:00
import ProfileEditor from '../profile-editor/ProfileEditor' ;
import SettingsIC from '../../../../public/res/ic/outlined/settings.svg' ;
2021-07-31 16:23:08 +02:00
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 16:23:08 +02:00
import InfoIC from '../../../../public/res/ic/outlined/info.svg' ;
2021-12-19 15:35:13 +01:00
import PowerIC from '../../../../public/res/ic/outlined/power.svg' ;
2021-07-28 15:15:52 +02:00
import CrossIC from '../../../../public/res/ic/outlined/cross.svg' ;
2021-07-31 18:20:15 +02:00
import CinnySVG from '../../../../public/res/svg/cinny.svg' ;
2021-09-09 07:47:26 +02:00
function GeneralSection ( ) {
return (
< div className = "settings-content" >
< SettingTile
2021-09-13 08:57:55 +02:00
title = ""
2021-09-09 07:47:26 +02:00
content = { (
< ProfileEditor userId = { initMatrix . matrixClient . getUserId ( ) } / >
) }
/ >
< / div >
) ;
}
2021-07-31 16:23:08 +02:00
function AppearanceSection ( ) {
2021-08-11 09:41:55 +02:00
const [ , updateState ] = useState ( { } ) ;
2021-07-31 16:23:08 +02:00
return (
< div className = "settings-content" >
< SettingTile
2022-01-03 14:16:43 +01:00
title = "Follow system theme"
options = { (
< Toggle
isActive = { settings . useSystemTheme }
onToggle = { ( ) => { toggleSystemTheme ( ) ; updateState ( { } ) ; } }
2021-07-31 16:23:08 +02:00
/ >
) }
2022-01-03 14:16:43 +01:00
content = { < Text variant = "b3" > Use light or dark mode based on the system ' s settings . < / Text > }
2021-07-31 16:23:08 +02:00
/ >
2022-01-03 14:16:43 +01: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 14:16:43 +01:00
) }
2022-01-29 15:20:51 +01:00
/ >
) ;
2022-01-03 14:16:43 +01:00
}
} ) ( ) }
2021-08-11 09:41:55 +02:00
< SettingTile
title = "Markdown formatting"
options = { (
< Toggle
isActive = { settings . isMarkdown }
2021-12-12 16:23:32 +01:00
onToggle = { ( ) => { toggleMarkdown ( ) ; updateState ( { } ) ; } }
2021-08-11 09:41:55 +02:00
/ >
) }
content = { < Text variant = "b3" > Format messages with markdown syntax before sending . < / Text > }
/ >
2021-12-12 16:23:32 +01:00
< 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 16:23:08 +02:00
< / 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 16:23:08 +02:00
function SecuritySection ( ) {
2021-07-31 18:20:15 +02:00
return (
2021-08-01 16:00:35 +02:00
< div className = "set-security settings-content" >
< SettingTile
title = { ` Device ID: ${ initMatrix . matrixClient . getDeviceId ( ) } ` }
2021-08-19 18:54:09 +02:00
/ >
< 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 16:00:35 +02:00
/ >
2021-12-06 05:52:45 +01:00
< 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 16:00:35 +02:00
< SettingTile
title = "Import E2E room keys"
content = { (
< >
2021-08-07 03:05:10 +02: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 16:00:35 +02:00
< ImportE2ERoomKeys / >
< / >
) }
/ >
2021-07-31 18:20:15 +02:00
< / div >
) ;
2021-07-31 16:23:08 +02:00
}
function AboutSection ( ) {
return (
2022-01-31 07:45:58 +01:00
< div className = "settings-content set__about" >
2021-08-01 16:00:35 +02:00
< div className = "set-about__branding" >
2021-07-31 18:20:15 +02:00
< img width = "60" height = "60" src = { CinnySVG } alt = "Cinny logo" / >
< div >
2022-01-31 07:45:58 +01:00
< Text variant = "h2" weight = 'medium' >
2021-07-31 18:20:15 +02:00
Cinny
2021-11-06 10:45:35 +01:00
< span className = "text text-b3" style = { { margin : '0 var(--sp-extra-tight)' } } > { ` v ${ cons . version } ` } < / span >
2021-07-31 18:20:15 +02:00
< / Text >
< Text > Yet another matrix client < / Text >
2021-08-01 16:00:35 +02:00
< div className = "set-about__btns" >
2021-07-31 18:20:15 +02:00
< Button onClick = { ( ) => window . open ( 'https://github.com/ajbura/cinny' ) } > Source code < / Button >
2021-10-06 10:18:30 +02:00
< Button onClick = { ( ) => window . open ( 'https://cinny.in/#sponsor' ) } > Support < / Button >
2021-07-31 18:20:15 +02:00
< / div >
< / div >
< / div >
2022-01-31 07:45:58 +01:00
< div className = "set-about__credits" >
< Text variant = "s1" weight = "medium" > Credits < / Text >
< ul >
< li >
{ /* eslint-disable-next-line react/jsx-one-expression-per-line */ }
< Text > The < a href = "https://github.com/matrix-org/matrix-js-sdk" rel = "noreferrer noopener" target = "_blank" > matrix - js - sdk < / a > is © < a href = "https://matrix.org/foundation" rel = "noreferrer noopener" target = "_blank" > The Matrix . org Foundation C . I . C < / a > used under the terms of < a href = "http://www.apache.org/licenses/LICENSE-2.0" rel = "noreferrer noopener" target = "_blank" > Apache 2.0 < / a > . < / Text >
< / li >
< li >
{ /* eslint-disable-next-line react/jsx-one-expression-per-line */ }
< Text > The < a href = "https://twemoji.twitter.com" target = "_blank" rel = "noreferrer noopener" > Twemoji < / a > emoji art is © < a href = "https://twemoji.twitter.com" target = "_blank" rel = "noreferrer noopener" > Twitter , Inc and other contributors < / a > used under the terms of < a href = "https://creativecommons.org/licenses/by/4.0/" target = "_blank" rel = "noreferrer noopener" > CC - BY 4.0 < / a > . < / Text >
< / li >
< / ul >
< / div >
2021-07-31 16:23:08 +02:00
< / div >
) ;
}
2021-07-28 15:15:52 +02:00
function Settings ( { isOpen , onRequestClose } ) {
2021-07-31 16:23:08 +02:00
const settingSections = [ {
2021-09-09 07:47:26 +02:00
name : 'General' ,
2021-09-13 05:25:58 +02:00
iconSrc : SettingsIC ,
2021-09-09 07:47:26 +02:00
render ( ) {
return < GeneralSection / > ;
} ,
} , {
2021-07-31 16:23:08 +02:00
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 16:23:08 +02:00
} , {
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 15:35:13 +01:00
const handleLogout = ( ) => {
if ( confirm ( 'Confirm logout' ) ) logout ( ) ;
} ;
2021-07-28 15:15:52 +02:00
return (
< PopupWindow
className = "settings-window"
isOpen = { isOpen }
onRequestClose = { onRequestClose }
title = "Settings"
2021-07-31 16:23:08 +02:00
contentTitle = { selectedSection . name }
2021-12-19 15:35:13 +01:00
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 16:23:08 +02:00
< PWContentSelector
2021-12-19 15:35:13 +01:00
variant = "danger"
onClick = { handleLogout }
iconSrc = { PowerIC }
2021-07-31 16:23:08 +02:00
>
2021-12-19 15:35:13 +01:00
Logout
2021-07-31 16:23:08 +02:00
< / PWContentSelector >
2021-12-19 15:35:13 +01:00
< / >
) }
2021-07-28 15:15:52 +02:00
contentOptions = { < IconButton src = { CrossIC } onClick = { onRequestClose } tooltip = "Close" / > }
>
2021-07-31 16:23:08 +02:00
{ selectedSection . render ( ) }
2021-07-28 15:15:52 +02:00
< / PopupWindow >
) ;
}
Settings . propTypes = {
isOpen : PropTypes . bool . isRequired ,
onRequestClose : PropTypes . func . isRequired ,
} ;
export default Settings ;