Fully working stuff

This commit is contained in:
Hariharan Mudaliar 2025-10-17 20:43:29 +05:30
commit 070f88df6f
7 changed files with 143 additions and 49 deletions

View file

@ -9189,6 +9189,9 @@
},
"LinkedIn" : {
},
"Liquid Glass requires macOS 26 or later." : {
},
"Live Monitoring" : {
@ -9198,6 +9201,9 @@
},
"Lock Screen" : {
},
"Lock screen material" : {
},
"Loop Mode" : {

View file

@ -9,15 +9,24 @@ import SwiftUI
import Defaults
struct LockScreenMusicPanel: View {
static let defaultSize = CGSize(width: 420, height: 180)
@ObservedObject var musicManager = MusicManager.shared
@State private var sliderValue: Double = 0
@State private var dragging: Bool = false
@State private var lastDragged: Date = .distantPast
@State private var isActive = true
@Default(.lockScreenGlassStyle) var lockScreenGlassStyle
private let panelWidth: CGFloat = 460
private let panelHeight: CGFloat = 180
private let cornerRadius: CGFloat = 28
private var panelSize: CGSize { Self.defaultSize }
private var usesLiquidGlass: Bool {
if #available(macOS 26.0, *) {
return lockScreenGlassStyle == .liquid
}
return false
}
var body: some View {
if isActive {
@ -27,7 +36,7 @@ struct LockScreenMusicPanel: View {
}
} else {
Color.clear
.frame(width: panelWidth, height: panelHeight)
.frame(width: panelSize.width, height: panelSize.height)
}
}
@ -87,26 +96,8 @@ struct LockScreenMusicPanel: View {
}
.padding(.horizontal, 20)
.padding(.vertical, 16)
.frame(width: panelWidth, height: panelHeight)
.background {
if #available(macOS 26.0, *) {
RoundedRectangle(cornerRadius: cornerRadius)
.glassEffect(in: .rect(cornerRadius: cornerRadius))
.onAppear {
let formatter = DateFormatter()
formatter.dateFormat = "HH:mm:ss.SSS"
print("[\(formatter.string(from: Date()))] LockScreenMusicPanel: ✨ Using macOS 26.0+ Liquid Glass effect")
}
} else {
RoundedRectangle(cornerRadius: cornerRadius)
.fill(.ultraThinMaterial)
.onAppear {
let formatter = DateFormatter()
formatter.dateFormat = "HH:mm:ss.SSS"
print("[\(formatter.string(from: Date()))] LockScreenMusicPanel: 🪟 Using ultraThinMaterial fallback (macOS < 26.0)")
}
}
}
.frame(width: panelSize.width, height: panelSize.height)
.background(panelBackground)
.overlay {
RoundedRectangle(cornerRadius: cornerRadius)
.stroke(Color.white.opacity(0.35), lineWidth: 1.4)
@ -115,9 +106,7 @@ struct LockScreenMusicPanel: View {
.onAppear {
sliderValue = musicManager.elapsedTime
isActive = true
let formatter = DateFormatter()
formatter.dateFormat = "HH:mm:ss.SSS"
print("[\(formatter.string(from: Date()))] LockScreenMusicPanel: ✅ View appeared")
logPanelAppearance()
}
}
@ -241,9 +230,8 @@ struct LockScreenMusicPanel: View {
Image(systemName: musicManager.isPlaying ? "pause.fill" : "play.fill")
.font(.system(size: 24, weight: .semibold))
.foregroundColor(.white)
.frame(width: 54, height: 54)
.background(Color.white.opacity(0.15))
.clipShape(Circle())
.frame(width: 48, height: 48)
.contentShape(Rectangle())
}
.buttonStyle(PlainButtonStyle())
}
@ -253,6 +241,8 @@ struct LockScreenMusicPanel: View {
Image(systemName: icon)
.font(.system(size: size, weight: .medium))
.foregroundColor(isActive ? .red : .white.opacity(0.8))
.frame(width: 32, height: 32)
.contentShape(Rectangle())
}
.buttonStyle(PlainButtonStyle())
}
@ -264,4 +254,38 @@ struct LockScreenMusicPanel: View {
case .one: return "repeat.1"
}
}
@ViewBuilder
private var panelBackground: some View {
if usesLiquidGlass {
liquidPanelBackground
} else {
frostedPanelBackground
}
}
@ViewBuilder
private var liquidPanelBackground: some View {
if #available(macOS 26.0, *) {
RoundedRectangle(cornerRadius: cornerRadius)
.glassEffect(
.regular
.tint(Color.white.opacity(0.12))
.interactive(),
in: .rect(cornerRadius: cornerRadius)
)
}
}
private var frostedPanelBackground: some View {
RoundedRectangle(cornerRadius: cornerRadius)
.fill(.ultraThinMaterial)
}
private func logPanelAppearance(event: String = "✅ View appeared") {
let formatter = DateFormatter()
formatter.dateFormat = "HH:mm:ss.SSS"
let styleDescriptor = usesLiquidGlass ? "Liquid Glass" : "Frosted"
print("[\(formatter.string(from: Date()))] LockScreenMusicPanel: \(event) – \(styleDescriptor)")
}
}

View file

