function onAppReady() {
  debugLog('Firing application "ready" event');

  // Create new window
  mainWindow = new BrowserWindow({
    minWidth: 790,
    minHeight: 395,
    width: 1000,
    height: 420,
    resizable: true,
    icon: path.join(__dirname, 'app', 'res', 'icons', 'icon.png'),
    frame: false,
    title: 'Google Assistant Unofficial Desktop Client',
    transparent: true,
    webPreferences: {
      nodeIntegration: true,
      scrollBounce: true,
      devTools: true,
      enableRemoteModule: true,
    },
    backgroundColor: process.platform !== 'darwin' ? '#00000000' : '#00000001',
    alwaysOnTop: true,
  });

  // Store `mainWindow` as global variable
  global.mainWindow = mainWindow;

  debugLog('Created Browser Window');

  // Tray Icon Section

  debugLog('Creating Tray Icon');

  // Set grayscale icon letting the user know
  // that the application is not ready to be launched
  let trayIcon = nativeImage.createFromPath(
    path.join(__dirname, 'app', 'res', 'icons', 'icon_grayscale.png'),
  );

  if (process.platform !== 'win32') {
    debugLog('Setting tray icon size');

    trayIcon = trayIcon.resize({
      height: 16.0,
      width: 16.0,
      quality: 'best',
    });
  }

  debugLog('Configuring tray');

  tray = new electron.Tray(trayIcon);
  tray.setToolTip('Google Assistant Unofficial Desktop Client');
  tray.on('double-click', () => launchAssistant());

  debugLog('Building tray context menu');

  let { assistantHotkey } = assistantConfig;

  if (!assistantHotkey || !isValidAccelerator(assistantHotkey)) {
    assistantHotkey = 'Super+Shift+A';
  }

  setTrayContextMenu(assistantHotkey);

  // SHORTCUT REGISTRATION

  debugLog('Registering Global Shortcut');
  registerAssistantHotkey(assistantHotkey);

  mainWindow.on('will-quit', () => electron.globalShortcut.unregisterAll());

  // 'close' ACTION OVERRIDE: Close to Tray

  mainWindow.on('close', (event) => {
    if (!app.isQuitting) {
      event.preventDefault();

      mainWindow.webContents.executeJavaScript(
        'document.querySelector("body").innerHTML = "";',
      );

      // Close window 100ms after the `body` is emptied
      // to avoid the window from appearing for a fraction of second
      // immediately after showing the assistant window

      setTimeout(() => mainWindow.hide(), 100);
    }

    return false;
  });

  // WINDOW SIZING AND POSITIONING

  debugLog('Setting Assistant window position');
  setAssistantWindowPosition();

  // Load HTML

  debugLog('Loading application in the browser window');

  mainWindow.loadURL(
    url.format({
      pathname: path.join(__dirname, 'app', 'src', 'index.html'),
      protocol: 'file:',
      slashes: true,
    }),
  );

  // HIDE ON START
  // Hidden when assistant is initializing

  debugLog('Hiding window');

  mainWindow.webContents
    .executeJavaScript('document.querySelector("body").innerHTML = "";')
    .then(() => {
      debugLog('Assistant is ready for launch');

      // After the assistant has been initialized
      // set `readyForLaunch` to `true`
      readyForLaunch = true;

      // Reset tray icon to let the user know that
      // application is ready to be launched
      trayIcon = nativeImage.createFromPath(
        path.join(__dirname, 'app', 'res', 'icons', 'icon.png'),
      );

      if (process.platform !== 'win32') {
        trayIcon = trayIcon.resize({
          height: 16.0,
          width: 16.0,
          quality: 'best',
        });
      }

      debugLog('Setting "Ready for launch" tray icon');
      tray.setImage(trayIcon);

      // Do not auto-reveal window if an update is pending
      // to be installed.

      if (shouldAutoInstallUpdate()) {
        debugLog('Supressing window auto-reveal [auto-update on startup]');
        return;
      }

      const shouldRevealWindowOnStart = (
        !assistantConfig['hideOnFirstLaunch']
        || flags.appVersion !== `v${app.getVersion()}`
        || isFirstTimeUser
      );

      if (shouldRevealWindowOnStart) {
        if (!openedAtLogin) {
          if (!assistantConfig['hideOnFirstLaunch']) {
            debugLog('Revealing assistant ["hideOnFirstLaunch" = false]');
          }
          else if (isFirstTimeUser) {
            debugLog('Revealing assistant [first-time user]');
          }
          else {
            debugLog('Revealing assistant [recently updated]');
          }

          launchAssistant();
        }
      }
      else if (assistantConfig['notifyOnStartup']) {
        // Notify user when app is ready
        displayNotification({
          title: 'Google Assistant',
          body: [
            'Google Assistant is running in background!',
            `Press ${assistantConfig.assistantHotkey
              .split('+')
              .map(getNativeKeyName)
              .join(' + ')
            } to launch`,
          ].join('\n\n'),
          actions: [
            {
              text: 'Launch',
              type: 'button',
              onClick: () => launchAssistant(),
            },
            {
              text: 'Dismiss',
              type: 'button',
              onClick: () => {},
            },
          ],
          onNotificationClick: () => launchAssistant(),
        });
      }

      // Send updater status to renderer process
      updater.sendStatusToWindow();
    });

  mainWindow.hide();

  // FLOATING WINDOW

  debugLog(
    `Setting window float behavior = "${assistantConfig['windowFloatBehavior']}"`,
  );

  if (assistantConfig['windowFloatBehavior'] === 'always-on-top') {
    mainWindow.setAlwaysOnTop(true, 'floating');
  }

  // IPC LISTENERS

  ipcMain.on('relaunch-assistant', (_, args) => {
    launchAssistant(args);
  });

  ipcMain.on('get-assistant-win-launch-args', (event) => {
    // eslint-disable-next-line no-param-reassign
    event.returnValue = assistantWindowLaunchArgs;
  });

  ipcMain.on('get-userdata-path', (event) => {
    // eslint-disable-next-line no-param-reassign
    event.returnValue = app.getPath('userData');
  });

  ipcMain.on('quit-app', () => {
    quitApp();
  });

  ipcMain.on('display-notification', (_, opts) => {
    displayNotification(opts);
  });

  ipcMain.on('display-dialog', (event, opts) => {
    // eslint-disable-next-line no-param-reassign
    event.returnValue = displayDialogMain(opts);
  });

  ipcMain.handle('display-async-dialog', async (_, opts) => {
    const result = await displayAsyncDialogMain(opts);
    return result;
  });

  ipcMain.handle('display-async-open-dialog', async (_, opts) => {
    const result = await displayAsyncOpenDialogMain(opts);
    return result;
  });

  ipcMain.on('get-allow-close-on-blur', (event) => {
    // eslint-disable-next-line no-param-reassign
    event.returnValue = global.allowCloseOnBlur;
  });

  ipcMain.on('set-allow-close-on-blur', (event, value) => {
    global.allowCloseOnBlur = value;

    // eslint-disable-next-line no-param-reassign
    event.returnValue = undefined;
  });

  ipcMain.on('update-first-launch', () => {
    global.firstLaunch = false;
  });

  ipcMain.on('update-did-launch-window', () => {
    didLaunchWindow = true;
  });

  ipcMain.on('update-config', (_, config) => {
    assistantConfig = config;

    // Set `shouldAutoDownload` property for updater
    updater.shouldAutoDownload = assistantConfig.autoDownloadUpdates;
  });

  ipcMain.on('update-flags', (_, updatedFlags) => {
    flags = updatedFlags;
  });

  ipcMain.on('set-assistant-window-position', (_) => {
    setAssistantWindowPosition();
  });

  ipcMain.on('update-hotkey', (_, hotkey) => {
    updateHotkey(hotkey);
  });

  ipcMain.on('minimize-window', (event) => {
    minimizeWindow();

    // eslint-disable-next-line no-param-reassign
    event.returnValue = undefined;
  });

  ipcMain.on('restart-fallback', () => {
    restartInFallbackMode();
  });

  ipcMain.on('restart-normal', () => {
    restartInNormalMode();
  });

  updater = new UpdaterService(mainWindow, app, assistantConfig.autoDownloadUpdates);

  // Initialize Updater Service
  updater.initializeUpdater(() => {
    setTrayContextMenu(assistantConfig.assistantHotkey, true);
    mainWindow.webContents.send('update:updateReady');

    // Auto-install update on next startup
    if (shouldAutoInstallUpdate()) {
      displayNotification({
        title: 'Installing update',
        body: 'Assistant is installing the update and will restart once done',
      });

      setTimeout(() => {
        updater.installUpdateAndRestart();
      }, 500);
    }
    else {
      displayNotification({
        title: 'Update Ready',
        body: 'Update has been downloaded. Click to install the update and restart app...',
        onNotificationClick: () => {
          if (!mainWindow.isVisible()) launchAssistant();
          else mainWindow.focus();
        },
      });
    }
  });
}
Function invoked when the application is ready to start.