mirror of
https://github.com/Whisky-App/Whisky.git
synced 2026-05-29 11:20:35 +00:00
Bug Fix: Program Configuration View Freezes (#1345)
* Quick FIx (#1343) * Fixes App Freeze on Program Configuration view by removing `.toolbar` method (side effect: Program icon removed from top bar). - modifying toolbar inside a NavigationStack somehow causes swiftUI into an infinite update loop. * Mitigated new SwiftLint rule #5263 (Prefer non-optional UTF8 String <-> Data conversion) * Quick FIx (#1343) [Amend 1] * Fixes App Freeze on Program Configuration view by removing `.toolbar` method (side effect: Program icon removed from top bar). - modifying toolbar inside a NavigationStack somehow causes swiftUI into an infinite update loop. * Mitigated new SwiftLint rule #5263 (Prefer non-optional UTF8 String <-> Data conversion) * Mitigated new SwiftLint rule #5845 (Optional Data -> String Conversion Violation: Prefer failable `String(bytes:encoding:)` initializer) ) * Quick FIx (#1343) [Amend 2] * Fixes App Freeze on Program Configuration view by removing `.toolbar` method (side effect: Program icon removed from top bar). - modifying toolbar inside a NavigationStack somehow causes swiftUI into an infinite update loop. * Mitigated new SwiftLint rule #5263 (Prefer non-optional UTF8 String <-> Data conversion) * Mitigated new SwiftLint rule #5845 (Optional Data -> String Conversion Violation: Prefer failable `String(bytes:encoding:)` initializer) ) * Bug FIx (#1343) * Fixes App Freeze on Program Configuration view by reimplementing program icon toolbar item. - `ToolbarItem` is uniquely identifiable and probably cached by SwiftUI internals, mutating its content / use a conflicting id will cause unexpected problems. - Now a new `ToolbarItem` will be created when its content updates. * Removed thread creation when fetching program icons - `.task` itself is async. * Mitigated new SwiftLint rules * Bug Fix (#1343) * Rectified a few spacing / indentation === Amended Commit === * Fixes App Freeze on Program Configuration view by reimplementing program icon toolbar item. - `ToolbarItem` is uniquely identifiable and probably cached by SwiftUI internals, mutating its content / use a conflicting id will cause unexpected problems. - Now a new `ToolbarItem` will be created when its content updates. * Removed thread creation when fetching program icons - `.task` itself is async. * Mitigated new SwiftLint rules
This commit is contained in:
@@ -81,19 +81,19 @@ class Winetricks {
|
||||
}
|
||||
|
||||
static func parseVerbs() async -> [WinetricksCategory] {
|
||||
var verbs: String?
|
||||
// Grab the verbs file
|
||||
let verbsURL = WhiskyWineInstaller.libraryFolder.appending(path: "verbs.txt")
|
||||
|
||||
do {
|
||||
let (data, _) = try await URLSession.shared.data(from: verbsURL)
|
||||
verbs = String(data: data, encoding: .utf8)
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
let verbs: String = await { () async -> String in
|
||||
do {
|
||||
let (data, _) = try await URLSession.shared.data(from: verbsURL)
|
||||
return String(data: data, encoding: .utf8) ?? String()
|
||||
} catch {
|
||||
return String()
|
||||
}
|
||||
}()
|
||||
|
||||
// Read the file line by line
|
||||
let lines = verbs?.components(separatedBy: "\n") ?? [""]
|
||||
let lines = verbs.components(separatedBy: "\n")
|
||||
var categories: [WinetricksCategory] = []
|
||||
var currentCategory: WinetricksCategory?
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@ import UniformTypeIdentifiers
|
||||
|
||||
struct ProgramView: View {
|
||||
@ObservedObject var program: Program
|
||||
@State var image: Image?
|
||||
@State var programLoading: Bool = false
|
||||
@State var cachedIconImage: Image?
|
||||
@AppStorage("configSectionExapnded") private var configSectionExpanded: Bool = true
|
||||
@AppStorage("envArgsSectionExpanded") private var envArgsSectionExpanded: Bool = true
|
||||
|
||||
@@ -48,9 +48,6 @@ struct ProgramView: View {
|
||||
}
|
||||
EnvironmentArgView(program: program, isExpanded: $envArgsSectionExpanded)
|
||||
}
|
||||
.formStyle(.grouped)
|
||||
.animation(.whiskyDefault, value: configSectionExpanded)
|
||||
.animation(.whiskyDefault, value: envArgsSectionExpanded)
|
||||
.bottomBar {
|
||||
HStack {
|
||||
Spacer()
|
||||
@@ -92,30 +89,29 @@ struct ProgramView: View {
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.navigationTitle(program.name)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigation) {
|
||||
Group {
|
||||
if let icon = image {
|
||||
icon
|
||||
.resizable()
|
||||
.frame(width: 25, height: 25)
|
||||
} else {
|
||||
Image(systemName: "app.dashed")
|
||||
.resizable()
|
||||
.frame(width: 25, height: 25)
|
||||
}
|
||||
if let image = cachedIconImage {
|
||||
ToolbarItem(id: "ProgramViewIcon", placement: .navigation) {
|
||||
image
|
||||
.resizable()
|
||||
.frame(width: 25, height: 25)
|
||||
.padding(.trailing, 5)
|
||||
}
|
||||
} else {
|
||||
ToolbarItem(id: "ProgramViewIcon", placement: .navigation) {
|
||||
Image(systemName: "app.dashed")
|
||||
.resizable()
|
||||
.frame(width: 25, height: 25)
|
||||
.padding(.trailing, 5)
|
||||
}
|
||||
.padding(.trailing, 5)
|
||||
}
|
||||
}
|
||||
.navigationTitle(program.name)
|
||||
.formStyle(.grouped)
|
||||
.animation(.whiskyDefault, value: configSectionExpanded)
|
||||
.animation(.whiskyDefault, value: envArgsSectionExpanded)
|
||||
.task {
|
||||
guard let peFile = program.peFile else { return }
|
||||
let task = Task.detached {
|
||||
guard let image = peFile.bestIcon() else { return nil as Image? }
|
||||
return Image(nsImage: image)
|
||||
}
|
||||
self.image = await task.value
|
||||
if let fetchedImage = program.peFile?.bestIcon() { self.cachedIconImage = Image(nsImage: fetchedImage) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,16 +177,24 @@ struct WhiskyApp: App {
|
||||
return
|
||||
}
|
||||
getconf.waitUntilExit()
|
||||
|
||||
let getconfOutput = pipe.fileHandleForReading.readDataToEndOfFile()
|
||||
if let getconfOutputString = String(data: getconfOutput, encoding: .utf8) {
|
||||
let d3dmPath = URL(fileURLWithPath: getconfOutputString.trimmingCharacters(in: .whitespacesAndNewlines))
|
||||
.appending(path: "d3dm").path
|
||||
do {
|
||||
try FileManager.default.removeItem(atPath: d3dmPath)
|
||||
} catch {
|
||||
return
|
||||
let getconfOutput = {() -> Data in
|
||||
if #available(macOS 10.15, *) {
|
||||
do {
|
||||
return try pipe.fileHandleForReading.readToEnd() ?? Data()
|
||||
} catch {
|
||||
return Data()
|
||||
}
|
||||
} else {
|
||||
return pipe.fileHandleForReading.readDataToEndOfFile()
|
||||
}
|
||||
}()
|
||||
guard let getconfOutputString = String(data: getconfOutput, encoding: .utf8) else {return}
|
||||
let d3dmPath = URL(fileURLWithPath: getconfOutputString.trimmingCharacters(in: .whitespacesAndNewlines))
|
||||
.appending(path: "d3dm").path
|
||||
do {
|
||||
try FileManager.default.removeItem(atPath: d3dmPath)
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,11 +121,11 @@ public extension Process {
|
||||
|
||||
extension FileHandle {
|
||||
func nextLine() -> String? {
|
||||
if let line = String(data: availableData, encoding: .utf8) {
|
||||
guard !line.isEmpty else { return nil }
|
||||
guard let line = String(data: availableData, encoding: .utf8) else { return nil }
|
||||
if !line.isEmpty {
|
||||
return line
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ extension PEFile {
|
||||
do {
|
||||
try handle.seek(toOffset: UInt64(offset))
|
||||
if let data = try handle.read(upToCount: 8) {
|
||||
let string = String(data: data, encoding: .utf8) ?? ""
|
||||
let string = String(data: data, encoding: .utf8) ?? String()
|
||||
self.name = string.replacingOccurrences(of: "\0", with: "")
|
||||
} else {
|
||||
self.name = ""
|
||||
|
||||
@@ -33,7 +33,7 @@ public class Tar {
|
||||
try process.run()
|
||||
|
||||
if let output = try pipe.fileHandleForReading.readToEnd() {
|
||||
let outputString = String(data: output, encoding: .utf8) ?? ""
|
||||
let outputString = String(data: output, encoding: .utf8) ?? String()
|
||||
process.waitUntilExit()
|
||||
let status = process.terminationStatus
|
||||
if status != 0 {
|
||||
@@ -54,7 +54,7 @@ public class Tar {
|
||||
try process.run()
|
||||
|
||||
if let output = try pipe.fileHandleForReading.readToEnd() {
|
||||
let outputString = String(data: output, encoding: .utf8) ?? ""
|
||||
let outputString = String(data: output, encoding: .utf8) ?? String()
|
||||
process.waitUntilExit()
|
||||
let status = process.terminationStatus
|
||||
if status != 0 {
|
||||
|
||||
Reference in New Issue
Block a user