pEpForiOS/UI/EmailDisplay/EmailListViewController.swift
author Dirk Zimmermann <dirk@pep-project.org>
Tue, 23 May 2017 11:32:32 +0200
changeset 2191 a01eb69e9664
parent 2190 4fe9e5ba269d
child 2240 cc38768aa006
permissions -rw-r--r--
IOS-490 viewed folders marked as "interesting"
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?
dirk@1906
    19
dirk@1906
    20
    let imageProvider = IdentityImageProvider()
igor@1260
    21
}
dirk@30
    22
xavier@1865
    23
class EmailListViewController: UITableViewController, FilterUpdateProtocol {
dirk@583
    24
    struct UIState {
dirk@583
    25
        var isSynching: Bool = false
dirk@583
    26
    }
dirk@30
    27
dirk@1344
    28
    var config: EmailListConfig?
dirk@275
    29
    var state = UIState()
igor@1301
    30
    let searchController = UISearchController(searchResultsController: nil)
dirk@1737
    31
    let cellsInUse = NSCache<NSString, EmailListViewCell>()
dirk@719
    32
dirk@1724
    33
    /**
dirk@1724
    34
     After trustwords have been invoked, this will be the partner identity that
dirk@1724
    35
     was either confirmed or mistrusted.
dirk@1724
    36
     */
dirk@1724
    37
    var partnerIdentity: Identity?
dirk@1724
    38
dirk@2067
    39
    @IBOutlet weak var enableFilterButton: UIBarButtonItem!
dirk@2067
    40
    @IBOutlet weak var textFilterButton: UIBarButtonItem!
dirk@2067
    41
dirk@2067
    42
    private var filterEnabled = false
dirk@2067
    43
dirk@275
    44
    override func viewDidLoad() {
ylandert@935
    45
        super.viewDidLoad()
xavier@1623
    46
dirk@2189
    47
        title = NSLocalizedString("Inbox", comment: "General name for (unified) inbox")
igor@1284
    48
        UIHelper.emailListTableHeight(self.tableView)
igor@1301
    49
        addSearchBar()
dirk@275
    50
    }
dirk@31
    51
dirk@784
    52
    override func viewWillAppear(_ animated: Bool) {
igor@1301
    53
        super.viewWillAppear(animated)
xavier@1623
    54
dirk@1344
    55
        if MiscUtil.isUnitTest() {
dirk@1344
    56
            return
dirk@1344
    57
        }
dirk@1344
    58
xavier@1832
    59
        self.textFilterButton.isEnabled = filterEnabled
xavier@1832
    60
dirk@1826
    61
        setDefaultColors()
dirk@1344
    62
        initialConfig()
dirk@854
    63
        updateModel()
dirk@1348
    64
dirk@2191
    65
        // Mark this folder as having been looked at by the user
dirk@2191
    66
        if let fol = config?.folder {
dirk@2191
    67
            fol.updateLastLookAt()
dirk@2191
    68
        }
dirk@2191
    69
dirk@1348
    70
        MessageModelConfig.messageFolderDelegate = self
dirk@1348
    71
    }
dirk@1348
    72
xavier@1948
    73
dirk@1348
    74
    override func viewWillDisappear(_ animated: Bool) {
dirk@1348
    75
        super.viewWillDisappear(animated)
dirk@1348
    76
        MessageModelConfig.messageFolderDelegate = nil
igor@1301
    77
    }
xavier@1623
    78
igor@1338
    79
    func initialConfig() {
dirk@1344
    80
        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
igor@1338
    81
            return
igor@1338
    82
        }
dirk@1348
    83
        if Account.all().isEmpty {
igor@1338
    84
            performSegue(withIdentifier:.segueAddNewAccount, sender: self)
igor@1338
    85
        }
xavier@2132
    86
        if config == nil {
dirk@2191
    87
            config = EmailListConfig(appConfig: appDelegate.appConfig,
dirk@2191
    88
                                     folder: Folder.unifiedInbox())
xavier@2132
    89
        }
xavier@2132
    90
        self.title = config?.folder?.realName
igor@1338
    91
    }
xavier@1623
    92
