Prática 1: Incluindo a Interface para Configurar Notificações

Assista e acompanhe a prática em sala dos exercícios "Incluindo a Interface para Configurar Notificações". Execute as instruções conforme a apresentação.

Exercício 1. Incluindo a Seleção dos Dias da Semana

1.1. Abrir o arquivo Main.Storyboard e localizar o View Controller de Formulário de Atividade

1.2. Duplicar a seção de Repetições

Duplicar a seção de repetições do Table View e posicioná-la abaixo da seção de Limite de Tempo.

1.3. Modificar as propriedades da seção

Modificar as propriedades da seção conforme abaixo:

  • Rows: Manter 4
  • Header: Lembrete
  • Foster: Escolha os dias da semana e o horário em que você deseja ser notificado através da central de notificações de seu dispositivo.

1.4. Modificar os Labels da Seção

Modificar os Labels de acordo:

  • Label Medir Repetições modificar para Habilitar Notificação
  • Label Quantidade de Repetições modificar para Dias
  • Label 100 modificar para Nenhum

1.5. Excluir a terceira célula

1.6. Duplicar a segunda célula

1.7. Modificar os labels da terceira célula

Modificar os Labels de acordo:

  • Label Dias para Horário da Notificação
  • Label Nenhum para 00:01

1.8. Modificar a propriedade Selection da Segunda e da Terceira Célula para Default

1.9. Reconfigure a quarta célula

Excluas todos os componentes da quarta célula. Altere a propriedade Row Height da célula para 162.

1.10. Desenhe e configure o Date Picker

Desenhe um UIDatePicker centralizado na célula e configure suas constraints para espaçamento 0 em todas as direções. Modifique suas propriedades para:

  • Mode: Time
  • Interval: 1 minute
  • Date: Current Date

Exercício 2. Acrescentando as Funcionalidades da Interface

2.1. Abrir o arquivo Main.Storyboard e localizar o View Controller de Formulário de Atividade

2.2. Crie os Outlets para os componentes desenhados

Crie os Outlets para os novos componentes conforme o código abaixo:

@IBOutlet weak var remindersSwitch: UISwitch!
@IBOutlet weak var reminderDaysLabel: UILabel!
@IBOutlet weak var reminderTimePickerCell: UITableViewCell!
@IBOutlet weak var reminderTimeLabel: UILabel!
@IBOutlet weak var reminderTimePicker: UIDatePicker!

2.3. Crie o Outlet Collection para as Células da Seção de Lembretes

Crie o Outlet Collection para as 3 últimas células da seção de reminders conforme o código abaixo:

@IBOutlet var remindersOptionsCells: [UITableViewCell]!

2.4. Adicione o método para ajustar a visibilidade das células

Abaixo do método setTimeLimitVisibility: inclua o método abaixo:

/// Esconde ou exibe as células das opções de lembretes
func setRemindersVisibility(hidden: Bool) {
    self.cells(self.remindersOptionsCells, setHidden: hidden)
    if hidden {
        self.cell(self.reminderTimePickerCell, setHidden: hidden)
    }
    self.reloadDataAnimated(true)
}

2.5. Inclua o Action Method para o Switch de Lembretes

Inclua o Action Method para o Switch de Lembretes conforme o código abaixo:

@IBAction func remindersSwitched(sender: UISwitch) {
    self.setRemindersVisibility(!sender.on)
}

2.6. Atualize o Código do Método tableView:didSelectRowAtIndexPath:

Atualize o código do método conforme o código abaixo:

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    let indexPathT = (indexPath.section, indexPath.row)
    switch indexPathT {
    case (3, 1):
        let cell = tableView.cellForRowAtIndexPath(indexPath) as TimeLimitViewCell
        cell.delegate = self
        cell.becomeFirstResponder()
    case (4, 2):
        let hidden = !self.cellIsHidden(self.reminderTimePickerCell)
        self.cell(self.reminderTimePickerCell, setHidden: hidden)
        self.reloadDataAnimated(true)
    case (5, 0):
    case (6, 0):
        let alert = UIAlertController(title: nil, message: nil, preferredStyle: .ActionSheet)
        alert.addAction(UIAlertAction(title: "Apagar Atividade", style: .Destructive) {
            (action) in
            TraqtDataContext.sharedInstance.activities.delete(self.activity!.activityId)
            self.navigationController?.popViewControllerAnimated(true)
            })
        alert.addAction(UIAlertAction(title: "Cancelar", style: .Cancel, handler: nil))

        self.tableView.deselectRowAtIndexPath(indexPath, animated: true)
        self.presentViewController(alert, animated: true, completion: nil)
    default:
        break
    }
}

