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
18 changes: 9 additions & 9 deletions Loop/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -531,8 +531,8 @@
},
"it" : {
"stringUnit" : {
"state" : "needs_review",
"value" : "Accent opacity"
"state" : "translated",
"value" : "Opacità colore dettagli"
}
},
"ja" : {
Expand Down Expand Up @@ -1766,8 +1766,8 @@
},
"it" : {
"stringUnit" : {
"state" : "needs_review",
"value" : "Background"
"state" : "translated",
"value" : "Sfondo"
}
},
"ja" : {
Expand Down Expand Up @@ -5320,8 +5320,8 @@
},
"it" : {
"stringUnit" : {
"state" : "needs_review",
"value" : "Enable blur"
"state" : "translated",
"value" : "Abilita sfocatura"
}
},
"ja" : {
Expand Down Expand Up @@ -5980,8 +5980,8 @@
},
"it" : {
"stringUnit" : {
"state" : "needs_review",
"value" : "Fill Available Space"
"state" : "translated",
"value" : "Riempi spazio disponibile"
}
},
"ja" : {
Expand Down Expand Up @@ -22205,7 +22205,7 @@
},
"it" : {
"stringUnit" : {
"state" : "needs_review",
"state" : "translated",
"value" : "Riavvia per completare"
}
},
Expand Down
10 changes: 7 additions & 3 deletions Loop/Private APIs/SkyLightToolBelt.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,17 @@ enum SkyLightToolBelt {
return false
}

var wid = windowID
var psn = ProcessSerialNumber()
let status = GetProcessForPID(pid, &psn)

var cgStatus = SLPSSetFrontProcessWithOptions(
guard status == noErr else {
Log.error("Failed to get PSN: \(status)", category: .skyLightToolBelt)
return false
}

let cgStatus = SLPSSetFrontProcessWithOptions(
&psn,
wid,
windowID,
kCPSUserGenerated
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ final class PreviewController {
panel.level = NSWindow.Level(NSWindow.Level.screenSaver.rawValue - 1)
panel.contentView = NSHostingView(rootView: PreviewView(viewModel: viewModel))
panel.collectionBehavior = .canJoinAllSpaces
panel.hasShadow = false
panel.ignoresMouseEvents = true
panel.orderFrontRegardless()
controller = .init(window: panel)
Expand Down
57 changes: 39 additions & 18 deletions Loop/Window Action Indicators/Radial Menu/RadialMenuView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import SwiftUI
struct RadialMenuView: View {
@Environment(\.luminareAnimation) private var luminareAnimation
@Environment(\.appearsActive) private var appearsActive
@Environment(\.colorScheme) private var colorScheme
@ObservedObject private var accentColorController: AccentColorController = .shared
@ObservedObject private var viewModel: RadialMenuViewModel
private let radialMenuSize: CGFloat = 100
Expand Down Expand Up @@ -53,24 +54,44 @@ struct RadialMenuView: View {
/// but for now, we have disabled the materialization Liquid Glass transition.
ZStack {
if viewModel.isShown {
radialMenuFill()
.mask(directionSelectorMask)
.mask(radialMenuMask)
.glassEffect(
.regular.tint(accentColorController.color1.opacity(0.025)),
in: .rect(cornerRadius: radialMenuCornerRadius)
.inset(by: radialMenuThickness / 2)
.stroke(lineWidth: radialMenuThickness)
)
.transition(.scale(scale: 1.25).combined(with: .opacity))
}
}
.overlay {
if viewModel.isShown {
overlayImage()
.transition(.scale(scale: 1.25).combined(with: .opacity))
ZStack {
radialMenuFill()
.mask(directionSelectorMask)
.glassEffect(
.regular.tint(accentColorController.color1.opacity(0.025)),
in: .rect(cornerRadius: radialMenuCornerRadius) // Using the radial menu thickness here causes a seam in the middle
)
.mask(radialMenuMask)

if appearsActive {
let borderColor: Color = colorScheme == .dark ? .white.opacity(0.25).mix(with: accentColorController.color1, by: 0.25) : .white

// Since the glass is just masked to the radial menu shape, it will be missing its inner border.
// This emulates a liquid glass inner border.
let innerBorderThickness: CGFloat = 0.5
RoundedRectangle(cornerRadius: radialMenuCornerRadius)
.inset(by: radialMenuThickness - innerBorderThickness)
.strokeBorder(lineWidth: innerBorderThickness)
.foregroundStyle(borderColor)
.mask {
LinearGradient(
colors: [
.white,
.clear,
.white
],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
}
}

overlayImage()
}
.transition(.scale(scale: 1.25).combined(with: .opacity))
}
}
.compositingGroup()
.frame(width: radialMenuSize, height: radialMenuSize)
.shadow(color: .black.opacity(viewModel.isShadowShown ? 0.2 : 0), radius: 10)
.scaleEffect(viewModel.shouldFillRadialMenu ? 0.85 : 1.0)
Expand Down Expand Up @@ -103,8 +124,8 @@ struct RadialMenuView: View {
LinearGradient(
gradient: Gradient(
colors: [
shouldAppearActive ? accentColorController.color1 : .systemGray,
shouldAppearActive ? accentColorController.color2 : .systemGray
accentColorController.color1,
accentColorController.color2
]
),
startPoint: .topLeading,
Expand Down
11 changes: 9 additions & 2 deletions Loop/Window Management/Window Manipulation/WindowEngine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,18 @@ enum WindowEngine {
// Record first frame if needed
WindowRecords.recordFirstIfNeeded(for: window)

// Defer recording action or undo
let storeAsFrame = WindowRecords.shouldStoreAsFinalFrame(action)

/// If this action doesn't require storage as a frame, then record it beforehand.
/// Otherwise, this action will be recorded *after* resizing, such that its final frame is considered if undoing.
if !storeAsFrame {
WindowRecords.record(window, action)
}

defer {
if action.direction == .undo {
WindowRecords.removeLastAction(for: window)
} else {
} else if storeAsFrame {
WindowRecords.record(window, action)
}
}
Expand Down
16 changes: 11 additions & 5 deletions Loop/Window Management/Window Manipulation/WindowRecords.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,16 @@ enum WindowRecords {
Log.info("Recorded first for: \(window)", category: .windowRecords)
}

/// Determines if an action should be recorded using its frame instead of the action applied onto it.
/// - Parameter action: the action to apply onto the window.
/// - Returns: Whether this action should be recorded with its final frame instead of using the action.
static func shouldStoreAsFinalFrame(_ action: WindowAction) -> Bool {
/// Actions that are stored as frames need to be recorded *after* resize.
/// These actions are context-dependent, and cannot simply be called as an action to restore the previous state.
let storeAsFrame = action.direction.willChangeScreen || action.willManipulateExistingWindowFrame
return storeAsFrame
}

/// Record a window's action in the records array
/// - Parameters:
/// - window: Window to record
Expand All @@ -52,11 +62,7 @@ enum WindowRecords {
return
}

/// These actions are context-dependent, and cannot simply be called as an action to restore the previous state.
/// That is why these should be stored as frames instead of actions.
let storeAsFrame = action.direction.willChangeScreen || action.willManipulateExistingWindowFrame

if storeAsFrame, let screen = ScreenUtility.screenContaining(window) {
if shouldStoreAsFinalFrame(action), let screen = ScreenUtility.screenContaining(window) {
let customActionName = "autogenerated_record_\(action.getName())"
let windowFrame = window.frame
let adjustedBounds = PaddingSettings
Expand Down