listless

A simple list app for Apple platforms
Log | Files | Refs | README | LICENSE

commit 27d3568ac9b8a0a47f8631d56718514aa270458b
parent 9d81e0ddac30910a5663550667ca43b8ae49d19a
Author: Michael Camilleri <[email protected]>
Date:   Sun,  8 Feb 2026 13:48:47 +0900

Make toolbar Mac only

Co-Authored-By: Claude 4.5 Sonnet <[email protected]>

Diffstat:
MListless.xcodeproj/project.pbxproj | 45+++++++++++++++++++++++++--------------------
MListless.xcodeproj/xcshareddata/xcschemes/Listless iOS.xcscheme | 16++++++++++++----
MListless.xcodeproj/xcshareddata/xcschemes/Listless macOS.xcscheme | 14++++++++++----
MListless/Views/TaskListView.swift | 47++++++++++++++---------------------------------
AListlessMac/Views/TaskListView+Toolbar.swift | 44++++++++++++++++++++++++++++++++++++++++++++
AListlessiOS/Views/TaskListView+Toolbar.swift | 10++++++++++
6 files changed, 115 insertions(+), 61 deletions(-)

diff --git a/Listless.xcodeproj/project.pbxproj b/Listless.xcodeproj/project.pbxproj @@ -3,10 +3,11 @@ archiveVersion = 1; classes = { }; - objectVersion = 63; + objectVersion = 77; objects = { /* Begin PBXBuildFile section */ + 074A81D9DAF58E8E088CBC89 /* TaskListView+Toolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 431B0EA72D590AF0CC868515 /* TaskListView+Toolbar.swift */; }; 0ACA67F6578EFF181EE5C9A7 /* TaskItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBB8A3BEB346267B30B4675F /* TaskItem.swift */; }; 0BB5D2C4FADE3F1E22202814 /* ColorExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917597025B3D5D18E33982D3 /* ColorExtensions.swift */; }; 15B71073767FB4766A6BA2BE /* HoverCursorModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = D41D6E0CED14D79F31C45062 /* HoverCursorModifier.swift */; }; @@ -34,6 +35,7 @@ D6B3DBDD6A3F0A6E166CFFD5 /* TaskRowDragGesture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B3D0B4710C7A0EE4F227851 /* TaskRowDragGesture.swift */; }; D878CD3A552C6A9685A30AA8 /* PlatformTextFieldWidthModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = EF6B0195EA0176B72DE9B092 /* PlatformTextFieldWidthModifier.swift */; }; D8EFF49E9156083D675D47F0 /* KeyboardNavigationModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7B37EF6A2389656D105FF8 /* KeyboardNavigationModifier.swift */; }; + D9DA553485AD0CA28D5BE0C8 /* TaskListView+Toolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93FF5B9F5B979D54D5DEE192 /* TaskListView+Toolbar.swift */; }; DC71C45D92524C3893BF9FDB /* PlatformTextFieldWidthModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81880970CCFC2CB00B65047E /* PlatformTextFieldWidthModifier.swift */; }; DC73A39A269AB495BCE1AC48 /* PersistenceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C14858BDFD1FD5119F1F24A6 /* PersistenceController.swift */; }; ECD5E7EA05AE1C00B38C939E /* TaskStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 967F7ECEB3915CEDCE584872 /* TaskStoreTests.swift */; }; @@ -57,25 +59,27 @@ 01E141436176F83594E2F26B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; }; 0E7B37EF6A2389656D105FF8 /* KeyboardNavigationModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardNavigationModifier.swift; sourceTree = "<group>"; }; 0F2BB7ABCABA4EB67180A200 /* ClickableTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClickableTextField.swift; sourceTree = "<group>"; }; - 126108860D7878DDC3BECC4B /* Listless iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Listless iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 126108860D7878DDC3BECC4B /* Listless iOS.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = "Listless iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 138612F350ECE29526F689B9 /* TaskRowDragGesture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskRowDragGesture.swift; sourceTree = "<group>"; }; 1B3D0B4710C7A0EE4F227851 /* TaskRowDragGesture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskRowDragGesture.swift; sourceTree = "<group>"; }; 1DA467DF2E59BDBE6EEF6A7D /* ListlessMacApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListlessMacApp.swift; sourceTree = "<group>"; }; 2D3A2DDCE24E54ABCCFBBD4C /* TaskStoreOrderingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskStoreOrderingTests.swift; sourceTree = "<group>"; }; 3313FEDB101EECA4B344EEF4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; }; + 431B0EA72D590AF0CC868515 /* TaskListView+Toolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TaskListView+Toolbar.swift"; sourceTree = "<group>"; }; 48AE1AE43296C1692FA6F755 /* PlatformScrollIndicatorsModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlatformScrollIndicatorsModifier.swift; sourceTree = "<group>"; }; - 4FC64B9F9370041BEDBD1E14 /* .gitkeep */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitkeep; sourceTree = "<group>"; }; + 4FC64B9F9370041BEDBD1E14 /* .gitkeep */ = {isa = PBXFileReference; path = .gitkeep; sourceTree = "<group>"; }; 537A913AC421BAEF60D26D9C /* TaskListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskListView.swift; sourceTree = "<group>"; }; 5B0E22B8F7B2B7283CAF749E /* Listless macOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Listless macOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 5E88DDD119EEEECCD45F36D2 /* TaskStoreCompletionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskStoreCompletionTests.swift; sourceTree = "<group>"; }; - 74255E6B6C40899E9B17D927 /* .gitkeep */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitkeep; sourceTree = "<group>"; }; + 74255E6B6C40899E9B17D927 /* .gitkeep */ = {isa = PBXFileReference; path = .gitkeep; sourceTree = "<group>"; }; 75B048B19C5219862BBED2E7 /* TestHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestHelpers.swift; sourceTree = "<group>"; }; 7C73E9D4C42CCABBF0F33543 /* Listless.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Listless.entitlements; sourceTree = "<group>"; }; 81880970CCFC2CB00B65047E /* PlatformTextFieldWidthModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlatformTextFieldWidthModifier.swift; sourceTree = "<group>"; }; 82A3509AD32A54434BCC8017 /* HoverCursorModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HoverCursorModifier.swift; sourceTree = "<group>"; }; 917597025B3D5D18E33982D3 /* ColorExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorExtensions.swift; sourceTree = "<group>"; }; 9262207DAC21619BD9EDEE15 /* Listless.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Listless.entitlements; sourceTree = "<group>"; }; - 944BAE054AAC1B9C4FC954F9 /* .gitkeep */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitkeep; sourceTree = "<group>"; }; + 93FF5B9F5B979D54D5DEE192 /* TaskListView+Toolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TaskListView+Toolbar.swift"; sourceTree = "<group>"; }; + 944BAE054AAC1B9C4FC954F9 /* .gitkeep */ = {isa = PBXFileReference; path = .gitkeep; sourceTree = "<group>"; }; 967F7ECEB3915CEDCE584872 /* TaskStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskStoreTests.swift; sourceTree = "<group>"; }; 97A08C589AB65ED2CB26A092 /* ClickableTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClickableTextField.swift; sourceTree = "<group>"; }; 9B2BBE01D99CDA278BCB9F49 /* TaskStoreEdgeCaseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskStoreEdgeCaseTests.swift; sourceTree = "<group>"; }; @@ -84,10 +88,10 @@ B4D74AE2501F35974F57D21F /* PlatformScrollIndicatorsModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlatformScrollIndicatorsModifier.swift; sourceTree = "<group>"; }; BBDF292392702661DBB94D06 /* ColorExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorExtensions.swift; sourceTree = "<group>"; }; C14858BDFD1FD5119F1F24A6 /* PersistenceController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistenceController.swift; sourceTree = "<group>"; }; - C71466C5CD1A5BA984352F8D /* Listless iOS Unit Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Listless iOS Unit Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - C9B14DC786A336008AAB78EE /* .gitkeep */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitkeep; sourceTree = "<group>"; }; - D10B5491A53E77C80F8F75CD /* .gitkeep */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitkeep; sourceTree = "<group>"; }; - D123BB181208FC825777B0A7 /* .gitkeep */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitkeep; sourceTree = "<group>"; }; + C71466C5CD1A5BA984352F8D /* Listless iOS Unit Tests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = "Listless iOS Unit Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + C9B14DC786A336008AAB78EE /* .gitkeep */ = {isa = PBXFileReference; path = .gitkeep; sourceTree = "<group>"; }; + D10B5491A53E77C80F8F75CD /* .gitkeep */ = {isa = PBXFileReference; path = .gitkeep; sourceTree = "<group>"; }; + D123BB181208FC825777B0A7 /* .gitkeep */ = {isa = PBXFileReference; path = .gitkeep; sourceTree = "<group>"; }; D41D6E0CED14D79F31C45062 /* HoverCursorModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HoverCursorModifier.swift; sourceTree = "<group>"; }; DC3DEE364304587D280C5672 /* TaskStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskStore.swift; sourceTree = "<group>"; }; EF6B0195EA0176B72DE9B092 /* PlatformTextFieldWidthModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlatformTextFieldWidthModifier.swift; sourceTree = "<group>"; }; @@ -134,6 +138,7 @@ 82A3509AD32A54434BCC8017 /* HoverCursorModifier.swift */, 48AE1AE43296C1692FA6F755 /* PlatformScrollIndicatorsModifier.swift */, 81880970CCFC2CB00B65047E /* PlatformTextFieldWidthModifier.swift */, + 93FF5B9F5B979D54D5DEE192 /* TaskListView+Toolbar.swift */, 1B3D0B4710C7A0EE4F227851 /* TaskRowDragGesture.swift */, ); path = Views; @@ -177,6 +182,7 @@ D41D6E0CED14D79F31C45062 /* HoverCursorModifier.swift */, B4D74AE2501F35974F57D21F /* PlatformScrollIndicatorsModifier.swift */, EF6B0195EA0176B72DE9B092 /* PlatformTextFieldWidthModifier.swift */, + 431B0EA72D590AF0CC868515 /* TaskListView+Toolbar.swift */, 138612F350ECE29526F689B9 /* TaskRowDragGesture.swift */, ); path = Views; @@ -300,7 +306,7 @@ isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = YES; - LastUpgradeCheck = 2620; + LastUpgradeCheck = 1430; TargetAttributes = { 0FB4F07A37999BBC6DFE4DBB = { DevelopmentTeam = 7TD7PZBNXP; @@ -326,6 +332,7 @@ ); mainGroup = ED4862258A8A70025EE14416; minimizedProjectReferenceProxies = 1; + preferredProjectObjectVersion = 77; projectDirPath = ""; projectRoot = ""; targets = ( @@ -351,6 +358,7 @@ A8D13DD6196772ECA146CF2A /* PlatformScrollIndicatorsModifier.swift in Sources */, D878CD3A552C6A9685A30AA8 /* PlatformTextFieldWidthModifier.swift in Sources */, C1FE091454864C4BBBBEB077 /* TaskItem.swift in Sources */, + 074A81D9DAF58E8E088CBC89 /* TaskListView+Toolbar.swift in Sources */, 8E08F4C82D6F9E67667CB20A /* TaskListView.swift in Sources */, C1BD61D6DFA687E9CB9ACA60 /* TaskRowDragGesture.swift in Sources */, C2400278D5F6F79C85A68897 /* TaskRowView.swift in Sources */, @@ -372,6 +380,7 @@ 8E680EC18B0339931E785F0C /* PlatformScrollIndicatorsModifier.swift in Sources */, DC71C45D92524C3893BF9FDB /* PlatformTextFieldWidthModifier.swift in Sources */, 0ACA67F6578EFF181EE5C9A7 /* TaskItem.swift in Sources */, + D9DA553485AD0CA28D5BE0C8 /* TaskListView+Toolbar.swift in Sources */, 42E4CDE1D17463554CC4F41F /* TaskListView.swift in Sources */, D6B3DBDD6A3F0A6E166CFFD5 /* TaskRowDragGesture.swift in Sources */, 9041B7CED5298439BF7DC2C1 /* TaskRowView.swift in Sources */, @@ -409,7 +418,7 @@ CODE_SIGN_ENTITLEMENTS = ListlessMac/Listless.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - DEAD_CODE_STRIPPING = YES; + DEVELOPMENT_TEAM = 7TD7PZBNXP; INFOPLIST_FILE = ListlessMac/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -427,7 +436,7 @@ CODE_SIGN_ENTITLEMENTS = ListlessMac/Listless.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - DEAD_CODE_STRIPPING = YES; + DEVELOPMENT_TEAM = 7TD7PZBNXP; INFOPLIST_FILE = ListlessMac/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -472,12 +481,9 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEVELOPMENT_TEAM = 7TD7PZBNXP; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -491,7 +497,6 @@ MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; - STRING_CATALOG_GENERATE_SYMBOLS = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 6; @@ -503,6 +508,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 7TD7PZBNXP; GENERATE_INFOPLIST_FILE = YES; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -550,12 +556,9 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; - DEVELOPMENT_TEAM = 7TD7PZBNXP; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -576,7 +579,6 @@ MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = "$(TARGET_NAME)"; - STRING_CATALOG_GENERATE_SYMBOLS = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 6; @@ -590,6 +592,7 @@ CODE_SIGN_ENTITLEMENTS = ListlessiOS/Listless.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 7TD7PZBNXP; INFOPLIST_FILE = ListlessiOS/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -606,6 +609,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 7TD7PZBNXP; GENERATE_INFOPLIST_FILE = YES; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -626,6 +630,7 @@ CODE_SIGN_ENTITLEMENTS = ListlessiOS/Listless.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 7TD7PZBNXP; INFOPLIST_FILE = ListlessiOS/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", diff --git a/Listless.xcodeproj/xcshareddata/xcschemes/Listless iOS.xcscheme b/Listless.xcodeproj/xcshareddata/xcschemes/Listless iOS.xcscheme @@ -1,10 +1,11 @@ <?xml version="1.0" encoding="UTF-8"?> <Scheme - LastUpgradeVersion = "2620" - version = "1.3"> + LastUpgradeVersion = "1430" + version = "1.7"> <BuildAction parallelizeBuildables = "YES" - buildImplicitDependencies = "YES"> + buildImplicitDependencies = "YES" + runPostActionsOnFailure = "NO"> <BuildActionEntries> <BuildActionEntry buildForTesting = "YES" @@ -26,7 +27,8 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - shouldUseLaunchSchemeArgsEnv = "YES"> + shouldUseLaunchSchemeArgsEnv = "YES" + onlyGenerateCoverageForSpecifiedTargets = "NO"> <MacroExpansion> <BuildableReference BuildableIdentifier = "primary" @@ -50,6 +52,8 @@ </BuildableReference> </TestableReference> </Testables> + <CommandLineArguments> + </CommandLineArguments> </TestAction> <LaunchAction buildConfiguration = "Debug" @@ -71,6 +75,8 @@ ReferencedContainer = "container:Listless.xcodeproj"> </BuildableReference> </BuildableProductRunnable> + <CommandLineArguments> + </CommandLineArguments> </LaunchAction> <ProfileAction buildConfiguration = "Release" @@ -88,6 +94,8 @@ ReferencedContainer = "container:Listless.xcodeproj"> </BuildableReference> </BuildableProductRunnable> + <CommandLineArguments> + </CommandLineArguments> </ProfileAction> <AnalyzeAction buildConfiguration = "Debug"> diff --git a/Listless.xcodeproj/xcshareddata/xcschemes/Listless macOS.xcscheme b/Listless.xcodeproj/xcshareddata/xcschemes/Listless macOS.xcscheme @@ -1,10 +1,11 @@ <?xml version="1.0" encoding="UTF-8"?> <Scheme - LastUpgradeVersion = "2620" - version = "1.3"> + LastUpgradeVersion = "1430" + version = "1.7"> <BuildAction parallelizeBuildables = "YES" - buildImplicitDependencies = "YES"> + buildImplicitDependencies = "YES" + runPostActionsOnFailure = "NO"> <BuildActionEntries> <BuildActionEntry buildForTesting = "YES" @@ -26,7 +27,8 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - shouldUseLaunchSchemeArgsEnv = "YES"> + shouldUseLaunchSchemeArgsEnv = "YES" + onlyGenerateCoverageForSpecifiedTargets = "NO"> <MacroExpansion> <BuildableReference BuildableIdentifier = "primary" @@ -59,6 +61,8 @@ ReferencedContainer = "container:Listless.xcodeproj"> </BuildableReference> </BuildableProductRunnable> + <CommandLineArguments> + </CommandLineArguments> </LaunchAction> <ProfileAction buildConfiguration = "Release" @@ -76,6 +80,8 @@ ReferencedContainer = "container:Listless.xcodeproj"> </BuildableReference> </BuildableProductRunnable> + <CommandLineArguments> + </CommandLineArguments> </ProfileAction> <AnalyzeAction buildConfiguration = "Debug"> diff --git a/Listless/Views/TaskListView.swift b/Listless/Views/TaskListView.swift @@ -18,8 +18,8 @@ struct TaskListView: View { animation: .default ) private var tasks: FetchedResults<TaskItem> - @FocusState private var focusedField: FocusField? - @State private var selectedTaskID: UUID? + @FocusState var focusedField: FocusField? + @State var selectedTaskID: UUID? @State private var refreshID = UUID() @State private var draggedTaskID: UUID? @State private var visualOrder: [UUID]? @@ -165,33 +165,7 @@ struct TaskListView: View { managedObjectContext.undoManager = newValue } .toolbar { - ToolbarItem(placement: .automatic) { - Spacer() - } - - ToolbarItem(placement: .automatic) { - Button { - createTaskAndFocus() - // Trigger focus resolution by setting to nil - focusedField = nil - } label: { - Label("New Task", systemImage: "plus") - } - .help("Create a new task") - } - - ToolbarItem(placement: .automatic) { - Button { - if let currentID = selectedTaskID, - let task = allTasksInDisplayOrder.first(where: { $0.id == currentID }) { - deleteTask(task) - } - } label: { - Label("Delete", systemImage: "trash") - } - .disabled(selectedTaskID == nil) - .help("Delete selected task") - } + platformToolbar } } @@ -210,12 +184,12 @@ struct TaskListView: View { } } - private var completedTasks: [TaskItem] { + var completedTasks: [TaskItem] { Array(tasks.filter { $0.isCompleted }) .sorted { $0.updatedAt > $1.updatedAt } } - private var allTasksInDisplayOrder: [TaskItem] { + var allTasksInDisplayOrder: [TaskItem] { displayActiveTasks + completedTasks } @@ -231,7 +205,7 @@ struct TaskListView: View { return lastTask.id == taskID } - private func createTaskAndFocus() { + func createTaskAndFocus() { // Clear any lingering drag state draggedTaskID = nil visualOrder = nil @@ -318,7 +292,7 @@ struct TaskListView: View { selectedTaskID = taskID } - private func deleteTask(_ task: TaskItem) { + func deleteTask(_ task: TaskItem) { let taskID = task.id print("🔴 deleteTask() called for task \(taskID)") @@ -332,6 +306,13 @@ struct TaskListView: View { print("🔴 deleteTask() completed") } + func clearCompletedTasks() { + // Delete all completed tasks (in reverse to avoid index issues) + for task in completedTasks.reversed() { + store.delete(taskID: task.id) + } + } + private func navigateUp() -> KeyPress.Result { print("⬆️ navigateUp() called, focusedField: \(String(describing: focusedField))") guard focusedField == .scrollView else { diff --git a/ListlessMac/Views/TaskListView+Toolbar.swift b/ListlessMac/Views/TaskListView+Toolbar.swift @@ -0,0 +1,44 @@ +import SwiftUI + +extension TaskListView { + @ToolbarContentBuilder + var platformToolbar: some ToolbarContent { + ToolbarItem(placement: .automatic) { + Spacer() + } + + ToolbarItemGroup(placement: .automatic) { + HStack { + Button { + createTaskAndFocus() + // Trigger focus resolution by setting to nil + focusedField = nil + } label: { + Label("New Task", systemImage: "plus") + } + .help("Create a new task") + + Button { + if let currentID = selectedTaskID, + let task = allTasksInDisplayOrder.first(where: { $0.id == currentID }) { + deleteTask(task) + } + } label: { + Label("Delete", systemImage: "trash") + } + .disabled(selectedTaskID == nil) + .help("Delete selected task") + + Divider() + + Button { + clearCompletedTasks() + } label: { + Label("Clear Completed", systemImage: "tray") + } + .disabled(completedTasks.isEmpty) + .help("Clear all completed tasks") + } + } + } +} diff --git a/ListlessiOS/Views/TaskListView+Toolbar.swift b/ListlessiOS/Views/TaskListView+Toolbar.swift @@ -0,0 +1,10 @@ +import SwiftUI + +extension TaskListView { + @ToolbarContentBuilder + var platformToolbar: some ToolbarContent { + // No toolbar on iOS - users interact with tasks directly + // (tap to toggle, swipe to delete, tap background to create) + ToolbarItemGroup {} + } +}