-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
SharingAccountViewController.swift
285 lines (218 loc) · 10.2 KB
/
SharingAccountViewController.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
import UIKit
import Gridicons
import WordPressShared
/// Displays a list of available keyring connection accounts that can be used to
/// forge a publicize connection.
///
@objc open class SharingAccountViewController: UITableViewController {
var publicizeService: PublicizeService
var keyringConnections: [KeyringConnection]
var existingPublicizeConnections: [PublicizeConnection]?
var immutableHandler: ImmuTableViewHandler!
var delegate: SharingAccountSelectionDelegate?
// MARK: - Lifecycle Methods
init(service: PublicizeService, connections: [KeyringConnection], existingConnections: [PublicizeConnection]?) {
publicizeService = service
keyringConnections = connections
existingPublicizeConnections = existingConnections
super.init(style: .grouped)
navigationItem.title = publicizeService.label
}
required public init?(coder aDecoder: NSCoder) {
// TODO:
fatalError("init(coder:) has not been implemented")
}
open override func viewDidLoad() {
super.viewDidLoad()
configureNavbar()
configureTableView()
}
// MARK: - Configuration
/// Configures the appearance of the nav bar.
///
fileprivate func configureNavbar() {
let image = Gridicon.iconOfType(.cross)
let closeButton = UIBarButtonItem(image: image, style: .plain, target: self, action: #selector(SharingAccountViewController.handleCloseTapped(_:)))
closeButton.tintColor = UIColor.white
navigationItem.leftBarButtonItem = closeButton
// The preceding WPWebViewController changes the default navbar appearance. Restore it.
if let navBar = navigationController?.navigationBar {
navBar.shadowImage = WPStyleGuide.navigationBarShadowImage()
navBar.setBackgroundImage(WPStyleGuide.navigationBarBackgroundImage(), for: .default)
navBar.barStyle = WPStyleGuide.navigationBarBarStyle()
}
}
/// Configures the `UITableView`
///
fileprivate func configureTableView() {
WPStyleGuide.configureColors(for: view, andTableView: tableView)
ImmuTable.registerRows([TextRow.self], tableView: tableView)
immutableHandler = ImmuTableViewHandler(takeOver: self)
immutableHandler.viewModel = tableViewModel()
}
// MARK: - View Model Wrangling
/// Builds and returns the ImmuTable view model.
///
/// - Returns: An ImmuTable instance.
///
fileprivate func tableViewModel() -> ImmuTable {
var sections = [ImmuTableSection]()
var connectedAccounts = [KeyringAccount]()
var accounts = keyringAccountsFromKeyringConnections(keyringConnections)
// Filter out connected accounts into a different Array
for (idx, acct) in accounts.enumerated() {
if accountIsConnected(acct) {
connectedAccounts.append(acct)
accounts.remove(at: idx)
break
}
}
// Build the section for unconnected accounts
var rows = rowsForUnconnectedKeyringAccounts(accounts)
if let section = sectionForUnconnectedKeyringAccountRows(rows) {
sections.append(section)
}
// Build the section for connected accounts
rows = rowsForConnectedKeyringAccounts(connectedAccounts)
if rows.count > 0 {
let title = NSLocalizedString("Connected", comment: "Adjective. The title of a list of third-part sharing service account names.")
let section = ImmuTableSection(headerText: title, rows: rows, footerText: nil)
sections.append(section)
}
return ImmuTable(sections: sections)
}
/// Builds the ImmuTableSection that displays unconnected keyring accounts.
///
/// - Parameter rows: An array of ImmuTableRow objects appearing in the section.
///
/// - Returns: An ImmuTableSection or `nil` if there were no rows.
///
fileprivate func sectionForUnconnectedKeyringAccountRows(_ rows: [ImmuTableRow]) -> ImmuTableSection? {
if rows.count == 0 {
return nil
}
var title = NSLocalizedString("Connecting %@", comment: "Connecting is a verb. Title of Publicize account selection. The %@ is a placeholder for the service's name")
title = NSString(format: title as NSString, publicizeService.label) as String
let manyAccountFooter = NSLocalizedString("Select the account you would like to authorize. Note that your posts will be automatically shared to the selected account.", comment: "")
let oneAccountFooter = NSLocalizedString("Confirm this is the account you would like to authorize. Note that your posts will be automatically shared to this account.", comment: "")
let footer = rows.count > 1 ? manyAccountFooter : oneAccountFooter
return ImmuTableSection(headerText: title, rows: rows, footerText: footer)
}
/// Builds the ImmuTableSection that displays connected keyring accounts.
///
/// - Parameter rows: An array of ImmuTableRow objects appearing in the section.
///
/// - Returns: An ImmuTableSection or `nil` if there were no rows.
///
fileprivate func rowsForUnconnectedKeyringAccounts(_ accounts: [KeyringAccount]) -> [ImmuTableRow] {
var rows = [ImmuTableRow]()
for acct in accounts {
let row = KeyringRow(title: acct.name, value: "", action: actionForRow(acct))
rows.append(row)
}
return rows
}
/// Builds an ImmuTableAction that should be performed when a specific row is selected.
///
/// - Parameter keyringAccount: The keyring account for the row.
///
/// - Returns: An ImmuTableAction instance.
///
fileprivate func actionForRow(_ keyringAccount: KeyringAccount) -> ImmuTableAction {
return { [unowned self] row in
self.tableView.deselectSelectedRowWithAnimation(true)
self.delegate?.sharingAccountViewController(self,
selectedKeyringConnection: keyringAccount.keyringConnection,
externalID: keyringAccount.externalID)
}
}
/// Builds ImmuTableRows for the specified keyring accounts.
///
/// - Parameter accounts: An array of KeyringAccount objects.
///
/// - Returns: An array of ImmuTableRows representing the keyring accounts.
///
fileprivate func rowsForConnectedKeyringAccounts(_ accounts: [KeyringAccount]) -> [ImmuTableRow] {
var rows = [ImmuTableRow]()
for acct in accounts {
let row = TextRow(title: acct.name, value: "")
rows.append(row)
}
return rows
}
/// Normalizes available accounts for a KeyringConnection and its `additionalExternalUsers`
///
/// - Parameter connections: An array of `KeyringConnection` instances to normalize.
///
/// - Returns: An array of `KeyringAccount` objects.
///
fileprivate func keyringAccountsFromKeyringConnections(_ connections: [KeyringConnection]) -> [KeyringAccount] {
var accounts = [KeyringAccount]()
for connection in connections {
let acct = KeyringAccount(name: connection.externalDisplay, externalID: nil, externalIDForConnection: connection.externalID, keyringConnection: connection)
accounts.append(acct)
for externalUser in connection.additionalExternalUsers {
let acct = KeyringAccount(name: externalUser.externalName, externalID: externalUser.externalID, externalIDForConnection: externalUser.externalID, keyringConnection: connection)
accounts.append(acct)
}
}
return accounts
}
/// Checks if the specified keyring account is connected.
///
/// - Parameter keyringAccount: The keyring account to check.
///
/// - Returns: true if the keyring account is being used by an existing publicize connection. False otherwise.
///
fileprivate func accountIsConnected(_ keyringAccount: KeyringAccount) -> Bool {
guard let existingConnections = existingPublicizeConnections else {
return false
}
let keyringConnection = keyringAccount.keyringConnection
for existingConnection in existingConnections {
if existingConnection.keyringConnectionID == keyringConnection.keyringID &&
existingConnection.keyringConnectionUserID == keyringConnection.userID &&
existingConnection.externalID == keyringAccount.externalIDForConnection {
return true
}
}
return false
}
// MARK: - Actions
/// Notifies the delegate that the user has clicked the close button to dismiss the controller.
///
/// - Parameter sender: The close button that was tapped.
///
func handleCloseTapped(_ sender: UIBarButtonItem) {
delegate?.didDismissSharingAccountViewController(self)
}
// MARK: - Structs
/// KeyringAccount is used to normalize the list of avaiable accounts while
/// preserving the owning keyring connection.
///
struct KeyringAccount {
var name: String // The account name
var externalID: String? // The actual externalID value that should be passed when creating/updating a publicize connection.
var externalIDForConnection: String // The effective external ID that should be used for comparing a keyring account with a PublicizeConnection.
var keyringConnection: KeyringConnection
}
/// An ImmuTableRow class.
///
struct KeyringRow: ImmuTableRow {
static let cell = ImmuTableCell.class(WPTableViewCellValue1.self)
let title: String
let value: String
let action: ImmuTableAction?
func configureCell(_ cell: UITableViewCell) {
cell.textLabel?.text = title
cell.detailTextLabel?.text = value
WPStyleGuide.configureTableViewCell(cell)
}
}
}
/// Delegate protocol.
///
@objc protocol SharingAccountSelectionDelegate: NSObjectProtocol {
func didDismissSharingAccountViewController(_ controller: SharingAccountViewController)
func sharingAccountViewController(_ controller: SharingAccountViewController, selectedKeyringConnection keyringConnection: KeyringConnection, externalID: String?)
}