<commit_before>import * as path from 'path';
import {app, BrowserWindow, globalShortcut, Tray, shell, dialog} from 'electron';
import windowState = require('electron-window-state');
import * as menubar from 'menubar';
import log from './log';
import {Config, Account} from './config';

const IS_DEBUG = process.env.NODE_ENV === 'development';
const IS_DARWIN = process.platform === 'darwin';
const APP_ICON = path.join(__dirname, '..', 'resources', 'icon', 'icon.png');
const PRELOAD_JS = path.join(__dirname, '..', 'renderer', 'preload.js');
const DEFAULT_WIDTH = 340;
const DEFAULT_HEIGHT = 400;

export class App {
    private account: Account;

    constructor(private win: Electron.BrowserWindow, private config: Config) {
        if (config.accounts.length === 0) {
            throw new Error('No account found. Please check the config.');
        }
        this.account = this.config.accounts[0];
    }

    open() {
        this.win.loadURL(`https://${this.account.host}${this.account.default_page}`);
        this.win.webContents.on('will-navigate', (e, url) => {
            if (!url.startsWith(`https://${this.account.host}`)) {
                e.preventDefault();
                shell.openExternal(url);
            }
        });
        this.win.webContents.on('new-window', (e, url) => {
            e.preventDefault();
            shell.openExternal(url);
        });
        this.win.webContents.session.setPermissionRequestHandler((contents, permission, callback) => {
            if (permission !== 'geolocation' && permission !== 'media') {
                // Granted
                callback(true);
                return;
            }

            dialog.showMessageBox({
                type: 'question',
                buttons: ['Accept', 'Reject'],
                message: `Permission '${permission}' is requested by ${contents.getURL()}`,
                detail: "Please choose one of 'Accept' or 'Reject'",
            }, (buttonIndex: number) => {
                const granted = buttonIndex === 0;
                callback(granted);
            });
        });
        this.win.show();
    }
}

function trayIcon(color: string) {
    return path.join(__dirname, '..', 'resources', 'icon', `tray-icon-${
        color === 'white' ? 'white' : 'black'
    }@2x.png`);
}

export default function startApp(config: Config) {
    return (config.normal_window ? startNormalWindow : startMenuBar)(config)
        .then(win => new App(win, config));
}

function startNormalWindow(config: Config): Promise<Electron.BrowserWindow> {
    log.debug('Setup a normal window');
    return new Promise<Electron.BrowserWindow>(resolve => {
        const state = windowState({
            defaultWidth: 600,
            defaultHeight: 800,
        });
        const win = new BrowserWindow({
            width: state.width,
            height: state.height,
            x: state.x,
            y: state.y,
            icon: APP_ICON,
            show: false,
            useContentSize: true,
            autoHideMenuBar: true,
            webPreferences: {
                nodeIntegration: false,
                sandbox: true,
                preload: PRELOAD_JS,
            },
        });
        win.once('ready-to-show', () => {
            win.show();
        });
        win.once('closed', () => {
            app.quit();
        });

        if (state.isFullScreen) {
            win.setFullScreen(true);
        } else if (state.isMaximized) {
            win.maximize();
        }
        state.manage(win);

        const toggleWindow = () => {
            if (win.isFocused()) {
                log.debug('Toggle window: shown -> hidden');
                if (IS_DARWIN) {
                    app.hide();
                } else {
                    win.hide();
                }
            } else {
                log.debug('Toggle window: hidden -> shown');
                win.show();
            }
        };

        win.webContents.on('dom-ready', () => {
            log.debug('Send config to renderer procress');
            win.webContents.send('mstdn:config', config);
        });
        win.webContents.once('dom-ready', () => {
            log.debug('Normal window application was launched');
            if (config.hot_key) {
                globalShortcut.register(config.hot_key, toggleWindow);
                log.debug('Hot key was set to:', config.hot_key);
            }
            if (IS_DEBUG) {
                win.webContents.openDevTools({mode: 'detach'});
            }
        });

        const normalIcon = trayIcon(config.icon_color);
        const tray = new Tray(normalIcon);
        tray.on('click', toggleWindow);
        tray.on('double-click', toggleWindow);
        if (IS_DARWIN) {
            tray.setHighlightMode('never');
            app.dock.setIcon(APP_ICON);
        }

        resolve(win);
    });
}

