Skip to content

Add 'Join Current Meeting' keyboard shortcut#897

Open
taakmatheus wants to merge 3 commits intoleits:masterfrom
taakmatheus:feature/join-current-event-shortcut
Open

Add 'Join Current Meeting' keyboard shortcut#897
taakmatheus wants to merge 3 commits intoleits:masterfrom
taakmatheus:feature/join-current-event-shortcut

Conversation

@taakmatheus
Copy link

@taakmatheus taakmatheus commented Mar 5, 2026

Add support for joining an in-progress meeting directly. Introduces Array.currentEvent(linkRequired:) to find the currently running event while respecting visibility/dismissal rules, a new KeyboardShortcuts.Name.joinCurrentEventShortcut, and UI/behavior changes: MenuBuilder now selects joinCurrent vs joinNext action/shortcut when the next event has already started; StatusBarItemController registers the new shortcut and implements joinCurrentMeeting() (opens current event or posts a notification if none); Preferences General tab gains recorder entries for the new shortcut.

Status

READY/IN DEVELOPMENT/HOLD

Description

A few sentences describing the overall goals of the pull request's commits.

Checklist

Steps to Test or Reproduce

Outline the steps to test or reproduce the PR here.

Summary by CodeRabbit

  • New Features

    • Join now: the Join menu can target the ongoing meeting when applicable.
    • New keyboard shortcuts added (including a dedicated "join current meeting" shortcut) and corresponding menu behavior.
    • Preferences updated to show and configure the "Join Current Meeting" shortcut.
  • Bug Fixes / Improvements

    • Improved detection of the current in-progress meeting, including optional link requirement.
  • Tests

    • Added tests verifying current-meeting selection and shortcut/menu behavior.

Add support for joining an in-progress meeting directly. Introduces Array.currentEvent(linkRequired:) to find the currently running event while respecting visibility/dismissal rules, a new KeyboardShortcuts.Name.joinCurrentEventShortcut, and UI/behavior changes: MenuBuilder now selects joinCurrent vs joinNext action/shortcut when the next event has already started; StatusBarItemController registers the new shortcut and implements joinCurrentMeeting() (opens current event or posts a notification if none); Preferences General tab gains recorder entries for the new shortcut.
@dosubot dosubot bot added the size:M This PR changes 30-99 lines, ignoring generated files. label Mar 5, 2026
@coderabbitai
Copy link

coderabbitai bot commented Mar 5, 2026

Walkthrough

Adds a new MBEvent.currentEvent(...) helper, keyboard shortcuts (including join-current), menu/status-bar logic to prefer joining an in-progress meeting, UI to configure the new shortcut, and tests validating current-event behavior and menu actions.

Changes

Cohort / File(s) Summary
Event Lookup Logic
MeetingBar/Core/Models/MBEvent+Helpers.swift
Adds currentEvent(linkRequired: Bool = false) on Array where Element == MBEvent to return the first currently running event, applying the same dismissal/all-day/declined/pending/tentative/canceled and link-required filters as nextEvent().
Keyboard Shortcut Names
MeetingBar/Extensions/KeyboardShortcutsNames.swift
Adds new public shortcut names: createMeetingShortcut, openMenuShortcut, joinEventShortcut, joinCurrentEventShortcut, openClipboardShortcut, toggleMeetingTitleVisibilityShortcut.
Menu & Status Bar Integration
MeetingBar/UI/StatusBar/MenuBuilder.swift, MeetingBar/UI/StatusBar/StatusBarItemController.swift
MenuBuilder now selects joinCurrentMeeting (with joinCurrentEventShortcut) when the next event has already started, otherwise joinNextMeeting. Adds joinCurrentMeeting() and binds it to the joinCurrentEventShortcut; shows localized notification if no current event.
Preferences / Shortcuts UI
MeetingBar/UI/Views/Preferences/GeneralTab.swift
Adds a Recorder and modal row to configure/display the new joinCurrentEventShortcut alongside existing shortcuts.
Tests
MeetingBarTests/NextEventTests.swift, MeetingBarTests/StatusBarItem/MenuBuilderTests.swift
Adds tests verifying currentEvent returns running events and respects link requirements; updates menu tests to assert correct join action selection for future vs current events.

