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