Adds basic AppDetailViewController implementation

This commit is contained in:
Riley Testut
2019-05-09 17:21:55 -07:00
parent f4a3a09cba
commit 41310a852f
16 changed files with 462 additions and 0 deletions

View File

@@ -20,6 +20,7 @@
BFD247932284D4B700981D42 /* AppTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFD247922284D4B700981D42 /* AppTableViewCell.swift */; };
BFD247952284D7BD00981D42 /* Apps.plist in Resources */ = {isa = PBXBuildFile; fileRef = BFD247942284D7BD00981D42 /* Apps.plist */; };
BFD2479A2284D80900981D42 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFD247992284D80900981D42 /* App.swift */; };
BFD2479C2284E19A00981D42 /* AppDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFD2479B2284E19A00981D42 /* AppDetailViewController.swift */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -51,6 +52,7 @@
BFD247922284D4B700981D42 /* AppTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppTableViewCell.swift; sourceTree = "<group>"; };
BFD247942284D7BD00981D42 /* Apps.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Apps.plist; sourceTree = "<group>"; };
BFD247992284D80900981D42 /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = "<group>"; };
BFD2479B2284E19A00981D42 /* AppDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDetailViewController.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -110,6 +112,7 @@
children = (
BFD2476F2284B9A500981D42 /* AppsViewController.swift */,
BFD247922284D4B700981D42 /* AppTableViewCell.swift */,
BFD2479B2284E19A00981D42 /* AppDetailViewController.swift */,
);
path = Apps;
sourceTree = "<group>";
@@ -225,6 +228,7 @@
BFD2478F2284C8F900981D42 /* Button.swift in Sources */,
BFD247722284B9A500981D42 /* SecondViewController.swift in Sources */,
BFD2478C2284C4C300981D42 /* AppIconImageView.swift in Sources */,
BFD2479C2284E19A00981D42 /* AppDetailViewController.swift in Sources */,
BFD2476E2284B9A500981D42 /* AppDelegate.swift in Sources */,
BFD247702284B9A500981D42 /* AppsViewController.swift in Sources */,
BFD2479A2284D80900981D42 /* App.swift in Sources */,

View File

@@ -0,0 +1,110 @@
//
// AppDetailViewController.swift
// AltStore
//
// Created by Riley Testut on 5/9/19.
// Copyright © 2019 Riley Testut. All rights reserved.
//
import UIKit
import Roxas
@objc(ScreenshotCollectionViewCell)
private class ScreenshotCollectionViewCell: UICollectionViewCell
{
@IBOutlet var imageView: UIImageView!
}
extension AppDetailViewController
{
private enum Row: Int
{
case general
case screenshots
case description
}
}
class AppDetailViewController: UITableViewController
{
var app: App!
private lazy var screenshotsDataSource = self.makeScreenshotsDataSource()
@IBOutlet private var nameLabel: UILabel!
@IBOutlet private var subtitleLabel: UILabel!
@IBOutlet private var developerButton: UIButton!
@IBOutlet private var appIconImageView: UIImageView!
@IBOutlet private var downloadButton: UIButton!
@IBOutlet private var screenshotsCollectionView: UICollectionView!
@IBOutlet private var descriptionLabel: UILabel!
override func viewDidLoad()
{
super.viewDidLoad()
self.tableView.delegate = self
self.screenshotsCollectionView.dataSource = self.screenshotsDataSource
self.update()
}
override func viewDidLayoutSubviews()
{
super.viewDidLayoutSubviews()
guard let image = self.screenshotsDataSource.items.first else { return }
let aspectRatio = image.size.width / image.size.height
let height = self.screenshotsCollectionView.bounds.height
let width = self.screenshotsCollectionView.bounds.height * aspectRatio
let layout = self.screenshotsCollectionView.collectionViewLayout as! UICollectionViewFlowLayout
layout.itemSize = CGSize(width: width, height: height)
}
}
private extension AppDetailViewController
{
func update()
{
self.nameLabel.text = self.app.name
self.subtitleLabel.text = self.app.subtitle
self.developerButton.setTitle(self.app.developer, for: .normal)
self.appIconImageView.image = UIImage(named: self.app.iconName)
let text = String(format: NSLocalizedString("Download %@", comment: ""), self.app.name)
self.downloadButton.setTitle(text, for: .normal)
self.descriptionLabel.text = self.app.localizedDescription
}
func makeScreenshotsDataSource() -> RSTArrayCollectionViewDataSource<UIImage>
{
let screenshots = self.app.screenshotNames.compactMap(UIImage.init(named:))
let dataSource = RSTArrayCollectionViewDataSource(items: screenshots)
dataSource.cellConfigurationHandler = { (cell, screenshot, indexPath) in
let cell = cell as! ScreenshotCollectionViewCell
cell.imageView.image = screenshot
}
return dataSource
}
}
extension AppDetailViewController
{
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
guard indexPath.row == Row.screenshots.rawValue else { return super.tableView(tableView, heightForRowAt: indexPath) }
guard !self.screenshotsDataSource.items.isEmpty else { return 0.0 }
let height = self.view.bounds.height * 0.67
return height
}
}

