Возвращение печально известного помощника Microsoft Word в 2019 году

Введение

Когда я учился в третьем классе, в моей семье появился первый компьютер. Он состоял из двух бежевых коробок, одна стояла на полу, другая на столе. Если я нажму большую красную кнопку внизу, компьютер включится, и я смогу играть в некоторые неподходящие для моего возраста игры, такие как Quake 3 и Carmageddon. В других случаях, насколько я помню, я открывал Microsoft Office, чтобы поиграть с Word Art . Там я встретил Clippy , странную заколку-невидимку, которая пыталась подсказать мне, как написать письмо, хотя все, что я хотел, это увидеть красивые текстовые эффекты. Если бы я был постарше и пытался выполнять какую-то настоящую работу, я бы, вероятно, воспринял его как надоедливого, но, поскольку я просто изучал великолепный мир домашних компьютеров, он показался мне забавным.

Через несколько лет моего друга не стало, и я быстро забыл о нем. Перенесемся в сегодняшний день, некоторые memes напомнили мне о нем. Возникла искра, за которой последовала идея — я должен воссоздать его как отдельное настольное приложение!

Но ждать! Это довольно глупо, зачем кому-то делать такие вещи? Чтобы повеселиться, изучая что-то, конечно!

Я не буду здесь описывать все подробности, не стесняйтесь задавать вопросы, возможно, я даже добавлю эту информацию в статью :) В конце статьи будет ссылка на репозиторий.

Технологии выбора

Об этом можно сделать вывод из названия этой статьи, но нам нужны некоторые сопутствующие технологии, чтобы это произошло, но не настолько, чтобы сделать это ошеломляющим:

  • Electron
  • React
  • TypeScript
  • Webpack

Мы могли бы отказаться от TypeScript, поскольку он требует одного дополнительного шага — компиляции его в JavaScript, тем самым добавляя еще одну зависимость, а именно Webpack, но я твердо верю в силу TypeScript.

Через несколько месяцев после того, как я все забыл о проекте, это поможет мне понять, что происходит. Во время разработки я буду намного быстрее замечать глупые ошибки и делать базу кода более приятной для чтения и работы.

Я сделал базовую настройку с основными технологиями, которые можно найти здесь. Не стесняйтесь делать с ним все, что пожелаете.

Электрон?

Это фреймворк для разработки кроссплатформенных настольных приложений с использованием стека технологий веб-разработчика: JavaScript, HTML и CSS.

Как это достигается? Каждое созданное приложение имеет встроенный Chromium. Единственным существенным недостатком этого является то, что даже самые простые приложения будут весить как минимум около 80 МБ, а производительность будет ниже, чем у нативного приложения. Это не большая цена, учитывая, что вы можете использовать все технологии, которые вы уже знаете.

Даже если вы только начинаете, это делает JavaScript очень заманчивым языком для изучения, так как вы можете попробовать свои силы в самых разных областях.

Я также нашел документацию очень полезной, вы можете найти ее здесь.

Давайте сделаем один маленький шаг назад

Прежде чем мы перейдем непосредственно к Clippy , немного основной информации о Electron .

Он имеет два важных процесса:

  • процесс main, который создает все приложение с графическим интерфейсом и управляет его жизненным циклом, он создает render процессов в Browser Window
  • процесс render, который отображает ваш графический интерфейс со всей его логикой

Думаю, этого достаточно, чтобы начать пачкать руки.

Некоторые требования, чтобы избежать расползания функций

Я представлял себе, что наш Clippy — это постоянное приложение, которое при сворачивании прячется в трее. Чтобы закрыть его, пользователь должен использовать трей. Он должен постоянно раздражать.

Окно нашего приложения не имеет рамки и прозрачно.

Что касается дизайна, я действительно хотел сделать его как можно ближе к оригиналу, но после некоторых исследований вскоре понял, что все ресурсы, которые я могу найти, имеют плохое разрешение. Чтобы сделать его действительно выделяющимся, мне понадобилась бы помощь графического дизайнера, поэтому я позволил себе некоторые вольности здесь и там.

