Skip to content

Commit

Permalink
🔀 Merge pull request #484 from SenpaiHunters/develop
Browse files Browse the repository at this point in the history
✨ Wallpaper color theming
  • Loading branch information
MrKai77 authored Jul 7, 2024
2 parents bc858fd + 11efb2b commit f6a6063
Show file tree
Hide file tree
Showing 16 changed files with 692 additions and 333 deletions.
25 changes: 18 additions & 7 deletions Loop.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
4C6B93E72C1DCF6E00AFF832 /* TheLoopTimes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C6B93E12C1DCF6E00AFF832 /* TheLoopTimes.swift */; };
4C6B93E82C1DCF6E00AFF832 /* Updater.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C6B93E22C1DCF6E00AFF832 /* Updater.swift */; };
4C6B93E92C1DCF6E00AFF832 /* UpdateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C6B93E32C1DCF6E00AFF832 /* UpdateView.swift */; };
4CD883A42C30F0D7009A132A /* WallpaperColors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CD883A32C30F0D7009A132A /* WallpaperColors.swift */; };
A8055EC22AFEDE0B00459D13 /* Keycorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8055EC12AFEDE0B00459D13 /* Keycorder.swift */; };
A80900D52AA3F9F30085C63B /* VisualEffectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A80900D32AA3F9F20085C63B /* VisualEffectView.swift */; };
A80D49BB2BAE479900493B67 /* WindowAction+Port.swift in Sources */ = {isa = PBXBuildFile; fileRef = A80D49BA2BAE479900493B67 /* WindowAction+Port.swift */; };
Expand Down Expand Up @@ -45,7 +46,6 @@
A85DDBDA2C1693D4008C103D /* WindowDirection+Snapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = A85DDBD92C1693D4008C103D /* WindowDirection+Snapping.swift */; };
A864F4682AA660CD00579738 /* WindowDragManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A864F4672AA660CD00579738 /* WindowDragManager.swift */; };
A867C20E2C26522B005831BC /* Observer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A867C20D2C26522B005831BC /* Observer.swift */; };
A867C3A52C329C520073A906 /* Luminare in Frameworks */ = {isa = PBXBuildFile; productRef = A867C3A42C329C520073A906 /* Luminare */; };
A86949862A8F2BB70051AAAF /* CGKeyCode+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A86949852A8F2BB60051AAAF /* CGKeyCode+Extensions.swift */; };
A869C1A12B38C6E600AD1A84 /* StageManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A869C1A02B38C6E600AD1A84 /* StageManager.swift */; };
A86B97AD2AB79E2500099D7F /* ShakeEffect.swift in Sources */ = {isa = PBXBuildFile; fileRef = A86B97AC2AB79E2500099D7F /* ShakeEffect.swift */; };
Expand All @@ -55,6 +55,7 @@
A87DDD152B50A6A400A32C76 /* ScreenManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A87DDD142B50A6A400A32C76 /* ScreenManager.swift */; };
A87F78942BAE28050087B1DE /* CustomWindowActionSizeMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = A87F78932BAE28050087B1DE /* CustomWindowActionSizeMode.swift */; };
A87F78962BAE333C0087B1DE /* CustomWindowActionPositionMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = A87F78952BAE333C0087B1DE /* CustomWindowActionPositionMode.swift */; };
A881FC2A2C38A67C00853711 /* Luminare in Frameworks */ = {isa = PBXBuildFile; productRef = A881FC292C38A67C00853711 /* Luminare */; };
A883642F298B7288005D6C19 /* ServiceManagement.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A883642E298B7288005D6C19 /* ServiceManagement.framework */; };
A8878A252AA3B2C800850A66 /* WindowTransformAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8878A242AA3B2C800850A66 /* WindowTransformAnimation.swift */; };
A88E27AD2BDDE5300042CF04 /* CustomActionConfigurationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A88E27AC2BDDE5300042CF04 /* CustomActionConfigurationView.swift */; };
Expand Down Expand Up @@ -86,6 +87,7 @@
A8F0125B2AEDD7660017307F /* WindowAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8F0125A2AEDD7660017307F /* WindowAction.swift */; };
A8F1E9662C253F5B00AAF871 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = A8F1E9652C253F5B00AAF871 /* Localizable.xcstrings */; };
A8F1E9692C253F8D00AAF871 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = A8F1E9672C253F8D00AAF871 /* InfoPlist.strings */; };
A8FF7A942C373B4500AF106E /* Luminare in Frameworks */ = {isa = PBXBuildFile; productRef = A8FF7A932C373B4500AF106E /* Luminare */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
Expand All @@ -94,6 +96,7 @@
4C6B93E12C1DCF6E00AFF832 /* TheLoopTimes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TheLoopTimes.swift; sourceTree = "<group>"; };
4C6B93E22C1DCF6E00AFF832 /* Updater.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Updater.swift; sourceTree = "<group>"; };
4C6B93E32C1DCF6E00AFF832 /* UpdateView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateView.swift; sourceTree = "<group>"; };
4CD883A32C30F0D7009A132A /* WallpaperColors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WallpaperColors.swift; sourceTree = "<group>"; };
A80521312A84878200BF7E22 /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; };
A8055EC12AFEDE0B00459D13 /* Keycorder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Keycorder.swift; sourceTree = "<group>"; };
A80900D32AA3F9F20085C63B /* VisualEffectView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VisualEffectView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -184,7 +187,8 @@
buildActionMask = 2147483647;
files = (
A8DCC97B2980D5F500D41065 /* Defaults in Frameworks */,
A867C3A52C329C520073A906 /* Luminare in Frameworks */,
A881FC2A2C38A67C00853711 /* Luminare in Frameworks */,
A8FF7A942C373B4500AF106E /* Luminare in Frameworks */,
A883642F298B7288005D6C19 /* ServiceManagement.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -223,6 +227,7 @@
children = (
A893D3632BD3299000063510 /* IconConfiguration.swift */,
A82B1AED2BD352A100E2F3F9 /* AccentColorConfiguration.swift */,
4CD883A32C30F0D7009A132A /* WallpaperColors.swift */,
A82B1AEF2BD357FC00E2F3F9 /* RadialMenuConfiguration.swift */,
A82B1AF12BD35A3800E2F3F9 /* PreviewConfiguration.swift */,
);
Expand Down Expand Up @@ -462,7 +467,8 @@
name = Loop;
packageProductDependencies = (
A8DCC97A2980D5F500D41065 /* Defaults */,
A867C3A42C329C520073A906 /* Luminare */,
A8FF7A932C373B4500AF106E /* Luminare */,
A881FC292C38A67C00853711 /* Luminare */,
);
productName = WindowManager;
productReference = A8E59C35297F5E9A0064D4BA /* Loop.app */;
Expand Down Expand Up @@ -500,7 +506,7 @@
mainGroup = A8E59C2C297F5E9A0064D4BA;
packageReferences = (
A8DCC9792980D5F500D41065 /* XCRemoteSwiftPackageReference "Defaults" */,
A867C3A32C329C520073A906 /* XCRemoteSwiftPackageReference "Luminare" */,
A881FC282C38A67C00853711 /* XCRemoteSwiftPackageReference "Luminare" */,
);
productRefGroup = A8E59C36297F5E9A0064D4BA /* Products */;
projectDirPath = "";
Expand Down Expand Up @@ -597,6 +603,7 @@
A8789F6929805B340040512E /* PreviewView.swift in Sources */,
A8E59C50298045D90064D4BA /* PreviewController.swift in Sources */,
A81B98182BDC854F005FD78C /* AboutConfiguration.swift in Sources */,
4CD883A42C30F0D7009A132A /* WallpaperColors.swift in Sources */,
A86CB7332A3D22E7006A78F2 /* WindowEngine.swift in Sources */,
A8E59C39297F5E9A0064D4BA /* LoopApp.swift in Sources */,
A8330ACB2A3AC1C000673C8D /* Angle+Extensions.swift in Sources */,
Expand Down Expand Up @@ -861,7 +868,7 @@
/* End XCConfigurationList section */

