Commit graph

17805 commits

Author SHA1 Message Date
Johannes Millan
4d17ae8f2f feat(ios): add keyboard and status bar support 2026-01-14 13:45:42 +01:00
Johannes Millan
02da3c283a feat(ios): add notification actions and iPad optimizations
iOS Notification Actions:
- Register Snooze/Done action buttons for reminder notifications
- Handle snooze action (reschedule reminder +10 minutes)
- Handle done action (dismiss reminder only)

iPad Optimizations:
- Add isIPad() detection in platform service
- Add isIPad body class for CSS targeting
- Wider content area on iPad (900px, 1000px landscape)
- Split-view support with narrow viewport detection
- Wider dialogs in landscape mode
2026-01-14 13:45:42 +01:00
Johannes Millan
1f06a54f11 refactor(ios): use IS_NATIVE_PLATFORM for shared mobile behavior
Migrate mobile-common features from IS_ANDROID_WEB_VIEW to IS_NATIVE_PLATFORM
so iOS gets the same behavior as Android:

- Service worker: disabled on both mobile platforms
- Reminder notifications: skip dialog on native (use Capacitor notifications)
- Share functionality: detect Capacitor Share plugin on both platforms
- File operations: use native filesystem on both platforms
2026-01-14 13:45:42 +01:00
Johannes Millan
7948929c97 feat(ios): add local backup, app lifecycle, and file export support
- Add iOS local backup using Capacitor Filesystem (Directory.Data)
- Add iOS app lifecycle listeners (appStateChange, appUrlOpen)
- Update download utility to use IS_NATIVE_PLATFORM for iOS support
- Update file-imex component to show success snack on iOS exports
2026-01-14 13:45:42 +01:00
Johannes Millan
a046c347d4 feat(ios): add safe area, keyboard, and status bar handling
Add iOS-specific UX improvements:

Safe Areas:
- Add CSS variables for safe area insets (notch, home indicator)
- Add body classes: isNativeMobile, isIOS, isKeyboardVisible
- Apply safe area padding on native mobile platforms

Keyboard Handling:
- Install @capacitor/keyboard plugin
- Track keyboard visibility via keyboardWillShow/Hide events
- Set --keyboard-height CSS variable for layout adjustments
- Remove bottom safe area padding when keyboard is visible

Status Bar:
- Install @capacitor/status-bar plugin
- Sync status bar style with app dark/light theme
- Configure overlaysWebView: false in capacitor.config.ts

These changes ensure proper display on iPhone devices with
notch/Dynamic Island and home indicator.
2026-01-14 13:45:42 +01:00
Johannes Millan
590e1592da feat(ios): add iOS platform support via Capacitor
Add iOS MVP with core functionality using Capacitor-first approach:

Platform Abstraction Layer:
- Add CapacitorPlatformService for unified platform detection
- Add PlatformCapabilities model with per-platform feature flags
- Add CapacitorNotificationService wrapping LocalNotifications plugin
- Add CapacitorReminderService for cross-platform reminder scheduling

iOS Support:
- Add Capacitor iOS project with proper configuration
- Configure Info.plist for notifications and background modes
- Add app icon and splash screen assets
- Enable CapacitorHttp for WebDAV sync (avoids CORS issues)

Refactoring:
- Update android.effects.ts to use CapacitorReminderService
- Update notify.service.ts to support iOS notifications
- Update startup.service.ts with platform-aware initialization
- Update sync-form.const.ts to hide CORS info on native platforms
- Update webdav-http-adapter.ts to use CapacitorHttp on iOS