Теперь о его полезности. Он мог рассказывать анекдоты или какие-то другие случайные сообщения, я чувствовал, что ему нужна интерактивность. Через gooogling я нашел очень хороший и бесплатный API-интерфейс для викторин — https://opentdb.com/, который идеально подходил для всех задач. Он достанет вас, если вы зададите простые вопросы!

Полный поток приложений:

  1. приложение запущено
  2. пользователя спрашивают, хочет ли он ответить на вопрос
  3. если ответ yes , задайте вопрос
  4. после того, как пользователь ответил на вопрос, попросить пройти еще один раунд или свернуть
  5. если ответ no или если пользователь предпочитает не отвечать, свернуть приложение
  6. через некоторое время разверните приложение и вернитесь к шагу 2.
  7. пользователь может убить приложение только через иконку в трее

Убрать рамку и сделать ее прозрачной

Этот шаг очень прост, так как он настраивается в файле процесса main:

mainWindow = new BrowserWindow({
    height: 400,
    width: 500,
    frame: false,      // this
    transparent: true, // and that
    webPreferences: {
        nodeIntegration: true
    },
    resizable: false,
    alwaysOnTop: true  // this as well
});

Теперь есть проблема, без рамки мы не можем перемещать окно, это можно решить с помощью некоторого CSS , мы будем использовать его позже.

-webkit-app-region: drag;

Создание лотка

Electron имеет встроенную поддержку для этого, нам снова нужно немного поработать с файлом mainprocess, сначала с настройкой значка. Это должно быть вверху, перед функцией createWindow.

// Importing files, so that webpack copies them
const trayImg = require("../resources/images/icon.png");
const nativeIcon = nativeImage.createFromPath(
    path.join(__dirname, "src/resources/images/icon.png")
);

И внутри функции createWindow:

tray = new Tray(nativeIcon);
const contextMenu = Menu.buildFromTemplate([
    {
        label: "Summon Clippy",
        click: function () {
            mainWindow.show();
        },
    },
    {
        label: "Hurt Clippy",
        click: function () {
        mainWindow.destroy();
            app.quit();
        },
    },
]);
tray.setToolTip("Clippy");
tray.setContextMenu(contextMenu);

Связь между main и нашим tenderer

Мы хотим иметь возможность минимизировать наше приложение, у Browser Window есть такой метод, хотя он недоступен из нашего rendered процесса.

Пакет electron дает нам два объекта, один для использования в main , другой в renderer . Соответственно ipcMain и ipcRenderer работают как event listeners .

Имея под рукой нашу задачу минимизации, нам нужно отправить событие из нашего renderer в main , это можно использовать при нажатии кнопки:

ipcRenderer.send("MINIMIZE");

А в нашем main нам нужно прослушать это событие и что-то с ним сделать:

ipcMain.on("MINIMIZE", () => {
    mainWindow.hide();
});

Это нужно сделать внутри функции createWindow нашего процесса main.

Мы также можем отправить некоторые параметры:

ipcRenderer.send("DO_SOMETHING", {
    param: "minimize"
});

В этом процессе приложения main я отправляю некоторую конфигурацию из файла, renderer отправляет resize событий, чтобы он выглядел более компактным, если меньше текста.

Создание графического интерфейса

Я выбрал React, так как он мне наиболее удобен. Vue , Angular тоже могут быть хорошими вариантами. Вы также можете сделать это без фреймворка, если вы достаточно смелы.

Я хотел, чтобы это было как можно проще, поэтому я использовал простое состояние React без библиотеки управления состоянием, хотя при желании вы можете легко добавить ее в базовую настройку.

Остальная часть приложения состоит из нескольких компонентов реагирования, составляющих интерфейс, тайм-ауты и интервалы для управления логическим потоком приложений, и это все. Не забудьте очистить тайм-ауты и интервалы!

Вывод

Это была забавная поездка, делать что-то несколько забавное, одновременно узнавая что-то о разработке настольных приложений с помощью JavaScript . Надеюсь, вам было интересно, мне очень понравилось это делать :)

Есть одна ошибка, когда прозрачная часть приложения становится черной, обычно это происходит, когда приложение частично перетаскивается за пределы экрана и с ним взаимодействуют, пока не знаю, как это исправить.

Полученный проект можно найти здесь, можете делать с ним что угодно.