mirror of
https://github.com/FBukovina/Atoll.git
synced 2026-10-27 15:14:33 +00:00
commit
d9742dbacd
12 changed files with 102 additions and 69 deletions
|
|
@ -1009,9 +1009,9 @@ struct ContentView: View {
|
|||
Image(nsImage: musicManager.albumArt)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.clipShape(RoundedRectangle(cornerRadius: musicManager.albumArt.size.width/musicManager.albumArt.size.height > 1.0 ? MusicPlayerImageSizes.cornerRadiusInset.closed/3.0 : MusicPlayerImageSizes.cornerRadiusInset.closed))
|
||||
)
|
||||
.clipped()
|
||||
.clipShape(RoundedRectangle(cornerRadius: MusicPlayerImageSizes.cornerRadiusInset.closed))
|
||||
.matchedGeometryEffect(id: "albumArt", in: albumArtNamespace)
|
||||
.albumArtFlip(angle: musicManager.flipAngle)
|
||||
albumArtBadge(for: secondary, badgeSize: badgeDisplaySize)
|
||||
|
|
|
|||
|
|
@ -982,6 +982,9 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"%0.1f" : {
|
||||
|
||||
},
|
||||
"%d%%" : {
|
||||
"localizations" : {
|
||||
|
|
@ -13767,6 +13770,7 @@
|
|||
}
|
||||
},
|
||||
"Enable album art parallax effect" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"ru" : {
|
||||
"stringUnit" : {
|
||||
|
|
@ -25883,6 +25887,9 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Parallax Effect Intensity" : {
|
||||
|
||||
},
|
||||
"Pause" : {
|
||||
"localizations" : {
|
||||
|
|
|
|||
|
|
@ -296,23 +296,24 @@ struct LockScreenMusicPanel: View {
|
|||
|
||||
private func albumArtButton(size: CGFloat, cornerRadius: CGFloat) -> some View {
|
||||
Button(action: toggleExpanded) {
|
||||
ZStack(alignment: .bottomTrailing) {
|
||||
albumArtImage(size: size, cornerRadius: cornerRadius)
|
||||
if showAppIcon, let icon = lockScreenAppIcon {
|
||||
icon
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fill)
|
||||
.frame(width: appIconSize, height: appIconSize)
|
||||
.clipShape(RoundedRectangle(cornerRadius: appIconCornerRadius, style: .continuous))
|
||||
.shadow(color: Color.black.opacity(0.35), radius: 6, x: 0, y: 4)
|
||||
.offset(x: appIconOffset, y: appIconOffset)
|
||||
.transition(.scale.combined(with: .opacity))
|
||||
ZStack(alignment: .bottomTrailing) {
|
||||
albumArtImage(size: size, cornerRadius: cornerRadius)
|
||||
if showAppIcon, let icon = lockScreenAppIcon {
|
||||
icon
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: appIconSize, height: appIconSize)
|
||||
|
||||
.shadow(color: Color.black.opacity(0.35), radius: 6, x: 0, y: 4)
|
||||
.offset(x: appIconOffset, y: appIconOffset)
|
||||
.transition(.scale.combined(with: .opacity))
|
||||
}
|
||||
}
|
||||
}
|
||||
.albumArtFlip(angle: musicManager.flipAngle)
|
||||
.parallax3D(magnitude: 12, enableOverride: lockScreenParallaxEnabled, suspended: isParallaxSuspended)
|
||||
.frame(width: size, height: size)
|
||||
.background(albumArtBackground(cornerRadius: cornerRadius))
|
||||
.albumArtFlip(angle: musicManager.flipAngle)
|
||||
.parallax3D(enableOverride: lockScreenParallaxEnabled, suspended: isParallaxSuspended)
|
||||
.frame(width: size)
|
||||
.background(albumArtBackground(cornerRadius: cornerRadius))
|
||||
.clipShape(RoundedRectangle(cornerRadius: musicManager.albumArt.size.width/musicManager.albumArt.size.height > 1.0 ? appIconCornerRadius/3 : appIconCornerRadius, style: .continuous))
|
||||
}
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
.opacity(musicManager.isPlaying ? 1 : 0.4)
|
||||
|
|
@ -1050,8 +1051,7 @@ struct LockScreenMusicPanel: View {
|
|||
Image(nsImage: musicManager.albumArt)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: size, height: size)
|
||||
.clipShape(RoundedRectangle(cornerRadius: cornerRadius, style: .continuous))
|
||||
.clipShape(RoundedRectangle(cornerRadius: musicManager.albumArt.size.width/musicManager.albumArt.size.height > 1.0 ? cornerRadius/3 : cornerRadius))
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
|
|
@ -1082,7 +1082,7 @@ struct LockScreenMusicPanel: View {
|
|||
}
|
||||
|
||||
private var appIconCornerRadius: CGFloat {
|
||||
isExpanded ? 18 : 10
|
||||
isExpanded ? 18 : 12
|
||||
}
|
||||
|
||||
private var appIconOffset: CGFloat {
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ struct MinimalisticMusicView: View {
|
|||
// Lyrics under the author name (same font size as author)
|
||||
if enableLyrics {
|
||||
lyricsLineView
|
||||
.font(.system(size: 11, weight: .regular))
|
||||
}
|
||||
}
|
||||
.frame(width: geo.size.width, height: geo.size.height, alignment: .center)
|
||||
|
|
@ -93,9 +94,10 @@ struct MinimalisticMusicView: View {
|
|||
Image(nsImage: musicManager.albumArt)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.clipShape(RoundedRectangle(cornerRadius: musicManager.albumArt.size.width/musicManager.albumArt.size.height > 1.0 ? 4 : 12))
|
||||
|
||||
)
|
||||
.clipped()
|
||||
.clipShape(RoundedRectangle(cornerRadius: 18)) // Dramatically increased corner radius for minimalistic mode
|
||||
.albumArtFlip(angle: musicManager.flipAngle)
|
||||
.frame(width: max(0, vm.effectiveClosedNotchHeight - 12), height: max(0, vm.effectiveClosedNotchHeight - 12))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ struct DynamicIslandHeader: View {
|
|||
@Default(.enableTimerFeature) var enableTimerFeature
|
||||
@Default(.timerDisplayMode) var timerDisplayMode
|
||||
@Default(.showClipboardIcon) var showClipboardIcon
|
||||
@Default(.showColorPickerIcon) var showColorPickerIcon
|
||||
@Default(.clipboardDisplayMode) var clipboardDisplayMode
|
||||
|
||||
var body: some View {
|
||||
|
|
@ -50,6 +51,8 @@ struct DynamicIslandHeader: View {
|
|||
.blur(radius: vm.notchState == .closed ? 20 : 0)
|
||||
.animation(.smooth.delay(0.1), value: vm.notchState)
|
||||
.zIndex(2)
|
||||
.padding(8)
|
||||
|
||||
}
|
||||
|
||||
if vm.notchState == .open && !Defaults[.enableMinimalisticUI] {
|
||||
|
|
@ -128,7 +131,7 @@ struct DynamicIslandHeader: View {
|
|||
}
|
||||
|
||||
// ColorPicker button
|
||||
if Defaults[.enableColorPickerFeature] {
|
||||
if Defaults[.enableColorPickerFeature] && showColorPickerIcon{
|
||||
Button(action: {
|
||||
switch Defaults[.colorPickerDisplayMode] {
|
||||
case .panel:
|
||||
|
|
@ -293,7 +296,7 @@ private extension DynamicIslandHeader {
|
|||
Defaults[.settingsIconInNotch]
|
||||
&& Defaults[.enableClipboardManager]
|
||||
&& Defaults[.showClipboardIcon]
|
||||
&& Defaults[.enableColorPickerFeature]
|
||||
&& Defaults[.showColorPickerIcon]
|
||||
&& Defaults[.enableTimerFeature]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -374,7 +374,7 @@ struct MinimalisticMusicPlayerView: View {
|
|||
private struct MinimalisticReminderEventListView: View {
|
||||
let reminders: [ReminderLiveActivityManager.ReminderEntry]
|
||||
|
||||
private let textFont = Font.system(size: 13, weight: .semibold)
|
||||
private let textFont = Font.system(size: 13, weight: .regular)
|
||||
private let separatorSpacing: CGFloat = 10
|
||||
|
||||
var body: some View {
|
||||
|
|
@ -1128,7 +1128,7 @@ struct MinimalisticAlbumArtView: View {
|
|||
.background(
|
||||
Image(nsImage: musicManager.albumArt)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.scaledToFill()
|
||||
)
|
||||
.clipped()
|
||||
.clipShape(RoundedRectangle(cornerRadius: 12))
|
||||
|
|
@ -1142,18 +1142,21 @@ struct MinimalisticAlbumArtView: View {
|
|||
Button {
|
||||
musicManager.openMusicApp()
|
||||
} label: {
|
||||
Color.clear
|
||||
.aspectRatio(1, contentMode: .fit)
|
||||
.background(
|
||||
Image(nsImage: musicManager.albumArt)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
)
|
||||
.clipped()
|
||||
.clipShape(RoundedRectangle(cornerRadius: 12))
|
||||
.matchedGeometryEffect(id: "albumArt", in: albumArtNamespace)
|
||||
.albumArtFlip(angle: musicManager.flipAngle)
|
||||
.parallax3D(magnitude: 12)
|
||||
Color.clear
|
||||
.aspectRatio(1, contentMode: .fit)
|
||||
.background(
|
||||
|
||||
Image(nsImage: musicManager.albumArt)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.clipShape(RoundedRectangle(cornerRadius: musicManager.albumArt.size.width/musicManager.albumArt.size.height > 1.0 ? 4 : 12))
|
||||
|
||||
|
||||
)
|
||||
.clipped()
|
||||
.matchedGeometryEffect(id: "albumArt", in: albumArtNamespace)
|
||||
.albumArtFlip(angle: musicManager.flipAngle)
|
||||
.parallax3D()
|
||||
}
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
.opacity(musicManager.isPlaying ? 1 : 0.4)
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ struct MusicPlayerView: View {
|
|||
var body: some View {
|
||||
HStack(alignment: .top, spacing: 12) {
|
||||
AlbumArtView(vm: vm, albumArtNamespace: albumArtNamespace)
|
||||
.padding(.all, 5)
|
||||
MusicControlsView()
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
|
|
@ -62,14 +61,17 @@ struct AlbumArtView: View {
|
|||
Image(nsImage: musicManager.albumArt)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.clipShape(
|
||||
RoundedRectangle(
|
||||
cornerRadius: Defaults[.cornerRadiusScaling]
|
||||
? musicManager.albumArt.size.width/musicManager.albumArt.size.height > 1.0 ? MusicPlayerImageSizes.cornerRadiusInset.opened/3 : MusicPlayerImageSizes.cornerRadiusInset.opened
|
||||
: musicManager.albumArt.size.width/musicManager.albumArt.size.height > 1.0 ? MusicPlayerImageSizes.cornerRadiusInset.closed/3 : MusicPlayerImageSizes.cornerRadiusInset.closed
|
||||
|
||||
|
||||
)
|
||||
)
|
||||
)
|
||||
.clipped()
|
||||
.clipShape(
|
||||
RoundedRectangle(
|
||||
cornerRadius: Defaults[.cornerRadiusScaling]
|
||||
? MusicPlayerImageSizes.cornerRadiusInset.opened
|
||||
: MusicPlayerImageSizes.cornerRadiusInset.closed)
|
||||
)
|
||||
.scaleEffect(x: 1.3, y: 1.4)
|
||||
.rotationEffect(.degrees(92))
|
||||
.blur(radius: 40)
|
||||
|
|
@ -86,7 +88,9 @@ struct AlbumArtView: View {
|
|||
appIconOverlay
|
||||
}
|
||||
.albumArtFlip(angle: musicManager.flipAngle)
|
||||
.parallax3D(magnitude: 12)
|
||||
.parallax3D()
|
||||
.padding(.bottom, -5)
|
||||
|
||||
}
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
.scaleEffect(musicManager.isPlaying ? 1 : 0.85)
|
||||
|
|
@ -110,15 +114,18 @@ struct AlbumArtView: View {
|
|||
Image(nsImage: musicManager.albumArt)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.clipShape(
|
||||
RoundedRectangle(
|
||||
cornerRadius: Defaults[.cornerRadiusScaling]
|
||||
? musicManager.albumArt.size.width/musicManager.albumArt.size.height > 1.0 ? MusicPlayerImageSizes.cornerRadiusInset.opened/3 : MusicPlayerImageSizes.cornerRadiusInset.opened
|
||||
: musicManager.albumArt.size.width/musicManager.albumArt.size.height > 1.0 ? MusicPlayerImageSizes.cornerRadiusInset.closed/3 : MusicPlayerImageSizes.cornerRadiusInset.closed
|
||||
|
||||
|
||||
)
|
||||
) // ensures that even the rectagular album cover is rounded just like the MacOS media player
|
||||
}
|
||||
.matchedGeometryEffect(id: "albumArt", in: albumArtNamespace)
|
||||
.clipped()
|
||||
.clipShape(
|
||||
RoundedRectangle(
|
||||
cornerRadius: Defaults[.cornerRadiusScaling]
|
||||
? MusicPlayerImageSizes.cornerRadiusInset.opened
|
||||
: MusicPlayerImageSizes.cornerRadiusInset.closed)
|
||||
)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
|
|
@ -126,8 +133,8 @@ struct AlbumArtView: View {
|
|||
if vm.notchState == .open && !musicManager.usingAppIconForArtwork {
|
||||
AppIcon(for: musicManager.bundleIdentifier ?? "com.apple.Music")
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fill)
|
||||
.frame(width: 30, height: 30)
|
||||
.scaledToFill()
|
||||
.frame(width: 36, height: 36)
|
||||
.offset(x: 10, y: 10)
|
||||
.transition(.scale.combined(with: .opacity).animation(.bouncy.delay(0.3)))
|
||||
.zIndex(2)
|
||||
|
|
@ -207,9 +214,9 @@ struct MusicControlsView: View {
|
|||
|
||||
MarqueeText(
|
||||
lyricsBinding,
|
||||
font: .headline,
|
||||
font: .system(size: 12, weight: .regular),
|
||||
nsFont: .headline,
|
||||
textColor: .white.opacity(0.8),
|
||||
textColor: .white.opacity(0.7),
|
||||
minDuration: 0.35,
|
||||
frameWidth: width
|
||||
)
|
||||
|
|
@ -605,6 +612,7 @@ struct NotchHomeView: View {
|
|||
.combined(with: .blurReplace.animation(.smooth.speed(0.9)))
|
||||
.combined(with: .move(edge: .top)))
|
||||
.blur(radius: vm.notchState == .closed ? 30 : 0)
|
||||
.padding(Defaults[.enableMinimalisticUI] ? 0 : 8) //Putting the main padding for home view here for consistency
|
||||
}
|
||||
|
||||
private var minimalisticOverridePayload: ExtensionNotchExperiencePayload? {
|
||||
|
|
@ -713,6 +721,7 @@ struct MusicSliderView: View {
|
|||
LiveStreamProgressIndicator(tint: sliderTint)
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(height: sliderFrameHeight)
|
||||
|
||||
case .inline:
|
||||
HStack(spacing: 10) {
|
||||
Spacer()
|
||||
|
|
@ -720,6 +729,7 @@ struct MusicSliderView: View {
|
|||
LiveStreamProgressIndicator(tint: sliderTint)
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(height: sliderFrameHeight)
|
||||
|
||||
Spacer()
|
||||
.frame(width: 48)
|
||||
}
|
||||
|
|
@ -748,10 +758,10 @@ struct MusicSliderView: View {
|
|||
)
|
||||
}
|
||||
|
||||
private var sliderTint: Color {
|
||||
private var sliderTint: Color {//
|
||||
switch Defaults[.sliderColor] {
|
||||
case .albumArt:
|
||||
return Color(nsColor: color).ensureMinimumBrightness(factor: 0.8)
|
||||
return Color(nsColor: color).ensureMinimumBrightness(factor: 0.6)
|
||||
case .accent:
|
||||
return .accentColor
|
||||
case .white:
|
||||
|
|
|
|||
|
|
@ -2444,6 +2444,9 @@ struct Media: View {
|
|||
@Default(.lockScreenMusicAlbumParallaxEnabled) private var lockScreenMusicAlbumParallaxEnabled
|
||||
@Default(.showStandardMediaControls) private var showStandardMediaControls
|
||||
@Default(.autoHideInactiveNotchMediaPlayer) private var autoHideInactiveNotchMediaPlayer
|
||||
@Default(.parallaxEffectIntensity) private var parallaxEffectIntensity
|
||||
|
||||
|
||||
@ObservedObject private var musicManager = MusicManager.shared
|
||||
|
||||
private var isAppleMusicActive: Bool {
|
||||
|
|
@ -2589,10 +2592,18 @@ struct Media: View {
|
|||
Text("Enable lyrics")
|
||||
}
|
||||
.settingsHighlight(id: highlightID("Enable lyrics"))
|
||||
Defaults.Toggle(key: .enableParallaxEffect) {
|
||||
Text("Enable album art parallax effect")
|
||||
|
||||
//Parallax Effect Intensity to control how much parallax is wanted
|
||||
Slider(value: $parallaxEffectIntensity, in: 0...12, step: 1.0) {
|
||||
HStack {
|
||||
Text("Parallax Effect Intensity")
|
||||
Spacer()
|
||||
Text("\(parallaxEffectIntensity, specifier: "%0.1f")")
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
.settingsHighlight(id: highlightID("Enable album art parallax effect"))
|
||||
|
||||
Picker("Sneak Peek Style", selection: $sneakPeekStyles){
|
||||
ForEach(SneakPeekStyle.allCases) { style in
|
||||
Text(style.rawValue).tag(style)
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ struct TabButton: View {
|
|||
var body: some View {
|
||||
Button(action: onClick) {
|
||||
Image(systemName: icon)
|
||||
.padding(.horizontal, 15)
|
||||
.contentShape(Capsule())
|
||||
}
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ struct TabSelectionView: View {
|
|||
return tabsArray
|
||||
}
|
||||
var body: some View {
|
||||
HStack(spacing: 0) {
|
||||
HStack(spacing: 24) {
|
||||
ForEach(Array(tabs.enumerated()), id: \.element.id) { idx, tab in
|
||||
let isSelected = isSelected(tab)
|
||||
let activeAccent = tab.accentColor ?? .white
|
||||
|
|
|
|||
|
|
@ -22,17 +22,16 @@ import AppKit
|
|||
import Defaults
|
||||
|
||||
struct ParallaxMotionModifier: ViewModifier {
|
||||
var magnitude: Double
|
||||
var enableOverride: Bool?
|
||||
var isSuspended: Bool
|
||||
|
||||
@Default(.enableParallaxEffect) var enableParallaxEffect
|
||||
@Default(.parallaxEffectIntensity) var parallaxEffectIntensity
|
||||
@State private var offset: CGSize = .zero
|
||||
@State private var isHovering = false
|
||||
@State private var viewSize: CGSize = .zero
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
if isSuspended || !(enableOverride ?? enableParallaxEffect) {
|
||||
if isSuspended || !(enableOverride ?? (parallaxEffectIntensity > 0.0)) {
|
||||
content
|
||||
} else {
|
||||
content
|
||||
|
|
@ -69,11 +68,11 @@ struct ParallaxMotionModifier: ViewModifier {
|
|||
}
|
||||
}
|
||||
.rotation3DEffect(
|
||||
.degrees(offset.height * magnitude), // Y movement rotates around X axis
|
||||
.degrees(offset.height * parallaxEffectIntensity), // Y movement rotates around X axis
|
||||
axis: (x: 1, y: 0, z: 0)
|
||||
)
|
||||
.rotation3DEffect(
|
||||
.degrees(offset.width * -magnitude), // X movement rotates around Y axis (inverted to look naturally)
|
||||
.degrees(offset.width * -parallaxEffectIntensity), // X movement rotates around Y axis (inverted to look naturally)
|
||||
axis: (x: 0, y: 1, z: 0)
|
||||
)
|
||||
.scaleEffect(isHovering ? 1.02 : 1.0) // Subtle scale up on hover
|
||||
|
|
@ -83,10 +82,9 @@ struct ParallaxMotionModifier: ViewModifier {
|
|||
|
||||
extension View {
|
||||
func parallax3D(
|
||||
magnitude: Double = 10,
|
||||
enableOverride: Bool? = nil,
|
||||
suspended: Bool = false
|
||||
) -> some View {
|
||||
modifier(ParallaxMotionModifier(magnitude: magnitude, enableOverride: enableOverride, isSuspended: suspended))
|
||||
modifier(ParallaxMotionModifier(enableOverride: enableOverride, isSuspended: suspended))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -779,7 +779,7 @@ extension Defaults.Keys {
|
|||
static let sneakPeekStyles = Key<SneakPeekStyle>("sneakPeekStyles", default: .standard)
|
||||
static let showSneakPeekOnTrackChange = Key<Bool>("showSneakPeekOnTrackChange", default: true)
|
||||
static let enableFullscreenMediaDetection = Key<Bool>("enableFullscreenMediaDetection", default: true)
|
||||
static let enableParallaxEffect = Key<Bool>("enableParallaxEffect", default: true)
|
||||
static let parallaxEffectIntensity = Key<Double>("parallaxEffectIntensity", default: 6.0)
|
||||
static let waitInterval = Key<Double>("waitInterval", default: 3)
|
||||
static let showShuffleAndRepeat = Key<Bool>("showShuffleAndRepeat", default: true)
|
||||
static let showMediaOutputControl = Key<Bool>("showMediaOutputControl", default: true)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue