mirror of
https://github.com/ninxsoft/Mist.git
synced 2025-05-30 15:05:18 -04:00
Add copy to clipboard for Firmwares (#119)
This commit is contained in:
parent
e9ad636584
commit
82f5b049e7
5 changed files with 102 additions and 23 deletions
|
@ -93,6 +93,7 @@
|
||||||
398734D028603D9E00B4C357 /* UInt8+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 398734CF28603D9E00B4C357 /* UInt8+Extension.swift */; };
|
398734D028603D9E00B4C357 /* UInt8+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 398734CF28603D9E00B4C357 /* UInt8+Extension.swift */; };
|
||||||
398734D228603DE700B4C357 /* [UInt8]+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 398734D128603DE700B4C357 /* [UInt8]+Extension.swift */; };
|
398734D228603DE700B4C357 /* [UInt8]+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 398734D128603DE700B4C357 /* [UInt8]+Extension.swift */; };
|
||||||
398734D4286046B000B4C357 /* UInt32+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 398734D3286046B000B4C357 /* UInt32+Extension.swift */; };
|
398734D4286046B000B4C357 /* UInt32+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 398734D3286046B000B4C357 /* UInt32+Extension.swift */; };
|
||||||
|
398BE6B52B62450500FE0C29 /* FloatingAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 398BE6B42B62450500FE0C29 /* FloatingAlert.swift */; };
|
||||||
39CA25E32941D8BB0030711E /* FileAttributesUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39CA25E22941D8BB0030711E /* FileAttributesUpdater.swift */; };
|
39CA25E32941D8BB0030711E /* FileAttributesUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39CA25E22941D8BB0030711E /* FileAttributesUpdater.swift */; };
|
||||||
39CB5E3D293F5C2E00CFDBB8 /* Catalog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39CB5E3C293F5C2E00CFDBB8 /* Catalog.swift */; };
|
39CB5E3D293F5C2E00CFDBB8 /* Catalog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39CB5E3C293F5C2E00CFDBB8 /* Catalog.swift */; };
|
||||||
39CB5E3F2941486D00CFDBB8 /* CatalogSeedType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39CB5E3E2941486D00CFDBB8 /* CatalogSeedType.swift */; };
|
39CB5E3F2941486D00CFDBB8 /* CatalogSeedType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39CB5E3E2941486D00CFDBB8 /* CatalogSeedType.swift */; };
|
||||||
|
@ -250,6 +251,7 @@
|
||||||
398734CF28603D9E00B4C357 /* UInt8+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UInt8+Extension.swift"; sourceTree = "<group>"; };
|
398734CF28603D9E00B4C357 /* UInt8+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UInt8+Extension.swift"; sourceTree = "<group>"; };
|
||||||
398734D128603DE700B4C357 /* [UInt8]+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "[UInt8]+Extension.swift"; sourceTree = "<group>"; };
|
398734D128603DE700B4C357 /* [UInt8]+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "[UInt8]+Extension.swift"; sourceTree = "<group>"; };
|
||||||
398734D3286046B000B4C357 /* UInt32+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UInt32+Extension.swift"; sourceTree = "<group>"; };
|
398734D3286046B000B4C357 /* UInt32+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UInt32+Extension.swift"; sourceTree = "<group>"; };
|
||||||
|
398BE6B42B62450500FE0C29 /* FloatingAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingAlert.swift; sourceTree = "<group>"; };
|
||||||
39CA25E22941D8BB0030711E /* FileAttributesUpdater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileAttributesUpdater.swift; sourceTree = "<group>"; };
|
39CA25E22941D8BB0030711E /* FileAttributesUpdater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileAttributesUpdater.swift; sourceTree = "<group>"; };
|
||||||
39CB5E3C293F5C2E00CFDBB8 /* Catalog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Catalog.swift; sourceTree = "<group>"; };
|
39CB5E3C293F5C2E00CFDBB8 /* Catalog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Catalog.swift; sourceTree = "<group>"; };
|
||||||
39CB5E3E2941486D00CFDBB8 /* CatalogSeedType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CatalogSeedType.swift; sourceTree = "<group>"; };
|
39CB5E3E2941486D00CFDBB8 /* CatalogSeedType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CatalogSeedType.swift; sourceTree = "<group>"; };
|
||||||
|
@ -538,6 +540,7 @@
|
||||||
children = (
|
children = (
|
||||||
39252AA2285C3CC400956C74 /* CodesigningPickerView.swift */,
|
39252AA2285C3CC400956C74 /* CodesigningPickerView.swift */,
|
||||||
39252AA4285C463A00956C74 /* DynamicTextView.swift */,
|
39252AA4285C463A00956C74 /* DynamicTextView.swift */,
|
||||||
|
398BE6B42B62450500FE0C29 /* FloatingAlert.swift */,
|
||||||
39252A86285ACE9C00956C74 /* FooterText.swift */,
|
39252A86285ACE9C00956C74 /* FooterText.swift */,
|
||||||
5795700C2A31B081004C7051 /* MistActionButtonStyle.swift */,
|
5795700C2A31B081004C7051 /* MistActionButtonStyle.swift */,
|
||||||
39252AA0285C2A1600956C74 /* PaddedDivider.swift */,
|
39252AA0285C2A1600956C74 /* PaddedDivider.swift */,
|
||||||
|
@ -843,6 +846,7 @@
|
||||||
39FF05F62859850F00A86670 /* SettingsFirmwaresView.swift in Sources */,
|
39FF05F62859850F00A86670 /* SettingsFirmwaresView.swift in Sources */,
|
||||||
3935F4A6286AD3E100760AB0 /* ActivityHeaderView.swift in Sources */,
|
3935F4A6286AD3E100760AB0 /* ActivityHeaderView.swift in Sources */,
|
||||||
3935F480286551FB00760AB0 /* Double+Extension.swift in Sources */,
|
3935F480286551FB00760AB0 /* Double+Extension.swift in Sources */,
|
||||||
|
398BE6B52B62450500FE0C29 /* FloatingAlert.swift in Sources */,
|
||||||
39252ABD285C8FFC00956C74 /* ListRowInstaller.swift in Sources */,
|
39252ABD285C8FFC00956C74 /* ListRowInstaller.swift in Sources */,
|
||||||
3935F49D286ABE4D00760AB0 /* FooterView.swift in Sources */,
|
3935F49D286ABE4D00760AB0 /* FooterView.swift in Sources */,
|
||||||
390451CC2856F23100E0B563 /* ScaledSystemImage.swift in Sources */,
|
390451CC2856F23100E0B563 /* ScaledSystemImage.swift in Sources */,
|
||||||
|
|
38
Mist/Views/Components/FloatingAlert.swift
Normal file
38
Mist/Views/Components/FloatingAlert.swift
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
//
|
||||||
|
// FloatingAlert.swift
|
||||||
|
// Mist
|
||||||
|
//
|
||||||
|
// Created by Nindi Gill on 25/1/2024.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct FloatingAlert: View {
|
||||||
|
var image: String
|
||||||
|
var message: String
|
||||||
|
private let length: CGFloat = 200
|
||||||
|
private let imageLength: CGFloat = 160
|
||||||
|
private let cornerRadius: CGFloat = 20
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack {
|
||||||
|
Image(systemName: image)
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
Text(message)
|
||||||
|
.font(.title)
|
||||||
|
.fontWeight(.medium)
|
||||||
|
}
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
.padding()
|
||||||
|
.frame(width: length, height: length)
|
||||||
|
.background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: cornerRadius))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FloatingAlert_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
FloatingAlert(image: "list.bullet.clipboard.fill", message: "Copied to Clipboard")
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,6 +21,7 @@ struct ContentView: View {
|
||||||
@State private var searchString: String = ""
|
@State private var searchString: String = ""
|
||||||
@State private var openPanel: NSOpenPanel = .init()
|
@State private var openPanel: NSOpenPanel = .init()
|
||||||
@State private var savePanel: NSSavePanel = .init()
|
@State private var savePanel: NSSavePanel = .init()
|
||||||
|
@State private var copiedToClipboard: Bool = false
|
||||||
@StateObject private var taskManager: TaskManager = .shared
|
@StateObject private var taskManager: TaskManager = .shared
|
||||||
private var filteredFirmwares: [Firmware] {
|
private var filteredFirmwares: [Firmware] {
|
||||||
var filteredFirmwares: [Firmware] = firmwares
|
var filteredFirmwares: [Firmware] = firmwares
|
||||||
|
@ -74,29 +75,35 @@ struct ContentView: View {
|
||||||
private let height: CGFloat = 720
|
private let height: CGFloat = 720
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
// swiftlint:disable:next closure_body_length
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
HeaderView(downloadType: $downloadType)
|
HeaderView(downloadType: $downloadType)
|
||||||
Divider()
|
Divider()
|
||||||
if downloadType == .firmware && filteredFirmwares.isEmpty || downloadType == .installer && filteredInstallers.isEmpty {
|
if downloadType == .firmware && filteredFirmwares.isEmpty || downloadType == .installer && filteredInstallers.isEmpty {
|
||||||
EmptyCollectionView("No macOS \(downloadType.description)s found!\n\nಥ_ಥ")
|
EmptyCollectionView("No macOS \(downloadType.description)s found!\n\nಥ_ಥ")
|
||||||
} else {
|
} else {
|
||||||
List {
|
ZStack {
|
||||||
ForEach(releaseNames(for: downloadType), id: \.self) { releaseName in
|
List {
|
||||||
Section(header: Text(releaseName)) {
|
ForEach(releaseNames(for: downloadType), id: \.self) { releaseName in
|
||||||
switch downloadType {
|
Section(header: Text(releaseName)) {
|
||||||
case .firmware:
|
switch downloadType {
|
||||||
ForEach(filteredFirmwares(for: releaseName)) { firmware in
|
case .firmware:
|
||||||
ListRowFirmware(firmware: firmware, savePanel: $savePanel, tasksInProgress: $tasksInProgress, taskManager: taskManager)
|
ForEach(filteredFirmwares(for: releaseName)) { firmware in
|
||||||
.tag(firmware)
|
ListRowFirmware(firmware: firmware, savePanel: $savePanel, copiedToClipboard: $copiedToClipboard, tasksInProgress: $tasksInProgress, taskManager: taskManager)
|
||||||
}
|
.tag(firmware)
|
||||||
case .installer:
|
}
|
||||||
ForEach(filteredInstallers(for: releaseName)) { installer in
|
case .installer:
|
||||||
ListRowInstaller(installer: installer, openPanel: $openPanel, tasksInProgress: $tasksInProgress, taskManager: taskManager)
|
ForEach(filteredInstallers(for: releaseName)) { installer in
|
||||||
.tag(installer)
|
ListRowInstaller(installer: installer, openPanel: $openPanel, tasksInProgress: $tasksInProgress, taskManager: taskManager)
|
||||||
|
.tag(installer)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if copiedToClipboard {
|
||||||
|
FloatingAlert(image: "list.bullet.clipboard.fill", message: "Copied to Clipboard")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Divider()
|
Divider()
|
||||||
|
@ -119,6 +126,18 @@ struct ContentView: View {
|
||||||
.onAppear {
|
.onAppear {
|
||||||
refresh()
|
refresh()
|
||||||
}
|
}
|
||||||
|
.onChange(of: copiedToClipboard) { copied in
|
||||||
|
|
||||||
|
guard copied else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
|
||||||
|
withAnimation {
|
||||||
|
copiedToClipboard = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func refresh() {
|
private func refresh() {
|
||||||
|
|
|
@ -17,6 +17,7 @@ struct ListRowFirmware: View {
|
||||||
private var retryDelay: Int = 30
|
private var retryDelay: Int = 30
|
||||||
var firmware: Firmware
|
var firmware: Firmware
|
||||||
@Binding var savePanel: NSSavePanel
|
@Binding var savePanel: NSSavePanel
|
||||||
|
@Binding var copiedToClipboard: Bool
|
||||||
@Binding var tasksInProgress: Bool
|
@Binding var tasksInProgress: Bool
|
||||||
@ObservedObject var taskManager: TaskManager
|
@ObservedObject var taskManager: TaskManager
|
||||||
@State private var alertType: FirmwareAlertType = .compatibility
|
@State private var alertType: FirmwareAlertType = .compatibility
|
||||||
|
@ -54,14 +55,23 @@ struct ListRowFirmware: View {
|
||||||
size: firmware.size.bytesString(),
|
size: firmware.size.bytesString(),
|
||||||
tooltip: firmware.tooltip
|
tooltip: firmware.tooltip
|
||||||
)
|
)
|
||||||
Button {
|
HStack(spacing: 1) {
|
||||||
firmware.compatible ? validate() : showCompatibilityWarning()
|
Button {
|
||||||
} label: {
|
firmware.compatible ? validate() : showCompatibilityWarning()
|
||||||
Image(systemName: "arrow.down.circle")
|
} label: {
|
||||||
.font(.body.bold())
|
Image(systemName: "arrow.down.circle")
|
||||||
|
.padding(.vertical, 1.5)
|
||||||
|
}
|
||||||
|
.help("Download macOS Firmware")
|
||||||
|
.buttonStyle(.mistAction)
|
||||||
|
Button {
|
||||||
|
copyToClipboard()
|
||||||
|
} label: {
|
||||||
|
Image(systemName: "list.bullet.clipboard")
|
||||||
|
}
|
||||||
|
.help("Copy macOS Firmware URL to Clipboard")
|
||||||
|
.buttonStyle(.mistAction)
|
||||||
}
|
}
|
||||||
.help("Download macOS Firmware")
|
|
||||||
.buttonStyle(.mistAction)
|
|
||||||
.clipShape(Capsule())
|
.clipShape(Capsule())
|
||||||
}
|
}
|
||||||
.alert(isPresented: $showAlert) {
|
.alert(isPresented: $showAlert) {
|
||||||
|
@ -108,6 +118,14 @@ struct ListRowFirmware: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func copyToClipboard() {
|
||||||
|
NSPasteboard.general.declareTypes([.string], owner: nil)
|
||||||
|
NSPasteboard.general.setString(firmware.url, forType: .string)
|
||||||
|
withAnimation(.easeIn) {
|
||||||
|
copiedToClipboard = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func save() {
|
private func save() {
|
||||||
showSavePanel = false
|
showSavePanel = false
|
||||||
savePanel.title = "Download Firmware"
|
savePanel.title = "Download Firmware"
|
||||||
|
@ -157,6 +175,6 @@ struct ListRowFirmware: View {
|
||||||
|
|
||||||
struct ListRowFirmware_Previews: PreviewProvider {
|
struct ListRowFirmware_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
ListRowFirmware(firmware: .example, savePanel: .constant(NSSavePanel()), tasksInProgress: .constant(false), taskManager: .shared)
|
ListRowFirmware(firmware: .example, savePanel: .constant(NSSavePanel()), copiedToClipboard: .constant(false), tasksInProgress: .constant(false), taskManager: .shared)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,7 @@ struct ListRowInstaller: View {
|
||||||
Button {
|
Button {
|
||||||
pressButton(.download)
|
pressButton(.download)
|
||||||
} label: {
|
} label: {
|
||||||
Image(systemName: "arrow.down.circle").font(.body.bold())
|
Image(systemName: "arrow.down.circle")
|
||||||
}
|
}
|
||||||
.help("Download and export macOS Installer")
|
.help("Download and export macOS Installer")
|
||||||
.buttonStyle(.mistAction)
|
.buttonStyle(.mistAction)
|
||||||
|
@ -98,7 +98,7 @@ struct ListRowInstaller: View {
|
||||||
Button {
|
Button {
|
||||||
pressButton(.volumeSelection)
|
pressButton(.volumeSelection)
|
||||||
} label: {
|
} label: {
|
||||||
Image(systemName: "externaldrive").font(.body.bold())
|
Image(systemName: "externaldrive")
|
||||||
.padding(.vertical, 1)
|
.padding(.vertical, 1)
|
||||||
}
|
}
|
||||||
.help("Create bootable macOS Installer")
|
.help("Create bootable macOS Installer")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue