+ASSERT_PATH="$HOME/Library/DoNotDisturb/DB/Assertions.json"
+MODECONFIG_PATH="$HOME/Library/DoNotDisturb/DB/ModeConfigurations.json"
+
+###############################################################################
+#
+# USAGE:
+#
+# You can ask a script to only continue if it matches a focus mode, or to halt
+# if it encounters it. You can do this by passing pipe separated values to
+# VAR_RUN_ON_FOCUS or VAR_HALT_ON_FOCUS and then calling focus_check.
+# For example, this will only run the script if "Personal" or "Do Not Disturb"
+# are active:
+#
+# VAR_RUN_ON_FOCUS="Personal|Do Not Disturb"
+# focus_check
+#
+# And this will halt the script only if the focus is Work
+#
+# VAR_HALT_ON_FOCUS="Work"
+# focus_check
+#
+# If neither variable is set, then all checks will be disabled.
+#
+# SETUP:
+#
+# Copy focus.utils.sh to your SwiftBar directory and include it if it exists.
+#
+# if [[ -f "${BASH_SOURCE%/*}/focus.utils.sh" ]]; then
+# source "${BASH_SOURCE%/*}/focus.utils.sh"
+# focus_check
+# fi
+#
+# PERMISSIONS:
+#
+# Accessing these databases requires that SwiftBar has full disk access
+# permissions. If the checks are enabled but the database files can't be read
+# it will instead return an error with instructions on what to do.
+#
+# ADDITIONAL FUNCTIONS:
+#
+# If you need custom behavior you can use the get_focus and is_focus_active
+#
+# get_focus will return the name of the currently active focus, or an empty
+# string if there's no focus enabled.
+#
+# is_focus_active receives a pipe delimited string and will return 0 if the
+# current focus is in the list, or 1 if the current focus is not present.
+#
+###############################################################################
+# Internal Utilities
+###############################################################################
+
+_assert_permissions() {
+
+ if [[ ! -r "$ASSERT_PATH" ]] || [[ ! -r "$MODECONFIG_PATH" ]]; then
+ echo ":light.beacon.max:"
+ echo "---"
+ echo "Focus database not readable.\nAllow SwiftBar in System Settings > Privacy & Security > Full Disk Access."
+ exit 0
+ fi
+}
+
+_run_on_focus() {
+ [[ -z "${VAR_RUN_ON_FOCUS}" ]] && return 0
+ _assert_permissions
+ is_focus_active $VAR_RUN_ON_FOCUS || exit 0
+ return 0
+}
+
+_halt_on_focus() {
+ [[ -z "${VAR_HALT_ON_FOCUS}" ]] && return 0
+ _assert_permissions
+ is_focus_active $VAR_HALT_ON_FOCUS || return 0
+ exit 0
+}
+
+###############################################################################
+# Public Functions
+###############################################################################
+
+get_focus() {
+ local focus=""
+
+ # Check for active assertions
+ if [[ -f "$ASSERT_PATH" ]]; then
+ local modeid=$(jq -r '.data[0].storeAssertionRecords[0].assertionDetails.assertionDetailsModeIdentifier // empty' "$ASSERT_PATH")
+
+ if [[ -n "$modeid" ]]; then
+ focus=$(jq -r --arg mid "$modeid" '.data[0].modeConfigurations[$mid].mode.name' "$MODECONFIG_PATH")
+ echo "$focus"
+ return
+ fi
+ fi
+
+ # Calculate current time in minutes
+ local hour=$(date +%H)
+ local minute=$(date +%M)
+ local now=$((hour * 60 + minute))
+
+ # Process scheduled triggers
+ jq -r '.data[0].modeConfigurations | to_entries[] | select(.value.triggers.triggers[0] != null) |
+ select(.value.triggers.triggers[0].enabledSetting == 2) |
+ {
+ id: .key,
+ name: .value.mode.name,
+ start: (.value.triggers.triggers[0].timePeriodStartTimeHour * 60 + .value.triggers.triggers[0].timePeriodStartTimeMinute),
+ end: (.value.triggers.triggers[0].timePeriodEndTimeHour * 60 + .value.triggers.triggers[0].timePeriodEndTimeMinute)
+ } | @json' "$MODECONFIG_PATH" 2>/dev/null | while read -r line; do
+ local start=$(echo "$line" | jq -r '.start')
+ local end=$(echo "$line" | jq -r '.end')
+ local name=$(echo "$line" | jq -r '.name')
+
+ if [[ $start -lt $end ]]; then
+ if [[ $now -ge $start && $now -lt $end ]]; then
+ focus="$name"
+ break
+ fi
+ elif [[ $start -gt $end ]]; then
+ if [[ $now -ge $start || $now -lt $end ]]; then
+ focus="$name"
+ break
+ fi
+ fi
+ done
+
+ echo -n "$focus" | xargs
+}
+
+is_focus_active() {
+ local current_focus=$(get_focus)
+ [[ "$current_focus" =~ ^($1)$ ]] && return 0
+ return 1
+}
+
+focus_check() {
+ _run_on_focus
+ _halt_on_focus
+}