/* Begin XCRemoteSwiftPackageReference section */
A867C3A32C329C520073A906 /* XCRemoteSwiftPackageReference "Luminare" */ = {
A881FC282C38A67C00853711 /* XCRemoteSwiftPackageReference "Luminare" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/MrKai77/Luminare";
requirement = {
Expand All @@ -880,16 +887,20 @@
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
A867C3A42C329C520073A906 /* Luminare */ = {
A881FC292C38A67C00853711 /* Luminare */ = {
isa = XCSwiftPackageProductDependency;
package = A867C3A32C329C520073A906 /* XCRemoteSwiftPackageReference "Luminare" */;
package = A881FC282C38A67C00853711 /* XCRemoteSwiftPackageReference "Luminare" */;
productName = Luminare;
};
A8DCC97A2980D5F500D41065 /* Defaults */ = {
isa = XCSwiftPackageProductDependency;
package = A8DCC9792980D5F500D41065 /* XCRemoteSwiftPackageReference "Defaults" */;
productName = Defaults;
};
A8FF7A932C373B4500AF106E /* Luminare */ = {
isa = XCSwiftPackageProductDependency;
productName = Luminare;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = A8E59C2D297F5E9A0064D4BA /* Project object */;
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "18px_image-depth.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
59 changes: 59 additions & 0 deletions Loop/Extensions/Color+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import Defaults
import SwiftUI

// MARK: - Loop theming

extension Color {
enum LoopAccentTone {
case normal
Expand All @@ -33,3 +35,60 @@ extension Color {
Color(nsColor: NSColor.systemGray.blended(withFraction: 0.2, of: .black)!)
}
}

// MARK: - Extension for wallpaper coloring

extension NSColor {
/// Converts NSColor to a hexadecimal string representation.
/// If the color is not in the device RGB color space, it defaults to black.
var toHexString: String {
// Attempt to convert the color to the RGB color space.
guard let rgbColor = usingColorSpace(.deviceRGB) else { return "#000000" }
// Format the RGB components into a hexadecimal string.
return String(format: "#%02X%02X%02X",
Int(rgbColor.redComponent * 0xFF),
Int(rgbColor.greenComponent * 0xFF),
Int(rgbColor.blueComponent * 0xFF))
}

/// Calculates the brightness of the color based on luminance.
/// Brightness is calculated using the luminance formula, which considers the different contributions
/// of the red, green, and blue components of the color. This property can be used to determine
/// how light or dark a color is perceived to be.
var brightness: CGFloat {
// Ensure the color is in the sRGB color space for accurate luminance calculation.
guard let rgbColor = usingColorSpace(.sRGB) else { return 0 }
// Calculate brightness using the luminance formula.
return 0.299 * rgbColor.redComponent + 0.587 * rgbColor.greenComponent + 0.114 * rgbColor.blueComponent
}

/// Determines if two colors are similar based on a threshold.
/// - Parameters:
/// - color: The color to compare with the receiver.
/// - threshold: The maximum allowed difference between color components.
/// - Returns: A Boolean value indicating whether the two colors are similar.
func isSimilar(to color: NSColor, threshold: CGFloat = 0.1) -> Bool {
// Convert both colors to the RGB color space for comparison.
guard let color1 = usingColorSpace(.deviceRGB),
let color2 = color.usingColorSpace(.deviceRGB) else { return false }
// Compare the red, green, and blue components of both colors.
return abs(color1.redComponent - color2.redComponent) < threshold &&
abs(color1.greenComponent - color2.greenComponent) < threshold &&
abs(color1.blueComponent - color2.blueComponent) < threshold
}

/// Quantizes the color to a limited set of values.
/// This process reduces the color's precision, effectively snapping it to a grid
/// in the color space defined by the quantization level. This simplification can
/// be beneficial for analyzing colors in smaller images by reducing the color palette's complexity.
/// - Returns: A quantized NSColor.
func quantized(levels: Double = 512.0) -> NSColor {
guard let sRGBColor = usingColorSpace(.sRGB) else { return self }
let divisionFactor = levels - 1
let red = round(sRGBColor.redComponent * divisionFactor) / divisionFactor
let green = round(sRGBColor.greenComponent * divisionFactor) / divisionFactor
let blue = round(sRGBColor.blueComponent * divisionFactor) / divisionFactor
let alpha = round(sRGBColor.alphaComponent * divisionFactor) / divisionFactor
return NSColor(srgbRed: red, green: green, blue: blue, alpha: alpha)
}
}
1 change: 1 addition & 0 deletions Loop/Extensions/Defaults+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ extension Defaults.Keys {
static let customAccentColor = Key<Color>("customAccentColor", default: Color(.white), iCloud: true)
static let useGradient = Key<Bool>("useGradient", default: true, iCloud: true)
static let gradientColor = Key<Color>("gradientColor", default: Color(.black), iCloud: true)
static let processWallpaper = Key<Bool>("processWallpaper", default: false, iCloud: true)

// Radial Menu
static let radialMenuVisibility = Key<Bool>("radialMenuVisibility", default: true, iCloud: true)
Expand Down
24 changes: 14 additions & 10 deletions Loop/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -161,16 +161,6 @@
}
}
},
"%@ (%lld)" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "new",
"value" : "%1$@ (%2$lld)"
}
}
}
},
"%@ %@" : {
"localizations" : {
"en" : {
Expand Down Expand Up @@ -337,6 +327,16 @@
}
}
},
"🧪 %@ (%lld)" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "new",
"value" : "🧪 %1$@ (%2$lld)"
}
}
}
},
"99 problems, updates ain't one." : {

},
Expand Down Expand Up @@ -6274,8 +6274,12 @@
},
"Sweet dreams are made of... no updates" : {

},
"Sync Wallpaper" : {

},
"System" : {
"extractionState" : "stale",
"localizations" : {
"en-GB" : {
"stringUnit" : {
Expand Down
20 changes: 5 additions & 15 deletions Loop/Luminare/Loop/AdvancedConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,23 @@ import SwiftUI

class AdvancedConfigurationModel: ObservableObject {
@Published var animateWindowResizes = Defaults[.animateWindowResizes] {
didSet {
Defaults[.animateWindowResizes] = animateWindowResizes
}
didSet { Defaults[.animateWindowResizes] = animateWindowResizes }
}

@Published var hideUntilDirectionIsChosen = Defaults[.hideUntilDirectionIsChosen] {
didSet {
Defaults[.hideUntilDirectionIsChosen] = hideUntilDirectionIsChosen
}
didSet { Defaults[.hideUntilDirectionIsChosen] = hideUntilDirectionIsChosen }
}

@Published var disableCursorInteraction = Defaults[.disableCursorInteraction] {
didSet {
Defaults[.disableCursorInteraction] = disableCursorInteraction
}
didSet { Defaults[.disableCursorInteraction] = disableCursorInteraction }
}

@Published var hapticFeedback = Defaults[.hapticFeedback] {
didSet {
Defaults[.hapticFeedback] = hapticFeedback
}
didSet { Defaults[.hapticFeedback] = hapticFeedback }
}

@Published var sizeIncrement = Defaults[.sizeIncrement] {
didSet {
Defaults[.sizeIncrement] = sizeIncrement
}
didSet { Defaults[.sizeIncrement] = sizeIncrement }
}

@Published var isAccessibilityAccessGranted = AccessibilityManager.getStatus()
Expand Down
4 changes: 1 addition & 3 deletions Loop/Luminare/Loop/ExcludedAppsConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ import SwiftUI

class ExcludedAppsConfigurationModel: ObservableObject {
@Published var excludedApps = Defaults[.excludedApps] {
didSet {
Defaults[.excludedApps] = excludedApps
}
didSet { Defaults[.excludedApps] = excludedApps }
}

@Published var selectedApps = Set<URL>()
Expand Down
40 changes: 10 additions & 30 deletions Loop/Luminare/Settings/Behavior/BehaviorConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,51 +28,35 @@ class BehaviorConfigurationModel: ObservableObject {
}

@Published var hideMenuBarIcon = Defaults[.hideMenuBarIcon] {
didSet {
Defaults[.hideMenuBarIcon] = hideMenuBarIcon
}
didSet { Defaults[.hideMenuBarIcon] = hideMenuBarIcon }
}

@Published var animationConfiguration = Defaults[.animationConfiguration] {
didSet {
Defaults[.animationConfiguration] = animationConfiguration
}
didSet { Defaults[.animationConfiguration] = animationConfiguration }
}

@Published var windowSnapping = Defaults[.windowSnapping] {
didSet {
Defaults[.windowSnapping] = windowSnapping
}
didSet { Defaults[.windowSnapping] = windowSnapping }
}

@Published var restoreWindowFrameOnDrag = Defaults[.restoreWindowFrameOnDrag] {
didSet {
Defaults[.restoreWindowFrameOnDrag] = restoreWindowFrameOnDrag
}
didSet { Defaults[.restoreWindowFrameOnDrag] = restoreWindowFrameOnDrag }
}

@Published var enablePadding = Defaults[.enablePadding] {
didSet {
Defaults[.enablePadding] = enablePadding
}
didSet { Defaults[.enablePadding] = enablePadding }
}

@Published var useScreenWithCursor = Defaults[.useScreenWithCursor] {
didSet {
Defaults[.useScreenWithCursor] = useScreenWithCursor
}
didSet { Defaults[.useScreenWithCursor] = useScreenWithCursor }
}

@Published var moveCursorWithWindow = Defaults[.moveCursorWithWindow] {
didSet {
Defaults[.moveCursorWithWindow] = moveCursorWithWindow
}
didSet { Defaults[.moveCursorWithWindow] = moveCursorWithWindow }
}

@Published var resizeWindowUnderCursor = Defaults[.resizeWindowUnderCursor] {
didSet {
Defaults[.resizeWindowUnderCursor] = resizeWindowUnderCursor
}
didSet { Defaults[.resizeWindowUnderCursor] = resizeWindowUnderCursor }
}

@Published var focusWindowOnResize = Defaults[.focusWindowOnResize] {
Expand All @@ -82,15 +66,11 @@ class BehaviorConfigurationModel: ObservableObject {
}

@Published var respectStageManager = Defaults[.respectStageManager] {
didSet {
Defaults[.respectStageManager] = respectStageManager
}
didSet { Defaults[.respectStageManager] = respectStageManager }
}

@Published var stageStripSize = Defaults[.stageStripSize] {
didSet {
Defaults[.stageStripSize] = stageStripSize
}
didSet { Defaults[.stageStripSize] = stageStripSize }
}

@Published var isPaddingConfigurationViewPresented = false
Expand Down
Loading

0 comments on commit f6a6063

Please sign in to comment.