diff --git a/Whisky.xcodeproj/project.pbxproj b/Whisky.xcodeproj/project.pbxproj index e49529ef8..cec03433c 100644 --- a/Whisky.xcodeproj/project.pbxproj +++ b/Whisky.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ 6365C4C12B1AA69D00AAE1FD /* Animation+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6365C4C02B1AA69D00AAE1FD /* Animation+Extensions.swift */; }; 6365C4C32B1AA8CD00AAE1FD /* BottleListEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6365C4C22B1AA8CD00AAE1FD /* BottleListEntry.swift */; }; 63FFDE862ADF0C7700178665 /* BottomBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63FFDE852ADF0C7700178665 /* BottomBar.swift */; }; + 67D278512BC5907E006F9A1E /* ActionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67D278502BC5907E006F9A1E /* ActionView.swift */; }; 6E064B1229DD32A200D9A2D2 /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = 6E064B1129DD32A200D9A2D2 /* Sparkle */; }; 6E064B1429DD331F00D9A2D2 /* SparkleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E064B1329DD331F00D9A2D2 /* SparkleView.swift */; }; 6E17B6462AF3FDC100831173 /* PinView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E17B6452AF3FDC100831173 /* PinView.swift */; }; @@ -112,6 +113,7 @@ 6365C4C02B1AA69D00AAE1FD /* Animation+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Animation+Extensions.swift"; sourceTree = ""; }; 6365C4C22B1AA8CD00AAE1FD /* BottleListEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottleListEntry.swift; sourceTree = ""; }; 63FFDE852ADF0C7700178665 /* BottomBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BottomBar.swift; sourceTree = ""; }; + 67D278502BC5907E006F9A1E /* ActionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionView.swift; sourceTree = ""; }; 6E064B1329DD331F00D9A2D2 /* SparkleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SparkleView.swift; sourceTree = ""; }; 6E17B6452AF3FDC100831173 /* PinView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PinView.swift; sourceTree = ""; }; 6E17B6482AF4118F00831173 /* EnvironmentArgView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnvironmentArgView.swift; sourceTree = ""; }; @@ -209,6 +211,7 @@ children = ( 63FFDE852ADF0C7700178665 /* BottomBar.swift */, 6330DD952B1B0EA4007A625A /* RenameView.swift */, + 67D278502BC5907E006F9A1E /* ActionView.swift */, ); path = Common; sourceTree = ""; @@ -582,6 +585,7 @@ EEA5A2462A31DD65008274AE /* AppDelegate.swift in Sources */, 6E70A4A12A9A280C007799E9 /* WhiskyCmd.swift in Sources */, 6E40495829CCA19C006E3F1B /* ContentView.swift in Sources */, + 67D278512BC5907E006F9A1E /* ActionView.swift in Sources */, 6EF557982A410599001A4F09 /* SetupView.swift in Sources */, 6E355E5A29D782B2002D83BE /* ProgramsView.swift in Sources */, DB696FC82AFAE5DA0037EB2F /* PinCreationView.swift in Sources */, diff --git a/Whisky/Views/Bottle/BottleCreationView.swift b/Whisky/Views/Bottle/BottleCreationView.swift index 8636bf5f6..f98fa3088 100644 --- a/Whisky/Views/Bottle/BottleCreationView.swift +++ b/Whisky/Views/Bottle/BottleCreationView.swift @@ -26,7 +26,6 @@ struct BottleCreationView: View { @State private var newBottleVersion: WinVersion = .win10 @State private var newBottleURL: URL = UserDefaults.standard.url(forKey: "defaultBottleLocation") ?? BottleData.defaultBottleDir - @State private var bottlePath: String = "" @State private var nameValid: Bool = false @Environment(\.dismiss) private var dismiss @@ -45,34 +44,21 @@ struct BottleCreationView: View { } } - HStack { - VStack(alignment: .leading) { - Text("create.path") - .foregroundStyle(.primary) - Text(bottlePath) - .foregroundStyle(.secondary) - .truncationMode(.middle) - .lineLimit(2) - .help(bottlePath) - } - - Spacer() - Button { - let panel = NSOpenPanel() - panel.canChooseFiles = false - panel.canChooseDirectories = true - panel.allowsMultipleSelection = false - panel.canCreateDirectories = true - panel.directoryURL = BottleData.containerDir - panel.begin { result in - if result == .OK { - if let url = panel.urls.first { - newBottleURL = url - } - } + ActionView( + text: "create.path", + subtitle: newBottleURL.prettyPath(), + actionName: "create.browse" + ) { + let panel = NSOpenPanel() + panel.canChooseFiles = false + panel.canChooseDirectories = true + panel.allowsMultipleSelection = false + panel.canCreateDirectories = true + panel.directoryURL = BottleData.containerDir + panel.begin { result in + if result == .OK, let url = panel.urls.first { + newBottleURL = url } - } label: { - Text("create.browse") } } } @@ -93,12 +79,6 @@ struct BottleCreationView: View { .disabled(!nameValid) } } - .onChange(of: newBottleURL) { - bottlePath = newBottleURL.prettyPath() - } - .onAppear { - bottlePath = newBottleURL.prettyPath() - } .onSubmit { submit() } diff --git a/Whisky/Views/Bottle/Pins/PinCreationView.swift b/Whisky/Views/Bottle/Pins/PinCreationView.swift index eada6be91..175ed18a5 100644 --- a/Whisky/Views/Bottle/Pins/PinCreationView.swift +++ b/Whisky/Views/Bottle/Pins/PinCreationView.swift @@ -35,35 +35,23 @@ struct PinCreationView: View { Form { TextField("pin.name", text: $newPinName) - HStack { - VStack(alignment: .leading) { - Text("pin.path") - .foregroundStyle(.primary) - Text(pinPath) - .foregroundStyle(.secondary) - .truncationMode(.middle) - .lineLimit(2) - .help(pinPath) - } - - Spacer() - - Button("create.browse") { - let panel = NSOpenPanel() - panel.canChooseFiles = true - panel.allowedContentTypes = [UTType.exe, - UTType(exportedAs: "com.microsoft.msi-installer"), - UTType(exportedAs: "com.microsoft.bat")] - panel.directoryURL = newPinURL ?? bottle.url.appending(path: "drive_c") - panel.canChooseDirectories = false - panel.allowsMultipleSelection = false - panel.canCreateDirectories = false - panel.begin { result in - if result == .OK { - if let url = panel.urls.first { - newPinURL = url - } - } + ActionView( + text: "pin.path", + subtitle: pinPath, + actionName: "create.browse" + ) { + let panel = NSOpenPanel() + panel.canChooseFiles = true + panel.allowedContentTypes = [UTType.exe, + UTType(exportedAs: "com.microsoft.msi-installer"), + UTType(exportedAs: "com.microsoft.bat")] + panel.directoryURL = newPinURL ?? bottle.url.appending(path: "drive_c") + panel.canChooseDirectories = false + panel.allowsMultipleSelection = false + panel.canCreateDirectories = false + panel.begin { result in + if result == .OK, let url = panel.urls.first { + newPinURL = url } } } diff --git a/Whisky/Views/Common/ActionView.swift b/Whisky/Views/Common/ActionView.swift new file mode 100644 index 000000000..dee071d49 --- /dev/null +++ b/Whisky/Views/Common/ActionView.swift @@ -0,0 +1,60 @@ +// +// ActionView.swift +// Whisky +// +// This file is part of Whisky. +// +// Whisky is free software: you can redistribute it and/or modify it under the terms +// of the GNU General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Whisky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; +// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along with Whisky. +// If not, see https://www.gnu.org/licenses/. +// + +import SwiftUI + +struct ActionView: View { + let text: LocalizedStringKey + let subtitle: String + let actionName: LocalizedStringKey + let action: () -> Void + + init( + text: LocalizedStringKey, + subtitle: String = "", + actionName: LocalizedStringKey, + action: @escaping () -> Void + ) { + self.text = text + self.subtitle = subtitle + self.actionName = actionName + self.action = action + } + + var body: some View { + HStack(alignment: subtitle.isEmpty ? .center : .top) { + VStack(alignment: .leading) { + Text(text) + .foregroundStyle(.primary) + + if !subtitle.isEmpty { + Text(subtitle) + .font(.callout) + .foregroundStyle(.secondary) + .truncationMode(.middle) + .lineLimit(2) + .help(subtitle) + } + } + Spacer() + Button(actionName) { + action() + } + } + } +} diff --git a/Whisky/Views/Settings/SettingsView.swift b/Whisky/Views/Settings/SettingsView.swift index 9dc938a8e..6cac55f5b 100644 --- a/Whisky/Views/Settings/SettingsView.swift +++ b/Whisky/Views/Settings/SettingsView.swift @@ -25,40 +25,25 @@ struct SettingsView: View { @AppStorage("checkWhiskyWineUpdates") var checkWhiskyWineUpdates = true @AppStorage("defaultBottleLocation") var defaultBottleLocation = BottleData.defaultBottleDir - @State private var bottlePath: String = "" - var body: some View { Form { Section("settings.general") { Toggle("settings.toggle.kill.on.terminate", isOn: $killOnTerminate) - HStack { - VStack(alignment: .leading) { - Text("settings.path") - .foregroundStyle(.primary) - Text(bottlePath) - .foregroundStyle(.secondary) - .truncationMode(.middle) - .lineLimit(2) - .help(bottlePath) - } - - Spacer() - Button { - let panel = NSOpenPanel() - panel.canChooseFiles = false - panel.canChooseDirectories = true - panel.allowsMultipleSelection = false - panel.canCreateDirectories = true - panel.directoryURL = BottleData.containerDir - panel.begin { result in - if result == .OK { - if let url = panel.urls.first { - defaultBottleLocation = url - } - } + ActionView( + text: "settings.path", + subtitle: defaultBottleLocation.prettyPath(), + actionName: "create.browse" + ) { + let panel = NSOpenPanel() + panel.canChooseFiles = false + panel.canChooseDirectories = true + panel.allowsMultipleSelection = false + panel.canCreateDirectories = true + panel.directoryURL = BottleData.containerDir + panel.begin { result in + if result == .OK, let url = panel.urls.first { + defaultBottleLocation = url } - } label: { - Text("create.browse") } } } @@ -69,12 +54,6 @@ struct SettingsView: View { } .formStyle(.grouped) .frame(width: 500, height: 250) - .onChange(of: defaultBottleLocation) { - bottlePath = defaultBottleLocation.prettyPath() - } - .onAppear { - bottlePath = defaultBottleLocation.prettyPath() - } } }