diff --git a/AGENTS.md b/AGENTS.md index 8bece72..5854934 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -23,3 +23,4 @@ Public macOS window manager. Swift 6, SwiftPM, macOS 14+, Apple Silicon. - AX success is not frame acceptance: verify actual geometry, including same-display resize clipping. - Readiness text must use the full model.ready state, not permission alone. - Cross-display acceptance must cover a full round trip between unequal screen sizes; verify the realized frame after settling. +- Custom button backgrounds, padding and contentShape must live inside the label; verify physical clicks in empty painted edges, not only AX activation. diff --git a/Assets/Info.plist b/Assets/Info.plist index 31fcf02..22877f3 100644 --- a/Assets/Info.plist +++ b/Assets/Info.plist @@ -22,9 +22,9 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.0.0 + 1.0.1 CFBundleVersion - 10 + 11 LSMinimumSystemVersion 14.0 LSUIElement diff --git a/CHANGELOG.md b/CHANGELOG.md index ec6be40..0a97124 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,19 @@ All notable changes to this project are documented here. ## [Unreleased] +## [1.0.1] - 2026-09-06 + +### Changed + +- Simplified Settings and Welcome windows with integrated native window controls. +- Reduced unused space at the bottom of the menu bar panel. + +### Fixed + +- Made the entire painted pause/resume button clickable, including its empty edges. +- Expanded add, dismiss and restore-defaults button targets. +- Aligned the language selector with the switches in Preferences. + ## [1.0.0] - 2026-09-06 First public release. diff --git a/Sources/EncajeApp/EncajeApp.swift b/Sources/EncajeApp/EncajeApp.swift index 2a58a45..eef9131 100644 --- a/Sources/EncajeApp/EncajeApp.swift +++ b/Sources/EncajeApp/EncajeApp.swift @@ -256,8 +256,12 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate, NSMe private func makeWindow(title: String, size: NSSize, view: V) -> NSWindow { let window = NSWindow( contentRect: NSRect(origin: .zero, size: size), - styleMask: [.titled, .closable, .miniaturizable], backing: .buffered, defer: false) + styleMask: [.titled, .closable, .miniaturizable, .fullSizeContentView], backing: .buffered, + defer: false) window.title = title + window.titleVisibility = .hidden + window.titlebarAppearsTransparent = true + window.titlebarSeparatorStyle = .none window.isReleasedWhenClosed = false let hosting = NSHostingView(rootView: view) hosting.sizingOptions = [] diff --git a/Sources/EncajeApp/MenuBarPopover.swift b/Sources/EncajeApp/MenuBarPopover.swift index ed97926..7162094 100644 --- a/Sources/EncajeApp/MenuBarPopover.swift +++ b/Sources/EncajeApp/MenuBarPopover.swift @@ -159,8 +159,11 @@ private struct MenuBarPopoverView: View { systemImage: model.paused ? "play.fill" : "pause.fill" ) .font(.system(size: 14, weight: .semibold)).frame(maxWidth: .infinity).padding( - .vertical, 11) - }.buttonStyle(.plain).background(.teal.gradient, in: RoundedRectangle(cornerRadius: 10)) + .vertical, 11 + ) + .background(.teal.gradient, in: RoundedRectangle(cornerRadius: 10)) + .contentShape(RoundedRectangle(cornerRadius: 10)) + }.buttonStyle(.plain) .foregroundStyle(.white) if updates.available, updates.phase != .idle { UpdateActionView() @@ -178,7 +181,9 @@ private struct MenuBarPopoverView: View { Rectangle()) }.buttonStyle(.plain).foregroundStyle(.red) }.font(.system(size: 13, weight: .medium)) - }.padding(18).frame(width: 300).fixedSize(horizontal: false, vertical: true).tint(.teal) + }.padding(.horizontal, 18).padding(.top, 18).padding(.bottom, 8).frame(width: 300).fixedSize( + horizontal: false, vertical: true + ).tint(.teal) } private func row(_ text: String, symbol: String, action: @escaping () -> Void) -> some View { diff --git a/Sources/EncajeApp/SettingsView.swift b/Sources/EncajeApp/SettingsView.swift index 4415ed2..8829ff5 100644 --- a/Sources/EncajeApp/SettingsView.swift +++ b/Sources/EncajeApp/SettingsView.swift @@ -19,7 +19,7 @@ struct SettingsView: View { Text(sectionSubtitle).font(.callout).foregroundStyle(.secondary) } Spacer() - }.padding(22) + }.padding(22).padding(.top, 12) Divider() Group { switch section { @@ -37,13 +37,13 @@ struct SettingsView: View { Button { model.message = nil } label: { - Image(systemName: "xmark") + Image(systemName: "xmark").frame(width: 24, height: 24).contentShape(Rectangle()) } .buttonStyle(.plain).accessibilityLabel(localized("Dismiss", "Cerrar")) }.padding(12).background(.quaternary.opacity(0.5)) } } - }.frame(width: 880, height: 660).tint(.teal) + }.frame(width: 880, height: 660).ignoresSafeArea(.container, edges: .top).tint(.teal) } private var sidebar: some View { @@ -72,7 +72,7 @@ struct SettingsView: View { : model.ready ? localized("Ready", "Listo") : localized("Setup needed", "Falta acceso"), systemImage: model.ready && !model.paused ? "checkmark.circle.fill" : "circle" ).font(.caption).foregroundStyle(model.ready && !model.paused ? .teal : .secondary) - }.padding(16).frame(width: 152).frame(maxHeight: .infinity) + }.padding(16).padding(.top, 28).frame(width: 152).frame(maxHeight: .infinity) .background(.quaternary.opacity(0.22)) } diff --git a/Sources/EncajeApp/UI/PreferencesView.swift b/Sources/EncajeApp/UI/PreferencesView.swift index ee8d458..2c21b34 100644 --- a/Sources/EncajeApp/UI/PreferencesView.swift +++ b/Sources/EncajeApp/UI/PreferencesView.swift @@ -52,7 +52,7 @@ struct PreferencesView: View { ForEach(AppLanguage.allCases, id: \.self) { language in Text(language.label).tag(language) } - }.labelsHidden().frame(width: 150) + }.labelsHidden().fixedSize().frame(width: 150, alignment: .trailing) } Divider() HStack { diff --git a/Sources/EncajeApp/UI/ZoneSettingsView.swift b/Sources/EncajeApp/UI/ZoneSettingsView.swift index 80a58bb..20fd1a8 100644 --- a/Sources/EncajeApp/UI/ZoneSettingsView.swift +++ b/Sources/EncajeApp/UI/ZoneSettingsView.swift @@ -23,7 +23,7 @@ struct ZoneSettingsView: View { Button { selectedID = model.addRule() } label: { - Image(systemName: "plus") + Image(systemName: "plus").frame(width: 24, height: 24).contentShape(Rectangle()) } .buttonStyle(.borderless).help(localized("Add a zone", "Añadir una zona")) }.padding(14) @@ -37,8 +37,12 @@ struct ZoneSettingsView: View { }.padding(.horizontal, 6) } Divider() - Button(localized("Restore defaults", "Restaurar originales")) { confirmReset = true } - .font(.caption).buttonStyle(.borderless).padding(12) + Button { + confirmReset = true + } label: { + Text(localized("Restore defaults", "Restaurar originales")) + .frame(maxWidth: .infinity).padding(12).contentShape(Rectangle()) + }.font(.caption).buttonStyle(.borderless) }.frame(width: 202) Divider() if let rule = selectedRule { diff --git a/Sources/EncajeApp/WelcomeView.swift b/Sources/EncajeApp/WelcomeView.swift index 6d181d9..c1dce92 100644 --- a/Sources/EncajeApp/WelcomeView.swift +++ b/Sources/EncajeApp/WelcomeView.swift @@ -102,12 +102,14 @@ struct WelcomeView: View { Button(localized("Set up later", "Configurar después"), action: finish).buttonStyle(.plain) .foregroundStyle(.secondary).font(.caption) } - }.padding(32).frame(width: 510, height: 590).tint(.teal) - .animation( - reduceMotion ? nil : .spring(response: 0.4, dampingFraction: 0.85), - value: permissions.granted - ) - .onAppear { withAnimation(reduceMotion ? nil : .easeOut(duration: 0.3)) { entrance = true } } + }.padding(32).frame(width: 510, height: 590).ignoresSafeArea(.container, edges: .top).tint( + .teal + ) + .animation( + reduceMotion ? nil : .spring(response: 0.4, dampingFraction: 0.85), + value: permissions.granted + ) + .onAppear { withAnimation(reduceMotion ? nil : .easeOut(duration: 0.3)) { entrance = true } } } private func complete() { diff --git a/docs/validation.md b/docs/validation.md index 5e1caa6..727a09d 100644 --- a/docs/validation.md +++ b/docs/validation.md @@ -46,6 +46,10 @@ retries when the observed size proves that correction is needed. - Open/close the menu panel by icon, outside click and Escape; Configuration/About must retain focus, and closed views must release monitors/rendering work. - Check the app icon in both its UI and the system's representation. +- Click empty painted edges of pause/resume and padded buttons; verify the action, + not only Accessibility activation. Confirm the language picker aligns with switches. +- Open Settings and Welcome in both languages; confirm integrated traffic lights, + no visible titlebar text or separator, unclipped content and native close behavior. - After closing the UI and settling for at least one minute, sample process CPU and memory over multiple intervals. Report bundle size separately from ignored development caches and rollback artifacts.