Road to v4.0.0

This commit is contained in:
Alin
2024-09-27 20:11:44 -06:00
parent c248e4c8ce
commit abdf1cfc3a
17 changed files with 1295 additions and 1024 deletions
+1 -1
View File
@@ -31,7 +31,7 @@ struct AppCommands: Commands {
CommandGroup(replacing: .appInfo) {
Button {
updater.checkForUpdates()
updater.checkForUpdatesForce(showSheet: true)
} label: {
Text("Check for Updates")
}
+136
View File
@@ -0,0 +1,136 @@
//
// IceGroupBox.swift
// Pearcleaner
//
// Created by Jordan Baird (Ice), modified for Pearcleaner usage by Alin Lupascu on 9/27/24.
//
import SwiftUI
struct PearGroupBox<Header: View, Content: View, Footer: View>: View {
private let header: Header
private let content: Content
private let footer: Footer
private let padding: CGFloat
/// Example usage:
/// ```
/// PearGroupBox(
/// header: { Text("Header View") },
/// content: { Text("Content View") },
/// footer: { Text("Footer View") }
/// )
/// ```
init(
padding: CGFloat = 10,
@ViewBuilder header: () -> Header,
@ViewBuilder content: () -> Content,
@ViewBuilder footer: () -> Footer
) {
self.padding = padding
self.header = header()
self.content = content()
self.footer = footer()
}
/// Example usage with no header:
/// ```
/// PearGroupBox(
/// content: { Text("Content View") },
/// footer: { Text("Footer View") }
/// )
/// ```
init(
padding: CGFloat = 10,
@ViewBuilder content: () -> Content,
@ViewBuilder footer: () -> Footer
) where Header == EmptyView {
self.init(padding: padding) {
EmptyView()
} content: {
content()
} footer: {
footer()
}
}
/// Example usage with no footer:
/// ```
/// PearGroupBox(
/// header: { Text("Header View") },
/// content: { Text("Content View") }
/// )
/// ```
init(
padding: CGFloat = 10,
@ViewBuilder header: () -> Header,
@ViewBuilder content: () -> Content
) where Footer == EmptyView {
self.init(padding: padding) {
header()
} content: {
content()
} footer: {
EmptyView()
}
}
/// Example usage with content only:
/// ```
/// PearGroupBox {
/// Text("Content View Only")
/// }
/// ```
init(
padding: CGFloat = 10,
@ViewBuilder content: () -> Content
) where Header == EmptyView, Footer == EmptyView {
self.init(padding: padding) {
EmptyView()
} content: {
content()
} footer: {
EmptyView()
}
}
/// Example usage with a title and content only:
/// ```
/// PearGroupBox("Header Title") {
/// Text("Content View")
/// }
/// ```
init(
_ title: LocalizedStringKey,
padding: CGFloat = 10,
@ViewBuilder content: () -> Content
) where Header == Text, Footer == EmptyView {
self.init(padding: padding) {
Text(title)
.font(.headline)
} content: {
content()
}
}
var body: some View {
VStack(alignment: .leading) {
header
content
.padding(padding)
.background {
backgroundShape
.fill(.quinary)
.overlay {
backgroundShape
.stroke(.quaternary)
}
}
footer
}
}
@ViewBuilder
private var backgroundShape: some Shape {
RoundedRectangle(cornerRadius: 7, style: .circular)
}
}
+28 -6
View File
@@ -282,12 +282,37 @@ struct SimpleButtonBrightStyle: ButtonStyle {
struct PearDropView: View {
var multiplier: CGFloat = 1.0 // Multiplier parameter with a default value
var body: some View {
VStack(alignment: .center, spacing: 0) {
HStack(spacing: 0) {
LinearGradient(gradient: Gradient(colors: [.green, .orange]), startPoint: .leading, endPoint: .trailing)
.frame(width: 220)
.frame(width: 220 * multiplier) // Adjust the width based on the multiplier
LinearGradient(gradient: Gradient(colors: [.orange, .primary.opacity(0.5)]), startPoint: .leading, endPoint: .trailing)
.frame(width: 10 * multiplier) // Adjust the width based on the multiplier
LinearGradient(gradient: Gradient(colors: [.primary.opacity(0.5), .primary.opacity(0.5)]), startPoint: .leading, endPoint: .trailing)
.frame(width: 300 * multiplier) // Adjust the width based on the multiplier
}
.mask(
Image("logo_text_small")
.resizable()
.scaledToFit()
.frame(width: 500 * multiplier) // Scale the mask image width
.padding()
)
}
.frame(height: 120 * multiplier) // Adjust the height of the VStack based on the multiplier
}
}
struct PearDropViewSmall: View {
var body: some View {
VStack(alignment: .center, spacing: 0) {
HStack(spacing: 0) {
LinearGradient(gradient: Gradient(colors: [.green, .orange]), startPoint: .leading, endPoint: .trailing)
.frame(width: 260)
LinearGradient(gradient: Gradient(colors: [.orange, .primary.opacity(0.5)]), startPoint: .leading, endPoint: .trailing)
.frame(width: 10)
LinearGradient(gradient: Gradient(colors: [.primary.opacity(0.5), .primary.opacity(0.5)]), startPoint: .leading, endPoint: .trailing)
@@ -297,13 +322,10 @@ struct PearDropView: View {
Image("logo_text_small")
.resizable()
.scaledToFit()
.frame(width: 500)
.padding()
.frame(width: 180)
)
}
.frame(height: 120)
.frame(height: 50)
}
}
+39
View File
@@ -703,6 +703,45 @@ extension URL {
}
}
// Removes the sidebar toggle button from the toolbar, if running on macOS 14.0 or newer.
extension View {
@ViewBuilder
func removeSidebarToggle() -> some View {
if #available(macOS 14.0, *) {
self.toolbar(removing: .sidebarToggle)
} else {
self
}
}
}
// Drag window by background
extension View {
// Helper function to apply the movable background window
func movableByWindowBackground() -> some View {
self.background(MovableWindowAccessor())
}
}
// Custom NSWindow accessor to modify window properties
struct MovableWindowAccessor: NSViewRepresentable {
func makeNSView(context: Context) -> NSView {
let nsView = NSView()
DispatchQueue.main.async {
if let window = nsView.window {
// Enable dragging by the window's background
window.isMovableByWindowBackground = true
}
}
return nsView
}
func updateNSView(_ nsView: NSView, context: Context) {}
}
// Return image for different folders
func folderImages(for path: String) -> AnyView? {
if path.contains("/Library/Containers/") || path.contains("/Library/Group Containers/") {