Skip to content

Commit d239783

Browse files
committed
Add deprecated and disabled warnings
1 parent 775db38 commit d239783

File tree

11 files changed

+226
-64
lines changed

11 files changed

+226
-64
lines changed

Applite.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
411EDDD72A9F58180051E07B /* URLExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 411EDDD62A9F58180051E07B /* URLExtension.swift */; };
1616
4120AB652A754B1700F68EFE /* AppliteAppView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4120AB642A754B1700F68EFE /* AppliteAppView.swift */; };
1717
4120AB682A755B5A00F68EFE /* CheckForUpdatesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4120AB672A755B5A00F68EFE /* CheckForUpdatesView.swift */; };
18+
4122B4792D3574A6002E9D6E /* CaskWarning.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4122B4782D3574A6002E9D6E /* CaskWarning.swift */; };
19+
4122B47B2D3576FB002E9D6E /* AppView+IconsAndWarnings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4122B47A2D3576FB002E9D6E /* AppView+IconsAndWarnings.swift */; };
1820
4125BB8A29539907000FBD25 /* PlaceholderAppView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4125BB8929539907000FBD25 /* PlaceholderAppView.swift */; };
1921
4126353E2A77C6EF00155034 /* ArrayExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4126353D2A77C6EF00155034 /* ArrayExtension.swift */; };
2022
412635442A77FB1600155034 /* BrewInstallationProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 412635432A77FB1600155034 /* BrewInstallationProgress.swift */; };
@@ -156,6 +158,8 @@
156158
411EDDD62A9F58180051E07B /* URLExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLExtension.swift; sourceTree = "<group>"; };
157159
4120AB642A754B1700F68EFE /* AppliteAppView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppliteAppView.swift; sourceTree = "<group>"; };
158160
4120AB672A755B5A00F68EFE /* CheckForUpdatesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckForUpdatesView.swift; sourceTree = "<group>"; };
161+
4122B4782D3574A6002E9D6E /* CaskWarning.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaskWarning.swift; sourceTree = "<group>"; };
162+
4122B47A2D3576FB002E9D6E /* AppView+IconsAndWarnings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppView+IconsAndWarnings.swift"; sourceTree = "<group>"; };
159163
4125BB8929539907000FBD25 /* PlaceholderAppView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaceholderAppView.swift; sourceTree = "<group>"; };
160164
4126353D2A77C6EF00155034 /* ArrayExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrayExtension.swift; sourceTree = "<group>"; };
161165
412635432A77FB1600155034 /* BrewInstallationProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrewInstallationProgress.swift; sourceTree = "<group>"; };
@@ -516,6 +520,7 @@
516520
4192561D2D1DEBE700D9EF10 /* AppView+UninstallButton.swift */,
517521
4192561F2D1DEC0D00D9EF10 /* AppView+UpdateButton.swift */,
518522
419256B52D26BBBD00D9EF10 /* AppView+GetInfoButton.swift */,
523+
4122B47A2D3576FB002E9D6E /* AppView+IconsAndWarnings.swift */,
519524
);
520525
path = "App View";
521526
sourceTree = "<group>";
@@ -622,6 +627,7 @@
622627
415135652D32C4570025DB70 /* Cask+Equtable.swift */,
623628
415135672D32C4710025DB70 /* Cask+Hashable.swift */,
624629
415135692D32C48A0025DB70 /* Cask+Comparable.swift */,
630+
4122B4782D3574A6002E9D6E /* CaskWarning.swift */,
625631
);
626632
path = Cask;
627633
sourceTree = "<group>";
@@ -849,6 +855,7 @@
849855
419256572D1E0E5F00D9EF10 /* DiscoverSectionView+AppRow.swift in Sources */,
850856
4192568F2D22DC9E00D9EF10 /* FontExtension.swift in Sources */,
851857
419506A42964A27F00FE5802 /* SetupView.swift in Sources */,
858+
4122B47B2D3576FB002E9D6E /* AppView+IconsAndWarnings.swift in Sources */,
852859
4192561E2D1DEBE700D9EF10 /* AppView+UninstallButton.swift in Sources */,
853860
413F872E2D33E1CA00D4BE10 /* HomeView+NoSearchResults.swift in Sources */,
854861
4192569B2D24335900D9EF10 /* CaskTaskError.swift in Sources */,
@@ -892,6 +899,7 @@
892899
4192569D2D2433E200D9EF10 /* CaskProgressState.swift in Sources */,
893900
418F331C28EB3D540023D76F /* AppGridView.swift in Sources */,
894901
419256332D1DF2E000D9EF10 /* SettingsView+BrewSettingsView.swift in Sources */,
902+
4122B4792D3574A6002E9D6E /* CaskWarning.swift in Sources */,
895903
419256962D2430C500D9EF10 /* CaskManager+LoadData.swift in Sources */,
896904
419256552D1E0E2500D9EF10 /* DiscoverSectionView+CategoryHeader.swift in Sources */,
897905
41062C972A3A20F900FD48EA /* UninstallSelf.swift in Sources */,

