mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-08 22:33:26 +01:00
Revises Patreon UI
This commit is contained in:
@@ -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 */,
|
||||
);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
64
AltStore/Settings/AboutPatreonHeaderView.xib
Normal file
64
AltStore/Settings/AboutPatreonHeaderView.xib
Normal 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>
|
||||
68
AltStore/Settings/PatreonComponents.swift
Normal file
68
AltStore/Settings/PatreonComponents.swift
Normal 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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user