2.7. Atualize o Código do Método viewDidLoad

Atualize o método

override func viewDidLoad() {
    // Código existente anteriormente, não modifique
    // ...

    // Configura a exibição e as animações da célula
    self.insertTableViewRowAnimation = .Middle
    self.deleteTableViewRowAnimation = .Middle
    self.reloadTableViewRowAnimation = .Middle
    self.cell(self.reminderTimePickerCell, setHidden: true)
    self.reloadDataAnimated(false)
}

2.8. Inclua o Método de Apoio para formatação da data selecionada

Inclua o método de apoio abaixo:

/// Configura o Label com o horário formatado de acordo com a seleção do Date Picker
func setReminderTime() {
    let dateFormatter = NSDateFormatter()
    dateFormatter.timeStyle = NSDateFormatterStyle.ShortStyle
    self.reminderTimeLabel.text = dateFormatter.stringFromDate(self.reminderTimePicker.date)
}

2.9. Inclua o Action Method do Date Picker

Inclua o Action Method para o evento Value Changed do Date Picker:

@IBAction func remindersValueChanged(sender: UIDatePicker) {
    self.setReminderTime()
}

Exercício 3: Incluindo o View Controller para a Seleção de Dias da Semana

3.1. Abrir o arquivo Main.Storyboard e Desenhar um Table View Controller Próximo ao formulário de Atividades

3.2. Embutir o View Controller dentro de um Navigation Controller

3.3. Configurar o View Controller

Alterar o título do View Controller Dias da Semana. Incluir dois UIBarButtonItem's na barra de navegação, sendo o da esquerda com o Identifier Cancel e o da direita com o Identifier Done.

3.4. Configurar a Célula de Proptótipo

Configurar a célula de protótipo com o o Identifier WeekDayCell e o tipo Basic.

3.5. Criar um Segue entre a célula Dias e o Navigation Controller

Criar um Segue do tipo Present Modally entre a célula Dias do formulário e o Navigation Controller, configurar seu Identifier para PickReminderDays.

3.6. Configurar a célula de Dias

Configurar a célula de dias com a propriedade Selection para Default e Accessory para Disclosure Indicator. Configurar a propriedade Constant da Constraint Trailing Space to: Superview Equals: 15 para 0.

3.7. Inserir os fontes de modelo dentro da pasta model

Baixe os arquivos adicionais de modelo a partir deste link. Insira-os no grupo model do projeto.

3.8. Criar a classe WeekDaysPickerController como subclasse de UITableViewController

3.9. Configurar o Table View para corresponder a nova classe

3.10. Declarar um novo protocolo para Delegate do Picker de dias da semana

No início do arquivo WeekDaysPickerController da classe criada incluir o código para o protocolo do Delegate desta classe (acima da declaraçãod a classe):

/// Protocolo usado pelo delegate do componente WeekDaysPickerController
protocol WeekDaysPickerControllerDelegate {

    /**
         Informa o delegate que o usuário concluiu a seleção dos dias da semana.

         - parameter controller: Uma referência para o Controller que realizou a operação.
         - parameter weekdays: Uma instância com os dias da semana selecionados pelo usuário.
     */
    func weekDaysPicker(controller: WeekDaysPickerController, didPickWeekDays weekdays: WeekDays)

    /**
         Informa o delegate que o usuário cancelou a seleção dos dias da semana.

         - parameter controller: Uma referência para o Controller que realizou a operação.
     */
    func weekDaysPickerDidCancel(controller: WeekDaysPickerController)
}

3.11. Inclua as propriedades da Classe WeekDaysPickerController

Inclua as propriedades conforme o código abaixo:

//
// MARK: - Properties