Applite/Model/Cask Models/Cask/Cask.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ final class Cask: ObservableObject {
4141
name: "Test",
4242
description: "Test application",
4343
homepageURL: URL(string: "https://aerolite.dev/"),
44-
caveats: nil,
45-
pkgInstaller: false
44+
pkgInstaller: false,
45+
warning: nil
4646
), downloadsIn365days: 100)
4747
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//
2+
// CaskWarning.swift
3+
// Applite
4+
//
5+
// Created by Milán Várady on 2025.01.13.
6+
//
7+
8+
import SwiftUI
9+
10+
enum CaskWarning: Codable {
11+
case hasCaveat(caveat: String)
12+
case deprecated(date: String, reason: String)
13+
case disabled(date: String, reason: String)
14+
15+
var title: LocalizedStringKey {
16+
switch self {
17+
case .hasCaveat: return "App has Caveats"
18+
case .deprecated: return "App is Deprecated"
19+
case .disabled: return "App is Disabled"
20+
}
21+
}
22+
23+
var isDisabled: Bool {
24+
switch self {
25+
case .hasCaveat, .deprecated: return false
26+
case .disabled: return true
27+
}
28+
}
29+
}

Applite/Model/Cask Models/CaskDTO.swift

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,32 @@ struct CaskDTO: Decodable {
1313
let token: String
1414
let fullToken: String
1515
let tap: String
16-
let desc: String?
1716
let nameArray: Array<String>
17+
let desc: String?
1818
let homepage: String
1919
let caveats: String?
2020
let url: String
21-
21+
let deprecated: Bool
22+
let deprecationDate: String?
23+
let deprecationReason: String?
24+
let disabled: Bool
25+
let disableDate: String?
26+
let disableReason: String?
27+
2228
enum CodingKeys: String, CodingKey {
2329
case token
2430
case fullToken = "full_token"
2531
case tap
26-
case desc
2732
case nameArray = "name"
33+
case desc
2834
case homepage
2935
case caveats
3036
case url
37+
case deprecated
38+
case deprecationDate = "deprecation_date"
39+
case deprecationReason = "deprecation_reason"
40+
case disabled
41+
case disableDate = "disable_date"
42+
case disableReason = "disable_reason"
3143
}
3244
}