View File

@@ -22,6 +22,18 @@ class AppsViewController: UITableViewController
// Hide trailing row separators.
self.tableView.tableFooterView = UIView()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
guard segue.identifier == "showAppDetail" else { return }
guard let cell = sender as? UITableViewCell, let indexPath = self.tableView.indexPath(for: cell) else { return }
let app = self.dataSource.item(at: indexPath)
let appDetailViewController = segue.destination as! AppDetailViewController
appDetailViewController.app = app
}
}
private extension AppsViewController

View File

@@ -114,6 +114,9 @@
</stackView>
<button opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="1000" verticalCompressionResistancePriority="1000" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="ScM-Z2-rAe" customClass="Button" customModule="AltStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="57.5" width="72" height="30"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="71g-sg-TqR"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="15"/>
<color key="tintColor" red="0.0" green="0.47843137250000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<state key="normal" title="Download"/>
@@ -143,6 +146,10 @@
<outlet property="button" destination="ScM-Z2-rAe" id="VnW-vG-JCc"/>
<outlet property="nameLabel" destination="d4v-IK-LuC" id="wFw-Js-PXE"/>
<outlet property="subtitleLabel" destination="xnf-XX-iX9" id="CYk-ud-YHz"/>
<segue destination="hR3-go-2DG" kind="show" identifier="showAppDetail" id="F38-66-skN">
<segue key="commit" inheritsFrom="parent" id="K6B-kg-jJz"/>
<segue key="preview" inheritsFrom="commit" id="sJk-KX-3sw"/>
</segue>
</connections>
</tableViewCell>
</prototypes>
@@ -157,6 +164,207 @@
</objects>
<point key="canvasLocation" x="1519" y="-319"/>
</scene>
<!--App Detail View Controller-->
<scene sceneID="XfG-lM-QRu">
<objects>
<tableViewController id="hR3-go-2DG" customClass="AppDetailViewController" customModule="AltStore" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" id="YzM-8a-RIS">
<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"/>
<sections>
<tableViewSection id="0FU-lm-58W">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" rowHeight="185" id="hHN-iH-vV1">
<rect key="frame" x="0.0" y="0.0" width="375" height="185"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="hHN-iH-vV1" id="iVa-h4-KoK">
<rect key="frame" x="0.0" y="0.0" width="375" height="184.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="6L4-Bb-DUF">
<rect key="frame" x="16" y="11" width="343" height="163"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" alignment="top" spacing="15" translatesAutoresizingMaskIntoConstraints="NO" id="uQy-Sy-Cgx">
<rect key="frame" x="0.0" y="0.0" width="343" height="129"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="DeltaIcon" translatesAutoresizingMaskIntoConstraints="NO" id="PVH-lp-hGl" customClass="AppIconImageView" customModule="AltStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="110" height="110"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="110" id="2sr-xS-Nyd"/>
<constraint firstAttribute="width" constant="110" id="HwO-7w-7K9"/>
</constraints>
</imageView>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="top" spacing="4" translatesAutoresizingMaskIntoConstraints="NO" id="F4R-0I-ucL">
<rect key="frame" x="125" y="0.0" width="218" height="68"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="1000" text="Name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="O5s-oz-KYW">
<rect key="frame" x="0.0" y="0.0" width="55" height="24"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="20"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="1000" text="Subtitle" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ozE-C3-F1B">
<rect key="frame" x="0.0" y="28" width="53" height="18"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<color key="textColor" white="0.5" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="rMJ-KT-YRw">
<rect key="frame" x="0.0" y="50" width="70" height="18"/>
<constraints>
<constraint firstAttribute="height" constant="18" id="2hT-PA-EjP"/>
</constraints>
<state key="normal" title="Developer"/>
</button>
</subviews>
</stackView>
</subviews>
</stackView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="i1B-Mu-s1h" customClass="Button" customModule="AltStore" customModuleProvider="target">
<rect key="frame" x="0.0" y="129" width="343" height="34"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="18"/>
<state key="normal" title="Download"/>
</button>
</subviews>
</stackView>
</subviews>
<constraints>
<constraint firstAttribute="trailingMargin" secondItem="6L4-Bb-DUF" secondAttribute="trailing" id="99m-HR-lHd"/>
<constraint firstItem="6L4-Bb-DUF" firstAttribute="leading" secondItem="iVa-h4-KoK" secondAttribute="leadingMargin" id="SGU-Gl-foG"/>
<constraint firstItem="6L4-Bb-DUF" firstAttribute="top" secondItem="iVa-h4-KoK" secondAttribute="topMargin" id="edE-G4-bkR"/>
<constraint firstAttribute="bottomMargin" secondItem="6L4-Bb-DUF" secondAttribute="bottom" id="uo9-J8-mW7"/>
</constraints>
</tableViewCellContentView>
<inset key="separatorInset" minX="15" minY="0.0" maxX="15" maxY="0.0"/>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" rowHeight="300" id="eY1-pC-LnW">
<rect key="frame" x="0.0" y="185" width="375" height="300"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="eY1-pC-LnW" id="fNc-tm-ceI">
<rect key="frame" x="0.0" y="0.0" width="375" height="299.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="center" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="NVu-cR-q8f">
<rect key="frame" x="0.0" y="0.0" width="375" height="299.5"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Screenshots" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="e2p-gM-mn5">
<rect key="frame" x="15" y="8" width="345" height="26.5"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="22"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="UJY-8X-bkB">
<rect key="frame" x="0.0" y="42.5" width="375" height="249"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<collectionViewFlowLayout key="collectionViewLayout" scrollDirection="horizontal" minimumLineSpacing="10" minimumInteritemSpacing="15" id="9OB-OD-w1I">
<size key="itemSize" width="138" height="253"/>
<size key="headerReferenceSize" width="0.0" height="0.0"/>
<size key="footerReferenceSize" width="0.0" height="0.0"/>
<inset key="sectionInset" minX="15" minY="0.0" maxX="15" maxY="0.0"/>
</collectionViewFlowLayout>
<cells>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="Cell" id="gbq-ih-dcI" customClass="ScreenshotCollectionViewCell">
<rect key="frame" x="15" y="-2" width="138" height="253"/>
<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="138" height="253"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="OCS-uW-Big">
<rect key="frame" x="0.0" y="0.0" width="138" height="300"/>
</imageView>
</subviews>
</view>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="OCS-uW-Big" firstAttribute="leading" secondItem="gbq-ih-dcI" secondAttribute="leading" id="88o-MG-3Eh"/>
<constraint firstItem="OCS-uW-Big" firstAttribute="top" secondItem="gbq-ih-dcI" secondAttribute="top" id="IcM-V4-RJ9"/>
<constraint firstAttribute="bottom" secondItem="OCS-uW-Big" secondAttribute="bottom" id="KNE-HI-Cpo"/>
<constraint firstAttribute="trailing" secondItem="OCS-uW-Big" secondAttribute="trailing" id="O73-Hi-RLf"/>
</constraints>
<connections>
<outlet property="imageView" destination="OCS-uW-Big" id="JYM-5w-apx"/>
</connections>
</collectionViewCell>
</cells>
</collectionView>
</subviews>
<constraints>
<constraint firstItem="UJY-8X-bkB" firstAttribute="width" secondItem="NVu-cR-q8f" secondAttribute="width" id="6ud-t2-rUG"/>
<constraint firstItem="e2p-gM-mn5" firstAttribute="leading" secondItem="NVu-cR-q8f" secondAttribute="leading" constant="15" id="7jL-kY-kwT"/>
</constraints>
<edgeInsets key="layoutMargins" top="8" left="0.0" bottom="8" right="0.0"/>
</stackView>
</subviews>
<constraints>
<constraint firstItem="NVu-cR-q8f" firstAttribute="leading" secondItem="fNc-tm-ceI" secondAttribute="leading" id="Kh3-a8-SAF"/>
<constraint firstItem="NVu-cR-q8f" firstAttribute="top" secondItem="fNc-tm-ceI" secondAttribute="top" id="OFv-zk-q24"/>
<constraint firstAttribute="trailing" secondItem="NVu-cR-q8f" secondAttribute="trailing" id="VEh-Lz-rhi"/>
<constraint firstAttribute="bottom" secondItem="NVu-cR-q8f" secondAttribute="bottom" id="beN-L9-6hC"/>
</constraints>
</tableViewCellContentView>
<inset key="separatorInset" minX="15" minY="0.0" maxX="15" maxY="0.0"/>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" id="Fng-Dg-Pak">
<rect key="frame" x="0.0" y="485" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="Fng-Dg-Pak" id="Dgq-ek-1h0">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" alignment="top" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="O4U-vh-Xtu">
<rect key="frame" x="0.0" y="0.0" width="375" height="43.5"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="Description" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1ri-OV-tIy">
<rect key="frame" x="15" y="8" width="116" height="19.5"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="22"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="g65-MO-uaH">
<rect key="frame" x="15" y="35.5" width="37.5" height="0.0"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleSubhead"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<edgeInsets key="layoutMargins" top="8" left="15" bottom="8" right="15"/>
</stackView>
</subviews>
<constraints>
<constraint firstItem="O4U-vh-Xtu" firstAttribute="top" secondItem="Dgq-ek-1h0" secondAttribute="top" id="5Se-DK-wSx"/>
<constraint firstAttribute="trailing" secondItem="O4U-vh-Xtu" secondAttribute="trailing" id="6fA-iC-Xql"/>
<constraint firstAttribute="bottom" secondItem="O4U-vh-Xtu" secondAttribute="bottom" id="MM3-Bf-YYK"/>
<constraint firstItem="O4U-vh-Xtu" firstAttribute="leading" secondItem="Dgq-ek-1h0" secondAttribute="leading" id="cDm-2j-B88"/>
</constraints>
</tableViewCellContentView>
<inset key="separatorInset" minX="1000" minY="0.0" maxX="0.0" maxY="0.0"/>
</tableViewCell>
</cells>
</tableViewSection>
</sections>
<connections>
<outlet property="dataSource" destination="hR3-go-2DG" id="HfZ-io-Qfb"/>
<outlet property="delegate" destination="hR3-go-2DG" id="Kce-sW-Xkm"/>
</connections>
</tableView>
<navigationItem key="navigationItem" largeTitleDisplayMode="never" id="M65-jg-bg9"/>
<connections>
<outlet property="appIconImageView" destination="PVH-lp-hGl" id="doE-lb-hMq"/>
<outlet property="descriptionLabel" destination="g65-MO-uaH" id="fod-v0-B4v"/>
<outlet property="developerButton" destination="rMJ-KT-YRw" id="7IH-1I-P8d"/>
<outlet property="downloadButton" destination="i1B-Mu-s1h" id="xbF-fk-xF8"/>
<outlet property="nameLabel" destination="O5s-oz-KYW" id="seg-JJ-VfB"/>
<outlet property="screenshotsCollectionView" destination="UJY-8X-bkB" id="6CI-Jg-yt6"/>
<outlet property="subtitleLabel" destination="ozE-C3-F1B" id="daJ-dx-5se"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="BLa-Qn-j83" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2308" y="-319.79010494752629"/>
</scene>
<!--Apps-->
<scene sceneID="YAm-Ca-4vd">
<objects>
@@ -178,7 +386,11 @@
</scene>
</scenes>
<resources>
<image name="DeltaIcon" width="512" height="512"/>
<image name="first" width="30" height="30"/>
<image name="second" width="30" height="30"/>
</resources>
<inferredMetricsTieBreakers>
<segue reference="F38-66-skN"/>
</inferredMetricsTieBreakers>
</document>

