Revises Patreon UI

This commit is contained in:
Riley Testut
2019-09-05 15:37:58 -07:00
parent 6635565a1c
commit e6bfdfdaee
6 changed files with 387 additions and 80 deletions

View File

@@ -180,7 +180,6 @@
BFD52C2222A1A9EC000B7ED1 /* cnary.c in Sources */ = {isa = PBXBuildFile; fileRef = BFD52C1F22A1A9EC000B7ED1 /* cnary.c */; };
BFD5D6E8230CC961007955AB /* PatreonAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFD5D6E7230CC961007955AB /* PatreonAPI.swift */; };
BFD5D6EA230CCAE5007955AB /* PatreonAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFD5D6E9230CCAE5007955AB /* PatreonAccount.swift */; };
BFD5D6EC230CCDA1007955AB /* PatreonViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFD5D6EB230CCDA1007955AB /* PatreonViewController.swift */; };
BFD5D6EE230D8A86007955AB /* Patron.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFD5D6ED230D8A86007955AB /* Patron.swift */; };
BFD5D6F2230DD974007955AB /* Benefit.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFD5D6F1230DD974007955AB /* Benefit.swift */; };
BFD5D6F4230DDB0A007955AB /* Campaign.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFD5D6F3230DDB0A007955AB /* Campaign.swift */; };
@@ -208,6 +207,9 @@
BFE6326822A858F300F30809 /* Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE6326722A858F300F30809 /* Account.swift */; };
BFE6326A22A85DAF00F30809 /* ReplaceCertificateViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE6326922A85DAF00F30809 /* ReplaceCertificateViewController.swift */; };
BFE6326C22A86FF300F30809 /* AuthenticationOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE6326B22A86FF300F30809 /* AuthenticationOperation.swift */; };
BFF0B68E23219520007A79E1 /* PatreonViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF0B68D23219520007A79E1 /* PatreonViewController.swift */; };
BFF0B69023219C6D007A79E1 /* PatreonComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF0B68F23219C6D007A79E1 /* PatreonComponents.swift */; };
BFF0B6922321A305007A79E1 /* AboutPatreonHeaderView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BFF0B6912321A305007A79E1 /* AboutPatreonHeaderView.xib */; };
DBAC68F8EC03F4A41D62EDE1 /* Pods_AltStore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1039C07E517311FC499A0B64 /* Pods_AltStore.framework */; };
/* End PBXBuildFile section */
@@ -456,7 +458,6 @@
BFD52C1F22A1A9EC000B7ED1 /* cnary.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cnary.c; path = Dependencies/libplist/libcnary/cnary.c; sourceTree = SOURCE_ROOT; };
BFD5D6E7230CC961007955AB /* PatreonAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PatreonAPI.swift; sourceTree = "<group>"; };
BFD5D6E9230CCAE5007955AB /* PatreonAccount.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PatreonAccount.swift; sourceTree = "<group>"; };
BFD5D6EB230CCDA1007955AB /* PatreonViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PatreonViewController.swift; sourceTree = "<group>"; };
BFD5D6ED230D8A86007955AB /* Patron.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Patron.swift; sourceTree = "<group>"; };
BFD5D6F1230DD974007955AB /* Benefit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Benefit.swift; sourceTree = "<group>"; };
BFD5D6F3230DDB0A007955AB /* Campaign.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Campaign.swift; sourceTree = "<group>"; };
@@ -484,6 +485,9 @@
BFE6326722A858F300F30809 /* Account.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Account.swift; sourceTree = "<group>"; };
BFE6326922A85DAF00F30809 /* ReplaceCertificateViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReplaceCertificateViewController.swift; sourceTree = "<group>"; };
BFE6326B22A86FF300F30809 /* AuthenticationOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationOperation.swift; sourceTree = "<group>"; };
BFF0B68D23219520007A79E1 /* PatreonViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PatreonViewController.swift; sourceTree = "<group>"; };
BFF0B68F23219C6D007A79E1 /* PatreonComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PatreonComponents.swift; sourceTree = "<group>"; };
BFF0B6912321A305007A79E1 /* AboutPatreonHeaderView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AboutPatreonHeaderView.xib; sourceTree = "<group>"; };
EA79A60285C6AF5848AA16E9 /* Pods-AltStore.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AltStore.debug.xcconfig"; path = "Target Support Files/Pods-AltStore/Pods-AltStore.debug.xcconfig"; sourceTree = "<group>"; };
FC3822AB1C4CF1D4CDF7445D /* Pods_AltServer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_AltServer.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
@@ -971,7 +975,9 @@
BFE60741231B07E6002B0E8E /* SettingsHeaderFooterView.swift */,
BFE6073B231AE1E7002B0E8E /* SettingsHeaderFooterView.xib */,
BF02419522F2199300129732 /* RefreshAttemptsViewController.swift */,
BFD5D6EB230CCDA1007955AB /* PatreonViewController.swift */,
BFF0B68D23219520007A79E1 /* PatreonViewController.swift */,
BFF0B68F23219C6D007A79E1 /* PatreonComponents.swift */,
BFF0B6912321A305007A79E1 /* AboutPatreonHeaderView.xib */,
);
path = Settings;
sourceTree = "<group>";
@@ -1223,6 +1229,7 @@
BFD2477A2284B9A700981D42 /* LaunchScreen.storyboard in Resources */,
BF770E6922BD57DD002A40FE /* Silence.m4a in Resources */,
BFD247772284B9A700981D42 /* Assets.xcassets in Resources */,
BFF0B6922321A305007A79E1 /* AboutPatreonHeaderView.xib in Resources */,
BFB6B22423187A3D0022A802 /* NewsCollectionViewCell.xib in Resources */,
BFD247752284B9A500981D42 /* Main.storyboard in Resources */,
BFDB5B2622EFBBEA00F74113 /* BrowseCollectionViewCell.xib in Resources */,
@@ -1393,7 +1400,6 @@
BFDB6A0F22AB2776007EA6D6 /* SendAppOperation.swift in Sources */,
BFDB6A0D22AAFC1A007EA6D6 /* OperationError.swift in Sources */,
BF3D649D22E7AC1B00E9056B /* PermissionPopoverViewController.swift in Sources */,
BFD5D6EC230CCDA1007955AB /* PatreonViewController.swift in Sources */,
BFE6325E22A8497000F30809 /* SelectTeamViewController.swift in Sources */,
BFD2478F2284C8F900981D42 /* Button.swift in Sources */,
BFD5D6F6230DDB12007955AB /* Tier.swift in Sources */,
@@ -1416,6 +1422,7 @@
BFD2478C2284C4C300981D42 /* AppIconImageView.swift in Sources */,
BFE338DD22F0E7F3002E24B9 /* Source.swift in Sources */,
BF8F69C422E662D300049BA1 /* AppViewController.swift in Sources */,
BFF0B68E23219520007A79E1 /* PatreonViewController.swift in Sources */,
BFD5D6EA230CCAE5007955AB /* PatreonAccount.swift in Sources */,
BFE6326822A858F300F30809 /* Account.swift in Sources */,
BFE6326622A857C200F30809 /* Team.swift in Sources */,
@@ -1458,6 +1465,7 @@
BFDB6A0522A9AFB2007EA6D6 /* Fetchable.swift in Sources */,
BFD2479F2284FBD000981D42 /* UIColor+AltStore.swift in Sources */,
BFDB5B1622EE90D300F74113 /* Date+RelativeDate.swift in Sources */,
BFF0B69023219C6D007A79E1 /* PatreonComponents.swift in Sources */,
BF770E5622BC3C03002A40FE /* Server.swift in Sources */,
BF43003022A71C960051E2BC /* UserDefaults+AltStore.swift in Sources */,
);

