mirror of
https://github.com/FBukovina/Atoll.git
synced 2026-10-27 15:14:33 +00:00
Terminal opacity fix
This commit is contained in:
parent
026f55dea7
commit
9c9f68399e
6 changed files with 161 additions and 21 deletions
|
|
@ -105,8 +105,8 @@
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/apple/swift-argument-parser",
|
"location" : "https://github.com/apple/swift-argument-parser",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "c5d11a805e765f52ba34ec7284bd4fcd6ba68615",
|
"revision" : "626b5b7b2f45e1b0b1c6f4a309296d1d21d7311b",
|
||||||
"version" : "1.7.0"
|
"version" : "1.7.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -132,8 +132,8 @@
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/migueldeicaza/SwiftTerm",
|
"location" : "https://github.com/migueldeicaza/SwiftTerm",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "b1262db5b6bea699a8260a8c66999436c508ca56",
|
"revision" : "8e7a1e154f470e19c709a00a8768df348ba5fc43",
|
||||||
"version" : "1.11.2"
|
"version" : "1.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5619,6 +5619,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"Amazon Music" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"Animation" : {
|
"Animation" : {
|
||||||
"extractionState" : "stale",
|
"extractionState" : "stale",
|
||||||
|
|
@ -41010,6 +41013,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"Terminal opacity only affects the terminal backdrop; text stays fully opaque. Blur uses the system material behind the window." : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"Text" : {
|
"Text" : {
|
||||||
"comment" : "Name of a clipboard item type that contains plain text.",
|
"comment" : "Name of a clipboard item type that contains plain text.",
|
||||||
|
|
@ -43754,6 +43760,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"Uses macOS Now Playing when the Amazon Music app is the active media source. Playback controls follow the system Now Playing target. Scrubbing the timeline may not work if the Amazon Music app does not support remote seek." : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"Uses the frosted blur treatment while glass mode is enabled." : {
|
"Uses the frosted blur treatment while glass mode is enabled." : {
|
||||||
"comment" : "A description of the frosted blur treatment when glass mode is enabled. | A description of the frosted blur treatment when glass mode is enabled. | merge:ko:alt='Glass 모드가 활성화되어 있는 동안에는 Frosted 블러 효과가 적용됩니다.'",
|
"comment" : "A description of the frosted blur treatment when glass mode is enabled. | A description of the frosted blur treatment when glass mode is enabled. | merge:ko:alt='Glass 모드가 활성화되어 있는 동안에는 Frosted 블러 효과가 적용됩니다.'",
|
||||||
|
|
|
||||||
|
|
@ -86,9 +86,39 @@ struct NotchTerminalView: View {
|
||||||
@ObservedObject var terminalManager = TerminalManager.shared
|
@ObservedObject var terminalManager = TerminalManager.shared
|
||||||
@EnvironmentObject var vm: DynamicIslandViewModel
|
@EnvironmentObject var vm: DynamicIslandViewModel
|
||||||
@Default(.enableTerminalFeature) var enableTerminalFeature
|
@Default(.enableTerminalFeature) var enableTerminalFeature
|
||||||
|
@Default(.cornerRadiusScaling) var cornerRadiusScaling
|
||||||
|
@Default(.enableMinimalisticUI) var enableMinimalisticUI
|
||||||
@State private var suppressionToken = UUID()
|
@State private var suppressionToken = UUID()
|
||||||
@State private var isSuppressing = false
|
@State private var isSuppressing = false
|
||||||
|
|
||||||
|
/// Top corners stay mild; bottom follows shell − padding (see `notchTerminalBottomCornerRadii`).
|
||||||
|
private static let terminalClipTopCornerRadius: CGFloat = 6
|
||||||
|
|
||||||
|
private var currentScreenName: String {
|
||||||
|
vm.screen ?? DynamicIslandViewCoordinator.shared.selectedScreen
|
||||||
|
}
|
||||||
|
|
||||||
|
private var isDynamicIslandMode: Bool {
|
||||||
|
shouldUseDynamicIslandMode(for: currentScreenName)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var terminalClipShape: UnevenRoundedRectangle {
|
||||||
|
let innerBottom = notchTerminalBottomCornerRadii(
|
||||||
|
isDynamicIslandMode: isDynamicIslandMode,
|
||||||
|
notchState: vm.notchState,
|
||||||
|
cornerRadiusScaling: cornerRadiusScaling,
|
||||||
|
enableMinimalisticUI: enableMinimalisticUI,
|
||||||
|
closedNotchHeight: vm.closedNotchSize.height
|
||||||
|
).innerBottom
|
||||||
|
return UnevenRoundedRectangle(
|
||||||
|
topLeadingRadius: Self.terminalClipTopCornerRadius,
|
||||||
|
bottomLeadingRadius: innerBottom,
|
||||||
|
bottomTrailingRadius: innerBottom,
|
||||||
|
topTrailingRadius: Self.terminalClipTopCornerRadius,
|
||||||
|
style: .continuous
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
if enableTerminalFeature {
|
if enableTerminalFeature {
|
||||||
|
|
@ -121,15 +151,15 @@ struct NotchTerminalView: View {
|
||||||
.padding(.bottom, 4)
|
.padding(.bottom, 4)
|
||||||
|
|
||||||
Divider()
|
Divider()
|
||||||
.padding(.horizontal, 8)
|
.padding(.horizontal, notchTerminalContentEdgePadding.horizontal)
|
||||||
|
|
||||||
// Terminal content — the containerView is stable across
|
// Terminal content — the containerView is stable across
|
||||||
// notch close/open cycles; updateNSView handles restart.
|
// notch close/open cycles; updateNSView handles restart.
|
||||||
TerminalNSViewRepresentable(terminalManager: terminalManager)
|
TerminalNSViewRepresentable(terminalManager: terminalManager)
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 6, style: .continuous))
|
.clipShape(terminalClipShape)
|
||||||
.padding(.horizontal, 8)
|
.padding(.horizontal, notchTerminalContentEdgePadding.horizontal)
|
||||||
.padding(.bottom, 8)
|
.padding(.bottom, notchTerminalContentEdgePadding.bottom)
|
||||||
.padding(.top, 4)
|
.padding(.top, notchTerminalContentEdgePadding.top)
|
||||||
.onHover { hovering in
|
.onHover { hovering in
|
||||||
updateSuppression(for: hovering)
|
updateSuppression(for: hovering)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -897,7 +897,7 @@ struct SettingsView: View {
|
||||||
SettingsSearchEntry(tab: .terminal, title: "Enable terminal", keywords: ["terminal", "guake", "shell"], highlightID: SettingsTab.terminal.highlightID(for: "Enable terminal")),
|
SettingsSearchEntry(tab: .terminal, title: "Enable terminal", keywords: ["terminal", "guake", "shell"], highlightID: SettingsTab.terminal.highlightID(for: "Enable terminal")),
|
||||||
SettingsSearchEntry(tab: .terminal, title: "Shell path", keywords: ["shell", "zsh", "bash", "terminal"], highlightID: SettingsTab.terminal.highlightID(for: "Shell path")),
|
SettingsSearchEntry(tab: .terminal, title: "Shell path", keywords: ["shell", "zsh", "bash", "terminal"], highlightID: SettingsTab.terminal.highlightID(for: "Shell path")),
|
||||||
SettingsSearchEntry(tab: .terminal, title: "Font size", keywords: ["terminal", "font", "text size"], highlightID: SettingsTab.terminal.highlightID(for: "Font size")),
|
SettingsSearchEntry(tab: .terminal, title: "Font size", keywords: ["terminal", "font", "text size"], highlightID: SettingsTab.terminal.highlightID(for: "Font size")),
|
||||||
SettingsSearchEntry(tab: .terminal, title: "Terminal opacity", keywords: ["terminal", "opacity", "transparency"], highlightID: SettingsTab.terminal.highlightID(for: "Terminal opacity")),
|
SettingsSearchEntry(tab: .terminal, title: "Terminal opacity", keywords: ["terminal", "opacity", "transparency", "blur", "background"], highlightID: SettingsTab.terminal.highlightID(for: "Terminal opacity")),
|
||||||
SettingsSearchEntry(tab: .terminal, title: "Maximum height", keywords: ["terminal", "height", "size"], highlightID: SettingsTab.terminal.highlightID(for: "Maximum height")),
|
SettingsSearchEntry(tab: .terminal, title: "Maximum height", keywords: ["terminal", "height", "size"], highlightID: SettingsTab.terminal.highlightID(for: "Maximum height")),
|
||||||
SettingsSearchEntry(tab: .terminal, title: "Background color", keywords: ["terminal", "background", "color", "theme"], highlightID: SettingsTab.terminal.highlightID(for: "Background color")),
|
SettingsSearchEntry(tab: .terminal, title: "Background color", keywords: ["terminal", "background", "color", "theme"], highlightID: SettingsTab.terminal.highlightID(for: "Background color")),
|
||||||
SettingsSearchEntry(tab: .terminal, title: "Foreground color", keywords: ["terminal", "foreground", "text color", "theme"], highlightID: SettingsTab.terminal.highlightID(for: "Foreground color")),
|
SettingsSearchEntry(tab: .terminal, title: "Foreground color", keywords: ["terminal", "foreground", "text color", "theme"], highlightID: SettingsTab.terminal.highlightID(for: "Foreground color")),
|
||||||
|
|
@ -7862,6 +7862,10 @@ struct TerminalSettings: View {
|
||||||
.settingsHighlight(id: highlightID("Maximum height"))
|
.settingsHighlight(id: highlightID("Maximum height"))
|
||||||
} header: {
|
} header: {
|
||||||
Text("Appearance")
|
Text("Appearance")
|
||||||
|
} footer: {
|
||||||
|
Text("Terminal opacity only affects the terminal backdrop; text stays fully opaque. Blur uses the system material behind the window.")
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Colors
|
// MARK: Colors
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import AppKit
|
||||||
import Foundation
|
import Foundation
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import SwiftTerm
|
import SwiftTerm
|
||||||
|
|
@ -89,12 +90,24 @@ class TerminalManager: ObservableObject {
|
||||||
let v = StableTerminalContainerView(frame: .zero)
|
let v = StableTerminalContainerView(frame: .zero)
|
||||||
v.autoresizingMask = [.width, .height]
|
v.autoresizingMask = [.width, .height]
|
||||||
v.wantsLayer = true
|
v.wantsLayer = true
|
||||||
|
v.layer?.backgroundColor = NSColor.clear.cgColor
|
||||||
return v
|
return v
|
||||||
}()
|
}()
|
||||||
|
|
||||||
/// The actual terminal view (child of `containerView`).
|
/// The actual terminal view (child of `containerView`).
|
||||||
private(set) var terminalView: LocalProcessTerminalView?
|
private(set) var terminalView: LocalProcessTerminalView?
|
||||||
|
|
||||||
|
/// Frosted blur of desktop/content behind the terminal; always below `terminalView`.
|
||||||
|
private lazy var terminalBackgroundEffectView: NSVisualEffectView = {
|
||||||
|
let v = NSVisualEffectView()
|
||||||
|
// Minimal frosted look with very light blur/vibrancy.
|
||||||
|
v.material = .underWindowBackground
|
||||||
|
v.blendingMode = .behindWindow
|
||||||
|
v.state = .active
|
||||||
|
v.autoresizingMask = [.width, .height]
|
||||||
|
return v
|
||||||
|
}()
|
||||||
|
|
||||||
private init() {}
|
private init() {}
|
||||||
|
|
||||||
// MARK: - Lifecycle
|
// MARK: - Lifecycle
|
||||||
|
|
@ -107,7 +120,7 @@ class TerminalManager: ObservableObject {
|
||||||
existing.processDelegate = delegate
|
existing.processDelegate = delegate
|
||||||
// Force a redraw — the view may have been off-screen (notch closed)
|
// Force a redraw — the view may have been off-screen (notch closed)
|
||||||
// and needs to re-render the terminal buffer.
|
// and needs to re-render the terminal buffer.
|
||||||
existing.needsDisplay = true
|
synchronizeTerminalTranslucencyPresentation(to: existing)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -119,6 +132,9 @@ class TerminalManager: ObservableObject {
|
||||||
? containerView.bounds
|
? containerView.bounds
|
||||||
: CGRect(x: 0, y: 0, width: 400, height: 300)
|
: CGRect(x: 0, y: 0, width: 400, height: 300)
|
||||||
|
|
||||||
|
// Replace only the terminal view - keep the blur underlay between restarts.
|
||||||
|
terminalView?.removeFromSuperview()
|
||||||
|
|
||||||
let view = LocalProcessTerminalView(frame: initialFrame)
|
let view = LocalProcessTerminalView(frame: initialFrame)
|
||||||
view.autoresizingMask = [.width, .height]
|
view.autoresizingMask = [.width, .height]
|
||||||
|
|
||||||
|
|
@ -127,14 +143,16 @@ class TerminalManager: ObservableObject {
|
||||||
|
|
||||||
view.processDelegate = delegate
|
view.processDelegate = delegate
|
||||||
|
|
||||||
// Mount inside the stable container
|
if terminalBackgroundEffectView.superview == nil {
|
||||||
containerView.subviews.forEach { $0.removeFromSuperview() }
|
containerView.addSubview(terminalBackgroundEffectView)
|
||||||
|
}
|
||||||
containerView.addSubview(view)
|
containerView.addSubview(view)
|
||||||
terminalView = view
|
terminalView = view
|
||||||
|
|
||||||
// If the container already has a valid size, snap the child to it.
|
// If the container already has a valid size, snap the child to it.
|
||||||
let containerSize = containerView.bounds.size
|
let containerSize = containerView.bounds.size
|
||||||
if containerSize.width >= 10, containerSize.height >= 10 {
|
if containerSize.width >= 10, containerSize.height >= 10 {
|
||||||
|
terminalBackgroundEffectView.frame = containerView.bounds
|
||||||
view.frame = containerView.bounds
|
view.frame = containerView.bounds
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -196,6 +214,40 @@ class TerminalManager: ObservableObject {
|
||||||
return NSFont.monospacedSystemFont(ofSize: size, weight: .regular)
|
return NSFont.monospacedSystemFont(ofSize: size, weight: .regular)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Background color with opacity slider applied to alpha only (glyphs stay fully opaque).
|
||||||
|
private func resolvedTerminalBackgroundNSColor(
|
||||||
|
baseColor: NSColor? = nil,
|
||||||
|
opacitySlider: CGFloat? = nil
|
||||||
|
) -> NSColor {
|
||||||
|
let raw = baseColor ?? NSColor(Defaults[.terminalBackgroundColor])
|
||||||
|
let rgb = raw.usingColorSpace(.deviceRGB) ?? raw.usingColorSpace(.sRGB) ?? raw
|
||||||
|
let opacity = opacitySlider ?? CGFloat(Defaults[.terminalOpacity])
|
||||||
|
let alpha = CGFloat(rgb.cgColor.alpha) * opacity
|
||||||
|
return rgb.withAlphaComponent(alpha)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Composites the terminal buffer over `terminalBackgroundEffectView` without dimming glyphs.
|
||||||
|
/// SwiftTerm’s `TerminalView.isOpaque` is read-only; translucency relies on alpha in `nativeBackgroundColor`.
|
||||||
|
private func applyTerminalBackgroundAppearance(to view: LocalProcessTerminalView) {
|
||||||
|
view.layer?.opacity = 1
|
||||||
|
view.nativeBackgroundColor = resolvedTerminalBackgroundNSColor()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Upstream `TerminalView.setupOptions()` assigns `layer.backgroundColor` from `nativeBackgroundColor`, which
|
||||||
|
/// prevents the `NSVisualEffectView` under the terminal from showing through. Re-clear after our color updates.
|
||||||
|
/// Default-cell alpha and attribute-cache invalidation on native color changes may still need a SwiftTerm PR
|
||||||
|
private func applyTerminalLayerTranslucencyHacks(to view: LocalProcessTerminalView) {
|
||||||
|
view.layer?.backgroundColor = NSColor.clear.cgColor
|
||||||
|
view.layer?.isOpaque = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Best-effort redraw. `TerminalView.installColors(_:)` could clear SwiftTerm color caches but needs 16
|
||||||
|
/// `SwiftTerm.Color` values; `Terminal.ansiColors` is not public, so we do not duplicate a palette here.
|
||||||
|
private func synchronizeTerminalTranslucencyPresentation(to view: LocalProcessTerminalView) {
|
||||||
|
applyTerminalLayerTranslucencyHacks(to: view)
|
||||||
|
view.setNeedsDisplay(view.bounds)
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Settings Application
|
// MARK: - Settings Application
|
||||||
|
|
||||||
/// Applies all persisted settings to a terminal view at creation time.
|
/// Applies all persisted settings to a terminal view at creation time.
|
||||||
|
|
@ -205,11 +257,8 @@ class TerminalManager: ObservableObject {
|
||||||
let fontFamily = Defaults[.terminalFontFamily]
|
let fontFamily = Defaults[.terminalFontFamily]
|
||||||
view.font = resolveFont(family: fontFamily, size: fontSize)
|
view.font = resolveFont(family: fontFamily, size: fontSize)
|
||||||
|
|
||||||
// Opacity
|
// Colors (background opacity is separate from terminal opacity slider — see `applyTerminalBackgroundAppearance`)
|
||||||
view.layer?.opacity = Float(Defaults[.terminalOpacity])
|
applyTerminalBackgroundAppearance(to: view)
|
||||||
|
|
||||||
// Colors
|
|
||||||
view.nativeBackgroundColor = NSColor(Defaults[.terminalBackgroundColor])
|
|
||||||
view.nativeForegroundColor = NSColor(Defaults[.terminalForegroundColor])
|
view.nativeForegroundColor = NSColor(Defaults[.terminalForegroundColor])
|
||||||
view.caretColor = NSColor(Defaults[.terminalCursorColor])
|
view.caretColor = NSColor(Defaults[.terminalCursorColor])
|
||||||
|
|
||||||
|
|
@ -219,6 +268,7 @@ class TerminalManager: ObservableObject {
|
||||||
view.getTerminal().setCursorStyle(cursorStyle.swiftTermStyle)
|
view.getTerminal().setCursorStyle(cursorStyle.swiftTermStyle)
|
||||||
|
|
||||||
// Keep drawing the selected cursor style when TerminalView.hasFocus is false; SwiftTerm
|
// Keep drawing the selected cursor style when TerminalView.hasFocus is false; SwiftTerm
|
||||||
|
// otherwise uses an unfocused/outline caret while tracksFocus is true.
|
||||||
view.caretViewTracksFocus = false
|
view.caretViewTracksFocus = false
|
||||||
|
|
||||||
// Scrollback
|
// Scrollback
|
||||||
|
|
@ -232,6 +282,8 @@ class TerminalManager: ObservableObject {
|
||||||
|
|
||||||
// Rendering
|
// Rendering
|
||||||
view.useBrightColors = Defaults[.terminalBoldAsBright]
|
view.useBrightColors = Defaults[.terminalBoldAsBright]
|
||||||
|
|
||||||
|
synchronizeTerminalTranslucencyPresentation(to: view)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates font size on the live terminal view.
|
/// Updates font size on the live terminal view.
|
||||||
|
|
@ -248,10 +300,12 @@ class TerminalManager: ObservableObject {
|
||||||
view.font = resolveFont(family: family, size: fontSize)
|
view.font = resolveFont(family: family, size: fontSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates opacity on the live terminal view.
|
/// Updates background opacity on the live terminal view (glyphs stay fully opaque).
|
||||||
func applyOpacity(_ opacity: Double) {
|
func applyOpacity(_ opacity: Double) {
|
||||||
guard let view = terminalView else { return }
|
guard let view = terminalView else { return }
|
||||||
view.layer?.opacity = Float(opacity)
|
view.layer?.opacity = 1
|
||||||
|
view.nativeBackgroundColor = resolvedTerminalBackgroundNSColor(opacitySlider: CGFloat(opacity))
|
||||||
|
synchronizeTerminalTranslucencyPresentation(to: view)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates cursor style on the live terminal view.
|
/// Updates cursor style on the live terminal view.
|
||||||
|
|
@ -289,13 +343,16 @@ class TerminalManager: ObservableObject {
|
||||||
/// Updates background color on the live terminal view.
|
/// Updates background color on the live terminal view.
|
||||||
func applyBackgroundColor(_ color: SwiftUI.Color) {
|
func applyBackgroundColor(_ color: SwiftUI.Color) {
|
||||||
guard let view = terminalView else { return }
|
guard let view = terminalView else { return }
|
||||||
view.nativeBackgroundColor = NSColor(color)
|
view.layer?.opacity = 1
|
||||||
|
view.nativeBackgroundColor = resolvedTerminalBackgroundNSColor(baseColor: NSColor(color))
|
||||||
|
synchronizeTerminalTranslucencyPresentation(to: view)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates foreground color on the live terminal view.
|
/// Updates foreground color on the live terminal view.
|
||||||
func applyForegroundColor(_ color: SwiftUI.Color) {
|
func applyForegroundColor(_ color: SwiftUI.Color) {
|
||||||
guard let view = terminalView else { return }
|
guard let view = terminalView else { return }
|
||||||
view.nativeForegroundColor = NSColor(color)
|
view.nativeForegroundColor = NSColor(color)
|
||||||
|
synchronizeTerminalTranslucencyPresentation(to: view)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates cursor color on the live terminal view.
|
/// Updates cursor color on the live terminal view.
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,46 @@ var minimalisticOpenNotchSize: CGSize {
|
||||||
let cornerRadiusInsets: (opened: (top: CGFloat, bottom: CGFloat), closed: (top: CGFloat, bottom: CGFloat)) = (opened: (top: 19, bottom: 24), closed: (top: 6, bottom: 14))
|
let cornerRadiusInsets: (opened: (top: CGFloat, bottom: CGFloat), closed: (top: CGFloat, bottom: CGFloat)) = (opened: (top: 19, bottom: 24), closed: (top: 6, bottom: 14))
|
||||||
let minimalisticCornerRadiusInsets: (opened: (top: CGFloat, bottom: CGFloat), closed: (top: CGFloat, bottom: CGFloat)) = (opened: (top: 35, bottom: 35), closed: cornerRadiusInsets.closed)
|
let minimalisticCornerRadiusInsets: (opened: (top: CGFloat, bottom: CGFloat), closed: (top: CGFloat, bottom: CGFloat)) = (opened: (top: 35, bottom: 35), closed: cornerRadiusInsets.closed)
|
||||||
|
|
||||||
|
// MARK: - Terminal tab clip (notch surface)
|
||||||
|
|
||||||
|
/// Padding on the terminal block inside the notch. Inner corner radius = outer shell radius on that edge, minus the matching edge padding.
|
||||||
|
let notchTerminalContentEdgePadding: (top: CGFloat, horizontal: CGFloat, bottom: CGFloat) = (4, 8, 8)
|
||||||
|
|
||||||
|
/// Bottom radii for the shell (outer) and the terminal ``clipShape`` (inner), per design: inner = outer shell bottom radius − `notchTerminalContentEdgePadding.bottom`.
|
||||||
|
func notchTerminalBottomCornerRadii(
|
||||||
|
isDynamicIslandMode: Bool,
|
||||||
|
notchState: NotchState,
|
||||||
|
cornerRadiusScaling: Bool,
|
||||||
|
enableMinimalisticUI: Bool,
|
||||||
|
closedNotchHeight: CGFloat
|
||||||
|
) -> (outerBottom: CGFloat, innerBottom: CGFloat) {
|
||||||
|
let p = notchTerminalContentEdgePadding.bottom
|
||||||
|
if isDynamicIslandMode {
|
||||||
|
let outer: CGFloat
|
||||||
|
if notchState == .open {
|
||||||
|
outer = enableMinimalisticUI
|
||||||
|
? minimalisticCornerRadiusInsets.opened.top
|
||||||
|
: dynamicIslandPillCornerRadiusInsets.opened
|
||||||
|
} else {
|
||||||
|
outer = max(closedNotchHeight / 2, dynamicIslandPillCornerRadiusInsets.closed.standard)
|
||||||
|
}
|
||||||
|
return (outer, max(0, outer - p))
|
||||||
|
}
|
||||||
|
let active: (opened: (top: CGFloat, bottom: CGFloat), closed: (top: CGFloat, bottom: CGFloat)) = {
|
||||||
|
if enableMinimalisticUI {
|
||||||
|
return (opened: minimalisticCornerRadiusInsets.opened, closed: cornerRadiusInsets.closed)
|
||||||
|
}
|
||||||
|
return cornerRadiusInsets
|
||||||
|
}()
|
||||||
|
let outerBottom: CGFloat
|
||||||
|
if notchState == .open && cornerRadiusScaling {
|
||||||
|
outerBottom = active.opened.bottom
|
||||||
|
} else {
|
||||||
|
outerBottom = active.closed.bottom
|
||||||
|
}
|
||||||
|
return (outerBottom, max(0, outerBottom - p))
|
||||||
|
}
|
||||||
|
|
||||||
func statsAdjustedNotchSize(
|
func statsAdjustedNotchSize(
|
||||||
from baseSize: CGSize,
|
from baseSize: CGSize,
|
||||||
isStatsTabActive: Bool,
|
isStatsTabActive: Bool,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue