Обновление библиотеки SPPermission и хейтер

— »Какая-то библиотека, кто-то обновил… Хейтер тут причем? Почему мне, отличному разработчику, нужно тратить время на эту статью? »

мог подумать ты, мой дорогой друг. Не нужно тратить время. Это просто вечернее чтиво с долей несмешных юморесок. Текст будет о библиотеке RequestPermission и о её загадочном авторе.
Начнем с главного — ребрендинг! Библиотека переименована в SPPermission. Уж не знаю, в этом дело или нет, но после изменения названия уже как вторую неделю висит в топе GitHub. Да-да, такой топ есть, он условный, но все же интересные проекты там можно найти. Автор (загадочная персона), обновил банеры на странице проекта, описание, огромный раздел донат вставил. Жадный какой!

Но все же перейдем к самому проекту:

g8b4pbkznhzv5e-fhz_rifcodpo.gif

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

Устанавливаем


Можно просто перетянуть исходники к себе в проект, это папка структурированых файлов. А можно не страдать ерундой встроить библиотеку при помощи СocoaPods. Плюсы и минусы рассказывать не буду, не об этом статья. Добавляем в pod файл строку:

pod 'SPPermission'


и обновляем зависимости. Скорее всего, это самый сложный шаг из всех предстоящих)

Используем


Если вы просто перетянули файлы в проект, модуль SPPermission уже доступен. Если же вы не страдали ерундой использовали СocoaPods, то стоит импортировать в контроллер библиотеку:

import SPPermission


Теперь в функции viewDidAppear вызовем следующую конструкцию:

override func viewDidAppear(_ animated: Bool) {
      super.viewDidAppear(animated)

      SPPermission.Dialog.request(
            with: [.camera, .calendar, .notification], 
            on: self
      )
}


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

Кастомизация


Если ты, дорогой друг, работал с таблицами или коллекциями, то слова Delegate и DataSource не испугают. А если немного помешан на паттернах, то даже вскрикнешь:

— »Ого! Протоколоориенторованный подход! »

Вот видишь! Видишь? А я же говорил что будет не смешно. Но раз дочитал до этой строки, то пойдем дальше.

Начнем с протокола SPPermissionDialogDataSource, он будет отвечать за кастомизацию диалогового окна и позволит более лояльно интегрировать библиотеку в проект. Посмотрим на параметры:

@objc public protocol SPPermissionDialogDataSource: class {

    @objc optional var dialogTitle: String { get }
    @objc optional var dialogSubtitle: String { get }
    @objc optional var dialogComment: String { get }
    @objc optional var allowTitle: String { get }
    @objc optional var allowedTitle: String { get }
    @objc optional var bottomComment: String { get }
    @objc optional var showCloseButton: Bool { get }
    @objc optional func name(for permission: SPPermissionType) -> String?
    @objc optional func description(for permission: SPPermissionType) -> String?
    @objc optional func image(for permission: SPPermissionType) -> UIImage?
}


Если честно, не вижу смысла останавливаться на каждом, так как названия у них говорящие. Разберем пару неоднозначных: bottomComment и showCloseButton.

Первый параметр отвечает за комментарий под диалоговым окном, туда можно поместить, к примеру, подсказку »Смахните чтобы закрыть»:

o3juolykpylxcrkpb1jumil_t5s.jpeg

Второй параметр, showCloseButton, отвечает за кнопку закрыть в правом верхнем углу экрана. Картинка с примерном у меня тоже есть:

dx8zva68cc4b6zwllgs5yk95ps0.jpeg

Некоторые функции разрешают вернуть nil, это необходимо, если не требуется кастомизировать все заголовки / иконки или текста. Достаточно вернуть nil, чтобы оставить значение по умолчанию:

func description(for permission: SPPermissionType) -> String? {

      if permission == .calendar {
            return "Календарь"
      } еlse {
            return nil
      } 
}


Остается передать в основную конструкцию объект DataSource:

