Skip to content

Conduit iOS stopwatch - #1

Open
arahe-dev wants to merge 50 commits into
mainfrom
cursor/productivity-tracker-ios-06d2
Open

arahe-dev wants to merge 50 commits into
mainfrom
cursor/productivity-tracker-ios-06d2

Conversation

@arahe-dev

@arahe-dev arahe-dev commented Aug 12, 2026

Copy link
Copy Markdown
Owner

Pause then play on the lock screen was leaving the digits frozen.

Cause

  1. The control was a Toggle / SetValueIntent. That can send “not running” on every tap, so Start never resumes.
  2. Text(timerInterval:pauseTime:) does not start counting again if you only clear pauseTime on the same view. The system timer stays paused.

Fix

  • Stop is StopFromLiveActivityIntent; Start is ResumeFromLiveActivityIntent.
  • Running digits use a timer without pauseTime. Stopped digits use pauseTime on a different view identity (elapsedClockID + new displayStart on resume).
  • Lock-screen Start/Stop then persist the session and publish ActivityKit from the engine so the clock matches the app.
  • Resume always targets the Space that owns the Live Activity, not whichever page is selected.

Install the IPA from the latest green ios-ci run on this branch (sign with your Apple account). The zip currently in artifacts/ is the previous build and does not include this fix.

Open in Web Open in Cursor 

cursoragent and others added 16 commits August 12, 2026 23:38
Introduce the SwiftUI stopwatch, SwiftData models, App Intents, Live Activity extension, tests, and a macOS GitHub Actions workflow that generates the Xcode project and an unsigned IPA.

Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
@arahe-dev
arahe-dev marked this pull request as ready for review August 13, 2026 00:51
Copilot AI lite review requested due to automatic review settings August 13, 2026 00:51

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Introduces the ProductivityTracker native SwiftUI iOS app and the supporting tooling/CI needed to build, test, screenshot, and package an unsigned device IPA via GitHub Actions (macOS 26), with a Windows helper path for downloading and sideload signing.

Changes:

  • Added the SwiftUI + SwiftData app implementation (timer engine/state machine, Spaces/tasks/history, App Intents, notifications, Live Activity widget).
  • Added XCTest + XCUITest coverage and deterministic screenshot capture for CI artifacts.
  • Added macOS CI workflow scripts to generate the Xcode project with XcodeGen, select a simulator, run tests, package an unsigned IPA, and publish artifacts (plus a Windows gh-based artifact fetch script).

Reviewed changes