var delegate: WeekDaysPickerControllerDelegate?
var selectedWeekDays: WeekDays = .None
var weekDays: [WeekDays.WeekDayInfo]!

3.12. Altere o método viewDidLoad da Classe WeekDaysPickerController

Altere o método viewDidLoad conforme o código abaixo:

//
// MARK: - View Lifecycle

override func viewDidLoad() {
    super.viewDidLoad()
    self.weekDays = selectedWeekDays.asWeekDays()
}

3.13. Configure o Data Source do Table View

Configure o Data Source do Table View alterando os métodos do protocolo conforme o código abaixo:

//
// MARK: - Table view data source

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    // #warning Potentially incomplete method implementation.
    // Return the number of sections.
    return 0
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return weekDays.count
}

3.14. Configure o Delegate do Table View

Configure o Delegate do Table View alterando os métodos do protocolo conforme o código abaixo:

//
// MARK: - Table View Delegate

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "Cell")
    let weekDay = weekDays[indexPath.row]

    cell.accessoryType = weekDay.selected ? .Checkmark : .None
    cell.textLabel!.text = weekDay.longName

    return cell
}

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    let selectedCell = tableView.cellForRowAtIndexPath(indexPath)
    if selectedCell?.accessoryType == UITableViewCellAccessoryType.Checkmark {
        selectedCell?.accessoryType = .None
        self.weekDays[indexPath.row].selected = false
        self.selectedWeekDays.remove(weekDays[indexPath.row].weekDaysValue!)
    } else {
        selectedCell?.accessoryType = .Checkmark
        self.weekDays[indexPath.row].selected = true
        self.selectedWeekDays.insert(weekDays[indexPath.row].weekDaysValue!)
    }
    selectedCell?.setSelected(false, animated: true)
}

3.15. Inclua os Action Methods dos Botões da Barra de Navegação

Inclua os Action Methods dos botões Done e Cancel conforme o código abaixo:

//
// MARK: - Action Methods

@IBAction func doneTapped(sender: UIBarButtonItem) {
    self.delegate?.weekDaysPicker(self, didPickWeekDays: self.selectedWeekDays)
}

@IBAction func cancelTapped(sender: UIBarButtonItem) {
    self.delegate?.weekDaysPickerDidCancel(self)
}

3.16. Inclua a propriedade de dia selecionado no arquivo ActiviftFormViewController

Inclua a seguinte propriedade no arquivo ActiviftFormViewController.swift:

var reminderWeekDays: WeekDays = .None

3.17. Inclua o método de apoio para mostrar os dias da semana selecionados

Inclua o método abaixo na seção de métodos de apoio:

/// Configura o Label de dias da semana com a descrição conforme a seleção atual
func setReminderDaysLabel() {
    self.reminderDaysLabel.text = self.reminderWeekDays.toString()
}

3.18. Torne a classe ActivityFormViewController aderente ao protocolo WeekDaysPickerControllerDelegate

Atualize a declaração da classe ActivityFormViewController para incluir o delegate do Week Days Picker:

class ActivityFormViewController: StaticDataTableViewController, TimeLimitChooserDelegate {
class ActivityFormViewController: StaticDataTableViewController, TimeLimitChooserDelegate, WeekDaysPickerControllerDelegate {

3.19. Implemente os métodos do delegate

Implemente os métodos do delegate conforme o código abaixo:

//
// MARK: - WeekDaysPickerControllerDelegate

func weekDaysPicker(controller: WeekDaysPickerController, didPickWeekDays weekdays: WeekDays) {
    self.reminderWeekDays = weekdays
    self.setReminderDaysLabel()
    self.dismissViewControllerAnimated(true, completion: nil)
}

func weekDaysPickerDidCancel(controller: WeekDaysPickerController) {
    self.dismissViewControllerAnimated(true, completion: nil)
}

3.20. Atualize o método prepareForSegue:sender:

Atualize o código do método prepareForSegue:sender: conforme a listagem abaixo:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue.identifier == "PickReminderDays" {
        let nvc = segue.destinationViewController as! UINavigationController
        let vc = nvc.topViewController as! WeekDaysPickerController
        vc.delegate = self
    }

