Я обожаю, когда в таск‑менеджерах можно быстро создавать задачи, не открывая окно приложения. К сожалению такой функции нет в ПланФиксе, которым мы пользуемся с командой. Приходится каждый раз открывать браузер и искать нужную вкладку, чтобы что‑то записать — и это отвлекает от текущей работы.

Вернее, такой функции в ПланФиксе не было раньше. Теперь есть. Рассказываю, как я настроил быстрое создание задач без сворачивания текущего окна.

Зачем это все

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

В Things есть прекрасное решение — быстрое добавление задач. Нажимаешь хоткей → поверх текущего окна появляется маленькое окошко → пишешь туда задачу → энтер → все, задача улетела во «Входящие». Занимает всего пару секунд.

А потом, когда будет время, можно вернуться к ней, расписать подробнее, перенести в нужный проект и так далее.

Можно без проблем создавать задачки во время созвонов с клиентами, планерок с командой, интервью с клиентами. Или во время игры в Total War Warhammer — бывает, обстреливаешь армию гоблинов из местеметов и резко вспоминаешь что‑то важное.

В TickTick подобную задачу решают готовые шорткаты для macOS в настройках. Установил — и тоже создаешь задачи по хоткею.

А в ПланФиксе ничего подобного нет. Только Телеграм‑бот — а это надо открыть Телеграм, найти в нем бота, ввести команду /task… Долго.

При этом сам ПланФикс мне нравится, уходить с него не собираюсь, поэтому решил что‑нибудь придумать.

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

Добавление задач через почту

В ПланФиксе можно создать виртуальный имейл‑адрес, типа adress@workspace.planfix.com

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

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

Сделал отдельный ящик для отправки писем и пошел думать, как их туда быстро отправлять.

Воркфлоу в приложении Alfred

Я уже давно пользуюсь Alfred и считаю его одним из самых полезных приложений для macoS. Там есть история буфера обмена, сниппеты для быстрой отправки шаблонных сообщений и возможность делать свои мини‑приложения — воркфлоу.

Их можно запускать по хоткею или через командную строку. Например, у меня есть воркфлоу для сокращения ссылок: выделил ссылку → нажал кнопку → ссылка сократилась через tiny.url. Очень удобно.

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

Я набросал первую часть воркфлоу:

  • Запускаем через командную строку по ключевому слову «з» (задача).

  • Пишем заголовок задачи, сохраняем его в переменную.

  • Затем описание задачи, тоже сохраняем. Можно не указывать, а просто нажать энтер и пропустить этап.

  • Указываем дедлайн, сохраняем. Тоже можно пропустить и создать задачу без дедлайна.

Альтернативный способ запуска — выделить какой‑то текст и нажать ⌃+⌘+P. Выделенный текст автоматически станет описание задачи, останется указать название задачи и дедлайн.

Дедлайн можно указать одним из двух способов.

  • Пишем дату числами без знаков препинания, например, 25 03 — 25 марта. Можно вводить не только дату, но и время. 25 03 12 30 — это 25 марта, полпервого. А 25 03 12 — это 25 марта, 12 часов ровно.

  • Выбираем одно из готовых ключевых слов: сегодня, завтра, через час, через неделю, через месяц и так далее.

Вот что получилось.

Зацикливать воркфлоу нельзя, поэтому я сделал возможность один раз переключиться между двумя режимами задания времени через ⌘+enter, если вдруг выбрал не тот.

Увы, блоков с отправкой писем в конструкторе нет, поэтому дальше на ноукоде не уедешь.

Скрипт отправки письма на AppleScript

Ни одного языка программирования я не помню, поэтому особой разницы, на нем писать код, для меня не было. Все равно надо разбираться в синтаксисе с нуля. Загуглил, как отправлять письма через Alfred, увидел совет, что это можно делать через AppleScript — его и выбрал.

На входе в скрипт подаются данные: Заголовок | Описание задачи время

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

Вот что у меня получилось:

on alfred_script(q)
  set input to q
  set the text item delimiters to "|"
  set {TheName, TheTask} to {text item 1, text item 2} of the input
  tell application "Mail"
    set m to make new outgoing message with properties {sender:"ХХХ@gmail.com", subject:TheName, content:TheTask}
    tell m
      make new to recipient with properties {name:"someone",address:"ХХХ@ХХХ.planfix.ru"}
      send
    end tell
  end tell
end alfred_script

Протестировал, все работает, письма улетают в ПланФикс, он создает задачу. Тема письма — название задачи, тело письма — описание.

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

Распознавание даты и времени на AppleScript