MVP includes: task management, scheduled notifications, Dropbox sync,
WebDAV sync, share-out, dark mode. Excludes: background tracking,
widgets, local file sync, share-in (post-MVP features).
2026-01-14 13:45:42 +01:00
Johannes Millan
9d21fa1b6e fix(e2e): stabilize flaky tests with improved waiting strategies
- Increase task creation timeout from 10s to 15s for slow renders
- Use force:true on backdrop click to bypass overlay coverage
- Replace page.evaluate() with Playwright locators in expandSection()
- Add proper condition-based waiting for collapsible panel visibility
2026-01-14 13:45:27 +01:00
Johannes Millan
c6028b980d fix(e2e): stabilize flaky menu-touch-submenu test
Replace arbitrary waitForTimeout calls with condition-based waiting:
- Use specific selector scoped to .mat-mdc-menu-content for tag button
- Wait for tag to appear on task instead of waiting for menu to close
- Keep only the justified 350ms wait for touch protection delay testing
2026-01-14 13:45:27 +01:00
Johannes Millan
78283e7423 test(selectors): add comprehensive tests for optimized selectors
Add unit tests for selectAllTasksWithDueDay and selectAllTasksDueToday
selectors to ensure the performance optimizations work correctly.

Tests cover:
- Filtering tasks by dueDay and dueWithTime
- Sorting by dueDay chronologically
- Handling empty state and missing entities
- Deduplication of tasks from multiple sources
- Edge cases like subtasks with dueDay
2026-01-14 13:45:27 +01:00
Johannes Millan
5cb8720058 perf(planner): optimize selectAllTasksDueToday selector
Consolidate two Object.values() calls into a single iteration over
taskState.ids. This avoids creating two intermediate arrays and
reduces the number of passes over all tasks from 2 to 1.
2026-01-14 13:45:27 +01:00
Johannes Millan
d345bc33ea perf(tasks): optimize selectAllTasksWithDueDay selector
Iterate taskState.ids instead of using Object.values() to avoid
creating an intermediate array. Also simplified the sort comparator
using localeCompare since dueDay is in YYYY-MM-DD format which is
lexicographically sortable.
2026-01-14 13:45:27 +01:00
Johannes Millan
f4b0391209 feat(metric): remove loading placeholder for activity heatmap 2026-01-14 13:45:27 +01:00
Johannes Millan
28bba15e05 fix(tag): correct emoji spacing in tag toggle menu dropdown
Emojis in tag icons were rendered inside <mat-icon> elements, causing
excessive whitespace. Now emojis are detected via isSingleEmoji() and
rendered in a <span> with proper emoji styling.

Fixes #5977
2026-01-14 13:45:27 +01:00
Johannes Millan
b2a807f7db perf(archive): remove unused NgRx archive stores to reduce memory usage
Archives (archiveYoung, archiveOld) were being loaded into NgRx state
at startup but their selectors were never read anywhere in the codebase.
All code that needs archives loads them directly from IndexedDB via
ArchiveDbAdapter (StateSnapshotService, TaskArchiveService, etc).

This change removes the archive store registrations from NgRx, which:
- Reduces memory usage for users with large archives
- Improves startup time (no longer dispatching large archive data to NgRx)
- Reduces GC pressure (fewer large objects in memory)

Archive functionality is unaffected - archives are still stored in
IndexedDB and loaded on-demand when needed for worklog, sync, etc.
2026-01-14 13:45:27 +01:00
Johannes Millan
c5625317bf fix: prevent memory leaks from unmanaged subscriptions and event listeners
- LocalBackupService: add takeUntilDestroyed to backup interval subscription
- GlobalProgressBarService: add takeUntilDestroyed to dirty countdown subscription
- PluginBridgeService: extract window/document listeners to named methods with cleanup
- shepherd-helper: add take(1) to waitForElObs$, add 10s timeout to waitForEl
- plugin.service: add max attempts (100) to plugin loading poll interval
2026-01-14 13:45:27 +01:00
Johannes Millan
a93f6a7ba2 fix(sync): use BackupImport OpType for backup imports to bypass 409
When importing a backup while connected to SuperSync, the server was
rejecting the operation with 409 SYNC_IMPORT_EXISTS error. This happened
because backup imports were using OpType.SyncImport which maps to
reason='initial' on the server.

Fix:
- Change OpType.SyncImport → OpType.BackupImport in backup.service.ts
- OpType.BackupImport maps to reason='recovery' on the server
- Server allows reason='recovery' even when SYNC_IMPORT exists

