Basic setup of ConnectionsTableViewController.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
Jeroen Leenarts
2018-05-24 20:14:01 +02:00
parent d15972d2ce
commit e6c6fd0b34
6 changed files with 222 additions and 23 deletions
+22 -5
View File
@@ -9,21 +9,30 @@
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Connections Table View Controller-->
<!--Profiles-->
<scene sceneID="Tud-vM-cYZ">
<objects>
<tableViewController storyboardIdentifier="ConnectionsTableViewController" id="kTU-BV-32R" customClass="ConnectionsTableViewController" customModule="Wireguard" customModuleProvider="target" sceneMemberID="viewController">
<tableViewController storyboardIdentifier="ConnectionsTableViewController" id="kTU-BV-32R" customClass="ConnectionsTableViewController" customModule="WireGuard" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="AJg-r0-KJH">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" id="fM3-cC-KPN">
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" accessoryType="detailDisclosureButton" indentationWidth="10" reuseIdentifier="ProfileTableViewCell" textLabel="hzX-lc-GyT" style="IBUITableViewCellStyleDefault" id="fM3-cC-KPN" customClass="ProfileTableViewCell" customModule="WireGuard" customModuleProvider="target">
<rect key="frame" x="0.0" y="28" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="fM3-cC-KPN" id="Rv6-XK-aK2">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="fM3-cC-KPN" id="Rv6-XK-aK2" customClass="ProfileTableViewCell" customModule="WireGuard" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="307" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="hzX-lc-GyT">
<rect key="frame" x="16" y="0.0" width="291" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
</prototypes>
@@ -32,6 +41,14 @@
<outlet property="delegate" destination="kTU-BV-32R" id="b6T-ZR-cmO"/>
</connections>
</tableView>
<navigationItem key="navigationItem" title="Profiles" id="j0L-5U-jDs">
<barButtonItem key="rightBarButtonItem" systemItem="add" id="h2H-H8-3Tn">
<connections>
<action selector="addProvider:" destination="kTU-BV-32R" id="xSg-ap-3Fx"/>
</connections>
</barButtonItem>
</navigationItem>
<simulatedNavigationBarMetrics key="simulatedTopBarMetrics" prompted="NO"/>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="4uZ-Vv-Fry" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
+7 -3
View File
@@ -86,17 +86,21 @@ class AppCoordinator: RootViewCoordinator {
extension AppCoordinator: ConnectionsTableViewControllerDelegate {
func addProvider(connectionsTableViewController: ConnectionsTableViewController) {
// TODO implement
print("Add provider")
}
func settings(connectionsTableViewController: ConnectionsTableViewController) {
func connect(profile: Profile, connectionsTableViewController: ConnectionsTableViewController) {
// TODO implement
print("connect profile \(profile)")
}
func connect(profile: Profile) {
func configure(profile: Profile, connectionsTableViewController: ConnectionsTableViewController) {
// TODO implement
print("configure profile \(profile)")
}
func delete(profile: Profile) {
func delete(profile: Profile, connectionsTableViewController: ConnectionsTableViewController) {
// TODO implement
print("delete profile \(profile)")
}
}
@@ -13,9 +13,9 @@ import BNRCoreDataStack
protocol ConnectionsTableViewControllerDelegate: class {
func addProvider(connectionsTableViewController: ConnectionsTableViewController)
func settings(connectionsTableViewController: ConnectionsTableViewController)
func connect(profile: Profile)
func delete(profile: Profile)
func connect(profile: Profile, connectionsTableViewController: ConnectionsTableViewController)
func configure(profile: Profile, connectionsTableViewController: ConnectionsTableViewController)
func delete(profile: Profile, connectionsTableViewController: ConnectionsTableViewController)
}
class ConnectionsTableViewController: UITableViewController {
@@ -23,16 +23,154 @@ class ConnectionsTableViewController: UITableViewController {
var viewContext: NSManagedObjectContext!
private lazy var fetchedResultsController: FetchedResultsController<Profile> = {
let fetchRequest = NSFetchRequest<Profile>()
fetchRequest.entity = Profile.entity()
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "title", ascending: true)]
let frc = FetchedResultsController<Profile>(fetchRequest: fetchRequest,
managedObjectContext: viewContext)
frc.setDelegate(self.frcDelegate)
return frc
}()
private lazy var frcDelegate: ProfileFetchedResultsControllerDelegate = { // swiftlint:disable:this weak_delegate
return ProfileFetchedResultsControllerDelegate(tableView: self.tableView)
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
do {
try fetchedResultsController.performFetch()
} catch {
print("Failed to fetch objects: \(error)")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
@IBAction func addProvider(_ sender: Any) {
delegate?.addProvider(connectionsTableViewController: self)
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fetchedResultsController.sections?[0].objects.count ?? 0
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(type: ProfileTableViewCell.self, for: indexPath)
guard let sections = fetchedResultsController.sections else {
fatalError("FetchedResultsController \(fetchedResultsController) should have sections, but found nil")
}
let section = sections[indexPath.section]
let profile = section.objects[indexPath.row]
cell.textLabel?.text = profile.title
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let sections = fetchedResultsController.sections else {
fatalError("FetchedResultsController \(fetchedResultsController) should have sections, but found nil")
}
let section = sections[indexPath.section]
let profile = section.objects[indexPath.row]
delegate?.connect(profile: profile, connectionsTableViewController: self)
tableView.deselectRow(at: indexPath, animated: true)
}
override func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
guard let sections = fetchedResultsController.sections else {
fatalError("FetchedResultsController \(fetchedResultsController) should have sections, but found nil")
}
let section = sections[indexPath.section]
let profile = section.objects[indexPath.row]
delegate?.configure(profile: profile, connectionsTableViewController: self)
}
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
guard let sections = fetchedResultsController.sections else {
fatalError("FetchedResultsController \(fetchedResultsController) should have sections, but found nil")
}
let section = sections[indexPath.section]
let profile = section.objects[indexPath.row]
delegate?.delete(profile: profile, connectionsTableViewController: self)
}
}
}
extension ConnectionsTableViewController: Identifyable {}
class ProfileFetchedResultsControllerDelegate: NSObject, FetchedResultsControllerDelegate {
private weak var tableView: UITableView?
// MARK: - Lifecycle
init(tableView: UITableView) {
self.tableView = tableView
}
func fetchedResultsControllerDidPerformFetch(_ controller: FetchedResultsController<Profile>) {
tableView?.reloadData()
}
func fetchedResultsControllerWillChangeContent(_ controller: FetchedResultsController<Profile>) {
tableView?.beginUpdates()
}
func fetchedResultsControllerDidChangeContent(_ controller: FetchedResultsController<Profile>) {
tableView?.endUpdates()
}
func fetchedResultsController(_ controller: FetchedResultsController<Profile>, didChangeObject change: FetchedResultsObjectChange<Profile>) {
guard let tableView = tableView else { return }
switch change {
case let .insert(_, indexPath):
tableView.insertRows(at: [indexPath], with: .automatic)
case let .delete(_, indexPath):
tableView.deleteRows(at: [indexPath], with: .automatic)
case let .move(_, fromIndexPath, toIndexPath):
tableView.moveRow(at: fromIndexPath, to: toIndexPath)
case let .update(_, indexPath):
tableView.reloadRows(at: [indexPath], with: .automatic)
}
}
func fetchedResultsController(_ controller: FetchedResultsController<Profile>, didChangeSection change: FetchedResultsSectionChange<Profile>) {
guard let tableView = tableView else { return }
switch change {
case let .insert(_, index):
tableView.insertSections(IndexSet(integer: index), with: .automatic)
case let .delete(_, index):
tableView.deleteSections(IndexSet(integer: index), with: .automatic)
}
}
}
class ProfileTableViewCell: UITableViewCell {
}
extension ProfileTableViewCell: Identifyable {}