pEpForiOS/UI/EmailDisplay/EmailListViewController.swift
author Dirk Zimmermann <dirk@pep-project.org>
Tue, 24 Jan 2017 10:47:08 +0100
changeset 1507 7270fb02923c
parent 1506 11d3b3dd5865
child 1510 2b4d784a6800
permissions -rw-r--r--
IOS-417 consolidating creation of swipe actions
dirk@30
     1
//
dirk@30
     2
//  EmailListViewController.swift
dirk@30
     3
//  pEpForiOS
dirk@30
     4
//
dirk@30
     5
//  Created by Dirk Zimmermann on 16/04/16.
dirk@30
     6
//  Copyright © 2016 p≡p Security S.A. All rights reserved.
dirk@30
     7
//
dirk@30
     8
dirk@30
     9
import Foundation
dirk@30
    10
import UIKit
dirk@31
    11
import CoreData
dirk@810
    12
import MessageModel
dirk@810
    13
igor@1260
    14
struct EmailListConfig {
igor@1338
    15
    var appConfig: AppConfig?
dirk@1333
    16
igor@1260
    17
    /** The folder to display, if it exists */
igor@1260
    18
    var folder: Folder?
igor@1260
    19
}
dirk@30
    20
dirk@854
    21
class EmailListViewController: UITableViewController {
igor@1260
    22
    
dirk@583
    23
    struct UIState {
dirk@583
    24
        var isSynching: Bool = false
dirk@583
    25
    }
dirk@30
    26
dirk@1344
    27
    var config: EmailListConfig?
dirk@275
    28
    var state = UIState()
igor@1301
    29
    let searchController = UISearchController(searchResultsController: nil)
dirk@719
    30
dirk@275
    31
    override func viewDidLoad() {
ylandert@935
    32
        super.viewDidLoad()
igor@1301
    33
        
igor@1408
    34
        title = "EmailList.title".localized
igor@1284
    35
        UIHelper.emailListTableHeight(self.tableView)
igor@1301
    36
        addSearchBar()
dirk@275
    37
    }
dirk@31
    38
dirk@784
    39
    override func viewWillAppear(_ animated: Bool) {
igor@1301
    40
        super.viewWillAppear(animated)
igor@1301
    41
        
dirk@1344
    42
        if MiscUtil.isUnitTest() {
dirk@1344
    43
            return
dirk@1344
    44
        }
dirk@1344
    45
dirk@1344
    46
        initialConfig()
dirk@854
    47
        updateModel()
dirk@1348
    48
dirk@1348
    49
        MessageModelConfig.messageFolderDelegate = self
dirk@1348
    50
    }
dirk@1348
    51
dirk@1348
    52
    override func viewWillDisappear(_ animated: Bool) {
dirk@1348
    53
        super.viewWillDisappear(animated)
dirk@1348
    54
        MessageModelConfig.messageFolderDelegate = nil
igor@1301
    55
    }
igor@1301
    56
    
igor@1338
    57
    func initialConfig() {
dirk@1344
    58
        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
igor@1338
    59
            return
igor@1338
    60
        }
dirk@1344
    61
dirk@1344
    62
        if config == nil {
igor@1395
    63
            config = EmailListConfig(appConfig: appDelegate.appConfig, folder: Folder.unifiedInbox())
dirk@1344
    64
        }
dirk@1348
    65
        if Account.all().isEmpty {
igor@1338
    66
            performSegue(withIdentifier:.segueAddNewAccount, sender: self)
igor@1338
    67
        }
igor@1338
    68
    }
igor@1338
    69
    
igor@1301
    70
    func addSearchBar() {
igor@1301
    71
        searchController.searchResultsUpdater = self
igor@1301
    72
        searchController.dimsBackgroundDuringPresentation = false
igor@1301
    73
        searchController.delegate = self
igor@1301
    74
        definesPresentationContext = true
igor@1301
    75
        tableView.tableHeaderView = searchController.searchBar
igor@1301
    76
        tableView.setContentOffset(CGPoint(x: 0.0, y: 40.0), animated: false)
igor@1301
    77
    }
