pEpForiOS/UI/EmailDisplay/EmailListViewController.swift
author buff <andreas@pep-project.org>
Tue, 24 Oct 2017 17:15:23 +0200
branchIOS-694
changeset 3289 f6a91b6ccbce
parent 3287 2227a62c88d5
child 3291 e8000000e820
permissions -rw-r--r--
IOS-964 reverts accidentally checked in commented code
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 UIKit
dirk@810
    10
import MessageModel
dirk@810
    11
andreas@3151
    12
class EmailListViewController: BaseTableViewController {
andreas@3223
    13
    var folderToShow: Folder?
andreas@3223
    14
andreas@3151
    15
    func updateLastLookAt() {
andreas@3224
    16
        guard let saveFolder = folderToShow else {
andreas@3151
    17
            return
andreas@3151
    18
        }
andreas@3151
    19
        saveFolder.updateLastLookAt()
andreas@3151
    20
    }
andreas@3208
    21
    
andreas@3151
    22
    private var model: EmailListViewModel?
andreas@3208
    23
    
andreas@3151
    24
    private let queue: OperationQueue = {
andreas@3151
    25
        let createe = OperationQueue()
andreas@3151
    26
        createe.qualityOfService = .userInteractive
andreas@3151
    27
        createe.maxConcurrentOperationCount = 10
andreas@3151
    28
        return createe
andreas@3151
    29
    }()
andreas@3151
    30
    private var operations = [IndexPath:Operation]()
andreas@2838
    31
    public static let storyboardId = "EmailListViewController"
andreas@3151
    32
    fileprivate var lastSelectedIndexPath: IndexPath?
andreas@3208
    33
    
igor@1301
    34
    let searchController = UISearchController(searchResultsController: nil)
andreas@3208
    35
    
andreas@3151
    36
    // MARK: - Outlets
andreas@3208
    37
    
dirk@2067
    38
    @IBOutlet weak var enableFilterButton: UIBarButtonItem!
dirk@2067
    39
    @IBOutlet weak var textFilterButton: UIBarButtonItem!
andreas@3151
    40
    @IBOutlet var showFoldersButton: UIBarButtonItem!
andreas@3208
    41
    
andreas@3151
    42
    // MARK: - Life Cycle
andreas@3208
    43
    
dirk@275
    44
    override func viewDidLoad() {
ylandert@935
    45
        super.viewDidLoad()
dirk@2189
    46
        title = NSLocalizedString("Inbox", comment: "General name for (unified) inbox")
igor@1284
    47
        UIHelper.emailListTableHeight(self.tableView)
andreas@3163
    48
        self.textFilterButton.isEnabled = false
igor@1301
    49
        addSearchBar()
dirk@275
    50
    }
andreas@3208
    51
    
dirk@784
    52
    override func viewWillAppear(_ animated: Bool) {
igor@1301
    53
        super.viewWillAppear(animated)
xavier@2325
    54
        self.navigationController?.setToolbarHidden(false, animated: true)
dirk@1344
    55
        if MiscUtil.isUnitTest() {
dirk@1344
    56
            return
dirk@1344
    57
        }
andreas@3223
    58
dirk@1826
    59
        setDefaultColors()
andreas@3151
    60
        setup()
andreas@3208
    61
        
dirk@2191
    62
        // Mark this folder as having been looked at by the user
andreas@3151
    63
        updateLastLookAt()
andreas@3151
    64
        setupFoldersBarButton()
andreas@3151
    65
    }
andreas@3208
    66
    
andreas@3151
    67
    // MARK: - NavigationBar
andreas@3208
    68
    
andreas@3151
    69
    private func hideFoldersNavigationBarButton() {
andreas@3151
    70
        self.showFoldersButton.isEnabled = false
andreas@3151
    71
        self.showFoldersButton.tintColor = UIColor.clear
andreas@3151
    72
    }
andreas@3208
    73
    
andreas@3151
    74
    private func showFoldersNavigationBarButton() {
andreas@3151
    75
        self.showFoldersButton.isEnabled = true
andreas@3151
    76
        self.showFoldersButton.tintColor = nil
andreas@3151
    77
    }
andreas@3208
    78
    
andreas@3151
    79
    private func resetModel() {
andreas@3223
    80
        if folderToShow != nil {
andreas@3223
    81
            model = EmailListViewModel(delegate: self, folderToShow: folderToShow)
xavier@2585
    82
        }
dirk@1348
    83
    }
andreas@3208
    84
    
andreas@3151
    85
    private func setup() {
andreas@3289
    86
        if noAccountsExist() {
andreas@3272
    87
            // No account exists. Show account setup.
andreas@3272
    88
            performSegue(withIdentifier:.segueAddNewAccount, sender: self)
andreas@3289
    89
        } else if let vm = model {
andreas@3223
    90
            // We came back from e.g EmailView ...
andreas@3223
    91
            updateFilterText()
andreas@3223
    92
            // ... so we want to update "seen" status
andreas@3226
    93
            vm.reloadData()
andreas@3272
    94
        } else if folderToShow == nil {
andreas@3223
    95
            // We have not been created to show a specific folder, thus we show unified inbox
andreas@3151
    96
            folderToShow = UnifiedInbox()
andreas@3223
    97
            resetModel()
andreas@3272
    98
        } else if model == nil {
andreas@3223
    99
            // We still got no model, because:
andreas@3223
   100
            // - We are not coming back from a pushed view (for instance ComposeEmailView)
andreas@3223
   101
            // - We are not a UnifiedInbox
andreas@3226
   102
            // So we have been created to show a specific folder. Show it!
andreas@3223
   103
            resetModel()
andreas@3151
   104
        }
andreas@3272
   105
andreas@3151
   106
        self.title = realNameOfFolderToShow()
andreas@2683
   107
    }
andreas@3223
   108
andreas@3223
   109
    private func weCameBackFromAPushedView() -> Bool {
andreas@3223
   110
        return model != nil
andreas@3223
   111
    }
andreas@3208
   112
    
andreas@3151
   113
    private func noAccountsExist() -> Bool {
andreas@3151
   114
        return Account.all().isEmpty
igor@1301
   115
    }
andreas@3208
   116
    
andreas@3151
   117
    private func setupFoldersBarButton() {
andreas@3151
   118
        if let size = navigationController?.viewControllers.count, size > 1 {
andreas@3151
   119
            hideFoldersNavigationBarButton()
andreas@3151
   120
        } else {
andreas@3151
   121
            showFoldersNavigationBarButton()
xavier@2132
   122
        }
igor@1338
   123
    }
andreas@3208
   124
    
andreas@3151
   125
    private func addSearchBar() {
igor@1301
   126
        searchController.searchResultsUpdater = self
igor@1301
   127
        searchController.dimsBackgroundDuringPresentation = false
igor@1301
   128
        searchController.delegate = self
igor@1301
   129
        definesPresentationContext = true
igor@1301
   130
        tableView.tableHeaderView = searchController.searchBar
xavier@3209
   131
        tableView.setContentOffset(CGPoint(x: 0.0, y: searchController.searchBar.frame.size.height), animated: false)
igor@1301
   132
    }
andreas@3208
   133
    
andreas@3151
   134
    // MARK: - Other
andreas@3208
   135
    
andreas@3151
   136
    private func realNameOfFolderToShow() -> String? {
andreas@3224
   137
        return folderToShow?.realName
andreas@2697
   138
    }
andreas@3208
   139
    
andreas@3151
   140
    private func configure(cell: EmailListViewCell, for indexPath: IndexPath) {
andreas@3151
   141
        // Configure lightweight stuff on main thread ...
andreas@3151
   142
        guard let saveModel = model else {
andreas@3151
   143
            return
xavier@2967
   144
        }
andreas@3151
   145
        guard let row = saveModel.row(for: indexPath) else {
andreas@3151
   146
            Log.shared.errorAndCrash(component: #function, errorString: "We should have a row here")
andreas@3151
   147
            return
andreas@3151
   148
        }
andreas@3151
   149
        cell.senderLabel.text = row.from
andreas@3151
   150
        cell.subjectLabel.text = row.subject
andreas@3151
   151
        cell.summaryLabel.text = row.bodyPeek
andreas@3151
   152
        cell.isFlagged = row.isFlagged
andreas@3151
   153
        cell.isSeen = row.isSeen
andreas@3151
   154
        cell.hasAttachment = row.showAttchmentIcon
andreas@3151
   155
        cell.dateLabel.text = row.dateText
andreas@3151
   156
        // Set image from cache if any
andreas@3151
   157
        cell.setContactImage(image: row.senderContactImage)
andreas@3208
   158
        
andreas@3151
   159
        let op = BlockOperation() { [weak self] in
andreas@3151
   160
            // ... and expensive computations in background
andreas@3151
   161
            guard let strongSelf = self else {
andreas@3151
   162
                // View is gone, nothing to do.
andreas@3151
   163
                return
andreas@3151
   164
            }
andreas@3208
   165
            
andreas@3151
   166
            var senderImage: UIImage?
andreas@3151
   167
            if row.senderContactImage == nil {
andreas@3220
   168
                // image for identity has not been cached yet
andreas@3220
   169
                // Get and cache it here in the background ...
andreas@3151
   170
                senderImage = strongSelf.model?.senderImage(forCellAt: indexPath)
andreas@3220
   171
andreas@3220
   172
                // ... and set it on the main queue
andreas@3220
   173
                DispatchQueue.main.async {
andreas@3220
   174
                    if senderImage != nil && senderImage != cell.contactImageView.image {
andreas@3220
   175
                        cell.contactImageView.image  = senderImage
andreas@3220
   176
                    }
andreas@3220
   177
                }
andreas@3151
   178
            }
andreas@3220
   179
andreas@3220
   180
            let pEpRatingImage = strongSelf.model?.pEpRatingColorImage(forCellAt: indexPath)
andreas@3220
   181
andreas@3151
   182
            // In theory we want to set all data in *one* async call. But as pEpRatingColorImage takes
andreas@3151
   183
            // very long, we are setting the sender image seperatelly.
andreas@3151
   184
            DispatchQueue.main.async {
andreas@3151
   185
                if pEpRatingImage != nil {
andreas@3151
   186
                    cell.setPepRatingImage(image: pEpRatingImage)
andreas@3151
   187
                }
andreas@3151
   188
            }
andreas@3151
   189
        }
andreas@3151
   190
        queue(operation: op, for: indexPath)
xavier@2967
   191
    }
andreas@3208
   192
    
andreas@3151
   193
    // MARK: - Actions
andreas@3208
   194
    
andreas@3151
   195
    @IBAction func filterButtonHasBeenPressed(_ sender: UIBarButtonItem) {
andreas@3163
   196
        guard let vm = model else {
andreas@3163
   197
            Log.shared.errorAndCrash(component: #function, errorString: "We should have a model here")
andreas@3163
   198
            return
andreas@3163
   199
        }
andreas@3163
   200
        vm.isFilterEnabled = !vm.isFilterEnabled
xavier@3193
   201
        updateFilterButtonView()
xavier@1832
   202
    }
andreas@3208
   203
    
xavier@3193
   204
    func updateFilterButtonView() {
andreas@3163
   205
        guard let vm = model else {
andreas@3163
   206
            Log.shared.errorAndCrash(component: #function, errorString: "We should have a model here")
andreas@3163
   207
            return
andreas@3163
   208
        }
andreas@3208
   209
        
andreas@3163
   210
        textFilterButton.isEnabled = vm.isFilterEnabled
andreas@3163
   211
        if textFilterButton.isEnabled {
andreas@3163
   212
            enableFilterButton.image = UIImage(named: "unread-icon-active")
andreas@3163
   213
            updateFilterText()
andreas@3163
   214
        } else {
andreas@3163
   215
            textFilterButton.title = ""
andreas@3163
   216
            enableFilterButton.image = UIImage(named: "unread-icon")
andreas@3163
   217
        }
andreas@3163
   218
    }
andreas@3208
   219
    
andreas@3163
   220
    func updateFilterText() {
xavier@3193
   221
        if let vm = model, let txt = vm.activeFilter?.title {
andreas@3163
   222
            textFilterButton.title = "Filter by: " + txt
andreas@3163
   223
        }
andreas@3151
   224
    }
andreas@3208
   225
    
dirk@31
   226
    // MARK: - UITableViewDataSource
andreas@3208
   227
    
dirk@784
   228
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
andreas@3151
   229
        return model?.rowCount ?? 0
dirk@31
   230
    }
andreas@3208
   231
    
dirk@784
   232
    override func tableView(_ tableView: UITableView,
dirk@784
   233
                            cellForRowAt indexPath: IndexPath) -> UITableViewCell {
andreas@3151
   234
        guard let cell = tableView.dequeueReusableCell(withIdentifier: EmailListViewCell.storyboardId,
andreas@3151
   235
                                                       for: indexPath) as? EmailListViewCell
andreas@3151
   236
            else {
andreas@3151
   237
                Log.shared.errorAndCrash(component: #function, errorString: "Wrong cell!")
andreas@3151
   238
                return UITableViewCell()
andreas@3151
   239
        }
andreas@3151
   240
        configure(cell: cell, for: indexPath)
dirk@31
   241
        return cell
dirk@31
   242
    }
andreas@3208
   243
    
dirk@719
   244
    // MARK: - UITableViewDelegate
andreas@3208
   245
    
dirk@784
   246
    override func tableView(_ tableView: UITableView, editActionsForRowAt
dirk@784
   247
        indexPath: IndexPath)-> [UITableViewRowAction]? {
andreas@3151
   248
        guard let flagAction = createFlagAction(forCellAt: indexPath),
andreas@3151
   249
            let deleteAction = createDeleteAction(forCellAt: indexPath),
andreas@3151
   250
            let moreAction = createMoreAction(forCellAt: indexPath) else {
andreas@3151
   251
                Log.shared.errorAndCrash(component: #function, errorString: "Error creating action.")
andreas@3151
   252
                return nil
dirk@855
   253
        }
andreas@3151
   254
        return [deleteAction, flagAction, moreAction]
dirk@744
   255
    }
andreas@3208
   256
    
andreas@3151
   257
    override func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
andreas@3151
   258
        cancelOperation(for: indexPath)
dirk@744
   259
    }
andreas@3208
   260
    
andreas@3151
   261
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
andreas@3151
   262
        lastSelectedIndexPath = indexPath
andreas@3151
   263
        tableView.selectRow(at: indexPath, animated: true, scrollPosition: .none)
andreas@3151
   264
        performSegue(withIdentifier: SegueIdentifier.segueShowEmail, sender: self)
dirk@744
   265
    }
andreas@3278
   266
andreas@3278
   267
    //BUFF:
andreas@3287
   268
    private let numRowsBeforeLastToTriggerFetchOder = 1
andreas@3278
   269
    private func triggerFetchOlder(lastDisplayedRow row: Int) -> Bool {
andreas@3278
   270
        guard let vm = model else {
andreas@3278
   271
            return false
andreas@3278
   272
        }
andreas@3278
   273
        return row >= vm.rowCount - numRowsBeforeLastToTriggerFetchOder
andreas@3278
   274
    }
andreas@3278
   275
andreas@3278
   276
    override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell,
andreas@3278
   277
                            forRowAt indexPath: IndexPath) {
andreas@3278
   278
andreas@3278
   279
        guard let folder = folderToShow,
andreas@3278
   280
            !(folder is UnifiedInbox) else {
andreas@3278
   281
                return //BUFF: check unified logic
andreas@3278
   282
        }
andreas@3278
   283
        if triggerFetchOlder(lastDisplayedRow: indexPath.row) {
andreas@3278
   284
            appConfig.messageSyncService.requestFetchOlderMessages(inFolder: folder)
andreas@3278
   285
        }
andreas@3278
   286
    }
andreas@3278
   287
    //FFUB
andreas@3208
   288
    
andreas@3151
   289
    // MARK: - Queue Handling
andreas@3208
   290
    
andreas@3151
   291
    private func queue(operation op:Operation, for indexPath: IndexPath) {
andreas@3151
   292
        operations[indexPath] = op
andreas@3151
   293
        queue.addOperation(op)
dirk@1507
   294
    }
andreas@3208
   295
    
andreas@3151
   296
    private func cancelOperation(for indexPath:IndexPath) {
andreas@3151
   297
        guard let op = operations.removeValue(forKey: indexPath) else {
andreas@3151
   298
            return
dirk@744
   299
        }
andreas@3151
   300
        if !op.isCancelled  {
andreas@3151
   301
            op.cancel()
dirk@1507
   302
        }
dirk@744
   303
    }
andreas@3208
   304
    
andreas@3151
   305
    override func didReceiveMemoryWarning() {
andreas@3151
   306
        model?.freeMemory()
andreas@3151
   307
    }
andreas@3151
   308
}
andreas@3151
   309
andreas@3151
   310
// MARK: - UISearchResultsUpdating, UISearchControllerDelegate
andreas@3151
   311
andreas@3151
   312
extension EmailListViewController: UISearchResultsUpdating, UISearchControllerDelegate {
andreas@3151
   313
    public func updateSearchResults(for searchController: UISearchController) {
andreas@3151
   314
        guard let vm = model, let searchText = searchController.searchBar.text else {
andreas@3151
   315
            return
igor@1242
   316
        }
andreas@3163
   317
        vm.setSearchFilter(forSearchText: searchText)
igor@1242
   318
    }
andreas@3208
   319
    
andreas@3151
   320
    func didDismissSearchController(_ searchController: UISearchController) {
andreas@3151
   321
        guard let vm = model else {
andreas@3151
   322
            return
andreas@3151
   323
        }
andreas@3151
   324
        vm.removeSearchFilter()
andreas@3151
   325
    }
andreas@3151
   326
}
xavier@1623
   327
andreas@3151
   328
// MARK: - EmailListModelDelegate
andreas@3151
   329
andreas@3151
   330
extension EmailListViewController: EmailListViewModelDelegate {
andreas@3151
   331
    func emailListViewModel(viewModel: EmailListViewModel, didInsertDataAt indexPath: IndexPath) {
andreas@3166
   332
        tableView.beginUpdates()
andreas@3151
   333
        tableView.insertRows(at: [indexPath], with: .automatic)
andreas@3151
   334
        tableView.endUpdates()
andreas@3151
   335
    }
andreas@3208
   336
    
andreas@3151
   337
    func emailListViewModel(viewModel: EmailListViewModel, didRemoveDataAt indexPath: IndexPath) {
andreas@3151
   338
        tableView.beginUpdates()
andreas@3151
   339
        tableView.deleteRows(at: [indexPath], with: .automatic)
andreas@3151
   340
        tableView.endUpdates()
andreas@3151
   341
    }
andreas@3208
   342
    
andreas@3151
   343
    func emailListViewModel(viewModel: EmailListViewModel, didUpdateDataAt indexPath: IndexPath) {
andreas@3151
   344
        tableView.beginUpdates()
andreas@3151
   345
        tableView.reloadRows(at: [indexPath], with: .none)
andreas@3151
   346
        tableView.endUpdates()
andreas@3151
   347
    }
andreas@3208
   348
    
andreas@3151
   349
    func updateView() {
andreas@3151
   350
        self.tableView.reloadData()
andreas@3151
   351
    }
andreas@3151
   352
}
andreas@3151
   353
andreas@3151
   354
// MARK: - ActionSheet & ActionSheet Actions
andreas@3151
   355
andreas@3151
   356
extension EmailListViewController {
andreas@3166
   357
    func showMoreActionSheet(forRowAt indexPath: IndexPath) {
andreas@3151
   358
        lastSelectedIndexPath = indexPath
igor@1242
   359
        let alertControler = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
igor@1438
   360
        alertControler.view.tintColor = .pEpGreen
igor@1242
   361
        let cancelAction = createCancelAction()
andreas@3151
   362
        let replyAction = createReplyAction()
andreas@3151
   363
        let replyAllAction = createReplyAllAction()
andreas@3151
   364
        let forwardAction = createForwardAction()
igor@1242
   365
        alertControler.addAction(cancelAction)
igor@1242
   366
        alertControler.addAction(replyAction)
xavier@1620
   367
        alertControler.addAction(replyAllAction)
igor@1242
   368
        alertControler.addAction(forwardAction)
igor@1414
   369
        if let popoverPresentationController = alertControler.popoverPresentationController {
andreas@3151
   370
            popoverPresentationController.sourceView = tableView
igor@1414
   371
        }
igor@1242
   372
        present(alertControler, animated: true, completion: nil)
igor@1242
   373
    }
andreas@3208
   374
    
andreas@3151
   375
    // MARK: Action Sheet Actions
andreas@3208
   376
    
igor@1242
   377
    func createCancelAction() -> UIAlertAction {
andreas@3151
   378
        return  UIAlertAction(title: "Cancel", style: .cancel) { (action) in
andreas@3151
   379
            self.tableView.beginUpdates()
andreas@3151
   380
            self.tableView.setEditing(false, animated: true)
andreas@3151
   381
            self.tableView.endUpdates()
igor@1242
   382
        }
igor@1242
   383
    }
andreas@3208
   384
    
andreas@3151
   385
    func createReplyAction() ->  UIAlertAction {
andreas@3151
   386
        return UIAlertAction(title: "Reply", style: .default) { (action) in
andreas@3151
   387
            self.performSegue(withIdentifier: .segueReply, sender: self)
xavier@1620
   388
        }
xavier@1620
   389
    }
andreas@3208
   390
    
andreas@3151
   391
    func createReplyAllAction() ->  UIAlertAction {
andreas@3151
   392
        return UIAlertAction(title: "Reply All", style: .default) { (action) in
andreas@3151
   393
            self.performSegue(withIdentifier: .segueReplyAll, sender: self)
igor@1242
   394
        }
igor@1242
   395
    }
andreas@3208
   396
    
andreas@3151
   397
    func createForwardAction() -> UIAlertAction {
andreas@3151
   398
        return UIAlertAction(title: "Forward", style: .default) { (action) in
andreas@3151
   399
            self.performSegue(withIdentifier: .segueForward, sender: self)
xavier@2369
   400
        }
igor@1301
   401
    }
igor@1301
   402
}
igor@1338
   403
andreas@3151
   404
// MARK: - TableViewCell Actions
andreas@3151
   405
andreas@3151
   406
extension EmailListViewController {
andreas@3151
   407
    private func createRowAction(image: UIImage?,
xavier@3266
   408
                                 action: @escaping (UITableViewRowAction, IndexPath) -> Void
xavier@3266
   409
        ) -> UITableViewRowAction {
xavier@3266
   410
        let rowAction = UITableViewRowAction(style: .normal, title: nil, handler: action)
andreas@3151
   411
        if let theImage = image {
andreas@3151
   412
            let iconColor = UIColor(patternImage: theImage)
andreas@3151
   413
            rowAction.backgroundColor = iconColor
andreas@3151
   414
        }
andreas@3151
   415
        return rowAction
andreas@3151
   416
    }
andreas@3208
   417
    
andreas@3151
   418
    func createFlagAction(forCellAt indexPath: IndexPath) -> UITableViewRowAction? {
andreas@3151
   419
        guard let row = model?.row(for: indexPath) else {
andreas@3151
   420
            Log.shared.errorAndCrash(component: #function, errorString: "No data for indexPath!")
andreas@3151
   421
            return nil
andreas@3151
   422
        }
andreas@3151
   423
        func action(action: UITableViewRowAction, indexPath: IndexPath) -> Void {
andreas@3151
   424
            if row.isFlagged {
andreas@3151
   425
                model?.unsetFlagged(forIndexPath: indexPath)
andreas@3151
   426
            } else {
andreas@3151
   427
                model?.setFlagged(forIndexPath: indexPath)
andreas@3151
   428
            }
andreas@3151
   429
            tableView.beginUpdates()
andreas@3151
   430
            tableView.setEditing(false, animated: true)
andreas@3166
   431
            tableView.reloadRows(at: [indexPath], with: .none)
andreas@3151
   432
            tableView.endUpdates()
andreas@3151
   433
        }
xavier@3266
   434
        return createRowAction(image: UIImage(named: "swipe-flag"), action: action)
andreas@3151
   435
    }
andreas@3208
   436
    
andreas@3151
   437
    func createDeleteAction(forCellAt indexPath: IndexPath) -> UITableViewRowAction? {
andreas@3151
   438
        func action(action: UITableViewRowAction, indexPath: IndexPath) -> Void {
andreas@3151
   439
            tableView.beginUpdates()
andreas@3151
   440
            model?.delete(forIndexPath: indexPath) // mark for deletion/trash
andreas@3151
   441
            tableView.deleteRows(at: [indexPath], with: .none)
andreas@3151
   442
            tableView.endUpdates()
andreas@3151
   443
        }
xavier@3266
   444
xavier@3266
   445
        return createRowAction(image: UIImage(named: "swipe-trash"), action: action)
andreas@3151
   446
    }
andreas@3208
   447
    
andreas@3151
   448
    func createMoreAction(forCellAt indexPath: IndexPath) -> UITableViewRowAction? {
andreas@3151
   449
        func action(action: UITableViewRowAction, indexPath: IndexPath) -> Void {
andreas@3151
   450
            self.showMoreActionSheet(forRowAt: indexPath)
andreas@3151
   451
        }
xavier@3266
   452
andreas@3151
   453
        return createRowAction(image: UIImage(named: "swipe-more"),
xavier@3266
   454
                               action: action)
andreas@3151
   455
    }
andreas@3151
   456
}
andreas@3151
   457
andreas@3151
   458
// MARK: - SegueHandlerType
igor@1338
   459
igor@1338
   460
extension EmailListViewController: SegueHandlerType {
andreas@3208
   461
    
igor@1338
   462
    enum SegueIdentifier: String {
igor@1338
   463
        case segueAddNewAccount
igor@1338
   464
        case segueShowEmail
igor@1338
   465
        case segueCompose
xavier@2715
   466
        case segueReply
xavier@1623
   467
        case segueReplyAll
xavier@1664
   468
        case segueForward
xavier@1865
   469
        case segueFilter
xavier@2248
   470
        case segueFolderViews
igor@1338
   471
        case noSegue
igor@1338
   472
    }
andreas@3208
   473
    
andreas@3110
   474
    private func setup(composeViewController vc: ComposeTableViewController,
andreas@3110
   475
                       composeMode: ComposeTableViewController.ComposeMode = .normal,
andreas@3110
   476
                       originalMessage: Message? = nil) {
andreas@3110
   477
        vc.appConfig = appConfig
andreas@3110
   478
        vc.composeMode = composeMode
andreas@3110
   479
        vc.originalMessage = originalMessage
andreas@3223
   480
        vc.origin = folderToShow?.account.user
andreas@3110
   481
    }
andreas@3208
   482
    
igor@1338
   483
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
igor@1338
   484
        switch segueIdentifier(for: segue) {
xavier@2715
   485
        case .segueReply:
andreas@2850
   486
            guard let nav = segue.destination as? UINavigationController,
xavier@2715
   487
                let destination = nav.topViewController as? ComposeTableViewController,
andreas@3151
   488
                let indexPath = lastSelectedIndexPath,
andreas@3151
   489
                let message = model?.message(representedByRowAt: indexPath) else {
andreas@2850
   490
                    Log.shared.errorAndCrash(component: #function, errorString: "Segue issue")
andreas@2850
   491
                    return
xavier@2715
   492
            }
andreas@3110
   493
            setup(composeViewController: destination, composeMode: .replyFrom,
andreas@3151
   494
                  originalMessage: message)
xavier@1623
   495
        case .segueReplyAll:
andreas@2850
   496
            guard let nav = segue.destination as? UINavigationController,
xavier@1623
   497
                let destination = nav.topViewController as? ComposeTableViewController,
andreas@3151
   498
                let indexPath = lastSelectedIndexPath,
andreas@3151
   499
                let message = model?.message(representedByRowAt: indexPath) else {
andreas@2850
   500
                    Log.shared.errorAndCrash(component: #function, errorString: "Segue issue")
andreas@2850
   501
                    return
xavier@1623
   502
            }
andreas@3110
   503
            setup(composeViewController: destination, composeMode: .replyAll,
andreas@3151
   504
                  originalMessage: message)
andreas@3111
   505
        case .segueShowEmail:
andreas@2850
   506
            guard let vc = segue.destination as? EmailViewController,
andreas@3151
   507
                let indexPath = lastSelectedIndexPath,
andreas@3208
   508
                let message = model?.message(representedByRowAt: indexPath) else {
andreas@2850
   509
                    Log.shared.errorAndCrash(component: #function, errorString: "Segue issue")
andreas@2850
   510
                    return
igor@1338
   511
            }
andreas@2850
   512
            vc.appConfig = appConfig
andreas@3151
   513
            vc.message = message
andreas@3223
   514
            vc.folderShow = folderToShow
andreas@3166
   515
            vc.messageId = indexPath.row //that looks wrong
xavier@1664
   516
        case .segueForward:
andreas@2850
   517
            guard let nav = segue.destination as? UINavigationController,
xavier@1664
   518
                let destination = nav.topViewController as? ComposeTableViewController,
andreas@3151
   519
                let indexPath = lastSelectedIndexPath,
andreas@3151
   520
                let message = model?.message(representedByRowAt: indexPath) else {
andreas@2850
   521
                    Log.shared.errorAndCrash(component: #function, errorString: "Segue issue")
andreas@2850
   522
                    return
xavier@1664
   523
            }
andreas@3110
   524
            setup(composeViewController: destination, composeMode: .forward,
andreas@3151
   525
                  originalMessage: message)
andreas@2850
   526
        case .segueFilter:
andreas@2850
   527
            guard let destiny = segue.destination as? FilterTableViewController  else {
andreas@2850
   528
                Log.shared.errorAndCrash(component: #function, errorString: "Segue issue")
andreas@2850
   529
                return
andreas@2850
   530
            }
andreas@2850
   531
            destiny.appConfig = appConfig
andreas@3163
   532
            destiny.filterDelegate = model
andreas@2850
   533
            destiny.inFolder = false
andreas@3223
   534
            destiny.filterEnabled = folderToShow?.filter
andreas@2850
   535
            destiny.hidesBottomBarWhenPushed = true
andreas@2850
   536
        case .segueAddNewAccount:
andreas@2850
   537
            guard let vc = segue.destination as? LoginTableViewController  else {
andreas@2850
   538
                Log.shared.errorAndCrash(component: #function, errorString: "Segue issue")
andreas@2850
   539
                return
andreas@2850
   540
            }
andreas@2850
   541
            vc.appConfig = appConfig
andreas@2850
   542
            vc.hidesBottomBarWhenPushed = true
xavier@1664
   543
            break
andreas@2850
   544
        case .segueFolderViews:
andreas@2850
   545
            guard let vC = segue.destination as? FolderTableViewController  else {
andreas@2850
   546
                Log.shared.errorAndCrash(component: #function, errorString: "Segue issue")
andreas@2850
   547
                return
xavier@1865
   548
            }
andreas@2850
   549
            vC.appConfig = appConfig
andreas@2850
   550
            vC.hidesBottomBarWhenPushed = true
xavier@1865
   551
            break
andreas@2850
   552
        case .segueCompose:
andreas@2850
   553
            guard let nav = segue.destination as? UINavigationController,
dirk@2957
   554
                let destination = nav.rootViewController as? ComposeTableViewController else {
andreas@2850
   555
                    Log.shared.errorAndCrash(component: #function, errorString: "Segue issue")
andreas@2850
   556
                    return
dirk@2240
   557
            }
andreas@3110
   558
            setup(composeViewController: destination)
andreas@2850
   559
        default:
andreas@2850
   560
            Log.shared.errorAndCrash(component: #function, errorString: "Unhandled segue")
dirk@1694
   561
            break
igor@1338
   562
        }
andreas@2838
   563
    }
andreas@3208
   564
    
andreas@3166
   565
    @IBAction func segueUnwindAccountAdded(segue: UIStoryboardSegue) {
andreas@3151
   566
        // nothing to do.
andreas@3150
   567
    }
dirk@1348
   568
}