View File

@@ -12,6 +12,8 @@ import Roxas
class NavigationBar: UINavigationBar
{
@IBInspectable var automaticallyAdjustsItemPositions: Bool = true
private let backgroundColorView = UIView()
override init(frame: CGRect)
@@ -55,11 +57,14 @@ class NavigationBar: UINavigationBar
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
if self.automaticallyAdjustsItemPositions
{
guard NSStringFromClass(type(of: contentView)).contains("ContentView") else { continue }
contentView.center.y -= 2
// We can't easily shift just the back button up, so we shift the entire content view slightly.
for contentView in self.subviews
{
guard NSStringFromClass(type(of: contentView)).contains("ContentView") else { continue }
contentView.center.y -= 2
}
}
}
}

View File

@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="Named colors" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<collectionReusableView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" reuseIdentifier="AboutHeader" id="xq2-Pl-zaG" customClass="AboutPatreonHeaderView" customModule="AltStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="375" height="284"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="XiA-Jf-XMp">
<rect key="frame" x="20" y="0.0" width="335" height="254"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bju-6l-3iA">
<rect key="frame" x="0.0" y="0.0" width="335" height="183"/>
<string key="text">Hey y'all!
If you'd like to support my work, you can donate here. In return, you'll gain access to beta versions of all of my apps and be among the first to try the latest features.
Thanks for all of your support 💜
Riley</string>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="0.75" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="yEi-L6-kQ8">
<rect key="frame" x="0.0" y="203" width="335" height="51"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="51" id="l4o-vb-cMy"/>
</constraints>
<fontDescription key="fontDescription" type="boldSystem" pointSize="19"/>
<state key="normal" title="Support me">
<color key="titleColor" name="Green"/>
</state>
</button>
</subviews>
</stackView>
</subviews>
<constraints>
<constraint firstItem="XiA-Jf-XMp" firstAttribute="leading" secondItem="xq2-Pl-zaG" secondAttribute="leading" constant="20" id="Ac6-gO-UtF"/>
<constraint firstAttribute="trailing" secondItem="XiA-Jf-XMp" secondAttribute="trailing" constant="20" id="iAM-Q4-hP4"/>
<constraint firstItem="XiA-Jf-XMp" firstAttribute="top" secondItem="xq2-Pl-zaG" secondAttribute="top" id="j8p-JX-Dcz"/>
<constraint firstAttribute="bottom" secondItem="XiA-Jf-XMp" secondAttribute="bottom" constant="30" id="qlR-EG-83F"/>
</constraints>
<connections>
<outlet property="supportButton" destination="yEi-L6-kQ8" id="Dzo-vd-SnD"/>
</connections>
</collectionReusableView>
</objects>
<resources>
<namedColor name="Green">
<color red="0.22352941176470589" green="0.49411764705882355" blue="0.396078431372549" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
</resources>
</document>