dirk@705
    78
igor@941
    79
    
dirk@1330
    80
    @IBAction func showUnreadButtonTapped(_ sender: UIBarButtonItem) {}
igor@941
    81
    
dirk@854
    82
    func updateModel() {
igor@1318
    83
        tableView.reloadData()
dirk@31
    84
    }
dirk@31
    85
dirk@58
    86
    // MARK: - UI State
dirk@58
    87
dirk@58
    88
    func updateUI() {
dirk@784
    89
        UIApplication.shared.isNetworkActivityIndicatorVisible = state.isSynching
dirk@748
    90
        if !state.isSynching {
igor@1260
    91
            refreshControl?.endRefreshing()
dirk@58
    92
        }
dirk@58
    93
    }
dirk@58
    94
dirk@31
    95
    // MARK: - UITableViewDataSource
dirk@31
    96
dirk@784
    97
    override func numberOfSections(in tableView: UITableView) -> Int {
dirk@1344
    98
        if let _ = config?.folder {
dirk@854
    99
            return 1
dirk@209
   100
        }
dirk@854
   101
        return 0
dirk@31
   102
    }
dirk@31
   103
dirk@784
   104
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
dirk@1344
   105
        if let fol = config?.folder  {
dirk@854
   106
            return fol.messageCount()
dirk@31
   107
        }
dirk@31
   108
        return 0
dirk@31
   109
    }
dirk@31
   110
dirk@784
   111
    override func tableView(_ tableView: UITableView,
dirk@784
   112
                            cellForRowAt indexPath: IndexPath) -> UITableViewCell {
dirk@784
   113
        let cell = tableView.dequeueReusableCell(
dirk@784
   114
            withIdentifier: "EmailListViewCell", for: indexPath) as! EmailListViewCell
igor@1260
   115
        cell.configureCell(indexPath: indexPath, config: config)
dirk@31
   116
        return cell
dirk@31
   117
    }
dirk@31
   118
dirk@719
   119
    // MARK: - UITableViewDelegate
dirk@719
   120
dirk@1333
   121
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
dirk@1507
   122
        let _ = tableView.cellForRow(at: indexPath) as! EmailListViewCell
dirk@719
   123
dirk@1344
   124
        if let fol = config?.folder {
dirk@855
   125
            if fol.folderType == .drafts {
igor@1395
   126
                //performSegue(withIdentifier: .segueCompose, sender: cell)
dirk@719
   127
                return
dirk@719
   128
            }
dirk@719
   129
        }
igor@1395
   130
        //performSegue(withIdentifier: .segueShowEmail, sender: cell)
dirk@719
   131
    }
dirk@719
   132
dirk@784
   133
    override func tableView(_ tableView: UITableView, editActionsForRowAt
dirk@784
   134
        indexPath: IndexPath)-> [UITableViewRowAction]? {
dirk@784
   135
        let cell = tableView.cellForRow(at: indexPath) as! EmailListViewCell
igor@1260
   136
        if let email = cell.messageAt(indexPath: indexPath, config: config) {
dirk@1507
   137
            let isFlagAction = createFlagAction(message: email, cell: cell)
dirk@1507
   138
            let deleteAction = createDeleteAction(message: email, cell: cell)
igor@1242
   139
            let moreAction = createMoreAction(message: email, cell: cell)
igor@1242
   140
            return [deleteAction,isFlagAction,moreAction]
dirk@855
   141
        }
dirk@855
   142
        return nil
dirk@744
   143
    }
dirk@744
   144
dirk@719
   145
    // MARK: - Misc
dirk@719
   146
dirk@1507
   147
    func createRowAction(cell: EmailListViewCell,
dirk@1507
   148
        image: UIImage?, action: @escaping (UITableViewRowAction, IndexPath) -> Void,
dirk@1507
   149
        titleBlock: () -> String) -> UITableViewRowAction {
dirk@1507
   150
        let rowAction = UITableViewRowAction(style: .normal, title: titleBlock(),
dirk@1507
   151
                                             handler: action)
dirk@1507
   152
dirk@1507
   153
        if let theImage = image {
dirk@1507
   154
            let iconColor = UIColor(patternImage: theImage)
dirk@1507
   155
            rowAction.backgroundColor = iconColor
dirk@744
   156
        }
dirk@744
   157
dirk@1507
   158
        return rowAction
dirk@744
   159
    }