@ -192,24 +192,29 @@ struct MinimalisticMusicPlayerView: View {
}
private var playPauseButton: some View {
Button(action: {
Task { await musicManager.togglePlay() }
}) {
Image(systemName: musicManager.isPlaying ? "pause.fill" : "play.fill")
.font(.system(size: 24, weight: .semibold))
.foregroundColor(.white)
.frame(width: 50, height: 50)
}
.buttonStyle(PlainButtonStyle())
MinimalisticSquircircleButton(
icon: musicManager.isPlaying ? "pause.fill" : "play.fill",
fontSize: 24,
fontWeight: .semibold,
frameSize: CGSize(width: 54, height: 54),
cornerRadius: 20,
foregroundColor: .white,
action: {
Task { await musicManager.togglePlay() }
}
)
}
private func controlButton(icon: String, size: CGFloat = 18, isActive: Bool = false, action: @escaping () -> Void) -> some View {
Button(action: action) {
Image(systemName: icon)
.font(.system(size: size, weight: .medium))
.foregroundColor(isActive ? .red : .white.opacity(0.8))
}
.buttonStyle(PlainButtonStyle())
MinimalisticSquircircleButton(
icon: icon,
fontSize: size,
fontWeight: .medium,
frameSize: CGSize(width: 40, height: 40),
cornerRadius: 16,
foregroundColor: isActive ? .red : .white.opacity(0.85),
action: action
)
}
private var repeatIcon: String {
@ -274,3 +279,37 @@ struct MinimalisticAlbumArtView: View {
.scaleEffect(musicManager.isPlaying ? 1 : 0.85)
}
}
// MARK: - Hover-highlighted control button
private struct MinimalisticSquircircleButton: View {
let icon: String
let fontSize: CGFloat
let fontWeight: Font.Weight
let frameSize: CGSize
let cornerRadius: CGFloat
let foregroundColor: Color
let action: () -> Void
@State private var isHovering = false
var body: some View {
Button(action: action) {
Image(systemName: icon)
.font(.system(size: fontSize, weight: fontWeight))
.foregroundColor(foregroundColor)
.frame(width: frameSize.width, height: frameSize.height)
.background(
RoundedRectangle(cornerRadius: cornerRadius, style: .continuous)
.fill(isHovering ? Color.white.opacity(0.18) : .clear)
)
.contentShape(RoundedRectangle(cornerRadius: cornerRadius, style: .continuous))
}
.buttonStyle(PlainButtonStyle())
.onHover { hovering in
withAnimation(.easeOut(duration: 0.18)) {
isHovering = hovering
}
}
}
}

View file

@ -174,6 +174,7 @@ struct GeneralSettings: View {
@Default(.enableScreenRecordingDetection) var enableScreenRecordingDetection
@Default(.showRecordingIndicator) var showRecordingIndicator
@Default(.enableMinimalisticUI) var enableMinimalisticUI
@Default(.lockScreenGlassStyle) var lockScreenGlassStyle
var body: some View {
Form {
@ -298,6 +299,23 @@ struct GeneralSettings: View {
Section {
Defaults.Toggle("Enable Lock Screen Live Activity", key: .enableLockScreenLiveActivity)
if #available(macOS 26.0, *) {
Picker("Lock screen material", selection: $lockScreenGlassStyle) {
ForEach(LockScreenGlassStyle.allCases) { style in
Text(style.rawValue).tag(style)
}
}
} else {
Picker("Lock screen material", selection: $lockScreenGlassStyle) {
ForEach(LockScreenGlassStyle.allCases) { style in
Text(style.rawValue).tag(style)
}
}
.disabled(true)
Text("Liquid Glass requires macOS 26 or later.")
.font(.caption)
.foregroundStyle(.secondary)
}
Button("Copy Latest Crash Report") {
copyLatestCrashReport()

View file

@ -70,3 +70,10 @@ enum SliderColorEnum: String, CaseIterable, Defaults.Serializable {
case albumArt = "Match album art"
case accent = "Accent color"
}
enum LockScreenGlassStyle: String, CaseIterable, Defaults.Serializable, Identifiable {
case liquid = "Liquid Glass"
case frosted = "Frosted Glass"
var id: String { rawValue }
}

View file

@ -41,12 +41,11 @@ class LockScreenPanelManager {
return
}
let panelWidth: CGFloat = 460
let panelHeight: CGFloat = 180
let panelSize = LockScreenMusicPanel.defaultSize
let screenFrame = screen.frame
let originX = screenFrame.origin.x + (screenFrame.width / 2) - (panelWidth / 2)
let originY = screenFrame.origin.y + (screenFrame.height / 2) - panelHeight - 32
let targetFrame = NSRect(x: originX, y: originY, width: panelWidth, height: panelHeight)
let originX = screenFrame.origin.x + (screenFrame.width / 2) - (panelSize.width / 2)
let originY = screenFrame.origin.y + (screenFrame.height / 2) - panelSize.height - 32
let targetFrame = NSRect(x: originX, y: originY, width: panelSize.width, height: panelSize.height)
let window: NSWindow

View file

@ -336,6 +336,7 @@ extension Defaults.Keys {
static let showShuffleAndRepeat = Key<Bool>("showShuffleAndRepeat", default: false)
// Enable lock screen media widget (shows the standalone panel when screen is locked)
static let enableLockScreenMediaWidget = Key<Bool>("enableLockScreenMediaWidget", default: true)
static let lockScreenGlassStyle = Key<LockScreenGlassStyle>("lockScreenGlassStyle", default: .liquid)
// MARK: Battery
static let showPowerStatusNotifications = Key<Bool>("showPowerStatusNotifications", default: true)