mami/src/mami.js/ui/settings.jsx
flash cf71bab92d Rewrote connection handling.
This has been in the works for over a month and might break things because it's a very radical change.
If it causes you to be unable to join chat, report it on the forum or try joining using the legacy chat on https://sockchat.flashii.net.
2024-04-17 15:42:50 +00:00

576 lines
20 KiB
JavaScript

#include animate.js
#include awaitable.js
#include common.js
#include emotes.js
#include utility.js
#include settings/backup.js
#include ui/baka.jsx
#include ui/emotes.js
#include ui/menus.js
#include ui/view.js
#include ui/youare.jsx
Umi.UI.Settings = (function() {
const items = [
{
name: 'interface',
title: 'Interface',
items: [
{
name: 'style',
title: 'Style',
type: 'select',
options: () => Umi.UI.View.AccentColours,
},
{
name: 'compactView',
title: 'Compact view',
type: 'checkbox',
},
{
name: 'autoScroll',
title: 'Scroll to latest message',
type: 'checkbox',
},
{
name: 'closeTabConfirm',
title: 'Confirm tab close',
type: 'checkbox',
},
{
name: 'showChannelList',
title: 'Show channel list',
type: 'checkbox',
},
{
name: 'fancyInfo',
title: 'Fancy server messages',
type: 'checkbox',
},
{
name: 'autoCloseUserContext',
title: 'Auto-close user menus',
type: 'checkbox',
},
],
},
{
name: 'text',
title: 'Text',
items: [
{
name: 'enableParser',
title: 'Parse markup',
type: 'checkbox',
},
{
name: 'enableEmoticons',
title: 'Parse emoticons',
type: 'checkbox',
},
{
name: 'autoParseUrls',
title: 'Auto detect links',
type: 'checkbox',
},
{
name: 'preventOverflow',
title: 'Prevent overflow',
type: 'checkbox',
},
{
name: 'expandTextBox',
title: 'Grow input box',
type: 'checkbox',
},
{
name: 'eepromAutoInsert',
title: 'Auto-insert uploads',
type: 'checkbox',
},
{
name: 'autoEmbedV1',
title: 'Auto-embed media',
type: 'checkbox',
},
],
},
{
name: 'notification',
title: 'Notification',
items: [
{
name: 'flashTitle',
title: 'Strobe title on new message',
type: 'checkbox',
},
{
name: 'showServerMsgInTitle',
title: 'Show server message in title',
type: 'checkbox',
},
{
name: 'enableNotifications',
title: 'Show notifications',
type: 'checkbox',
},
{
name: 'notificationShowMessage',
title: 'Show contents of message',
type: 'checkbox',
},
{
name: 'notificationTriggers',
title: 'Triggers',
type: 'text',
},
],
},
{
name: 'sounds',
title: 'Sound',
items: [
{
name: 'soundEnable',
title: 'Enable sound',
type: 'checkbox',
},
{
name: 'soundPack',
title: 'Sound pack',
type: 'select',
options: () => {
const packs = mami.sound.packs;
const options = {};
for(const name of packs.names())
options[name] = packs.info(name).getTitle();
return options;
},
},
{
name: 'soundVolume',
title: 'Sound volume',
type: 'range',
},
{
name: 'soundEnableJoin',
title: 'Play join sound',
type: 'checkbox',
},
{
name: 'soundEnableLeave',
title: 'Play leave sound',
type: 'checkbox',
},
{
name: 'soundEnableError',
title: 'Play error sound',
type: 'checkbox',
},
{
name: 'soundEnableServer',
title: 'Play server message sound',
type: 'checkbox',
},
{
name: 'soundEnableIncoming',
title: 'Play receive message sound',
type: 'checkbox',
},
{
name: 'onlySoundOnMention',
title: 'Do Not Play Any Sound Effects, Unless the Message Contains the Username of the User Controlling the Current Flashii Chat Session, Including but Not Limited To Joke Triggers, Receive Sounds and Join Sounds, but Excluding Typing Sounds',
type: 'checkbox',
},
{
name: 'soundEnableOutgoing',
title: 'Play send message sound',
type: 'checkbox',
},
{
name: 'soundEnablePrivate',
title: 'Play private message sound',
type: 'checkbox',
},
{
name: 'soundEnableForceLeave',
title: 'Play kick sound',
type: 'checkbox',
},
{
name: 'minecraft',
title: 'Minecraft',
type: 'select',
options: () => {
return {
'no': 'No Minecraft',
'yes': 'Yes Minecraft',
'old': 'Old Minecraft',
};
},
},
{
name: 'windowsLiveMessenger',
title: 'Windows Live Messenger',
type: 'checkbox',
},
{
name: 'seinfeld',
title: 'Seinfeld',
type: 'checkbox',
},
],
},
{
name: 'misc',
title: 'Misc',
items: [
{
name: 'onlyConnectWhenVisible',
title: 'Only connect when the tab is in the foreground',
type: 'checkbox',
confirm: 'Please only disable this setting if you are using a desktop or laptop computer, this should always remain on on a phone, tablet or other device of that sort. Ignoring this warning may carry consequences.',
},
{
name: 'playJokeSounds',
title: 'Run joke triggers',
type: 'checkbox',
},
{
name: 'weeaboo',
title: 'Weeaboo',
type: 'checkbox',
},
{
name: 'motivationalImages',
title: 'Make images motivational',
type: 'checkbox',
},
{
name: 'motivationalVideos',
title: 'Make videos motivational',
type: 'checkbox',
},
{
name: 'osuKeysV2',
title: 'osu! keyboard sounds',
type: 'select',
options: () => {
return {
'no': 'Off',
'yes': 'On',
'rng': 'On, random pitch',
};
},
},
{
name: 'explosionRadius',
title: 'Messages to keep on clear',
type: 'number',
},
{
title: 'Reload emoticons',
type: 'button',
invoke: button => {
const emotes = futami.get('emotes');
setTimeout(() => {
button.disabled = true;
futami.getJson('emotes', true)
.then(emotes => {
MamiEmotes.clear();
MamiEmotes.loadLegacy(emotes);
})
.finally(() => {
Umi.UI.Emoticons.Init();
button.disabled = false;
});
}, 200);
},
},
{
title: 'Reload joke triggers',
type: 'button',
invoke: button => {
button.disabled = true;
const triggers = mami.textTriggers;
triggers.clearTriggers();
if(mami.settings.get('playJokeSounds'))
futami.getJson('texttriggers', true)
.then(trigInfos => triggers.addTriggers(trigInfos))
.finally(() => button.disabled = false);
},
},
{
title: 'Open compatibility client',
type: 'button',
invoke: () => {
const meow = $e('a', { href: window.AMI_URL, target: '_blank', style: { display: 'none' } });
document.body.appendChild(meow);
meow.click();
$r(meow);
},
},
{
title: 'Manual reconnect',
type: 'button',
invoke: async button => {
const textOrig = button.value;
let lock = 10;
button.disabled = true;
button.value = 'Reconnecting...';
try {
await mami.conMan.start();
while(--lock > 0) {
button.value = textOrig + ` (${lock}s)`;
await MamiSleep(1000);
}
} finally {
button.value = textOrig;
button.disabled = false;
}
},
},
],
},
{
name: 'settings',
title: 'Settings',
items: [
{
title: 'Import settings',
type: 'button',
invoke: () => {
if(!confirm('Your current settings will be replaced with the ones in the export. Are you sure you want to continue?'))
return;
(new MamiSettingsBackup(mami.settings)).importUpload(document.body);
},
},
{
title: 'Export settings',
type: 'button',
invoke: () => {
const user = Umi.User.getCurrentUser();
let fileName;
if(user !== null)
fileName = `${user.name}'s settings.mami`;
(new MamiSettingsBackup(mami.settings)).exportDownload(document.body, fileName);
},
},
{
title: 'Reset settings',
type: 'button',
invoke: () => {
if(!confirm('This will reset all your settings to their defaults values. Are you sure you want to do this?'))
return;
mami.settings.clear();
},
},
],
},
{
name: 'debug',
title: 'Debug',
collapse: true,
warning: "Only touch these settings if you're ABSOLUTELY sure you know what you're doing, you're on your own if you break something.",
items: [
{
name: 'dumpPackets',
title: 'Dump packets to console',
type: 'checkbox',
},
{
name: 'dumpEvents',
title: 'Dump events to console',
type: 'checkbox',
},
{
name: 'marqueeAllNames',
title: 'Apply marquee on everyone',
type: 'checkbox',
},
{
name: 'tmpDisableOldThemeSys',
title: 'Disable Old Theme System',
type: 'checkbox',
},
{
title: 'Test kick/ban notice',
type: 'button',
invoke: async button => {
button.disabled = true;
const notice = new MamiForceDisconnectNotice({ perma: true, type: 'ban' });
await notice.pushOn(mami.views);
await MamiSleep(5000);
await notice.popOff(mami.views);
button.disabled = false;
},
},
{
title: 'You are an idiot!',
type: 'button',
invoke: async button => {
button.disabled = true;
await (new MamiYouAreAnIdiot()).pushOn(mami.views);
button.disabled = false;
},
},
{
title: 'Reset audio context',
type: 'button',
invoke: async () => {
mami.sound.reset();
},
},
],
}
];
const createCopyright = function() {
return <div class="mami-copyright">
<a href="//patchii.net/flashii/mami" target="_blank">Mami</a> # <a href={`//patchii.net/flashii/mami/commit/${GIT_HASH}`} target="_blank">{GIT_HASH.substring(0, 7)}</a> © <a href="//flash.moe" target="_blank">flash.moe</a><br/>
<a href="//railgun.sh/sockchat" target="_blank">Sock Chat documentation</a><br/>
</div>;
};
const createSetting = function(display) {
let setting;
if('name' in display)
setting = mami.settings.info(display.name);
let input = display.type === 'select'
? <select class="setting__input"/>
: <input type={display.type} class="setting__input"/>;
if(display.disabled === true)
input.disabled = true;
if(display.type === 'select') {
const options = display.options();
for(const name in options)
input.appendChild(<option class={['setting__style', `setting__style--${display.name}-${name}`]} value={name}>
{options[name]}
</option>);
} else if(display.type === 'button') {
input.value = display.title;
input.addEventListener('click', () => display.invoke(input));
}
if(setting !== undefined) {
if(!input.disabled && setting.immutable)
input.disabled = true;
if(display.type === 'checkbox') {
mami.settings.watch(setting.name, ev => input.checked = ev.detail.value);
input.addEventListener('change', () => {
if(display.confirm !== undefined && input.checked !== setting.fallback && !confirm(display.confirm)) {
input.checked = setting.fallback;
return;
}
mami.settings.toggle(setting.name);
});
} else {
mami.settings.watch(setting.name, ev => input.value = ev.detail.value);
input.addEventListener('change', () => mami.settings.set(setting.name, input.value));
}
}
let label = input;
if(display.type === 'checkbox') {
label = <label class="setting__label">
{input}
<div>{display.title}</div>
</label>;
} else if(display.type === 'button') {
label = <label class="setting__label">{input}</label>;
} else {
label = <label class="setting__label">
<div>{display.title}</div>
{input}
</label>;
}
return <div class={['setting__container', `setting__container--${display.type}`]}>{label}</div>;
};
const createCategory = function(category) {
const catHeader = <div class={['setting__category-title', `setting__category-title--${category.name}`]} style={{ cursor: 'pointer' }}>{category.title}</div>;
const catBody = <div class={['setting__category', `setting__category--${category.name}`]} style={{ overflow: 'hidden' }}/>;
const catContainer = <div>{catHeader}{catBody}</div>;
let anime, closed = false;
catHeader.onclick = () => {
if(anime !== undefined) {
anime.cancel();
anime = undefined;
}
let start, update, end, height;
if(closed) {
start = () => {
const curHeight = catBody.style.height;
catBody.style.height = null;
height = catBody.clientHeight;
catBody.style.height = curHeight;
};
update = t => catBody.style.height = `${height * t}px`;
end = () => catBody.style.height = null;
} else {
start = () => height = catBody.clientHeight;
update = t => catBody.style.height = `${height - (height * t)}px`;
end = () => catBody.style.height = '0';
}
closed = !closed;
anime = MamiAnimate({
duration: 500,
easing: 'outExpo',
start: start,
update: update,
end: end,
});
};
if(category.warning)
catBody.appendChild(<div style={{ fontSize: '.9em', lineHeight: '1.4em', margin: '5px', padding: '5px', backgroundColor: 'darkred', border: '2px solid red', borderRadius: '5px' }}>{category.warning}</div>);
if(category.items)
for(const item of category.items)
catBody.appendChild(createSetting(item));
return catContainer;
};
return {
Init: function() {
const html = Umi.UI.Menus.Get('settings');
$rc(html);
for(const category of items) {
const elem = createCategory(category);
html.appendChild(elem);
// only a little bit of hacking, stan
if(category.collapse)
elem.firstChild.click();
}
html.appendChild(createCopyright());
},
};
})();