dirk@744
   160
dirk@1507
   161
    func createFlagAction(message: Message, cell: EmailListViewCell) -> UITableViewRowAction {
dirk@1507
   162
        func action(action: UITableViewRowAction, indexPath: IndexPath) -> Void {
dirk@1507
   163
            if (cell.isImportant(message: message)) {
dirk@1507
   164
                message.imapFlags?.flagged = false
dirk@1507
   165
            } else {
dirk@1507
   166
                message.imapFlags?.flagged = true
dirk@1507
   167
            }
dirk@1507
   168
            message.save()
dirk@1507
   169
            self.tableView.reloadRows(at: [indexPath], with: .none)
dirk@1507
   170
        }
dirk@1507
   171
        func title() -> String {
dirk@1507
   172
            var title = "Flag".localized
dirk@1507
   173
            if (message.imapFlags?.flagged ?? true) {
dirk@1507
   174
                title = "UnFlag".localized
dirk@1507
   175
            }
dirk@1507
   176
            return title
dirk@744
   177
        }
dirk@744
   178
dirk@1507
   179
        let image = UIImage(named: "swipe-flag")
dirk@1507
   180
dirk@1507
   181
        return createRowAction(cell: cell, image: image, action: action, titleBlock: title)
dirk@744
   182
    }
dirk@744
   183
dirk@1507
   184
    func createDeleteAction(message: Message, cell: EmailListViewCell) -> UITableViewRowAction {
dirk@1507
   185
        func action(action: UITableViewRowAction, indexPath: IndexPath) -> Void {
dirk@1507
   186
            guard let message = cell.messageAt(indexPath: indexPath, config: self.config) else {
dirk@1507
   187
                return
dirk@1507
   188
            }
dirk@1507
   189
            message.imapFlags?.deleted = true
dirk@1507
   190
            message.save()
dirk@1507
   191
            self.tableView.reloadRows(at: [indexPath], with: .none)
dirk@1507
   192
        }
dirk@1507
   193
        func title() -> String {
dirk@1507
   194
            return "Delete".localized
dirk@744
   195
        }
dirk@744
   196
dirk@1507
   197
        let image = UIImage(named: "swipe-trash")
dirk@1507
   198
dirk@1507
   199
        return createRowAction(cell: cell, image: image, action: action, titleBlock: title)
dirk@1507
   200
    }
dirk@1507
   201
dirk@1507
   202
    func createMarkAsReadAction(message: Message, cell: EmailListViewCell) -> UITableViewRowAction {
dirk@1507
   203
        func action(action: UITableViewRowAction, indexPath: IndexPath) -> Void {
dirk@1507
   204
            if (cell.isRead(message: message)) {
dirk@1507
   205
                message.imapFlags?.seen = false
dirk@1507
   206
            } else {
dirk@1507
   207
                message.imapFlags?.seen = true
dirk@1507
   208
            }
dirk@1507
   209
            self.tableView.reloadRows(at: [indexPath], with: .none)
dirk@744
   210
        }
dirk@1507
   211
        func title() -> String {
dirk@1507
   212
            if (cell.isRead(message: message)) {
dirk@1507
   213
                return NSLocalizedString(
dirk@1507
   214
                    "Unread",
dirk@1507
   215
                    comment: "Unread button title in swipe action on EmailListViewController")
dirk@1507
   216
            } else {
dirk@1507
   217
                return NSLocalizedString(
dirk@1507
   218
                    "Read",
dirk@1507
   219
                    comment: "Read button title in swipe action on EmailListViewController")
dirk@1507
   220
            }
dirk@1507
   221
        }
dirk@1507
   222
dirk@1507
   223
        let isReadAction = createRowAction(cell: cell, image: nil, action: action,
dirk@1507
   224
                                           titleBlock: title)
dirk@784
   225
        isReadAction.backgroundColor = UIColor.blue
dirk@744
   226
dirk@744
   227
        return isReadAction
dirk@744
   228
    }
