diff --git a/AltStore.xcodeproj/project.pbxproj b/AltStore.xcodeproj/project.pbxproj index d4bdbee6..b6897373 100644 --- a/AltStore.xcodeproj/project.pbxproj +++ b/AltStore.xcodeproj/project.pbxproj @@ -115,6 +115,7 @@ BF54E8212315EF0D000AE0D8 /* ALTPatreonBenefitType.m in Sources */ = {isa = PBXBuildFile; fileRef = BF54E8202315EF0D000AE0D8 /* ALTPatreonBenefitType.m */; }; BF5AB3A82285FE7500DC914B /* AltSign.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF5AB3A72285FE6C00DC914B /* AltSign.framework */; }; BF5AB3A92285FE7500DC914B /* AltSign.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BF5AB3A72285FE6C00DC914B /* AltSign.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + BF74989B23621C0700CED65F /* ForwardingNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF74989A23621C0700CED65F /* ForwardingNavigationController.swift */; }; BF770E5122BB1CF6002A40FE /* InstallAppOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF770E5022BB1CF6002A40FE /* InstallAppOperation.swift */; }; BF770E5422BC044E002A40FE /* AppOperationContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF770E5322BC044E002A40FE /* AppOperationContext.swift */; }; BF770E5622BC3C03002A40FE /* Server.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF770E5522BC3C02002A40FE /* Server.swift */; }; @@ -395,6 +396,7 @@ BF54E81F2315EF0D000AE0D8 /* ALTPatreonBenefitType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ALTPatreonBenefitType.h; sourceTree = ""; }; BF54E8202315EF0D000AE0D8 /* ALTPatreonBenefitType.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ALTPatreonBenefitType.m; sourceTree = ""; }; BF5AB3A72285FE6C00DC914B /* AltSign.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = AltSign.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + BF74989A23621C0700CED65F /* ForwardingNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForwardingNavigationController.swift; sourceTree = ""; }; BF770E5022BB1CF6002A40FE /* InstallAppOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstallAppOperation.swift; sourceTree = ""; }; BF770E5322BC044E002A40FE /* AppOperationContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppOperationContext.swift; sourceTree = ""; }; BF770E5522BC3C02002A40FE /* Server.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Server.swift; sourceTree = ""; }; @@ -929,6 +931,7 @@ isa = PBXGroup; children = ( BFD2478B2284C4C300981D42 /* AppIconImageView.swift */, + BF74989A23621C0700CED65F /* ForwardingNavigationController.swift */, BFD2478E2284C8F900981D42 /* Button.swift */, BF43002D22A714AF0051E2BC /* Keychain.swift */, BF770E6622BD57C3002A40FE /* BackgroundTaskManager.swift */, @@ -1448,6 +1451,7 @@ files = ( BFDB6A0F22AB2776007EA6D6 /* SendAppOperation.swift in Sources */, BFDB6A0D22AAFC1A007EA6D6 /* OperationError.swift in Sources */, + BF74989B23621C0700CED65F /* ForwardingNavigationController.swift in Sources */, BF3D649D22E7AC1B00E9056B /* PermissionPopoverViewController.swift in Sources */, BFD2478F2284C8F900981D42 /* Button.swift in Sources */, BFD5D6F6230DDB12007955AB /* Tier.swift in Sources */, diff --git a/AltStore/App Detail/AppContentViewController.swift b/AltStore/App Detail/AppContentViewController.swift index 33ddd9d5..fcdb9bfd 100644 --- a/AltStore/App Detail/AppContentViewController.swift +++ b/AltStore/App Detail/AppContentViewController.swift @@ -73,6 +73,8 @@ class AppContentViewController: UITableViewController self.tableView.contentInset.bottom = 20 self.screenshotsCollectionView.dataSource = self.screenshotsDataSource + self.screenshotsCollectionView.prefetchDataSource = self.screenshotsDataSource + self.permissionsCollectionView.dataSource = self.permissionsDataSource self.subtitleLabel.text = self.app.subtitle diff --git a/AltStore/App Detail/AppViewController.swift b/AltStore/App Detail/AppViewController.swift index d2b4ff5c..2869ae91 100644 --- a/AltStore/App Detail/AppViewController.swift +++ b/AltStore/App Detail/AppViewController.swift @@ -27,18 +27,11 @@ class AppViewController: UIViewController @IBOutlet private var scrollView: UIScrollView! @IBOutlet private var contentView: UIView! - @IBOutlet private var headerView: UIView! - @IBOutlet private var headerContentView: UIView! + @IBOutlet private var bannerView: AppBannerView! @IBOutlet private var backButton: UIButton! @IBOutlet private var backButtonContainerView: UIVisualEffectView! - @IBOutlet private var nameLabel: UILabel! - @IBOutlet private var developerLabel: UILabel! - @IBOutlet private var downloadButton: PillButton! - @IBOutlet private var appIconImageView: UIImageView! - @IBOutlet private var betaBadgeView: UIImageView! - @IBOutlet private var backgroundAppIconImageView: UIImageView! @IBOutlet private var backgroundBlurView: UIVisualEffectView! @@ -51,6 +44,12 @@ class AppViewController: UIViewController private var _backgroundBlurEffect: UIBlurEffect? private var _backgroundBlurTintColor: UIColor? + private var _preferredStatusBarStyle: UIStatusBarStyle = .default + + override var preferredStatusBarStyle: UIStatusBarStyle { + return _preferredStatusBarStyle + } + override func viewDidLoad() { super.viewDidLoad() @@ -75,21 +74,20 @@ class AppViewController: UIViewController self.contentViewController.tableView.panGestureRecognizer.require(toFail: self.scrollView.panGestureRecognizer) self.contentViewController.tableView.showsVerticalScrollIndicator = false - self.headerView.frame = CGRect(x: 0, y: 0, width: 300, height: 93) - self.headerView.layer.cornerRadius = 24 - self.headerView.layer.masksToBounds = true - // Bring to front so the scroll indicators are visible. self.view.bringSubviewToFront(self.scrollView) self.scrollView.isUserInteractionEnabled = false - self.nameLabel.text = self.app.name - self.developerLabel.text = self.app.developerName - self.developerLabel.textColor = self.app.tintColor - self.appIconImageView.image = nil - self.appIconImageView.tintColor = self.app.tintColor - self.downloadButton.tintColor = self.app.tintColor - self.betaBadgeView.isHidden = !self.app.isBeta + self.bannerView.frame = CGRect(x: 0, y: 0, width: 300, height: 93) + self.bannerView.backgroundEffectView.effect = UIBlurEffect(style: .regular) + self.bannerView.backgroundEffectView.backgroundColor = .clear + self.bannerView.titleLabel.text = self.app.name + self.bannerView.subtitleLabel.text = self.app.developerName + self.bannerView.iconImageView.image = nil + self.bannerView.iconImageView.tintColor = self.app.tintColor + self.bannerView.button.tintColor = self.app.tintColor + self.bannerView.betaBadgeView.isHidden = !self.app.isBeta + self.bannerView.tintColor = self.app.tintColor self.backButtonContainerView.tintColor = self.app.tintColor @@ -112,7 +110,7 @@ class AppViewController: UIViewController self._backgroundBlurTintColor = self.backgroundBlurView.contentView.backgroundColor // Load Images - for imageView in [self.appIconImageView!, self.backgroundAppIconImageView!, self.navigationBarAppIconImageView!] + for imageView in [self.bannerView.iconImageView!, self.backgroundAppIconImageView!, self.navigationBarAppIconImageView!] { imageView.isIndicatingActivity = true @@ -219,7 +217,7 @@ class AppViewController: UIViewController var backButtonFrame = CGRect(x: inset, y: statusBarHeight, width: backButtonSize.width + 20, height: backButtonSize.height + 20) - var headerFrame = CGRect(x: inset, y: 0, width: self.view.bounds.width - inset * 2, height: self.headerView.bounds.height) + var headerFrame = CGRect(x: inset, y: 0, width: self.view.bounds.width - inset * 2, height: self.bannerView.bounds.height) var contentFrame = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height) var backgroundIconFrame = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.width) @@ -305,12 +303,11 @@ class AppViewController: UIViewController // Set frames. self.contentViewController.view.superview?.frame = contentFrame - self.headerView.frame = headerFrame + self.bannerView.frame = headerFrame self.backgroundAppIconImageView.frame = backgroundIconFrame self.backgroundBlurView.frame = backgroundIconFrame self.backButtonContainerView.frame = backButtonFrame - self.headerContentView.frame = CGRect(x: 0, y: 0, width: self.headerView.bounds.width, height: self.headerView.bounds.height) self.contentViewControllerShadowView.frame = self.contentViewController.view.frame self.backButtonContainerView.layer.cornerRadius = self.backButtonContainerView.bounds.midY @@ -325,6 +322,14 @@ class AppViewController: UIViewController self.scrollView.contentSize = contentSize self.scrollView.contentOffset = contentOffset + + self.bannerView.backgroundEffectView.backgroundColor = .clear + } + + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) + { + super.traitCollectionDidChange(previousTraitCollection) + self._shouldResetLayout = true } deinit @@ -350,7 +355,7 @@ private extension AppViewController { func update() { - for button in [self.downloadButton!, self.navigationBarDownloadButton!] + for button in [self.bannerView.button!, self.navigationBarDownloadButton!] { button.tintColor = self.app.tintColor button.isIndicatingActivity = false @@ -358,12 +363,10 @@ private extension AppViewController if self.app.installedApp == nil { button.setTitle(NSLocalizedString("FREE", comment: ""), for: .normal) - button.isInverted = false } else { button.setTitle(NSLocalizedString("OPEN", comment: ""), for: .normal) - button.isInverted = true } let progress = AppManager.shared.installationProgress(for: self.app) @@ -372,12 +375,12 @@ private extension AppViewController if Date() < self.app.versionDate { - self.downloadButton.countdownDate = self.app.versionDate + self.bannerView.button.countdownDate = self.app.versionDate self.navigationBarDownloadButton.countdownDate = self.app.versionDate } else { - self.downloadButton.countdownDate = nil + self.bannerView.button.countdownDate = nil self.navigationBarDownloadButton.countdownDate = nil } @@ -389,18 +392,29 @@ private extension AppViewController func showNavigationBar(for navigationController: UINavigationController? = nil) { let navigationController = navigationController ?? self.navigationController - navigationController?.navigationBar.barStyle = .default navigationController?.navigationBar.alpha = 1.0 - navigationController?.navigationBar.barTintColor = .white navigationController?.navigationBar.tintColor = .altPrimary + navigationController?.navigationBar.setNeedsLayout() + + if self.traitCollection.userInterfaceStyle == .dark + { + self._preferredStatusBarStyle = .lightContent + } + else + { + self._preferredStatusBarStyle = .default + } + + navigationController?.setNeedsStatusBarAppearanceUpdate() } func hideNavigationBar(for navigationController: UINavigationController? = nil) { let navigationController = navigationController ?? self.navigationController - navigationController?.navigationBar.barStyle = .black navigationController?.navigationBar.alpha = 0.0 - navigationController?.navigationBar.barTintColor = .white + + self._preferredStatusBarStyle = .lightContent + navigationController?.setNeedsStatusBarAppearanceUpdate() } func prepareBlur() @@ -445,7 +459,7 @@ private extension AppViewController self.navigationBarAnimator = nil self.hideNavigationBar() - self.navigationController?.navigationBar.barTintColor = .white + self.contentViewController.view.layer.cornerRadius = self.contentViewControllerShadowView.layer.cornerRadius } } @@ -491,12 +505,14 @@ extension AppViewController } DispatchQueue.main.async { - self.downloadButton.progress = nil + self.bannerView.button.progress = nil + self.navigationBarDownloadButton.progress = nil self.update() } } - self.downloadButton.progress = progress + self.bannerView.button.progress = progress + self.navigationBarDownloadButton.progress = progress } func open(_ installedApp: InstalledApp) diff --git a/AltStore/Authentication/Authentication.storyboard b/AltStore/Authentication/Authentication.storyboard index 50d473c7..2ada4c02 100644 --- a/AltStore/Authentication/Authentication.storyboard +++ b/AltStore/Authentication/Authentication.storyboard @@ -1,9 +1,9 @@ - + - + @@ -17,7 +17,7 @@ - + @@ -65,7 +65,7 @@ @@ -174,13 +174,13 @@ - + @@ -445,12 +445,12 @@ - - - - + + + + diff --git a/AltStore/Authentication/AuthenticationViewController.swift b/AltStore/Authentication/AuthenticationViewController.swift index 56aefd43..ac1db12e 100644 --- a/AltStore/Authentication/AuthenticationViewController.swift +++ b/AltStore/Authentication/AuthenticationViewController.swift @@ -30,6 +30,8 @@ class AuthenticationViewController: UIViewController { super.viewDidLoad() + self.signInButton.activityIndicatorView.style = .white + for view in [self.appleIDBackgroundView!, self.passwordBackgroundView!, self.signInButton!] { view.clipsToBounds = true diff --git a/AltStore/Authentication/InstructionsViewController.swift b/AltStore/Authentication/InstructionsViewController.swift index 744da7af..0a37f2be 100644 --- a/AltStore/Authentication/InstructionsViewController.swift +++ b/AltStore/Authentication/InstructionsViewController.swift @@ -17,6 +17,10 @@ class InstructionsViewController: UIViewController @IBOutlet private var contentStackView: UIStackView! @IBOutlet private var dismissButton: UIButton! + override var preferredStatusBarStyle: UIStatusBarStyle { + return .lightContent + } + override func viewDidLoad() { super.viewDidLoad() diff --git a/AltStore/Base.lproj/Main.storyboard b/AltStore/Base.lproj/Main.storyboard index 3fb0ebd8..5e796cf0 100644 --- a/AltStore/Base.lproj/Main.storyboard +++ b/AltStore/Base.lproj/Main.storyboard @@ -1,12 +1,11 @@ - + - + - @@ -55,12 +54,12 @@ - - + + - + @@ -110,10 +109,9 @@ - - + @@ -124,69 +122,10 @@ - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -201,22 +140,35 @@ - + + + + + + + + + + + - + - + @@ -248,18 +200,12 @@ - - + - - - - - @@ -278,7 +224,7 @@ - + @@ -303,6 +249,7 @@ + @@ -314,7 +261,7 @@ - + @@ -340,6 +287,7 @@ + @@ -351,7 +299,7 @@ - + @@ -363,6 +311,7 @@ + @@ -416,7 +365,7 @@ - + @@ -431,6 +380,7 @@ + @@ -451,7 +401,7 @@ - + @@ -521,6 +471,7 @@ World + @@ -575,7 +526,7 @@ World - + @@ -610,12 +561,12 @@ World - + - + - + @@ -632,7 +583,7 @@ World - + @@ -652,7 +603,7 @@ World - + @@ -677,7 +628,7 @@ World - + @@ -685,104 +636,94 @@ World - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - + + + + - - - - - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + + @@ -830,12 +771,12 @@ World - + - + @@ -855,11 +796,16 @@ World - + + + + + + diff --git a/AltStore/Browse/BrowseCollectionViewCell.swift b/AltStore/Browse/BrowseCollectionViewCell.swift index 3192c28f..e27b51bf 100644 --- a/AltStore/Browse/BrowseCollectionViewCell.swift +++ b/AltStore/Browse/BrowseCollectionViewCell.swift @@ -20,40 +20,24 @@ import Nuke } } private lazy var dataSource = self.makeDataSource() - - @IBOutlet var nameLabel: UILabel! - @IBOutlet var developerLabel: UILabel! - @IBOutlet var appIconImageView: UIImageView! - @IBOutlet var actionButton: PillButton! + + @IBOutlet var bannerView: AppBannerView! @IBOutlet var subtitleLabel: UILabel! - @IBOutlet var screenshotsCollectionView: UICollectionView! - @IBOutlet var betaBadgeView: UIImageView! - - @IBOutlet private var screenshotsContentView: UIView! + @IBOutlet private(set) var screenshotsCollectionView: UICollectionView! override func awakeFromNib() { super.awakeFromNib() + self.contentView.preservesSuperviewLayoutMargins = true + // Must be registered programmatically, not in BrowseCollectionViewCell.xib, or else it'll throw an exception 🤷‍♂️. self.screenshotsCollectionView.register(ScreenshotCollectionViewCell.self, forCellWithReuseIdentifier: RSTCellContentGenericCellIdentifier) self.screenshotsCollectionView.delegate = self self.screenshotsCollectionView.dataSource = self.dataSource self.screenshotsCollectionView.prefetchDataSource = self.dataSource - - self.screenshotsContentView.layer.cornerRadius = 20 - self.screenshotsContentView.layer.masksToBounds = true - - self.update() - } - - override func tintColorDidChange() - { - super.tintColorDidChange() - - self.update() } } @@ -96,12 +80,6 @@ private extension BrowseCollectionViewCell return dataSource } - - private func update() - { - self.subtitleLabel.textColor = self.tintColor - self.screenshotsContentView.backgroundColor = self.tintColor.withAlphaComponent(0.1) - } } extension BrowseCollectionViewCell: UICollectionViewDelegateFlowLayout diff --git a/AltStore/Browse/BrowseCollectionViewCell.xib b/AltStore/Browse/BrowseCollectionViewCell.xib index 41e216af..ecd02b4e 100644 --- a/AltStore/Browse/BrowseCollectionViewCell.xib +++ b/AltStore/Browse/BrowseCollectionViewCell.xib @@ -1,131 +1,64 @@ - - - - + + - - + - - + + - + - - + + - - + + + - - + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - - - - - + - + - - - diff --git a/AltStore/Browse/BrowseViewController.swift b/AltStore/Browse/BrowseViewController.swift index b08f4d69..775dd2d2 100644 --- a/AltStore/Browse/BrowseViewController.swift +++ b/AltStore/Browse/BrowseViewController.swift @@ -72,47 +72,49 @@ private extension BrowseViewController let dataSource = RSTFetchedResultsCollectionViewPrefetchingDataSource(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext) dataSource.cellConfigurationHandler = { (cell, app, indexPath) in let cell = cell as! BrowseCollectionViewCell - cell.nameLabel.text = app.name - cell.developerLabel.text = app.developerName + cell.layoutMargins.left = self.view.layoutMargins.left + cell.layoutMargins.right = self.view.layoutMargins.right + cell.subtitleLabel.text = app.subtitle cell.imageURLs = Array(app.screenshotURLs.prefix(2)) - cell.appIconImageView.image = nil - cell.appIconImageView.isIndicatingActivity = true - cell.betaBadgeView.isHidden = !app.isBeta + cell.bannerView.titleLabel.text = app.name + cell.bannerView.subtitleLabel.text = app.developerName + cell.bannerView.betaBadgeView.isHidden = !app.isBeta - cell.actionButton.addTarget(self, action: #selector(BrowseViewController.performAppAction(_:)), for: .primaryActionTriggered) - cell.actionButton.activityIndicatorView.style = .white + cell.bannerView.iconImageView.image = nil + cell.bannerView.iconImageView.isIndicatingActivity = true + + cell.bannerView.button.addTarget(self, action: #selector(BrowseViewController.performAppAction(_:)), for: .primaryActionTriggered) + cell.bannerView.button.activityIndicatorView.style = .white // Explicitly set to false to ensure we're starting from a non-activity indicating state. // Otherwise, cell reuse can mess up some cached values. - cell.actionButton.isIndicatingActivity = false + cell.bannerView.button.isIndicatingActivity = false let tintColor = app.tintColor ?? .altPrimary cell.tintColor = tintColor if app.installedApp == nil { - cell.actionButton.setTitle(NSLocalizedString("FREE", comment: ""), for: .normal) + cell.bannerView.button.setTitle(NSLocalizedString("FREE", comment: ""), for: .normal) let progress = AppManager.shared.installationProgress(for: app) - cell.actionButton.progress = progress - cell.actionButton.isInverted = false + cell.bannerView.button.progress = progress if Date() < app.versionDate { - cell.actionButton.countdownDate = app.versionDate + cell.bannerView.button.countdownDate = app.versionDate } else { - cell.actionButton.countdownDate = nil + cell.bannerView.button.countdownDate = nil } } else { - cell.actionButton.setTitle(NSLocalizedString("OPEN", comment: ""), for: .normal) - cell.actionButton.progress = nil - cell.actionButton.isInverted = true - cell.actionButton.countdownDate = nil + cell.bannerView.button.setTitle(NSLocalizedString("OPEN", comment: ""), for: .normal) + cell.bannerView.button.progress = nil + cell.bannerView.button.countdownDate = nil } } dataSource.prefetchHandler = { (storeApp, indexPath, completionHandler) -> Foundation.Operation? in @@ -135,8 +137,8 @@ private extension BrowseViewController } dataSource.prefetchCompletionHandler = { (cell, image, indexPath, error) in let cell = cell as! BrowseCollectionViewCell - cell.appIconImageView.isIndicatingActivity = false - cell.appIconImageView.image = image + cell.bannerView.iconImageView.isIndicatingActivity = false + cell.bannerView.iconImageView.image = image if let error = error { @@ -286,8 +288,8 @@ extension BrowseViewController: UICollectionViewDelegateFlowLayout let maxVisibleScreenshots = 2 as CGFloat let aspectRatio: CGFloat = 16.0 / 9.0 - let layout = collectionViewLayout as! UICollectionViewFlowLayout - let padding = (layout.minimumInteritemSpacing * (maxVisibleScreenshots - 1)) + let layout = self.prototypeCell.screenshotsCollectionView.collectionViewLayout as! UICollectionViewFlowLayout + let padding = (layout.minimumInteritemSpacing * (maxVisibleScreenshots - 1)) + layout.sectionInset.left + layout.sectionInset.right self.dataSource.cellConfigurationHandler(self.prototypeCell, item, indexPath) @@ -295,6 +297,8 @@ extension BrowseViewController: UICollectionViewDelegateFlowLayout widthConstraint.isActive = true defer { widthConstraint.isActive = false } + // Manually update cell width & layout so we can accurately calculate screenshot sizes. + self.prototypeCell.frame.size.width = widthConstraint.constant self.prototypeCell.layoutIfNeeded() let collectionViewWidth = self.prototypeCell.screenshotsCollectionView.bounds.width @@ -302,6 +306,7 @@ extension BrowseViewController: UICollectionViewDelegateFlowLayout let screenshotHeight = screenshotWidth * aspectRatio let heightConstraint = self.prototypeCell.screenshotsCollectionView.heightAnchor.constraint(equalToConstant: screenshotHeight) + heightConstraint.priority = .defaultHigh // Prevent temporary unsatisfiable constraints error. heightConstraint.isActive = true defer { heightConstraint.isActive = false } diff --git a/AltStore/Components/AppBannerView.swift b/AltStore/Components/AppBannerView.swift index 3187fbd9..e2eb257d 100644 --- a/AltStore/Components/AppBannerView.swift +++ b/AltStore/Components/AppBannerView.swift @@ -15,8 +15,12 @@ class AppBannerView: RSTNibView @IBOutlet var subtitleLabel: UILabel! @IBOutlet var iconImageView: AppIconImageView! @IBOutlet var button: PillButton! + @IBOutlet var buttonLabel: UILabel! @IBOutlet var betaBadgeView: UIView! + @IBOutlet var backgroundEffectView: UIVisualEffectView! + @IBOutlet private var vibrancyView: UIVisualEffectView! + override func tintColorDidChange() { super.tintColorDidChange() @@ -35,6 +39,6 @@ private extension AppBannerView self.subtitleLabel.textColor = self.tintColor self.button.tintColor = self.tintColor - self.backgroundColor = self.tintColor.withAlphaComponent(0.1) + self.backgroundEffectView.backgroundColor = self.tintColor } } diff --git a/AltStore/Components/AppBannerView.xib b/AltStore/Components/AppBannerView.xib index 932629ec..cb5810f4 100644 --- a/AltStore/Components/AppBannerView.xib +++ b/AltStore/Components/AppBannerView.xib @@ -1,21 +1,23 @@ - - - - + + - + + + + + @@ -23,6 +25,15 @@ + + + + + + + + + @@ -34,54 +45,97 @@ - + - - + + - + + + + + - + + + + + + + + + + + + + + + + + + + - + + + + + - - - - + + + + + + + + + + + + diff --git a/AltStore/Components/AppIconImageView.swift b/AltStore/Components/AppIconImageView.swift index 2a8c6492..08371e8a 100644 --- a/AltStore/Components/AppIconImageView.swift +++ b/AltStore/Components/AppIconImageView.swift @@ -19,13 +19,16 @@ class AppIconImageView: UIImageView self.backgroundColor = .white - self.layer.borderWidth = 0.5 - self.layer.borderColor = self.tintColor.cgColor - - // Allows us to match system look for app icons. - if self.layer.responds(to: Selector(("continuousCorners"))) + if #available(iOS 13, *) { - self.layer.setValue(true, forKey: "continuousCorners") + self.layer.cornerCurve = .continuous + } + else + { + if self.layer.responds(to: Selector(("continuousCorners"))) + { + self.layer.setValue(true, forKey: "continuousCorners") + } } } @@ -37,11 +40,4 @@ class AppIconImageView: UIImageView let radius = self.bounds.height / 5 self.layer.cornerRadius = radius } - - override func tintColorDidChange() - { - super.tintColorDidChange() - - self.layer.borderColor = self.tintColor.cgColor - } } diff --git a/AltStore/Components/ForwardingNavigationController.swift b/AltStore/Components/ForwardingNavigationController.swift new file mode 100644 index 00000000..6af0f806 --- /dev/null +++ b/AltStore/Components/ForwardingNavigationController.swift @@ -0,0 +1,20 @@ +// +// ForwardingNavigationController.swift +// AltStore +// +// Created by Riley Testut on 10/24/19. +// Copyright © 2019 Riley Testut. All rights reserved. +// + +import UIKit + +class ForwardingNavigationController: UINavigationController +{ + override var childForStatusBarStyle: UIViewController? { + return self.topViewController + } + + override var childForStatusBarHidden: UIViewController? { + return self.topViewController + } +} diff --git a/AltStore/Components/NavigationBar.swift b/AltStore/Components/NavigationBar.swift index 890813c1..a57a2599 100644 --- a/AltStore/Components/NavigationBar.swift +++ b/AltStore/Components/NavigationBar.swift @@ -32,19 +32,52 @@ class NavigationBar: UINavigationBar private func initialize() { - self.shadowImage = UIImage() - - if let tintColor = self.barTintColor + if #available(iOS 13, *) { - self.backgroundColorView.backgroundColor = tintColor + let standardAppearance = UINavigationBarAppearance() + standardAppearance.configureWithDefaultBackground() + standardAppearance.shadowColor = nil - // 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)) + let edgeAppearance = UINavigationBarAppearance() + edgeAppearance.configureWithOpaqueBackground() + edgeAppearance.backgroundColor = self.barTintColor + edgeAppearance.shadowColor = nil + + if let tintColor = self.barTintColor + { + let textAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white] + + standardAppearance.backgroundColor = tintColor + standardAppearance.titleTextAttributes = textAttributes + standardAppearance.largeTitleTextAttributes = textAttributes + + edgeAppearance.titleTextAttributes = textAttributes + edgeAppearance.largeTitleTextAttributes = textAttributes + } + else + { + standardAppearance.backgroundColor = nil + } + + self.scrollEdgeAppearance = edgeAppearance + self.standardAppearance = standardAppearance } else { - 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 + } } } diff --git a/AltStore/Components/PillButton.swift b/AltStore/Components/PillButton.swift index e6f464ca..c9483ee8 100644 --- a/AltStore/Components/PillButton.swift +++ b/AltStore/Components/PillButton.swift @@ -11,13 +11,15 @@ import UIKit class PillButton: UIButton { var progress: Progress? { - didSet { + didSet { self.progressView.progress = Float(self.progress?.fractionCompleted ?? 0) self.progressView.observedProgress = self.progress let isUserInteractionEnabled = self.isUserInteractionEnabled self.isIndicatingActivity = (self.progress != nil) self.isUserInteractionEnabled = isUserInteractionEnabled + + self.update() } } @@ -30,12 +32,6 @@ class PillButton: UIButton } } - var isInverted: Bool = false { - didSet { - self.update() - } - } - var countdownDate: Date? { didSet { self.isEnabled = (self.countdownDate == nil) @@ -120,18 +116,18 @@ private extension PillButton { func update() { - if self.isInverted + if self.progress == nil { self.setTitleColor(.white, for: .normal) self.backgroundColor = self.tintColor - self.progressView.progressTintColor = self.tintColor.withAlphaComponent(0.15) } else { self.setTitleColor(self.tintColor, for: .normal) self.backgroundColor = self.tintColor.withAlphaComponent(0.15) - self.progressView.progressTintColor = self.tintColor } + + self.progressView.progressTintColor = self.tintColor } @objc func updateCountdown() diff --git a/AltStore/Info.plist b/AltStore/Info.plist index 05c14cb4..09fb4dd1 100644 --- a/AltStore/Info.plist +++ b/AltStore/Info.plist @@ -120,7 +120,5 @@ - UIUserInterfaceStyle - Light diff --git a/AltStore/My Apps/MyAppsComponents.swift b/AltStore/My Apps/MyAppsComponents.swift index 3733afce..74b2facd 100644 --- a/AltStore/My Apps/MyAppsComponents.swift +++ b/AltStore/My Apps/MyAppsComponents.swift @@ -10,11 +10,18 @@ import UIKit class InstalledAppCollectionViewCell: UICollectionViewCell { - @IBOutlet var appIconImageView: UIImageView! - @IBOutlet var nameLabel: UILabel! - @IBOutlet var developerLabel: UILabel! - @IBOutlet var refreshButton: PillButton! - @IBOutlet var betaBadgeView: UIImageView! + @IBOutlet var bannerView: AppBannerView! + + override func awakeFromNib() + { + super.awakeFromNib() + + self.contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + self.contentView.preservesSuperviewLayoutMargins = true + + self.bannerView.buttonLabel.text = NSLocalizedString("Expires in", comment: "") + self.bannerView.buttonLabel.isHidden = false + } } class InstalledAppsCollectionHeaderView: UICollectionReusableView @@ -23,6 +30,18 @@ class InstalledAppsCollectionHeaderView: UICollectionReusableView @IBOutlet var button: UIButton! } +class NoUpdatesCollectionViewCell: UICollectionViewCell +{ + @IBOutlet var blurView: UIVisualEffectView! + + override func awakeFromNib() + { + super.awakeFromNib() + + self.contentView.preservesSuperviewLayoutMargins = true + } +} + class UpdatesCollectionHeaderView: UICollectionReusableView { let button = PillButton(type: .system) diff --git a/AltStore/My Apps/MyAppsViewController.swift b/AltStore/My Apps/MyAppsViewController.swift index 605efa85..88a92e0c 100644 --- a/AltStore/My Apps/MyAppsViewController.swift +++ b/AltStore/My Apps/MyAppsViewController.swift @@ -74,7 +74,6 @@ class MyAppsViewController: UICollectionViewController self.collectionView.prefetchDataSource = self.dataSource self.prototypeUpdateCell = UpdateCollectionViewCell.instantiate(with: UpdateCollectionViewCell.nib!) - self.prototypeUpdateCell.translatesAutoresizingMaskIntoConstraints = false self.prototypeUpdateCell.contentView.translatesAutoresizingMaskIntoConstraints = false self.collectionView.register(UpdateCollectionViewCell.nib, forCellWithReuseIdentifier: "UpdateCell") @@ -156,9 +155,13 @@ private extension MyAppsViewController dynamicDataSource.numberOfItemsHandler = { _ in self.updatesDataSource.itemCount == 0 ? 1 : 0 } dynamicDataSource.cellIdentifierHandler = { _ in "NoUpdatesCell" } dynamicDataSource.cellConfigurationHandler = { (cell, _, indexPath) in - cell.layer.cornerRadius = 20 - cell.layer.masksToBounds = true - cell.contentView.backgroundColor = UIColor.altPrimary.withAlphaComponent(0.15) + let cell = cell as! NoUpdatesCollectionViewCell + cell.layoutMargins.left = self.view.layoutMargins.left + cell.layoutMargins.right = self.view.layoutMargins.right + + cell.blurView.layer.cornerRadius = 20 + cell.blurView.layer.masksToBounds = true + cell.blurView.backgroundColor = .altPrimary } return dynamicDataSource @@ -179,15 +182,19 @@ private extension MyAppsViewController guard let app = installedApp.storeApp else { return } let cell = cell as! UpdateCollectionViewCell - cell.tintColor = app.tintColor ?? .altPrimary - cell.nameLabel.text = app.name - cell.versionDescriptionTextView.text = app.versionDescription - cell.appIconImageView.image = nil - cell.appIconImageView.isIndicatingActivity = true - cell.betaBadgeView.isHidden = !app.isBeta + cell.layoutMargins.left = self.view.layoutMargins.left + cell.layoutMargins.right = self.view.layoutMargins.right - cell.updateButton.isIndicatingActivity = false - cell.updateButton.addTarget(self, action: #selector(MyAppsViewController.updateApp(_:)), for: .primaryActionTriggered) + cell.tintColor = app.tintColor ?? .altPrimary + cell.versionDescriptionTextView.text = app.versionDescription + + cell.bannerView.titleLabel.text = app.name + cell.bannerView.iconImageView.image = nil + cell.bannerView.iconImageView.isIndicatingActivity = true + cell.bannerView.betaBadgeView.isHidden = !app.isBeta + + cell.bannerView.button.isIndicatingActivity = false + cell.bannerView.button.addTarget(self, action: #selector(MyAppsViewController.updateApp(_:)), for: .primaryActionTriggered) if self.expandedAppUpdates.contains(app.bundleIdentifier) { @@ -201,9 +208,9 @@ private extension MyAppsViewController cell.versionDescriptionTextView.moreButton.addTarget(self, action: #selector(MyAppsViewController.toggleUpdateCellMode(_:)), for: .primaryActionTriggered) let progress = AppManager.shared.installationProgress(for: app) - cell.updateButton.progress = progress + cell.bannerView.button.progress = progress - cell.dateLabel.text = Date().relativeDateString(since: app.versionDate, dateFormatter: self.dateFormatter) + cell.bannerView.subtitleLabel.text = Date().relativeDateString(since: app.versionDate, dateFormatter: self.dateFormatter) cell.setNeedsLayout() } @@ -227,8 +234,8 @@ private extension MyAppsViewController } dataSource.prefetchCompletionHandler = { (cell, image, indexPath, error) in let cell = cell as! UpdateCollectionViewCell - cell.appIconImageView.isIndicatingActivity = false - cell.appIconImageView.image = image + cell.bannerView.iconImageView.isIndicatingActivity = false + cell.bannerView.iconImageView.image = image if let error = error { @@ -254,12 +261,15 @@ private extension MyAppsViewController let tintColor = installedApp.storeApp?.tintColor ?? .altPrimary let cell = cell as! InstalledAppCollectionViewCell + cell.layoutMargins.left = self.view.layoutMargins.left + cell.layoutMargins.right = self.view.layoutMargins.right cell.tintColor = tintColor - cell.appIconImageView.isIndicatingActivity = true - cell.betaBadgeView.isHidden = !(installedApp.storeApp?.isBeta ?? false) - cell.refreshButton.isIndicatingActivity = false - cell.refreshButton.addTarget(self, action: #selector(MyAppsViewController.refreshApp(_:)), for: .primaryActionTriggered) + cell.bannerView.iconImageView.isIndicatingActivity = true + cell.bannerView.betaBadgeView.isHidden = !(installedApp.storeApp?.isBeta ?? false) + + cell.bannerView.button.isIndicatingActivity = false + cell.bannerView.button.addTarget(self, action: #selector(MyAppsViewController.refreshApp(_:)), for: .primaryActionTriggered) let currentDate = Date() @@ -267,34 +277,34 @@ private extension MyAppsViewController if numberOfDays == 1 { - cell.refreshButton.setTitle(NSLocalizedString("1 DAY", comment: ""), for: .normal) + cell.bannerView.button.setTitle(NSLocalizedString("1 DAY", comment: ""), for: .normal) } else { - cell.refreshButton.setTitle(String(format: NSLocalizedString("%@ DAYS", comment: ""), NSNumber(value: numberOfDays)), for: .normal) + cell.bannerView.button.setTitle(String(format: NSLocalizedString("%@ DAYS", comment: ""), NSNumber(value: numberOfDays)), for: .normal) } - cell.nameLabel.text = installedApp.name - cell.developerLabel.text = installedApp.storeApp?.developerName ?? NSLocalizedString("Sideloaded", comment: "") + cell.bannerView.titleLabel.text = installedApp.name + cell.bannerView.subtitleLabel.text = installedApp.storeApp?.developerName ?? NSLocalizedString("Sideloaded", comment: "") // Make sure refresh button is correct size. cell.layoutIfNeeded() switch numberOfDays { - case 2...3: cell.refreshButton.tintColor = .refreshOrange - case 4...5: cell.refreshButton.tintColor = .refreshYellow - case 6...: cell.refreshButton.tintColor = .refreshGreen - default: cell.refreshButton.tintColor = .refreshRed + case 2...3: cell.bannerView.button.tintColor = .refreshOrange + case 4...5: cell.bannerView.button.tintColor = .refreshYellow + case 6...: cell.bannerView.button.tintColor = .refreshGreen + default: cell.bannerView.button.tintColor = .refreshRed } if let refreshGroup = self.refreshGroup, let progress = refreshGroup.progress(for: installedApp), progress.fractionCompleted < 1.0 { - cell.refreshButton.progress = progress + cell.bannerView.button.progress = progress } else { - cell.refreshButton.progress = nil + cell.bannerView.button.progress = nil } } dataSource.prefetchHandler = { (item, indexPath, completion) in @@ -312,8 +322,8 @@ private extension MyAppsViewController } dataSource.prefetchCompletionHandler = { (cell, image, indexPath, error) in let cell = cell as! InstalledAppCollectionViewCell - cell.appIconImageView.image = image - cell.appIconImageView.isIndicatingActivity = false + cell.bannerView.iconImageView.image = image + cell.bannerView.iconImageView.isIndicatingActivity = false } return dataSource @@ -813,14 +823,11 @@ extension MyAppsViewController: UICollectionViewDelegateFlowLayout { func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { - let padding = 30 as CGFloat - let width = collectionView.bounds.width - padding - let section = Section.allCases[indexPath.section] switch section { case .noUpdates: - let size = CGSize(width: width, height: 44) + let size = CGSize(width: collectionView.bounds.width, height: 44) return size case .updates: @@ -831,7 +838,10 @@ extension MyAppsViewController: UICollectionViewDelegateFlowLayout return previousHeight } - let widthConstraint = self.prototypeUpdateCell.contentView.widthAnchor.constraint(equalToConstant: width) + // Manually change cell's width to prevent conflicting with UIView-Encapsulated-Layout-Width constraints. + self.prototypeUpdateCell.frame.size.width = collectionView.bounds.width + + let widthConstraint = self.prototypeUpdateCell.contentView.widthAnchor.constraint(equalToConstant: collectionView.bounds.width) NSLayoutConstraint.activate([widthConstraint]) defer { NSLayoutConstraint.deactivate([widthConstraint]) } @@ -842,7 +852,7 @@ extension MyAppsViewController: UICollectionViewDelegateFlowLayout return size case .installedApps: - return CGSize(width: collectionView.bounds.width, height: 60) + return CGSize(width: collectionView.bounds.width, height: 88) } } @@ -860,20 +870,14 @@ extension MyAppsViewController: UICollectionViewDelegateFlowLayout } } - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets + func collectionView(_ myCV: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { let section = Section.allCases[section] switch section { - case .noUpdates: - guard self.updatesDataSource.itemCount == 0 else { return .zero } - return UIEdgeInsets(top: 12, left: 15, bottom: 20, right: 15) - - case .updates: - guard self.updatesDataSource.itemCount > 0 else { return .zero } - return UIEdgeInsets(top: 12, left: 15, bottom: 20, right: 15) - - case .installedApps: return UIEdgeInsets(top: 12, left: 0, bottom: 20, right: 0) + case .noUpdates where self.updatesDataSource.itemCount != 0: return .zero + case .updates where self.updatesDataSource.itemCount == 0: return .zero + default: return UIEdgeInsets(top: 12, left: 0, bottom: 20, right: 0) } } } diff --git a/AltStore/My Apps/UpdateCollectionViewCell.swift b/AltStore/My Apps/UpdateCollectionViewCell.swift index 04cff8e0..d5a7974e 100644 --- a/AltStore/My Apps/UpdateCollectionViewCell.swift +++ b/AltStore/My Apps/UpdateCollectionViewCell.swift @@ -25,20 +25,25 @@ extension UpdateCollectionViewCell } } - @IBOutlet var appIconImageView: UIImageView! - @IBOutlet var nameLabel: UILabel! - @IBOutlet var dateLabel: UILabel! - @IBOutlet var updateButton: PillButton! + @IBOutlet var bannerView: AppBannerView! @IBOutlet var versionDescriptionTitleLabel: UILabel! @IBOutlet var versionDescriptionTextView: CollapsingTextView! - @IBOutlet var betaBadgeView: UIImageView! + + @IBOutlet private var blurView: UIVisualEffectView! override func awakeFromNib() { super.awakeFromNib() - self.contentView.layer.cornerRadius = 20 - self.contentView.layer.masksToBounds = true + // Prevent temporary unsatisfiable constraint errors due to UIView-Encapsulated-Layout constraints. + self.contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + self.contentView.preservesSuperviewLayoutMargins = true + + self.bannerView.backgroundEffectView.isHidden = true + self.bannerView.button.setTitle(NSLocalizedString("UPDATE", comment: ""), for: .normal) + + self.blurView.layer.cornerRadius = 20 + self.blurView.layer.masksToBounds = true self.update() } @@ -87,11 +92,10 @@ private extension UpdateCollectionViewCell } self.versionDescriptionTitleLabel.textColor = self.tintColor - self.contentView.backgroundColor = self.tintColor.withAlphaComponent(0.1) + self.blurView.backgroundColor = self.tintColor - self.updateButton.setTitleColor(self.tintColor, for: .normal) - self.updateButton.backgroundColor = self.tintColor.withAlphaComponent(0.15) - self.updateButton.progressTintColor = self.tintColor + self.bannerView.button.tintColor = self.tintColor + self.bannerView.button.progressTintColor = self.tintColor self.setNeedsLayout() self.layoutIfNeeded() diff --git a/AltStore/My Apps/UpdateCollectionViewCell.xib b/AltStore/My Apps/UpdateCollectionViewCell.xib index 4b928242..73a2f158 100644 --- a/AltStore/My Apps/UpdateCollectionViewCell.xib +++ b/AltStore/My Apps/UpdateCollectionViewCell.xib @@ -1,130 +1,112 @@ - - - - + + - - + + - - + + - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + - - - - + + - - - - - - + + @@ -132,6 +114,8 @@ - + + + diff --git a/AltStore/News/NewsCollectionViewCell.swift b/AltStore/News/NewsCollectionViewCell.swift index adf9ba18..d9c4b276 100644 --- a/AltStore/News/NewsCollectionViewCell.swift +++ b/AltStore/News/NewsCollectionViewCell.swift @@ -13,13 +13,16 @@ class NewsCollectionViewCell: UICollectionViewCell @IBOutlet var titleLabel: UILabel! @IBOutlet var captionLabel: UILabel! @IBOutlet var imageView: UIImageView! + @IBOutlet var contentBackgroundView: UIView! override func awakeFromNib() { super.awakeFromNib() - self.contentView.layer.cornerRadius = 30 - self.contentView.clipsToBounds = true + self.contentView.preservesSuperviewLayoutMargins = true + + self.contentBackgroundView.layer.cornerRadius = 30 + self.contentBackgroundView.clipsToBounds = true self.imageView.layer.cornerRadius = 30 self.imageView.clipsToBounds = true diff --git a/AltStore/News/NewsCollectionViewCell.xib b/AltStore/News/NewsCollectionViewCell.xib index 0b29532b..42ec35d6 100644 --- a/AltStore/News/NewsCollectionViewCell.xib +++ b/AltStore/News/NewsCollectionViewCell.xib @@ -1,11 +1,9 @@ - - - - + + - + @@ -18,23 +16,26 @@ - - + + + + + - + - + - - + - + @@ -63,15 +64,21 @@ - - + + + + + + + + diff --git a/AltStore/News/NewsViewController.swift b/AltStore/News/NewsViewController.swift index 9e0ca0a3..dfa73fcc 100644 --- a/AltStore/News/NewsViewController.swift +++ b/AltStore/News/NewsViewController.swift @@ -22,8 +22,17 @@ private class AppBannerFooterView: UICollectionReusableView { super.init(frame: frame) - self.addSubview(self.bannerView, pinningEdgesWith: UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20)) self.addGestureRecognizer(self.tapGestureRecognizer) + + self.bannerView.translatesAutoresizingMaskIntoConstraints = false + self.addSubview(self.bannerView) + + NSLayoutConstraint.activate([ + self.bannerView.topAnchor.constraint(equalTo: self.topAnchor), + self.bannerView.bottomAnchor.constraint(equalTo: self.bottomAnchor), + self.bannerView.leadingAnchor.constraint(equalTo: self.layoutMarginsGuide.leadingAnchor), + self.bannerView.trailingAnchor.constraint(equalTo: self.layoutMarginsGuide.trailingAnchor) + ]) } required init?(coder aDecoder: NSCoder) { @@ -52,7 +61,6 @@ class NewsViewController: UICollectionViewController super.viewDidLoad() self.prototypeCell = NewsCollectionViewCell.instantiate(with: NewsCollectionViewCell.nib!) - self.prototypeCell.translatesAutoresizingMaskIntoConstraints = false self.prototypeCell.contentView.translatesAutoresizingMaskIntoConstraints = false self.collectionView.dataSource = self.dataSource @@ -93,15 +101,18 @@ private extension NewsViewController let fetchRequest = NewsItem.fetchRequest() as NSFetchRequest fetchRequest.sortDescriptors = [NSSortDescriptor(keyPath: \NewsItem.sortIndex, ascending: false)] - let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext, sectionNameKeyPath: #keyPath(NewsItem.date), cacheName: nil) + let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext, sectionNameKeyPath: #keyPath(NewsItem.sortIndex), cacheName: nil) let dataSource = RSTFetchedResultsCollectionViewPrefetchingDataSource(fetchedResultsController: fetchedResultsController) dataSource.proxy = self dataSource.cellConfigurationHandler = { (cell, newsItem, indexPath) in let cell = cell as! NewsCollectionViewCell + cell.layoutMargins.left = self.view.layoutMargins.left + cell.layoutMargins.right = self.view.layoutMargins.right + cell.titleLabel.text = newsItem.title cell.captionLabel.text = newsItem.caption - cell.contentView.backgroundColor = newsItem.tintColor + cell.contentBackgroundView.backgroundColor = newsItem.tintColor cell.imageView.image = nil @@ -315,6 +326,9 @@ extension NewsViewController let footerView = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: "AppBanner", for: indexPath) as! AppBannerFooterView guard let storeApp = item.storeApp else { return footerView } + footerView.layoutMargins.left = self.view.layoutMargins.left + footerView.layoutMargins.right = self.view.layoutMargins.right + footerView.bannerView.titleLabel.text = storeApp.name footerView.bannerView.subtitleLabel.text = storeApp.developerName footerView.bannerView.tintColor = storeApp.tintColor @@ -330,7 +344,6 @@ extension NewsViewController let progress = AppManager.shared.installationProgress(for: storeApp) footerView.bannerView.button.progress = progress - footerView.bannerView.button.isInverted = false if Date() < storeApp.versionDate { @@ -345,7 +358,6 @@ extension NewsViewController { footerView.bannerView.button.setTitle(NSLocalizedString("OPEN", comment: ""), for: .normal) footerView.bannerView.button.progress = nil - footerView.bannerView.button.isInverted = true footerView.bannerView.button.countdownDate = nil } @@ -358,10 +370,7 @@ extension NewsViewController extension NewsViewController: UICollectionViewDelegateFlowLayout { func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize - { - let padding = 40 as CGFloat - let width = collectionView.bounds.width - padding - + { let item = self.dataSource.item(at: indexPath) if let previousSize = self.cachedCellSizes[item.identifier] @@ -369,7 +378,7 @@ extension NewsViewController: UICollectionViewDelegateFlowLayout return previousSize } - let widthConstraint = self.prototypeCell.contentView.widthAnchor.constraint(equalToConstant: width) + let widthConstraint = self.prototypeCell.contentView.widthAnchor.constraint(equalToConstant: collectionView.bounds.width) NSLayoutConstraint.activate([widthConstraint]) defer { NSLayoutConstraint.deactivate([widthConstraint]) } @@ -396,7 +405,7 @@ extension NewsViewController: UICollectionViewDelegateFlowLayout func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { - var insets = UIEdgeInsets(top: 30, left: 20, bottom: 13, right: 20) + var insets = UIEdgeInsets(top: 30, left: 0, bottom: 13, right: 0) if section == 0 { diff --git a/AltStore/Resources/Assets.xcassets/Colors/Background.colorset/Contents.json b/AltStore/Resources/Assets.xcassets/Colors/Background.colorset/Contents.json new file mode 100644 index 00000000..1ea0e567 --- /dev/null +++ b/AltStore/Resources/Assets.xcassets/Colors/Background.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + }, + "colors" : [ + { + "idiom" : "universal", + "color" : { + "color-space" : "srgb", + "components" : { + "red" : "1.000", + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000" + } + } + }, + { + "idiom" : "universal", + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "red" : "28", + "alpha" : "1.000", + "blue" : "30", + "green" : "28" + } + } + } + ] +} \ No newline at end of file diff --git a/AltStore/Resources/Assets.xcassets/Colors/BlurTint.colorset/Contents.json b/AltStore/Resources/Assets.xcassets/Colors/BlurTint.colorset/Contents.json new file mode 100644 index 00000000..378c34e1 --- /dev/null +++ b/AltStore/Resources/Assets.xcassets/Colors/BlurTint.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + }, + "colors" : [ + { + "idiom" : "universal", + "color" : { + "color-space" : "srgb", + "components" : { + "red" : "255", + "alpha" : "0.300", + "blue" : "255", + "green" : "255" + } + } + }, + { + "idiom" : "universal", + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "red" : "0", + "alpha" : "0.300", + "blue" : "0", + "green" : "0" + } + } + } + ] +} \ No newline at end of file diff --git a/AltStore/Resources/Assets.xcassets/Colors/SettingsBackground.colorset/Contents.json b/AltStore/Resources/Assets.xcassets/Colors/SettingsBackground.colorset/Contents.json new file mode 100644 index 00000000..ba4b0d05 --- /dev/null +++ b/AltStore/Resources/Assets.xcassets/Colors/SettingsBackground.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + }, + "colors" : [ + { + "idiom" : "universal", + "color" : { + "color-space" : "srgb", + "components" : { + "red" : "1", + "alpha" : "1.000", + "blue" : "132", + "green" : "128" + } + } + }, + { + "idiom" : "universal", + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "red" : "2", + "alpha" : "1.000", + "blue" : "103", + "green" : "82" + } + } + } + ] +} \ No newline at end of file diff --git a/AltStore/Resources/Assets.xcassets/Colors/SettingsHighlighted.colorset/Contents.json b/AltStore/Resources/Assets.xcassets/Colors/SettingsHighlighted.colorset/Contents.json new file mode 100644 index 00000000..14f49d48 --- /dev/null +++ b/AltStore/Resources/Assets.xcassets/Colors/SettingsHighlighted.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + }, + "colors" : [ + { + "idiom" : "universal", + "color" : { + "color-space" : "srgb", + "components" : { + "red" : "0.008", + "alpha" : "1.000", + "blue" : "0.404", + "green" : "0.322" + } + } + }, + { + "idiom" : "universal", + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "red" : "0.004", + "alpha" : "1.000", + "blue" : "0.518", + "green" : "0.502" + } + } + } + ] +} \ No newline at end of file diff --git a/AltStore/Settings/AboutPatreonHeaderView.xib b/AltStore/Settings/AboutPatreonHeaderView.xib index 09227294..8ed7b0cf 100644 --- a/AltStore/Settings/AboutPatreonHeaderView.xib +++ b/AltStore/Settings/AboutPatreonHeaderView.xib @@ -1,11 +1,9 @@ - - - - + + - + @@ -74,24 +72,24 @@ Riley @@ -111,12 +109,13 @@ Riley + - - - + + + diff --git a/AltStore/Settings/LicensesViewController.swift b/AltStore/Settings/LicensesViewController.swift index 748343c3..66b50736 100644 --- a/AltStore/Settings/LicensesViewController.swift +++ b/AltStore/Settings/LicensesViewController.swift @@ -14,6 +14,10 @@ class LicensesViewController: UIViewController @IBOutlet private var textView: UITextView! + override var preferredStatusBarStyle: UIStatusBarStyle { + return .lightContent + } + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) diff --git a/AltStore/Settings/PatreonViewController.swift b/AltStore/Settings/PatreonViewController.swift index 827a77dd..ffb105f4 100644 --- a/AltStore/Settings/PatreonViewController.swift +++ b/AltStore/Settings/PatreonViewController.swift @@ -30,6 +30,10 @@ class PatreonViewController: UICollectionViewController private var patronsResult: Result<[Patron], Error>? + override var preferredStatusBarStyle: UIStatusBarStyle { + return .lightContent + } + override func viewDidLoad() { super.viewDidLoad() diff --git a/AltStore/Settings/Settings.storyboard b/AltStore/Settings/Settings.storyboard index a9413989..1d47289d 100644 --- a/AltStore/Settings/Settings.storyboard +++ b/AltStore/Settings/Settings.storyboard @@ -1,11 +1,9 @@ - - - - + + - + @@ -18,14 +16,14 @@ - + - + @@ -55,7 +53,7 @@ - + @@ -87,7 +85,7 @@ - + @@ -119,7 +117,7 @@ - + @@ -155,7 +153,7 @@ - + @@ -195,7 +193,7 @@ - + @@ -235,7 +233,7 @@ - + @@ -275,20 +273,20 @@ - + - + - + - + - + - + - + - +