function startMenuBar(config: Config): Promise<Electron.BrowserWindow> {
    log.debug('Setup a menubar window');
    return new Promise<Electron.BrowserWindow>(resolve => {
        const state = windowState({
            defaultWidth: DEFAULT_WIDTH,
            defaultHeight: DEFAULT_HEIGHT,
        });
        const icon = trayIcon(config.icon_color);
        const mb = menubar({
            icon,
            width: state.width,
            height: state.height,
            alwaysOnTop: IS_DEBUG || !!config.always_on_top,
            tooltip: 'Mstdn',
            showDockIcon: true,
            autoHideMenuBar: true,
            useContentSize: true,
            show: false,
            webPreferences: {
                nodeIntegration: false,
                sandbox: true,
                preload: PRELOAD_JS,
            },
        });
        mb.once('ready', () => mb.showWindow());
        mb.once('after-create-window', () => {
            log.debug('Menubar application was launched');
            if (config.hot_key) {
                globalShortcut.register(config.hot_key, () => {
                    if (mb.window.isFocused()) {
                        log.debug('Toggle window: shown -> hidden');
                        mb.hideWindow();
                    } else {
                        log.debug('Toggle window: hidden -> shown');
                        mb.showWindow();
                    }<commit_msg>hide dock icon on menubar mode<commit_after>import * as path from 'path';
import {app, BrowserWindow, globalShortcut, Tray, shell, dialog} from 'electron';
import windowState = require('electron-window-state');
import * as menubar from 'menubar';
import log from './log';
import {Config, Account} from './config';

const IS_DEBUG = process.env.NODE_ENV === 'development';
const IS_DARWIN = process.platform === 'darwin';
const APP_ICON = path.join(__dirname, '..', 'resources', 'icon', 'icon.png');
const PRELOAD_JS = path.join(__dirname, '..', 'renderer', 'preload.js');
const DEFAULT_WIDTH = 340;
const DEFAULT_HEIGHT = 400;

export class App {
    private account: Account;

    constructor(private win: Electron.BrowserWindow, private config: Config) {
        if (config.accounts.length === 0) {
            throw new Error('No account found. Please check the config.');
        }
        this.account = this.config.accounts[0];
    }

    open() {
        this.win.loadURL(`https://${this.account.host}${this.account.default_page}`);
        this.win.webContents.on('will-navigate', (e, url) => {
            if (!url.startsWith(`https://${this.account.host}`)) {
                e.preventDefault();
                shell.openExternal(url);
            }
        });
        this.win.webContents.on('new-window', (e, url) => {
            e.preventDefault();
            shell.openExternal(url);
        });
        this.win.webContents.session.setPermissionRequestHandler((contents, permission, callback) => {
            if (permission !== 'geolocation' && permission !== 'media') {
                // Granted
                callback(true);
                return;
            }

            dialog.showMessageBox({
                type: 'question',
                buttons: ['Accept', 'Reject'],
                message: `Permission '${permission}' is requested by ${contents.getURL()}`,
                detail: "Please choose one of 'Accept' or 'Reject'",
            }, (buttonIndex: number) => {
                const granted = buttonIndex === 0;
                callback(granted);
            });
        });
        this.win.show();
    }
}

function trayIcon(color: string) {
    return path.join(__dirname, '..', 'resources', 'icon', `tray-icon-${
        color === 'white' ? 'white' : 'black'
    }@2x.png`);
}

export default function startApp(config: Config) {
    return (config.normal_window ? startNormalWindow : startMenuBar)(config)
        .then(win => new App(win, config));
}

function startNormalWindow(config: Config): Promise<Electron.BrowserWindow> {
    log.debug('Setup a normal window');
    return new Promise<Electron.BrowserWindow>(resolve => {
        const state = windowState({
            defaultWidth: 600,
            defaultHeight: 800,
        });
        const win = new BrowserWindow({
            width: state.width,
            height: state.height,
            x: state.x,
            y: state.y,
            icon: APP_ICON,
            show: false,
            useContentSize: true,
            autoHideMenuBar: true,
            webPreferences: {
                nodeIntegration: false,
                sandbox: true,
                preload: PRELOAD_JS,
            },
        });
        win.once('ready-to-show', () => {
            win.show();
        });
        win.once('closed', () => {
            app.quit();
        });

        if (state.isFullScreen) {
            win.setFullScreen(true);
        } else if (state.isMaximized) {
            win.maximize();
        }
        state.manage(win);

        const toggleWindow = () => {
            if (win.isFocused()) {
                log.debug('Toggle window: shown -> hidden');
                if (IS_DARWIN) {
                    app.hide();
                } else {
                    win.hide();
                }
            } else {
                log.debug('Toggle window: hidden -> shown');
                win.show();
            }
        };

        win.webContents.on('dom-ready', () => {
            log.debug('Send config to renderer procress');
            win.webContents.send('mstdn:config', config);
        });
        win.webContents.once('dom-ready', () => {
            log.debug('Normal window application was launched');
            if (config.hot_key) {
                globalShortcut.register(config.hot_key, toggleWindow);
                log.debug('Hot key was set to:', config.hot_key);
            }
            if (IS_DEBUG) {
                win.webContents.openDevTools({mode: 'detach'});
            }
        });

        const normalIcon = trayIcon(config.icon_color);
        const tray = new Tray(normalIcon);
        tray.on('click', toggleWindow);
        tray.on('double-click', toggleWindow);
        if (IS_DARWIN) {
            tray.setHighlightMode('never');
            app.dock.setIcon(APP_ICON);
        }

        resolve(win);
    });
}

function startMenuBar(config: Config): Promise<Electron.BrowserWindow> {
    log.debug('Setup a menubar window');
    return new Promise<Electron.BrowserWindow>(resolve => {
        const state = windowState({
            defaultWidth: DEFAULT_WIDTH,
            defaultHeight: DEFAULT_HEIGHT,
        });
        const icon = trayIcon(config.icon_color);
        const mb = menubar({
            icon,
            width: state.width,
            height: state.height,
            alwaysOnTop: IS_DEBUG || !!config.always_on_top,
            tooltip: 'Mstdn',
            autoHideMenuBar: true,
            useContentSize: true,
            show: false,
            webPreferences: {
                nodeIntegration: false,
                sandbox: true,
                preload: PRELOAD_JS,
            },
        });
        mb.once('ready', () => mb.showWindow());
        mb.once('after-create-window', () => {
            log.debug('Menubar application was launched');
            if (config.hot_key) {
                globalShortcut.register(config.hot_key, () => {
                    if (mb.window.isFocused()) {
                        log.debug('Toggle window: shown -> hidden');
                        mb.hideWindow();
                    } else {
                        log.debug('Toggle window: hidden -> shown');
                        mb.showWindow();
                    }
{'fraction_non_alphanumeric': 0.1357760329923071, 'fraction_numerical': 0.002537869775557142, 'mean_word_length': 1.7200172562553926, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 49, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2424739', 'n_tokens_mistral': 3493, 'n_tokens_neox': 3361, 'n_words': 711}