SPPermission.Dialog.request(
    with: [.camera, .calendar, .microphone, .notification],
    on: self,
    dataSource: self
)


Делегат


Он позволяет отследить некоторые события. Заглянем в протокол:

@objc public protocol SPPermissionDialogDelegate: class {
    
    @objc optional func didHide()
    @objc optional func didAllow(permission: SPPermissionType)
}


Мда, не густо… А хотя, что еще надо?) Объяснять при каких событиях будут вызваны функции, думаю, не стоит. Названия говорящие. Обращаю внимание — делегат нужно не забыть указать:

SPPermission.Dialog.request(
    with: [.camera, .calendar, .microphone, .notification],
    on: self,
    delegate: self
    dataSource: self
)


Разрешения


ogowqtraw3cz4vrwpjjupu4vmuo.jpeg

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

Плюшки


Стоит обратить внимание на полезную функцию:

func isAllow(_ permission: SPPermissionType) -> Bool


Она позволит узнать дал ли пользователь разрешение. Для повышения лояльности рекомендуется запрашивать разрешения не пачкой, а перед использованием. И не более 3-ех! Хотя мне трудно придумать ситуацию где нужно больше) Использовать так:

let isAvailableCamera = SPPermission.isAllow(.сamera)


Зачем было обновлять


Старая версия выглядела так, и возможно еще год назад она была ничего:

2701d00370d74987ae03348cc59d24b0.gif

Собственно год я ее не обновлял (да ладно, не делайте вид что не поняли что я автор библиотеки), а совсем недавно, получив письмо… хотя об этой истории давайте чуть позже. Мы тут серьезными делами занимаемся!

Архитектура


Примерно год назад я написал статью, в которой прямо громил любителей неоправданного использования архитектуры. Но так думал только я, и основной посыл был не услышен. Мое стремление упрощать за этот год не остановилось. Когда я задумал редизайн, то понял, проект придется переписывать целиком. Это какая-то буровая установка с возможностью слушать радио, резать овощи и обогреватель на пол ставки. Я это увидел спустя год! Сейчас мне кажется было глупо писать эту статью, имея такой сложный пример. Наверное, через ещё один год, я сделаю всё ещё проще. Посмотрим)

Так что за история?


Туториал собсна закончился и мы переходим к болтовне. Несколько недель назад я получил письмо, с просьбой объяснить как работает библиотека. Это был странный вопрос, а так как я библиотеку забросил, то просто ответил шаблонным:

— »Дорогой друг, я не поддерживаю библиотеку сейчас, не имею свободного времени. Всего хорошего»

Вот прямо так и написал, только на забугорском. И забыл. Зайдя с мака, я увидел около десятка!!! сообщений в папке спам. Ну все, явно какой-то портал разошелся, сейчас как отпишусь от их рассылки! А нннет… Мне писал тот же парень, только в этот раз в гневе. В письмах я узнал что я не автор библиотеки (поэтому и не могу подсказать), узнал что такие как я это самые ужасные люди (и нам нужно запретить регистрацию на GitHub), узнал что я хочу много денег за свою никчемную работу. Денег? На старой странице небыло даже формы доната. Но я понял суть, человек был просто зол.

Я решил помочь, но не из-за доброты — мне было безумно интересно что такое невероятное было нужно кастомизировать, что спровоцировало огромную волну гнева. Оказалось, он искал метод, который вызывается при закрытии диалогового окна. Моему смеху сквозь слезы небыло предела! Делегат был описан в первой же версии.

История грустная, но дальше еще грустнее! Да-да! Я подробно описал лично ему как использовать делегаты, так сказать общий курс. Не упустил возможности съехидничать сказать что все это было на главной странице проекта с самого начала. Ответ я получил. Но плакать захотелось еще больше:

— »Я недавно начал программировать и не хочу разбираться в документациях. До свидания»

Я долго смеялся.

Заканчиваем


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



Всем успешных миграций на новый Swift!

© Habrahabr.ru