Add colored nicks settings option
This commit is contained in:
parent
ec03db4db6
commit
6c6a9e12cf
File diff suppressed because one or more lines are too long
@ -81,7 +81,7 @@
|
|||||||
"test:watch": "jest --watch",
|
"test:watch": "jest --watch",
|
||||||
"gen:install": "GO111MODULE=off go get -u github.com/andyleap/gencode github.com/mailru/easyjson/... github.com/SlinSo/egon/cmd/egon",
|
"gen:install": "GO111MODULE=off go get -u github.com/andyleap/gencode github.com/mailru/easyjson/... github.com/SlinSo/egon/cmd/egon",
|
||||||
"gen:binary": "gencode go -package storage -schema ../storage/storage.schema -unsafe",
|
"gen:binary": "gencode go -package storage -schema ../storage/storage.schema -unsafe",
|
||||||
"gen:json": "easyjson -all -lower_camel_case -omit_empty ../server/json.go ../server/index_data.go",
|
"gen:json": "easyjson -all -lower_camel_case -omit_empty ../server/json.go ../server/index_data.go && easyjson -lower_camel_case -omit_empty ../storage/user.go",
|
||||||
"gen:template": "egon -s -m ../server"
|
"gen:template": "egon -s -m ../server"
|
||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
body {
|
body {
|
||||||
font-family: Roboto Mono, monospace;
|
font-family: Roboto Mono, monospace;
|
||||||
background: #f0f0f0;
|
background: #f0f0f0;
|
||||||
|
color: #222;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1,
|
h1,
|
||||||
@ -16,11 +17,6 @@ h4,
|
|||||||
h5,
|
h5,
|
||||||
h6 {
|
h6 {
|
||||||
font-family: Montserrat, sans-serif;
|
font-family: Montserrat, sans-serif;
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
input {
|
input {
|
||||||
@ -28,6 +24,7 @@ input {
|
|||||||
border: none;
|
border: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
|
color: #222;
|
||||||
}
|
}
|
||||||
|
|
||||||
input::-ms-clear {
|
input::-ms-clear {
|
||||||
@ -54,26 +51,44 @@ button:active {
|
|||||||
background: #6bb758;
|
background: #6bb758;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type='checkbox'] {
|
label {
|
||||||
|
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
user-select: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox.top-label {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox input {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: -99999px;
|
left: -99999px;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type='checkbox'] + span {
|
.checkbox span {
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
border: 2px solid #777;
|
border: 2px solid #777;
|
||||||
display: inline-block;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type='checkbox']:checked + span {
|
.checkbox:not(.top-label) span {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox input:checked + span {
|
||||||
background: #6bb758;
|
background: #6bb758;
|
||||||
border-color: #6bb758;
|
border-color: #6bb758;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type='checkbox']:checked + span:before {
|
.checkbox input:checked + span:before {
|
||||||
content: '';
|
content: '';
|
||||||
width: 5px;
|
width: 5px;
|
||||||
height: 10px;
|
height: 10px;
|
||||||
@ -456,6 +471,8 @@ input::-webkit-inner-spin-button {
|
|||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
padding: 0 5px;
|
padding: 0 5px;
|
||||||
font: 24px Montserrat, sans-serif;
|
font: 24px Montserrat, sans-serif;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #222;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
line-height: 50px;
|
line-height: 50px;
|
||||||
}
|
}
|
||||||
@ -692,48 +709,86 @@ input.message-input-nick.invalid {
|
|||||||
background: #ddd;
|
background: #ddd;
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings {
|
.settings-container {
|
||||||
text-align: center;
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings p {
|
.settings {
|
||||||
color: #999;
|
flex: 1;
|
||||||
|
max-width: 692px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-section {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
padding: 15px;
|
||||||
|
margin: 0 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings .checkbox {
|
||||||
|
margin-top: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings h1 {
|
.settings h1 {
|
||||||
|
text-align: center;
|
||||||
margin: 20px;
|
margin: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings h2 {
|
.settings h2 {
|
||||||
margin: 15px;
|
font-weight: 700;
|
||||||
|
color: #222;
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings button {
|
.settings button {
|
||||||
margin: 5px;
|
|
||||||
width: 200px;
|
width: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings div {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.settings .error {
|
.settings .error {
|
||||||
margin: 10px;
|
margin-top: 15px;
|
||||||
color: #f6546a;
|
color: #f6546a;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-file {
|
.input-file {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
background: #222 !important;
|
background: #222 !important;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
margin: 5px;
|
|
||||||
width: 200px;
|
width: 200px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.settings-file {
|
||||||
|
text-align: center;
|
||||||
|
display: inline-block;
|
||||||
|
margin-top: 15px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 906px) {
|
||||||
|
.settings-file {
|
||||||
|
display: block;
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-button {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-file p {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-cert {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
.ReactVirtualized__List {
|
.ReactVirtualized__List {
|
||||||
box-sizing: content-box !important;
|
box-sizing: content-box !important;
|
||||||
outline: none;
|
outline: none;
|
||||||
@ -813,4 +868,8 @@ input.message-input-nick.invalid {
|
|||||||
margin: auto 50px;
|
margin: auto 50px;
|
||||||
max-width: 400px;
|
max-width: 400px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.settings-section {
|
||||||
|
margin-left: 50px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,7 @@ export default class Chat extends Component {
|
|||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
channel,
|
channel,
|
||||||
|
coloredNicks,
|
||||||
currentInputHistoryEntry,
|
currentInputHistoryEntry,
|
||||||
hasMoreMessages,
|
hasMoreMessages,
|
||||||
messages,
|
messages,
|
||||||
@ -69,7 +70,6 @@ export default class Chat extends Component {
|
|||||||
toggleSearch,
|
toggleSearch,
|
||||||
toggleUserList
|
toggleUserList
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
let chatClass;
|
let chatClass;
|
||||||
if (isChannel(tab)) {
|
if (isChannel(tab)) {
|
||||||
chatClass = 'chat-channel';
|
chatClass = 'chat-channel';
|
||||||
@ -93,6 +93,7 @@ export default class Chat extends Component {
|
|||||||
/>
|
/>
|
||||||
<Search search={search} onSearch={this.handleSearch} />
|
<Search search={search} onSearch={this.handleSearch} />
|
||||||
<MessageBox
|
<MessageBox
|
||||||
|
coloredNicks={coloredNicks}
|
||||||
hasMoreMessages={hasMoreMessages}
|
hasMoreMessages={hasMoreMessages}
|
||||||
messages={messages}
|
messages={messages}
|
||||||
tab={tab}
|
tab={tab}
|
||||||
@ -111,6 +112,7 @@ export default class Chat extends Component {
|
|||||||
{...inputActions}
|
{...inputActions}
|
||||||
/>
|
/>
|
||||||
<UserList
|
<UserList
|
||||||
|
coloredNicks={coloredNicks}
|
||||||
showUserList={showUserList}
|
showUserList={showUserList}
|
||||||
users={users}
|
users={users}
|
||||||
onNickClick={this.handleNickClick}
|
onNickClick={this.handleNickClick}
|
||||||
|
@ -6,7 +6,7 @@ export default class Message extends PureComponent {
|
|||||||
handleNickClick = () => this.props.onNickClick(this.props.message.from);
|
handleNickClick = () => this.props.onNickClick(this.props.message.from);
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { message } = this.props;
|
const { message, coloredNick } = this.props;
|
||||||
|
|
||||||
const className = classnames('message', {
|
const className = classnames('message', {
|
||||||
[`message-${message.type}`]: message.type
|
[`message-${message.type}`]: message.type
|
||||||
@ -19,7 +19,7 @@ export default class Message extends PureComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const senderStyle = {};
|
const senderStyle = {};
|
||||||
if (message.from) {
|
if (message.from && coloredNick) {
|
||||||
senderStyle.color = stringToRGB(message.from);
|
senderStyle.color = stringToRGB(message.from);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,13 +176,14 @@ export default class MessageBox extends PureComponent {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { messages, onNickClick } = this.props;
|
const { messages, coloredNicks, onNickClick } = this.props;
|
||||||
const message = messages[index - 1];
|
const message = messages[index - 1];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Message
|
<Message
|
||||||
key={message.id}
|
key={message.id}
|
||||||
message={message}
|
message={message}
|
||||||
|
coloredNick={coloredNicks}
|
||||||
style={style}
|
style={style}
|
||||||
onNickClick={onNickClick}
|
onNickClick={onNickClick}
|
||||||
/>
|
/>
|
||||||
|
@ -16,12 +16,13 @@ export default class UserList extends PureComponent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
renderUser = ({ index, style, key }) => {
|
renderUser = ({ index, style, key }) => {
|
||||||
const { users, onNickClick } = this.props;
|
const { users, coloredNicks, onNickClick } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<UserListItem
|
<UserListItem
|
||||||
key={key}
|
key={key}
|
||||||
user={users[index]}
|
user={users[index]}
|
||||||
|
coloredNick={coloredNicks}
|
||||||
style={style}
|
style={style}
|
||||||
onClick={onNickClick}
|
onClick={onNickClick}
|
||||||
/>
|
/>
|
||||||
|
@ -5,11 +5,15 @@ export default class UserListItem extends PureComponent {
|
|||||||
handleClick = () => this.props.onClick(this.props.user.nick);
|
handleClick = () => this.props.onClick(this.props.user.nick);
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { user } = this.props;
|
const { user, coloredNick } = this.props;
|
||||||
const style = {
|
let { style } = this.props;
|
||||||
color: stringToRGB(user.nick),
|
|
||||||
...this.props.style
|
if (coloredNick) {
|
||||||
};
|
style = {
|
||||||
|
color: stringToRGB(user.nick),
|
||||||
|
...style
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<p style={style} onClick={this.handleClick}>
|
<p style={style} onClick={this.handleClick}>
|
||||||
|
@ -2,7 +2,7 @@ import React, { Component } from 'react';
|
|||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { Form, withFormik } from 'formik';
|
import { Form, withFormik } from 'formik';
|
||||||
import Navicon from 'containers/Navicon';
|
import Navicon from 'containers/Navicon';
|
||||||
import Checkbox from 'components/ui/Checkbox';
|
import Checkbox from 'components/ui/formik/Checkbox';
|
||||||
import TextInput from 'components/ui/TextInput';
|
import TextInput from 'components/ui/TextInput';
|
||||||
import Error from 'components/ui/formik/Error';
|
import Error from 'components/ui/formik/Error';
|
||||||
import { isValidNick, isValidChannel, isValidUsername, isInt } from 'utils';
|
import { isValidNick, isValidChannel, isValidUsername, isInt } from 'utils';
|
||||||
@ -77,7 +77,12 @@ class Connect extends Component {
|
|||||||
<div className="connect-form-address">
|
<div className="connect-form-address">
|
||||||
<TextInput name="host" placeholder="Host" />
|
<TextInput name="host" placeholder="Host" />
|
||||||
<TextInput name="port" type="number" placeholder="Port" />
|
<TextInput name="port" type="number" placeholder="Port" />
|
||||||
<Checkbox name="tls" label="SSL" onChange={this.handleSSLChange} />
|
<Checkbox
|
||||||
|
name="tls"
|
||||||
|
label="SSL"
|
||||||
|
topLabel
|
||||||
|
onChange={this.handleSSLChange}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Error name="host" />
|
<Error name="host" />
|
||||||
<Error name="port" />
|
<Error name="port" />
|
||||||
|
@ -1,32 +1,56 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Navicon from 'containers/Navicon';
|
import Navicon from 'containers/Navicon';
|
||||||
|
import Checkbox from 'components/ui/Checkbox';
|
||||||
import FileInput from 'components/ui/FileInput';
|
import FileInput from 'components/ui/FileInput';
|
||||||
|
|
||||||
const Settings = ({ settings, onCertChange, onKeyChange, uploadCert }) => {
|
const Settings = ({
|
||||||
|
settings,
|
||||||
|
setSetting,
|
||||||
|
onCertChange,
|
||||||
|
onKeyChange,
|
||||||
|
uploadCert
|
||||||
|
}) => {
|
||||||
const status = settings.uploadingCert ? 'Uploading...' : 'Upload';
|
const status = settings.uploadingCert ? 'Uploading...' : 'Upload';
|
||||||
const error = settings.certError;
|
const error = settings.certError;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="settings">
|
<div className="settings-container">
|
||||||
<Navicon />
|
<div className="settings">
|
||||||
<h1>Settings</h1>
|
<Navicon />
|
||||||
<h2>Client Certificate</h2>
|
<h1>Settings</h1>
|
||||||
<div>
|
<div className="settings-section">
|
||||||
<p>Certificate</p>
|
<h2>Visuals</h2>
|
||||||
<FileInput
|
<Checkbox
|
||||||
name={settings.certFile || 'Select Certificate'}
|
name="coloredNicks"
|
||||||
onChange={onCertChange}
|
label="Colored nicks"
|
||||||
/>
|
checked={settings.coloredNicks}
|
||||||
|
onChange={e => setSetting('coloredNicks', e.target.checked)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="settings-section">
|
||||||
|
<h2>Client Certificate</h2>
|
||||||
|
<div className="settings-cert">
|
||||||
|
<div className="settings-file">
|
||||||
|
<p>Certificate</p>
|
||||||
|
<FileInput
|
||||||
|
name={settings.certFile || 'Select Certificate'}
|
||||||
|
onChange={onCertChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="settings-file">
|
||||||
|
<p>Private Key</p>
|
||||||
|
<FileInput
|
||||||
|
name={settings.keyFile || 'Select Key'}
|
||||||
|
onChange={onKeyChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button className="settings-button" onClick={uploadCert}>
|
||||||
|
{status}
|
||||||
|
</button>
|
||||||
|
{error ? <p className="error">{error}</p> : null}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<p>Private Key</p>
|
|
||||||
<FileInput
|
|
||||||
name={settings.keyFile || 'Select Key'}
|
|
||||||
onChange={onKeyChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<button onClick={uploadCert}>{status}</button>
|
|
||||||
{error ? <p className="error">{error}</p> : null}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,30 +1,18 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Field } from 'formik';
|
import classnames from 'classnames';
|
||||||
|
|
||||||
const Checkbox = ({ name, label, onChange, ...props }) => (
|
const Checkbox = ({ name, label, topLabel, ...props }) => (
|
||||||
<Field
|
<label
|
||||||
name={name}
|
className={classnames('checkbox', {
|
||||||
render={({ field, form }) => (
|
'top-label': topLabel
|
||||||
<label htmlFor={name}>
|
})}
|
||||||
{label && <div>{label}</div>}
|
htmlFor={name}
|
||||||
<input
|
>
|
||||||
type="checkbox"
|
{topLabel && label}
|
||||||
id={name}
|
<input type="checkbox" id={name} name={name} {...props} />
|
||||||
name={name}
|
<span />
|
||||||
checked={field.value}
|
{!topLabel && label}
|
||||||
onChange={e => {
|
</label>
|
||||||
form.setFieldTouched(name, true);
|
|
||||||
field.onChange(e);
|
|
||||||
if (onChange) {
|
|
||||||
onChange(e);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
<span />
|
|
||||||
</label>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
export default Checkbox;
|
export default Checkbox;
|
||||||
|
25
client/src/js/components/ui/formik/Checkbox.js
Normal file
25
client/src/js/components/ui/formik/Checkbox.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Field } from 'formik';
|
||||||
|
import Checkbox from 'components/ui/Checkbox';
|
||||||
|
|
||||||
|
const FormikCheckbox = ({ name, onChange, ...props }) => (
|
||||||
|
<Field
|
||||||
|
name={name}
|
||||||
|
render={({ field, form }) => (
|
||||||
|
<Checkbox
|
||||||
|
name={name}
|
||||||
|
checked={field.value}
|
||||||
|
onChange={e => {
|
||||||
|
form.setFieldTouched(name, true);
|
||||||
|
field.onChange(e);
|
||||||
|
if (onChange) {
|
||||||
|
onChange(e);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default FormikCheckbox;
|
0
client/src/js/components/ui/formik/TextInput.js
Normal file
0
client/src/js/components/ui/formik/TextInput.js
Normal file
@ -32,6 +32,7 @@ import {
|
|||||||
setNick,
|
setNick,
|
||||||
setServerName
|
setServerName
|
||||||
} from 'state/servers';
|
} from 'state/servers';
|
||||||
|
import { getSettings } from 'state/settings';
|
||||||
import { getSelectedTab, select } from 'state/tab';
|
import { getSelectedTab, select } from 'state/tab';
|
||||||
import { getShowUserList, toggleUserList } from 'state/ui';
|
import { getShowUserList, toggleUserList } from 'state/ui';
|
||||||
|
|
||||||
@ -46,7 +47,8 @@ const mapState = createStructuredSelector({
|
|||||||
status: getCurrentServerStatus,
|
status: getCurrentServerStatus,
|
||||||
tab: getSelectedTab,
|
tab: getSelectedTab,
|
||||||
title: getSelectedTabTitle,
|
title: getSelectedTabTitle,
|
||||||
users: getSelectedChannelUsers
|
users: getSelectedChannelUsers,
|
||||||
|
coloredNicks: state => getSettings(state).coloredNicks
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatch = dispatch => ({
|
const mapDispatch = dispatch => ({
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createStructuredSelector } from 'reselect';
|
import { createStructuredSelector } from 'reselect';
|
||||||
import Settings from 'components/pages/Settings';
|
import Settings from 'components/pages/Settings';
|
||||||
import { getSettings, setCert, setKey, uploadCert } from 'state/settings';
|
import {
|
||||||
|
getSettings,
|
||||||
|
setSetting,
|
||||||
|
setCert,
|
||||||
|
setKey,
|
||||||
|
uploadCert
|
||||||
|
} from 'state/settings';
|
||||||
|
|
||||||
const mapState = createStructuredSelector({
|
const mapState = createStructuredSelector({
|
||||||
settings: getSettings
|
settings: getSettings
|
||||||
@ -10,7 +16,8 @@ const mapState = createStructuredSelector({
|
|||||||
const mapDispatch = {
|
const mapDispatch = {
|
||||||
onCertChange: setCert,
|
onCertChange: setCert,
|
||||||
onKeyChange: setKey,
|
onKeyChange: setKey,
|
||||||
uploadCert
|
uploadCert,
|
||||||
|
setSetting
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
|
@ -2,6 +2,7 @@ import Cookie from 'js-cookie';
|
|||||||
import { socket as socketActions } from 'state/actions';
|
import { socket as socketActions } from 'state/actions';
|
||||||
import { getWrapWidth, setConnectDefaults, appSet } from 'state/app';
|
import { getWrapWidth, setConnectDefaults, appSet } from 'state/app';
|
||||||
import { addMessages } from 'state/messages';
|
import { addMessages } from 'state/messages';
|
||||||
|
import { setSettings } from 'state/settings';
|
||||||
import { select, updateSelection } from 'state/tab';
|
import { select, updateSelection } from 'state/tab';
|
||||||
import { find } from 'utils';
|
import { find } from 'utils';
|
||||||
import { when } from 'utils/observe';
|
import { when } from 'utils/observe';
|
||||||
@ -12,6 +13,7 @@ export default function initialState({ store }) {
|
|||||||
|
|
||||||
store.dispatch(setConnectDefaults(env.defaults));
|
store.dispatch(setConnectDefaults(env.defaults));
|
||||||
store.dispatch(appSet('hexIP', env.hexIP));
|
store.dispatch(appSet('hexIP', env.hexIP));
|
||||||
|
store.dispatch(setSettings(env.settings, true));
|
||||||
|
|
||||||
if (env.servers) {
|
if (env.servers) {
|
||||||
store.dispatch({
|
store.dispatch({
|
||||||
|
@ -37,6 +37,7 @@ export const SET_CERT = 'SET_CERT';
|
|||||||
export const SET_CERT_ERROR = 'SET_CERT_ERROR';
|
export const SET_CERT_ERROR = 'SET_CERT_ERROR';
|
||||||
export const SET_KEY = 'SET_KEY';
|
export const SET_KEY = 'SET_KEY';
|
||||||
export const UPLOAD_CERT = 'UPLOAD_CERT';
|
export const UPLOAD_CERT = 'UPLOAD_CERT';
|
||||||
|
export const SETTINGS_SET = 'SETTINGS_SET';
|
||||||
|
|
||||||
export const SELECT_TAB = 'SELECT_TAB';
|
export const SELECT_TAB = 'SELECT_TAB';
|
||||||
|
|
||||||
|
@ -200,8 +200,8 @@ export function setServerName(name, server) {
|
|||||||
server
|
server
|
||||||
},
|
},
|
||||||
debounce: {
|
debounce: {
|
||||||
delay: 1000,
|
delay: 500,
|
||||||
key: server
|
key: `server_name:${server}`
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import assign from 'lodash/assign';
|
||||||
import createReducer from 'utils/createReducer';
|
import createReducer from 'utils/createReducer';
|
||||||
import * as actions from './actions';
|
import * as actions from './actions';
|
||||||
|
|
||||||
@ -36,6 +37,14 @@ export default createReducer(
|
|||||||
[actions.SET_KEY](state, action) {
|
[actions.SET_KEY](state, action) {
|
||||||
state.keyFile = action.fileName;
|
state.keyFile = action.fileName;
|
||||||
state.key = action.key;
|
state.key = action.key;
|
||||||
|
},
|
||||||
|
|
||||||
|
[actions.SETTINGS_SET](state, { key, value, settings }) {
|
||||||
|
if (settings) {
|
||||||
|
assign(state, settings);
|
||||||
|
} else {
|
||||||
|
state[key] = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -82,3 +91,37 @@ export function setKey(fileName, key) {
|
|||||||
key: key
|
key: key
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setSetting(key, value) {
|
||||||
|
return {
|
||||||
|
type: actions.SETTINGS_SET,
|
||||||
|
key,
|
||||||
|
value,
|
||||||
|
socket: {
|
||||||
|
type: 'settings_set',
|
||||||
|
data: {
|
||||||
|
[key]: value
|
||||||
|
},
|
||||||
|
debounce: {
|
||||||
|
delay: 250,
|
||||||
|
key: `settings:${key}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setSettings(settings, local = false) {
|
||||||
|
const action = {
|
||||||
|
type: actions.SETTINGS_SET,
|
||||||
|
settings
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!local) {
|
||||||
|
action.socket = {
|
||||||
|
type: 'settings_set',
|
||||||
|
data: settings
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
@ -27,6 +27,8 @@ type indexData struct {
|
|||||||
Channels []*storage.Channel
|
Channels []*storage.Channel
|
||||||
HexIP bool
|
HexIP bool
|
||||||
|
|
||||||
|
Settings *storage.ClientSettings
|
||||||
|
|
||||||
// Users in the selected channel
|
// Users in the selected channel
|
||||||
Users *Userlist
|
Users *Userlist
|
||||||
|
|
||||||
@ -54,6 +56,8 @@ func getIndexData(r *http.Request, state *State) *indexData {
|
|||||||
return &data
|
return &data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data.Settings = state.user.GetClientSettings()
|
||||||
|
|
||||||
servers, err := state.user.GetServers()
|
servers, err := state.user.GetServers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
|
@ -99,6 +99,16 @@ func easyjson7e607aefDecodeGithubComKhliengDispatchServer(in *jlexer.Lexer, out
|
|||||||
}
|
}
|
||||||
case "hexIP":
|
case "hexIP":
|
||||||
out.HexIP = bool(in.Bool())
|
out.HexIP = bool(in.Bool())
|
||||||
|
case "settings":
|
||||||
|
if in.IsNull() {
|
||||||
|
in.Skip()
|
||||||
|
out.Settings = nil
|
||||||
|
} else {
|
||||||
|
if out.Settings == nil {
|
||||||
|
out.Settings = new(storage.ClientSettings)
|
||||||
|
}
|
||||||
|
easyjson7e607aefDecodeGithubComKhliengDispatchStorage1(in, &*out.Settings)
|
||||||
|
}
|
||||||
case "users":
|
case "users":
|
||||||
if in.IsNull() {
|
if in.IsNull() {
|
||||||
in.Skip()
|
in.Skip()
|
||||||
@ -199,6 +209,16 @@ func easyjson7e607aefEncodeGithubComKhliengDispatchServer(out *jwriter.Writer, i
|
|||||||
}
|
}
|
||||||
out.Bool(bool(in.HexIP))
|
out.Bool(bool(in.HexIP))
|
||||||
}
|
}
|
||||||
|
if in.Settings != nil {
|
||||||
|
const prefix string = ",\"settings\":"
|
||||||
|
if first {
|
||||||
|
first = false
|
||||||
|
out.RawString(prefix[1:])
|
||||||
|
} else {
|
||||||
|
out.RawString(prefix)
|
||||||
|
}
|
||||||
|
easyjson7e607aefEncodeGithubComKhliengDispatchStorage1(out, *in.Settings)
|
||||||
|
}
|
||||||
if in.Users != nil {
|
if in.Users != nil {
|
||||||
const prefix string = ",\"users\":"
|
const prefix string = ",\"users\":"
|
||||||
if first {
|
if first {
|
||||||
@ -245,6 +265,53 @@ func (v *indexData) UnmarshalJSON(data []byte) error {
|
|||||||
func (v *indexData) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
func (v *indexData) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
||||||
easyjson7e607aefDecodeGithubComKhliengDispatchServer(l, v)
|
easyjson7e607aefDecodeGithubComKhliengDispatchServer(l, v)
|
||||||
}
|
}
|
||||||
|
func easyjson7e607aefDecodeGithubComKhliengDispatchStorage1(in *jlexer.Lexer, out *storage.ClientSettings) {
|
||||||
|
isTopLevel := in.IsStart()
|
||||||
|
if in.IsNull() {
|
||||||
|
if isTopLevel {
|
||||||
|
in.Consumed()
|
||||||
|
}
|
||||||
|
in.Skip()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
in.Delim('{')
|
||||||
|
for !in.IsDelim('}') {
|
||||||
|
key := in.UnsafeString()
|
||||||
|
in.WantColon()
|
||||||
|
if in.IsNull() {
|
||||||
|
in.Skip()
|
||||||
|
in.WantComma()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch key {
|
||||||
|
case "coloredNicks":
|
||||||
|
out.ColoredNicks = bool(in.Bool())
|
||||||
|
default:
|
||||||
|
in.SkipRecursive()
|
||||||
|
}
|
||||||
|
in.WantComma()
|
||||||
|
}
|
||||||
|
in.Delim('}')
|
||||||
|
if isTopLevel {
|
||||||
|
in.Consumed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func easyjson7e607aefEncodeGithubComKhliengDispatchStorage1(out *jwriter.Writer, in storage.ClientSettings) {
|
||||||
|
out.RawByte('{')
|
||||||
|
first := true
|
||||||
|
_ = first
|
||||||
|
if in.ColoredNicks {
|
||||||
|
const prefix string = ",\"coloredNicks\":"
|
||||||
|
if first {
|
||||||
|
first = false
|
||||||
|
out.RawString(prefix[1:])
|
||||||
|
} else {
|
||||||
|
out.RawString(prefix)
|
||||||
|
}
|
||||||
|
out.Bool(bool(in.ColoredNicks))
|
||||||
|
}
|
||||||
|
out.RawByte('}')
|
||||||
|
}
|
||||||
func easyjson7e607aefDecodeGithubComKhliengDispatchStorage(in *jlexer.Lexer, out *storage.Channel) {
|
func easyjson7e607aefDecodeGithubComKhliengDispatchStorage(in *jlexer.Lexer, out *storage.Channel) {
|
||||||
isTopLevel := in.IsStart()
|
isTopLevel := in.IsStart()
|
||||||
if in.IsNull() {
|
if in.IsNull() {
|
||||||
|
@ -274,6 +274,13 @@ func (h *wsHandler) setServerName(b []byte) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *wsHandler) setSettings(b []byte) {
|
||||||
|
err := h.state.user.UnmarshalClientSettingsJSON(b)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (h *wsHandler) initHandlers() {
|
func (h *wsHandler) initHandlers() {
|
||||||
h.handlers = map[string]func([]byte){
|
h.handlers = map[string]func([]byte){
|
||||||
"connect": h.connect,
|
"connect": h.connect,
|
||||||
@ -293,6 +300,7 @@ func (h *wsHandler) initHandlers() {
|
|||||||
"cert": h.cert,
|
"cert": h.cert,
|
||||||
"fetch_messages": h.fetchMessages,
|
"fetch_messages": h.fetchMessages,
|
||||||
"set_server_name": h.setServerName,
|
"set_server_name": h.setServerName,
|
||||||
|
"settings_set": h.setSettings,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
struct User {
|
struct User {
|
||||||
ID uint64
|
ID uint64
|
||||||
Username string
|
Username string
|
||||||
lastIP []byte
|
clientSettings *ClientSettings
|
||||||
|
lastIP []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ClientSettings {
|
||||||
|
ColoredNicks bool
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Server {
|
struct Server {
|
||||||
|
@ -29,6 +29,15 @@ func (d *User) Size() (s uint64) {
|
|||||||
}
|
}
|
||||||
s += l
|
s += l
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
if d.clientSettings != nil {
|
||||||
|
|
||||||
|
{
|
||||||
|
s += (*d.clientSettings).Size()
|
||||||
|
}
|
||||||
|
s += 0
|
||||||
|
}
|
||||||
|
}
|
||||||
{
|
{
|
||||||
l := uint64(len(d.lastIP))
|
l := uint64(len(d.lastIP))
|
||||||
|
|
||||||
@ -44,7 +53,7 @@ func (d *User) Size() (s uint64) {
|
|||||||
}
|
}
|
||||||
s += l
|
s += l
|
||||||
}
|
}
|
||||||
s += 8
|
s += 9
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (d *User) Marshal(buf []byte) ([]byte, error) {
|
func (d *User) Marshal(buf []byte) ([]byte, error) {
|
||||||
@ -82,6 +91,22 @@ func (d *User) Marshal(buf []byte) ([]byte, error) {
|
|||||||
copy(buf[i+8:], d.Username)
|
copy(buf[i+8:], d.Username)
|
||||||
i += l
|
i += l
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
if d.clientSettings == nil {
|
||||||
|
buf[i+8] = 0
|
||||||
|
} else {
|
||||||
|
buf[i+8] = 1
|
||||||
|
|
||||||
|
{
|
||||||
|
nbuf, err := (*d.clientSettings).Marshal(buf[i+9:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
i += uint64(len(nbuf))
|
||||||
|
}
|
||||||
|
i += 0
|
||||||
|
}
|
||||||
|
}
|
||||||
{
|
{
|
||||||
l := uint64(len(d.lastIP))
|
l := uint64(len(d.lastIP))
|
||||||
|
|
||||||
@ -90,18 +115,18 @@ func (d *User) Marshal(buf []byte) ([]byte, error) {
|
|||||||
t := uint64(l)
|
t := uint64(l)
|
||||||
|
|
||||||
for t >= 0x80 {
|
for t >= 0x80 {
|
||||||
buf[i+8] = byte(t) | 0x80
|
buf[i+9] = byte(t) | 0x80
|
||||||
t >>= 7
|
t >>= 7
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
buf[i+8] = byte(t)
|
buf[i+9] = byte(t)
|
||||||
i++
|
i++
|
||||||
|
|
||||||
}
|
}
|
||||||
copy(buf[i+8:], d.lastIP)
|
copy(buf[i+9:], d.lastIP)
|
||||||
i += l
|
i += l
|
||||||
}
|
}
|
||||||
return buf[:i+8], nil
|
return buf[:i+9], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *User) Unmarshal(buf []byte) (uint64, error) {
|
func (d *User) Unmarshal(buf []byte) (uint64, error) {
|
||||||
@ -132,16 +157,34 @@ func (d *User) Unmarshal(buf []byte) (uint64, error) {
|
|||||||
d.Username = string(buf[i+8 : i+8+l])
|
d.Username = string(buf[i+8 : i+8+l])
|
||||||
i += l
|
i += l
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
if buf[i+8] == 1 {
|
||||||
|
if d.clientSettings == nil {
|
||||||
|
d.clientSettings = new(ClientSettings)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ni, err := (*d.clientSettings).Unmarshal(buf[i+9:])
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
i += ni
|
||||||
|
}
|
||||||
|
i += 0
|
||||||
|
} else {
|
||||||
|
d.clientSettings = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
{
|
{
|
||||||
l := uint64(0)
|
l := uint64(0)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
bs := uint8(7)
|
bs := uint8(7)
|
||||||
t := uint64(buf[i+8] & 0x7F)
|
t := uint64(buf[i+9] & 0x7F)
|
||||||
for buf[i+8]&0x80 == 0x80 {
|
for buf[i+9]&0x80 == 0x80 {
|
||||||
i++
|
i++
|
||||||
t |= uint64(buf[i+8]&0x7F) << bs
|
t |= uint64(buf[i+9]&0x7F) << bs
|
||||||
bs += 7
|
bs += 7
|
||||||
}
|
}
|
||||||
i++
|
i++
|
||||||
@ -154,10 +197,45 @@ func (d *User) Unmarshal(buf []byte) (uint64, error) {
|
|||||||
} else {
|
} else {
|
||||||
d.lastIP = make([]byte, l)
|
d.lastIP = make([]byte, l)
|
||||||
}
|
}
|
||||||
copy(d.lastIP, buf[i+8:])
|
copy(d.lastIP, buf[i+9:])
|
||||||
i += l
|
i += l
|
||||||
}
|
}
|
||||||
return i + 8, nil
|
return i + 9, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ClientSettings) Size() (s uint64) {
|
||||||
|
|
||||||
|
s += 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
func (d *ClientSettings) Marshal(buf []byte) ([]byte, error) {
|
||||||
|
size := d.Size()
|
||||||
|
{
|
||||||
|
if uint64(cap(buf)) >= size {
|
||||||
|
buf = buf[:size]
|
||||||
|
} else {
|
||||||
|
buf = make([]byte, size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i := uint64(0)
|
||||||
|
|
||||||
|
{
|
||||||
|
if d.ColoredNicks {
|
||||||
|
buf[0] = 1
|
||||||
|
} else {
|
||||||
|
buf[0] = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf[:i+1], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *ClientSettings) Unmarshal(buf []byte) (uint64, error) {
|
||||||
|
i := uint64(0)
|
||||||
|
|
||||||
|
{
|
||||||
|
d.ColoredNicks = buf[0] == 1
|
||||||
|
}
|
||||||
|
return i + 1, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Server) Size() (s uint64) {
|
func (d *Server) Size() (s uint64) {
|
||||||
|
@ -12,16 +12,20 @@ type User struct {
|
|||||||
IDBytes []byte
|
IDBytes []byte
|
||||||
Username string
|
Username string
|
||||||
|
|
||||||
store Store
|
store Store
|
||||||
messageLog MessageStore
|
messageLog MessageStore
|
||||||
messageIndex MessageSearchProvider
|
messageIndex MessageSearchProvider
|
||||||
lastIP []byte
|
clientSettings *ClientSettings
|
||||||
certificate *tls.Certificate
|
lastIP []byte
|
||||||
lock sync.Mutex
|
certificate *tls.Certificate
|
||||||
|
lock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUser(store Store) (*User, error) {
|
func NewUser(store Store) (*User, error) {
|
||||||
user := &User{store: store}
|
user := &User{
|
||||||
|
store: store,
|
||||||
|
clientSettings: DefaultClientSettings(),
|
||||||
|
}
|
||||||
|
|
||||||
err := store.SaveUser(user)
|
err := store.SaveUser(user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -84,6 +88,44 @@ func (u *User) SetLastIP(ip []byte) error {
|
|||||||
return u.store.SaveUser(u)
|
return u.store.SaveUser(u)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//easyjson:json
|
||||||
|
type ClientSettings struct {
|
||||||
|
ColoredNicks bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultClientSettings() *ClientSettings {
|
||||||
|
return &ClientSettings{
|
||||||
|
ColoredNicks: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) GetClientSettings() *ClientSettings {
|
||||||
|
u.lock.Lock()
|
||||||
|
settings := *u.clientSettings
|
||||||
|
u.lock.Unlock()
|
||||||
|
return &settings
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) SetClientSettings(settings *ClientSettings) error {
|
||||||
|
u.lock.Lock()
|
||||||
|
u.clientSettings = settings
|
||||||
|
u.lock.Unlock()
|
||||||
|
|
||||||
|
return u.store.SaveUser(u)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) UnmarshalClientSettingsJSON(b []byte) error {
|
||||||
|
u.lock.Lock()
|
||||||
|
err := u.clientSettings.UnmarshalJSON(b)
|
||||||
|
u.lock.Unlock()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return u.store.SaveUser(u)
|
||||||
|
}
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
Name string
|
Name string
|
||||||
Host string
|
Host string
|
||||||
|
90
storage/user_easyjson.go
Normal file
90
storage/user_easyjson.go
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
|
||||||
|
|
||||||
|
package storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
json "encoding/json"
|
||||||
|
easyjson "github.com/mailru/easyjson"
|
||||||
|
jlexer "github.com/mailru/easyjson/jlexer"
|
||||||
|
jwriter "github.com/mailru/easyjson/jwriter"
|
||||||
|
)
|
||||||
|
|
||||||
|
// suppress unused package warning
|
||||||
|
var (
|
||||||
|
_ *json.RawMessage
|
||||||
|
_ *jlexer.Lexer
|
||||||
|
_ *jwriter.Writer
|
||||||
|
_ easyjson.Marshaler
|
||||||
|
)
|
||||||
|
|
||||||
|
func easyjson9e1087fdDecodeGithubComKhliengDispatchStorage(in *jlexer.Lexer, out *ClientSettings) {
|
||||||
|
isTopLevel := in.IsStart()
|
||||||
|
if in.IsNull() {
|
||||||
|
if isTopLevel {
|
||||||
|
in.Consumed()
|
||||||
|
}
|
||||||
|
in.Skip()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
in.Delim('{')
|
||||||
|
for !in.IsDelim('}') {
|
||||||
|
key := in.UnsafeString()
|
||||||
|
in.WantColon()
|
||||||
|
if in.IsNull() {
|
||||||
|
in.Skip()
|
||||||
|
in.WantComma()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch key {
|
||||||
|
case "coloredNicks":
|
||||||
|
out.ColoredNicks = bool(in.Bool())
|
||||||
|
default:
|
||||||
|
in.SkipRecursive()
|
||||||
|
}
|
||||||
|
in.WantComma()
|
||||||
|
}
|
||||||
|
in.Delim('}')
|
||||||
|
if isTopLevel {
|
||||||
|
in.Consumed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func easyjson9e1087fdEncodeGithubComKhliengDispatchStorage(out *jwriter.Writer, in ClientSettings) {
|
||||||
|
out.RawByte('{')
|
||||||
|
first := true
|
||||||
|
_ = first
|
||||||
|
if in.ColoredNicks {
|
||||||
|
const prefix string = ",\"coloredNicks\":"
|
||||||
|
if first {
|
||||||
|
first = false
|
||||||
|
out.RawString(prefix[1:])
|
||||||
|
} else {
|
||||||
|
out.RawString(prefix)
|
||||||
|
}
|
||||||
|
out.Bool(bool(in.ColoredNicks))
|
||||||
|
}
|
||||||
|
out.RawByte('}')
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON supports json.Marshaler interface
|
||||||
|
func (v ClientSettings) MarshalJSON() ([]byte, error) {
|
||||||
|
w := jwriter.Writer{}
|
||||||
|
easyjson9e1087fdEncodeGithubComKhliengDispatchStorage(&w, v)
|
||||||
|
return w.Buffer.BuildBytes(), w.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalEasyJSON supports easyjson.Marshaler interface
|
||||||
|
func (v ClientSettings) MarshalEasyJSON(w *jwriter.Writer) {
|
||||||
|
easyjson9e1087fdEncodeGithubComKhliengDispatchStorage(w, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON supports json.Unmarshaler interface
|
||||||
|
func (v *ClientSettings) UnmarshalJSON(data []byte) error {
|
||||||
|
r := jlexer.Lexer{Data: data}
|
||||||
|
easyjson9e1087fdDecodeGithubComKhliengDispatchStorage(&r, v)
|
||||||
|
return r.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
|
||||||
|
func (v *ClientSettings) UnmarshalEasyJSON(l *jlexer.Lexer) {
|
||||||
|
easyjson9e1087fdDecodeGithubComKhliengDispatchStorage(l, v)
|
||||||
|
}
|
@ -80,6 +80,16 @@ func TestUser(t *testing.T) {
|
|||||||
channels, err = user.GetChannels()
|
channels, err = user.GetChannels()
|
||||||
assert.Len(t, channels, 0)
|
assert.Len(t, channels, 0)
|
||||||
|
|
||||||
|
settings := user.GetClientSettings()
|
||||||
|
assert.NotNil(t, settings)
|
||||||
|
assert.Equal(t, storage.DefaultClientSettings(), settings)
|
||||||
|
|
||||||
|
settings.ColoredNicks = !settings.ColoredNicks
|
||||||
|
err = user.SetClientSettings(settings)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, settings, user.GetClientSettings())
|
||||||
|
assert.NotEqual(t, settings, storage.DefaultClientSettings())
|
||||||
|
|
||||||
user.Remove()
|
user.Remove()
|
||||||
_, err = os.Stat(storage.Path.User(user.Username))
|
_, err = os.Stat(storage.Path.User(user.Username))
|
||||||
assert.True(t, os.IsNotExist(err))
|
assert.True(t, os.IsNotExist(err))
|
||||||
|
Loading…
Reference in New Issue
Block a user