View File

@@ -0,0 +1,68 @@
//
// PatreonComponents.swift
// AltStore
//
// Created by Riley Testut on 9/5/19.
// Copyright © 2019 Riley Testut. All rights reserved.
//
import UIKit
class PatronCollectionViewCell: UICollectionViewCell
{
@IBOutlet var textLabel: UILabel!
}
class PatronsHeaderView: UICollectionReusableView
{
let textLabel = UILabel()
override init(frame: CGRect)
{
super.init(frame: frame)
self.textLabel.font = UIFont.boldSystemFont(ofSize: 17)
self.textLabel.textColor = .white
self.addSubview(self.textLabel, pinningEdgesWith: UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20))
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class PatronsFooterView: UICollectionReusableView
{
let button = UIButton(type: .system)
override init(frame: CGRect)
{
super.init(frame: frame)
self.button.translatesAutoresizingMaskIntoConstraints = false
self.button.activityIndicatorView.style = .white
self.button.titleLabel?.textColor = .white
self.addSubview(self.button)
NSLayoutConstraint.activate([self.button.centerXAnchor.constraint(equalTo: self.centerXAnchor),
self.button.centerYAnchor.constraint(equalTo: self.centerYAnchor)])
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class AboutPatreonHeaderView: UICollectionReusableView
{
@IBOutlet var supportButton: UIButton!
override func awakeFromNib()
{
super.awakeFromNib()
self.supportButton.clipsToBounds = true
self.supportButton.layer.cornerRadius = 16
}
}

View File

@@ -2,18 +2,33 @@
// PatreonViewController.swift
// AltStore
//
// Created by Riley Testut on 8/20/19.
// Created by Riley Testut on 9/5/19.
// Copyright © 2019 Riley Testut. All rights reserved.
//
import UIKit
import SafariServices
import AuthenticationServices
import Roxas
class PatreonViewController: UITableViewController
extension PatreonViewController
{
private enum Section: Int, CaseIterable
{
case about
case patrons
}
}
class PatreonViewController: UICollectionViewController
{
private lazy var dataSource = self.makeDataSource()
private lazy var patronsDataSource = self.makePatronsDataSource()
private var prototypeAboutHeader: AboutPatreonHeaderView!
private var patronsResult: Result<[Patron], Error>?
@IBOutlet private var signInButton: UIBarButtonItem!
@IBOutlet private var signOutButton: UIBarButtonItem!
@@ -22,7 +37,14 @@ class PatreonViewController: UITableViewController
{
super.viewDidLoad()
self.tableView.dataSource = self.dataSource
let aboutHeaderNib = UINib(nibName: "AboutPatreonHeaderView", bundle: nil)
self.prototypeAboutHeader = aboutHeaderNib.instantiate(withOwner: nil, options: nil)[0] as? AboutPatreonHeaderView
self.collectionView.dataSource = self.dataSource
self.collectionView.register(aboutHeaderNib, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "AboutHeader")
self.collectionView.register(PatronsHeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "PatronsHeader")
self.collectionView.register(PatronsFooterView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: "PatronsFooter")
self.update()
}
@@ -32,19 +54,45 @@ class PatreonViewController: UITableViewController
super.viewWillAppear(animated)
self.fetchPatrons()
self.update()
}
override func viewDidLayoutSubviews()
{
super.viewDidLayoutSubviews()
let layout = self.collectionViewLayout as! UICollectionViewFlowLayout
var itemWidth = (self.collectionView.bounds.width - (layout.sectionInset.left + layout.sectionInset.right + layout.minimumInteritemSpacing)) / 2
itemWidth.round(.down)
layout.itemSize = CGSize(width: itemWidth, height: layout.itemSize.height)
}
}
private extension PatreonViewController
{
func makeDataSource() -> RSTArrayTableViewDataSource<Patron>
func makeDataSource() -> RSTCompositeCollectionViewDataSource<Patron>
{
let dataSource = RSTArrayTableViewDataSource<Patron>(items: [])
dataSource.cellConfigurationHandler = { (cell, patron, indexPath) in
cell.textLabel?.text = patron.name
let aboutDataSource = RSTDynamicCollectionViewDataSource<Patron>()
aboutDataSource.numberOfSectionsHandler = { 1 }
aboutDataSource.numberOfItemsHandler = { _ in 0 }
let dataSource = RSTCompositeCollectionViewDataSource<Patron>(dataSources: [aboutDataSource, self.patronsDataSource])
dataSource.proxy = self
return dataSource
}
func makePatronsDataSource() -> RSTArrayCollectionViewDataSource<Patron>
{
let patronsDataSource = RSTArrayCollectionViewDataSource<Patron>(items: [])
patronsDataSource.cellConfigurationHandler = { (cell, patron, indexPath) in
let cell = cell as! PatronCollectionViewCell
cell.textLabel.text = patron.name
}
return dataSource
return patronsDataSource
}
func update()
@@ -58,28 +106,48 @@ private extension PatreonViewController
self.navigationItem.rightBarButtonItem = self.signInButton
}
}
func fetchPatrons()
{
PatreonAPI.shared.fetchPatrons { (result) in
do
{
let patrons = try result.get()
self.dataSource.items = patrons
}
catch
{
DispatchQueue.main.async {
let toastView = ToastView(text: error.localizedDescription, detailText: nil)
toastView.show(in: self.navigationController?.view ?? self.view, duration: 2.0)
}
}
}
}
}
private extension PatreonViewController
{
@objc func fetchPatrons()
{
if let result = self.patronsResult, case .failure = result
{
self.patronsResult = nil
self.collectionView.reloadData()
}
PatreonAPI.shared.fetchPatrons { (result) in
self.patronsResult = result
do
{
let patrons = try result.get()
let sortedPatrons = patrons.sorted { $0.name < $1.name }
self.patronsDataSource.items = sortedPatrons
}
catch
{
print("Failed to fetch patrons:", error)
DispatchQueue.main.async {
self.collectionView.reloadData()
}
}
}
}
@objc func openPatreonURL(_ sender: UIButton)
{
let patreonURL = URL(string: "https://www.patreon.com/rileytestut")!
let safariViewController = SFSafariViewController(url: patreonURL)
safariViewController.preferredControlTintColor = self.view.tintColor
self.present(safariViewController, animated: true, completion: nil)
}
@IBAction func authenticate(_ sender: UIBarButtonItem)
{
PatreonAPI.shared.authenticate { (result) in
@@ -108,22 +176,100 @@ private extension PatreonViewController
@IBAction func signOut(_ sender: UIBarButtonItem)
{
PatreonAPI.shared.signOut { (result) in
do
{
try result.get()
DispatchQueue.main.async {
self.update()
func signOut()
{
PatreonAPI.shared.signOut { (result) in
do
{
try result.get()
DispatchQueue.main.async {
self.update()
}
}
catch
{
DispatchQueue.main.async {
let toastView = ToastView(text: error.localizedDescription, detailText: nil)
toastView.show(in: self.navigationController?.view ?? self.view, duration: 2.0)
}
}
}
catch
}
let alertController = UIAlertController(title: NSLocalizedString("Are you sure you want to sign out?", comment: ""), message: NSLocalizedString("You will no longer have access to beta versions of apps once you sign out.", comment: ""), preferredStyle: .actionSheet)
alertController.addAction(UIAlertAction(title: NSLocalizedString("Sign Out", comment: ""), style: .destructive) { _ in signOut() })
alertController.addAction(.cancel)
self.present(alertController, animated: true, completion: nil)
}
}
extension PatreonViewController
{
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView
{
let section = Section.allCases[indexPath.section]
switch section
{
case .about:
let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "AboutHeader", for: indexPath) as! AboutPatreonHeaderView
headerView.supportButton.addTarget(self, action: #selector(PatreonViewController.openPatreonURL(_:)), for: .primaryActionTriggered)
return headerView
case .patrons:
if kind == UICollectionView.elementKindSectionHeader
{
DispatchQueue.main.async {
let toastView = ToastView(text: error.localizedDescription, detailText: nil)
toastView.show(in: self.navigationController?.view ?? self.view, duration: 2.0)
let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "PatronsHeader", for: indexPath) as! PatronsHeaderView
headerView.textLabel.text = NSLocalizedString("Special thanks to...", comment: "")
return headerView
}
else
{
let footerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "PatronsFooter", for: indexPath) as! PatronsFooterView
footerView.button.isIndicatingActivity = false
footerView.button.isHidden = false
footerView.button.addTarget(self, action: #selector(PatreonViewController.fetchPatrons), for: .primaryActionTriggered)
switch self.patronsResult
{
case .none: footerView.button.isIndicatingActivity = true
case .success?: footerView.button.isHidden = true
case .failure?: footerView.button.setTitle(NSLocalizedString("Error Loading Patrons", comment: ""), for: .normal)
}
return footerView
}
}
}
}
extension PatreonViewController: UICollectionViewDelegateFlowLayout
{
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize
{
let section = Section.allCases[section]
switch section
{
case .about:
let widthConstraint = self.prototypeAboutHeader.widthAnchor.constraint(equalToConstant: collectionView.bounds.width)
NSLayoutConstraint.activate([widthConstraint])
defer { NSLayoutConstraint.deactivate([widthConstraint]) }
let size = self.prototypeAboutHeader.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
return size
case .patrons:
return CGSize(width: 320, height: 20)
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize
{
let section = Section.allCases[section]
switch section
{
case .about: return .zero
case .patrons: return CGSize(width: 320, height: 20)
}
}
}

View File

@@ -186,7 +186,7 @@
<userDefinedRuntimeAttribute type="boolean" keyPath="isSelectable" value="YES"/>
</userDefinedRuntimeAttributes>
<connections>
<segue destination="SMU-vR-jsh" kind="show" identifier="showPatreon" id="SQ1-Kp-L45"/>
<segue destination="dp8-8j-vt9" kind="show" identifier="showPatreon" id="gCj-C6-hPm"/>
</connections>
</tableViewCell>
</cells>
@@ -300,7 +300,11 @@
<rect key="frame" x="0.0" y="20" width="375" height="96"/>
<autoresizingMask key="autoresizingMask"/>
<color key="backgroundColor" name="Orange"/>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="barTintColor" name="Orange"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="automaticallyAdjustsItemPositions" value="NO"/>
</userDefinedRuntimeAttributes>
</navigationBar>
<nil name="viewControllers"/>
<connections>
@@ -381,56 +385,71 @@
<point key="canvasLocation" x="1697" y="797"/>
</scene>
<!--Patreon-->
<scene sceneID="h2z-Zg-r0l">
<scene sceneID="Lnh-9P-HnL">
<objects>
<tableViewController id="SMU-vR-jsh" customClass="PatreonViewController" customModule="AltStore" 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="KIK-07-O36">
<collectionViewController id="dp8-8j-vt9" customClass="PatreonViewController" customModule="AltStore" customModuleProvider="target" sceneMemberID="viewController">
<collectionView key="view" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" id="OTF-Qv-Z5w">
<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" reuseIdentifier="Cell" textLabel="kKJ-b1-Ewh" style="IBUITableViewCellStyleDefault" id="fdL-CS-Ig8">
<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="fdL-CS-Ig8" id="Vcq-Uu-TK4">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<color key="backgroundColor" name="Orange"/>
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="20" id="5Ex-oN-7dE">
<size key="itemSize" width="157" height="20"/>
<size key="headerReferenceSize" width="0.0" height="0.0"/>
<size key="footerReferenceSize" width="0.0" height="0.0"/>
<inset key="sectionInset" minX="20" minY="8" maxX="20" maxY="0.0"/>
</collectionViewFlowLayout>
<cells>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="Cell" id="T6v-Rq-ntX" customClass="PatronCollectionViewCell" customModule="AltStore" customModuleProvider="target">
<rect key="frame" x="20" y="8" width="157" height="20"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO">
<rect key="frame" x="0.0" y="0.0" width="157" height="20"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="kKJ-b1-Ewh">
<rect key="frame" x="16" y="0.0" width="343" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Caroline Moore" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumScaleFactor="0.25" translatesAutoresizingMaskIntoConstraints="NO" id="ahr-fF-k3e">
<rect key="frame" x="0.0" y="0.0" width="157" height="20"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" white="1" alpha="0.75" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
</prototypes>
</view>
<constraints>
<constraint firstAttribute="trailing" secondItem="ahr-fF-k3e" secondAttribute="trailing" id="9aF-2y-sZf"/>
<constraint firstItem="ahr-fF-k3e" firstAttribute="top" secondItem="T6v-Rq-ntX" secondAttribute="top" id="M89-x2-VnS"/>
<constraint firstItem="ahr-fF-k3e" firstAttribute="leading" secondItem="T6v-Rq-ntX" secondAttribute="leading" id="THC-sX-gVq"/>
<constraint firstAttribute="bottom" secondItem="ahr-fF-k3e" secondAttribute="bottom" id="loA-GD-3td"/>
</constraints>
<connections>
<outlet property="textLabel" destination="ahr-fF-k3e" id="xql-Ch-bfh"/>
</connections>
</collectionViewCell>
</cells>
<connections>
<outlet property="dataSource" destination="SMU-vR-jsh" id="Hj4-Km-9nk"/>
<outlet property="delegate" destination="SMU-vR-jsh" id="ASl-Da-Ah0"/>
<outlet property="dataSource" destination="dp8-8j-vt9" id="ONG-kb-M7N"/>
<outlet property="delegate" destination="dp8-8j-vt9" id="790-Kr-6l7"/>
</connections>
</tableView>
<navigationItem key="navigationItem" title="Patreon" largeTitleDisplayMode="never" id="dK7-R5-OHU">
<barButtonItem key="rightBarButtonItem" title="Sign In" style="done" id="5jH-Bg-xV0">
</collectionView>
<navigationItem key="navigationItem" title="Patreon" largeTitleDisplayMode="always" id="uUV-1f-xEq">
<barButtonItem key="rightBarButtonItem" title="Sign In" style="done" id="E5h-CT-k6v">
<connections>
<action selector="authenticate:" destination="SMU-vR-jsh" id="idl-h4-lM8"/>
<action selector="authenticate:" destination="dp8-8j-vt9" id="pFp-yX-Tqi"/>
</connections>
</barButtonItem>
</navigationItem>
<connections>
<outlet property="signInButton" destination="5jH-Bg-xV0" id="iwr-Yd-iv5"/>
<outlet property="signOutButton" destination="OLU-TR-ZrX" id="N7y-lz-yJu"/>
<outlet property="signInButton" destination="E5h-CT-k6v" id="G3Y-ZY-lVk"/>
<outlet property="signOutButton" destination="gsd-cI-bVF" id="cEC-IE-vcJ"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="AQT-F8-lsD" userLabel="First Responder" sceneMemberID="firstResponder"/>
<barButtonItem title="Sign Out" style="done" id="OLU-TR-ZrX">
<color key="tintColor" name="RefreshRed"/>
</collectionViewController>
<barButtonItem title="Sign Out" style="done" id="gsd-cI-bVF">
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<connections>
<action selector="signOut:" destination="SMU-vR-jsh" id="LIj-5B-xIs"/>
<action selector="signOut:" destination="dp8-8j-vt9" id="BvZ-yR-Sa3"/>
</connections>
</barButtonItem>
<placeholder placeholderIdentifier="IBFirstResponder" id="qq3-Hj-S9f" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1697" y="44"/>
</scene>
@@ -441,8 +460,5 @@
<namedColor name="Orange">
<color red="0.94509803921568625" green="0.67450980392156867" blue="0.24313725490196078" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
<namedColor name="RefreshRed">
<color red="1" green="0.23137254901960785" blue="0.18823529411764706" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
</resources>
</document>