Skip to content
Open
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
6 changes: 4 additions & 2 deletions NotchFlow.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@
2474D448FEE15E2DADFF838D = { isa = PBXBuildFile; fileRef = A6639F26620839C4BDA4701E; };
5C3CF4321B18A8F1CF711060 = { isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sources/NotchCore/Timeline.swift"; sourceTree = SOURCE_ROOT; };
D6BA4A33AC1853D7F1789809 = { isa = PBXBuildFile; fileRef = 5C3CF4321B18A8F1CF711060; };
392A9A39E34F4EF8E7C6966C = { isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sources/NotchCore/TransitionIntervalRegistry.swift"; sourceTree = SOURCE_ROOT; };
6752229172BF1214D083E0E8 = { isa = PBXBuildFile; fileRef = 392A9A39E34F4EF8E7C6966C; };
CC5E1673DB3296059A654139 = { isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sources/NotchCore/WorkModes.swift"; sourceTree = SOURCE_ROOT; };
3D2F4E3AE05A63FDAF46CB2F = { isa = PBXBuildFile; fileRef = CC5E1673DB3296059A654139; };
7662768407F1DC45247CF84A = { isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Sources/NotchFlow/AppModel.swift"; sourceTree = SOURCE_ROOT; };
Expand Down Expand Up @@ -167,9 +169,9 @@
B6C393742C1DDE3CB7732468 = { isa = PBXFileReference; lastKnownFileType = text.script.python; path = "Scripts/notchflow.py"; sourceTree = SOURCE_ROOT; };
F714C0DF77BCFA1211A6F966 = { isa = PBXBuildFile; fileRef = B6C393742C1DDE3CB7732468; };
A8792157CB4F27FB949C035F = { isa = PBXFileReference; explicitFileType = wrapper.application; path = NotchFlow.app; sourceTree = BUILT_PRODUCTS_DIR; };
0035FE99EA2940F7FA633A58 = { isa = PBXGroup; children = (1812E8B283BFA47E69ACF399, 5A7F3F4A84031311E77A0164, 3CECEB5FED9E7F500491C577, 6C8E7615C783C1BB78872203, 3A44419E062027A7AAE2EAA0, B2251B3A8A69C20563F23364, 1F1CE127F2DA86EBEE72F2D2, A600C9D44FF2DA4115C53F69, B4DB45235D65BE4421B19A78, D7AFE7FE17A534E8C11E0741, ECB4528FB658C13A5365C02E, C87CDC1F23C8BCBA8CEB56F9, F55D58E371080DCFDB4F2E2F, 789C7952C7B72ADF848C3A09, 5F6D718D550D61BF82A9DA01, 3C2BB994AE027908279A6248, E94744F9046A05B3E63E22FE, 2E3E4036F075C3292C666964, 511DF09574F487963110ECCF, A9EC388D89B5F9807A823AD9, 85ED6DD8B022695B2E7B7F69, 7CD2263EE188315B17365101, FF8B038819A03750DB8544FB, AAB4A21093B8BC3026FBD591, A6639F26620839C4BDA4701E, 5C3CF4321B18A8F1CF711060, CC5E1673DB3296059A654139, 7662768407F1DC45247CF84A, F5CEC30DF457DCC196D8C6E0, D53852D5A8909E20842259FE, 7A0532B3F9E75328B24C97B5, B624CC734F280E2228750B86, 8EFA8E362640111D53EFF11E, C3E619E1D9D9316D4F3EBF0E, DCD0F5F44ACC1FBBEB2E9F8F, D8493B8BB73A675459CF7C12, 2CE4310076E05B278EC12F4F, 692426AE4E2A9BFE1A8EDC6D, 17E18A8FCF74DEE64ED78072, 77F67997CDD48A577E49297F, E81FA485C0156AF16D3B198A, 15FF0F7E2051E86CD4723E1C, EEE56F64100039B0DC2813BE, E01147EBA180B37F512D7256, A4E75153FB9CF98AE6123B6A, 3AF5B6094E9D5C89BE0C4088, 04CD8EE537105AA9D2B75030, 89085FDB7A32B3FA369D24B7, E70E1AA159EEE19A3D25871A, E15751F19DCC4825F9EF6053, 78F2B557AA84D34297A2EA2A, 684F7615F080636075073DF4, 16972D44735623105011B979, 68BF9C0431C353478780D2DD, 0AF638319A3D2B29C2FAF29B, 11D26DB1A9C4CFF06FAB2932, 500D7EF02DC6387D3856315E, 2F406AC7154319C1729DD753, 71062BB5D783B1CBC1277469, A70EF3AB270C49660EF54D55, 45F44E17E17DCE2167115EF9, B747F1C3548B2543672F1D84, C81171208111C59DAD1040D9, E38888276C2D8500D6A5C9AE, 46220EFC9838C84B38DAED3E, 2DC2CB5E3D845883C804A4F0, 4C0F4C852EE05628755056C9, B2AD5ED812CAF86438F4850D, 459943405DC95355A27C801A, 844A74B6C1831CBC03BE2081, 78D02551F5C92BC94130A61E, BB90A00D022CCA3247177E6E, F412C5DA8349178C87AA267A, F2190E9992189FA413D5A143, 3ABBA1256D201227AA4AB570, 9F057A3F58A7AAA52387EAF8, D2D012F243FA677616977CB9, D5BA9F5650E82F36BAC4F650, 42E9A23F63FA1F271F7952C7, FF5E144ABB5323C66E1BF272, B6C393742C1DDE3CB7732468, 0A3E27B8CA818264D75C8D81); sourceTree = "<group>"; };
0035FE99EA2940F7FA633A58 = { isa = PBXGroup; children = (1812E8B283BFA47E69ACF399, 5A7F3F4A84031311E77A0164, 3CECEB5FED9E7F500491C577, 6C8E7615C783C1BB78872203, 3A44419E062027A7AAE2EAA0, B2251B3A8A69C20563F23364, 1F1CE127F2DA86EBEE72F2D2, A600C9D44FF2DA4115C53F69, B4DB45235D65BE4421B19A78, D7AFE7FE17A534E8C11E0741, ECB4528FB658C13A5365C02E, C87CDC1F23C8BCBA8CEB56F9, F55D58E371080DCFDB4F2E2F, 789C7952C7B72ADF848C3A09, 5F6D718D550D61BF82A9DA01, 3C2BB994AE027908279A6248, E94744F9046A05B3E63E22FE, 2E3E4036F075C3292C666964, 511DF09574F487963110ECCF, A9EC388D89B5F9807A823AD9, 85ED6DD8B022695B2E7B7F69, 7CD2263EE188315B17365101, FF8B038819A03750DB8544FB, AAB4A21093B8BC3026FBD591, A6639F26620839C4BDA4701E, 5C3CF4321B18A8F1CF711060, 392A9A39E34F4EF8E7C6966C, CC5E1673DB3296059A654139, 7662768407F1DC45247CF84A, F5CEC30DF457DCC196D8C6E0, D53852D5A8909E20842259FE, 7A0532B3F9E75328B24C97B5, B624CC734F280E2228750B86, 8EFA8E362640111D53EFF11E, C3E619E1D9D9316D4F3EBF0E, DCD0F5F44ACC1FBBEB2E9F8F, D8493B8BB73A675459CF7C12, 2CE4310076E05B278EC12F4F, 692426AE4E2A9BFE1A8EDC6D, 17E18A8FCF74DEE64ED78072, 77F67997CDD48A577E49297F, E81FA485C0156AF16D3B198A, 15FF0F7E2051E86CD4723E1C, EEE56F64100039B0DC2813BE, E01147EBA180B37F512D7256, A4E75153FB9CF98AE6123B6A, 3AF5B6094E9D5C89BE0C4088, 04CD8EE537105AA9D2B75030, 89085FDB7A32B3FA369D24B7, E70E1AA159EEE19A3D25871A, E15751F19DCC4825F9EF6053, 78F2B557AA84D34297A2EA2A, 684F7615F080636075073DF4, 16972D44735623105011B979, 68BF9C0431C353478780D2DD, 0AF638319A3D2B29C2FAF29B, 11D26DB1A9C4CFF06FAB2932, 500D7EF02DC6387D3856315E, 2F406AC7154319C1729DD753, 71062BB5D783B1CBC1277469, A70EF3AB270C49660EF54D55, 45F44E17E17DCE2167115EF9, B747F1C3548B2543672F1D84, C81171208111C59DAD1040D9, E38888276C2D8500D6A5C9AE, 46220EFC9838C84B38DAED3E, 2DC2CB5E3D845883C804A4F0, 4C0F4C852EE05628755056C9, B2AD5ED812CAF86438F4850D, 459943405DC95355A27C801A, 844A74B6C1831CBC03BE2081, 78D02551F5C92BC94130A61E, BB90A00D022CCA3247177E6E, F412C5DA8349178C87AA267A, F2190E9992189FA413D5A143, 3ABBA1256D201227AA4AB570, 9F057A3F58A7AAA52387EAF8, D2D012F243FA677616977CB9, D5BA9F5650E82F36BAC4F650, 42E9A23F63FA1F271F7952C7, FF5E144ABB5323C66E1BF272, B6C393742C1DDE3CB7732468, 0A3E27B8CA818264D75C8D81); sourceTree = "<group>"; };
0A3E27B8CA818264D75C8D81 = { isa = PBXGroup; children = (A8792157CB4F27FB949C035F); name = Products; sourceTree = "<group>"; };
878A52FC5FF6A57D50B7B870 = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = (838101EDC745C9EFCDB55F3F, DCA2235244451FCE80737304, 170288596C038EF9B38CA6FA, 52884E6A43586698ED3486BE, 2C85CC51357BA5BE7CDEECD3, DD00439CF4DD9E2483E9B999, 291F94D3B4E66E1045F31F46, 50865D8BFA857D0DEFE8D0C0, 8C75EB5252B61D45C2871EEE, F88E6F53A0051910DCE1D09D, 98DD6C30DC7F90C69BB855C8, CBC97E30829C4AAE1C00868F, 770A585B15611EEC04DEEBE6, 887815FA4A2C30D4F1F16A61, E72EB16ED23150CF0FDB894F, 808BAC9090B028993A247770, 71ACDE9B681C5A6C5C01F8D2, 67FCE41B7186EFB7E3BBD49A, 3D0B56E84808AEC94EA8DDCA, D031EB49C9F328486BD17D2E, 4214CA1947E72F5BC46DBE14, C42C662069F0383132CCF353, DAA44475EDA1C067556CA787, EAEFE9839FA0C87258C83F9A, 2474D448FEE15E2DADFF838D, D6BA4A33AC1853D7F1789809, 3D2F4E3AE05A63FDAF46CB2F, 7F93D0030D6CEA347839D22D, 5E7135314858C63292B460A3, 5D249582000EE04FC9BEEC2B, B58F2C891C84245C8C76C818, 30A9344796424F2567B3ECB2, 7EECE407F12410D1E029CDD8, 581AB9187434E966786FF36F, E663333A273183C55AEC4B38, CC4C468E306D37931984A146, 9D1F5DA9721B8BAB79B7373D, CAE4BBD9BD29D0891D371623, 68FBF284B2705FFC53C313BE, 8518B3F2AE8EC2E55686DFB6, 07C857639B90B358A5B23DB6, B7BF9E4A5762374B2C7C7A83, ADB2510331CEB1334829A98F, C8485529E03C40D59B0BE5B4, F7B45BE0D8896FC7A1EC7126, 905AE083FE9DCE006B0E88E4, 22D768C4C80EDCC6C8EB439D, 01CCC6B8F1A60467C3B2FC09, 279BA486166895768D71BCC4, 3690DCC89F4621B2AEAF157C, 75AAEA907F7672C0D284F3CD, C92099F8AE9925DE16A2F029, CB2498B517E78F3959B23C88, BD533AE5B16B836CFB37FD67, 1BD267F6DE19649E1D42F940, 3ECCCC2550B55C0F650CEF17, 3931C005A5DA15A30F5DB448, 8CCD5B83487EEFE097FB15D4, 5BD9808607E19F091C774E8E, F1EF653FC8C58E966BA9B1E1, 83E14EC73E2AC4FCC1677B2F, 21B709EC2DC5E30953571ABB, 01518D97EC7A86C2FB0C6D4B, B102017C9E002123FA416E73, ADCA0CA0938C6B23ED446345, 53E002279F85837476860490, 6E62A967AE1FA4FA642D3171, B005507345F726BF3ED77185, 9CC4CA9B1851BE54B3DBD7BF, EE875DA86603C811FDF2473B, 4FD4E242C5C9C04A88653A1A, 3F9DEED6AADFAA66679A2F12, 9A3E58689C5BCBE915042666, 30C788F984DBC9613186DF04, C0FD643ACB280764A8A27053, 3FFB6426764842656BE2507D, E0A0515482626884BCD06388, 2B2EE2830D2379A3DC654E0C, 124FAFFAC3FECD131F669DDD); runOnlyForDeploymentPostprocessing = 0; };
878A52FC5FF6A57D50B7B870 = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = (838101EDC745C9EFCDB55F3F, DCA2235244451FCE80737304, 170288596C038EF9B38CA6FA, 52884E6A43586698ED3486BE, 2C85CC51357BA5BE7CDEECD3, DD00439CF4DD9E2483E9B999, 291F94D3B4E66E1045F31F46, 50865D8BFA857D0DEFE8D0C0, 8C75EB5252B61D45C2871EEE, F88E6F53A0051910DCE1D09D, 98DD6C30DC7F90C69BB855C8, CBC97E30829C4AAE1C00868F, 770A585B15611EEC04DEEBE6, 887815FA4A2C30D4F1F16A61, E72EB16ED23150CF0FDB894F, 808BAC9090B028993A247770, 71ACDE9B681C5A6C5C01F8D2, 67FCE41B7186EFB7E3BBD49A, 3D0B56E84808AEC94EA8DDCA, D031EB49C9F328486BD17D2E, 4214CA1947E72F5BC46DBE14, C42C662069F0383132CCF353, DAA44475EDA1C067556CA787, EAEFE9839FA0C87258C83F9A, 2474D448FEE15E2DADFF838D, D6BA4A33AC1853D7F1789809, 6752229172BF1214D083E0E8, 3D2F4E3AE05A63FDAF46CB2F, 7F93D0030D6CEA347839D22D, 5E7135314858C63292B460A3, 5D249582000EE04FC9BEEC2B, B58F2C891C84245C8C76C818, 30A9344796424F2567B3ECB2, 7EECE407F12410D1E029CDD8, 581AB9187434E966786FF36F, E663333A273183C55AEC4B38, CC4C468E306D37931984A146, 9D1F5DA9721B8BAB79B7373D, CAE4BBD9BD29D0891D371623, 68FBF284B2705FFC53C313BE, 8518B3F2AE8EC2E55686DFB6, 07C857639B90B358A5B23DB6, B7BF9E4A5762374B2C7C7A83, ADB2510331CEB1334829A98F, C8485529E03C40D59B0BE5B4, F7B45BE0D8896FC7A1EC7126, 905AE083FE9DCE006B0E88E4, 22D768C4C80EDCC6C8EB439D, 01CCC6B8F1A60467C3B2FC09, 279BA486166895768D71BCC4, 3690DCC89F4621B2AEAF157C, 75AAEA907F7672C0D284F3CD, C92099F8AE9925DE16A2F029, CB2498B517E78F3959B23C88, BD533AE5B16B836CFB37FD67, 1BD267F6DE19649E1D42F940, 3ECCCC2550B55C0F650CEF17, 3931C005A5DA15A30F5DB448, 8CCD5B83487EEFE097FB15D4, 5BD9808607E19F091C774E8E, F1EF653FC8C58E966BA9B1E1, 83E14EC73E2AC4FCC1677B2F, 21B709EC2DC5E30953571ABB, 01518D97EC7A86C2FB0C6D4B, B102017C9E002123FA416E73, ADCA0CA0938C6B23ED446345, 53E002279F85837476860490, 6E62A967AE1FA4FA642D3171, B005507345F726BF3ED77185, 9CC4CA9B1851BE54B3DBD7BF, EE875DA86603C811FDF2473B, 4FD4E242C5C9C04A88653A1A, 3F9DEED6AADFAA66679A2F12, 9A3E58689C5BCBE915042666, 30C788F984DBC9613186DF04, C0FD643ACB280764A8A27053, 3FFB6426764842656BE2507D, E0A0515482626884BCD06388, 2B2EE2830D2379A3DC654E0C, 124FAFFAC3FECD131F669DDD); runOnlyForDeploymentPostprocessing = 0; };
41D311A605520FC7B8B9A980 = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = (3C9FB2BAAA5E42AD8C29E4AC, F714C0DF77BCFA1211A6F966); runOnlyForDeploymentPostprocessing = 0; };
E2AA269EB967A8853A258BFA = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = (); runOnlyForDeploymentPostprocessing = 0; };
73EBF6644258C120893E685D = { isa = XCBuildConfiguration; buildSettings = { SDKROOT = "macosx"; MACOSX_DEPLOYMENT_TARGET = "14.6"; SWIFT_VERSION = "5.0"; CLANG_ENABLE_MODULES = "YES"; SWIFT_STRICT_CONCURRENCY = "targeted"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG"; }; name = Debug; };
Expand Down
26 changes: 26 additions & 0 deletions Sources/NotchCore/TransitionIntervalRegistry.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
enum TransitionIntervalEndReason: Equatable {
case completed
case fallback
case superseded(by: Int)
}

struct TransitionIntervalRegistry<Value> {
private var intervals: [Int: Value] = [:]

mutating func insert(_ interval: Value, for transition: Int) {
precondition(intervals[transition] == nil)
intervals[transition] = interval
}

mutating func end(_ transition: Int, reason: TransitionIntervalEndReason)
-> (transition: Int, interval: Value, reason: TransitionIntervalEndReason)? {
intervals.removeValue(forKey: transition).map { (transition, $0, reason) }
}

mutating func supersede(before latestTransition: Int)
-> [(transition: Int, interval: Value, reason: TransitionIntervalEndReason)] {
intervals.keys.filter { $0 < latestTransition }.sorted().compactMap { transition in
intervals.removeValue(forKey: transition).map { (transition, $0, .superseded(by: latestTransition)) }
}
}
}
38 changes: 33 additions & 5 deletions Sources/NotchFlow/AppModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import SwiftUI
import SwiftData
import Combine
import CoreAudio
import os

/// One-second clock that runs only while something on screen counts down. Views that show time
/// observe this instead of the model, so the rest of the surface never redraws on a tick.
Expand Down Expand Up @@ -683,6 +684,20 @@ struct CommandItem: Identifiable {
focusing ? FlowGuardian.lowestPriorityDuringFocus : .silent))
}