    if let destVC = segue.destinationViewController as? SessionHistoryTableViewController {
        destVC.activity = self.activity
    }
}

3.21. Execute o App e verifique a tela de seleção de dias da semana


Exercício 4. Carregando e Persistindo as Configurações de Lembrete

4.1. Obtenha a pasta Extensions e insira a pasta no Traqt do projeto

Baixa a pasta com os códigos fontes de extensões adicionais do Swift a partir deste link. Inclua a pasta como um novo grupo no projeto Traqt.

4.2. Atualize o método viewDidLoad da class ActivityFormViewController para carregar as informações de lembrete

Atualize o método viewDidLoad conforme a listagem abaixo:

override func viewDidLoad() {
    super.viewDidLoad()

    // Configura os componentes
    self.descriptionTextView.placeholder = "Descrição detalhada da atividade..."

    // Do any additional setup after loading the view.
    if let a = self.activity {
        self.title = "Editar Atividade"
        self.nameTextField.text = a.name
        self.descriptionTextView.text = a.details

        // Carrega e confgiura as opções de repetições
        var repetitionsEnabled = (a.repetitions.integerValue > 0)
        self.setRepetitionsVisibility(!repetitionsEnabled)
        self.repetitionsSwitch.on = repetitionsEnabled
        self.repetitionsSlider.value = a.repetitions.floatValue
        self.repetitionsLabel.text = a.repetitions.stringValue

        // Carrega e configura as opções de tempo limite
        var timeLimitEnabled = (a.timeLimit.integerValue > 0)
        self.setTimeLimitVisibility(!timeLimitEnabled)
        self.selectedTimeLimit = a.timeLimit.integerValue
        self.timeLimitSwitch.on = timeLimitEnabled
        self.timeLimitLabel.text = self.getTimeDescription(a.timeLimit.integerValue)

        // Configura as propriedades do Reminders
        let remindersEnabled = a.reminders!.boolValue
        self.setRemindersVisibility(!remindersEnabled)
        self.remindersSwitch.on = remindersEnabled
        self.reminderTimePicker.date = a.reminderTime!.integerValue.timeIntToDate()!
        if let reminderDays = a.reminderDays?.integerValue {
            self.reminderWeekDays = WeekDays(rawValue: reminderDays)
        }
        self.setReminderDaysLabel()
        self.setReminderTime()

        // Quantidade de sessões dessa atividade
        let sessions = a.sessions.count
        if sessions > 0 {
            self.historyLabel.text = "\(sessions) " + ((sessions == 1) ? "Sessão" : "Sessões")
        }
    } else {
        self.title = "Nova Atividade"
    }

    // Configura a exibição e as animações da célula
    self.insertTableViewRowAnimation = .Middle
    self.deleteTableViewRowAnimation = .Middle
    self.reloadTableViewRowAnimation = .Middle
    self.cell(self.reminderTimePickerCell, setHidden: true)
    self.reloadDataAnimated(false)
}

4.3. Atualizar o Método setActivityData:

Atualize o método setActivityData: conforme a listagem abaixo:

func setActivityData(activity: Activity) {
    activity.name = self.nameTextField.text
    activity.details = self.descriptionTextView.text
    activity.enableVibration = self.vibrateSwitch.on
    activity.repetitions = self.repetitionsSwitch.on ? Int(self.repetitionsSlider.value) : 0
    activity.timeLimit = self.timeLimitSwitch.on ? self.selectedTimeLimit : 0
    activity.reminders = self.remindersSwitch.on
    activity.reminderTime = self.reminderTimePicker.date.toIntTime()
    activity.reminderDays = self.reminderWeekDays.rawValue
}

4.4. Atualizar o Método prepareForSegue:sender:

Atualize o método prepareForSegue:sender: para repassar a informação dos dias selecionados conforme a listagem abaixo:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue.identifier == "PickReminderDays" {
        let nvc = segue.destinationViewController as UINavigationController
        let vc = nvc.topViewController as WeekDaysPickerController
        vc.delegate = self
        vc.selectedWeekDays = self.reminderWeekDays
    }

    if let destVC = segue.destinationViewController as? SessionHistoryTableViewController {
        destVC.activity = self.activity
    }
}

4.5. Execute o App e verifique se as informações de lembretes estão sendo persistidas corretamente