[Experimental Feature] Game Screenshots (#242)
* Adds extension to handle interactions with Photos app - isAuthorized to check/ask for authorization - saveUIImage to save a UIImage to Photos * Adds a Pause Menu button for taking game screenshots * Adds @Feature and @Options for Game Screenshots * Implements Game Screenshots feature in GameViewController * Updates project settings * Passes call to save to Photos as a closure into authorization prompt - Ensures that the screenshot is saved when the user is first prompted for access to Photos - More elegant extension code --------- Co-authored-by: Riley Testut <riley@rileytestut.com>
This commit is contained in:
parent
05e94902b8
commit
6bdc05f640
@ -34,6 +34,8 @@
|
|||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
1FA4ABA79AB72914FE414A61 /* libPods-Delta.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC866E433B3BA9AE18ABA1EC /* libPods-Delta.a */; };
|
1FA4ABA79AB72914FE414A61 /* libPods-Delta.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC866E433B3BA9AE18ABA1EC /* libPods-Delta.a */; };
|
||||||
87343D7B985519A5890A61C6 /* libPods-DeltaPreviews.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7E3E5A45AB20C8A87754453B /* libPods-DeltaPreviews.a */; };
|
87343D7B985519A5890A61C6 /* libPods-DeltaPreviews.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7E3E5A45AB20C8A87754453B /* libPods-DeltaPreviews.a */; };
|
||||||
|
ACF7E30D29F73D03000FE071 /* GameScreenshots.swift in Sources */ = {isa = PBXBuildFile; fileRef = ACF7E30C29F73D03000FE071 /* GameScreenshots.swift */; };
|
||||||
|
ACF7E30F29F743A3000FE071 /* PHPhotoLibrary+Authorization.swift in Sources */ = {isa = PBXBuildFile; fileRef = ACF7E30E29F743A3000FE071 /* PHPhotoLibrary+Authorization.swift */; };
|
||||||
BF00BEA625B758AA00C8607D /* SystemBIOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF00BEA525B758AA00C8607D /* SystemBIOS.swift */; };
|
BF00BEA625B758AA00C8607D /* SystemBIOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF00BEA525B758AA00C8607D /* SystemBIOS.swift */; };
|
||||||
BF02D5DA1DDEBB3000A5E131 /* openvgdb.sqlite in Resources */ = {isa = PBXBuildFile; fileRef = BF02D5D91DDEBB3000A5E131 /* openvgdb.sqlite */; };
|
BF02D5DA1DDEBB3000A5E131 /* openvgdb.sqlite in Resources */ = {isa = PBXBuildFile; fileRef = BF02D5D91DDEBB3000A5E131 /* openvgdb.sqlite */; };
|
||||||
BF04E6FF1DB8625C000F35D3 /* ControllerSkinsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF04E6FE1DB8625C000F35D3 /* ControllerSkinsViewController.swift */; };
|
BF04E6FF1DB8625C000F35D3 /* ControllerSkinsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF04E6FE1DB8625C000F35D3 /* ControllerSkinsViewController.swift */; };
|
||||||
@ -257,6 +259,8 @@
|
|||||||
8ECE6641DE30D01EA30FE7F6 /* Pods-DeltaPreviews.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DeltaPreviews.release.xcconfig"; path = "Pods/Target Support Files/Pods-DeltaPreviews/Pods-DeltaPreviews.release.xcconfig"; sourceTree = "<group>"; };
|
8ECE6641DE30D01EA30FE7F6 /* Pods-DeltaPreviews.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DeltaPreviews.release.xcconfig"; path = "Pods/Target Support Files/Pods-DeltaPreviews/Pods-DeltaPreviews.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
A01281C7023C0041B25963BE /* Pods-DeltaPreviews.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DeltaPreviews.debug.xcconfig"; path = "Pods/Target Support Files/Pods-DeltaPreviews/Pods-DeltaPreviews.debug.xcconfig"; sourceTree = "<group>"; };
|
A01281C7023C0041B25963BE /* Pods-DeltaPreviews.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DeltaPreviews.debug.xcconfig"; path = "Pods/Target Support Files/Pods-DeltaPreviews/Pods-DeltaPreviews.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
A19FF50F55441BC2B2248241 /* Pods-Delta.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Delta.release.xcconfig"; path = "Pods/Target Support Files/Pods-Delta/Pods-Delta.release.xcconfig"; sourceTree = "<group>"; };
|
A19FF50F55441BC2B2248241 /* Pods-Delta.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Delta.release.xcconfig"; path = "Pods/Target Support Files/Pods-Delta/Pods-Delta.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
ACF7E30C29F73D03000FE071 /* GameScreenshots.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameScreenshots.swift; sourceTree = "<group>"; };
|
||||||
|
ACF7E30E29F743A3000FE071 /* PHPhotoLibrary+Authorization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PHPhotoLibrary+Authorization.swift"; sourceTree = "<group>"; };
|
||||||
BF00BEA525B758AA00C8607D /* SystemBIOS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SystemBIOS.swift; sourceTree = "<group>"; };
|
BF00BEA525B758AA00C8607D /* SystemBIOS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SystemBIOS.swift; sourceTree = "<group>"; };
|
||||||
BF02D5D91DDEBB3000A5E131 /* openvgdb.sqlite */ = {isa = PBXFileReference; lastKnownFileType = file; path = openvgdb.sqlite; sourceTree = "<group>"; };
|
BF02D5D91DDEBB3000A5E131 /* openvgdb.sqlite */ = {isa = PBXFileReference; lastKnownFileType = file; path = openvgdb.sqlite; sourceTree = "<group>"; };
|
||||||
BF0418131D01E93400E85BCF /* GBADeltaCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = GBADeltaCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
BF0418131D01E93400E85BCF /* GBADeltaCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = GBADeltaCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
@ -526,6 +530,7 @@
|
|||||||
D524F4A2273DE9C000D500B2 /* ProcessInfo+JIT.swift */,
|
D524F4A2273DE9C000D500B2 /* ProcessInfo+JIT.swift */,
|
||||||
D524F4A4273DEBB400D500B2 /* ServerManager+Delta.swift */,
|
D524F4A4273DEBB400D500B2 /* ServerManager+Delta.swift */,
|
||||||
D5011C47281B6E8B00A0760B /* CharacterSet+Filename.swift */,
|
D5011C47281B6E8B00A0760B /* CharacterSet+Filename.swift */,
|
||||||
|
ACF7E30E29F743A3000FE071 /* PHPhotoLibrary+Authorization.swift */,
|
||||||
);
|
);
|
||||||
path = Extensions;
|
path = Extensions;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -1068,6 +1073,7 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
D5A9C01C29DE058C00A8D610 /* VariableFastForward.swift */,
|
D5A9C01C29DE058C00A8D610 /* VariableFastForward.swift */,
|
||||||
|
ACF7E30C29F73D03000FE071 /* GameScreenshots.swift */,
|
||||||
);
|
);
|
||||||
path = Features;
|
path = Features;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -1554,6 +1560,8 @@
|
|||||||
D5A9C00329DDED6D00A8D610 /* ExperimentalFeaturesView.swift in Sources */,
|
D5A9C00329DDED6D00A8D610 /* ExperimentalFeaturesView.swift in Sources */,
|
||||||
BF1F45BF21AF676F00EF9895 /* Box.swift in Sources */,
|
BF1F45BF21AF676F00EF9895 /* Box.swift in Sources */,
|
||||||
BF7AE80A1C2E8C7600B1B5BC /* UIColor+Delta.swift in Sources */,
|
BF7AE80A1C2E8C7600B1B5BC /* UIColor+Delta.swift in Sources */,
|
||||||
|
ACF7E30F29F743A3000FE071 /* PHPhotoLibrary+Authorization.swift in Sources */,
|
||||||
|
ACF7E30D29F73D03000FE071 /* GameScreenshots.swift in Sources */,
|
||||||
BF797A2D1C2D339F00F1A000 /* UILabel+FontSize.swift in Sources */,
|
BF797A2D1C2D339F00F1A000 /* UILabel+FontSize.swift in Sources */,
|
||||||
BF80E1D21F13117000847008 /* ControllerInputsViewController.swift in Sources */,
|
BF80E1D21F13117000847008 /* ControllerInputsViewController.swift in Sources */,
|
||||||
BF5942641E09BBB10051894B /* LoadControllerSkinImageOperation.swift in Sources */,
|
BF5942641E09BBB10051894B /* LoadControllerSkinImageOperation.swift in Sources */,
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
import Photos
|
||||||
|
|
||||||
import DeltaCore
|
import DeltaCore
|
||||||
import GBADeltaCore
|
import GBADeltaCore
|
||||||
@ -412,6 +413,9 @@ extension GameViewController
|
|||||||
pauseViewController.fastForwardItem?.action = { [unowned self] item in
|
pauseViewController.fastForwardItem?.action = { [unowned self] item in
|
||||||
self.performFastForwardAction(activate: item.isSelected)
|
self.performFastForwardAction(activate: item.isSelected)
|
||||||
}
|
}
|
||||||
|
pauseViewController.screenshotItem?.action = { [unowned self] item in
|
||||||
|
self.performScreenshotAction()
|
||||||
|
}
|
||||||
|
|
||||||
pauseViewController.sustainButtonsItem?.isSelected = gameController.sustainedInputs.count > 0
|
pauseViewController.sustainButtonsItem?.isSelected = gameController.sustainedInputs.count > 0
|
||||||
pauseViewController.sustainButtonsItem?.action = { [unowned self, unowned pauseViewController] item in
|
pauseViewController.sustainButtonsItem?.action = { [unowned self, unowned pauseViewController] item in
|
||||||
@ -1078,6 +1082,73 @@ extension GameViewController
|
|||||||
emulatorCore.rate = emulatorCore.deltaCore.supportedRates.lowerBound
|
emulatorCore.rate = emulatorCore.deltaCore.supportedRates.lowerBound
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func performScreenshotAction()
|
||||||
|
{
|
||||||
|
guard let snapshot = self.emulatorCore?.videoManager.snapshot() else { return }
|
||||||
|
|
||||||
|
let imageScale = ExperimentalFeatures.shared.gameScreenshots.size?.rawValue ?? 1.0
|
||||||
|
let imageSize = CGSize(width: snapshot.size.width * imageScale, height: snapshot.size.height * imageScale)
|
||||||
|
|
||||||
|
let format = UIGraphicsImageRendererFormat()
|
||||||
|
format.scale = 1
|
||||||
|
let renderer = UIGraphicsImageRenderer(size: imageSize, format: format)
|
||||||
|
|
||||||
|
let scaledSnapshot = renderer.image { (context) in
|
||||||
|
context.cgContext.interpolationQuality = .none
|
||||||
|
snapshot.draw(in: CGRect(origin: .zero, size: imageSize))
|
||||||
|
}
|
||||||
|
|
||||||
|
if ExperimentalFeatures.shared.gameScreenshots.saveToPhotos
|
||||||
|
{
|
||||||
|
PHPhotoLibrary.runIfAuthorized
|
||||||
|
{
|
||||||
|
PHPhotoLibrary.saveUIImage(image: scaledSnapshot)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ExperimentalFeatures.shared.gameScreenshots.saveToFiles
|
||||||
|
{
|
||||||
|
guard let data = scaledSnapshot.pngData() else { return }
|
||||||
|
|
||||||
|
let screenshotsDirectory = FileManager.default.documentsDirectory.appendingPathComponent("Screenshots")
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
try FileManager.default.createDirectory(at: screenshotsDirectory, withIntermediateDirectories: true, attributes: nil)
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
print(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
let date = Date()
|
||||||
|
let dateFormatter = DateFormatter()
|
||||||
|
dateFormatter.dateFormat = "yyyy-MM-dd_HH-mm-ss"
|
||||||
|
|
||||||
|
let fileName: URL
|
||||||
|
if let game = self.game as? Game
|
||||||
|
{
|
||||||
|
let filename = game.name + "_" + dateFormatter.string(from: date) + ".png"
|
||||||
|
fileName = screenshotsDirectory.appendingPathComponent(filename)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fileName = screenshotsDirectory.appendingPathComponent(dateFormatter.string(from: date) + ".png")
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
try data.write(to: fileName)
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
print(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.pauseViewController?.screenshotItem?.isSelected = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//MARK: - GameViewControllerDelegate -
|
//MARK: - GameViewControllerDelegate -
|
||||||
|
|||||||
@ -21,6 +21,11 @@ struct ExperimentalFeatures: FeatureContainer
|
|||||||
description: "Enable to show the Status Bar during gameplay.")
|
description: "Enable to show the Status Bar during gameplay.")
|
||||||
var showStatusBar
|
var showStatusBar
|
||||||
|
|
||||||
|
@Feature(name: "Game Screenshots",
|
||||||
|
description: "When enabled, a Screenshot button will appear in the Pause Menu, allowing you to save a screenshot of your game. You can choose to save the screenshot to Photos or Files.",
|
||||||
|
options: GameScreenshotsOptions())
|
||||||
|
var gameScreenshots
|
||||||
|
|
||||||
private init()
|
private init()
|
||||||
{
|
{
|
||||||
self.prepareFeatures()
|
self.prepareFeatures()
|
||||||
|
|||||||
54
Delta/Experimental Features/Features/GameScreenshots.swift
Normal file
54
Delta/Experimental Features/Features/GameScreenshots.swift
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
//
|
||||||
|
// GameScreenshots.swift
|
||||||
|
// Delta
|
||||||
|
//
|
||||||
|
// Created by Chris Rittenhouse on 4/24/23.
|
||||||
|
// Copyright © 2023 Riley Testut. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
import DeltaFeatures
|
||||||
|
|
||||||
|
enum ScreenshotSize: Double, CaseIterable, CustomStringConvertible
|
||||||
|
{
|
||||||
|
case x5 = 5
|
||||||
|
case x4 = 4
|
||||||
|
case x3 = 3
|
||||||
|
case x2 = 2
|
||||||
|
|
||||||
|
var description: String {
|
||||||
|
if #available(iOS 15, *)
|
||||||
|
{
|
||||||
|
let formattedText = self.rawValue.formatted(.number.decimalSeparator(strategy: .automatic))
|
||||||
|
return "\(formattedText)x Size"
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return "\(self.rawValue)x Size"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ScreenshotSize: LocalizedOptionValue
|
||||||
|
{
|
||||||
|
var localizedDescription: Text {
|
||||||
|
Text(self.description)
|
||||||
|
}
|
||||||
|
|
||||||
|
static var localizedNilDescription: Text {
|
||||||
|
Text("Original Size")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct GameScreenshotsOptions
|
||||||
|
{
|
||||||
|
@Option(name: "Save to Files", description: "Save the screenshot to the app's directory in Files.")
|
||||||
|
var saveToFiles: Bool = true
|
||||||
|
|
||||||
|
@Option(name: "Save to Photos", description: "Save the screenshot to the Photo Library.")
|
||||||
|
var saveToPhotos: Bool = false
|
||||||
|
|
||||||
|
@Option(name: "Image Size", description: "Choose the size of screenshots. This only increases the export size, it does not increase the quality.", values: ScreenshotSize.allCases)
|
||||||
|
var size: ScreenshotSize?
|
||||||
|
}
|
||||||
46
Delta/Extensions/PHPhotoLibrary+Authorization.swift
Normal file
46
Delta/Extensions/PHPhotoLibrary+Authorization.swift
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
//
|
||||||
|
// PHPhotoLibrary+Authorization.swift
|
||||||
|
// Delta
|
||||||
|
//
|
||||||
|
// Created by Chris Rittenhouse on 4/24/23.
|
||||||
|
// Copyright © 2023 Riley Testut. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import Photos
|
||||||
|
|
||||||
|
extension PHPhotoLibrary
|
||||||
|
{
|
||||||
|
static func runIfAuthorized(code: @escaping () -> Void)
|
||||||
|
{
|
||||||
|
PHPhotoLibrary.requestAuthorization(for: .addOnly, handler: { success in
|
||||||
|
switch success
|
||||||
|
{
|
||||||
|
case .authorized:
|
||||||
|
code()
|
||||||
|
|
||||||
|
case .denied, .restricted, .notDetermined, .limited:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
static func saveUIImage(image: UIImage)
|
||||||
|
{
|
||||||
|
// Save the image to the Photos app
|
||||||
|
PHPhotoLibrary.shared().performChanges({
|
||||||
|
PHAssetChangeRequest.creationRequestForAsset(from: image)
|
||||||
|
}, completionHandler: { success, error in
|
||||||
|
if success
|
||||||
|
{
|
||||||
|
// Image saved successfully
|
||||||
|
print("Image saved to Photos app.")
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Error saving image
|
||||||
|
print("Error saving image: \(error?.localizedDescription ?? "Unknown error")")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -19,7 +19,7 @@ class PauseViewController: UIViewController, PauseInfoProviding
|
|||||||
}
|
}
|
||||||
|
|
||||||
var pauseItems: [MenuItem] {
|
var pauseItems: [MenuItem] {
|
||||||
return [self.saveStateItem, self.loadStateItem, self.cheatCodesItem, self.fastForwardItem, self.sustainButtonsItem].compactMap { $0 }
|
return [self.saveStateItem, self.loadStateItem, self.cheatCodesItem, self.fastForwardItem, self.sustainButtonsItem, self.screenshotItem].compactMap { $0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pause Items
|
/// Pause Items
|
||||||
@ -28,6 +28,7 @@ class PauseViewController: UIViewController, PauseInfoProviding
|
|||||||
var cheatCodesItem: MenuItem?
|
var cheatCodesItem: MenuItem?
|
||||||
var fastForwardItem: MenuItem?
|
var fastForwardItem: MenuItem?
|
||||||
var sustainButtonsItem: MenuItem?
|
var sustainButtonsItem: MenuItem?
|
||||||
|
var screenshotItem: MenuItem?
|
||||||
|
|
||||||
/// PauseInfoProviding
|
/// PauseInfoProviding
|
||||||
var pauseText: String?
|
var pauseText: String?
|
||||||
@ -160,6 +161,7 @@ private extension PauseViewController
|
|||||||
self.cheatCodesItem = nil
|
self.cheatCodesItem = nil
|
||||||
self.sustainButtonsItem = nil
|
self.sustainButtonsItem = nil
|
||||||
self.fastForwardItem = nil
|
self.fastForwardItem = nil
|
||||||
|
self.screenshotItem = nil
|
||||||
|
|
||||||
guard self.emulatorCore != nil else { return }
|
guard self.emulatorCore != nil else { return }
|
||||||
|
|
||||||
@ -179,6 +181,11 @@ private extension PauseViewController
|
|||||||
|
|
||||||
self.fastForwardItem = MenuItem(text: NSLocalizedString("Fast Forward", comment: ""), image: #imageLiteral(resourceName: "FastForward"), action: { _ in })
|
self.fastForwardItem = MenuItem(text: NSLocalizedString("Fast Forward", comment: ""), image: #imageLiteral(resourceName: "FastForward"), action: { _ in })
|
||||||
self.sustainButtonsItem = MenuItem(text: NSLocalizedString("Hold Buttons", comment: ""), image: #imageLiteral(resourceName: "SustainButtons"), action: { _ in })
|
self.sustainButtonsItem = MenuItem(text: NSLocalizedString("Hold Buttons", comment: ""), image: #imageLiteral(resourceName: "SustainButtons"), action: { _ in })
|
||||||
|
|
||||||
|
if ExperimentalFeatures.shared.gameScreenshots.isEnabled
|
||||||
|
{
|
||||||
|
self.screenshotItem = MenuItem(text: NSLocalizedString("Screenshot", comment: ""), image: #imageLiteral(resourceName: "Screenshot"), action: { _ in })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateSafeAreaInsets()
|
func updateSafeAreaInsets()
|
||||||
|
|||||||
26
Resources/Assets.xcassets/Pause Icons/Screenshot.imageset/Contents.json
vendored
Normal file
26
Resources/Assets.xcassets/Pause Icons/Screenshot.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "screenshot.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "screenshot@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "screenshot@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"template-rendering-intent" : "template"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
Resources/Assets.xcassets/Pause Icons/Screenshot.imageset/screenshot.png
vendored
Normal file
BIN
Resources/Assets.xcassets/Pause Icons/Screenshot.imageset/screenshot.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
BIN
Resources/Assets.xcassets/Pause Icons/Screenshot.imageset/screenshot@2x.png
vendored
Normal file
BIN
Resources/Assets.xcassets/Pause Icons/Screenshot.imageset/screenshot@2x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
BIN
Resources/Assets.xcassets/Pause Icons/Screenshot.imageset/screenshot@3x.png
vendored
Normal file
BIN
Resources/Assets.xcassets/Pause Icons/Screenshot.imageset/screenshot@3x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.9 KiB |
Loading…
Reference in New Issue
Block a user