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