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