mirror of
https://codeberg.org/emersion/gamja
synced 2025-03-13 07:48:37 +01:00
Add a settings dialog
Add an option to hide chat events or always expand them. Closes: https://todo.sr.ht/~emersion/gamja/73
This commit is contained in:
parent
e3c2d85a94
commit
baaf576d82
@ -11,12 +11,13 @@ import NetworkForm from "./network-form.js";
|
|||||||
import AuthForm from "./auth-form.js";
|
import AuthForm from "./auth-form.js";
|
||||||
import RegisterForm from "./register-form.js";
|
import RegisterForm from "./register-form.js";
|
||||||
import VerifyForm from "./verify-form.js";
|
import VerifyForm from "./verify-form.js";
|
||||||
|
import SettingsForm from "./settings-form.js";
|
||||||
import Composer from "./composer.js";
|
import Composer from "./composer.js";
|
||||||
import ScrollManager from "./scroll-manager.js";
|
import ScrollManager from "./scroll-manager.js";
|
||||||
import Dialog from "./dialog.js";
|
import Dialog from "./dialog.js";
|
||||||
import { html, Component, createRef } from "../lib/index.js";
|
import { html, Component, createRef } from "../lib/index.js";
|
||||||
import { strip as stripANSI } from "../lib/ansi.js";
|
import { strip as stripANSI } from "../lib/ansi.js";
|
||||||
import { SERVER_BUFFER, BufferType, ReceiptType, ServerStatus, Unread, State, getServerName, receiptFromMessage, isReceiptBefore, isMessageBeforeReceipt } from "../state.js";
|
import { SERVER_BUFFER, BufferType, ReceiptType, ServerStatus, Unread, BufferEventsDisplayMode, State, getServerName, receiptFromMessage, isReceiptBefore, isMessageBeforeReceipt } from "../state.js";
|
||||||
import commands from "../commands.js";
|
import commands from "../commands.js";
|
||||||
import { setup as setupKeybindings } from "../keybindings.js";
|
import { setup as setupKeybindings } from "../keybindings.js";
|
||||||
import * as store from "../store.js";
|
import * as store from "../store.js";
|
||||||
@ -221,6 +222,13 @@ export default class App extends Component {
|
|||||||
this.handleRegisterSubmit = this.handleRegisterSubmit.bind(this);
|
this.handleRegisterSubmit = this.handleRegisterSubmit.bind(this);
|
||||||
this.handleVerifyClick = this.handleVerifyClick.bind(this);
|
this.handleVerifyClick = this.handleVerifyClick.bind(this);
|
||||||
this.handleVerifySubmit = this.handleVerifySubmit.bind(this);
|
this.handleVerifySubmit = this.handleVerifySubmit.bind(this);
|
||||||
|
this.handleOpenSettingsClick = this.handleOpenSettingsClick.bind(this);
|
||||||
|
this.handleSettingsChange = this.handleSettingsChange.bind(this);
|
||||||
|
|
||||||
|
this.state.settings = {
|
||||||
|
...this.state.settings,
|
||||||
|
...store.settings.load(),
|
||||||
|
};
|
||||||
|
|
||||||
this.bufferStore = new store.Buffer();
|
this.bufferStore = new store.Buffer();
|
||||||
|
|
||||||
@ -632,7 +640,10 @@ export default class App extends Component {
|
|||||||
});
|
});
|
||||||
this.setState({ connectParams: params });
|
this.setState({ connectParams: params });
|
||||||
|
|
||||||
let client = new Client(fillConnectParams(params));
|
let client = new Client({
|
||||||
|
...fillConnectParams(params),
|
||||||
|
eventPlayback: this.state.settings.bufferEvents !== BufferEventsDisplayMode.HIDE,
|
||||||
|
});
|
||||||
client.debug = this.debug;
|
client.debug = this.debug;
|
||||||
|
|
||||||
this.clients.set(serverID, client);
|
this.clients.set(serverID, client);
|
||||||
@ -1321,6 +1332,10 @@ export default class App extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
disconnectAll() {
|
||||||
|
this.close(this.state.buffers.keys().next().value);
|
||||||
|
}
|
||||||
|
|
||||||
executeCommand(s) {
|
executeCommand(s) {
|
||||||
let parts = s.split(" ");
|
let parts = s.split(" ");
|
||||||
let name = parts[0].toLowerCase().slice(1);
|
let name = parts[0].toLowerCase().slice(1);
|
||||||
@ -1681,6 +1696,15 @@ export default class App extends Component {
|
|||||||
this.dismissDialog();
|
this.dismissDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleOpenSettingsClick() {
|
||||||
|
this.openDialog("settings");
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSettingsChange(settings) {
|
||||||
|
store.settings.put(settings);
|
||||||
|
this.setState({ settings });
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.baseTitle = document.title;
|
this.baseTitle = document.title;
|
||||||
setupKeybindings(this);
|
setupKeybindings(this);
|
||||||
@ -1742,6 +1766,7 @@ export default class App extends Component {
|
|||||||
onReconnect=${() => this.reconnect()}
|
onReconnect=${() => this.reconnect()}
|
||||||
onAddNetwork=${this.handleAddNetworkClick}
|
onAddNetwork=${this.handleAddNetworkClick}
|
||||||
onManageNetwork=${() => this.handleManageNetworkClick(activeBuffer.server)}
|
onManageNetwork=${() => this.handleManageNetworkClick(activeBuffer.server)}
|
||||||
|
onOpenSettings=${this.handleOpenSettingsClick}
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
`;
|
`;
|
||||||
@ -1850,6 +1875,18 @@ export default class App extends Component {
|
|||||||
</>
|
</>
|
||||||
`;
|
`;
|
||||||
break;
|
break;
|
||||||
|
case "settings":
|
||||||
|
dialog = html`
|
||||||
|
<${Dialog} title="Settings" onDismiss=${this.dismissDialog}>
|
||||||
|
<${SettingsForm}
|
||||||
|
settings=${this.state.settings}
|
||||||
|
onChange=${this.handleSettingsChange}
|
||||||
|
onDisconnect=${() => this.disconnectAll()}
|
||||||
|
onClose=${() => this.dismissDialog()}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
`;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
let error = null;
|
let error = null;
|
||||||
@ -1906,6 +1943,7 @@ export default class App extends Component {
|
|||||||
buffer=${activeBuffer}
|
buffer=${activeBuffer}
|
||||||
server=${activeServer}
|
server=${activeServer}
|
||||||
bouncerNetwork=${activeBouncerNetwork}
|
bouncerNetwork=${activeBouncerNetwork}
|
||||||
|
settings=${this.state.settings}
|
||||||
onChannelClick=${this.handleChannelClick}
|
onChannelClick=${this.handleChannelClick}
|
||||||
onNickClick=${this.handleNickClick}
|
onNickClick=${this.handleNickClick}
|
||||||
onAuthClick=${() => this.handleAuthClick(activeBuffer.server)}
|
onAuthClick=${() => this.handleAuthClick(activeBuffer.server)}
|
||||||
|
@ -74,6 +74,12 @@ export default function BufferHeader(props) {
|
|||||||
onClick=${props.onReconnect}
|
onClick=${props.onReconnect}
|
||||||
>Reconnect</button>
|
>Reconnect</button>
|
||||||
`;
|
`;
|
||||||
|
let settingsButton = html`
|
||||||
|
<button
|
||||||
|
key="settings"
|
||||||
|
onClick="${props.onOpenSettings}"
|
||||||
|
>Settings</button>
|
||||||
|
`;
|
||||||
|
|
||||||
if (props.server.isBouncer) {
|
if (props.server.isBouncer) {
|
||||||
if (props.server.bouncerNetID) {
|
if (props.server.bouncerNetID) {
|
||||||
@ -99,27 +105,16 @@ export default function BufferHeader(props) {
|
|||||||
} else if (props.server.status === ServerStatus.DISCONNECTED) {
|
} else if (props.server.status === ServerStatus.DISCONNECTED) {
|
||||||
actions.push(reconnectButton);
|
actions.push(reconnectButton);
|
||||||
}
|
}
|
||||||
actions.push(html`
|
actions.push(settingsButton);
|
||||||
<button
|
|
||||||
key="disconnect"
|
|
||||||
class="danger"
|
|
||||||
onClick=${props.onClose}
|
|
||||||
>Disconnect</button>
|
|
||||||
`);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (fullyConnected) {
|
if (fullyConnected) {
|
||||||
actions.push(joinButton);
|
actions.push(joinButton);
|
||||||
|
actions.push(settingsButton);
|
||||||
} else if (props.server.status === ServerStatus.DISCONNECTED) {
|
} else if (props.server.status === ServerStatus.DISCONNECTED) {
|
||||||
actions.push(reconnectButton);
|
actions.push(reconnectButton);
|
||||||
}
|
}
|
||||||
actions.push(html`
|
actions.push(settingsButton);
|
||||||
<button
|
|
||||||
key="disconnect"
|
|
||||||
class="danger"
|
|
||||||
onClick=${props.onClose}
|
|
||||||
>Disconnect</button>
|
|
||||||
`);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BufferType.CHANNEL:
|
case BufferType.CHANNEL:
|
||||||
|
@ -2,7 +2,7 @@ import { html, Component } from "../lib/index.js";
|
|||||||
import linkify from "../lib/linkify.js";
|
import linkify from "../lib/linkify.js";
|
||||||
import * as irc from "../lib/irc.js";
|
import * as irc from "../lib/irc.js";
|
||||||
import { strip as stripANSI } from "../lib/ansi.js";
|
import { strip as stripANSI } from "../lib/ansi.js";
|
||||||
import { BufferType, ServerStatus, getNickURL, getChannelURL, getMessageURL, isMessageBeforeReceipt } from "../state.js";
|
import { BufferType, ServerStatus, BufferEventsDisplayMode, getNickURL, getChannelURL, getMessageURL, isMessageBeforeReceipt } from "../state.js";
|
||||||
import * as store from "../store.js";
|
import * as store from "../store.js";
|
||||||
import Membership from "./membership.js";
|
import Membership from "./membership.js";
|
||||||
|
|
||||||
@ -546,7 +546,8 @@ function sameDate(d1, d2) {
|
|||||||
|
|
||||||
export default class Buffer extends Component {
|
export default class Buffer extends Component {
|
||||||
shouldComponentUpdate(nextProps) {
|
shouldComponentUpdate(nextProps) {
|
||||||
return this.props.buffer !== nextProps.buffer;
|
return this.props.buffer !== nextProps.buffer ||
|
||||||
|
this.props.settings !== nextProps.settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -557,6 +558,7 @@ export default class Buffer extends Component {
|
|||||||
|
|
||||||
let server = this.props.server;
|
let server = this.props.server;
|
||||||
let bouncerNetwork = this.props.bouncerNetwork;
|
let bouncerNetwork = this.props.bouncerNetwork;
|
||||||
|
let settings = this.props.settings;
|
||||||
let serverName = server.name;
|
let serverName = server.name;
|
||||||
|
|
||||||
let children = [];
|
let children = [];
|
||||||
@ -633,6 +635,10 @@ export default class Buffer extends Component {
|
|||||||
buf.messages.forEach((msg) => {
|
buf.messages.forEach((msg) => {
|
||||||
let sep = [];
|
let sep = [];
|
||||||
|
|
||||||
|
if (settings.bufferEvents === BufferEventsDisplayMode.HIDE && canFoldMessage(msg)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!hasUnreadSeparator && buf.type != BufferType.SERVER && !isMessageBeforeReceipt(msg, buf.prevReadReceipt)) {
|
if (!hasUnreadSeparator && buf.type != BufferType.SERVER && !isMessageBeforeReceipt(msg, buf.prevReadReceipt)) {
|
||||||
sep.push(html`<${UnreadSeparator} key="unread"/>`);
|
sep.push(html`<${UnreadSeparator} key="unread"/>`);
|
||||||
hasUnreadSeparator = true;
|
hasUnreadSeparator = true;
|
||||||
@ -651,7 +657,7 @@ export default class Buffer extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: consider checking the time difference too
|
// TODO: consider checking the time difference too
|
||||||
if (canFoldMessage(msg)) {
|
if (settings.bufferEvents === BufferEventsDisplayMode.FOLD && canFoldMessage(msg)) {
|
||||||
foldMessages.push(msg);
|
foldMessages.push(msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
71
components/settings-form.js
Normal file
71
components/settings-form.js
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import { html, Component } from "../lib/index.js";
|
||||||
|
|
||||||
|
export default class SettingsForm extends Component {
|
||||||
|
state = {};
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state.bufferEvents = props.settings.bufferEvents;
|
||||||
|
|
||||||
|
this.handleChange = this.handleChange.bind(this);
|
||||||
|
this.handleSubmit = this.handleSubmit.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleChange(event) {
|
||||||
|
let target = event.target;
|
||||||
|
let value = target.type == "checkbox" ? target.checked : target.value;
|
||||||
|
this.setState({ [target.name]: value }, () => {
|
||||||
|
this.props.onChange(this.state);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSubmit(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.props.onClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`
|
||||||
|
<form onChange=${this.handleChange} onSubmit=${this.handleSubmit}>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="bufferEvents"
|
||||||
|
value="fold"
|
||||||
|
checked=${this.state.bufferEvents === "fold"}
|
||||||
|
/>
|
||||||
|
Show and fold chat events
|
||||||
|
</label>
|
||||||
|
<br/>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="bufferEvents"
|
||||||
|
value="expand"
|
||||||
|
checked=${this.state.bufferEvents === "expand"}
|
||||||
|
/>
|
||||||
|
Show and expand chat events
|
||||||
|
</label>
|
||||||
|
<br/>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="bufferEvents"
|
||||||
|
value="hide"
|
||||||
|
checked=${this.state.bufferEvents === "hide"}
|
||||||
|
/>
|
||||||
|
Hide chat events
|
||||||
|
</label>
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
<button type="button" class="danger" onClick=${() => this.props.onDisconnect()}>
|
||||||
|
Disconnect
|
||||||
|
</button>
|
||||||
|
<button>
|
||||||
|
Close
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
@ -19,7 +19,6 @@ const permanentCaps = [
|
|||||||
|
|
||||||
"draft/account-registration",
|
"draft/account-registration",
|
||||||
"draft/chathistory",
|
"draft/chathistory",
|
||||||
"draft/event-playback",
|
|
||||||
"draft/extended-monitor",
|
"draft/extended-monitor",
|
||||||
|
|
||||||
"soju.im/bouncer-networks",
|
"soju.im/bouncer-networks",
|
||||||
@ -124,6 +123,7 @@ export default class Client extends EventTarget {
|
|||||||
saslExternal: false,
|
saslExternal: false,
|
||||||
bouncerNetwork: null,
|
bouncerNetwork: null,
|
||||||
ping: 0,
|
ping: 0,
|
||||||
|
eventPlayback: true,
|
||||||
};
|
};
|
||||||
debug = false;
|
debug = false;
|
||||||
batches = new Map();
|
batches = new Map();
|
||||||
@ -624,6 +624,9 @@ export default class Client extends EventTarget {
|
|||||||
if (!this.params.bouncerNetwork) {
|
if (!this.params.bouncerNetwork) {
|
||||||
wantCaps.push("soju.im/bouncer-networks-notify");
|
wantCaps.push("soju.im/bouncer-networks-notify");
|
||||||
}
|
}
|
||||||
|
if (this.params.eventPlayback) {
|
||||||
|
wantCaps.push("draft/event-playback");
|
||||||
|
}
|
||||||
|
|
||||||
let msg = this.caps.requestAvailable(wantCaps);
|
let msg = this.caps.requestAvailable(wantCaps);
|
||||||
if (msg) {
|
if (msg) {
|
||||||
|
9
state.js
9
state.js
@ -34,6 +34,12 @@ export const ReceiptType = {
|
|||||||
READ: "read",
|
READ: "read",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const BufferEventsDisplayMode = {
|
||||||
|
FOLD: "fold",
|
||||||
|
EXPAND: "expand",
|
||||||
|
HIDE: "hide",
|
||||||
|
};
|
||||||
|
|
||||||
export function getNickURL(nick) {
|
export function getNickURL(nick) {
|
||||||
return "irc:///" + encodeURIComponent(nick) + ",isuser";
|
return "irc:///" + encodeURIComponent(nick) + ",isuser";
|
||||||
}
|
}
|
||||||
@ -209,6 +215,9 @@ export const State = {
|
|||||||
buffers: new Map(),
|
buffers: new Map(),
|
||||||
activeBuffer: null,
|
activeBuffer: null,
|
||||||
bouncerNetworks: new Map(),
|
bouncerNetworks: new Map(),
|
||||||
|
settings: {
|
||||||
|
bufferEvents: BufferEventsDisplayMode.FOLD,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
updateServer(state, id, updater) {
|
updateServer(state, id, updater) {
|
||||||
|
1
store.js
1
store.js
@ -26,6 +26,7 @@ class Item {
|
|||||||
|
|
||||||
export const autoconnect = new Item("autoconnect");
|
export const autoconnect = new Item("autoconnect");
|
||||||
export const naggedProtocolHandler = new Item("naggedProtocolHandler");
|
export const naggedProtocolHandler = new Item("naggedProtocolHandler");
|
||||||
|
export const settings = new Item("settings");
|
||||||
|
|
||||||
function debounce(f, delay) {
|
function debounce(f, delay) {
|
||||||
let timeout = null;
|
let timeout = null;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user