View File

@@ -13,6 +13,7 @@ class Button: UIButton
override var intrinsicContentSize: CGSize {
var size = super.intrinsicContentSize
size.width += 20
size.height += 10
return size
}

View File

@@ -12,6 +12,10 @@ class App: NSObject, Codable
{
var name: String
var subtitle: String
var developer: String
var localizedDescription: String
var iconName: String
var screenshotNames: [String]
}

View File

@@ -7,16 +7,45 @@
<string>Delta</string>
<key>subtitle</key>
<string>All-in-one Nintendo emulator</string>
<key>localizedDescription</key>
<string>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Sed enim ut sem viverra aliquet eget sit amet. Viverra mauris in aliquam sem fringilla ut. Egestas erat imperdiet sed euismod nisi porta. Sit amet dictum sit amet justo donec enim diam vulputate. Phasellus vestibulum lorem sed risus ultricies tristique nulla. Elit pellentesque habitant morbi tristique. Ut lectus arcu bibendum at. Ullamcorper a lacus vestibulum sed. Mi tempus imperdiet nulla malesuada pellentesque elit eget gravida. Nec feugiat nisl pretium fusce id velit ut. Amet nulla facilisi morbi tempus. Ut sem nulla pharetra diam sit amet nisl.
Tortor at auctor urna nunc id cursus metus. Commodo ullamcorper a lacus vestibulum sed arcu non odio. Faucibus turpis in eu mi bibendum neque egestas. Auctor augue mauris augue neque gravida in fermentum et sollicitudin. Aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus. Placerat in egestas erat imperdiet sed euismod nisi. Aliquam id diam maecenas ultricies mi eget mauris. Nunc faucibus a pellentesque sit amet porttitor eget dolor. Sed faucibus turpis in eu mi. Tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed. Id semper risus in hendrerit gravida rutrum quisque. At lectus urna duis convallis convallis. Egestas maecenas pharetra convallis posuere. Id velit ut tortor pretium viverra. Quam pellentesque nec nam aliquam sem et tortor consequat. Risus pretium quam vulputate dignissim. Urna nec tincidunt praesent semper feugiat nibh sed pulvinar.
Tempor orci eu lobortis elementum nibh tellus. Mattis rhoncus urna neque viverra justo nec. Maecenas pharetra convallis posuere morbi leo. Rhoncus mattis rhoncus urna neque viverra justo nec. Gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim. At imperdiet dui accumsan sit amet. Elit sed vulputate mi sit amet mauris commodo. Pellentesque habitant morbi tristique senectus. Tortor id aliquet lectus proin nibh. Magna etiam tempor orci eu lobortis elementum. Est pellentesque elit ullamcorper dignissim. Dapibus ultrices in iaculis nunc. Commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula. Diam vel quam elementum pulvinar. Vel turpis nunc eget lorem dolor sed viverra. Tortor pretium viverra suspendisse potenti nullam ac tortor vitae. Euismod nisi porta lorem mollis. Massa id neque aliquam vestibulum morbi blandit.
Massa massa ultricies mi quis hendrerit dolor magna eget est. Augue interdum velit euismod in pellentesque massa. Sed risus ultricies tristique nulla aliquet enim. Risus viverra adipiscing at in tellus. Donec adipiscing tristique risus nec feugiat. Eget sit amet tellus cras adipiscing enim eu turpis. Auctor neque vitae tempus quam pellentesque nec. Sit amet tellus cras adipiscing enim eu turpis egestas. Dui faucibus in ornare quam viverra. Fermentum iaculis eu non diam phasellus vestibulum lorem. Odio ut enim blandit volutpat maecenas. Dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique. Pellentesque diam volutpat commodo sed egestas egestas. Aliquam purus sit amet luctus venenatis lectus magna fringilla. Viverra mauris in aliquam sem fringilla ut morbi tincidunt. Elit duis tristique sollicitudin nibh sit. Fermentum dui faucibus in ornare quam viverra orci sagittis. Aliquet eget sit amet tellus cras adipiscing.</string>
<key>developer</key>
<string>Riley Testut</string>
<key>iconName</key>
<string>DeltaIcon</string>
<key>screenshotNames</key>
<array>
<string>Delta1</string>
<string>Delta2</string>
<string>Delta3</string>
<string>Delta4</string>
</array>
</dict>
<dict>
<key>name</key>
<string>Clipboard Manager</string>
<key>subtitle</key>
<string>Simple but powerful clipboard manager</string>
<key>localizedDescription</key>
<string>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Sed enim ut sem viverra aliquet eget sit amet. Viverra mauris in aliquam sem fringilla ut. Egestas erat imperdiet sed euismod nisi porta. Sit amet dictum sit amet justo donec enim diam vulputate. Phasellus vestibulum lorem sed risus ultricies tristique nulla. Elit pellentesque habitant morbi tristique. Ut lectus arcu bibendum at. Ullamcorper a lacus vestibulum sed. Mi tempus imperdiet nulla malesuada pellentesque elit eget gravida. Nec feugiat nisl pretium fusce id velit ut. Amet nulla facilisi morbi tempus. Ut sem nulla pharetra diam sit amet nisl.
Tortor at auctor urna nunc id cursus metus. Commodo ullamcorper a lacus vestibulum sed arcu non odio. Faucibus turpis in eu mi bibendum neque egestas. Auctor augue mauris augue neque gravida in fermentum et sollicitudin. Aliquam vestibulum morbi blandit cursus risus at ultrices mi tempus. Placerat in egestas erat imperdiet sed euismod nisi. Aliquam id diam maecenas ultricies mi eget mauris. Nunc faucibus a pellentesque sit amet porttitor eget dolor. Sed faucibus turpis in eu mi. Tortor vitae purus faucibus ornare suspendisse sed nisi lacus sed. Id semper risus in hendrerit gravida rutrum quisque. At lectus urna duis convallis convallis. Egestas maecenas pharetra convallis posuere. Id velit ut tortor pretium viverra. Quam pellentesque nec nam aliquam sem et tortor consequat. Risus pretium quam vulputate dignissim. Urna nec tincidunt praesent semper feugiat nibh sed pulvinar.
Tempor orci eu lobortis elementum nibh tellus. Mattis rhoncus urna neque viverra justo nec. Maecenas pharetra convallis posuere morbi leo. Rhoncus mattis rhoncus urna neque viverra justo nec. Gravida dictum fusce ut placerat orci nulla pellentesque dignissim enim. At imperdiet dui accumsan sit amet. Elit sed vulputate mi sit amet mauris commodo. Pellentesque habitant morbi tristique senectus. Tortor id aliquet lectus proin nibh. Magna etiam tempor orci eu lobortis elementum. Est pellentesque elit ullamcorper dignissim. Dapibus ultrices in iaculis nunc. Commodo quis imperdiet massa tincidunt nunc pulvinar sapien et ligula. Diam vel quam elementum pulvinar. Vel turpis nunc eget lorem dolor sed viverra. Tortor pretium viverra suspendisse potenti nullam ac tortor vitae. Euismod nisi porta lorem mollis. Massa id neque aliquam vestibulum morbi blandit.
Massa massa ultricies mi quis hendrerit dolor magna eget est. Augue interdum velit euismod in pellentesque massa. Sed risus ultricies tristique nulla aliquet enim. Risus viverra adipiscing at in tellus. Donec adipiscing tristique risus nec feugiat. Eget sit amet tellus cras adipiscing enim eu turpis. Auctor neque vitae tempus quam pellentesque nec. Sit amet tellus cras adipiscing enim eu turpis egestas. Dui faucibus in ornare quam viverra. Fermentum iaculis eu non diam phasellus vestibulum lorem. Odio ut enim blandit volutpat maecenas. Dolor sit amet consectetur adipiscing elit pellentesque habitant morbi tristique. Pellentesque diam volutpat commodo sed egestas egestas. Aliquam purus sit amet luctus venenatis lectus magna fringilla. Viverra mauris in aliquam sem fringilla ut morbi tincidunt. Elit duis tristique sollicitudin nibh sit. Fermentum dui faucibus in ornare quam viverra orci sagittis. Aliquet eget sit amet tellus cras adipiscing.</string>
<key>developer</key>
<string>Riley Testut</string>
<key>iconName</key>
<string>ClipboardIcon</string>
<key>screenshotNames</key>
<array/>
</dict>
</array>
</plist>

View File

@@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "IMG_8547.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 MiB

View File

@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "IMG_8548.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 MiB

View File

@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "IMG_8549.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

View File

@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "IMG_8550.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB