Skip to content

Commit

Permalink
Add deprecated and disabled warnings
Browse files Browse the repository at this point in the history
  • Loading branch information
milanvarady committed Jan 13, 2025
1 parent 775db38 commit d239783
Show file tree
Hide file tree
Showing 11 changed files with 226 additions and 64 deletions.
8 changes: 8 additions & 0 deletions Applite.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
411EDDD72A9F58180051E07B /* URLExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 411EDDD62A9F58180051E07B /* URLExtension.swift */; };
4120AB652A754B1700F68EFE /* AppliteAppView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4120AB642A754B1700F68EFE /* AppliteAppView.swift */; };
4120AB682A755B5A00F68EFE /* CheckForUpdatesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4120AB672A755B5A00F68EFE /* CheckForUpdatesView.swift */; };
4122B4792D3574A6002E9D6E /* CaskWarning.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4122B4782D3574A6002E9D6E /* CaskWarning.swift */; };
4122B47B2D3576FB002E9D6E /* AppView+IconsAndWarnings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4122B47A2D3576FB002E9D6E /* AppView+IconsAndWarnings.swift */; };
4125BB8A29539907000FBD25 /* PlaceholderAppView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4125BB8929539907000FBD25 /* PlaceholderAppView.swift */; };
4126353E2A77C6EF00155034 /* ArrayExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4126353D2A77C6EF00155034 /* ArrayExtension.swift */; };
412635442A77FB1600155034 /* BrewInstallationProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 412635432A77FB1600155034 /* BrewInstallationProgress.swift */; };
Expand Down Expand Up @@ -156,6 +158,8 @@
411EDDD62A9F58180051E07B /* URLExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLExtension.swift; sourceTree = "<group>"; };
4120AB642A754B1700F68EFE /* AppliteAppView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppliteAppView.swift; sourceTree = "<group>"; };
4120AB672A755B5A00F68EFE /* CheckForUpdatesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckForUpdatesView.swift; sourceTree = "<group>"; };
4122B4782D3574A6002E9D6E /* CaskWarning.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaskWarning.swift; sourceTree = "<group>"; };
4122B47A2D3576FB002E9D6E /* AppView+IconsAndWarnings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppView+IconsAndWarnings.swift"; sourceTree = "<group>"; };
4125BB8929539907000FBD25 /* PlaceholderAppView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaceholderAppView.swift; sourceTree = "<group>"; };
4126353D2A77C6EF00155034 /* ArrayExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrayExtension.swift; sourceTree = "<group>"; };
412635432A77FB1600155034 /* BrewInstallationProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrewInstallationProgress.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -516,6 +520,7 @@
4192561D2D1DEBE700D9EF10 /* AppView+UninstallButton.swift */,
4192561F2D1DEC0D00D9EF10 /* AppView+UpdateButton.swift */,
419256B52D26BBBD00D9EF10 /* AppView+GetInfoButton.swift */,
4122B47A2D3576FB002E9D6E /* AppView+IconsAndWarnings.swift */,
);
path = "App View";
sourceTree = "<group>";
Expand Down Expand Up @@ -622,6 +627,7 @@
415135652D32C4570025DB70 /* Cask+Equtable.swift */,
415135672D32C4710025DB70 /* Cask+Hashable.swift */,
415135692D32C48A0025DB70 /* Cask+Comparable.swift */,
4122B4782D3574A6002E9D6E /* CaskWarning.swift */,
);
path = Cask;
sourceTree = "<group>";
Expand Down Expand Up @@ -849,6 +855,7 @@
419256572D1E0E5F00D9EF10 /* DiscoverSectionView+AppRow.swift in Sources */,
4192568F2D22DC9E00D9EF10 /* FontExtension.swift in Sources */,
419506A42964A27F00FE5802 /* SetupView.swift in Sources */,
4122B47B2D3576FB002E9D6E /* AppView+IconsAndWarnings.swift in Sources */,
4192561E2D1DEBE700D9EF10 /* AppView+UninstallButton.swift in Sources */,
413F872E2D33E1CA00D4BE10 /* HomeView+NoSearchResults.swift in Sources */,
4192569B2D24335900D9EF10 /* CaskTaskError.swift in Sources */,
Expand Down Expand Up @@ -892,6 +899,7 @@
4192569D2D2433E200D9EF10 /* CaskProgressState.swift in Sources */,
418F331C28EB3D540023D76F /* AppGridView.swift in Sources */,
419256332D1DF2E000D9EF10 /* SettingsView+BrewSettingsView.swift in Sources */,
4122B4792D3574A6002E9D6E /* CaskWarning.swift in Sources */,
419256962D2430C500D9EF10 /* CaskManager+LoadData.swift in Sources */,
419256552D1E0E2500D9EF10 /* DiscoverSectionView+CategoryHeader.swift in Sources */,
41062C972A3A20F900FD48EA /* UninstallSelf.swift in Sources */,
Expand Down
4 changes: 2 additions & 2 deletions Applite/Model/Cask Models/Cask/Cask.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ final class Cask: ObservableObject {
name: "Test",
description: "Test application",
homepageURL: URL(string: "https://aerolite.dev/"),
caveats: nil,
pkgInstaller: false
pkgInstaller: false,
warning: nil
), downloadsIn365days: 100)
}
29 changes: 29 additions & 0 deletions Applite/Model/Cask Models/Cask/CaskWarning.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// CaskWarning.swift
// Applite
//
// Created by Milán Várady on 2025.01.13.
//

import SwiftUI

enum CaskWarning: Codable {
case hasCaveat(caveat: String)
case deprecated(date: String, reason: String)
case disabled(date: String, reason: String)

var title: LocalizedStringKey {
switch self {
case .hasCaveat: return "App has Caveats"
case .deprecated: return "App is Deprecated"
case .disabled: return "App is Disabled"
}
}

var isDisabled: Bool {
switch self {
case .hasCaveat, .deprecated: return false
case .disabled: return true
}
}
}
18 changes: 15 additions & 3 deletions Applite/Model/Cask Models/CaskDTO.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,32 @@ struct CaskDTO: Decodable {
let token: String
let fullToken: String
let tap: String
let desc: String?
let nameArray: Array<String>
let desc: String?
let homepage: String
let caveats: String?
let url: String

let deprecated: Bool
let deprecationDate: String?
let deprecationReason: String?
let disabled: Bool
let disableDate: String?
let disableReason: String?

enum CodingKeys: String, CodingKey {
case token
case fullToken = "full_token"
case tap
case desc
case nameArray = "name"
case desc
case homepage
case caveats
case url
case deprecated
case deprecationDate = "deprecation_date"
case deprecationReason = "deprecation_reason"
case disabled
case disableDate = "disable_date"
case disableReason = "disable_reason"
}
}
18 changes: 13 additions & 5 deletions Applite/Model/Cask Models/CaskInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,9 @@ struct CaskInfo: Codable {
/// Short description
let description: String
let homepageURL: URL?
/// Description of any caveats with the app
let caveats: String?
/// If true app has a .pkg installer
let pkgInstaller: Bool
let warning: CaskWarning?

/// Initialize from a ``CaskDTO`` data transfer object
init(from decoder: Decoder) throws {
Expand All @@ -33,18 +32,27 @@ struct CaskInfo: Codable {
self.name = rawData.nameArray[safeIndex: 0] ?? "N/A"
self.description = rawData.desc ?? "N/A"
self.homepageURL = URL(string: rawData.homepage)
self.caveats = rawData.caveats
self.pkgInstaller = rawData.url.hasSuffix("pkg")

if rawData.disabled {
self.warning = .disabled(date: rawData.disableDate ?? "N/A", reason: rawData.disableReason ?? "N/A")
} else if rawData.deprecated {
self.warning = .deprecated(date: rawData.deprecationDate ?? "N/A", reason: rawData.deprecationReason ?? "N/A")
} else if let caveat = rawData.caveats {
self.warning = .hasCaveat(caveat: caveat)
} else {
self.warning = nil
}
}

init(token: String, fullToken: String, tap: String, name: String, description: String, homepageURL: URL?, caveats: String?, pkgInstaller: Bool) {
init(token: String, fullToken: String, tap: String, name: String, description: String, homepageURL: URL?, pkgInstaller: Bool, warning: CaskWarning?) {
self.token = token
self.fullToken = fullToken
self.tap = tap
self.name = name
self.description = description
self.homepageURL = homepageURL
self.caveats = caveats
self.pkgInstaller = pkgInstaller
self.warning = warning
}
}
34 changes: 25 additions & 9 deletions Applite/Views/App Views/App View/AppView+DownloadButton.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,42 +16,58 @@ extension AppView {

// Alerts
@State var showingPopover = false
@State var showingCaveats = false
@State var showingBrewError = false
@State var showingForceInstallConfirmation = false
@State var showCaveatsAndWarnings = false

@State var buttonFill = false

var body: some View {
/// Download button
Button {
if cask.info.caveats != nil {
// Show caveats dialog
showingCaveats = true
if cask.info.warning != nil {
// Show download confirmation
showCaveatsAndWarnings = true
return
}

caskManager.install(cask)
} label: {
Image(systemName: "arrow.down.to.line.circle\(buttonFill ? ".fill" : "")")
.font(.system(size: 22))
.foregroundColor(.accentColor)
if case .disabled(_, _) = cask.info.warning {
Image(systemName: "xmark.circle")
.foregroundStyle(.red)
.font(.system(size: 22))
} else {
Image(systemName: "arrow.down.to.line.circle\(buttonFill ? ".fill" : "")")
.foregroundStyle(Color.accentColor)
.font(.system(size: 22))
}
}
.disabled(cask.info.warning?.isDisabled ?? false)
.padding(.trailing, -8)
.onHover { isHovering in
// Hover effect
withAnimation(.snappy) {
buttonFill = isHovering
}
}
.alert("App caveats", isPresented: $showingCaveats) {
.alert(cask.info.warning?.title ?? "", isPresented: $showCaveatsAndWarnings) {
Button("Download Anyway") {
caskManager.install(cask)
}

Button("Cancel", role: .cancel) { }
} message: {
Text(cask.info.caveats ?? "")
if let warning = cask.info.warning {
switch warning {
case .hasCaveat(let caveat):
Text(caveat)
case .deprecated(let date, let reason):
Text("**This app is deprecated**\n**Reason:** \(reason)\n**Date:** \(date)")
case .disabled(let date, let reason):
Text("**This app is disabled**\n**Reason:** \(reason)\n**Date:** \(date)")
}
}
}
.alert("Broken Brew Path", isPresented: $showingBrewError) {} message: {
Text(DependencyManager.brokenPathOrIstallMessage)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,33 @@
import SwiftUI

extension AppView {
var iconAndDescriptionView: some View {
HStack {
if let iconURL = URL(string: "https://github.com/App-Fair/appcasks/releases/download/cask-\(cask.info.token)/AppIcon.png"),
let faviconURL = URL(string: "https://icon.horse/icon/\(cask.info.homepageURL?.host ?? "")") {
AppIconView(
iconURL: iconURL,
faviconURL: faviconURL,
cacheKey: cask.info.token
)
.padding(.leading, 5)
}

// Name and description
VStack(alignment: .leading) {
Text(cask.info.name)
.font(.system(size: 16, weight: .bold))
struct IconAndDescriptionView: View {
@ObservedObject var cask: Cask

Text(cask.info.description)
.foregroundColor(.secondary)
var body: some View {
HStack {
if let iconURL = URL(string: "https://github.com/App-Fair/appcasks/releases/download/cask-\(cask.info.token)/AppIcon.png"),
let faviconURL = URL(string: "https://icon.horse/icon/\(cask.info.homepageURL?.host ?? "")") {
AppIconView(
iconURL: iconURL,
faviconURL: faviconURL,
cacheKey: cask.info.token
)
.padding(.leading, 5)
}

// Name and description
VStack(alignment: .leading) {
Text(cask.info.name)
.font(.system(size: 16, weight: .bold))

Text(cask.info.description)
.foregroundColor(.secondary)
}

Spacer()
}

Spacer()
.contentShape(Rectangle())
}
.contentShape(Rectangle())
}
}
52 changes: 52 additions & 0 deletions Applite/Views/App Views/App View/AppView+IconsAndWarnings.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//
// AppView+IconsAndWarnings.swift
// Applite
//
// Created by Milán Várady on 2025.01.13.
//

import SwiftUI

extension AppView {
struct IconsAndWarnings: View {
@ObservedObject var cask: Cask

var body: some View {
// Show tap icon if from a third-party tap
if cask.info.tap != "homebrew/cask" {
InfoPopup(
text: "This app is from a third-party tap:\n`\(cask.info.tap)`",
sfSymbol: "spigot.fill"
)
.controlSize(.large)
}

if let warning = cask.info.warning {
Group {
switch warning {
case .hasCaveat(let caveat):
InfoPopup(
text: LocalizedStringKey(caveat),
sfSymbol: "exclamationmark.circle"
)

case .deprecated(let date, let reason):
InfoPopup(
text: "**This app is deprecated**\n**Reason:** \(reason)\n**Date:** \(date)",
sfSymbol: "exclamationmark.triangle.fill",
color: .orange
)

case .disabled(let date, let reason):
InfoPopup(
text: "**This app is disabled**\n**Reason:** \(reason)\n**Date:** \(date)",
sfSymbol: "exclamationmark.triangle.fill",
color: .red
)
}
}
.imageScale(.large)
}
}
}
}
13 changes: 2 additions & 11 deletions Applite/Views/App Views/App View/AppView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,8 @@ struct AppView: View {

var body: some View {
HStack {
// Icon name and description
iconAndDescriptionView

// Show tap icon if from a third-party tap
if cask.info.tap != "homebrew/cask" {
Image(systemName: "spigot.fill")
.controlSize(.large)
.help("This app is from a third-party tap")
}

// Buttons
IconAndDescriptionView(cask: cask)
IconsAndWarnings(cask: cask)
actionsView
}
.buttonStyle(.plain)
Expand Down
Loading

0 comments on commit d239783

Please sign in to comment.