private func signpostName(from previous: Presentation, to next: Presentation) -> StaticString {
switch (previous, next) {
case (.collapsed, .collapsed): return "collapsed→collapsed"
case (.collapsed, .preview): return "collapsed→preview"
case (.collapsed, .expanded): return "collapsed→expanded"
case (.preview, .collapsed): return "preview→collapsed"
case (.preview, .preview): return "preview→preview"
case (.preview, .expanded): return "preview→expanded"
case (.expanded, .collapsed): return "expanded→collapsed"
case (.expanded, .preview): return "expanded→preview"
case (.expanded, .expanded): return "expanded→expanded"
}
}

func send(_ event: InteractionEvent) {
var next = snapshot; next.interaction.send(event)
commit(next)
Expand Down Expand Up @@ -739,6 +754,15 @@ struct CommandItem: Identifiable {
guard next != previous || nextForm != form || also != nil else { return }
if nextForm.size != form.size { windows?.prepare(for: nextForm.size) }
let transition = windows?.beginTransition() ?? 0
let intervalName: StaticString?
let transitionWindows = windows
if let transitionWindows, transitionWindows.signposter.isEnabled {
let name = signpostName(from: previous.interaction.presentation, to: next.interaction.presentation)
intervalName = name
transitionWindows.beginSignpostInterval(name, for: transition)
} else {
intervalName = nil
}
let reshaping = nextForm.size != previousForm.size || next.interaction.presentation != previous.interaction.presentation
let portalMoved = next.interaction.portal != previous.interaction.portal && next.interaction.presentation != .expanded
let motion = animation ?? (portalMoved ? Motion.portal(to: next.interaction.portal)
Expand All @@ -758,13 +782,17 @@ struct CommandItem: Identifiable {
if nextForm.size != previousForm.size { windows?.prepare(for: nextForm.size) }
}
form = nextForm
} completion: { [weak self] in
self?.windows?.settle(transition)
if self?.windows?.isLatest(transition) ?? true { self?.surfaceMoving = false }
} completion: { [weak self, transitionWindows] in
if intervalName != nil { transitionWindows?.endSignpostInterval(transition, reason: .completed) }
transitionWindows?.settle(transition)
if transitionWindows?.isLatest(transition) ?? true { self?.surfaceMoving = false }
}
// Completions can be held back while the window isn't drawn (Mission Control, occlusion). A timed
// fallback still trims the panel, so it never lingers as an invisible block over the menu bar.
DispatchQueue.main.asyncAfter(deadline: .now() + 0.9) { [weak self] in self?.windows?.settle(transition) }
// fallback closes its interval and trims the panel, so neither lingers while the window is hidden.
DispatchQueue.main.asyncAfter(deadline: .now() + 0.9) { [transitionWindows] in
if intervalName != nil { transitionWindows?.endSignpostInterval(transition, reason: .fallback) }
transitionWindows?.settle(transition)
}
didCommit(from: previous)
}

Expand Down
Loading