diff --git a/AltStore/Base.lproj/Main.storyboard b/AltStore/Base.lproj/Main.storyboard
index c768a3b0..8e392304 100644
--- a/AltStore/Base.lproj/Main.storyboard
+++ b/AltStore/Base.lproj/Main.storyboard
@@ -685,104 +685,94 @@ World
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
-
-
-
-
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
@@ -830,7 +820,7 @@ World
-
+
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..ad55a4aa 100644
--- a/AltStore/Components/AppBannerView.xib
+++ b/AltStore/Components/AppBannerView.xib
@@ -1,21 +1,22 @@
-
-
-
-
+
+
-
+
+
+
+
@@ -23,6 +24,15 @@
+
+
+
+
+
+
+
+
+
@@ -34,51 +44,91 @@
-
+
-
-
+
+
-
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
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/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..b2bc0616 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,16 @@ 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.isInverted = true
+ cell.bannerView.button.isIndicatingActivity = false
+ cell.bannerView.button.addTarget(self, action: #selector(MyAppsViewController.refreshApp(_:)), for: .primaryActionTriggered)
let currentDate = Date()
@@ -267,34 +278,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 +323,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 +824,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 +839,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 +853,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 +871,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..5dbe41c1 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,11 @@ 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.isInverted = true
+ 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..a35dd0a7 100644
--- a/AltStore/My Apps/UpdateCollectionViewCell.xib
+++ b/AltStore/My Apps/UpdateCollectionViewCell.xib
@@ -1,113 +1,81 @@
-
-
-
-
+
+
-
-
+
-
-
+
+
-
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
-
@@ -115,23 +83,16 @@
-
-
+
+
-
-
-
-
-
-
+
+
-
-
-