igor@1301
    93
    func addSearchBar() {
igor@1301
    94
        searchController.searchResultsUpdater = self
igor@1301
    95
        searchController.dimsBackgroundDuringPresentation = false
igor@1301
    96
        searchController.delegate = self
igor@1301
    97
        definesPresentationContext = true
igor@1301
    98
        tableView.tableHeaderView = searchController.searchBar
igor@1301
    99
        tableView.setContentOffset(CGPoint(x: 0.0, y: 40.0), animated: false)
igor@1301
   100
    }
dirk@705
   101
dirk@854
   102
    func updateModel() {
igor@1318
   103
        tableView.reloadData()
dirk@31
   104
    }
dirk@31
   105
xavier@1832
   106
xavier@1832
   107
    @IBAction func showUnreadButtonTapped(_ sender: UIBarButtonItem) {
xavier@1832
   108
        if filterEnabled {
xavier@1832
   109
            filterEnabled = false
xavier@1832
   110
            textFilterButton.title = ""
xavier@1832
   111
            enableFilterButton.image = UIImage(named: "unread-icon")
xavier@1865
   112
            updateFilter(filter: Filter.unified())
xavier@1832
   113
        } else {
xavier@1832
   114
            filterEnabled = true
xavier@1832
   115
            textFilterButton.title = "Filter by: unread"
xavier@1832
   116
            enableFilterButton.image = UIImage(named: "unread-icon-active")
xavier@1832
   117
            if config != nil {
xavier@1865
   118
                updateFilter(filter: Filter.unread())
xavier@1832
   119
            }
xavier@1832
   120
        }
xavier@1832
   121
        self.textFilterButton.isEnabled = filterEnabled
xavier@1832
   122
xavier@1832
   123
    }
xavier@1832
   124
xavier@1865
   125
    func updateFilter(filter: Filter) {
xavier@1865
   126
        config?.folder?.updateFilter(filter: filter)
xavier@1865
   127
        self.tableView.reloadData()
xavier@1865
   128
    }
xavier@1865
   129
dirk@58
   130
    // MARK: - UI State
dirk@58
   131
dirk@58
   132
    func updateUI() {
dirk@784
   133
        UIApplication.shared.isNetworkActivityIndicatorVisible = state.isSynching
dirk@748
   134
        if !state.isSynching {
igor@1260
   135
            refreshControl?.endRefreshing()
dirk@58
   136
        }
dirk@58
   137
    }
dirk@58
   138
dirk@31
   139
    // MARK: - UITableViewDataSource
dirk@31
   140
dirk@784
   141
    override func numberOfSections(in tableView: UITableView) -> Int {
dirk@1344
   142
        if let _ = config?.folder {
dirk@854
   143
            return 1
dirk@209
   144
        }
dirk@854
   145
        return 0
dirk@31
   146
    }
dirk@31
   147
dirk@784
   148
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
dirk@1344
   149
        if let fol = config?.folder  {
dirk@854
   150
            return fol.messageCount()
dirk@31
   151
        }
dirk@31
   152
        return 0
dirk@31
   153
    }
dirk@31
   154
dirk@784
   155
    override func tableView(_ tableView: UITableView,
dirk@784
   156
                            cellForRowAt indexPath: IndexPath) -> UITableViewCell {
dirk@784
   157
        let cell = tableView.dequeueReusableCell(
dirk@784
   158
            withIdentifier: "EmailListViewCell", for: indexPath) as! EmailListViewCell
dirk@1737
   159
        if let message = cell.configureCell(config: config, indexPath: indexPath) {
dirk@1737
   160
            associate(message: message, toCell: cell)
dirk@1542
   161
        }
dirk@31
   162
        return cell
dirk@31
   163
    }
dirk@31
   164
dirk@719
   165
    // MARK: - UITableViewDelegate
dirk@719
   166
dirk@784
   167
    override func tableView(_ tableView: UITableView, editActionsForRowAt
dirk@784
   168
        indexPath: IndexPath)-> [UITableViewRowAction]? {
xavier@1623
   169
dirk@784
   170
        let cell = tableView.cellForRow(at: indexPath) as! EmailListViewCell
igor@1260
   171
        if let email = cell.messageAt(indexPath: indexPath, config: config) {
igor@1576
   172
            let flagAction = createFlagAction(message: email, cell: cell)
dirk@1507
   173
            let deleteAction = createDeleteAction(message: email, cell: cell)
igor@1242
   174
            let moreAction = createMoreAction(message: email, cell: cell)
igor@1576
   175
            return [deleteAction, flagAction, moreAction]
dirk@855
   176
        }
dirk@855
   177
        return nil
dirk@744
   178
    }