Напомню, первый способ указания дедлайна задачи — набор чисел через пробел ДД ММ чч мм. При этом часы и минуты опциональные, их можно указать, а можно и нет.

Сначала я через готовый блок в Alfred заменил пробелы на слэши «/». Если честно, сейчас сам не понимаю, зачем, можно было работать и с пробелами. Но тогда мне это показалось логичным.

Итого на входе в скрипт подаются данные в формате ДД/ММ/чч/мм.

Что надо сделать:

  1. Понять количество чисел на входе и решить, нужны ли нам часы и минуты или нет.

  2. Разделить текстовую строку на отдельные переменные: месяц, день, часы, минуты.

  3. Понять, какой указывать год: текущий или следующий. Решил так — если дата больше сегодняшней, то и год будет текущий. Если дата раньше сегодняшней, то на текущий год эту задачу планировать бесполезно, выбираем следующий.

  4. Собрать все обратно в строку, которую передадим в письмо.

Заодно я решил добавить всякие проверки, чтобы нельзя было задать глупое время в духе: 43 июля 60 часов 993 минуты. Если вводим какие‑то глупости, скрипт завершается, и задача создается без дедлайн.

И еще одна проверка — если чисел на входе меньше 2 или больше 4, данные тоже считаем бракованными.

Вот что получилось:

