Commit 6529a790 authored by domenicw's avatar domenicw
Browse files

Added Settings

Finished Login
parent 6bbbeea9
...@@ -30,6 +30,16 @@ ...@@ -30,6 +30,16 @@
B050E17A215180D20090CB79 /* AmivApplicationCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B050E179215180D20090CB79 /* AmivApplicationCell.swift */; }; B050E17A215180D20090CB79 /* AmivApplicationCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B050E179215180D20090CB79 /* AmivApplicationCell.swift */; };
B050E17D2151910F0090CB79 /* LoginViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B050E17C2151910F0090CB79 /* LoginViewController.swift */; }; B050E17D2151910F0090CB79 /* LoginViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B050E17C2151910F0090CB79 /* LoginViewController.swift */; };
B050E17F215195B50090CB79 /* UIFont+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B050E17E215195B50090CB79 /* UIFont+Extension.swift */; }; B050E17F215195B50090CB79 /* UIFont+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B050E17E215195B50090CB79 /* UIFont+Extension.swift */; };
B050E18121519B390090CB79 /* LoginViewControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B050E18021519B390090CB79 /* LoginViewControllerDelegate.swift */; };
B050E1852151A3700090CB79 /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B050E1842151A3700090CB79 /* SettingsViewController.swift */; };
B050E1872151A3C40090CB79 /* SettingsViewControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B050E1862151A3C40090CB79 /* SettingsViewControllerDelegate.swift */; };
B050E18A2151A4A80090CB79 /* SettingsAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B050E1892151A4A80090CB79 /* SettingsAction.swift */; };
B050E18C2151A54D0090CB79 /* SettingsCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B050E18B2151A54D0090CB79 /* SettingsCellModel.swift */; };
B050E18E2151A5660090CB79 /* SettingsCellType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B050E18D2151A5660090CB79 /* SettingsCellType.swift */; };
B050E1902151A6000090CB79 /* SettingsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B050E18F2151A6000090CB79 /* SettingsModel.swift */; };
B050E1922151A61F0090CB79 /* SettingsSectionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = B050E1912151A61F0090CB79 /* SettingsSectionModel.swift */; };
B050E1942151A9750090CB79 /* Bundle+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = B050E1932151A9750090CB79 /* Bundle+Extension.swift */; };
B050E1972151AAC40090CB79 /* SettingsNavigator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B050E1962151AAC40090CB79 /* SettingsNavigator.swift */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
...@@ -71,6 +81,16 @@ ...@@ -71,6 +81,16 @@
B050E179215180D20090CB79 /* AmivApplicationCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AmivApplicationCell.swift; sourceTree = "<group>"; }; B050E179215180D20090CB79 /* AmivApplicationCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AmivApplicationCell.swift; sourceTree = "<group>"; };
B050E17C2151910F0090CB79 /* LoginViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewController.swift; sourceTree = "<group>"; }; B050E17C2151910F0090CB79 /* LoginViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewController.swift; sourceTree = "<group>"; };
B050E17E215195B50090CB79 /* UIFont+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIFont+Extension.swift"; sourceTree = "<group>"; }; B050E17E215195B50090CB79 /* UIFont+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIFont+Extension.swift"; sourceTree = "<group>"; };
B050E18021519B390090CB79 /* LoginViewControllerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewControllerDelegate.swift; sourceTree = "<group>"; };
B050E1842151A3700090CB79 /* SettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = "<group>"; };
B050E1862151A3C40090CB79 /* SettingsViewControllerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewControllerDelegate.swift; sourceTree = "<group>"; };
B050E1892151A4A80090CB79 /* SettingsAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsAction.swift; sourceTree = "<group>"; };
B050E18B2151A54D0090CB79 /* SettingsCellModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsCellModel.swift; sourceTree = "<group>"; };
B050E18D2151A5660090CB79 /* SettingsCellType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsCellType.swift; sourceTree = "<group>"; };
B050E18F2151A6000090CB79 /* SettingsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsModel.swift; sourceTree = "<group>"; };
B050E1912151A61F0090CB79 /* SettingsSectionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsSectionModel.swift; sourceTree = "<group>"; };
B050E1932151A9750090CB79 /* Bundle+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle+Extension.swift"; sourceTree = "<group>"; };
B050E1962151AAC40090CB79 /* SettingsNavigator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsNavigator.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
...@@ -117,8 +137,8 @@ ...@@ -117,8 +137,8 @@
B050E15721516E160090CB79 /* Model */, B050E15721516E160090CB79 /* Model */,
B050E141215169740090CB79 /* View Controller */, B050E141215169740090CB79 /* View Controller */,
B050E140215169690090CB79 /* Navigation */, B050E140215169690090CB79 /* Navigation */,
B050E13F2151695A0090CB79 /* Base */,
B050E1632151762C0090CB79 /* Amiv Apps */, B050E1632151762C0090CB79 /* Amiv Apps */,
B050E13F2151695A0090CB79 /* Base */,
B050E12B215169250090CB79 /* Info.plist */, B050E12B215169250090CB79 /* Info.plist */,
); );
path = Amiv; path = Amiv;
...@@ -184,6 +204,7 @@ ...@@ -184,6 +204,7 @@
B050E14921516A2E0090CB79 /* App */ = { B050E14921516A2E0090CB79 /* App */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
B050E1952151AAB70090CB79 /* Settings */,
B050E16C215177E30090CB79 /* Amiv Applications */, B050E16C215177E30090CB79 /* Amiv Applications */,
B050E1692151776A0090CB79 /* Jobs */, B050E1692151776A0090CB79 /* Jobs */,
B050E15A215171E40090CB79 /* Home */, B050E15A215171E40090CB79 /* Home */,
...@@ -203,6 +224,8 @@ ...@@ -203,6 +224,8 @@
B050E15221516C860090CB79 /* App */ = { B050E15221516C860090CB79 /* App */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
B050E1832151A3600090CB79 /* Jobs */,
B050E1822151A3590090CB79 /* Settings */,
B050E16F2151798B0090CB79 /* Amiv Application */, B050E16F2151798B0090CB79 /* Amiv Application */,
B050E15421516D3D0090CB79 /* Home */, B050E15421516D3D0090CB79 /* Home */,
); );
...@@ -227,6 +250,7 @@ ...@@ -227,6 +250,7 @@
B050E15721516E160090CB79 /* Model */ = { B050E15721516E160090CB79 /* Model */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
B050E1882151A4850090CB79 /* Settings Model */,
B050E15821516E230090CB79 /* EventModel.swift */, B050E15821516E230090CB79 /* EventModel.swift */,
); );
path = Model; path = Model;
...@@ -245,6 +269,7 @@ ...@@ -245,6 +269,7 @@
children = ( children = (
B050E15E2151735A0090CB79 /* UIColor+Extension.swift */, B050E15E2151735A0090CB79 /* UIColor+Extension.swift */,
B050E17E215195B50090CB79 /* UIFont+Extension.swift */, B050E17E215195B50090CB79 /* UIFont+Extension.swift */,
B050E1932151A9750090CB79 /* Bundle+Extension.swift */,
); );
path = Extension; path = Extension;
sourceTree = "<group>"; sourceTree = "<group>";
...@@ -321,10 +346,47 @@ ...@@ -321,10 +346,47 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
B050E17C2151910F0090CB79 /* LoginViewController.swift */, B050E17C2151910F0090CB79 /* LoginViewController.swift */,
B050E18021519B390090CB79 /* LoginViewControllerDelegate.swift */,
); );
path = Login; path = Login;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
B050E1822151A3590090CB79 /* Settings */ = {
isa = PBXGroup;
children = (
B050E1842151A3700090CB79 /* SettingsViewController.swift */,
B050E1862151A3C40090CB79 /* SettingsViewControllerDelegate.swift */,
);
path = Settings;
sourceTree = "<group>";
};
B050E1832151A3600090CB79 /* Jobs */ = {
isa = PBXGroup;
children = (
);
path = Jobs;
sourceTree = "<group>";
};
B050E1882151A4850090CB79 /* Settings Model */ = {
isa = PBXGroup;
children = (
B050E18F2151A6000090CB79 /* SettingsModel.swift */,
B050E1892151A4A80090CB79 /* SettingsAction.swift */,
B050E18B2151A54D0090CB79 /* SettingsCellModel.swift */,
B050E18D2151A5660090CB79 /* SettingsCellType.swift */,
B050E1912151A61F0090CB79 /* SettingsSectionModel.swift */,
);
path = "Settings Model";
sourceTree = "<group>";
};
B050E1952151AAB70090CB79 /* Settings */ = {
isa = PBXGroup;
children = (
B050E1962151AAC40090CB79 /* SettingsNavigator.swift */,
);
path = Settings;
sourceTree = "<group>";
};
/* End PBXGroup section */ /* End PBXGroup section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
...@@ -427,17 +489,27 @@ ...@@ -427,17 +489,27 @@
files = ( files = (
B050E17821517EF50090CB79 /* AmivApplicationModel.swift in Sources */, B050E17821517EF50090CB79 /* AmivApplicationModel.swift in Sources */,
B050E16E215178BA0090CB79 /* AmivApplictionsNavigator.swift in Sources */, B050E16E215178BA0090CB79 /* AmivApplictionsNavigator.swift in Sources */,
B050E18C2151A54D0090CB79 /* SettingsCellModel.swift in Sources */,
B050E17521517E1B0090CB79 /* AmivApplicationViewControllerDelegate.swift in Sources */, B050E17521517E1B0090CB79 /* AmivApplicationViewControllerDelegate.swift in Sources */,
B050E120215169230090CB79 /* AppDelegate.swift in Sources */, B050E120215169230090CB79 /* AppDelegate.swift in Sources */,
B050E17D2151910F0090CB79 /* LoginViewController.swift in Sources */, B050E17D2151910F0090CB79 /* LoginViewController.swift in Sources */,
B050E171215179A30090CB79 /* AmivApplicationViewController.swift in Sources */, B050E171215179A30090CB79 /* AmivApplicationViewController.swift in Sources */,
B050E18A2151A4A80090CB79 /* SettingsAction.swift in Sources */,
B050E146215169D00090CB79 /* RootNavigator.swift in Sources */, B050E146215169D00090CB79 /* RootNavigator.swift in Sources */,
B050E1872151A3C40090CB79 /* SettingsViewControllerDelegate.swift in Sources */,
B050E15021516BA60090CB79 /* OnboardingNavigator.swift in Sources */, B050E15021516BA60090CB79 /* OnboardingNavigator.swift in Sources */,
B050E16B215177820090CB79 /* JobsNavigator.swift in Sources */, B050E16B215177820090CB79 /* JobsNavigator.swift in Sources */,
B050E14C21516A590090CB79 /* AmivRootNavigator.swift in Sources */, B050E14C21516A590090CB79 /* AmivRootNavigator.swift in Sources */,
B050E15C215171F70090CB79 /* HomeNavigator.swift in Sources */, B050E15C215171F70090CB79 /* HomeNavigator.swift in Sources */,
B050E1972151AAC40090CB79 /* SettingsNavigator.swift in Sources */,
B050E1942151A9750090CB79 /* Bundle+Extension.swift in Sources */,
B050E14E21516AFE0090CB79 /* AppNavigator.swift in Sources */, B050E14E21516AFE0090CB79 /* AppNavigator.swift in Sources */,
B050E18121519B390090CB79 /* LoginViewControllerDelegate.swift in Sources */,
B050E18E2151A5660090CB79 /* SettingsCellType.swift in Sources */,
B050E1852151A3700090CB79 /* SettingsViewController.swift in Sources */,
B050E1902151A6000090CB79 /* SettingsModel.swift in Sources */,
B050E15621516D4D0090CB79 /* HomeViewController.swift in Sources */, B050E15621516D4D0090CB79 /* HomeViewController.swift in Sources */,
B050E1922151A61F0090CB79 /* SettingsSectionModel.swift in Sources */,
B050E15921516E230090CB79 /* EventModel.swift in Sources */, B050E15921516E230090CB79 /* EventModel.swift in Sources */,
B050E168215176D50090CB79 /* AmivApplicationActionDelegate.swift in Sources */, B050E168215176D50090CB79 /* AmivApplicationActionDelegate.swift in Sources */,
B050E144215169950090CB79 /* Navigator.swift in Sources */, B050E144215169950090CB79 /* Navigator.swift in Sources */,
......
//
// Bundle+Extension.swift
// Amiv
//
// Created by Domenic Wüthrich on 18.09.18.
// Copyright © 2018 Amiv an der ETH. All rights reserved.
//
import Foundation
extension Bundle {
/// Version number of app
var releaseVersionNumber: String? {
return infoDictionary?["CFBundleShortVersionString"] as? String
}
/// Build number of app
var buildVersionNumber: String? {
return infoDictionary?["CFBundleVersion"] as? String
}
}
//
// SettingsAction.swift
// Amiv
//
// Created by Domenic Wüthrich on 18.09.18.
// Copyright © 2018 Amiv an der ETH. All rights reserved.
//
import Foundation
import UIKit
public enum SettingsAction {
case none
case changeValue(String)
case toggleLogin
public func indicator() -> UITableViewCell.AccessoryType {
switch self {
case .none, .toggleLogin:
return .none
case .changeValue:
return .disclosureIndicator
}
}
public func selectionStyle() -> UITableViewCell.SelectionStyle {
switch self {
case .none:
return .none
case .toggleLogin, .changeValue:
return .default
}
}
}
//
// SettingsCellModel.swift
// Amiv
//
// Created by Domenic Wüthrich on 18.09.18.
// Copyright © 2018 Amiv an der ETH. All rights reserved.
//
import Foundation
public class SettingsCellModel {
// MARK: - Variables
public var text: String
public var detailText: String?
public var action: SettingsAction
public var cellType: SettingsCellType
// MARK: - Initializers
public init(text: String, detailText: String? = nil, action: SettingsAction, cellType: SettingsCellType = .normal) {
self.text = text
self.detailText = detailText
self.action = action
self.cellType = cellType
}
}
//
// SettingsCellType.swift
// Amiv
//
// Created by Domenic Wüthrich on 18.09.18.
// Copyright © 2018 Amiv an der ETH. All rights reserved.
//
import Foundation
import UIKit
public enum SettingsCellType {
case normal
case login
case changeValue
public func reuseIdentifier() -> String {
switch self {
case .normal:
return "cell"
case .login:
return "login"
case .changeValue:
return "changeValue"
}
}
public func style() -> UITableViewCell.CellStyle {
switch self {
case .normal:
return .default
case .changeValue:
return .subtitle
case .login:
return .subtitle
}
}
}
//
// SettingsModel.swift
// Amiv
//
// Created by Domenic Wüthrich on 18.09.18.
// Copyright © 2018 Amiv an der ETH. All rights reserved.
//
import Foundation
import UIKit
public class SettingsModel {
// MARK: - Variables
public private(set) var sectionModels: [SettingsSectionModel]
// MARK: - Initializers
public init(sectionModels: [SettingsSectionModel]) {
self.sectionModels = sectionModels
}
}
extension SettingsModel {
public static func create() -> SettingsModel {
let sections: [SettingsSectionModel] = [SettingsModel.createLoginSection(), SettingsModel.createValueSection(), SettingsModel.createDisclosureSection()]
return SettingsModel(sectionModels: sections)
}
private static func createLoginSection() -> SettingsSectionModel {
let first = SettingsCellModel(text: "Name: Hans", detailText: "Email: hans@ethz.ch", action: .none, cellType: .login)
let second = SettingsCellModel(text: "Status: Logged In", detailText: "Tap to log out", action: .toggleLogin, cellType: .login)
return SettingsSectionModel(headerText: "Login", footerText: nil, cellModels: [first, second])
}
private static func createValueSection() -> SettingsSectionModel{
let food = SettingsCellModel(text: "Food Preference", detailText: "All", action: .changeValue("food"), cellType: .changeValue)
let publicTransport = SettingsCellModel(text: "Public Transport", detailText: "GA", action: .changeValue("pubTrans"), cellType: .changeValue)
let pushNotification = SettingsCellModel(text: "Enabled", detailText: "Tap to disable Push Notifications", action: .changeValue("pushNotification"), cellType: .changeValue)
return SettingsSectionModel(headerText: "Settings", footerText: nil, cellModels: [food, publicTransport, pushNotification])
}
private static func createDisclosureSection() -> SettingsSectionModel {
var disclosureFooterText: String
if let release = Bundle.main.releaseVersionNumber, let build = Bundle.main.buildVersionNumber {
disclosureFooterText = "Amiv an der ETH © 2018\nVersion \(release) (\(build))"
} else {
disclosureFooterText = "Amiv an der ETH © 2018"
}
let disclosureSection: SettingsSectionModel = SettingsSectionModel(headerText: nil, footerText: disclosureFooterText, cellModels: [], footerTextAlignment: .center)
return disclosureSection
}
}
//
// SettingsSectionModel.swift
// Amiv
//
// Created by Domenic Wüthrich on 18.09.18.
// Copyright © 2018 Amiv an der ETH. All rights reserved.
//
import Foundation
import UIKit
public class SettingsSectionModel {
// MARK: - Variables
public var headerText: String?
public var footerText: String?
public var footerTextAlignment: NSTextAlignment
public var cellModels: [SettingsCellModel]
// MARK: - Initializers
public init(headerText: String?, footerText: String?, cellModels: [SettingsCellModel], footerTextAlignment: NSTextAlignment = .left) {
self.headerText = headerText
self.footerText = footerText
self.footerTextAlignment = footerTextAlignment
self.cellModels = cellModels
}
public convenience init(headerText: String?, footerText: String?) {
self.init(headerText: headerText, footerText: footerText, cellModels: [])
}
}
...@@ -42,6 +42,7 @@ public class AppNavigator: Navigator { ...@@ -42,6 +42,7 @@ public class AppNavigator: Navigator {
// Create all tabs // Create all tabs
self.createHomeTab() self.createHomeTab()
self.createAmivApplicationTab() self.createAmivApplicationTab()
self.createSettingsTab()
// Make tabBarController ready // Make tabBarController ready
self.tabBarController.viewControllers = self.childNavigators.map({ $0.rootViewController }) self.tabBarController.viewControllers = self.childNavigators.map({ $0.rootViewController })
...@@ -59,4 +60,9 @@ public class AppNavigator: Navigator { ...@@ -59,4 +60,9 @@ public class AppNavigator: Navigator {
self.childNavigators.append(app) self.childNavigators.append(app)
} }
private func createSettingsTab() {
let settings = SettingsNavigator()
self.childNavigators.append(settings)
}
} }
//
// SettingsNavigator.swift
// Amiv
//
// Created by Domenic Wüthrich on 18.09.18.
// Copyright © 2018 Amiv an der ETH. All rights reserved.
//
import Foundation
import UIKit
public class SettingsNavigator: Navigator {
// MARK: - Variables
public var rootViewController: UIViewController {
return self.navigationController
}
private let navigationController: UINavigationController
// MARK: - Initializers
public init() {
let model = SettingsModel.create()
let settings = SettingsViewController(model: model)
self.navigationController = UINavigationController(rootViewController: settings)
settings.delegate = self
}
}
extension SettingsNavigator: SettingsViewControllerDelegate {
public func toggleLogin() {
debugPrint("toggle login")
}
public func pushNotification() {
debugPrint("push notification")
}
public func changeValue(for key: String) {
debugPrint("change value for key \(key)")
}
}
//
// SettingsViewController.swift
// Amiv
//
// Created by Domenic Wüthrich on 18.09.18.
// Copyright © 2018 Amiv an der ETH. All rights reserved.
//
import Foundation
import UIKit
public class SettingsViewController: UITableViewController {
// MARK: - View Variables
// MARK: - Variables
private var model: SettingsModel
public var delegate: SettingsViewControllerDelegate?
fileprivate var cellIdentifier = "cell"
// MARK: - Initializers
public init(model: SettingsModel) {
self.model = model
super.init(style: .grouped)
self.title = "Settings"
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - View Creation
// MARK: - View Setup
public override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.navigationBar.prefersLargeTitles = true
self.navigationItem.largeTitleDisplayMode = .always
}
}
// MARK: - SettingsViewController TableView Extension
extension SettingsViewController {
public override func numberOfSections(in tableView: UITableView) -> Int {
return self.model.sectionModels.count
}
public override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.model.sectionModels[section].cellModels.count
}
public override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.model.sectionModels[section].headerText
}
public override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
return self.model.sectionModels[section].footerText
}
public override func tableView(_ tableView: UITableView, willDisplayFooterView view: UIView, forSection section: Int) {
if let footer = view as? UITableViewHeaderFooterView {
footer.textLabel?.textAlignment = self.model.sectionModels[section].footerTextAlignment
}
}
public override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellModel = self.model.sectionModels[indexPath.section].cellModels[indexPath.row]
let cell: UITableViewCell = {
guard