Displays remaining App ID count

This commit is contained in:
Riley Testut
2020-01-24 14:54:52 -08:00
parent b196981c89
commit 74f44ddfe8
4 changed files with 110 additions and 5 deletions

View File

@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15400" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="wKh-xq-NuP">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15705" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="wKh-xq-NuP">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15404"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15706"/>
<capability name="Named colors" minToolsVersion="9.0"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@@ -629,7 +629,7 @@ World</string>
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="15" minimumInteritemSpacing="10" id="SB5-U0-jyy">
<size key="itemSize" width="375" height="60"/>
<size key="headerReferenceSize" width="50" height="50"/>
<size key="footerReferenceSize" width="0.0" height="0.0"/>
<size key="footerReferenceSize" width="50" height="50"/>
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
</collectionViewFlowLayout>
<cells>
@@ -750,6 +750,39 @@ World</string>
<outlet property="textLabel" destination="BDU-hM-rro" id="CQM-8K-bcH"/>
</connections>
</collectionReusableView>
<collectionReusableView key="sectionFooterView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" reuseIdentifier="InstalledAppsFooter" id="HYs-co-nJZ" customClass="InstalledAppsCollectionFooterView" customModule="AltStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="185" width="375" height="50"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="5/10 App IDs" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="LLv-8I-6Of">
<rect key="frame" x="138.5" y="0.0" width="98" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="NHb-0F-cHZ">
<rect key="frame" x="241.5" y="-0.5" width="22" height="22"/>
<constraints>
<constraint firstAttribute="width" constant="22" id="K1V-bV-Mjg"/>
<constraint firstAttribute="height" constant="22" id="vW1-aN-slG"/>
</constraints>
<state key="normal" image="questionmark.circle" catalog="system"/>
<connections>
<action selector="presentAppIDHelpAlert:" destination="hv7-Ar-voT" eventType="touchUpInside" id="m2N-Lx-adY"/>
</connections>
</button>
</subviews>
<constraints>
<constraint firstItem="NHb-0F-cHZ" firstAttribute="leading" secondItem="LLv-8I-6Of" secondAttribute="trailing" constant="5" id="Fpk-zD-6AK"/>
<constraint firstItem="LLv-8I-6Of" firstAttribute="top" secondItem="HYs-co-nJZ" secondAttribute="top" id="UVG-MJ-SPb"/>
<constraint firstItem="LLv-8I-6Of" firstAttribute="centerX" secondItem="HYs-co-nJZ" secondAttribute="centerX" id="Wc0-ul-McA"/>
<constraint firstItem="NHb-0F-cHZ" firstAttribute="centerY" secondItem="LLv-8I-6Of" secondAttribute="centerY" id="wSf-Lv-NC0"/>
</constraints>
<connections>
<outlet property="button" destination="NHb-0F-cHZ" id="wOh-Ee-jhN"/>
<outlet property="textLabel" destination="LLv-8I-6Of" id="t2D-f1-5pC"/>
</connections>
</collectionReusableView>
<connections>
<outlet property="dataSource" destination="hv7-Ar-voT" id="YOx-f4-chF"/>
<outlet property="delegate" destination="hv7-Ar-voT" id="1PN-pf-cZK"/>
@@ -797,6 +830,7 @@ World</string>
<image name="MyApps" width="20" height="20"/>
<image name="News" width="19" height="20"/>
<image name="Settings" width="20" height="20"/>
<image name="questionmark.circle" catalog="system" width="64" height="60"/>
<namedColor name="Background">
<color red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>

View File