on run argv

  set theQuery to item 1 of argv
  set the text item delimiters to "/"
  set theLength to length of words of theQuery
  set NeedHours to 0
  set TheHours to 0
  set TheMinutes to 0
  
  if theLength < 2 then return " "
  if theLength = 2 then set {TheDay, TheMonth} to {text item 1, text item 2} of the theQuery
  
  if theLength = 3 then
    set {TheDay, TheMonth, TheHours} to {text item 1, text item 2, text item 3} of the theQuery
    set TheMinutes to "00"
  	set NeedHours to 1
  end if

  if theLength = 4 then
    set {TheDay, TheMonth, TheHours, TheMinutes} to {text item 1, text item 2, text item 3, text item 4} of the theQuery
	set NeedHours to 1
  end if

  if theLength > 4 then return " "

  if TheMonth > 12 then return " "
  if TheHours > 23 then set NeedHours to 0
  if TheMinutes > 59 then set NeedHours to 0

  set currentDate to (current date)
  set currentMonth to month of currentDate as integer
  set TheMonth to TheMonth as integer
  set currentYear to year of currentDate
  set currentDay to day of currentDate
  set TheYear to 0

  if TheMonth > currentMonth then
  	set TheYear to currentYear
  end if

  if TheMonth = currentMonth then
  	if TheDay < currentDay then
  		set TheYear to currentYear + 1
  	else
  		set TheYear to currentYear
  	end if
  end if

  if TheMonth < currentMonth then set TheYear to currentYear + 1

  set leap to (TheYear mod 4 = 0 and TheYear mod 100 ≠ 0 or TheYear mod 400 = 0) as integer
  set numberOfDaysInMonth to {31, 28 + leap, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
  if TheDay > text item TheMonth of the numberOfDaysInMonth then return " "

  if NeedHours = 0 then
	set theDate to ("[[[" & TheDay & "/" & TheMonth & "/" & TheYear & "]]]")
  else
    set theDate to ("[[[" & TheDay & "/" & TheMonth & "/" & TheYear & " <&%#> " & TheHours & ":" & TheMinutes & "]]]")
  end if

  return theDate

end run

Кусочек кода с проверкой количества дней в месяце, включая февраль в високосные и обычные года, я придумал не сам, а где‑то нашел.

Протестировал, все работает. Если вводим только месяц и день, скрипт выдает дату в формате: [[[ДД/ММ/ГГ]]].

Если добавляем часы и минуты, то [[[ДД/ММ/ГГ <&%#> чч:мм]]].

Потом мы эту дату спарсим в самом ПланФиксе с помощью наших [[[скобочек]]] и метки времени <&%#>. А пока что разберемся с заранее заготовленными ключевыми словами: сегодня, завтра и так далее.

Расчет времени через Х часов или дней от текущего на AppleScript

Вот какой набор ключевых слов я для себя написал: сегодня, завтра, через 3 дня, через неделю, через месяц, через час, через 3 часа, сегодня вечером (в 20:00).

При выборе одного из вариантов Alfred передает в скрипт определенное значение переменной. Я не стал заморачиваться и просто передавал числа от 0 до 7.

Скрипт должен взять текущие дату и время и добавить к ним определенное количество часов и дней.

Сложнее всего было с месяцем — AppleScript категорически отказывался вычислять «сегодня + 1 месяц», поэтому пришлось переводить месяцы в числа, складывать их и делать проверку «если сейчас 30 января и мы добавляем месяц, то должно получиться 28 февраля, а не 30».

В случае с «сегодня вечером» сделал так: если сейчас меньше 20:00, то ставим задачу на 20:00. Если больше, то просто кидаем ее на завтра без определенного времени.

Вот что получилось:

on run argv

  set theQuery to item 1 of argv
  set currentDate to (current date)
  set currentHours to hours of currentDate as integer
  set NeedHours to 0
  set theDate to 0
  set haveMonth to 0
  if theQuery = "0" then
    set theDate to currentDate
  end if

  if theQuery = "1" then
	set theDate to currentDate + 1 * days
  end if

  if theQuery = "2" then set theDate to currentDate + 3 * days

  if theQuery = "3" then set theDate to currentDate + 7 * days
  
  if theQuery = "4" then
	set currentMonth to month of currentDate as integer
	set currentYear to year of currentDate as integer
	set TheDays to day of currentDate as integer
	if currentMonth = 12 then
    	set TheYear to currentYear + 1
		set TheMonth to 1
	else
		set TheYear to currentYear
		set TheMonth to currentMonth + 1
	end if
    set leap to (TheYear mod 4 = 0 and TheYear mod 100 ≠ 0 or TheYear mod 400 = 0) as integer
    set numberOfDaysInMonth to {31, 28 + leap, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
    if TheDays > text item TheMonth of the numberOfDaysInMonth then set TheDays to text item TheMonth of the numberOfDaysInMonth
  	set theDate to ("[[[" & TheDays & "/" & TheMonth & "/" & TheYear & "]]]")
	return theDate	
  end if

  if theQuery = "5" then
	set theDate to currentDate + 1 * hours
	set NeedHours to 1
  end if

  if theQuery = "6" then
	set theDate to currentDate + 3 * hours
	set NeedHours to 1
  end if

  if theQuery = "7" then
	if currentHours > 19 then
		set theDate to currentDate + 1 * days
	else
		set theDate to currentDate
		set hours of theDate to 20
		set NeedHours to 1
	end if
  end if

  set TheMonth to month of theDate as integer
  set TheDays to day of theDate as integer
  set TheYear to year of theDate as integer

  if NeedHours = 1 then
  	set TheHours to hours of theDate as integer
  	set TheMinutes to minutes of theDate as integer
    set theDate to ("[[[" & TheDays & "/" & TheMonth & "/" & TheYear & " <&%#> " & TheHours & ":" & TheMinutes & "]]]")
  else
  	set theDate to ("[[[" & TheDays & "/" & TheMonth & "/" & TheYear & "]]]")
  end if

  return theDate

end run

Как и прошлый скрипт, выдает дату в формате [[[ДД/ММ/ГГ]]] или дату со временем в формате [[[ДД/ММ/ГГ <&%#> чч:мм]]]

Парсим письмо в ПланФиксе

Время распознается и подставляется в описание задачи, письма отправляются. Осталось самое простое — настроить парсинг в ПланФиксе, который будет искать метку даты и времени и подставлять ее в поле «дата планируемого завершения».

Делаем 2 правила.

Первое — для дат без времени. Находим дату, сохраняем в переменную, затем эту переменную подставляем в «дату планируемого завершения».

Затем подключаем меня в качестве исполнителя и постановщика задачи и отправляем автоматическое сообщение от робота, что это задача из Альфреда, она может быть заполнена не до конца.

Второе правило — для дат со временем. Работает также, только находим 2 переменные: дату и время — а потом подставляем их в «дату планируемого завершения».

Все! Теперь я вызываю командную строку Альфреда через ⌘+space → пишу «з» → название задачи → описание, если надо → дату, если надо → в ПланФиксе создается задача.

Или выделяю нужный мне текст → нажимаю ⌃+⌘+P → пишу название задачи → дату, если надо → создается задача с выделенным текстом в описании.


Если вы вдруг пользуетесь Альфредом и ПланФиксом и хотите себе такую же штуку, я выложил готовое воркфлоу на гуглдиске (Гитхабом не пользуюсь, сорян):

→ Скачать воркфлоу для Alfred

Подозреваю, то же самое можно сделать с помощью шорткатов в macOS — и даже Альфред не потребуется.


Спасибо, что дочитали статью, надеюсь, вам было интересно. Мне, например, было интересно размять мозги, разобраться в Applescript и сделать такую штуку. Успехов!

Комментарии (0)