Skip to content

Commit

Permalink
Create additional cask info window
Browse files Browse the repository at this point in the history
  • Loading branch information
milanvarady committed Jan 2, 2025
1 parent a5d1c29 commit 0f6d94a
Show file tree
Hide file tree
Showing 15 changed files with 261 additions and 13 deletions.
22 changes: 21 additions & 1 deletion Applite.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@
419256AD2D25E1F100D9EF10 /* BrewManagementView+InfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 419256AC2D25E1F100D9EF10 /* BrewManagementView+InfoView.swift */; };
419256AF2D25F68700D9EF10 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 419256AE2D25F68700D9EF10 /* AppDelegate.swift */; };
419256B22D26033400D9EF10 /* DebouncedOnChange in Frameworks */ = {isa = PBXBuildFile; productRef = 419256B12D26033400D9EF10 /* DebouncedOnChange */; };
419256B42D26B8A200D9EF10 /* CaskAdditionalInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 419256B32D26B8A200D9EF10 /* CaskAdditionalInfo.swift */; };
419256B62D26BBBD00D9EF10 /* AppView+GetInfoButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 419256B52D26BBBD00D9EF10 /* AppView+GetInfoButton.swift */; };
419256B92D26C02E00D9EF10 /* CaskInfoWindowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 419256B82D26C02E00D9EF10 /* CaskInfoWindowView.swift */; };
419506A42964A27F00FE5802 /* SetupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 419506A32964A27F00FE5802 /* SetupView.swift */; };
419506A62964A5EF00FE5802 /* BrewPathSelectorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 419506A52964A5EF00FE5802 /* BrewPathSelectorView.swift */; };
4196C8F528F9CB2600EADDDA /* DiscoverView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4196C8F428F9CB2600EADDDA /* DiscoverView.swift */; };
Expand Down Expand Up @@ -219,6 +222,9 @@
419256AA2D25E19B00D9EF10 /* BrewManagementView+ActionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BrewManagementView+ActionsView.swift"; sourceTree = "<group>"; };
419256AC2D25E1F100D9EF10 /* BrewManagementView+InfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BrewManagementView+InfoView.swift"; sourceTree = "<group>"; };
419256AE2D25F68700D9EF10 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
419256B32D26B8A200D9EF10 /* CaskAdditionalInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaskAdditionalInfo.swift; sourceTree = "<group>"; };
419256B52D26BBBD00D9EF10 /* AppView+GetInfoButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppView+GetInfoButton.swift"; sourceTree = "<group>"; };
419256B82D26C02E00D9EF10 /* CaskInfoWindowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaskInfoWindowView.swift; sourceTree = "<group>"; };
419506A32964A27F00FE5802 /* SetupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupView.swift; sourceTree = "<group>"; };
419506A52964A5EF00FE5802 /* BrewPathSelectorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrewPathSelectorView.swift; sourceTree = "<group>"; };
419506A729696A5300FE5802 /* Applite-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Applite-Info.plist"; sourceTree = SOURCE_ROOT; };
Expand Down Expand Up @@ -369,9 +375,9 @@
419256212D1DF12900D9EF10 /* Setup */,
4192562F2D1DF27E00D9EF10 /* Settings */,
4196C8F628F9CB4100EADDDA /* App Views */,
419256B72D26C00B00D9EF10 /* Windows */,
41062C982A3A263F00FD48EA /* UninstallSelfView.swift */,
4166EE6F28F5D4C900CE305A /* Commands.swift */,
415563A12A98BB2500AE2F2E /* ErrorWindowView.swift */,
412635412A77FA1A00155034 /* Components */,
);
path = Views;
Expand All @@ -394,6 +400,7 @@
419256822D22055200D9EF10 /* CaskInfo.swift */,
4191392B29159B5C00F1D75D /* CaskDTO.swift */,
4166EE7C28F73B2300CE305A /* BrewAnalytics.swift */,
419256B32D26B8A200D9EF10 /* CaskAdditionalInfo.swift */,
);
path = "Cask Models";
sourceTree = "<group>";
Expand Down Expand Up @@ -468,6 +475,7 @@
419256192D1DEB2100D9EF10 /* AppView+OpenAndManageView.swift */,
4192561D2D1DEBE700D9EF10 /* AppView+UninstallButton.swift */,
4192561F2D1DEC0D00D9EF10 /* AppView+UpdateButton.swift */,
419256B52D26BBBD00D9EF10 /* AppView+GetInfoButton.swift */,
);
path = "App View";
sourceTree = "<group>";
Expand Down Expand Up @@ -617,6 +625,15 @@
path = "Brew Management";
sourceTree = "<group>";
};
419256B72D26C00B00D9EF10 /* Windows */ = {
isa = PBXGroup;
children = (
415563A12A98BB2500AE2F2E /* ErrorWindowView.swift */,
419256B82D26C02E00D9EF10 /* CaskInfoWindowView.swift */,
);
path = Windows;
sourceTree = "<group>";
};
4196C8F628F9CB4100EADDDA /* App Views */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -770,6 +787,7 @@
41857B752912D94A004A1894 /* CategoryView.swift in Sources */,
4196C8F528F9CB2600EADDDA /* DiscoverView.swift in Sources */,
4192561C2D1DEB7E00D9EF10 /* AppView+DownloadButton.swift in Sources */,
419256B92D26C02E00D9EF10 /* CaskInfoWindowView.swift in Sources */,
419256232D1DF14C00D9EF10 /* SetupView+PageControllerButtons.swift in Sources */,
4125BB8A29539907000FBD25 /* PlaceholderAppView.swift in Sources */,
419256182D1DEA4400D9EF10 /* AppView+ActionsView.swift in Sources */,
Expand All @@ -788,6 +806,7 @@
419506A42964A27F00FE5802 /* SetupView.swift in Sources */,
4192561E2D1DEBE700D9EF10 /* AppView+UninstallButton.swift in Sources */,
4192569B2D24335900D9EF10 /* CaskTaskError.swift in Sources */,
419256B42D26B8A200D9EF10 /* CaskAdditionalInfo.swift in Sources */,
41524B99295E352200D0046A /* SettingsView.swift in Sources */,
419256292D1DF1CF00D9EF10 /* SetupView+BrewPathSelection.swift in Sources */,
415563A22A98BB2500AE2F2E /* ErrorWindowView.swift in Sources */,
Expand Down Expand Up @@ -821,6 +840,7 @@
41062C952A3794EA00FD48EA /* BrewPaths.swift in Sources */,
4192565B2D1E0ECF00D9EF10 /* DiscoverSectionView+Placeholder.swift in Sources */,
41483CCD29101C9900BB10C2 /* Category.swift in Sources */,
419256B62D26BBBD00D9EF10 /* AppView+GetInfoButton.swift in Sources */,
4192569D2D2433E200D9EF10 /* CaskProgressState.swift in Sources */,
418F331C28EB3D540023D76F /* AppGridView.swift in Sources */,
419256332D1DF2E000D9EF10 /* SettingsView+BrewPath.swift in Sources */,
Expand Down
6 changes: 5 additions & 1 deletion Applite/AppliteApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,13 @@ struct AppliteApp: App {
.preferredColorScheme(selectedColorScheme)
}
.windowResizability(.contentSize)

WindowGroup("Shell Output", for: String.self) { $errorString in
ErrorWindowView(errorString: errorString ?? "N/a")
}

WindowGroup("Cask Info", for: CaskAdditionalInfo.self) { $info in
CaskInfoWindowView(info: info ?? .dummy)
}
}
}
5 changes: 5 additions & 0 deletions Applite/Model/Cask Models/Cask Manager/CaskLoadError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@ import Foundation
enum CaskLoadError: LocalizedError {
case failedToLoadCategoryJSON
case failedToLoadFromCache
case failedToLoadAdditionalInfo

var errorDescription: String? {
switch self {
case .failedToLoadCategoryJSON:
return "Failed to load categories"
case .failedToLoadFromCache:
return "Failed to load app catalog from cache"
case .failedToLoadAdditionalInfo:
return "Failed to load additional info"
}
}

Expand All @@ -26,6 +29,8 @@ enum CaskLoadError: LocalizedError {
return "Couldn't load category JSON file"
case .failedToLoadFromCache:
return "The file doesn't exist or couldn't be read"
case .failedToLoadAdditionalInfo:
return "The response object was empty"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,23 @@ extension CaskManager {
}
}

func getAdditionalInfoForCask(_ cask: Cask) async throws -> CaskAdditionalInfo {
let json = try await Shell.runBrewCommand(["info", "--json=v2", "--cask", cask.info.id])
.trimmingCharacters(in: .whitespacesAndNewlines)

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .secondsSince1970

let responseObject = try decoder.decode(CaskAdditionalInfoResponse.self, from: json.data(using: .utf8)!)

guard let additionalInfo = responseObject.casks.first else {
Self.logger.error("Couldn't find cask \(cask.info.id)")
throw CaskLoadError.failedToLoadAdditionalInfo
}

return additionalInfo
}

// MARK: - Helper functions

/// Starts a brew task and appends it to active tasks
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ extension CaskManager {
let output = try await Shell.runBrewCommand(["list", "--cask"])

if output.isEmpty {
await Self.logger.notice("No installed casks were found")
await Self.logger.notice("No installed casks were found. Output: \(output)")
}

return output
Expand Down
48 changes: 48 additions & 0 deletions Applite/Model/Cask Models/CaskAdditionalInfo.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// CaskAdditionalInfo.swift
// Applite
//
// Created by Milán Várady on 2025.01.02.
//

import Foundation

struct CaskAdditionalInfoResponse: Decodable {
let casks: [CaskAdditionalInfo]
}

struct CaskAdditionalInfo: Codable, Hashable {
let token: String
let tap: String
let homepage: URL
let url: URL
/// Installed version
let installed: String?
let installed_time: Date?
let auto_updates: Bool?
let deprecated: Bool
let deprection_date: Date?
let deprecation_reason: String?
let deprecation_replacement: String?
let disabled: Bool
let disabled_date: Date?
let disabled_reason: String?
let disabled_replacement: String?

static let dummy = CaskAdditionalInfo(
token: "Applite", tap: "homebrew/cask",
homepage: URL(string: "https://aerolite.dev/applite")!,
url: URL(string: "https://github.com/milanvarady/Applite/releases/download/v1.2.5/Applite.dmg")!,
installed: "1.2.5",
installed_time: Date(timeIntervalSince1970: 1735754762),
auto_updates: true,
deprecated: false,
deprection_date: nil,
deprecation_reason: nil,
deprecation_replacement: nil,
disabled: false,
disabled_date: nil,
disabled_reason: nil,
disabled_replacement: nil
)
}
2 changes: 2 additions & 0 deletions Applite/Views/App Views/App View/AppView+DownloadButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ extension AppView {
.fontWeight(.thin)
}

GetInfoButton(cask: cask)

// Force install button
Button {
showingForceInstallConfirmation = true
Expand Down
34 changes: 34 additions & 0 deletions Applite/Views/App Views/App View/AppView+GetInfoButton.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// AppView+GetInfoButton.swift
// Applite
//
// Created by Milán Várady on 2025.01.02.
//

import SwiftUI

extension AppView {
struct GetInfoButton: View {
@ObservedObject var cask: Cask
@EnvironmentObject var caskManager: CaskManager
@Environment(\.openWindow) var openWindow

@StateObject var alert = AlertManager()

var body: some View {
Button {
Task {
do {
let caskInfo = try await caskManager.getAdditionalInfoForCask(cask)
openWindow(value: caskInfo)
} catch {
alert.show(error: error, title: "Failed to gather cask info")
}
}
} label: {
Label("Get Info", systemImage: "info.circle")
}
.alertManager(alert)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import SwiftUI
extension AppView {
/// Button used in the Download section, launches, uninstalls or reinstalls the app
struct OpenAndManageView: View {
@StateObject var cask: Cask
@ObservedObject var cask: Cask
let deleteButton: Bool

@EnvironmentObject var caskManager: CaskManager
Expand Down Expand Up @@ -50,6 +50,8 @@ extension AppView {
}
.popover(isPresented: $showPopover) {
VStack(alignment: .leading, spacing: 6) {
GetInfoButton(cask: cask)

// Reinstall button
Button {
caskManager.reinstall(cask)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import SwiftUI

extension AppView {
struct UninstallButton: View {
@StateObject var cask: Cask
@ObservedObject var cask: Cask
@EnvironmentObject var caskManager: CaskManager

@State var showingError = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import SwiftUI

extension AppView {
struct UpdateButton: View {
@ObservedObject var cask: Cask
@EnvironmentObject var caskManager: CaskManager
@StateObject var cask: Cask

var body: some View {
Button {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,17 @@ extension DiscoverSectionView {
PlaceholderAppGroup()
}
}
}.background(GeometryReader { geometry in
Color.clear.preference(key: ViewOffsetKey.self,
value: -geometry.frame(in: .named("\(category.id)Scroll")).origin.x)
}
.background(GeometryReader { geometry in
Color.clear.preference(
key: ViewOffsetKey.self,
value: -geometry.frame(in: .named("\(category.id)Scroll")).origin.x
)
})
.onPreferenceChange(ViewOffsetKey.self) { value in
Task { @MainActor in
scrollOffset = value
}
}
.onPreferenceChange(ViewOffsetKey.self) { value in
Task { @MainActor in
scrollOffset = value
}
}
}
Expand Down
Loading

0 comments on commit 0f6d94a

Please sign in to comment.