Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
bf09e30
fix: update deployment target to 10.13 and fix window occlusion check
karbassi Jan 31, 2026
0511076
chore: raise deployment target to macOS 14 (Sonoma)
karbassi Jan 31, 2026
fd08169
feat: persist sound choice to UserDefaults
karbassi Jan 31, 2026
e710fa8
refactor: extract pure logic from MVClockView and MVTimerController i…
karbassi Jan 31, 2026
6fac8ee
fix: resolve all SwiftLint warnings
karbassi Feb 1, 2026
a60a373
refactor: replace NSString(format:) with native Swift strings in Time…
karbassi Feb 1, 2026
6c7fdbb
refactor: remove unnecessary break statements in MVClockArrowView
karbassi Feb 3, 2026
7c7bf76
refactor: replace import Cocoa with import AppKit, add explicit self
karbassi Feb 6, 2026
687c12a
feat: add TimerUITests target with XCUITest framework
karbassi Feb 6, 2026
2d672a0
fix: update CI workflow, README deployment target, and notification auth
karbassi Feb 7, 2026
512e4f2
refactor: remove duplicate `enter` keycode constant (identical to `ke…
karbassi Feb 7, 2026
d7bccfd
perf: cache allocations and add VoiceOver accessibility
karbassi Feb 7, 2026
4626b64
refactor: replace NSTextView with NSTextField in MVLabel
karbassi Feb 7, 2026
2a3d7e6
chore: modernize Xcode project settings
karbassi Feb 7, 2026
6a613a7
feat: add dark mode color support and arrow accessibility
karbassi Feb 7, 2026
e1db677
docs: update CHANGELOG with app improvements
karbassi Feb 7, 2026
d14d18c
docs: rewrite CHANGELOG with full version history from tags
karbassi Feb 7, 2026
5424cf6
feat: upgrade to Swift 6 with strict concurrency
karbassi Feb 7, 2026
678c0a3
chore: add mise.toml for swiftlint tooling
karbassi Feb 7, 2026
cb0e047
refactor: split large files, remove Keycodes.swift, clean up SwiftLin…
karbassi Feb 7, 2026
7423f0e
refactor: streamline code and expand SwiftLint opt-in rules to 73
karbassi Feb 7, 2026
d1b7d16
docs: rewrite CHANGELOG for clarity
karbassi Feb 7, 2026
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
26 changes: 5 additions & 21 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ jobs:
runs-on: macos-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
uses: actions/checkout@v4

- name: Clean project
run: xcodebuild clean
run: xcodebuild clean

- name: Build project
run: xcodebuild build CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO
Expand All @@ -24,24 +24,8 @@ jobs:
cd ./build/Release/
zip -r "../../Timer.app.zip" "Timer.app/"

- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Create Release and Upload Asset
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.ref }}
release_name: ${{ github.ref }}
draft: true
prerelease: false

- name: Upload Release Asset
id: upload-release-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./Timer.app.zip
asset_name: Timer.app.zip
asset_content_type: application/zip
files: Timer.app.zip
11 changes: 6 additions & 5 deletions .github/workflows/swift.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,20 @@ name: Swift

on:
push:
branches: [ master ]
branches: [ main ]
pull_request:
branches: [ master ]
branches: [ main ]

jobs:
build:

runs-on: macos-latest

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Clean
run: xcodebuild clean
- name: Build
run: xcodebuild build CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO

run: xcodebuild build CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO
- name: Test
run: xcodebuild test -scheme Timer -destination 'platform=macOS' CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO
18 changes: 6 additions & 12 deletions .github/workflows/swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,10 @@ on:

jobs:
SwiftLint:
runs-on: ubuntu-latest
runs-on: macos-latest
steps:
- uses: actions/checkout@v1
- name: GitHub Action for SwiftLint
uses: norio-nomura/action-swiftlint@3.1.0
- name: GitHub Action for SwiftLint with --strict
uses: norio-nomura/action-swiftlint@3.1.0
with:
args: --strict
- name: GitHub Action for SwiftLint (Only files changed in the PR)
uses: norio-nomura/action-swiftlint@3.1.0
env:
DIFF_BASE: ${{ github.base_ref }}
- uses: actions/checkout@v4
- name: Install SwiftLint
run: brew install swiftlint
- name: Lint
run: swiftlint --strict
73 changes: 60 additions & 13 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
@@ -1,44 +1,91 @@
# rule identifiers to exclude from running
disabled_rules:
- type_body_length
- function_body_length
- file_length
- unneeded_break_in_switch

# some rules are only opt-in
# Find all the available rules by running: swiftlint rules
opt_in_rules:
- anyobject_protocol
- array_init
- balanced_xctest_lifecycle
- closure_end_indentation
- closure_spacing
- collection_alignment
- comma_inheritance
- contains_over_filter_count
- contains_over_filter_is_empty
- contains_over_first_not_nil
- contains_over_range_nil_comparison
- convenience_type
- direct_return
- discarded_notification_center_observer
- discouraged_optional_boolean
- discouraged_optional_collection
- empty_collection_literal
- empty_count
- empty_string
- empty_xctest_method
- explicit_init
- explicit_self
- fatal_error_message
- final_test_case
- first_where
- flatmap_over_map_reduce
- force_unwrapping
- function_default_parameter_at_end
- identical_operands
- implicit_return
- implicitly_unwrapped_optional
- joined_default_parameter
- last_where
- legacy_multiple
- literal_expression_end_indentation
- lower_acl_than_parent
- modifier_order
# - number_separator
- no_empty_block
- non_overridable_class_declaration
- number_separator
- operator_usage_whitespace
- optional_enum_case_matching
- pattern_matching_keywords
- period_spacing
- prefer_condition_list
- prefer_key_path
- prefer_self_in_static_references
- prefer_self_type_over_type_of_self
- prefer_zero_over_explicit_init
- private_over_fileprivate
- reduce_into
- redundant_nil_coalescing
- redundant_type_annotation
- return_value_from_void_function
- self_binding
- shorthand_argument
- shorthand_optional_binding
- sorted_enum_cases
- sorted_first_last
- sorted_imports
- static_over_final_class
- superfluous_else
- toggle_bool
- trailing_closure
- unhandled_throwing_task
- unneeded_parentheses_in_closure_argument
- unowned_variable_capture
- untyped_error_in_catch
- unused_import
- unused_parameter
- vertical_parameter_alignment_on_call
- vertical_whitespace_between_cases
- vertical_whitespace_closing_braces
- vertical_whitespace_opening_braces
- weak_delegate
- xct_specific_matcher
- yoda_condition

analyzer_rules:
- explicit_self
- unused_import

included:
- Timer
- TimerTests
- TimerUITests


excluded:
- Timer/Keycodes.swift

# reporter type (xcode, json, csv, checkstyle, junit, html, emoji, sonarqube, markdown)
reporter: 'xcode'
204 changes: 204 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/).

## [Unreleased]

### Added

- 43 unit tests and 38 UI tests
- Xcode schemes for running tests; `make test` and `make uitest` targets
- `make lint`, `make analyze`, and `make format` targets
- CI test step in build workflow
- Sound choice persists across launches
- Dark mode color support
- VoiceOver accessibility for timer state and arrow control

### Changed

- Upgraded to Swift 6
- Raised deployment target to macOS 14 (Sonoma)
- Replaced deprecated `NSUserNotification` with `UNUserNotificationCenter`
- Adopted `async`/`await` throughout (timers, notifications, authorization)
- Improved keyboard input to use character-based matching (better international keyboard support)
- Reduced per-frame allocations by caching gradients, images, paths, and formatters
- Extracted reusable logic into `TimerLogic` for testability
- Split large files to stay within default SwiftLint thresholds
- Modernized Xcode project settings and build configuration
- Expanded SwiftLint opt-in rules from 6 to 73
- General code cleanup: tightened access control, removed force unwraps, reduced Obj-C surface

### Removed

- `Keycodes.swift` (replaced by character-based key matching)
- ~500 lines of unused XIB menus and dead code
- Deprecated `Info.plist` keys

### Fixed

- Window occlusion detection now checks actual visibility, not just window ordering
- Secondary timer windows no longer overwrite the primary window's saved position

### CI

- Updated all GitHub Actions to current versions
- Replaced deprecated SwiftLint and release actions

## [1.6.0] - 2021-01-08

### Added

- Sound selection menu: choose between 3 sounds or no sound (#107)

### Changed

- Updated cask install instructions (#106)
- Updated brew cask command format (#98)

## [1.5.5] - 2020-07-16

### Fixed

- Simplified and fixed countdown display skipping seconds (#94)

### Changed

- Added SwiftLint for code style enforcement (#87)

## [1.5.4] - 2020-07-09

### Changed

- Use fixed-width font for less jittery countdown display (#86)

## [1.5.3] - 2020-04-23

### Changed

- Switch to `AVAudioPlayer` for playing the alert sound (#80)

## [1.5.2] - 2020-04-12

### Added

- Press `R` to restart with the last timer after Escape or completion (#75)

### Changed

- Updated text for "Show in Dock" menu option (#74)

## [1.5.1] - 2020-04-11

### Fixed

- Fixed buggy mouse control (#72)

## [1.5.0] - 2020-04-11

### Added

- Dark mode support (#67)
- GitHub Actions for build and release (#62)
- Issue templates and Code of Conduct (#63, #64)
- Keyboard shortcuts documented in README (#65)
- Makefile for build process (#47)

### Changed

- Updated window layout for Mojave compatibility (#50)
- Improved battery life with timer tolerance and reduced display updates (#44)
- Improved countdown precision to ~1/30 second with pre-timer for seconds-boundary alignment (#44)
- Reduced CPU usage by 20x when window is hidden by tracking visibility (#44)
- Window position auto-saved and restored across launches (#39)
- Locale-aware time formatting with small-caps AM/PM (#38)
- Migrated to Swift 4.1 (#37)
- Windows properly deallocated when closed with weak references (#39)

### Fixed

- Fixed crash when reopening dock timer after switching dock assignment (#39)
- Fixed memory leak in mouse event handling (#45)
- Dock badge properly removed when unchecking "Show in Dock" (#42)

## [1.4] - 2018-08-08

### Added

- Keypad Enter support (#35)
- Dock badge with timer countdown (#29)
- Context menu with dock badge toggle (#29)
- Current time label when idle (#27)
- LICENSE file (#18)
- `.gitignore` (#33)

### Changed

- Hidden unused menus (#34)
- Compressed image assets (#32)

### Fixed

- Replaced `CGFloat(M_PI)` with `.pi` (#30)

## [1.3] - 2017-06-01

### Added

- Type seconds from keyboard — e.g., `.150` sets timer to 2:30 (#14)
- Accept second values up to 599 (#14)

### Fixed

- Reduced beeping on key down (#15)

## [1.2] - 2017-02-13

### Added

- Homebrew cask install instructions
- Stay on Top toggle with preference persistence (#9)

### Changed

- Migrated to Swift 3 (#8)

## [1.1.0] - 2016-05-18

### Added

- Keyboard input support
- macOS 10.10 support

### Fixed

- Fixed countdown timing

## [1.0.2] - 2016-03-30

### Changed

- README updates

## [1.0.1] - 2016-03-30

### Fixed

- Fixed crash on launch

[Unreleased]: https://github.com/karbassi/timer-app/compare/1.6.0...HEAD
[1.6.0]: https://github.com/michaelvillar/timer-app/compare/1.5.5...1.6.0
[1.5.5]: https://github.com/michaelvillar/timer-app/compare/1.5.4...1.5.5
[1.5.4]: https://github.com/michaelvillar/timer-app/compare/1.5.3...1.5.4
[1.5.3]: https://github.com/michaelvillar/timer-app/compare/1.5.2...1.5.3
[1.5.2]: https://github.com/michaelvillar/timer-app/compare/1.5.1...1.5.2
[1.5.1]: https://github.com/michaelvillar/timer-app/compare/1.5.0...1.5.1
[1.5.0]: https://github.com/michaelvillar/timer-app/compare/1.4...1.5.0
[1.4]: https://github.com/michaelvillar/timer-app/compare/1.3...1.4
[1.3]: https://github.com/michaelvillar/timer-app/compare/1.2...1.3
[1.2]: https://github.com/michaelvillar/timer-app/compare/1.1.0...1.2
[1.1.0]: https://github.com/michaelvillar/timer-app/compare/1.0.2...1.1.0
[1.0.2]: https://github.com/michaelvillar/timer-app/compare/1.0.1...1.0.2
[1.0.1]: https://github.com/michaelvillar/timer-app/releases/tag/1.0.1
Loading