Sequence Diagram

sequenceDiagram
    actor User
    participant Keyboard as Keyboard Shortcut
    participant Controller as StatusBarItemController
    participant Events as MBEvent Array (currentEvent)
    participant Launcher as Meeting Launcher

    User->>Keyboard: Press joinCurrentEventShortcut
    Keyboard->>Controller: invoke joinCurrentMeeting()
    Controller->>Events: currentEvent(linkRequired: Bool)
    alt event found
        Events-->>Controller: MBEvent
        Controller->>Launcher: open meeting link
        Launcher-->>User: join meeting
    else no event
        Events-->>Controller: nil
        Controller-->>User: show notification (no current meeting)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped through calendars, nose in the breeze,
Found a meeting already buzzing with bees.
A shortcut, a click — we leap in as one,
Join current, not next; the rabbit's work done. 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.77% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'Add 'Join Current Meeting' keyboard shortcut' directly and clearly summarizes the main change—introducing a new keyboard shortcut feature for joining current meetings.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@dosubot dosubot bot added the feature New feature or request label Mar 5, 2026
@codecov
Copy link

codecov bot commented Mar 5, 2026

Codecov Report

❌ Patch coverage is 65.75342% with 25 lines in your changes missing coverage. Please review.
✅ Project coverage is 36.83%. Comparing base (84e0a9f) to head (80c5a58).
⚠️ Report is 15 commits behind head on master.

Files with missing lines Patch % Lines
MeetingBar/Core/Models/MBEvent+Helpers.swift 47.82% 6 Missing and 6 partials ⚠️
...tingBar/UI/StatusBar/StatusBarItemController.swift 0.00% 7 Missing ⚠️
MeetingBar/UI/Views/Preferences/GeneralTab.swift 0.00% 6 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           master     #897       +/-   ##
===========================================
+ Coverage   26.30%   36.83%   +10.52%     
===========================================
  Files          36       48       +12     
  Lines        5645     5172      -473     
  Branches     2210     1756      -454     
===========================================
+ Hits         1485     1905      +420     
+ Misses       4103     3204      -899     
- Partials       57       63        +6     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
MeetingBar/UI/Views/Preferences/GeneralTab.swift (2)

46-47: Inconsistent label formatting with trailing colon.

The label appends a colon (+ ":") while other shortcut labels in this section (e.g., line 49 preferences_general_shortcut_join_next) don't include a trailing colon. Consider removing the colon for consistency, or adding a dedicated localization key that includes proper punctuation.

✨ Suggested fix
-            Text("status_bar_section_join_current_meeting".loco() + ":")
+            Text("status_bar_section_join_current_meeting".loco())
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@MeetingBar/UI/Views/Preferences/GeneralTab.swift` around lines 46 - 47, The
label Text("status_bar_section_join_current_meeting".loco() + ":") is
inconsistent with other shortcut labels; remove the hard-coded trailing colon by
changing the Text call to use the localized string without appending ":" (i.e.,
use "status_bar_section_join_current_meeting".loco()) so it matches other
entries like the KeyboardShortcuts.Recorder(for: .joinCurrentEventShortcut);
alternatively, if punctuation must be part of the localized text, replace the
concatenation with a dedicated localization key (e.g., add a key that includes
the colon) and use that key instead.

80-84: Same trailing colon inconsistency in modal.

Apply the same fix here for consistency with other shortcuts in the modal list.

✨ Suggested fix
                 HStack {
-                    Text("status_bar_section_join_current_meeting".loco() + ":")
+                    Text("status_bar_section_join_current_meeting".loco())
                     Spacer()
                     KeyboardShortcuts.Recorder(for: .joinCurrentEventShortcut)
                 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@MeetingBar/UI/Views/Preferences/GeneralTab.swift` around lines 80 - 84, The