@@ -30,6 +30,12 @@ class InstalledAppsCollectionHeaderView: UICollectionReusableView
@IBOutlet var button: UIButton!
}
class InstalledAppsCollectionFooterView: UICollectionReusableView
{
@IBOutlet var textLabel: UILabel!
@IBOutlet var button: UIButton!
}
class NoUpdatesCollectionViewCell: UICollectionViewCell
{
@IBOutlet var blurView: UIVisualEffectView!

View File

@@ -615,7 +615,7 @@ private extension MyAppsViewController
func presentSideloadingAlert(completion: @escaping (Bool) -> Void)
{
let alertController = UIAlertController(title: NSLocalizedString("Sideload Apps (Beta)", comment: ""), message: NSLocalizedString("You may only install 10 apps + app extensions per week due to Apple's restrictions.\n\nIf you encounter an app that is not able to be sideloaded, please report the app to support@altstore.io.", comment: ""), preferredStyle: .alert)
let alertController = UIAlertController(title: NSLocalizedString("Sideload Apps (Beta)", comment: ""), message: NSLocalizedString("If you encounter an app that is not able to be sideloaded, please report the app to support@altstore.io.", comment: ""), preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: RSTSystemLocalizedString("OK"), style: .default, handler: { (action) in
completion(true)
}))
@@ -700,6 +700,19 @@ private extension MyAppsViewController
self.present(alertController, animated: true, completion: nil)
}
@IBAction func presentAppIDHelpAlert(_ sender: UIButton)
{
let message = NSLocalizedString("""
Each app and app extension installed with AltStore must register an App ID with Apple. Apple limits free developer accounts to 10 App IDs at a time.
App IDs expire after one week, but AltStore will automatically renew them for all installed apps. Once an App ID expires, it no longer counts toward your total.
""", comment: "")
let alertController = UIAlertController(title: NSLocalizedString("What are App IDs?", comment: ""), message: message, preferredStyle: .alert)
alertController.addAction(.ok)
self.present(alertController, animated: true, completion: nil)
}
}
private extension MyAppsViewController
@@ -805,7 +818,7 @@ extension MyAppsViewController
return headerView
case .installedApps:
case .installedApps where kind == UICollectionView.elementKindSectionHeader:
let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "InstalledAppsHeader", for: indexPath) as! InstalledAppsCollectionHeaderView
UIView.performWithoutAnimation {
@@ -821,6 +834,29 @@ extension MyAppsViewController
}
return headerView
case .installedApps:
let installedApps = self.installedAppsDataSource.fetchedResultsController.fetchedObjects ?? []
let registeredAppIDs = installedApps.filter { $0.team?.isActiveTeam ?? false }.reduce(0) { (sum, installedApp) in
// Each InstallApp has it's own app ID, plus one for each app extension.
return sum + 1 + installedApp.appExtensions.count
}
let maximumAppIDCount = 10
let remainingAppIDs = max(maximumAppIDCount - registeredAppIDs, 0)
let footerView = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: "InstalledAppsFooter", for: indexPath) as! InstalledAppsCollectionFooterView
if remainingAppIDs == 1
{
footerView.textLabel.text = String(format: NSLocalizedString("1 App ID Remaining", comment: ""))
}
else
{
footerView.textLabel.text = String(format: NSLocalizedString("%@ App IDs Remaining", comment: ""), NSNumber(value: remainingAppIDs))
}
return footerView
}
}
@@ -889,6 +925,29 @@ extension MyAppsViewController: UICollectionViewDelegateFlowLayout
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize
{
let section = Section.allCases[section]
switch section
{
case .noUpdates: return .zero
case .updates: return .zero
case .installedApps:
#if BETA
if let team = DatabaseManager.shared.activeTeam(), team.type == .free
{
return CGSize(width: collectionView.bounds.width, height: 44)
}
else
{
return .zero
}
#else
return .zero
#endif
}
}
func collectionView(_ myCV: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets
{
let section = Section.allCases[section]

View File

@@ -164,6 +164,12 @@ class AuthenticationOperation: ResultOperation<(ALTSigner, ALTAppleAPISession)>
team.isActiveTeam = false
}
if let altStoreApp = InstalledApp.fetchAltStore(in: context), altStoreApp.team == nil
{
// No team assigned to AltStore app yet, so assume this team was used to originally install it.
altStoreApp.team = team
}
// Save
try context.save()