Applite/Model/Cask Models/CaskInfo.swift

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,9 @@ struct CaskInfo: Codable {
1818
/// Short description
1919
let description: String
2020
let homepageURL: URL?
21-
/// Description of any caveats with the app
22-
let caveats: String?
2321
/// If true app has a .pkg installer
2422
let pkgInstaller: Bool
23+
let warning: CaskWarning?
2524

2625
/// Initialize from a ``CaskDTO`` data transfer object
2726
init(from decoder: Decoder) throws {
@@ -33,18 +32,27 @@ struct CaskInfo: Codable {
3332
self.name = rawData.nameArray[safeIndex: 0] ?? "N/A"
3433
self.description = rawData.desc ?? "N/A"
3534
self.homepageURL = URL(string: rawData.homepage)
36-
self.caveats = rawData.caveats
3735
self.pkgInstaller = rawData.url.hasSuffix("pkg")
36+
37+
if rawData.disabled {
38+
self.warning = .disabled(date: rawData.disableDate ?? "N/A", reason: rawData.disableReason ?? "N/A")
39+
} else if rawData.deprecated {
40+
self.warning = .deprecated(date: rawData.deprecationDate ?? "N/A", reason: rawData.deprecationReason ?? "N/A")
41+
} else if let caveat = rawData.caveats {
42+
self.warning = .hasCaveat(caveat: caveat)
43+
} else {
44+
self.warning = nil
45+
}
3846
}
3947

40-
init(token: String, fullToken: String, tap: String, name: String, description: String, homepageURL: URL?, caveats: String?, pkgInstaller: Bool) {
48+
init(token: String, fullToken: String, tap: String, name: String, description: String, homepageURL: URL?, pkgInstaller: Bool, warning: CaskWarning?) {
4149
self.token = token
4250
self.fullToken = fullToken
4351
self.tap = tap
4452
self.name = name
4553
self.description = description
4654
self.homepageURL = homepageURL
47-
self.caveats = caveats
4855
self.pkgInstaller = pkgInstaller
56+
self.warning = warning
4957
}
5058
}

Applite/Views/App Views/App View/AppView+DownloadButton.swift

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,42 +16,58 @@ extension AppView {
1616

1717
// Alerts
1818
@State var showingPopover = false
19-
@State var showingCaveats = false
2019
@State var showingBrewError = false
2120
@State var showingForceInstallConfirmation = false
21+
@State var showCaveatsAndWarnings = false
2222

2323
@State var buttonFill = false
2424

2525
var body: some View {
2626
/// Download button
2727
Button {
28-
if cask.info.caveats != nil {
29-
// Show caveats dialog
30-
showingCaveats = true
28+
if cask.info.warning != nil {
29+
// Show download confirmation
30+
showCaveatsAndWarnings = true
3131
return
3232
}
3333

3434
caskManager.install(cask)
3535
} label: {
36-
Image(systemName: "arrow.down.to.line.circle\(buttonFill ? ".fill" : "")")
37-
.font(.system(size: 22))
38-
.foregroundColor(.accentColor)
36+
if case .disabled(_, _) = cask.info.warning {
37+
Image(systemName: "xmark.circle")
38+
.foregroundStyle(.red)
39+
.font(.system(size: 22))
40+
} else {
41+
Image(systemName: "arrow.down.to.line.circle\(buttonFill ? ".fill" : "")")
42+
.foregroundStyle(Color.accentColor)
43+
.font(.system(size: 22))
44+
}
3945
}
46+
.disabled(cask.info.warning?.isDisabled ?? false)
4047
.padding(.trailing, -8)
4148
.onHover { isHovering in
4249
// Hover effect
4350
withAnimation(.snappy) {
4451
buttonFill = isHovering
4552
}
4653
}
47-
.alert("App caveats", isPresented: $showingCaveats) {
54+
.alert(cask.info.warning?.title ?? "", isPresented: $showCaveatsAndWarnings) {
4855
Button("Download Anyway") {
4956
caskManager.install(cask)
5057
}
5158

5259
Button("Cancel", role: .cancel) { }
5360
} message: {
54-
Text(cask.info.caveats ?? "")
61+
if let warning = cask.info.warning {
62+
switch warning {
63+
case .hasCaveat(let caveat):
64+
Text(caveat)
65+
case .deprecated(let date, let reason):
66+
Text("**This app is deprecated**\n**Reason:** \(reason)\n**Date:** \(date)")
67+
case .disabled(let date, let reason):
68+
Text("**This app is disabled**\n**Reason:** \(reason)\n**Date:** \(date)")
69+
}
70+
}
5571
}
5672
.alert("Broken Brew Path", isPresented: $showingBrewError) {} message: {
5773
Text(DependencyManager.brokenPathOrIstallMessage)

Applite/Views/App Views/App View/AppView+IconAndDescriptionView.swift

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,29 +8,33 @@
88
import SwiftUI
99

1010
extension AppView {
11-
var iconAndDescriptionView: some View {
12-
HStack {
13-
if let iconURL = URL(string: "https://github.com/App-Fair/appcasks/releases/download/cask-\(cask.info.token)/AppIcon.png"),
14-
let faviconURL = URL(string: "https://icon.horse/icon/\(cask.info.homepageURL?.host ?? "")") {
15-
AppIconView(
16-
iconURL: iconURL,
17-
faviconURL: faviconURL,
18-
cacheKey: cask.info.token
19-
)
20-
.padding(.leading, 5)
21-
}
22-
23-
// Name and description
24-
VStack(alignment: .leading) {
25-
Text(cask.info.name)
26-
.font(.system(size: 16, weight: .bold))
11+
struct IconAndDescriptionView: View {
12+
@ObservedObject var cask: Cask
2713

28-
Text(cask.info.description)
29-
.foregroundColor(.secondary)
14+
var body: some View {
15+
HStack {
16+
if let iconURL = URL(string: "https://github.com/App-Fair/appcasks/releases/download/cask-\(cask.info.token)/AppIcon.png"),
17+
let faviconURL = URL(string: "https://icon.horse/icon/\(cask.info.homepageURL?.host ?? "")") {
18+
AppIconView(
19+
iconURL: iconURL,
20+
faviconURL: faviconURL,
21+
cacheKey: cask.info.token
22+
)
23+
.padding(.leading, 5)
24+
}
25+
26+
// Name and description
27+
VStack(alignment: .leading) {
28+
Text(cask.info.name)
29+
.font(.system(size: 16, weight: .bold))
30+
31+
Text(cask.info.description)
32+
.foregroundColor(.secondary)
33+
}
34+
35+
Spacer()
3036
}
31-
32-
Spacer()
37+
.contentShape(Rectangle())
3338
}
34-
.contentShape(Rectangle())
3539
}
3640
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//
2+
// AppView+IconsAndWarnings.swift
3+
// Applite
4+
//
5+
// Created by Milán Várady on 2025.01.13.
6+
//
7+
8+
import SwiftUI
9+
10+
extension AppView {
11+
struct IconsAndWarnings: View {
12+
@ObservedObject var cask: Cask
13+
14+
var body: some View {
15+
// Show tap icon if from a third-party tap
16+
if cask.info.tap != "homebrew/cask" {
17+
InfoPopup(
18+
text: "This app is from a third-party tap:\n`\(cask.info.tap)`",
19+
sfSymbol: "spigot.fill"
20+
)
21+
.controlSize(.large)
22+
}
23+
24+
if let warning = cask.info.warning {
25+
Group {
26+
switch warning {
27+
case .hasCaveat(let caveat):
28+
InfoPopup(
29+
text: LocalizedStringKey(caveat),
30+
sfSymbol: "exclamationmark.circle"
31+
)
32+
33+
case .deprecated(let date, let reason):
34+
InfoPopup(
35+
text: "**This app is deprecated**\n**Reason:** \(reason)\n**Date:** \(date)",
36+
sfSymbol: "exclamationmark.triangle.fill",
37+
color: .orange
38+
)
39+
40+
case .disabled(let date, let reason):
41+
InfoPopup(
42+
text: "**This app is disabled**\n**Reason:** \(reason)\n**Date:** \(date)",
43+
sfSymbol: "exclamationmark.triangle.fill",
44+
color: .red
45+
)
46+
}
47+
}
48+
.imageScale(.large)
49+
}
50+
}
51+
}
52+
}

Applite/Views/App Views/App View/AppView.swift

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,8 @@ struct AppView: View {
3838

3939
var body: some View {
4040
HStack {
41-
// Icon name and description
42-
iconAndDescriptionView
43-
44-
// Show tap icon if from a third-party tap
45-
if cask.info.tap != "homebrew/cask" {
46-
Image(systemName: "spigot.fill")
47-
.controlSize(.large)
48-
.help("This app is from a third-party tap")
49-
}
50-
51-
// Buttons
41+
IconAndDescriptionView(cask: cask)
42+
IconsAndWarnings(cask: cask)
5243
actionsView
5344
}
5445
.buttonStyle(.plain)

0 commit comments

Comments
 (0)