Copilot reviewed 74 out of 80 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
Scripts/windows/fetch-ipa.ps1 Downloads latest successful CI artifact IPA on Windows and verifies SHA-256 when present.
Scripts/ci/select-simulator.sh Selects a preferred iPhone simulator (newest runtime + preferred model) for CI.
Scripts/ci/package-ipa.sh Packages an unsigned .ipa from a built .app and emits SHA256SUMS + sanity checks.
Scripts/ci/install-xcodegen.sh Installs pinned XcodeGen version for CI project generation.
README.md Replaces repo README with app-focused documentation and workflow overview.
project.yml XcodeGen spec defining app, widget extension, and test targets/schemes.
ProductivityTrackerUITests/ProductivityTrackerUITests.swift UI tests for navigation, paging isolation, controls, persistence, and screenshots.
ProductivityTrackerTests/TimerEngineTests.swift Unit tests for timer engine state transitions and formatter.
ProductivityTrackerTests/TaskIntervalTests.swift SwiftData-backed tests for session/task interval behavior.
ProductivityTrackerTests/SpacePersistenceTests.swift SwiftData-backed tests for Spaces CRUD, ordering, deletion safeguards, recovery.
ProductivityTrackerTests/NotificationAndImportTests.swift Tests for distraction scheduling, JSON import validation, launch config.
ProductivityTrackerLiveActivity/ProductivityTrackerLiveActivityBundle.swift Widget bundle entry point for Live Activity/Dynamic Island UI.
ProductivityTrackerLiveActivity/LiveActivityView/LiveActivityView.swift Lock Screen Live Activity UI with App Intent controls and timer text.
ProductivityTrackerLiveActivity/Intents/LiveActivityIntents.swift App Intents for pause/resume/stop/lap from the Live Activity.
ProductivityTrackerLiveActivity/Info.plist Widget extension Info.plist for WidgetKit/Live Activities.
ProductivityTrackerLiveActivity/DynamicIsland/DynamicIslandViews.swift Dynamic Island compact/minimal/expanded rendering.
ProductivityTrackerLiveActivity/ActivityAttributes/SessionActivityAttributes.swift ActivityKit attributes/state shared between app and widget.
ProductivityTracker/Views/Timer/TimerScreen.swift Main timer screen layout: upper pager + lower task panel + settings sheet.
ProductivityTracker/Views/Timer/TaskPickerSheet.swift Sheet UI for selecting a task (long-press Lap).
ProductivityTracker/Views/Timer/StopwatchDisplay.swift Timeline-driven stopwatch display with accessibility values.
ProductivityTracker/Views/Timer/StopwatchCard.swift Glass “card” for stopwatch + controls + page dots per Space.
ProductivityTracker/Views/Timer/StopwatchButtons.swift Start/Stop/Lap button cluster and long-press task picker trigger.
ProductivityTracker/Views/Timer/PageDots.swift Page indicator dots with accessibility label.
ProductivityTracker/Views/Tasks/TaskRow.swift Row view for a task showing name + elapsed.
ProductivityTracker/Views/Tasks/TaskPanel.swift Task list panel (tap-to-select while running).
ProductivityTracker/Views/Spaces/SpaceListView.swift Space management list (reorder/delete/create).
ProductivityTracker/Views/Spaces/SpaceEditorView.swift Space editor for name, tint, enabled tasks, add/delete tasks.
ProductivityTracker/Views/Settings/SettingsView.swift Settings UI including Spaces/History navigation and distraction threshold.
ProductivityTracker/Views/RootView.swift Root bootstrap creating SessionController and presenting settings.
ProductivityTracker/Views/History/HistoryView.swift Session history list with per-task grouped durations.
ProductivityTracker/Timer/TimeSource.swift Time source abstraction + controllable clock for tests.
ProductivityTracker/Timer/TimerSnapshot.swift Snapshot model for timestamp-based elapsed calculation.
ProductivityTracker/Timer/TimerEngine.swift Pure timer state machine with explicit transitions.
ProductivityTracker/Timer/SessionController.swift Main app controller integrating SwiftData, timer engine, live activity, notifications.
ProductivityTracker/Timer/ElapsedFormatter.swift Stopwatch/compact elapsed string formatting utilities.
ProductivityTracker/Services/SettingsStore.swift UserDefaults-backed settings (selected space, distraction timeout, appearance).
ProductivityTracker/Services/LiveActivityManager.swift ActivityKit integration for starting/updating/ending the live activity.
ProductivityTracker/Services/Haptics.swift Centralized haptic feedback helpers.
ProductivityTracker/Resources/PrivacyInfo.xcprivacy App privacy manifest (tracking off + accessed API reasons).
ProductivityTracker/Resources/Info.plist App Info.plist including Live Activities and orientations.
ProductivityTracker/Resources/Assets.xcassets/Contents.json Asset catalog metadata.
ProductivityTracker/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json App icon asset entry.
ProductivityTracker/Resources/Assets.xcassets/AccentColor.colorset/Contents.json Accent color definition.
ProductivityTracker/Persistence/PersistenceController.swift SwiftData container construction (memory vs disk).
ProductivityTracker/Persistence/DemoDataSeeder.swift Demo seed data + stable IDs for tests/UI.
ProductivityTracker/Notifications/NotificationService.swift Local notification scheduling + action handling + recording test double.
ProductivityTracker/Notifications/DistractionMonitor.swift Distraction tracking state for scheduling/cancelling reminders.
ProductivityTracker/Models/TimerPhase.swift Timer phase enum.
ProductivityTracker/Models/TaskItem.swift SwiftData model for tasks.
ProductivityTracker/Models/TaskInterval.swift SwiftData model for per-task intervals within a session.
ProductivityTracker/Models/SpaceTint.swift Tint enum + parsing for imports.
ProductivityTracker/Models/Space.swift SwiftData model for Spaces and task ordering helpers.
ProductivityTracker/Models/Session.swift SwiftData model for sessions + elapsed calculation.
ProductivityTracker/Intents/SpaceImportPayload.swift JSON parsing/validation for Space import intent.
ProductivityTracker/Intents/SessionIntents.swift Core app intents: select/start/stop/pause/resume/lap.
ProductivityTracker/Intents/ImportAndDistractionIntents.swift App intents for task selection, import, and distraction start/end.
ProductivityTracker/Intents/FocusFilterIntent.swift Focus Filter intent to select a Space when a Focus activates.
ProductivityTracker/Intents/Entities.swift AppEntity + queries for Spaces and Tasks.
ProductivityTracker/Intents/AppShortcuts.swift Suggested Shortcuts phrases for key intents.
ProductivityTracker/DesignSystem/StopwatchButtonStyle.swift Custom glass stopwatch button component.
ProductivityTracker/DesignSystem/GlassSurface.swift Shared “glass surface” container styling.
ProductivityTracker/DesignSystem/AppTheme.swift Shared accessibility IDs and layout metrics.
ProductivityTracker/App/ProductivityTrackerApp.swift App entry point + model container + launch configuration handling.
ProductivityTracker/App/LaunchConfiguration.swift Launch argument/environment parsing for tests and screenshots.
ProductivityTracker/App/AppRuntime.swift Shared runtime container/controller for intents and services.
INSTALL_WINDOWS.md Windows sideload installation guide (free-signing flow).
Design/screenshots/README.md Documents CI-produced simulator screenshots.
Design/references/space-import.schema.json Example JSON payload for Space import.
Design/references/SPACE_IMPORT.md Human-readable schema documentation for Space import.
Design/references/README.md Notes about missing original concept images and reference usage.
ARCHITECTURE.md High-level architecture and rationale for timer/timestamps/CI pipeline.
.xcodegen-version Pins XcodeGen version for CI install script.
.gitignore iOS/Swift/Xcode ignores + artifacts/output directories.
.github/workflows/ios-ci.yml CI workflow for generation, build, tests, screenshots, IPA packaging, artifact upload.
.cursor/rules/productivity-tracker.mdc Project constraints and workflow rules for Cursor/Windows-first development.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +28 to +31
init(center: UNUserNotificationCenter = .current()) {
self.center = center
super.init()
}
Comment on lines +14 to +16
#if !targetEnvironment(simulator) || true
guard ActivityAuthorizationInfo().areActivitiesEnabled else { return }
let snapshot = controller.snapshot
Comment on lines +35 to +38
let continueAction = UNNotificationAction(
identifier: NotificationIdentifiers.continueAction,
title: "Continue"
)
Comment on lines +30 to +34
.simultaneousGesture(
LongPressGesture(minimumDuration: 0.55).onEnded { _ in
onLongPressLap()
}
)
Comment on lines +333 to +337
private func activeSession() -> Session? {
guard let id = engine.snapshot.sessionID else { return nil }
let all = (try? context.fetch(FetchDescriptor<Session>())) ?? []
return all.first(where: { $0.id == id })
}
Stop now freezes a resumable stopwatch; Start resumes the same session; Reset archives history and dismisses the Live Activity immediately. Each Space owns its own timer. The main screen drops tinted glass cards, tasks are directly editable, and Live Activity presentation is timer-first with explicit controls only.

Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
@cursor cursor Bot changed the title ProductivityTracker native iOS app ProductivityTracker iOS stopwatch Aug 13, 2026
cursoragent and others added 8 commits August 13, 2026 10:35
Widget code now builds ContentState from primitive fields so the extension compiles without app timer types.

Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Publish timer snapshots before Live Activity refresh, apply a new default task while idle, and query timer controls through descendants so disabled Lap remains visible to XCTest.

Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
cursoragent and others added 10 commits August 13, 2026 11:48
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
…y tree.

Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Swipe past the last Space to create one in place, with color, SF Symbols, emoji, or a monogram. Tasks can be added inline and completed with a double-tap. The whole Space page pages together, the lock screen uses a Clock-style hh:mm:ss timer in the Space color with a large icon, and the home-screen app is Conduit with a new icon and IPA name.

Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
@cursor cursor Bot changed the title ProductivityTracker iOS stopwatch Conduit iOS stopwatch Aug 14, 2026
cursoragent and others added 15 commits August 14, 2026 03:35
SwiftUI double-tap arbitration delays the single tap, and TabView paging is not instantaneous with animations disabled.

Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Shrink icons and add lock-screen padding. Pause, resume, and close wait for ActivityKit so they feel immediate; close archives even while running. Tap the Space name to edit. The canvas tint fills the status bar. Paging uses a committed swipe to reach New Space, and leaving that page dismisses the keyboard. Task rows select immediately. A squircle save control stores elapsed time without resetting, with filtered history. Distraction reminders are removed from the UI.

Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Avoid SwiftUI’s double-tap delay so row selection stays immediate.

Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Drop the full-screen tint washes, page Spaces with native paging, and add exponential resistance only when pulling into New Space. Push ActivityKit updates before SwiftData saves and reuse the running clock anchor on pause.

Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Rubber-band the New Space peek so it moves less than the finger, and keep an in-pager New Space page under UITesting so the last swipe still lands reliably.

Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
This is the green CI build from 6b1d7df. Sign it with your own Apple account before installing.

Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Pause/resume now flips the system timer on the Live Activity before SwiftData work, skip lock-screen auth, and keep SessionController ready as soon as the process launches.

Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
WidgetKit can pre-render running and stopped controls so the glyph flips on tap, while perform() only sets pauseTime on the system timer then persists in the background.

Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
The Toggle intent was defaulting to running=false, so Stop worked and Start was a no-op. Decide the target from the current Live Activity state, pre-render both Toggle values, and actually resume the system timer plus the session.

Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Stop and Start are dedicated Live Activity buttons, not a Toggle.
Resume publishes a new timer view identity so the system clock
actually runs again instead of keeping pauseTime.

Co-authored-by: Abdur Raheem Imami <arahe-dev@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants