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