This enables users to recover data by importing backups when connected
to SuperSync, which is essential for disaster recovery scenarios.

Add unit test verifying OpType.BackupImport is used and E2E test that
validates the full backup recovery flow works when SYNC_IMPORT exists.
2026-01-14 13:45:27 +01:00
Johannes Millan
0fd2618dab fix(sync): preserve archived tasks during server migration and backup
SYNC_IMPORT operations and local backups were losing archived tasks because
they used sync snapshot methods that return empty DEFAULT_ARCHIVE instead of
loading real archive data from IndexedDB.

Changes:
- ServerMigrationService: use getStateSnapshotAsync() to include archives
- LocalBackupService: use getAllSyncModelDataFromStoreAsync() for backups
- ArchiveOperationHandler: add safety guard to prevent overwriting non-empty
  archives with empty ones

Add unit tests for archive preservation and E2E test that triggers actual
server migration by switching sync providers.
2026-01-14 13:45:27 +01:00
Johannes Millan
64ccc99ddb
Merge pull request #5986 from steindvart/time-tracer-position
Made tracking time panel position left of the other elements and remove hiding
2026-01-14 12:51:25 +01:00
Johannes Millan
81ab8d52d0
Merge pull request #5980 from steindvart/fix-readme-links
Fix: links and remove extra symbols in main README
2026-01-14 12:19:33 +01:00
Johannes Millan
b477b0b1fc
Merge pull request #5982 from super-productivity/dependabot/npm_and_yarn/npm_and_yarn-f02db13dca
build(deps): bump the npm_and_yarn group across 1 directory with 2 updates
2026-01-14 12:10:56 +01:00
Ivan Kalashnikov
1fa27662ad Merge remote-tracking branch 'origin/master' into time-tracer-position 2026-01-14 17:40:33 +07:00
Johannes Millan
5a4290eccf
Merge pull request #5988 from steindvart/fix-small-letters
Fix small letters
2026-01-14 11:15:30 +01:00
Ivan Kalashnikov
05c53741af fix: improve capitalization and punctuation in various strings in ru.json 2026-01-14 14:55:24 +07:00
Ivan Kalashnikov
ffceed18b5 fix: update TIME_LOCALE_DESCRIPTION in ru.json for to match the current information in en.json. 2026-01-14 14:51:36 +07:00
Ivan Kalashnikov
0f7000a3ef fix: capitalization and punctuation in START_OF_NEXT_DAY_HINT string. 2026-01-14 14:48:30 +07:00
Ivan Kalashnikov
a9c0b4a590 fix: remove hover effects for current task title and action navigation 2026-01-14 14:17:39 +07:00
Ivan Kalashnikov
75f9f1f348 fix: better adaptation to screen width for time tracking panel. 2026-01-14 14:11:43 +07:00
Ivan Kalashnikov
f0e9020936 fix: move time tracking panel position to the left of all elements in heared. 2026-01-14 14:07:50 +07:00
dependabot[bot]
c0db559e5c
build(deps): bump the npm_and_yarn group across 1 directory with 2 updates
Bumps the npm_and_yarn group with 2 updates in the / directory: [qs](https://github.com/ljharb/qs) and [hono](https://github.com/honojs/hono).


Updates `qs` from 6.13.0 to 6.14.1
- [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ljharb/qs/compare/v6.13.0...v6.14.1)

Updates `hono` from 4.11.3 to 4.11.4
- [Release notes](https://github.com/honojs/hono/releases)
- [Commits](https://github.com/honojs/hono/compare/v4.11.3...v4.11.4)

---
updated-dependencies:
- dependency-name: qs
  dependency-version: 6.14.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: hono
  dependency-version: 4.11.4
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-13 22:09:08 +00:00
Johannes Millan
c57392c5c1 chore(menu): remove debug logging from touch fix 2026-01-13 18:26:45 +01:00
Johannes Millan
3cda4bda92 fix(menu): use document-level capturing to block touch submenu clicks
The previous fix didn't fully work because:
1. Submenus don't trigger openMenu() in Angular Material 21
2. Element-level capturing listeners don't intercept before Angular handlers

This fix adds:
- MutationObserver to detect when any menu panel appears (including submenus)
- Document-level capturing listener that intercepts clicks on menu items
  BEFORE they reach Angular's event handlers
- Shared timestamp between monkey patch and directive via exports

The document-level approach is critical because capturing at the document
runs before the event reaches the target, allowing stopImmediatePropagation()
to block Angular's (click) bindings.

Issue: #4436
2026-01-13 18:26:45 +01:00
Johannes Millan
4ffad50f34 fix(menu): update touch monkey patch for Angular Material 21
The monkey patch that prevents accidental submenu selection on touch
devices was broken after the Angular Material 21 update.

Root cause: Angular Material renamed MatMenuItem._handleClick to
_checkDisabled in version 21.

Changes:
- Update patch to override _checkDisabled instead of _handleClick
- Add unit tests to detect future Angular Material API changes
- Add e2e tests for context menu submenu functionality
- Document API dependencies and change history in code comments

Fixes touch devices accidentally selecting menu items when submenus
open under the user's finger near screen edges.

Issue: #4436
2026-01-13 18:26:45 +01:00
Johannes Millan
6af397eeaf fix(task): correct vertical alignment of issue updated icon
Remove complex CSS positioning that caused the update icon to be
vertically misaligned. The icon now uses the button's native flexbox
centering like the other icons (chat/close) in the same position.
2026-01-13 18:26:45 +01:00
Johannes Millan
9431f23a1a fix(e2e): stabilize flaky supersync tests with better waiting strategies
Replace fixed timeouts with condition-based waiting to improve test
reliability under load:
- USE_REMOTE test: wait for sync completion instead of fixed 2s delay
- Encryption test: add retry logic for error state checking
- Undo delete test: use waitForTask polling instead of fixed timeout
- Task ordering test: add UI settling time after sync operations
2026-01-13 18:26:45 +01:00
Johannes Millan
80b760f8ea chore: remove unused ShortDate2Pipe import 2026-01-13 18:26:45 +01:00
Johannes Millan
205d6f1a26 fix(notes): auto-focus textarea in fullscreen markdown dialog
Add autoFocus: 'textarea' to dialog config to ensure textarea receives
focus instead of toolbar buttons when the dialog opens.
2026-01-13 18:26:45 +01:00
Johannes Millan
df036953ad fix(notes): improve fullscreen markdown toolbar styling and scrolling
Use Material button class selector for proper dark theme support and
prevent toolbar wrapping by enabling horizontal scroll instead.
2026-01-13 18:26:45 +01:00
Johannes Millan
c17b7dc4e9 fix(notes): show reflection banner only for daily reflections, not regular notes
The startup banner was incorrectly showing any recently created note as a
"Reflection Note". Now it only shows reflections added via "Evaluate Day"
by querying MetricService instead of NoteService.
2026-01-13 18:26:45 +01:00
Johannes Millan
8294976525 fix(notes): auto-focus textarea when fullscreen view opens 2026-01-13 18:26:45 +01:00
Johannes Millan
df386a7a7e fix(electron): only pass tray GUID on Windows to prevent validation error
Electron validates the GUID argument even when undefined is passed,
causing "Invalid GUID format" error on Linux/macOS. Only pass the
GUID argument on Windows where it's needed.
2026-01-13 18:26:45 +01:00
Johannes Millan
0414b74365 fix(repeat): add event loop yield and isPaused filter (#5976)
Add potential fix for repeat tasks not appearing in Today view:
- Add event loop yield after creating repeat tasks to ensure store
  processes dispatched actions before querying
- Add isPaused filter to selectors to exclude paused repeat configs
- Add unit tests for isPaused filter
- Add E2E test for regression protection

Note: We're not 100% certain the event loop yield fixes #5976, but it
follows the established pattern used elsewhere in the codebase.
2026-01-13 18:26:45 +01:00
Johannes Millan
7fb59050e3 fix(focus-mode): resolve Pomodoro timer sync issues with breaks (#5974)
- Fix break pause not stopping tracking (syncSessionPauseToTracking$ now
  handles break purpose)
- Fix manual break start not resuming tracking when isPauseTrackingDuringBreak
  is disabled
- Fix banner icon not updating when break is paused via tracking button
  (BannerService now creates new object instead of mutating)
- Fix typo: "session" -> "sessions" in sync setting label

Add comprehensive unit tests for all fixes and E2E tests for basic
Pomodoro focus mode behavior.
2026-01-13 18:26:45 +01:00
Johannes Millan
74671bb482 Revert "fix(ui): visibility menu positioning after toggling Inbox"
This reverts commit 91e0984617fcf85c4f75032805844479b8f13fdd.
2026-01-13 18:26:45 +01:00
Johannes Millan
b435f28a23 fix(ui): visibility menu positioning after toggling Inbox
Remove overflow: hidden from .g-multi-btn-wrapper which caused
Angular Material's CDK overlay to miscalculate menu position after
DOM changes from toggling project visibility.

Fixes #5955
2026-01-13 18:26:45 +01:00
Johannes Millan
9140f51a8d feat(electron): add static GUID to tray icon for Windows
Add a static GUID to the Electron Tray constructor on Windows to persist
tray icon position and visibility preferences across app updates. This
prevents the tray icon from being hidden in the overflow menu after
Microsoft Store updates change the executable path.

Closes #5973
2026-01-13 18:26:45 +01:00
Johannes Millan
e7e693e78f fix(sync-server): add rate limiting to page endpoints
Add explicit per-route rate limits to /verify-email and /magic-login
endpoints to address CodeQL security alerts. These endpoints previously
relied only on global rate limiting.
2026-01-13 18:26:45 +01:00
Johannes Millan
aaa041f75a test(sync): add tests for ETag-based If-Match conflict detection
Add unit tests verifying the If-Match header is properly used when
the expectedRev is an ETag (not a valid date):
- If-Match header sent instead of If-Unmodified-Since for ETags
- ETags properly quoted per RFC 7232
- Already-quoted ETags not double-quoted
- 412 Precondition Failed handled correctly for ETag conflicts
2026-01-13 18:26:45 +01:00
Johannes Millan
c628c3d7ce test(e2e): add legacy migration sync tests for WebDAV and SuperSync
Add E2E tests covering the scenario where two clients both migrate from
the old Super Productivity format (pre-operation-log) and then sync.

Tests include:
- Both clients migrated with different data (keep local/remote resolution)
- Both clients migrated with same entity IDs (ID collision handling)
- Archive data preservation after migration + sync (WebDAV only)

New files:
- legacy-migration-helpers.ts: Helper functions for seeding legacy DB
- 4 JSON fixtures for legacy data scenarios
- webdav-legacy-migration-sync.spec.ts: 4 WebDAV tests
- supersync-legacy-migration-sync.spec.ts: 3 SuperSync tests (1 skipped)
2026-01-13 18:26:45 +01:00
Johannes Millan
dcc7bd95c5 fix(sync): use If-Match header for ETag-based conflict detection
When WebDAV servers don't return Last-Modified headers and ETags
are used as revisions, use the If-Match header instead of skipping
conflict detection entirely. This ensures proper conflict detection
on servers that only support ETags.

Previously, non-date revisions (ETags) would cause the conditional
header to be skipped, disabling server-side conflict detection.
Now ETags are properly quoted per RFC 7232 and sent via If-Match.
2026-01-13 18:26:45 +01:00
Johannes Millan
b54c65f8a5 refactor(formly): replace any type with proper DOM types
Replace `as any` type assertions with proper HTMLInputElement |
HTMLTextAreaElement typing for event target access. This improves
type safety and follows CLAUDE.md guidelines to avoid any types.
2026-01-13 18:26:45 +01:00