První implementace seznamu a pár tlačítek

This commit is contained in:
David Bureš 2022-07-03 16:07:38 +02:00 committed by David Bureš
parent bd8b874e14
commit 945746e3de
13 changed files with 407 additions and 17 deletions

View File

@ -11,6 +11,16 @@
634065672871AA42001A2178 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 634065662871AA42001A2178 /* ContentView.swift */; };
634065692871AA42001A2178 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 634065682871AA42001A2178 /* Assets.xcassets */; };
6340656C2871AA42001A2178 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6340656B2871AA42001A2178 /* Preview Assets.xcassets */; };
634065752871AB22001A2178 /* DavidFoundation in Frameworks */ = {isa = PBXBuildFile; productRef = 634065742871AB22001A2178 /* DavidFoundation */; };
634065782871AB3A001A2178 /* Shell Interface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 634065772871AB3A001A2178 /* Shell Interface.swift */; };
6340657A2871AC27001A2178 /* Brew Data Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 634065792871AC27001A2178 /* Brew Data Storage.swift */; };
6340657D2871AC65001A2178 /* Brew Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6340657C2871AC65001A2178 /* Brew Package.swift */; };
6340657F2871AF68001A2178 /* App Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6340657E2871AF68001A2178 /* App Constants.swift */; };
634065822871B0BE001A2178 /* Get Contents of Folder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 634065812871B0BE001A2178 /* Get Contents of Folder.swift */; };
634EB3972871C1F00009DFC2 /* Get Package Version.swift in Sources */ = {isa = PBXBuildFile; fileRef = 634EB3962871C1F00009DFC2 /* Get Package Version.swift */; };
6371EA1E2871D98100300E1B /* Package List Item.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6371EA1D2871D98100300E1B /* Package List Item.swift */; };
639A7D832871D08200B50280 /* Add Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = 639A7D822871D08200B50280 /* Add Package.swift */; };
639A7D862871D78C00B50280 /* Package Details.swift in Sources */ = {isa = PBXBuildFile; fileRef = 639A7D852871D78C00B50280 /* Package Details.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@ -20,6 +30,15 @@
634065682871AA42001A2178 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
6340656B2871AA42001A2178 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
6340656D2871AA42001A2178 /* Cork.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Cork.entitlements; sourceTree = "<group>"; };
634065772871AB3A001A2178 /* Shell Interface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Shell Interface.swift"; sourceTree = "<group>"; };
634065792871AC27001A2178 /* Brew Data Storage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Brew Data Storage.swift"; sourceTree = "<group>"; };
6340657C2871AC65001A2178 /* Brew Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Brew Package.swift"; sourceTree = "<group>"; };
6340657E2871AF68001A2178 /* App Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "App Constants.swift"; sourceTree = "<group>"; };
634065812871B0BE001A2178 /* Get Contents of Folder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Get Contents of Folder.swift"; sourceTree = "<group>"; };
634EB3962871C1F00009DFC2 /* Get Package Version.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Get Package Version.swift"; sourceTree = "<group>"; };
6371EA1D2871D98100300E1B /* Package List Item.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Package List Item.swift"; sourceTree = "<group>"; };
639A7D822871D08200B50280 /* Add Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Add Package.swift"; sourceTree = "<group>"; };
639A7D852871D78C00B50280 /* Package Details.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Package Details.swift"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -27,6 +46,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
634065752871AB22001A2178 /* DavidFoundation in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -52,11 +72,15 @@
634065632871AA42001A2178 /* Cork */ = {
isa = PBXGroup;
children = (
639A7D812871D07800B50280 /* Views */,
6340657B2871AC4F001A2178 /* Models */,
634065762871AB2A001A2178 /* Logic */,
634065642871AA42001A2178 /* CorkApp.swift */,
634065662871AA42001A2178 /* ContentView.swift */,
634065682871AA42001A2178 /* Assets.xcassets */,
6340656D2871AA42001A2178 /* Cork.entitlements */,
6340656A2871AA42001A2178 /* Preview Content */,
6340657E2871AF68001A2178 /* App Constants.swift */,
);
path = Cork;
sourceTree = "<group>";
@ -69,6 +93,51 @@
path = "Preview Content";
sourceTree = "<group>";
};
634065762871AB2A001A2178 /* Logic */ = {
isa = PBXGroup;
children = (
634065802871B0A3001A2178 /* File Browser */,
634065772871AB3A001A2178 /* Shell Interface.swift */,
634065792871AC27001A2178 /* Brew Data Storage.swift */,
);
path = Logic;
sourceTree = "<group>";
};
6340657B2871AC4F001A2178 /* Models */ = {
isa = PBXGroup;
children = (
6340657C2871AC65001A2178 /* Brew Package.swift */,
);
path = Models;
sourceTree = "<group>";
};
634065802871B0A3001A2178 /* File Browser */ = {
isa = PBXGroup;
children = (
634065812871B0BE001A2178 /* Get Contents of Folder.swift */,
634EB3962871C1F00009DFC2 /* Get Package Version.swift */,
);
path = "File Browser";
sourceTree = "<group>";
};
6371EA1C2871D96800300E1B /* Packages */ = {
isa = PBXGroup;
children = (
639A7D852871D78C00B50280 /* Package Details.swift */,
6371EA1D2871D98100300E1B /* Package List Item.swift */,
);
path = Packages;
sourceTree = "<group>";
};
639A7D812871D07800B50280 /* Views */ = {
isa = PBXGroup;
children = (
6371EA1C2871D96800300E1B /* Packages */,
639A7D822871D08200B50280 /* Add Package.swift */,
);
path = Views;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@ -85,6 +154,9 @@
dependencies = (
);
name = Cork;
packageProductDependencies = (
634065742871AB22001A2178 /* DavidFoundation */,
);
productName = Cork;
productReference = 634065612871AA42001A2178 /* Cork.app */;
productType = "com.apple.product-type.application";
@ -113,6 +185,9 @@
Base,
);
mainGroup = 634065582871AA42001A2178;
packageReferences = (
634065732871AB22001A2178 /* XCRemoteSwiftPackageReference "DavidFoundation" */,
);
productRefGroup = 634065622871AA42001A2178 /* Products */;
projectDirPath = "";
projectRoot = "";
@ -139,7 +214,16 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
634065782871AB3A001A2178 /* Shell Interface.swift in Sources */,
634065822871B0BE001A2178 /* Get Contents of Folder.swift in Sources */,
639A7D832871D08200B50280 /* Add Package.swift in Sources */,
6340657A2871AC27001A2178 /* Brew Data Storage.swift in Sources */,
6340657F2871AF68001A2178 /* App Constants.swift in Sources */,
634065672871AA42001A2178 /* ContentView.swift in Sources */,
6340657D2871AC65001A2178 /* Brew Package.swift in Sources */,
6371EA1E2871D98100300E1B /* Package List Item.swift in Sources */,
634EB3972871C1F00009DFC2 /* Get Package Version.swift in Sources */,
639A7D862871D78C00B50280 /* Package Details.swift in Sources */,
634065652871AA42001A2178 /* CorkApp.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -274,6 +358,7 @@
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
INFOPLIST_KEY_NSHumanReadableCopyright = "";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
@ -301,6 +386,7 @@
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
INFOPLIST_KEY_NSHumanReadableCopyright = "";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
@ -336,6 +422,25 @@
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */
634065732871AB22001A2178 /* XCRemoteSwiftPackageReference "DavidFoundation" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/buresdv/DavidFoundation";
requirement = {
branch = main;
kind = branch;
};
};
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
634065742871AB22001A2178 /* DavidFoundation */ = {
isa = XCSwiftPackageProductDependency;
package = 634065732871AB22001A2178 /* XCRemoteSwiftPackageReference "DavidFoundation" */;
productName = DavidFoundation;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 634065592871AA42001A2178 /* Project object */;
}

13
Cork/App Constants.swift Normal file
View File

@ -0,0 +1,13 @@
//
// App Constants.swift
// Cork
//
// Created by David Bureš on 03.07.2022.
//
import Foundation
struct AppConstantsLocal { // Had to add "local" because my package already has a struct called "AppConstants"
static let brewCellarPath: URL = URL(string: "/opt/homebrew/Cellar")!
static let brewCaskPath: URL = URL(string: "/opt/homebrew/Caskroom")!
}

View File

@ -8,18 +8,130 @@
import SwiftUI
struct ContentView: View {
@StateObject var brewData = BrewDataStorage()
@State private var multiSelection = Set<UUID>()
@State private var isShowingInstallSheet: Bool = false
@State private var isShowingAlert: Bool = false
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("Hello, world!")
List(selection: $multiSelection) {
Section("Installed Formulae") {
Text("Installed Formulae")
.font(.headline)
if brewData.installedFormulae.count != 0 {
ForEach(brewData.installedFormulae) { package in
PackageListItem(packageItem: package)
}
} else {
ProgressView()
}
}
Section("Installed Casks") {
Text("Installed Casks")
.font(.headline)
if brewData.installedCasks.count != 0 {
ForEach(brewData.installedCasks) { package in
PackageListItem(packageItem: package)
}
} else {
ProgressView()
}
}
}
.listStyle(.bordered)
.toolbar {
VStack(alignment: .leading) {
Text("Cork")
.font(.headline)
Text("\(brewData.installedCasks.count + brewData.installedFormulae.count) packages installed")
.font(.subheadline)
}
Spacer()
if !multiSelection.isEmpty { // If the user selected a package, show a button to uninstall it
Button {
print("Clicked Delete")
isShowingAlert.toggle()
} label: {
Label {
Text("Remove Package")
} icon: {
Image(systemName: "trash")
}
}
.alert("Are you sure you want to delete the selected package(s)?", isPresented: $isShowingAlert) {
Button("Delete", role: .destructive) {
}
Button("Cancel", role: .cancel) {
isShowingAlert.toggle()
}
} message: {
Text("Deleting a package will completely remove it from your Mac. You will have to reinstall the package if you want to use it again.")
Text("This action cannot be undone.")
}
}
Button {
isShowingInstallSheet.toggle()
} label: {
Label {
Text("Add Package")
} icon: {
Image(systemName: "plus")
}
}
}
}
.padding()
.environmentObject(brewData)
.onAppear {
Task {
print("Started Command task at \(Date())")
do {
let commandResult = try await executeCommand("/opt/homebrew/bin list")
print(commandResult)
} catch let error as NSError {
print("Error executing command: \(error)")
}
}
Task { // Task that gets the contents of the Cellar folder
print("Started Cellar task at \(Date())")
let contentsOfCellarFolder = await getContentsOfFolder(targetFolder: AppConstantsLocal.brewCellarPath)
for package in contentsOfCellarFolder {
brewData.installedFormulae.append(BrewPackage(name: package))
print("Appended \(package)")
}
//print(brewData.installedFormulae!)
}
Task { // Task that gets the contents of the Cask folder
print("Started Cask task at \(Date())")
let contentsOfCaskFolder = await getContentsOfFolder(targetFolder: AppConstantsLocal.brewCaskPath)
for package in contentsOfCaskFolder {
brewData.installedCasks.append(BrewPackage(name: package))
print("Appended \(package)")
}
//print(brewData.installedCasks!)
}
}
.sheet(isPresented: $isShowingInstallSheet) {
AddPackageView(isShowingSheet: $isShowingInstallSheet)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

View File

@ -1,10 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
</dict>
<dict/>
</plist>

View File

@ -8,10 +8,12 @@
import SwiftUI
@main
struct CorkApp: App {
struct CorkApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.windowToolbarStyle(UnifiedWindowToolbarStyle(showsTitle: false))
.windowStyle(HiddenTitleBarWindowStyle())
}
}

View File

@ -0,0 +1,13 @@
//
// Brew Data Storage.swift
// Cork
//
// Created by David Bureš on 03.07.2022.
//
import Foundation
class BrewDataStorage: ObservableObject {
@Published var installedFormulae = [BrewPackage]()
@Published var installedCasks = [BrewPackage]()
}

View File

@ -0,0 +1,23 @@
//
// Get Contents of Folder.swift
// Cork
//
// Created by David Bureš on 03.07.2022.
//
import Foundation
func getContentsOfFolder(targetFolder: URL) async -> [String] {
var contentsOfFolder = [String]()
do {
let items = try FileManager.default.contentsOfDirectory(atPath: targetFolder.path)
for item in items {
contentsOfFolder.append(item)
}
} catch let error as NSError {
print("Failed while accessing foldeR: \(error)")
}
return contentsOfFolder
}

View File

@ -0,0 +1,14 @@
//
// Get Package Version.swift
// Cork
//
// Created by David Bureš on 03.07.2022.
//
import Foundation
/*
func getPackageVersion(_ parentDirectory: URL, packageName: String) async -> String {
}
*/

View File

@ -0,0 +1,25 @@
//
// Shell Interface.swift
// Cork
//
// Created by David Bureš on 03.07.2022.
//
import Foundation
func executeCommand(_ commandToExecute: String) async throws -> String {
let task = Process()
let pipe = Pipe()
task.standardOutput = pipe
task.standardError = pipe
task.arguments = ["-c", commandToExecute]
task.launchPath = "/bin/zsh"
task.standardInput = nil
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output = String(data: data, encoding: .utf8)!
return output
}

View File

@ -0,0 +1,13 @@
//
// Brew Package.swift
// Cork
//
// Created by David Bureš on 03.07.2022.
//
import Foundation
struct BrewPackage: Identifiable {
let id = UUID()
let name: String
}

View File

@ -0,0 +1,37 @@
//
// Add Package.swift
// Cork
//
// Created by David Bureš on 03.07.2022.
//
import SwiftUI
struct AddPackageView: View {
@Binding var isShowingSheet: Bool
@State private var packageRequested: String = ""
var body: some View {
VStack(spacing: 20) {
TextField("Search For Package...", text: $packageRequested)
HStack {
Button {
isShowingSheet.toggle()
} label: {
Text("Cancel")
}
Spacer()
Button {
isShowingSheet.toggle()
} label: {
Text("Add")
}
}
}
.padding()
}
}

View File

@ -0,0 +1,16 @@
//
// Package Details.swift
// Cork
//
// Created by David Bureš on 03.07.2022.
//
import SwiftUI
struct PackageDetailView: View {
@State var packageName: String
var body: some View {
Text(packageName)
}
}

View File

@ -0,0 +1,22 @@
//
// Package List Item.swift
// Cork
//
// Created by David Bureš on 03.07.2022.
//
import SwiftUI
struct PackageListItem: View {
var packageItem: BrewPackage
var body: some View {
HStack {
Text(packageItem.name)
Spacer()
Image(systemName: "arrow.right")
}
}
}