Added ability to save screen.

This commit is contained in:
Casey Fleser 2022-08-21 06:07:15 -05:00
parent b68c2779fd
commit 7b02bd3da2
8 changed files with 171 additions and 37 deletions

View file

@ -19,6 +19,8 @@
C90DCC162896B0370072E403 /* AppearancePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = C90DCC152896B0370072E403 /* AppearancePicker.swift */; };
C927A0D92846414900533D66 /* Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = C927A0D82846414900533D66 /* Helpers.swift */; };
C927A0DB2846502300533D66 /* PathActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C927A0DA2846502300533D66 /* PathActions.swift */; };
C95CC0F828B2411700928FAE /* AppearanceButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = C95CC0F728B2411700928FAE /* AppearanceButtonStyle.swift */; };
C95CC0FA28B2414900928FAE /* SystemIconButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = C95CC0F928B2414900928FAE /* SystemIconButtonStyle.swift */; };
C9779742284F6DE000706DFB /* ToolbarMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9779741284F6DE000706DFB /* ToolbarMenu.swift */; };
C982F859283B9F9000D491F4 /* SimDirsApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = C982F858283B9F9000D491F4 /* SimDirsApp.swift */; };
C982F85B283B9F9000D491F4 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C982F85A283B9F9000D491F4 /* ContentView.swift */; };
@ -60,6 +62,8 @@
C90DCC152896B0370072E403 /* AppearancePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearancePicker.swift; sourceTree = "<group>"; };
C927A0D82846414900533D66 /* Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Helpers.swift; sourceTree = "<group>"; };
C927A0DA2846502300533D66 /* PathActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PathActions.swift; sourceTree = "<group>"; };
C95CC0F728B2411700928FAE /* AppearanceButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceButtonStyle.swift; sourceTree = "<group>"; };
C95CC0F928B2414900928FAE /* SystemIconButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SystemIconButtonStyle.swift; sourceTree = "<group>"; };
C9779741284F6DE000706DFB /* ToolbarMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolbarMenu.swift; sourceTree = "<group>"; };
C982F855283B9F9000D491F4 /* SimDirs.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SimDirs.app; sourceTree = BUILT_PRODUCTS_DIR; };
C982F858283B9F9000D491F4 /* SimDirsApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimDirsApp.swift; sourceTree = "<group>"; };
@ -101,6 +105,16 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
C95CC0F628B240F500928FAE /* Styles */ = {
isa = PBXGroup;
children = (
C95CC0F728B2411700928FAE /* AppearanceButtonStyle.swift */,
C9BF5233289FE99600BDDC91 /* DescriptiveToggleStyle.swift */,
C95CC0F928B2414900928FAE /* SystemIconButtonStyle.swift */,
);
path = Styles;
sourceTree = "<group>";
};
C982F84C283B9F9000D491F4 = {
isa = PBXGroup;
children = (
@ -159,12 +173,12 @@
C982F881283E7F0400D491F4 /* Views */ = {
isa = PBXGroup;
children = (
C95CC0F628B240F500928FAE /* Styles */,
C9DD54C12860935300D46AB3 /* SourceItem Views */,
C9DD54CC2860992200D46AB3 /* Model Views */,
C90DCC152896B0370072E403 /* AppearancePicker.swift */,
C90DCC132896AAAA0072E403 /* ContentHeader.swift */,
C9BF5231289FE95D00BDDC91 /* DescriptiveToggle.swift */,
C9BF5233289FE99600BDDC91 /* DescriptiveToggleStyle.swift */,
C90BCE472861D70500C2EF35 /* ErrorView.swift */,
C927A0DA2846502300533D66 /* PathActions.swift */,
C9EE0CD128478FDB00E9B97A /* PathRow.swift */,
@ -309,6 +323,7 @@
C982F877283D020C00D491F4 /* SimProductFamily.swift in Sources */,
C982F859283B9F9000D491F4 /* SimDirsApp.swift in Sources */,
C982F871283CE7B800D491F4 /* SimRuntime.swift in Sources */,
C95CC0FA28B2414900928FAE /* SystemIconButtonStyle.swift in Sources */,
C9EE0CD228478FDB00E9B97A /* PathRow.swift in Sources */,
C982F86B283BA22100D491F4 /* SimPlatform.swift in Sources */,
C927A0D92846414900533D66 /* Helpers.swift in Sources */,
@ -317,6 +332,7 @@
C9D73C29285C8C4B0044A279 /* SourceItem.swift in Sources */,
C982F879283D042E00D491F4 /* SimModel.swift in Sources */,
C982F87B283E40C800D491F4 /* SimCtl.swift in Sources */,
C95CC0F828B2411700928FAE /* AppearanceButtonStyle.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View file

@ -115,4 +115,8 @@ struct SimCtl {
func setDeviceIncreaseContrast(_ device: SimDevice, increaseContrast: SimDevice.IncreaseContrast) throws {
try runAsync(args: ["ui", device.udid, "increase_contrast", increaseContrast.rawValue])
}
func saveScreen(_ device: SimDevice, url: URL) throws {
try runAsync(args: ["io", device.udid, "screenshot", url.path])
}
}

View file

@ -182,6 +182,14 @@ class SimDevice: ObservableObject, Decodable {
print("Failed to set device increase contrast: \(error)")
}
}
func saveScreen(_ url: URL) {
do {
try SimCtl().saveScreen(self, url: url)
} catch {
print("Failed to save screen: \(error)")
}
}
}
extension SimDevice {

View file

@ -7,42 +7,6 @@
import SwiftUI
extension ButtonStyle where Self == AppearanceButtonStyle {
static func appearance(selected: Bool, scheme: ColorScheme) -> AppearanceButtonStyle {
AppearanceButtonStyle(selected: selected, scheme: scheme)
}
}
struct AppearanceButtonStyle: ButtonStyle {
let selected : Bool
let scheme : ColorScheme
func makeBody(configuration: Configuration) -> some View {
VStack {
let bordered = selected != configuration.isPressed
let color = scheme == .light ? Color.white : Color.black
let content = color
.frame(width: 48, height: 32)
.cornerRadius(5.0)
if bordered {
content
.overlay(
RoundedRectangle(cornerRadius: 6.0)
.stroke(Color.accentColor, lineWidth: 2.0)
)
}
else {
content
.shadow(color: .black.opacity(0.5), radius: 1.0, x: 0, y: 1.0)
}
configuration.label
}
.padding(1.0)
}
}
struct AppearancePicker: View {
@Environment(\.isEnabled) var isEnabled
@Binding var scheme : ColorScheme?

View file

@ -48,6 +48,14 @@ struct DeviceContent: View {
@ObservedObject var device : SimDevice
@State var isBooted : Bool
var fileDateFormatter : DateFormatter {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy.MM.dd'_'HH.mm.ss"
return formatter
}
init(_ device: SimDevice) {
self.device = device
self.isBooted = device.isBooted
@ -91,6 +99,14 @@ struct DeviceContent: View {
.opacity(isBooted ? 1.0 : 0.5)
}
}
ContentHeader("Actions")
Button(action: saveScreen) {
Text("Save Screen")
.fontWeight(.semibold)
.font(.system(size: 11))
}
.buttonStyle(.systemIcon("camera.on.rectangle"))
}
.environment(\.isEnabled, isBooted)
.onAppear {
@ -108,6 +124,24 @@ struct DeviceContent: View {
}
}
}
func saveScreen() {
let savePanel = NSSavePanel()
savePanel.allowedContentTypes = [.png]
savePanel.canCreateDirectories = true
savePanel.isExtensionHidden = false
savePanel.title = "Save Screen"
savePanel.message = "Select destination"
savePanel.nameFieldLabel = "Filename:"
savePanel.nameFieldStringValue = "\(device.name) - \(fileDateFormatter.string(from: Date()))"
if savePanel.runModal() == .OK {
if let url = savePanel.url {
device.saveScreen(url)
}
}
}
}
struct DeviceContent_Previews: PreviewProvider {

View file

@ -0,0 +1,44 @@
//
// AppearanceButtonStyle.swift
// SimDirs
//
// Created by Casey Fleser on 8/21/22.
//
import SwiftUI
extension ButtonStyle where Self == AppearanceButtonStyle {
static func appearance(selected: Bool, scheme: ColorScheme) -> AppearanceButtonStyle {
AppearanceButtonStyle(selected: selected, scheme: scheme)
}
}
struct AppearanceButtonStyle: ButtonStyle {
let selected : Bool
let scheme : ColorScheme
func makeBody(configuration: Configuration) -> some View {
VStack {
let bordered = selected != configuration.isPressed
let color = scheme == .light ? Color.white : Color.black
let content = color
.frame(width: 48, height: 32)
.cornerRadius(5.0)
if bordered {
content
.overlay(
RoundedRectangle(cornerRadius: 6.0)
.stroke(Color.accentColor, lineWidth: 2.0)
)
}
else {
content
.shadow(color: .black.opacity(0.5), radius: 1.0, x: 0, y: 1.0)
}
configuration.label
}
.padding(1.0)
}
}

View file

@ -0,0 +1,64 @@
//
// SystemIconButtonStyle.swift
// SimDirs
//
// Created by Casey Fleser on 8/21/22.
//
import SwiftUI
extension ButtonStyle where Self == SystemIconButtonStyle {
static func systemIcon(_ imageName: String) -> SystemIconButtonStyle {
SystemIconButtonStyle(imageName)
}
}
struct SystemIconButtonStyle: ButtonStyle {
@State var isFocused = false
let imageName : String
init(_ imageName: String) {
self.imageName = imageName
}
func makeBody(configuration: Configuration) -> some View {
VStack {
ZStack {
backgroundColor(pressed: configuration.isPressed)
.frame(width: 36, height: 36)
.cornerRadius(5.0)
Image(systemName: imageName)
.resizable()
.aspectRatio(contentMode: ContentMode.fit)
.frame(width: 24, height: 24)
}
configuration.label
}
.foregroundColor(foregroundColor(pressed: configuration.isPressed))
.padding(1.0)
.onHover { isFocused = $0 }
}
func foregroundColor(pressed: Bool) -> Color {
return .primary.opacity(pressed ? 1.0 : 0.6)
}
func backgroundColor(pressed: Bool) -> Color {
return .primary.opacity(0.05 + (isFocused ? 0.1 : 0.0) + (pressed ? 0.1 : 0.0))
}
}
struct SystemIconButtonStyle_Previews: PreviewProvider {
static var previews: some View {
Button("Button") { print("do stuff") }
.preferredColorScheme(.light)
.buttonStyle(.systemIcon("camera.on.rectangle"))
.padding(20)
Button("Button") { print("do stuff") }
.preferredColorScheme(.dark)
.buttonStyle(.systemIcon("camera.on.rectangle"))
.padding(20)
}
}