0.2.4 - also fix theme building
This commit is contained in:
		
							parent
							
								
									6d9fd35805
								
							
						
					
					
						commit
						cf015bd4b7
					
				@ -137,7 +137,7 @@
 | 
			
		||||
 | 
			
		||||
        onKeyDown(e: KeyboardEvent): void {
 | 
			
		||||
            const key = getKey(e);
 | 
			
		||||
            if(e.ctrlKey && !e.shiftKey && key !== 'Control') { //tslint:disable-line:curly
 | 
			
		||||
            if((e.metaKey || e.ctrlKey) && !e.shiftKey && key !== 'Control' && key !== 'Meta') { //tslint:disable-line:curly
 | 
			
		||||
                for(const button of this.buttons)
 | 
			
		||||
                    if(button.key === key) {
 | 
			
		||||
                        e.stopPropagation();
 | 
			
		||||
 | 
			
		||||
@ -16,10 +16,15 @@
 | 
			
		||||
                <option :value="setting.False">{{l('conversationSettings.false')}}</option>
 | 
			
		||||
            </select>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="form-group">
 | 
			
		||||
            <label class="control-label" for="defaultHighlights">
 | 
			
		||||
                <input type="checkbox" id="defaultHighlights" v-model="defaultHighlights"/>
 | 
			
		||||
                {{l('settings.defaultHighlights')}}
 | 
			
		||||
            </label>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="form-group">
 | 
			
		||||
            <label class="control-label" :for="'highlightWords' + conversation.key">{{l('settings.highlightWords')}}</label>
 | 
			
		||||
            <input :id="'highlightWords' + conversation.key" class="form-control" v-model="highlightWords"
 | 
			
		||||
                   :disabled="highlight == setting.Default"/>
 | 
			
		||||
            <input :id="'highlightWords' + conversation.key" class="form-control" v-model="highlightWords"/>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="form-group">
 | 
			
		||||
            <label class="control-label" :for="'joinMessages' + conversation.key">{{l('settings.joinMessages')}}</label>
 | 
			
		||||
@ -52,6 +57,7 @@
 | 
			
		||||
        highlight: Conversation.Setting;
 | 
			
		||||
        highlightWords: string;
 | 
			
		||||
        joinMessages: Conversation.Setting;
 | 
			
		||||
        defaultHighlights: boolean;
 | 
			
		||||
 | 
			
		||||
        constructor() {
 | 
			
		||||
            super();
 | 
			
		||||
@ -64,6 +70,7 @@
 | 
			
		||||
            this.highlight = settings.highlight;
 | 
			
		||||
            this.highlightWords = settings.highlightWords.join(',');
 | 
			
		||||
            this.joinMessages = settings.joinMessages;
 | 
			
		||||
            this.defaultHighlights = settings.defaultHighlights;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        @Watch('conversation')
 | 
			
		||||
@ -76,7 +83,8 @@
 | 
			
		||||
                notify: this.notify,
 | 
			
		||||
                highlight: this.highlight,
 | 
			
		||||
                highlightWords: this.highlightWords.split(',').filter((x) => x.length),
 | 
			
		||||
                joinMessages: this.joinMessages
 | 
			
		||||
                joinMessages: this.joinMessages,
 | 
			
		||||
                defaultHighlights: this.defaultHighlights
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -148,6 +148,7 @@
 | 
			
		||||
            const touch = e instanceof TouchEvent ? e.changedTouches[0] : e;
 | 
			
		||||
            let node = <Node & {character?: Character, channel?: Channel}>touch.target;
 | 
			
		||||
            while(node !== document.body) {
 | 
			
		||||
                if(e.type === 'touchstart' && node === this.$refs['menu']) return;
 | 
			
		||||
                if(node.character !== undefined || node.parentNode === null) break;
 | 
			
		||||
                node = node.parentNode;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -46,6 +46,7 @@ export class ConversationSettings implements Conversation.Settings {
 | 
			
		||||
    highlight = Conversation.Setting.Default;
 | 
			
		||||
    highlightWords: string[] = [];
 | 
			
		||||
    joinMessages = Conversation.Setting.Default;
 | 
			
		||||
    defaultHighlights = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function formatTime(this: void | never, date: Date): string {
 | 
			
		||||
 | 
			
		||||
@ -439,19 +439,33 @@ export default function(this: void): Interfaces.State {
 | 
			
		||||
        for(const item of state.pinned.private) state.getPrivate(core.characters.get(item));
 | 
			
		||||
        queuedJoin(state.pinned.channels.slice());
 | 
			
		||||
    });
 | 
			
		||||
    core.channels.onEvent((type, channel) => {
 | 
			
		||||
    core.channels.onEvent((type, channel, member) => {
 | 
			
		||||
        const key = channel.id.toLowerCase();
 | 
			
		||||
        if(type === 'join') {
 | 
			
		||||
            const conv = new ChannelConversation(channel);
 | 
			
		||||
            state.channelMap[key] = conv;
 | 
			
		||||
            state.channelConversations.push(conv);
 | 
			
		||||
            state.addRecent(conv);
 | 
			
		||||
        } else {
 | 
			
		||||
        if(type === 'join')
 | 
			
		||||
            if(member === undefined) {
 | 
			
		||||
                const conv = new ChannelConversation(channel);
 | 
			
		||||
                state.channelMap[key] = conv;
 | 
			
		||||
                state.channelConversations.push(conv);
 | 
			
		||||
                state.addRecent(conv);
 | 
			
		||||
            } else {
 | 
			
		||||
                const conv = state.channelMap[channel.id]!;
 | 
			
		||||
                if(conv.settings.joinMessages === Interfaces.Setting.False || conv.settings.joinMessages === Interfaces.Setting.Default &&
 | 
			
		||||
                    !core.state.settings.joinMessages) return;
 | 
			
		||||
                const text = l('events.channelJoin', `[user]${member.character.name}[/user]`);
 | 
			
		||||
                conv.addMessage(new EventMessage(text));
 | 
			
		||||
            }
 | 
			
		||||
        else if(member === undefined) {
 | 
			
		||||
            const conv = state.channelMap[key]!;
 | 
			
		||||
            state.channelConversations.splice(state.channelConversations.indexOf(conv), 1);
 | 
			
		||||
            delete state.channelMap[key];
 | 
			
		||||
            state.savePinned();
 | 
			
		||||
            if(state.selectedConversation === conv) state.show(state.consoleTab);
 | 
			
		||||
        } else {
 | 
			
		||||
            const conv = state.channelMap[channel.id]!;
 | 
			
		||||
            if(conv.settings.joinMessages === Interfaces.Setting.False || conv.settings.joinMessages === Interfaces.Setting.Default &&
 | 
			
		||||
                !core.state.settings.joinMessages) return;
 | 
			
		||||
            const text = l('events.channelLeave', `[user]${member.character.name}[/user]`);
 | 
			
		||||
            conv.addMessage(new EventMessage(text));
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
@ -469,14 +483,10 @@ export default function(this: void): Interfaces.State {
 | 
			
		||||
        const message = createMessage(MessageType.Message, char, decodeHTML(data.message), time);
 | 
			
		||||
        conversation.addMessage(message);
 | 
			
		||||
 | 
			
		||||
        let words: string[];
 | 
			
		||||
        if(conversation.settings.highlight !== Interfaces.Setting.Default) {
 | 
			
		||||
            words = conversation.settings.highlightWords.slice();
 | 
			
		||||
            if(conversation.settings.highlight === Interfaces.Setting.True) words.push(core.connection.character);
 | 
			
		||||
        } else {
 | 
			
		||||
            words = core.state.settings.highlightWords.slice();
 | 
			
		||||
            if(core.state.settings.highlight) words.push(core.connection.character);
 | 
			
		||||
        }
 | 
			
		||||
        const words = conversation.settings.highlightWords.slice();
 | 
			
		||||
        if(conversation.settings.defaultHighlights) words.push(...core.state.settings.highlightWords);
 | 
			
		||||
        if(conversation.settings.highlight === Interfaces.Setting.Default && core.state.settings.highlight ||
 | 
			
		||||
            conversation.settings.highlight === Interfaces.Setting.True) words.push(core.connection.character);
 | 
			
		||||
        //tslint:disable-next-line:no-null-keyword
 | 
			
		||||
        const results = words.length > 0 ? message.text.match(new RegExp(`\\b(${words.join('|')})\\b`, 'i')) : null;
 | 
			
		||||
        if(results !== null) {
 | 
			
		||||
@ -523,7 +533,7 @@ export default function(this: void): Interfaces.State {
 | 
			
		||||
        const message = new EventMessage(l('events.login', `[user]${data.identity}[/user]`), time);
 | 
			
		||||
        if(isOfInterest(core.characters.get(data.identity))) addEventMessage(message);
 | 
			
		||||
        const conv = state.privateMap[data.identity.toLowerCase()];
 | 
			
		||||
        if(conv !== undefined && core.state.settings.eventMessages && conv !== state.selectedConversation) conv.addMessage(message);
 | 
			
		||||
        if(conv !== undefined && (!core.state.settings.eventMessages || conv !== state.selectedConversation)) conv.addMessage(message);
 | 
			
		||||
    });
 | 
			
		||||
    connection.onMessage('FLN', (data, time) => {
 | 
			
		||||
        const message = new EventMessage(l('events.logout', `[user]${data.character}[/user]`), time);
 | 
			
		||||
@ -531,7 +541,7 @@ export default function(this: void): Interfaces.State {
 | 
			
		||||
        const conv = state.privateMap[data.character.toLowerCase()];
 | 
			
		||||
        if(conv === undefined) return;
 | 
			
		||||
        conv.typingStatus = 'clear';
 | 
			
		||||
        if(core.state.settings.eventMessages && conv !== state.selectedConversation) conv.addMessage(message);
 | 
			
		||||
        if(!core.state.settings.eventMessages || conv !== state.selectedConversation) conv.addMessage(message);
 | 
			
		||||
    });
 | 
			
		||||
    connection.onMessage('TPN', (data) => {
 | 
			
		||||
        const conv = state.privateMap[data.character.toLowerCase()];
 | 
			
		||||
@ -660,22 +670,6 @@ export default function(this: void): Interfaces.State {
 | 
			
		||||
        state.selectedConversation.infoText = data.message;
 | 
			
		||||
        addEventMessage(new EventMessage(data.message, time));
 | 
			
		||||
    });
 | 
			
		||||
    connection.onMessage('JCH', (data, time) => {
 | 
			
		||||
        if(data.character.identity === core.connection.character) return;
 | 
			
		||||
        const conv = state.channelMap[data.channel.toLowerCase()]!;
 | 
			
		||||
        if(conv.settings.joinMessages === Interfaces.Setting.False || conv.settings.joinMessages === Interfaces.Setting.Default &&
 | 
			
		||||
            !core.state.settings.joinMessages) return;
 | 
			
		||||
        const text = l('events.channelJoin', `[user]${data.character.identity}[/user]`);
 | 
			
		||||
        conv.addMessage(new EventMessage(text, time));
 | 
			
		||||
    });
 | 
			
		||||
    connection.onMessage('LCH', (data, time) => {
 | 
			
		||||
        if(data.character === core.connection.character) return;
 | 
			
		||||
        const conv = state.channelMap[data.channel.toLowerCase()]!;
 | 
			
		||||
        if(conv.settings.joinMessages === Interfaces.Setting.False || conv.settings.joinMessages === Interfaces.Setting.Default &&
 | 
			
		||||
            !core.state.settings.joinMessages) return;
 | 
			
		||||
        const text = l('events.channelLeave', `[user]${data.character}[/user]`);
 | 
			
		||||
        conv.addMessage(new EventMessage(text, time));
 | 
			
		||||
    });
 | 
			
		||||
    connection.onMessage('ZZZ', (data, time) => {
 | 
			
		||||
        state.selectedConversation.infoText = data.message;
 | 
			
		||||
        addEventMessage(new EventMessage(data.message, time));
 | 
			
		||||
 | 
			
		||||
@ -92,6 +92,7 @@ export namespace Conversation {
 | 
			
		||||
        readonly highlight: Setting;
 | 
			
		||||
        readonly highlightWords: ReadonlyArray<string>;
 | 
			
		||||
        readonly joinMessages: Setting;
 | 
			
		||||
        readonly defaultHighlights: boolean;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    export const enum UnreadState { None, Unread, Mention }
 | 
			
		||||
 | 
			
		||||
@ -8,7 +8,7 @@ const strings: {[key: string]: string | undefined} = {
 | 
			
		||||
    'action.copyLink': 'Copy Link',
 | 
			
		||||
    'action.suggestions': 'Suggestions',
 | 
			
		||||
    'action.open': 'Show',
 | 
			
		||||
    'action.quit': 'Exit',
 | 
			
		||||
    'action.quit': 'Quit',
 | 
			
		||||
    'action.updateAvailable': 'UPDATE AVAILABLE',
 | 
			
		||||
    'action.update': 'Restart now!',
 | 
			
		||||
    'action.cancel': 'Cancel',
 | 
			
		||||
@ -18,6 +18,7 @@ const strings: {[key: string]: string | undefined} = {
 | 
			
		||||
    'help.rules': 'F-List Rules',
 | 
			
		||||
    'help.faq': 'F-List FAQ',
 | 
			
		||||
    'help.report': 'How to report a user',
 | 
			
		||||
    'help.changelog': 'Changelog',
 | 
			
		||||
    'title': 'FChat 3.0',
 | 
			
		||||
    'version': 'Version {0}',
 | 
			
		||||
    'filter': 'Type to filter...',
 | 
			
		||||
@ -130,6 +131,7 @@ Are you sure?`,
 | 
			
		||||
    'settings.theme': 'Theme',
 | 
			
		||||
    'settings.logMessages': 'Log messages',
 | 
			
		||||
    'settings.logAds': 'Log ads',
 | 
			
		||||
    'settings.defaultHighlights': 'Use global highlight words',
 | 
			
		||||
    'conversationSettings.title': 'Settings',
 | 
			
		||||
    'conversationSettings.action': 'Edit settings for {0}',
 | 
			
		||||
    'conversationSettings.default': 'Default',
 | 
			
		||||
@ -344,7 +346,7 @@ Are you sure?`,
 | 
			
		||||
    'status.dnd': 'Do Not Disturb',
 | 
			
		||||
    'status.idle': 'Idle',
 | 
			
		||||
    'status.offline': 'Offline',
 | 
			
		||||
    'status.crown': 'Rewarded by Admin',
 | 
			
		||||
    'status.crown': 'Rewarded',
 | 
			
		||||
    'importer.importGeneral': 'slimCat data has been detected on your computer.\nWould you like to import general settings?',
 | 
			
		||||
    'importer.importCharacter': 'slimCat data for this character has been detected on your computer.\nWould you like to import settings and logs?\nThis may take a while.\nAny existing FChat 3.0 data for this character will be overwritten.',
 | 
			
		||||
    'importer.importing': 'Importing data',
 | 
			
		||||
 | 
			
		||||
@ -42,7 +42,7 @@ export function parse(this: void | never, input: string, context: CommandContext
 | 
			
		||||
            switch(param.type) {
 | 
			
		||||
                case ParamType.String:
 | 
			
		||||
                    if(i === command.params.length - 1) values[i] = args.substr(index);
 | 
			
		||||
                    continue;
 | 
			
		||||
                    break;
 | 
			
		||||
                case ParamType.Enum:
 | 
			
		||||
                    if((param.options !== undefined ? param.options : []).indexOf(value) === -1)
 | 
			
		||||
                        return l('commands.invalidParam', l(`commands.${name}.param${i}`));
 | 
			
		||||
@ -62,7 +62,7 @@ export function parse(this: void | never, input: string, context: CommandContext
 | 
			
		||||
                    const char = core.characters.get(value);
 | 
			
		||||
                    if(char.status === 'offline') return l('commands.invalidCharacter');
 | 
			
		||||
            }
 | 
			
		||||
            index = endIndex + 1;
 | 
			
		||||
            index = endIndex === -1 ? args.length : endIndex + 1;
 | 
			
		||||
        }
 | 
			
		||||
    if(command.context !== undefined)
 | 
			
		||||
        return function(this: Conversation): void {
 | 
			
		||||
 | 
			
		||||
@ -44,7 +44,8 @@ const UserView = Vue.extend({
 | 
			
		||||
            else rankIcon = '';
 | 
			
		||||
        } else rankIcon = '';
 | 
			
		||||
 | 
			
		||||
        const html = (props.showStatus !== undefined ? `<span class="fa fa-fw ${getStatusIcon(character.status)}"></span>` : '') +
 | 
			
		||||
        const html = (props.showStatus !== undefined || character.status === 'crown'
 | 
			
		||||
            ? `<span class="fa fa-fw ${getStatusIcon(character.status)}"></span>` : '') +
 | 
			
		||||
            (rankIcon !== '' ? `<span class="fa ${rankIcon}"></span>` : '') + character.name;
 | 
			
		||||
        return createElement('span', {
 | 
			
		||||
            attrs: {class: `user-view gender-${character.gender !== undefined ? character.gender.toLowerCase() : 'none'}`},
 | 
			
		||||
 | 
			
		||||
@ -59,6 +59,10 @@
 | 
			
		||||
    import {GeneralSettings, getGeneralSettings, Logs, setGeneralSettings, SettingsStore} from './filesystem';
 | 
			
		||||
    import Notifications from './notifications';
 | 
			
		||||
 | 
			
		||||
    function confirmBack(): void {
 | 
			
		||||
        if(confirm(l('chat.confirmLeave'))) (<Navigator & {app: {exitApp(): void}}>navigator).app.exitApp();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Component({
 | 
			
		||||
        components: {chat: Chat, modal: Modal}
 | 
			
		||||
    })
 | 
			
		||||
@ -105,9 +109,11 @@
 | 
			
		||||
                const connection = new Connection(Socket, this.settings!.account, this.settings!.password);
 | 
			
		||||
                connection.onEvent('connected', () => {
 | 
			
		||||
                    Raven.setUserContext({username: core.connection.character});
 | 
			
		||||
                    document.addEventListener('backbutton', confirmBack);
 | 
			
		||||
                });
 | 
			
		||||
                connection.onEvent('closed', () => {
 | 
			
		||||
                    Raven.setUserContext();
 | 
			
		||||
                    document.removeEventListener('backbutton', confirmBack);
 | 
			
		||||
                });
 | 
			
		||||
                initCore(connection, Logs, SettingsStore, Notifications);
 | 
			
		||||
                this.characters = data.characters.sort();
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,7 @@
 | 
			
		||||
    </description>
 | 
			
		||||
    <author email="maya@f-list.net" href="https://www.f-list.net">The F-list Team</author>
 | 
			
		||||
    <content src="index.html" />
 | 
			
		||||
    <icon src="../electron/build/icon.png" />
 | 
			
		||||
    <access origin="*" />
 | 
			
		||||
    <allow-intent href="http://*/*" />
 | 
			
		||||
    <allow-intent href="https://*/*" />
 | 
			
		||||
 | 
			
		||||
@ -27,7 +27,7 @@ export class GeneralSettings {
 | 
			
		||||
    account = '';
 | 
			
		||||
    password = '';
 | 
			
		||||
    host = 'wss://chat.f-list.net:9799';
 | 
			
		||||
    theme = 'dark';
 | 
			
		||||
    theme = 'default';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Index = {[key: string]: {name: string, index: {[key: number]: number | undefined}} | undefined};
 | 
			
		||||
@ -99,12 +99,13 @@ function serializeMessage(message: Conversation.Message): Blob {
 | 
			
		||||
    dv.setUint8(5, senderLength);
 | 
			
		||||
    const textLength = getByteLength(message.text);
 | 
			
		||||
    dv.setUint16(6, textLength);
 | 
			
		||||
    return new Blob([buffer, name, message.text, String.fromCharCode(senderLength + textLength + 10)]);
 | 
			
		||||
    const length = senderLength + textLength + 8;
 | 
			
		||||
    return new Blob([buffer, name, message.text, String.fromCharCode(length >> 255), String.fromCharCode(length % 255)]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function deserializeMessage(buffer: ArrayBuffer): {message: Conversation.Message, end: number} {
 | 
			
		||||
    const dv = new DataView(buffer, 0, 8);
 | 
			
		||||
    const time = dv.getUint32(0);
 | 
			
		||||
    const time = dv.getUint32(0) * 1000;
 | 
			
		||||
    const type = dv.getUint8(4);
 | 
			
		||||
    const senderLength = dv.getUint8(5);
 | 
			
		||||
    const messageLength = dv.getUint16(6);
 | 
			
		||||
@ -183,7 +184,7 @@ export class Logs implements Logging.Persistent {
 | 
			
		||||
        let messages = new Array<Conversation.Message>(count);
 | 
			
		||||
        let pos = file.size;
 | 
			
		||||
        while(pos > 0 && count > 0) {
 | 
			
		||||
            const length = new DataView(await readAsArrayBuffer(file)).getUint16(0);
 | 
			
		||||
            const length = new DataView(await readAsArrayBuffer(file.slice(pos - 2, pos))).getUint16(0);
 | 
			
		||||
            pos = pos - length - 2;
 | 
			
		||||
            messages[--count] = deserializeMessage(await readAsArrayBuffer(file.slice(pos, pos + length))).message;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -88,7 +88,6 @@
 | 
			
		||||
        {label: l('action.open'), click: () => mainWindow!.show()},
 | 
			
		||||
        {
 | 
			
		||||
            label: l('action.quit'),
 | 
			
		||||
            role: 'quit',
 | 
			
		||||
            click: () => {
 | 
			
		||||
                isClosing = true;
 | 
			
		||||
                mainWindow!.close();
 | 
			
		||||
@ -201,7 +200,13 @@
 | 
			
		||||
                },
 | 
			
		||||
                {type: 'separator'},
 | 
			
		||||
                {role: 'minimize'},
 | 
			
		||||
                {role: 'quit'}
 | 
			
		||||
                process.platform === 'darwin' ? {role: 'quit'} : {
 | 
			
		||||
                    label: l('action.quit'),
 | 
			
		||||
                    click(): void {
 | 
			
		||||
                        isClosing = true;
 | 
			
		||||
                        mainWindow!.close();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            ];
 | 
			
		||||
            electron.remote.Menu.setApplicationMenu(electron.remote.Menu.buildFromTemplate(appMenu));
 | 
			
		||||
 | 
			
		||||
@ -220,6 +225,9 @@
 | 
			
		||||
                                electron.ipcRenderer.send('install-update');
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }, {
 | 
			
		||||
                        label: l('help.changelog'),
 | 
			
		||||
                        click: () => electron.shell.openExternal('https://wiki.f-list.net/F-Chat_3.0#Changelog')
 | 
			
		||||
                    }])
 | 
			
		||||
                }));
 | 
			
		||||
                electron.remote.Menu.setApplicationMenu(menu);
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "fchat",
 | 
			
		||||
  "version": "0.2.2",
 | 
			
		||||
  "version": "0.2.4",
 | 
			
		||||
  "author": "The F-List Team",
 | 
			
		||||
  "description": "F-List.net Chat Client",
 | 
			
		||||
  "main": "main.js",
 | 
			
		||||
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 969 B  | 
							
								
								
									
										
											BIN
										
									
								
								electron/build/tray@2x.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								electron/build/tray@2x.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 2.5 KiB  | 
@ -98,7 +98,7 @@ function createMessage(line: string, ownCharacter: string, name: string, isChann
 | 
			
		||||
        let endIndex = line.indexOf('[', lineIndex += 6);
 | 
			
		||||
        if(endIndex - lineIndex > 20) endIndex = lineIndex + 20;
 | 
			
		||||
        sender = line.substring(lineIndex, endIndex);
 | 
			
		||||
        text = line.substring(endIndex + 6, 65535);
 | 
			
		||||
        text = line.substring(endIndex + 6, 50000);
 | 
			
		||||
    } else {
 | 
			
		||||
        if(lineIndex + ownCharacter.length <= line.length && line.substr(lineIndex, ownCharacter.length) === ownCharacter)
 | 
			
		||||
            sender = ownCharacter;
 | 
			
		||||
@ -117,7 +117,7 @@ function createMessage(line: string, ownCharacter: string, name: string, isChann
 | 
			
		||||
                lineIndex += 3;
 | 
			
		||||
            }
 | 
			
		||||
        } else type = Conversation.Message.Type.Action;
 | 
			
		||||
        text = line.substr(lineIndex, 65535);
 | 
			
		||||
        text = line.substr(lineIndex, 50000);
 | 
			
		||||
    }
 | 
			
		||||
    return {type, sender: {name: sender}, text, time: addMinutes(date, h * 60 + m)};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -18,6 +18,10 @@ function sortMember(this: void | never, array: Interfaces.Member[], member: Inte
 | 
			
		||||
        if(member.character.isChatOp && !other.character.isChatOp) break;
 | 
			
		||||
        if(other.rank > member.rank) continue;
 | 
			
		||||
        if(member.rank > other.rank) break;
 | 
			
		||||
        if(other.character.isFriend && !member.character.isFriend) continue;
 | 
			
		||||
        if(member.character.isFriend && !other.character.isFriend) break;
 | 
			
		||||
        if(other.character.isBookmarked && !member.character.isBookmarked) continue;
 | 
			
		||||
        if(member.character.isBookmarked && !other.character.isBookmarked) break;
 | 
			
		||||
        if(name < other.character.name) break;
 | 
			
		||||
    }
 | 
			
		||||
    array.splice(i, 0, member);
 | 
			
		||||
@ -37,6 +41,7 @@ class Channel implements Interfaces.Channel {
 | 
			
		||||
    addMember(member: Interfaces.Member): void {
 | 
			
		||||
        this.members[member.character.name] = member;
 | 
			
		||||
        sortMember(this.sortedMembers, member);
 | 
			
		||||
        for(const handler of state.handlers) handler('join', this, member);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    removeMember(name: string): void {
 | 
			
		||||
@ -44,6 +49,7 @@ class Channel implements Interfaces.Channel {
 | 
			
		||||
        if(member !== undefined) {
 | 
			
		||||
            delete this.members[name];
 | 
			
		||||
            this.sortedMembers.splice(this.sortedMembers.indexOf(member), 1);
 | 
			
		||||
            for(const handler of state.handlers) handler('leave', this, member);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -105,12 +111,17 @@ let state: State;
 | 
			
		||||
export default function(this: void, connection: Connection, characters: Character.State): Interfaces.State {
 | 
			
		||||
    state = new State(connection);
 | 
			
		||||
    let getChannelTimer: NodeJS.Timer | undefined;
 | 
			
		||||
    connection.onEvent('connecting', () => {
 | 
			
		||||
    let rejoin: string[] | undefined;
 | 
			
		||||
    connection.onEvent('connecting', (isReconnect) => {
 | 
			
		||||
        if(isReconnect) rejoin = Object.keys(state.joinedMap);
 | 
			
		||||
        state.joinedChannels = [];
 | 
			
		||||
        state.joinedMap = {};
 | 
			
		||||
    });
 | 
			
		||||
    connection.onEvent('connected', (isReconnect) => {
 | 
			
		||||
        if(isReconnect) queuedJoin(Object.keys(state.joinedChannels));
 | 
			
		||||
    connection.onEvent('connected', () => {
 | 
			
		||||
        if(rejoin !== undefined) {
 | 
			
		||||
            queuedJoin(rejoin);
 | 
			
		||||
            rejoin = undefined;
 | 
			
		||||
        }
 | 
			
		||||
        const getChannels = () => {
 | 
			
		||||
            connection.send('CHA');
 | 
			
		||||
            connection.send('ORS');
 | 
			
		||||
@ -152,7 +163,8 @@ export default function(this: void, connection: Connection, characters: Characte
 | 
			
		||||
            if(item !== undefined) item.isJoined = true;
 | 
			
		||||
        } else {
 | 
			
		||||
            const channel = state.getChannel(data.channel)!;
 | 
			
		||||
            channel.addMember(channel.createMember(characters.get(data.character.identity)));
 | 
			
		||||
            const member = channel.createMember(characters.get(data.character.identity));
 | 
			
		||||
            channel.addMember(member);
 | 
			
		||||
            if(item !== undefined) item.memberCount++;
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
@ -128,22 +128,28 @@ export default function(this: void, connection: Connection): Interfaces.State {
 | 
			
		||||
        char.isChatOp = false;
 | 
			
		||||
    });
 | 
			
		||||
    connection.onMessage('RTB', (data) => {
 | 
			
		||||
        if(data.type !== 'trackadd' && data.type !== 'trackrem' && data.type !== 'friendadd' && data.type !== 'friendremove') return;
 | 
			
		||||
        const character = state.get(data.name);
 | 
			
		||||
        switch(data.type) {
 | 
			
		||||
            case 'trackadd':
 | 
			
		||||
                state.bookmarkList.push(data.name);
 | 
			
		||||
                state.get(data.name).isBookmarked = true;
 | 
			
		||||
                character.isBookmarked = true;
 | 
			
		||||
                if(character.status !== 'offline') state.bookmarks.push(character);
 | 
			
		||||
                break;
 | 
			
		||||
            case 'trackrem':
 | 
			
		||||
                state.bookmarkList.splice(state.bookmarkList.indexOf(data.name), 1);
 | 
			
		||||
                state.get(data.name).isBookmarked = false;
 | 
			
		||||
                character.isBookmarked = false;
 | 
			
		||||
                if(character.status !== 'offline') state.bookmarks.splice(state.bookmarks.indexOf(character), 1);
 | 
			
		||||
                break;
 | 
			
		||||
            case 'friendadd':
 | 
			
		||||
                state.friendList.push(data.name);
 | 
			
		||||
                state.get(data.name).isFriend = true;
 | 
			
		||||
                character.isFriend = true;
 | 
			
		||||
                if(character.status !== 'offline') state.friends.push(character);
 | 
			
		||||
                break;
 | 
			
		||||
            case 'friendremove':
 | 
			
		||||
                state.friendList.splice(state.friendList.indexOf(data.name), 1);
 | 
			
		||||
                state.get(data.name).isFriend = false;
 | 
			
		||||
                character.isFriend = false;
 | 
			
		||||
                if(character.status !== 'offline') state.friends.splice(state.friends.indexOf(character), 1);
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
    return state;
 | 
			
		||||
 | 
			
		||||
@ -180,7 +180,7 @@ export namespace Character {
 | 
			
		||||
export type Character = Character.Character;
 | 
			
		||||
 | 
			
		||||
export namespace Channel {
 | 
			
		||||
    export type EventHandler = (type: 'join' | 'leave', channel: Channel) => void;
 | 
			
		||||
    export type EventHandler = (type: 'join' | 'leave', channel: Channel, member?: Member) => void;
 | 
			
		||||
 | 
			
		||||
    export interface State {
 | 
			
		||||
        readonly officialChannels: {readonly [key: string]: (ListItem | undefined)};
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,7 @@
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "bootstrap": "^3.3.7",
 | 
			
		||||
    "font-awesome": "^4.7.0",
 | 
			
		||||
    "less": "^2.7.2",
 | 
			
		||||
    "less-plugin-npm-import": "^2.1.0"
 | 
			
		||||
  },
 | 
			
		||||
@ -115,6 +115,10 @@ fast-deep-equal@^1.0.0:
 | 
			
		||||
  version "1.0.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff"
 | 
			
		||||
 | 
			
		||||
font-awesome@^4.7.0:
 | 
			
		||||
  version "4.7.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/font-awesome/-/font-awesome-4.7.0.tgz#8fa8cf0411a1a31afd07b06d2902bb9fc815a133"
 | 
			
		||||
 | 
			
		||||
forever-agent@~0.6.1:
 | 
			
		||||
  version "0.6.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
 | 
			
		||||
@ -31,9 +31,9 @@ See https://electron.atom.io/docs/tutorial/application-distribution/
 | 
			
		||||
 | 
			
		||||
## Building a custom theme
 | 
			
		||||
See [the wiki](https://wiki.f-list.net/F-Chat_3.0/Themes) for instructions on how to create a custom theme.
 | 
			
		||||
 - Change into the `less/themes/chat` directory.
 | 
			
		||||
 - Change into the `less` directory.
 | 
			
		||||
 - Run `yarn install`.
 | 
			
		||||
 - Run `yarn build {name}.less {name}.css`.
 | 
			
		||||
 - Run `yarn build themes/chat/{name}.less {name}.css`.
 | 
			
		||||
 | 
			
		||||
## Dependencies
 | 
			
		||||
Note: Adding *and upgrading* dependencies should only be done with prior consideration and subsequent testing.
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user