From 6635565a1cbced1a2386364ecfe1031100185b4d Mon Sep 17 00:00:00 2001 From: Riley Testut Date: Thu, 5 Sep 2019 11:59:10 -0700 Subject: [PATCH] Revises Settings UI --- AltStore.xcodeproj/project.pbxproj | 24 +- AltStore/Base.lproj/Main.storyboard | 337 +------------ AltStore/Components/NavigationBar.swift | 21 +- .../Colors/Orange.colorset/Contents.json | 20 + .../Assets.xcassets/Next.imageset/Back@2x.png | Bin 0 -> 939 bytes .../Next.imageset/Contents.json | 24 + .../Settings/InsetGroupTableViewCell.swift | 132 ++++++ AltStore/Settings/Settings.storyboard | 448 ++++++++++++++++++ .../Settings/SettingsHeaderFooterView.swift | 36 ++ .../Settings/SettingsHeaderFooterView.xib | 64 +++ .../Settings/SettingsViewController.swift | 238 +++++++--- 11 files changed, 952 insertions(+), 392 deletions(-) create mode 100644 AltStore/Resources/Assets.xcassets/Colors/Orange.colorset/Contents.json create mode 100644 AltStore/Resources/Assets.xcassets/Next.imageset/Back@2x.png create mode 100644 AltStore/Resources/Assets.xcassets/Next.imageset/Contents.json create mode 100644 AltStore/Settings/InsetGroupTableViewCell.swift create mode 100644 AltStore/Settings/Settings.storyboard create mode 100644 AltStore/Settings/SettingsHeaderFooterView.swift create mode 100644 AltStore/Settings/SettingsHeaderFooterView.xib diff --git a/AltStore.xcodeproj/project.pbxproj b/AltStore.xcodeproj/project.pbxproj index c101c182..71f3bb4e 100644 --- a/AltStore.xcodeproj/project.pbxproj +++ b/AltStore.xcodeproj/project.pbxproj @@ -188,7 +188,6 @@ BFD6B03322DFF20800B86064 /* MyAppsComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFD6B03222DFF20800B86064 /* MyAppsComponents.swift */; }; BFDB5B1622EE90D300F74113 /* Date+RelativeDate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDB5B1522EE90D300F74113 /* Date+RelativeDate.swift */; }; BFDB5B2622EFBBEA00F74113 /* BrowseCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = BFDB5B2522EFBBEA00F74113 /* BrowseCollectionViewCell.xib */; }; - BFDB69FD22A9A7B7007EA6D6 /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDB69FC22A9A7B7007EA6D6 /* SettingsViewController.swift */; }; BFDB6A0522A9AFB2007EA6D6 /* Fetchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDB6A0422A9AFB2007EA6D6 /* Fetchable.swift */; }; BFDB6A0822AAED73007EA6D6 /* ResignAppOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDB6A0722AAED73007EA6D6 /* ResignAppOperation.swift */; }; BFDB6A0B22AAEDB7007EA6D6 /* Operation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDB6A0A22AAEDB7007EA6D6 /* Operation.swift */; }; @@ -197,6 +196,11 @@ BFE338DD22F0E7F3002E24B9 /* Source.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE338DC22F0E7F3002E24B9 /* Source.swift */; }; BFE338DF22F0EADB002E24B9 /* FetchSourceOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE338DE22F0EADB002E24B9 /* FetchSourceOperation.swift */; }; BFE338E822F10E56002E24B9 /* LaunchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE338E722F10E56002E24B9 /* LaunchViewController.swift */; }; + BFE60738231ADF49002B0E8E /* Settings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BFE60737231ADF49002B0E8E /* Settings.storyboard */; }; + BFE6073A231ADF82002B0E8E /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE60739231ADF82002B0E8E /* SettingsViewController.swift */; }; + BFE6073C231AE1E7002B0E8E /* SettingsHeaderFooterView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BFE6073B231AE1E7002B0E8E /* SettingsHeaderFooterView.xib */; }; + BFE60740231AFD2A002B0E8E /* InsetGroupTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE6073F231AFD2A002B0E8E /* InsetGroupTableViewCell.swift */; }; + BFE60742231B07E6002B0E8E /* SettingsHeaderFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE60741231B07E6002B0E8E /* SettingsHeaderFooterView.swift */; }; BFE6325A22A83BEB00F30809 /* Authentication.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BFE6325922A83BEB00F30809 /* Authentication.storyboard */; }; BFE6325C22A83C0100F30809 /* AuthenticationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE6325B22A83C0100F30809 /* AuthenticationViewController.swift */; }; BFE6325E22A8497000F30809 /* SelectTeamViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE6325D22A8497000F30809 /* SelectTeamViewController.swift */; }; @@ -460,7 +464,6 @@ BFD6B03222DFF20800B86064 /* MyAppsComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyAppsComponents.swift; sourceTree = ""; }; BFDB5B1522EE90D300F74113 /* Date+RelativeDate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+RelativeDate.swift"; sourceTree = ""; }; BFDB5B2522EFBBEA00F74113 /* BrowseCollectionViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = BrowseCollectionViewCell.xib; sourceTree = ""; }; - BFDB69FC22A9A7B7007EA6D6 /* SettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = ""; }; BFDB6A0422A9AFB2007EA6D6 /* Fetchable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Fetchable.swift; sourceTree = ""; }; BFDB6A0722AAED73007EA6D6 /* ResignAppOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResignAppOperation.swift; sourceTree = ""; }; BFDB6A0A22AAEDB7007EA6D6 /* Operation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Operation.swift; sourceTree = ""; }; @@ -469,6 +472,11 @@ BFE338DC22F0E7F3002E24B9 /* Source.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Source.swift; sourceTree = ""; }; BFE338DE22F0EADB002E24B9 /* FetchSourceOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchSourceOperation.swift; sourceTree = ""; }; BFE338E722F10E56002E24B9 /* LaunchViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchViewController.swift; sourceTree = ""; }; + BFE60737231ADF49002B0E8E /* Settings.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Settings.storyboard; sourceTree = ""; }; + BFE60739231ADF82002B0E8E /* SettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = ""; }; + BFE6073B231AE1E7002B0E8E /* SettingsHeaderFooterView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SettingsHeaderFooterView.xib; sourceTree = ""; }; + BFE6073F231AFD2A002B0E8E /* InsetGroupTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsetGroupTableViewCell.swift; sourceTree = ""; }; + BFE60741231B07E6002B0E8E /* SettingsHeaderFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsHeaderFooterView.swift; sourceTree = ""; }; BFE6325922A83BEB00F30809 /* Authentication.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Authentication.storyboard; sourceTree = ""; }; BFE6325B22A83C0100F30809 /* AuthenticationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationViewController.swift; sourceTree = ""; }; BFE6325D22A8497000F30809 /* SelectTeamViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectTeamViewController.swift; sourceTree = ""; }; @@ -957,7 +965,11 @@ BFDB69FB22A9A7A6007EA6D6 /* Settings */ = { isa = PBXGroup; children = ( - BFDB69FC22A9A7B7007EA6D6 /* SettingsViewController.swift */, + BFE60737231ADF49002B0E8E /* Settings.storyboard */, + BFE60739231ADF82002B0E8E /* SettingsViewController.swift */, + BFE6073F231AFD2A002B0E8E /* InsetGroupTableViewCell.swift */, + BFE60741231B07E6002B0E8E /* SettingsHeaderFooterView.swift */, + BFE6073B231AE1E7002B0E8E /* SettingsHeaderFooterView.xib */, BF02419522F2199300129732 /* RefreshAttemptsViewController.swift */, BFD5D6EB230CCDA1007955AB /* PatreonViewController.swift */, ); @@ -1207,12 +1219,14 @@ files = ( BFB1169D22932DB100BB457C /* Apps-Staging.json in Resources */, BFB4323F22DE852000B7F8BC /* UpdateCollectionViewCell.xib in Resources */, + BFE60738231ADF49002B0E8E /* Settings.storyboard in Resources */, BFD2477A2284B9A700981D42 /* LaunchScreen.storyboard in Resources */, BF770E6922BD57DD002A40FE /* Silence.m4a in Resources */, BFD247772284B9A700981D42 /* Assets.xcassets in Resources */, BFB6B22423187A3D0022A802 /* NewsCollectionViewCell.xib in Resources */, BFD247752284B9A500981D42 /* Main.storyboard in Resources */, BFDB5B2622EFBBEA00F74113 /* BrowseCollectionViewCell.xib in Resources */, + BFE6073C231AE1E7002B0E8E /* SettingsHeaderFooterView.xib in Resources */, BF29012F2318F6B100D88A45 /* AppBannerView.xib in Resources */, BFE6325A22A83BEB00F30809 /* Authentication.storyboard in Resources */, ); @@ -1383,15 +1397,16 @@ BFE6325E22A8497000F30809 /* SelectTeamViewController.swift in Sources */, BFD2478F2284C8F900981D42 /* Button.swift in Sources */, BFD5D6F6230DDB12007955AB /* Tier.swift in Sources */, - BFDB69FD22A9A7B7007EA6D6 /* SettingsViewController.swift in Sources */, BFE6326A22A85DAF00F30809 /* ReplaceCertificateViewController.swift in Sources */, BFB11692229322E400BB457C /* DatabaseManager.swift in Sources */, BFC1F38D22AEE3A4003AC21A /* DownloadAppOperation.swift in Sources */, BF54E8212315EF0D000AE0D8 /* ALTPatreonBenefitType.m in Sources */, BFBBE2E122931F81002097FA /* InstalledApp.swift in Sources */, + BFE6073A231ADF82002B0E8E /* SettingsViewController.swift in Sources */, BFE338DF22F0EADB002E24B9 /* FetchSourceOperation.swift in Sources */, BFBBE2DF22931F73002097FA /* App.swift in Sources */, BFB6B21E231870160022A802 /* NewsViewController.swift in Sources */, + BFE60740231AFD2A002B0E8E /* InsetGroupTableViewCell.swift in Sources */, BFD5D6F4230DDB0A007955AB /* Campaign.swift in Sources */, BFB6B21B23186D640022A802 /* NewsItem.swift in Sources */, BFD5D6E8230CC961007955AB /* PatreonAPI.swift in Sources */, @@ -1410,6 +1425,7 @@ BF3D64B022E8D4B800E9056B /* AppContentViewControllerCells.swift in Sources */, BFBBE2DD22931B20002097FA /* AltStore.xcdatamodeld in Sources */, BF02419422F2156E00129732 /* RefreshAttempt.swift in Sources */, + BFE60742231B07E6002B0E8E /* SettingsHeaderFooterView.swift in Sources */, BFE338E822F10E56002E24B9 /* LaunchViewController.swift in Sources */, BFE6325C22A83C0100F30809 /* AuthenticationViewController.swift in Sources */, BFB1169B2293274D00BB457C /* JSONDecoder+ManagedObjectContext.swift in Sources */, diff --git a/AltStore/Base.lproj/Main.storyboard b/AltStore/Base.lproj/Main.storyboard index 14bfc1ab..3612bef5 100644 --- a/AltStore/Base.lproj/Main.storyboard +++ b/AltStore/Base.lproj/Main.storyboard @@ -42,7 +42,7 @@ - + @@ -73,7 +73,7 @@ - + @@ -271,7 +271,7 @@ - + @@ -548,7 +548,7 @@ World - + @@ -595,319 +595,17 @@ World - + - + - - - - - - - - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -933,7 +631,7 @@ World - + @@ -953,7 +651,7 @@ World - + @@ -974,7 +672,7 @@ World - + @@ -1133,7 +831,7 @@ World - + @@ -1152,7 +850,7 @@ World - + @@ -1164,9 +862,6 @@ World - - - diff --git a/AltStore/Components/NavigationBar.swift b/AltStore/Components/NavigationBar.swift index f935d808..b12276e3 100644 --- a/AltStore/Components/NavigationBar.swift +++ b/AltStore/Components/NavigationBar.swift @@ -12,6 +12,8 @@ import Roxas class NavigationBar: UINavigationBar { + private let backgroundColorView = UIView() + override init(frame: CGRect) { super.init(frame: frame) @@ -28,14 +30,31 @@ class NavigationBar: UINavigationBar private func initialize() { - self.barTintColor = .white self.shadowImage = UIImage() + + if let tintColor = self.barTintColor + { + self.backgroundColorView.backgroundColor = tintColor + + // Top = -50 to cover status bar area above navigation bar on any device. + // Bottom = -1 to prevent a flickering gray line from appearing. + self.addSubview(self.backgroundColorView, pinningEdgesWith: UIEdgeInsets(top: -50, left: 0, bottom: -1, right: 0)) + } + else + { + self.barTintColor = .white + } } override func layoutSubviews() { super.layoutSubviews() + if self.backgroundColorView.superview != nil + { + self.insertSubview(self.backgroundColorView, at: 1) + } + // We can't easily shift just the back button up, so we shift the entire content view slightly. for contentView in self.subviews { diff --git a/AltStore/Resources/Assets.xcassets/Colors/Orange.colorset/Contents.json b/AltStore/Resources/Assets.xcassets/Colors/Orange.colorset/Contents.json new file mode 100644 index 00000000..f5e0bf0f --- /dev/null +++ b/AltStore/Resources/Assets.xcassets/Colors/Orange.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + }, + "colors" : [ + { + "idiom" : "universal", + "color" : { + "color-space" : "srgb", + "components" : { + "red" : "241", + "alpha" : "1.000", + "blue" : "62", + "green" : "172" + } + } + } + ] +} \ No newline at end of file diff --git a/AltStore/Resources/Assets.xcassets/Next.imageset/Back@2x.png b/AltStore/Resources/Assets.xcassets/Next.imageset/Back@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..77e348a70f44c17f30a36210dd7f8e494c7b18f0 GIT binary patch literal 939 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbBSkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6Xz}5igjtE6@fg!CBxDSzC zHb_`sNdc^+B->Ug!Z$#{Ilm}X!Bo#g&p^qJOF==wrYI%ND#*nRsvXF)RmvzSDX`Ml zFE20GD>v55FG|-pw6wI;H!#vSGSUUA&@HaaD@m--%_~-h7y>iLCAB!YD6^m>Ge1uO zWNucmA z*yy9HfNHkU2YDCC`;f2&ivk1Jjti(07EyLwELUEf21cuwr;B4q1n1iszFdb41X`E( zHa$3$%=t)`rF_?wwYCe~0|g3IJEET7~U z>T%47 z+TV2kxlNsl)^{7epYy&}&i}h7%I1FO)OU9lRc)X0dg+m_mktN#vn8!OwBd^IbGzD8 zX)Dh;x_;K2zI0N{CA+O+Z<}39rY|)K`OxvM$t!4|+$y=vF`s7IJv}x5tLgrC+Z`F% zE_K#qY5I3EZJlbuETNK8<3Cp-Lnol3(QRVRJ&FIFjZ0Lrn=jt?J2>~3u*Cb7M_7ez z49eJ!eVMt!NR{>S@1B3MS}MFZ9-XQG$x}4ztkJ<*HiKW`x29-v^=vzH?88hAgN{QQ r2e&7$I&Ri4r7@FNTcIl@ar>9J`C>=w-|%}K0c8nKS3j3^P6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AltStore/Settings/SettingsHeaderFooterView.swift b/AltStore/Settings/SettingsHeaderFooterView.swift new file mode 100644 index 00000000..aec7b2f7 --- /dev/null +++ b/AltStore/Settings/SettingsHeaderFooterView.swift @@ -0,0 +1,36 @@ +// +// SettingsHeaderFooterView.swift +// AltStore +// +// Created by Riley Testut on 8/31/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +import UIKit + +import Roxas + +class SettingsHeaderFooterView: UITableViewHeaderFooterView +{ + @IBOutlet var primaryLabel: UILabel! + @IBOutlet var secondaryLabel: UILabel! + @IBOutlet var button: UIButton! + + @IBOutlet private var stackView: UIStackView! + + override func awakeFromNib() + { + super.awakeFromNib() + + self.contentView.layoutMargins = .zero + self.contentView.preservesSuperviewLayoutMargins = true + + self.stackView.translatesAutoresizingMaskIntoConstraints = false + self.contentView.addSubview(self.stackView) + + NSLayoutConstraint.activate([self.stackView.leadingAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.leadingAnchor), + self.stackView.trailingAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.trailingAnchor), + self.stackView.topAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.topAnchor), + self.stackView.bottomAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.bottomAnchor)]) + } +} diff --git a/AltStore/Settings/SettingsHeaderFooterView.xib b/AltStore/Settings/SettingsHeaderFooterView.xib new file mode 100644 index 00000000..fa93d7bd --- /dev/null +++ b/AltStore/Settings/SettingsHeaderFooterView.xib @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AltStore/Settings/SettingsViewController.swift b/AltStore/Settings/SettingsViewController.swift index c7ed7159..27702476 100644 --- a/AltStore/Settings/SettingsViewController.swift +++ b/AltStore/Settings/SettingsViewController.swift @@ -1,37 +1,45 @@ // -// AccountViewController.swift +// SettingsViewController.swift // AltStore // -// Created by Riley Testut on 6/6/19. +// Created by Riley Testut on 8/31/19. // Copyright © 2019 Riley Testut. All rights reserved. // import UIKit -import Roxas +extension SettingsViewController +{ + fileprivate enum Section: Int, CaseIterable + { + case signIn + case account + case patreon + case backgroundRefresh + case debug + } +} class SettingsViewController: UITableViewController { - private var team: Team? + private var activeTeam: Team? - private lazy var placeholderView = self.makePlaceholderView() + private var prototypeHeaderFooterView: SettingsHeaderFooterView! - @IBOutlet var accountNameLabel: UILabel! - @IBOutlet var accountEmailLabel: UILabel! + @IBOutlet private var accountNameLabel: UILabel! + @IBOutlet private var accountEmailLabel: UILabel! + @IBOutlet private var accountTypeLabel: UILabel! - @IBOutlet var teamNameLabel: UILabel! - @IBOutlet var teamTypeLabel: UILabel! + @IBOutlet private var backgroundRefreshSwitch: UISwitch! override func viewDidLoad() { super.viewDidLoad() - self.update() - } - - override func viewWillAppear(_ animated: Bool) - { - super.viewWillAppear(animated) + let nib = UINib(nibName: "SettingsHeaderFooterView", bundle: nil) + self.prototypeHeaderFooterView = nib.instantiate(withOwner: nil, options: nil)[0] as? SettingsHeaderFooterView + + self.tableView.register(nib, forHeaderFooterViewReuseIdentifier: "HeaderFooterView") self.update() } @@ -39,73 +47,92 @@ class SettingsViewController: UITableViewController private extension SettingsViewController { - func makePlaceholderView() -> RSTPlaceholderView - { - let placeholderView = RSTPlaceholderView() - placeholderView.autoresizingMask = [.flexibleWidth, .flexibleHeight] - placeholderView.textLabel.text = NSLocalizedString("Not Signed In", comment: "") - placeholderView.detailTextLabel.text = NSLocalizedString("Please sign in with your Apple ID to download and refresh apps.", comment: "") - - let signInButton = UIButton(type: .system) - signInButton.titleLabel?.font = UIFont.preferredFont(forTextStyle: .body) - signInButton.setTitle(NSLocalizedString("Sign In", comment: ""), for: .normal) - signInButton.addTarget(self, action: #selector(SettingsViewController.signIn(_:)), for: .primaryActionTriggered) - placeholderView.stackView.addArrangedSubview(signInButton) - - return placeholderView - } - func update() { if let team = DatabaseManager.shared.activeTeam() { - self.tableView.separatorStyle = .singleLine - self.tableView.isScrollEnabled = true - self.tableView.backgroundView = nil - - self.navigationItem.rightBarButtonItem?.isEnabled = true - - self.accountNameLabel.text = team.account.localizedName + self.accountNameLabel.text = team.name self.accountEmailLabel.text = team.account.appleID + self.accountTypeLabel.text = team.type.localizedDescription - self.teamNameLabel.text = team.name - self.teamTypeLabel.text = team.type.localizedDescription - - self.team = team + self.activeTeam = team } else { - self.tableView.separatorStyle = .none - self.tableView.isScrollEnabled = false - self.tableView.backgroundView = self.placeholderView - - self.navigationItem.rightBarButtonItem?.isEnabled = false - - self.team = nil + self.activeTeam = nil } + self.backgroundRefreshSwitch.isOn = UserDefaults.standard.isBackgroundRefreshEnabled + if self.isViewLoaded { self.tableView.reloadData() } } + + func prepare(_ settingsHeaderFooterView: SettingsHeaderFooterView, for section: Section, isHeader: Bool) + { + settingsHeaderFooterView.primaryLabel.isHidden = !isHeader + settingsHeaderFooterView.secondaryLabel.isHidden = isHeader + settingsHeaderFooterView.button.isHidden = true + + settingsHeaderFooterView.layoutMargins.bottom = isHeader ? 0 : 8 + + switch section + { + case .signIn: + if isHeader + { + settingsHeaderFooterView.primaryLabel.text = NSLocalizedString("ACCOUNT", comment: "") + } + else + { + settingsHeaderFooterView.secondaryLabel.text = NSLocalizedString("Sign in with your Apple ID to download apps from AltStore.", comment: "") + } + + case .patreon: + settingsHeaderFooterView.secondaryLabel.text = NSLocalizedString("Donate and receive access to beta versions of AltStore, Delta, and more.", comment: "") + + case .account: + settingsHeaderFooterView.primaryLabel.text = NSLocalizedString("ACCOUNT", comment: "") + + settingsHeaderFooterView.button.setTitle(NSLocalizedString("SIGN OUT", comment: ""), for: .normal) + settingsHeaderFooterView.button.addTarget(self, action: #selector(SettingsViewController.signOut(_:)), for: .primaryActionTriggered) + settingsHeaderFooterView.button.isHidden = false + + case .backgroundRefresh: + settingsHeaderFooterView.secondaryLabel.text = NSLocalizedString("Automatically refresh apps in the background when connected to the same WiFi as AltServer.", comment: "") + + case .debug: + settingsHeaderFooterView.primaryLabel.text = NSLocalizedString("DEBUG", comment: "") + } + } + + func preferredHeight(for settingsHeaderFooterView: SettingsHeaderFooterView, in section: Section, isHeader: Bool) -> CGFloat + { + let widthConstraint = settingsHeaderFooterView.contentView.widthAnchor.constraint(equalToConstant: tableView.bounds.width) + NSLayoutConstraint.activate([widthConstraint]) + defer { NSLayoutConstraint.deactivate([widthConstraint]) } + + self.prepare(settingsHeaderFooterView, for: section, isHeader: isHeader) + + let size = settingsHeaderFooterView.contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) + return size.height + } } private extension SettingsViewController { - @objc func signIn(_ sender: UIButton) + func signIn() { - sender.isIndicatingActivity = true - AppManager.shared.authenticate(presentingViewController: self) { (result) in DispatchQueue.main.async { - sender.isIndicatingActivity = false self.update() } } } - @IBAction func signOut(_ sender: UIBarButtonItem) + @objc func signOut(_ sender: UIBarButtonItem) { func signOut() { @@ -113,14 +140,7 @@ private extension SettingsViewController DispatchQueue.main.async { if let error = error { - let toastView = RSTToastView(text: error.localizedDescription, detailText: nil) - toastView.tintColor = .red - toastView.show(in: self.navigationController?.view ?? self.view, duration: 2.0) - } - else - { - let toastView = RSTToastView(text: NSLocalizedString("Successfully Signed Out!", comment: ""), detailText: nil) - toastView.tintColor = .altPurple + let toastView = ToastView(text: error.localizedDescription, detailText: nil) toastView.show(in: self.navigationController?.view ?? self.view, duration: 2.0) } @@ -134,15 +154,101 @@ private extension SettingsViewController alertController.addAction(.cancel) self.present(alertController, animated: true, completion: nil) } + + @IBAction func toggleIsBackgroundRefreshEnabled(_ sender: UISwitch) + { + UserDefaults.standard.isBackgroundRefreshEnabled = sender.isOn + } } extension SettingsViewController { - override func numberOfSections(in tableView: UITableView) -> Int + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - let count = (self.team == nil) ? 0 : super.numberOfSections(in: tableView) - return count + let section = Section.allCases[section] + switch section + { + case .signIn: return (self.activeTeam == nil) ? 1 : 0 + case .account: return (self.activeTeam == nil) ? 0 : 3 + default: return super.tableView(tableView, numberOfRowsInSection: section.rawValue) + } + } + + override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? + { + let section = Section.allCases[section] + switch section + { + case .signIn where self.activeTeam != nil: return nil + case .account where self.activeTeam == nil: return nil + + case .signIn, .account, .debug: + let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "HeaderFooterView") as! SettingsHeaderFooterView + self.prepare(headerView, for: section, isHeader: true) + return headerView + + default: return nil + } + } + + override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? + { + let section = Section.allCases[section] + switch section + { + case .signIn where self.activeTeam != nil: return nil + + case .signIn, .patreon, .backgroundRefresh: + let footerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "HeaderFooterView") as! SettingsHeaderFooterView + self.prepare(footerView, for: section, isHeader: false) + return footerView + + default: return nil + } + } + + override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat + { + let section = Section.allCases[section] + switch section + { + case .signIn where self.activeTeam != nil: return 1.0 + case .account where self.activeTeam == nil: return 1.0 + + case .signIn, .account, .debug: + let height = self.preferredHeight(for: self.prototypeHeaderFooterView, in: section, isHeader: true) + return height + + default: return 0.0 + } + } + + override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat + { + let section = Section.allCases[section] + switch section + { + case .signIn where self.activeTeam != nil: return 1.0 + case .account where self.activeTeam == nil: return 1.0 + + case .signIn, .patreon, .backgroundRefresh: + let height = self.preferredHeight(for: self.prototypeHeaderFooterView, in: section, isHeader: false) + return height + + default: return 0.0 + } } } - +extension SettingsViewController +{ + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) + { + let section = Section.allCases[indexPath.section] + switch section + { + case .signIn: self.signIn() + default: break + } + } +}