Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Spaceman.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,7 @@
PRODUCT_BUNDLE_IDENTIFIER = dev.jaysce.Spaceman;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Spaceman/Spaceman-Bridging-Header.h";
SWIFT_VERSION = 5.0;
SWIFT_VERSION = 5.10;
};
name = Debug;
};
Expand Down Expand Up @@ -576,7 +576,7 @@
PRODUCT_BUNDLE_IDENTIFIER = dev.jaysce.Spaceman;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Spaceman/Spaceman-Bridging-Header.h";
SWIFT_VERSION = 5.0;
SWIFT_VERSION = 5.10;
};
name = Release;
};
Expand All @@ -597,7 +597,7 @@
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
SWIFT_EMIT_LOC_STRINGS = NO;
SWIFT_VERSION = 5.0;
SWIFT_VERSION = 5.10;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Spaceman.app/Contents/MacOS/Spaceman";
};
name = Debug;
Expand All @@ -619,7 +619,7 @@
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
SWIFT_EMIT_LOC_STRINGS = NO;
SWIFT_VERSION = 5.0;
SWIFT_VERSION = 5.10;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Spaceman.app/Contents/MacOS/Spaceman";
};
name = Release;
Expand Down
136 changes: 70 additions & 66 deletions Spaceman/Helpers/IconCreator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,14 @@ final class IconCreator {
for space in spaces {
let textRect = NSRect(origin: CGPoint.zero, size: iconSize)
let spaceNumber = NSString(string: String(space.spaceNumber))
let image = NSImage(size: iconSize)

image.lockFocus()
spaceNumber.drawVerticallyCentered(
in: textRect,
withAttributes: getStringAttributes(
alpha: space.isCurrentSpace ? 1 : 0.4,
fontSize: 12))
let attributes = getStringAttributes(
alpha: space.isCurrentSpace ? 1 : 0.4,
fontSize: 12)
let image = NSImage(size: iconSize, flipped: false) { _ in
spaceNumber.drawVerticallyCentered(in: textRect, withAttributes: attributes)
return true
}
image.isTemplate = true
image.unlockFocus()

newIcons.append(image)
}
Expand All @@ -83,31 +81,31 @@ final class IconCreator {
for space in spaces {
let textRect = NSRect(origin: CGPoint.zero, size: iconSize)
let number = desktopsOnly ? space.desktopNumber : space.spaceNumber
let iconImage = NSImage(size: iconSize)
let numberImage = NSImage(size: iconSize)
let numberImage = NSImage(size: iconSize, flipped: false) { _ in
if let number {
let spaceNumber = NSString(string: String(number))
spaceNumber.drawVerticallyCentered(
in: textRect,
withAttributes: self.getStringAttributes(alpha: 1))
}
return true
}

if let number {
numberImage.lockFocus()
let spaceNumber = NSString(string: String(number))
spaceNumber.drawVerticallyCentered(
let baseIcon = icons[index]
let iconImage = NSImage(size: iconSize, flipped: false) { _ in
baseIcon.draw(
in: textRect,
withAttributes: getStringAttributes(alpha: 1))
numberImage.unlockFocus()
from: NSRect.zero,
operation: NSCompositingOperation.sourceOver,
fraction: 1.0)
numberImage.draw(
in: textRect,
from: NSRect.zero,
operation: NSCompositingOperation.destinationOut,
fraction: 1.0)
return true
}

iconImage.lockFocus()
icons[index].draw(
in: textRect,
from: NSRect.zero,
operation: NSCompositingOperation.sourceOver,
fraction: 1.0)
numberImage.draw(
in: textRect,
from: NSRect.zero,
operation: NSCompositingOperation.destinationOut,
fraction: 1.0)
iconImage.isTemplate = true
iconImage.unlockFocus()

newIcons.append(iconImage)
index += 1
Expand All @@ -123,28 +121,28 @@ final class IconCreator {
for space in spaces {
let textRect = NSRect(origin: CGPoint.zero, size: iconSize)
let spaceText = NSString(string: "\(space.spaceNumber): \(space.spaceName.uppercased())")
let iconImage = NSImage(size: iconSize)
let textImage = NSImage(size: iconSize)

textImage.lockFocus()
spaceText.drawVerticallyCentered(
in: textRect,
withAttributes: getStringAttributes(alpha: 1))
textImage.unlockFocus()

iconImage.lockFocus()
icons[index].draw(
in: textRect,
from: NSRect.zero,
operation: NSCompositingOperation.sourceOver,
fraction: 1.0)
textImage.draw(
in: textRect,
from: NSRect.zero,
operation: NSCompositingOperation.destinationOut,
fraction: 1.0)
let textImage = NSImage(size: iconSize, flipped: false) { _ in
spaceText.drawVerticallyCentered(
in: textRect,
withAttributes: self.getStringAttributes(alpha: 1))
return true
}

let baseIcon = icons[index]
let iconImage = NSImage(size: iconSize, flipped: false) { _ in
baseIcon.draw(
in: textRect,
from: NSRect.zero,
operation: NSCompositingOperation.sourceOver,
fraction: 1.0)
textImage.draw(
in: textRect,
from: NSRect.zero,
operation: NSCompositingOperation.destinationOut,
fraction: 1.0)
return true
}
iconImage.isTemplate = true
iconImage.unlockFocus()

newIcons.append(iconImage)
index += 1
Expand Down Expand Up @@ -185,24 +183,30 @@ final class IconCreator {
let accomodatingGapWidth = CGFloat(numIcons - 1) * gapWidth
let accomodatingDisplayGapWidth = CGFloat(displayCount - 1) * displayGapWidth
let totalWidth = combinedIconWidth + accomodatingGapWidth + accomodatingDisplayGapWidth
let image = NSImage(size: NSSize(width: totalWidth, height: iconSize.height))

image.lockFocus()
var xOffset = CGFloat.zero
for icon in iconsWithDisplayProperties {
icon.image.draw(
at: NSPoint(x: xOffset, y: 0),
from: NSRect.zero,
operation: NSCompositingOperation.sourceOver,
fraction: 1.0)
if icon.nextSpaceOnDifferentDisplay {
xOffset += iconSize.width + displayGapWidth
} else {
xOffset += iconSize.width + gapWidth
let iconHeight = iconSize.height
let iconWidth = iconSize.width
let gapWidth = self.gapWidth
let displayGapWidth = self.displayGapWidth
let image = NSImage(
size: NSSize(width: totalWidth, height: iconHeight),
flipped: false
) { _ in
var xOffset = CGFloat.zero
for icon in iconsWithDisplayProperties {
icon.image.draw(
at: NSPoint(x: xOffset, y: 0),
from: NSRect.zero,
operation: NSCompositingOperation.sourceOver,
fraction: 1.0)
if icon.nextSpaceOnDifferentDisplay {
xOffset += iconWidth + displayGapWidth
} else {
xOffset += iconWidth + gapWidth
}
}
return true
}
image.isTemplate = true
image.unlockFocus()

return image
}
Expand Down
7 changes: 4 additions & 3 deletions Spaceman/View/PreferencesView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ struct PreferencesView: View {
@AppStorage("displayStyle") private var selectedStyle = 0
@AppStorage("spaceNames") private var data = Data()
@AppStorage("autoRefreshSpaces") private var autoRefreshSpaces = false
@StateObject private var prefsVM = PreferencesViewModel()
@State private var prefsVM = PreferencesViewModel()

// MARK: - Main Body
var body: some View {
Expand All @@ -36,7 +36,7 @@ struct PreferencesView: View {
}
.ignoresSafeArea()
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
.onAppear(perform: prefsVM.loadData)
.onAppear { prefsVM.loadData() }
.onChange(of: data) {
prefsVM.loadData()
}
Expand Down Expand Up @@ -163,7 +163,8 @@ struct PreferencesView: View {

// MARK: - Space Name Editor
private var spaceNameEditor: some View {
HStack {
@Bindable var prefsVM = prefsVM
return HStack {
Picker(selection: $prefsVM.selectedSpace, label: Text("Space")) {
ForEach(0..<prefsVM.sortedSpaceNamesDict.count, id: \.self) {
Text(String(prefsVM.sortedSpaceNamesDict[$0].value.spaceNum))
Expand Down
20 changes: 12 additions & 8 deletions Spaceman/ViewModel/PreferencesViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,20 @@
//

import Foundation
import SwiftUI
import Observation

final class PreferencesViewModel: ObservableObject {
@AppStorage("autoRefreshSpaces") private var autoRefreshSpaces = false
@Published var selectedSpace = 0
@Published var spaceName = ""
@MainActor
@Observable
final class PreferencesViewModel {
var selectedSpace = 0
var spaceName = ""
var spaceNamesDict: [String: SpaceNameInfo] = [:]
var sortedSpaceNamesDict: [Dictionary<String, SpaceNameInfo>.Element] = []
private var timer: Timer?

@ObservationIgnored private var timer: Timer?

init() {
if autoRefreshSpaces {
if UserDefaults.standard.bool(forKey: "autoRefreshSpaces") {
startTimer()
}
}
Expand Down Expand Up @@ -54,7 +56,9 @@ final class PreferencesViewModel: ObservableObject {
func startTimer() {
timer?.invalidate()
timer = Timer.scheduledTimer(withTimeInterval: 5, repeats: true) { [weak self] _ in
self?.refreshSpaces()
Task { @MainActor in
self?.refreshSpaces()
}
}
}

Expand Down
Loading