igor@1242
   229
    
igor@1242
   230
    func createMoreAction(message: Message, cell: EmailListViewCell) -> UITableViewRowAction {
igor@1242
   231
        let moreCompletitionHandler :(UITableViewRowAction, IndexPath) -> Void = {(action, indexPath) in
igor@1242
   232
            self.showMoreActionSheet(cell: cell)
igor@1242
   233
        }
igor@1242
   234
        let moreAction = UITableViewRowAction(style: .normal, title: "          ", handler: moreCompletitionHandler)
igor@1242
   235
        let swipeMoreImage = UIImage(named: "swipe-more")
igor@1242
   236
        let moreIconColor = UIColor(patternImage: swipeMoreImage!)
igor@1242
   237
        moreAction.backgroundColor = moreIconColor
igor@1242
   238
        return moreAction
igor@1242
   239
    }
igor@1242
   240
    
igor@1242
   241
    // MARK: - Action Sheet
igor@1242
   242
    
igor@1242
   243
    func showMoreActionSheet(cell: EmailListViewCell) {
igor@1242
   244
        let alertControler = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
igor@1438
   245
        alertControler.view.tintColor = .pEpGreen
igor@1242
   246
        let cancelAction = createCancelAction()
igor@1242
   247
        let replyAction = createReplyAction(cell: cell)
igor@1242
   248
        let forwardAction = createForwardAction(cell: cell)
igor@1242
   249
        let markAction = createMarkAction()
igor@1242
   250
        alertControler.addAction(cancelAction)
igor@1242
   251
        alertControler.addAction(replyAction)
igor@1242
   252
        alertControler.addAction(forwardAction)
igor@1242
   253
        alertControler.addAction(markAction)
igor@1414
   254
        if let popoverPresentationController = alertControler.popoverPresentationController {
igor@1414
   255
            popoverPresentationController.sourceView = cell
igor@1414
   256
        }
igor@1242
   257
        present(alertControler, animated: true, completion: nil)
igor@1242
   258
    }
igor@1242
   259
    
igor@1242
   260
    // MARK: - Action Sheet Actions
igor@1242
   261
igor@1242
   262
    func createCancelAction() -> UIAlertAction {
igor@1242
   263
      return  UIAlertAction(title: "Cancel", style: .cancel) { (action) in}
igor@1242
   264
    }
igor@1242
   265
    
igor@1242
   266
    func createReplyAction(cell: EmailListViewCell) ->  UIAlertAction {
igor@1242
   267
        return UIAlertAction(title: "Reply", style: .default) { (action) in
igor@1338
   268
           // self.performSegue(withIdentifier: self.segueCompose, sender: cell)
igor@1338
   269
            self.performSegue(withIdentifier: .segueCompose, sender: cell)
igor@1242
   270
        }
igor@1242
   271
    }
igor@1242
   272
    
igor@1242
   273
    func createForwardAction(cell: EmailListViewCell) -> UIAlertAction {
igor@1242
   274
        return UIAlertAction(title: "Forward", style: .default) { (action) in
igor@1338
   275
            //self.performSegue(withIdentifier: self.segueCompose, sender: cell)
igor@1338
   276
            self.performSegue(withIdentifier: .segueCompose, sender: cell)
igor@1242
   277
        }
igor@1242
   278
    }
igor@1242
   279
    
igor@1242
   280
    func createMarkAction() -> UIAlertAction {
igor@1242
   281
        return UIAlertAction(title: "Mark", style: .default) { (action) in
igor@1242
   282
        }
igor@1242
   283
    }
igor@1301
   284
    
igor@1301
   285
    // MARK: - Content Search
igor@1301
   286
    
igor@1301
   287
    func filterContentForSearchText(searchText: String) {
igor@1301
   288
        
igor@1301
   289
    }
igor@1395
   290
 
igor@1338
   291
    // MARK: - Actions
igor@1395
   292
//    @IBAction func unwindToEmailList(for unwindSegue: UIStoryboardSegue) {
igor@1395
   293
//        
igor@1395
   294
//    }
igor@1338
   295
   
dirk@784
   296
}
igor@1301
   297
igor@1301
   298
extension EmailListViewController: UISearchResultsUpdating, UISearchControllerDelegate {
igor@1301
   299
    public func updateSearchResults(for searchController: UISearchController) {
igor@1301
   300
        filterContentForSearchText(searchText: searchController.searchBar.text!)
igor@1301
   301
    }
igor@1301
   302
    
igor@1301
   303
    func didDismissSearchController(_ searchController: UISearchController) {
igor@1301
   304
    }
igor@1301
   305
}
igor@1338
   306
igor@1338
   307
// MARK: - Navigation
igor@1338
   308
igor@1338
   309
extension EmailListViewController: SegueHandlerType {
igor@1338
   310
    
igor@1338
   311
    // MARK: - SegueHandlerType
igor@1338
   312
    
igor@1338
   313
    enum SegueIdentifier: String {
igor@1338
   314
        case segueAddNewAccount
igor@1338
   315
        case segueEditAccounts
igor@1338
   316
        case segueShowEmail
igor@1338
   317
        case segueCompose
igor@1338
   318
        case noSegue
igor@1338
   319
    }
igor@1338
   320
    
igor@1338
   321
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
igor@1338
   322
        switch segueIdentifier(for: segue) {
igor@1338
   323
        case .segueCompose:
igor@1338
   324
            //let destination = segue.destination as! ComposeTableViewController
igor@1338
   325
            // destination.appConfig = config.appConfig
igor@1338
   326
            //            if let draft = draftMessageToCompose {
igor@1338
   327
            //                draft.imapFlags?.seen = true
igor@1338
   328
            //
igor@1338
   329
            //                destination.originalMessage = draft
igor@1338
   330
            //                destination.composeMode = .draft
igor@1338
   331
        //            }
igor@1338
   332
            break
igor@1338
   333
        case .segueShowEmail:
igor@1338
   334
            guard
igor@1338
   335
                let vc = segue.destination as? EmailViewController,
igor@1338
   336
                let cell = sender as? EmailListViewCell,
igor@1338
   337
                let indexPath = self.tableView.indexPath(for: cell),
igor@1338
   338
                let email = cell.messageAt(indexPath: indexPath, config: config) else {
igor@1338
   339
                    return
igor@1338
   340
            }
dirk@1344
   341
            vc.appConfig = config?.appConfig
igor@1338
   342
            vc.message = email
igor@1338
   343
            break
igor@1338
   344
        default: ()
igor@1338
   345
        }
igor@1338
   346
    }
dirk@1350
   347
dirk@1350
   348
    func didChangeInternal(messageFolder: MessageFolder) {
dirk@1350
   349
        if let folder = config?.folder,
dirk@1350
   350
            let message = messageFolder as? Message,
dirk@1350
   351
            folder.contains(message: message) {
dirk@1350
   352
            if let msg = messageFolder as? Message {
dirk@1350
   353
                if msg.isOriginal {
dirk@1350
   354
                    self.tableView.reloadData()
dirk@1350
   355
                }
dirk@1350
   356
            }
dirk@1350
   357
        }
dirk@1350
   358
    }
igor@1338
   359
}
dirk@1348
   360
dirk@1348
   361
// MARK: - MessageFolderDelegate
dirk@1348
   362
dirk@1348
   363
extension EmailListViewController: MessageFolderDelegate {
dirk@1348
   364
    func didChange(messageFolder: MessageFolder) {
dirk@1350
   365
        GCD.onMain {
dirk@1350
   366
            self.didChangeInternal(messageFolder: messageFolder)
dirk@1348
   367
        }
dirk@1348
   368
    }
dirk@1348
   369
}