dirk@744
   179
dirk@719
   180
    // MARK: - Misc
dirk@719
   181
dirk@1507
   182
    func createRowAction(cell: EmailListViewCell,
xavier@1623
   183
                         image: UIImage?, action: @escaping (UITableViewRowAction, IndexPath) -> Void,
xavier@1623
   184
                         title: String) -> UITableViewRowAction {
dirk@1510
   185
        let rowAction = UITableViewRowAction(
dirk@1510
   186
            style: .normal, title: title, handler: action)
dirk@1507
   187
dirk@1507
   188
        if let theImage = image {
dirk@1507
   189
            let iconColor = UIColor(patternImage: theImage)
dirk@1507
   190
            rowAction.backgroundColor = iconColor
dirk@744
   191
        }
dirk@744
   192
dirk@1507
   193
        return rowAction
dirk@744
   194
    }
dirk@744
   195
dirk@1507
   196
    func createFlagAction(message: Message, cell: EmailListViewCell) -> UITableViewRowAction {
dirk@1507
   197
        func action(action: UITableViewRowAction, indexPath: IndexPath) -> Void {
dirk@1522
   198
            if message.imapFlags == nil {
dirk@1522
   199
                Log.warn(component: #function, content: "message.imapFlags == nil")
dirk@1522
   200
            }
dirk@1605
   201
            if cell.isFlagged(message: message) {
dirk@1507
   202
                message.imapFlags?.flagged = false
dirk@1507
   203
            } else {
dirk@1507
   204
                message.imapFlags?.flagged = true
dirk@1507
   205
            }
dirk@1507
   206
            message.save()
dirk@1507
   207
            self.tableView.reloadRows(at: [indexPath], with: .none)
dirk@1507
   208
        }
dirk@1510
   209
dirk@2190
   210
        var title = "\n\n" + NSLocalizedString("Flag", comment: "Message action (on swipe)")
dirk@1605
   211
        if message.imapFlags?.flagged ?? true {
dirk@2190
   212
            title = "\n\n" + NSLocalizedString("Unflag", comment: "Message action (on swipe)")
dirk@744
   213
        }
dirk@744
   214
dirk@1510
   215
        return createRowAction(
dirk@1510
   216
            cell: cell, image: UIImage(named: "swipe-flag"), action: action, title: title)
dirk@744
   217
    }
dirk@744
   218
dirk@1507
   219
    func createDeleteAction(message: Message, cell: EmailListViewCell) -> UITableViewRowAction {
dirk@1507
   220
        func action(action: UITableViewRowAction, indexPath: IndexPath) -> Void {
dirk@1507
   221
            guard let message = cell.messageAt(indexPath: indexPath, config: self.config) else {
dirk@1507
   222
                return
dirk@1507
   223
            }
xavier@1623
   224
dirk@1650
   225
            message.delete() // mark for deletion/trash
dirk@1507
   226
            message.save()
igor@1576
   227
            self.tableView.reloadData()
dirk@1507
   228
        }
dirk@744
   229
dirk@1510
   230
        return createRowAction(
dirk@1510
   231
            cell: cell, image: UIImage(named: "swipe-trash"), action: action,
dirk@2190
   232
            title: "\n\n" + NSLocalizedString("Delete", comment: "Message action (on swipe)"))
dirk@1507
   233
    }
dirk@1507
   234
dirk@1507
   235
    func createMarkAsReadAction(message: Message, cell: EmailListViewCell) -> UITableViewRowAction {
dirk@1507
   236
        func action(action: UITableViewRowAction, indexPath: IndexPath) -> Void {
dirk@1605
   237
            if cell.haveSeen(message: message) {
dirk@1507
   238
                message.imapFlags?.seen = false
dirk@1507
   239
            } else {
dirk@1507
   240
                message.imapFlags?.seen = true
dirk@1507
   241
            }
dirk@1507
   242
            self.tableView.reloadRows(at: [indexPath], with: .none)
dirk@744
   243
        }
dirk@1510
   244
dirk@1510
   245
        var title = NSLocalizedString(
dirk@2190
   246
            "Unread", comment: "Message action (on swipe)")
dirk@1605
   247
        if !cell.haveSeen(message: message) {
dirk@1510
   248
            title = NSLocalizedString(
dirk@2190
   249
                "Read", comment: "Message action (on swipe)")
dirk@1507
   250
        }
dirk@1507
   251
dirk@1507
   252
        let isReadAction = createRowAction(cell: cell, image: nil, action: action,
dirk@1510
   253
                                           title: title)
dirk@784
   254
        isReadAction.backgroundColor = UIColor.blue
dirk@744
   255
dirk@744
   256
        return isReadAction
dirk@744
   257
    }
xavier@1623
   258
igor@1242
   259
    func createMoreAction(message: Message, cell: EmailListViewCell) -> UITableViewRowAction {
dirk@1510
   260
        func action(action: UITableViewRowAction, indexPath: IndexPath) -> Void {
igor@1242
   261
            self.showMoreActionSheet(cell: cell)
igor@1242
   262
        }
dirk@1510
   263
dirk@1510
   264
        return createRowAction(
dirk@1510
   265
            cell: cell, image: UIImage(named: "swipe-more"), action: action,
dirk@2190
   266
            title: "\n\n" + NSLocalizedString("More", comment: "Message action (on swipe)"))
igor@1242
   267
    }
xavier@1623
   268
igor@1242
   269
    // MARK: - Action Sheet
xavier@1623
   270
igor@1242
   271
    func showMoreActionSheet(cell: EmailListViewCell) {
igor@1242
   272
        let alertControler = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
igor@1438
   273
        alertControler.view.tintColor = .pEpGreen
igor@1242
   274
        let cancelAction = createCancelAction()
igor@1242
   275
        let replyAction = createReplyAction(cell: cell)
xavier@1623
   276
        let replyAllAction = createReplyAllAction(cell: cell)
igor@1242
   277
        let forwardAction = createForwardAction(cell: cell)
igor@1242
   278
        let markAction = createMarkAction()
igor@1242
   279
        alertControler.addAction(cancelAction)
igor@1242
   280
        alertControler.addAction(replyAction)
xavier@1620
   281
        alertControler.addAction(replyAllAction)
igor@1242
   282
        alertControler.addAction(forwardAction)
igor@1242
   283
        alertControler.addAction(markAction)
igor@1414
   284
        if let popoverPresentationController = alertControler.popoverPresentationController {
igor@1414
   285
            popoverPresentationController.sourceView = cell
igor@1414
   286
        }
igor@1242
   287
        present(alertControler, animated: true, completion: nil)
igor@1242
   288
    }
xavier@1623
   289
igor@1242
   290
    // MARK: - Action Sheet Actions
igor@1242
   291
igor@1242
   292
    func createCancelAction() -> UIAlertAction {
xavier@1623
   293
        return  UIAlertAction(title: "Cancel", style: .cancel) { (action) in}
igor@1242
   294
    }
xavier@1623
   295
igor@1242
   296
    func createReplyAction(cell: EmailListViewCell) ->  UIAlertAction {
igor@1242
   297
        return UIAlertAction(title: "Reply", style: .default) { (action) in
xavier@1623
   298
            // self.performSegue(withIdentifier: self.segueCompose, sender: cell)
igor@1338
   299
            self.performSegue(withIdentifier: .segueCompose, sender: cell)
igor@1242
   300
        }
igor@1242
   301
    }
xavier@1620
   302
xavier@1620
   303
    func createReplyAllAction(cell: EmailListViewCell) ->  UIAlertAction {
xavier@1623
   304
        return UIAlertAction(title: "Reply All", style: .default) { (action) in
xavier@1623
   305
            self.performSegue(withIdentifier: .segueReplyAll, sender: cell)
xavier@1620
   306
        }
xavier@1620
   307
    }
xavier@1620
   308
igor@1242
   309
    func createForwardAction(cell: EmailListViewCell) -> UIAlertAction {
igor@1242
   310
        return UIAlertAction(title: "Forward", style: .default) { (action) in
igor@1338
   311
            //self.performSegue(withIdentifier: self.segueCompose, sender: cell)
xavier@1664
   312
            self.performSegue(withIdentifier: .segueForward, sender: cell)
igor@1242
   313
        }
igor@1242
   314
    }
xavier@1623
   315
igor@1242
   316
    func createMarkAction() -> UIAlertAction {
igor@1242
   317
        return UIAlertAction(title: "Mark", style: .default) { (action) in
igor@1242
   318
        }
igor@1242
   319
    }
xavier@1623
   320
igor@1301
   321
    // MARK: - Content Search
xavier@1623
   322
igor@1301
   323
    func filterContentForSearchText(searchText: String) {
xavier@1623
   324
igor@1301
   325
    }
xavier@1623
   326
dirk@784
   327
}
igor@1301
   328
igor@1301
   329
extension EmailListViewController: UISearchResultsUpdating, UISearchControllerDelegate {
igor@1301
   330
    public func updateSearchResults(for searchController: UISearchController) {
igor@1301
   331
        filterContentForSearchText(searchText: searchController.searchBar.text!)
igor@1301
   332
    }
xavier@1623
   333
igor@1301
   334
    func didDismissSearchController(_ searchController: UISearchController) {
igor@1301
   335
    }
igor@1301
   336
}
igor@1338
   337
igor@1338
   338
// MARK: - Navigation
igor@1338
   339
igor@1338
   340
extension EmailListViewController: SegueHandlerType {
xavier@1623
   341
igor@1338
   342
    // MARK: - SegueHandlerType
xavier@1623
   343
igor@1338
   344
    enum SegueIdentifier: String {
igor@1338
   345
        case segueAddNewAccount
igor@1338
   346
        case segueEditAccounts
igor@1338
   347
        case segueShowEmail
igor@1338
   348
        case segueCompose
xavier@1623
   349
        case segueReplyAll
xavier@1664
   350
        case segueForward
xavier@1865
   351
        case segueFilter
igor@1338
   352
        case noSegue
igor@1338
   353
    }
xavier@1623
   354
igor@1338
   355
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
igor@1338
   356
        switch segueIdentifier(for: segue) {
xavier@1623
   357
        case .segueReplyAll:
xavier@1623
   358
            if let nav = segue.destination as? UINavigationController,
xavier@1623
   359
                let destination = nav.topViewController as? ComposeTableViewController,
xavier@1623
   360
                let cell = sender as? EmailListViewCell,
xavier@1623
   361
                let indexPath = self.tableView.indexPath(for: cell),
xavier@1623
   362
                let email = cell.messageAt(indexPath: indexPath, config: config) {
xavier@1623
   363
                destination.composeMode = .replyAll
xavier@1623
   364
                destination.appConfig = config?.appConfig
xavier@1623
   365
                destination.originalMessage = email
xavier@1623
   366
            }
igor@1338
   367
            break
igor@1338
   368
        case .segueShowEmail:
dirk@1594
   369
            if let vc = segue.destination as? EmailViewController,
igor@1338
   370
                let cell = sender as? EmailListViewCell,
igor@1338
   371
                let indexPath = self.tableView.indexPath(for: cell),
dirk@1594
   372
                let email = cell.messageAt(indexPath: indexPath, config: config) {
xavier@1623
   373
                vc.appConfig = config?.appConfig
xavier@1623
   374
                vc.message = email
igor@1338
   375
            }
igor@1338
   376
            break
xavier@1664
   377
        case .segueForward:
xavier@1664
   378
            if let nav = segue.destination as? UINavigationController,
xavier@1664
   379
                let destination = nav.topViewController as? ComposeTableViewController,
xavier@1664
   380
                let cell = sender as? EmailListViewCell,
xavier@1664
   381
                let indexPath = self.tableView.indexPath(for: cell),
xavier@1664
   382
                let email = cell.messageAt(indexPath: indexPath, config: config) {
xavier@1664
   383
                destination.composeMode = .forward
xavier@1664
   384
                destination.appConfig = config?.appConfig
xavier@1664
   385
                destination.originalMessage = email
xavier@1664
   386
            }
xavier@1664
   387
            break
xavier@1865
   388
        case .segueFilter:
xavier@1865
   389
            if let destiny = segue.destination as? FilterTableViewController {
xavier@1865
   390
                destiny.filterDelegate = self
xavier@1865
   391
                destiny.inFolder = false
xavier@1876
   392
                destiny.filterEnabled = self.config?.folder?.filter as! Filter?
xavier@1865
   393
            }
xavier@1865
   394
            break
dirk@1694
   395
        case .segueAddNewAccount, .segueEditAccounts, .segueCompose, .noSegue:
dirk@1694
   396
            break
igor@1338
   397
        }
xavier@1865
   398
igor@1338
   399
    }
dirk@1350
   400
dirk@1350
   401
    func didChangeInternal(messageFolder: MessageFolder) {
dirk@1350
   402
        if let folder = config?.folder,
dirk@1350
   403
            let message = messageFolder as? Message,
dirk@1558
   404
            folder.contains(message: message, deletedMessagesAreContained: true) {
dirk@2181
   405
            if message.isOriginal {
dirk@2181
   406
                // new message has arrived
dirk@2181
   407
                if let index = folder.indexOf(message: message) {
dirk@2181
   408
                    let ip = IndexPath(row: index, section: 0)
dirk@2181
   409
                    Log.info(
dirk@2181
   410
                        component: #function,
dirk@2181
   411
                        content: "insert message at \(index), \(folder.messageCount()) messages")
dirk@2181
   412
                    tableView.insertRows(at: [ip], with: .automatic)
dirk@1535
   413
                } else {
dirk@2181
   414
                    tableView.reloadData()
dirk@2181
   415
                }
dirk@2181
   416
            } else if message.isGhost {
dirk@2181
   417
                if let cell = cellFor(message: message), let ip = tableView.indexPath(for: cell) {
dirk@2181
   418
                    Log.info(
dirk@2181
   419
                        component: #function,
dirk@2181
   420
                        content: "delete message at \(index), \(folder.messageCount()) messages")
dirk@2181
   421
                    tableView.deleteRows(at: [ip], with: .automatic)
dirk@2181
   422
                } else {
dirk@2181
   423
                    tableView.reloadData()
dirk@2181
   424
                }
dirk@2181
   425
            } else {
dirk@2181
   426
                // other flags than delete must have been changed
dirk@2181
   427
                if let cell = cellFor(message: message) {
dirk@2181
   428
                    cell.updateFlags(message: message)
dirk@2181
   429
                } else {
dirk@2181
   430
                    tableView.reloadData()
dirk@1350
   431
                }
dirk@1350
   432
            }
dirk@1350
   433
        }
dirk@1350
   434
    }
dirk@1737
   435
dirk@1737
   436
    // MARK: - Message -> Cell association
dirk@1737
   437
dirk@1737
   438
    func keyFor(message: Message) -> NSString {
dirk@1737
   439
        let parentName = message.parent?.name ?? "unknown"
dirk@1737
   440
        return "\(message.uuid) \(parentName) \(message.uuid)" as NSString
dirk@1737
   441
    }
dirk@1737
   442
dirk@1737
   443
    func associate(message: Message, toCell: EmailListViewCell) {
dirk@1737
   444
        cellsInUse.setObject(toCell, forKey: keyFor(message: message))
dirk@1737
   445
    }
dirk@1737
   446
dirk@1737
   447
    func cellFor(message: Message) -> EmailListViewCell? {
dirk@1737
   448
        return cellsInUse.object(forKey: keyFor(message: message))
dirk@1737
   449
    }
igor@1338
   450
}
dirk@1348
   451
dirk@1348
   452
// MARK: - MessageFolderDelegate
dirk@1348
   453
dirk@1348
   454
extension EmailListViewController: MessageFolderDelegate {
dirk@1348
   455
    func didChange(messageFolder: MessageFolder) {
dirk@1675
   456
        GCD.onMainWait {
dirk@1350
   457
            self.didChangeInternal(messageFolder: messageFolder)
dirk@1348
   458
        }
dirk@1348
   459
    }
dirk@1348
   460
}