Text in the HStack for the join shortcut currently appends a hardcoded ":" which
causes trailing-colon inconsistency; update the HStack so
Text("status_bar_section_join_current_meeting".loco()) does not concatenate ":",
leaving punctuation to the localized string (or add the colon into the
localization if needed) and keep the rest intact (HStack and
KeyboardShortcuts.Recorder(for: .joinCurrentEventShortcut)) to match the other
modal shortcut entries.
MeetingBar/Core/Models/MBEvent+Helpers.swift (1)

176-213: Missing personalEventsAppereance filter that exists in nextEvent().

The nextEvent() method (lines 107-109) filters out personal events when Defaults[.personalEventsAppereance] != .show_active. The new currentEvent() method lacks this filter, which could cause inconsistent behavior: an event might be hidden from nextEvent() but returned by currentEvent().

Consider adding the same filter for consistency:

♻️ Proposed fix
 func currentEvent(linkRequired: Bool = false) -> MBEvent? {
     let now = Date()

+    // Filter out personal events if not marked as 'active'
+    let candidates: [MBEvent]
+    if Defaults[.personalEventsAppereance] != .show_active {
+        candidates = self.filter { !$0.attendees.isEmpty }
+    } else {
+        candidates = self
+    }
+
-    for event in self {
+    for event in candidates {
         guard event.startDate <= now, event.endDate > now else {
             continue
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@MeetingBar/Core/Models/MBEvent`+Helpers.swift around lines 176 - 213,
currentEvent(linkRequired:) is missing the same personal-events filter used in
nextEvent(), causing inconsistent results; update currentEvent to skip events
where event.isPersonal is true when Defaults[.personalEventsAppereance] !=
.show_active (same check/logic used in nextEvent()) so personal events are
filtered out consistently.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@MeetingBar/Core/Models/MBEvent`+Helpers.swift:
- Around line 176-213: currentEvent(linkRequired:) is missing the same
personal-events filter used in nextEvent(), causing inconsistent results; update
currentEvent to skip events where event.isPersonal is true when
Defaults[.personalEventsAppereance] != .show_active (same check/logic used in
nextEvent()) so personal events are filtered out consistently.

In `@MeetingBar/UI/Views/Preferences/GeneralTab.swift`:
- Around line 46-47: The label
Text("status_bar_section_join_current_meeting".loco() + ":") is inconsistent
with other shortcut labels; remove the hard-coded trailing colon by changing the
Text call to use the localized string without appending ":" (i.e., use
"status_bar_section_join_current_meeting".loco()) so it matches other entries
like the KeyboardShortcuts.Recorder(for: .joinCurrentEventShortcut);
alternatively, if punctuation must be part of the localized text, replace the
concatenation with a dedicated localization key (e.g., add a key that includes
the colon) and use that key instead.
- Around line 80-84: The Text in the HStack for the join shortcut currently
appends a hardcoded ":" which causes trailing-colon inconsistency; update the
HStack so Text("status_bar_section_join_current_meeting".loco()) does not
concatenate ":", leaving punctuation to the localized string (or add the colon
into the localization if needed) and keep the rest intact (HStack and
KeyboardShortcuts.Recorder(for: .joinCurrentEventShortcut)) to match the other
modal shortcut entries.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 42c2745c-4392-4ebe-a42f-a9b49692d8e1

📥 Commits

Reviewing files that changed from the base of the PR and between 48373d7 and 51723fd.

📒 Files selected for processing (5)
  • MeetingBar/Core/Models/MBEvent+Helpers.swift
  • MeetingBar/Extensions/KeyboardShortcutsNames.swift
  • MeetingBar/UI/StatusBar/MenuBuilder.swift
  • MeetingBar/UI/StatusBar/StatusBarItemController.swift
  • MeetingBar/UI/Views/Preferences/GeneralTab.swift

Update MBEvent+Helpers to document currentEvent and add a linkRequired parameter (default false) so callers can opt to consider only events with meeting links. Add descriptive comments for global keyboard shortcut names in KeyboardShortcutsNames. Also add documentation for joinCurrentMeeting in StatusBarItemController to clarify behavior when no active event is present. Changes are focused on widening API clarity and improving inline documentation across these components.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@MeetingBar/Extensions/KeyboardShortcutsNames.swift`:
- Around line 18-19: Update the documentation for the static constant
joinEventShortcut to reflect its actual behavior: change the comment so it
states that this global shortcut triggers joining the next meeting (not the
nearest/current), since StatusBarItemController.setupKeyboardShortcuts maps
.joinEventShortcut to joinNextMeeting(); locate the constant in
KeyboardShortcutsNames.swift (joinEventShortcut) and replace the misleading
phrase "nearest meeting (current or next)" with wording that clearly indicates
it starts/join the next scheduled meeting.

In `@MeetingBar/UI/StatusBar/StatusBarItemController.swift`:
- Line 415: Replace the generic next-meeting copy in the current-meeting "no
active event" branch by using a current-meeting-specific localization key
instead of "next_meeting_empty_message" in the sendNotification call; update the
call in StatusBarItemController where
sendNotification("status_bar_section_join_current_meeting".loco(),
"next_meeting_empty_message".loco()) is used to reference a dedicated key like
"current_meeting_empty_message" (and add that localization entry if it doesn’t
exist) so the title ("status_bar_section_join_current_meeting") and message
reflect the current-meeting context.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 3dc24c78-754d-4b09-ba45-e00b1683ee53

📥 Commits

Reviewing files that changed from the base of the PR and between 51723fd and dcccc49.

📒 Files selected for processing (3)
  • MeetingBar/Core/Models/MBEvent+Helpers.swift
  • MeetingBar/Extensions/KeyboardShortcutsNames.swift
  • MeetingBar/UI/StatusBar/StatusBarItemController.swift
🚧 Files skipped from review as they are similar to previous changes (1)
  • MeetingBar/Core/Models/MBEvent+Helpers.swift

Comment on lines +18 to 19
/// Global shortcut used to join the nearest meeting (current or next).
static let joinEventShortcut = Self("joinEventShortcut")
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix joinEventShortcut doc to match actual behavior.

The comment says “nearest meeting (current or next)”, but current wiring in MeetingBar/UI/StatusBar/StatusBarItemController.swift (setupKeyboardShortcuts) maps .joinEventShortcut to joinNextMeeting(). Update the doc to avoid API confusion.

✏️ Suggested doc fix
-    /// Global shortcut used to join the nearest meeting (current or next).
+    /// Global shortcut used to join the next meeting.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@MeetingBar/Extensions/KeyboardShortcutsNames.swift` around lines 18 - 19,
Update the documentation for the static constant joinEventShortcut to reflect
its actual behavior: change the comment so it states that this global shortcut
triggers joining the next meeting (not the nearest/current), since
StatusBarItemController.setupKeyboardShortcuts maps .joinEventShortcut to
joinNextMeeting(); locate the constant in KeyboardShortcutsNames.swift
(joinEventShortcut) and replace the misleading phrase "nearest meeting (current
or next)" with wording that clearly indicates it starts/join the next scheduled
meeting.

if let currentEvent = events.currentEvent() {
currentEvent.openMeeting()
} else {
sendNotification("status_bar_section_join_current_meeting".loco(), "next_meeting_empty_message".loco())
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use current-meeting-specific notification copy here.

The “no active event” branch uses "next_meeting_empty_message", which can produce misleading text in the current-meeting path. Prefer dedicated current-meeting title/message localization keys for this branch.

💡 Suggested adjustment
-            sendNotification("status_bar_section_join_current_meeting".loco(), "next_meeting_empty_message".loco())
+            sendNotification("current_meeting_empty_title".loco(), "current_meeting_empty_message".loco())
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
sendNotification("status_bar_section_join_current_meeting".loco(), "next_meeting_empty_message".loco())
sendNotification("current_meeting_empty_title".loco(), "current_meeting_empty_message".loco())
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@MeetingBar/UI/StatusBar/StatusBarItemController.swift` at line 415, Replace
the generic next-meeting copy in the current-meeting "no active event" branch by
using a current-meeting-specific localization key instead of
"next_meeting_empty_message" in the sendNotification call; update the call in
StatusBarItemController where
sendNotification("status_bar_section_join_current_meeting".loco(),
"next_meeting_empty_message".loco()) is used to reference a dedicated key like
"current_meeting_empty_message" (and add that localization entry if it doesn’t
exist) so the title ("status_bar_section_join_current_meeting") and message
reflect the current-meeting context.

Add unit tests covering currentEvent() behavior and menu join actions. NextEventTests: verify currentEvent() returns a running event and that the linkRequired parameter filters out events without links. MenuBuilderTests: assert the current meeting menu item uses the joinCurrentMeeting selector and add a test ensuring a future event produces the "status_bar_section_join_next_meeting" title and uses the joinNextMeeting selector.
@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. and removed size:M This PR changes 30-99 lines, ignoring generated files. labels Mar 5, 2026
let future = makeFakeEvent(
id: "F",
start: Date().addingTimeInterval(300),
end: Date().addingTimeInterval(1_200)

Check warning

Code scanning / Swiftlint (reported by Codacy)

Underscores should be used as thousand separator in large decimal numbers. Warning

Underscores should be used as thousand separator in large decimal numbers.
XCTAssertEqual(array.nextEvent(), running)
}

func test_currentEvent_returnsRunningEvent() {

Check warning

Code scanning / Tailor (reported by Codacy)

Function names should be lowerCamelCase Warning

Function names should be lowerCamelCase
XCTAssertEqual([future, running].currentEvent(), running)
}

func test_currentEvent_respectsLinkRequirement() {

Check warning

Code scanning / Tailor (reported by Codacy)

Function names should be lowerCamelCase Warning

Function names should be lowerCamelCase
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
MeetingBarTests/StatusBarItem/MenuBuilderTests.swift (1)

47-57: ⚠️ Potential issue | 🟡 Minor

Potential flaky test due to timing edge case.

The event is created with start: Date() (line 49). The buildJoinSection logic at MenuBuilder.swift:74 compares nextEvent.startDate < now where now is captured inside the method. If any time elapses between event creation and the comparison (even microseconds), the condition becomes true and joinCurrentMeeting is selected. However, if executed fast enough, the times could be equal, making the condition false and selecting joinNextMeeting instead.

To make this deterministic, offset the start time slightly into the past:

Proposed fix
     func test_joinSectionHasCreateAndJoin() {
         let next = makeFakeEvent(id: "J",
-                                 start: Date(), end: Date().addingTimeInterval(60))
+                                 start: Date().addingTimeInterval(-1), end: Date().addingTimeInterval(60))
         let items = MenuBuilder(target: Dummy())
             .buildJoinSection(nextEvent: next)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@MeetingBarTests/StatusBarItem/MenuBuilderTests.swift` around lines 47 - 57,
The test test_joinSectionHasCreateAndJoin is flaky because makeFakeEvent uses
start: Date() and MenuBuilder.buildJoinSection compares nextEvent.startDate <
now; change the test to create the event with a small negative offset (e.g.
start: Date().addingTimeInterval(-1)) so nextEvent.startDate is guaranteed to be
before now, keeping the assertions for
StatusBarItemController.joinCurrentMeeting and createMeetingAction
deterministic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@MeetingBarTests/StatusBarItem/MenuBuilderTests.swift`:
- Around line 47-57: The test test_joinSectionHasCreateAndJoin is flaky because
makeFakeEvent uses start: Date() and MenuBuilder.buildJoinSection compares
nextEvent.startDate < now; change the test to create the event with a small
negative offset (e.g. start: Date().addingTimeInterval(-1)) so
nextEvent.startDate is guaranteed to be before now, keeping the assertions for
StatusBarItemController.joinCurrentMeeting and createMeetingAction
deterministic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: f2594337-45df-4ee6-9cc6-b16f19d66826

📥 Commits

Reviewing files that changed from the base of the PR and between dcccc49 and 80c5a58.

📒 Files selected for processing (2)
  • MeetingBarTests/NextEventTests.swift
  • MeetingBarTests/StatusBarItem/MenuBuilderTests.swift

@taakmatheus
Copy link
Author

@leits please could you verify this PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature or request size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant