Give reminders an indicator and a full QS flow
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
# omarchy:summary=Send an Omarchy desktop notification
|
# omarchy:summary=Send an Omarchy desktop notification
|
||||||
# omarchy:args=[-g <glyph>] [-u <low|normal|critical>] <headline> [description] [notify-send options]
|
# omarchy:args=[-g <glyph>] [-u <low|normal|critical>] <headline> [description] [notify-send options]
|
||||||
# omarchy:examples=omarchy notification send "Reminder" "5 minutes are up" -g -u critical
|
# omarchy:examples=omarchy notification send "Reminder" "5 minutes are up" -g
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
|||||||
+103
-38
@@ -1,8 +1,8 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# omarchy:summary=Set and show lightweight desktop notification reminders
|
# omarchy:summary=Set and show lightweight desktop notification reminders
|
||||||
# omarchy:args=<minutes> [message] | show | clear
|
# omarchy:args=[-i|--interactive] | <minutes> [message] | show [-j|--json] | clear
|
||||||
# omarchy:examples=omarchy reminder 5 | omarchy reminder 30 "Check the oven" | omarchy reminder show | omarchy reminder clear
|
# omarchy:examples=omarchy reminder -i | omarchy reminder 5 | omarchy reminder 30 "Check the oven" | omarchy reminder show | omarchy reminder show --json | omarchy reminder clear
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
@@ -20,31 +20,9 @@ format_remaining() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_systemd_timespan() {
|
active_reminder_timers() {
|
||||||
local timespan="$1"
|
local now=${1:-$(date +%s)}
|
||||||
local total=0
|
local timer next
|
||||||
local value unit whole
|
|
||||||
|
|
||||||
while read -r value unit; do
|
|
||||||
whole=${value%.*}
|
|
||||||
|
|
||||||
case $unit in
|
|
||||||
d) total=$((total + whole * 86400)) ;;
|
|
||||||
h) total=$((total + whole * 3600)) ;;
|
|
||||||
min) total=$((total + whole * 60)) ;;
|
|
||||||
s) total=$((total + whole)) ;;
|
|
||||||
ms | us) ;;
|
|
||||||
esac
|
|
||||||
done < <(grep -oE '[0-9]+([.][0-9]+)?(d|h|min|s|ms|us)' <<<"$timespan" | sed -E 's/^([0-9.]+)([a-z]+)$/\1 \2/')
|
|
||||||
|
|
||||||
echo "$total"
|
|
||||||
}
|
|
||||||
|
|
||||||
show_reminders() {
|
|
||||||
local timer next remaining body=""
|
|
||||||
local reminder_dir="${XDG_RUNTIME_DIR:-/tmp}/omarchy-reminders"
|
|
||||||
local reminder_message=""
|
|
||||||
local now=$(date +%s)
|
|
||||||
|
|
||||||
while IFS=$'\t' read -r timer next; do
|
while IFS=$'\t' read -r timer next; do
|
||||||
[[ -z $timer || -z $next ]] && continue
|
[[ -z $timer || -z $next ]] && continue
|
||||||
@@ -52,10 +30,28 @@ show_reminders() {
|
|||||||
next=$((next / 1000000))
|
next=$((next / 1000000))
|
||||||
((next <= now)) && continue
|
((next <= now)) && continue
|
||||||
|
|
||||||
|
printf "%s\t%s\n" "$timer" "$next"
|
||||||
|
done < <(systemctl --user list-timers --all --output=json "omarchy-reminder-*.timer" 2>/dev/null | jq -r '.[] | [.unit, .next] | @tsv')
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh_indicator() {
|
||||||
|
omarchy-shell -q omarchy.indicators refresh >/dev/null 2>&1 || true
|
||||||
|
}
|
||||||
|
|
||||||
|
open_interactive() {
|
||||||
|
omarchy-shell shell summon omarchy.reminders "{}"
|
||||||
|
}
|
||||||
|
|
||||||
|
show_reminders() {
|
||||||
|
local timer next remaining reminder reminder_minutes body=""
|
||||||
|
local reminder_dir="${XDG_RUNTIME_DIR:-/tmp}/omarchy-reminders"
|
||||||
|
local reminder_message=""
|
||||||
|
local now=$(date +%s)
|
||||||
|
|
||||||
|
while IFS=$'\t' read -r timer next; do
|
||||||
remaining=$((next - now))
|
remaining=$((next - now))
|
||||||
reminder=${timer%.timer}
|
reminder=${timer%.timer}
|
||||||
reminder=${reminder#omarchy-reminder-}
|
reminder=${reminder#omarchy-reminder-}
|
||||||
set_at=${reminder##*-}
|
|
||||||
reminder_minutes=${reminder%%m-*}
|
reminder_minutes=${reminder%%m-*}
|
||||||
reminder_message=""
|
reminder_message=""
|
||||||
[[ -f $reminder_dir/${timer%.timer}.message ]] && reminder_message=$(<"$reminder_dir/${timer%.timer}.message")
|
[[ -f $reminder_dir/${timer%.timer}.message ]] && reminder_message=$(<"$reminder_dir/${timer%.timer}.message")
|
||||||
@@ -65,15 +61,62 @@ show_reminders() {
|
|||||||
else
|
else
|
||||||
body+="${reminder_minutes}-min reminder in $(format_remaining $remaining) ($(date -d "@$next" +%-H:%M))"$'\n'
|
body+="${reminder_minutes}-min reminder in $(format_remaining $remaining) ($(date -d "@$next" +%-H:%M))"$'\n'
|
||||||
fi
|
fi
|
||||||
done < <(systemctl --user list-timers --all --output=json "omarchy-reminder-*.timer" 2>/dev/null | jq -r '.[] | [.unit, .next] | @tsv')
|
done < <(active_reminder_timers "$now")
|
||||||
|
|
||||||
if [[ -z $body ]]; then
|
if [[ -z $body ]]; then
|
||||||
omarchy-notification-send -g "Upcoming reminders" "No outstanding reminders"
|
omarchy-notification-send -g "Upcoming reminders" "No outstanding reminders"
|
||||||
else
|
else
|
||||||
omarchy-notification-send -g "Upcoming reminders" "${body%$'\n'}"
|
omarchy-notification-send -g "Upcoming reminders" "${body%$'\n'}"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
show_json() {
|
||||||
|
local timer next remaining reminder reminder_minutes unit reminder_message label item_json reminders_json="[]"
|
||||||
|
local reminder_dir="${XDG_RUNTIME_DIR:-/tmp}/omarchy-reminders"
|
||||||
|
local now=$(date +%s)
|
||||||
|
local count=0
|
||||||
|
local tooltip="Set Reminder"
|
||||||
|
|
||||||
|
while IFS=$'\t' read -r timer next; do
|
||||||
|
count=$((count + 1))
|
||||||
|
|
||||||
|
unit=${timer%.timer}
|
||||||
|
reminder=${unit#omarchy-reminder-}
|
||||||
|
reminder_minutes=${reminder%%m-*}
|
||||||
|
[[ ! $reminder_minutes =~ ^[0-9]+$ ]] && reminder_minutes=0
|
||||||
|
remaining=$((next - now))
|
||||||
|
reminder_message=""
|
||||||
|
[[ -f $reminder_dir/$unit.message ]] && reminder_message=$(<"$reminder_dir/$unit.message")
|
||||||
|
|
||||||
|
if [[ -n $reminder_message ]]; then
|
||||||
|
label=$reminder_message
|
||||||
|
else
|
||||||
|
label="${reminder_minutes}-min reminder"
|
||||||
|
fi
|
||||||
|
|
||||||
|
item_json=$(jq -cn \
|
||||||
|
--arg unit "$unit" \
|
||||||
|
--arg timer "$timer" \
|
||||||
|
--arg label "$label" \
|
||||||
|
--arg message "$reminder_message" \
|
||||||
|
--arg remaining "$(format_remaining "$remaining")" \
|
||||||
|
--arg atTime "$(date -d "@$next" +%-H:%M)" \
|
||||||
|
--argjson minutes "$reminder_minutes" \
|
||||||
|
--argjson at "$next" \
|
||||||
|
--argjson remainingSeconds "$remaining" \
|
||||||
|
'{unit:$unit,timer:$timer,minutes:$minutes,message:$message,label:$label,remaining:$remaining,remainingSeconds:$remainingSeconds,at:$at,atTime:$atTime}')
|
||||||
|
reminders_json=$(jq -cn --argjson reminders "$reminders_json" --argjson item "$item_json" '$reminders + [$item]')
|
||||||
|
done < <(active_reminder_timers "$now")
|
||||||
|
|
||||||
|
if ((count == 1)); then
|
||||||
|
tooltip="1 reminder"
|
||||||
|
elif ((count > 1)); then
|
||||||
|
tooltip="$count reminders"
|
||||||
|
fi
|
||||||
|
|
||||||
|
jq -cn --argjson count "$count" --arg tooltip "$tooltip" --argjson reminders "$reminders_json" '{count:$count,active:($count > 0),tooltip:$tooltip,reminders:$reminders}'
|
||||||
|
}
|
||||||
|
|
||||||
clear_reminders() {
|
clear_reminders() {
|
||||||
local units
|
local units
|
||||||
local reminder_dir="${XDG_RUNTIME_DIR:-/tmp}/omarchy-reminders"
|
local reminder_dir="${XDG_RUNTIME_DIR:-/tmp}/omarchy-reminders"
|
||||||
@@ -85,12 +128,35 @@ clear_reminders() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
rm -f "$reminder_dir"/omarchy-reminder-*.message 2>/dev/null || true
|
rm -f "$reminder_dir"/omarchy-reminder-*.message 2>/dev/null || true
|
||||||
omarchy-notification-send -g "All reminders have been cleared"
|
refresh_indicator
|
||||||
|
omarchy-notification-send -g "All reminders have been cleared"
|
||||||
|
}
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo "Usage: omarchy-reminder [-i|--interactive]"
|
||||||
|
echo " omarchy-reminder <minutes> [message]"
|
||||||
|
echo " omarchy-reminder show [-j|--json]"
|
||||||
|
echo " omarchy-reminder clear"
|
||||||
}
|
}
|
||||||
|
|
||||||
case ${1:-} in
|
case ${1:-} in
|
||||||
|
-i | --interactive)
|
||||||
|
open_interactive
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
show | list)
|
show | list)
|
||||||
show_reminders
|
case ${2:-} in
|
||||||
|
-j | --json)
|
||||||
|
show_json
|
||||||
|
;;
|
||||||
|
"")
|
||||||
|
show_reminders
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
clear)
|
clear)
|
||||||
@@ -105,9 +171,7 @@ message="$*"
|
|||||||
custom_message="$message"
|
custom_message="$message"
|
||||||
|
|
||||||
if [[ -z $minutes ]] || [[ ! $minutes =~ ^[0-9]+$ ]] || ((minutes == 0)); then
|
if [[ -z $minutes ]] || [[ ! $minutes =~ ^[0-9]+$ ]] || ((minutes == 0)); then
|
||||||
echo "Usage: omarchy-reminder <minutes> [message]"
|
usage
|
||||||
echo " omarchy-reminder show"
|
|
||||||
echo " omarchy-reminder clear"
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -131,6 +195,7 @@ if [[ -n $custom_message ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
systemd-run --user --quiet --collect --on-active="${minutes}m" --unit="$unit" \
|
systemd-run --user --quiet --collect --on-active="${minutes}m" --unit="$unit" \
|
||||||
bash -c 'omarchy-notification-send -g "Reminder" "$1" -u critical; rm -f "$2"' bash "$message" "$message_file"
|
bash -c 'omarchy-notification-send -g "Reminder" "$1"; rm -f "$2"; omarchy-shell -q omarchy.indicators refresh >/dev/null 2>&1 || true' bash "$message" "$message_file"
|
||||||
|
|
||||||
omarchy-notification-send -g "$confirmation_title" "$confirmation"
|
refresh_indicator
|
||||||
|
omarchy-notification-send -g "$confirmation_title" "$confirmation"
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# omarchy:summary=Prompt for a reminder duration + message and schedule it
|
|
||||||
# omarchy:examples=omarchy reminder set-interactive
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
prompt_minutes() {
|
|
||||||
while :; do
|
|
||||||
minutes=$(omarchy-menu-input "Remind in minutes") || exit 0
|
|
||||||
if [[ $minutes =~ ^[0-9]+$ ]] && (( minutes > 0 )); then
|
|
||||||
printf '%s' "$minutes"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
[[ -z $minutes ]] && exit 0
|
|
||||||
omarchy-notification-send "Invalid reminder" "Enter the number of minutes" -u critical
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
minutes=$(prompt_minutes)
|
|
||||||
[[ -n $minutes ]] || exit 0
|
|
||||||
|
|
||||||
message=$(omarchy-menu-input "Reminder message") || exit 0
|
|
||||||
if [[ -n $message ]]; then
|
|
||||||
omarchy-reminder "$minutes" "$message"
|
|
||||||
else
|
|
||||||
omarchy-reminder "$minutes"
|
|
||||||
fi
|
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
"learn.bash": {"icon":"","label":"Bash","keywords":"shell cheatsheet","action":"omarchy-launch-webapp 'https://devhints.io/bash'"},
|
"learn.bash": {"icon":"","label":"Bash","keywords":"shell cheatsheet","action":"omarchy-launch-webapp 'https://devhints.io/bash'"},
|
||||||
|
|
||||||
// Trigger
|
// Trigger
|
||||||
"trigger.reminder": {"icon":"","label":"Reminder","aliases":["reminder"],"keywords":"timer notification remind"},
|
"trigger.reminder": {"icon":"","label":"Reminder","aliases":["reminder"],"keywords":"timer notification remind"},
|
||||||
"trigger.capture": {"icon":"","label":"Capture","aliases":["capture","screenshot","screenrecord","screen-record","screenrecording"],"keywords":"color text extraction"},
|
"trigger.capture": {"icon":"","label":"Capture","aliases":["capture","screenshot","screenrecord","screen-record","screenrecording"],"keywords":"color text extraction"},
|
||||||
"trigger.capture.screenshot": {"icon":"","label":"Screenshot","keywords":"picture","action":"omarchy-capture-screenshot"},
|
"trigger.capture.screenshot": {"icon":"","label":"Screenshot","keywords":"picture","action":"omarchy-capture-screenshot"},
|
||||||
"trigger.capture.screenrecord.stop": {"icon":"","label":"Stop Screenrecording","keywords":"recording video","when":"pgrep -f '^gpu-screen-recorder' >/dev/null","action":"omarchy-capture-screenrecording --stop-recording"},
|
"trigger.capture.screenrecord.stop": {"icon":"","label":"Stop Screenrecording","keywords":"recording video","when":"pgrep -f '^gpu-screen-recorder' >/dev/null","action":"omarchy-capture-screenrecording --stop-recording"},
|
||||||
@@ -67,9 +67,9 @@
|
|||||||
"trigger.hardware.touchpad-haptics.mid": {"icon":"","label":"mid","keywords":"medium","when":"omarchy-hw-dell-xps-haptic-touchpad >/dev/null && omarchy-cmd-present dell-xps-touchpad-haptics","checked":"[[ \"$(dell-xps-touchpad-haptics get)\" == \"mid\" ]]","action":"dell-xps-touchpad-haptics set mid"},
|
"trigger.hardware.touchpad-haptics.mid": {"icon":"","label":"mid","keywords":"medium","when":"omarchy-hw-dell-xps-haptic-touchpad >/dev/null && omarchy-cmd-present dell-xps-touchpad-haptics","checked":"[[ \"$(dell-xps-touchpad-haptics get)\" == \"mid\" ]]","action":"dell-xps-touchpad-haptics set mid"},
|
||||||
"trigger.hardware.touchpad-haptics.high": {"icon":"","label":"high","when":"omarchy-hw-dell-xps-haptic-touchpad >/dev/null && omarchy-cmd-present dell-xps-touchpad-haptics","checked":"[[ \"$(dell-xps-touchpad-haptics get)\" == \"high\" ]]","action":"dell-xps-touchpad-haptics set high"},
|
"trigger.hardware.touchpad-haptics.high": {"icon":"","label":"high","when":"omarchy-hw-dell-xps-haptic-touchpad >/dev/null && omarchy-cmd-present dell-xps-touchpad-haptics","checked":"[[ \"$(dell-xps-touchpad-haptics get)\" == \"high\" ]]","action":"dell-xps-touchpad-haptics set high"},
|
||||||
"trigger.hardware.touchscreen": {"icon":"","label":"Touchscreen","keywords":"tablet","when":"omarchy-hw-touchscreen >/dev/null","action":"omarchy-toggle-touchscreen"},
|
"trigger.hardware.touchscreen": {"icon":"","label":"Touchscreen","keywords":"tablet","when":"omarchy-hw-touchscreen >/dev/null","action":"omarchy-toggle-touchscreen"},
|
||||||
"trigger.reminder.set": {"icon":"","label":"Set one","aliases":["reminder-set","remind"],"keywords":"timer","action":"omarchy-reminder-set-interactive"},
|
"trigger.reminder.set": {"icon":"","label":"Set one","aliases":["reminder-set","remind"],"keywords":"timer","action":"omarchy-reminder -i"},
|
||||||
"trigger.reminder.show": {"icon":"","label":"Show all","keywords":"list","action":"omarchy-reminder show"},
|
"trigger.reminder.show": {"icon":"","label":"Show all","keywords":"list","action":"omarchy-reminder show"},
|
||||||
"trigger.reminder.clear": {"icon":"","label":"Clear all","keywords":"delete","action":"omarchy-reminder clear"},
|
"trigger.reminder.clear": {"icon":"","label":"Clear all","keywords":"delete","action":"omarchy-reminder clear"},
|
||||||
"trigger.share.clipboard": {"icon":"","label":"Clipboard","action":"omarchy-menu-share clipboard"},
|
"trigger.share.clipboard": {"icon":"","label":"Clipboard","action":"omarchy-menu-share clipboard"},
|
||||||
"trigger.share.file": {"icon":"","label":"File","action":"xdg-terminal-exec --app-id=org.omarchy.terminal bash -c 'omarchy-menu-share file'"},
|
"trigger.share.file": {"icon":"","label":"File","action":"xdg-terminal-exec --app-id=org.omarchy.terminal bash -c 'omarchy-menu-share file'"},
|
||||||
"trigger.share.folder": {"icon":"","label":"Folder","keywords":"directory","action":"xdg-terminal-exec --app-id=org.omarchy.terminal bash -c 'omarchy-menu-share folder'"},
|
"trigger.share.folder": {"icon":"","label":"Folder","keywords":"directory","action":"xdg-terminal-exec --app-id=org.omarchy.terminal bash -c 'omarchy-menu-share folder'"},
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ User-installed plugins live alongside these conceptually but on disk under
|
|||||||
| Image picker | `omarchy.image-picker` | `overlay` | `image-picker/ImagePicker.qml` |
|
| Image picker | `omarchy.image-picker` | `overlay` | `image-picker/ImagePicker.qml` |
|
||||||
| Emojis | `omarchy.emojis` | `overlay` | `emojis/Emojis.qml` |
|
| Emojis | `omarchy.emojis` | `overlay` | `emojis/Emojis.qml` |
|
||||||
| Clipboard mgr | `omarchy.clipboard` | `overlay` | `clipboard/Clipboard.qml` |
|
| Clipboard mgr | `omarchy.clipboard` | `overlay` | `clipboard/Clipboard.qml` |
|
||||||
|
| Reminders | `omarchy.reminders` | `overlay` | `reminders/ReminderFlow.qml` |
|
||||||
| Omarchy menu | `omarchy.menu` | `menu`, `bar-widget` | `menu/Menu.qml`, `menu/BarWidget.qml` |
|
| Omarchy menu | `omarchy.menu` | `menu`, `bar-widget` | `menu/Menu.qml`, `menu/BarWidget.qml` |
|
||||||
| Notifications | `omarchy.notifications` | `service`, `bar-widget` | `notifications/Service.qml`, `notifications/BarWidget.qml` |
|
| Notifications | `omarchy.notifications` | `service`, `bar-widget` | `notifications/Service.qml`, `notifications/BarWidget.qml` |
|
||||||
| Media | `omarchy.media` | `service`, `bar-widget` | `services/media/Service.qml`, `services/media/BarWidget.qml` |
|
| Media | `omarchy.media` | `service`, `bar-widget` | `services/media/Service.qml`, `services/media/BarWidget.qml` |
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ Example `shell.json` (bar subtree only shown):
|
|||||||
| `omarchy.bluetooth` | Bluetooth icon + popup with device list, connect/disconnect, battery | left = popup · right = toggle radio · middle = bluetoothctl TUI |
|
| `omarchy.bluetooth` | Bluetooth icon + popup with device list, connect/disconnect, battery | left = popup · right = toggle radio · middle = bluetoothctl TUI |
|
||||||
| `omarchy.monitor` | Brightness and laptop display controls | left = popup |
|
| `omarchy.monitor` | Brightness and laptop display controls | left = popup |
|
||||||
|
|
||||||
The `omarchy.indicators` widget loads individual bar indicators from `indicators/`. Omit `items` (or set it to an empty array) to show all indicators in the default order, or set `items` to a subset such as `["Dnd", "NightLight"]`. Set `alwaysShow` to `true` to keep inactive indicators visible instead of revealing them only on hover. Multiple `omarchy.indicators` instances are allowed, so different sections can show different subsets.
|
The `omarchy.indicators` widget loads individual bar indicators from `indicators/`. Omit `items` (or set it to an empty array) to show all indicators in the default order, or set `items` to a subset such as `["Dnd", "Reminder", "NightLight"]`. Set `alwaysShow` to `true` to keep inactive indicators visible instead of revealing them only on hover. Multiple `omarchy.indicators` instances are allowed, so different sections can show different subsets.
|
||||||
|
|
||||||
## Orientation
|
## Orientation
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
import qs.Ui
|
||||||
|
|
||||||
|
BarIndicator {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property int reminderCount: 0
|
||||||
|
property string tooltip: ""
|
||||||
|
|
||||||
|
active: reminderCount > 0
|
||||||
|
activeText: ""
|
||||||
|
inactiveText: ""
|
||||||
|
activeTooltipText: tooltip
|
||||||
|
inactiveTooltipText: tooltip
|
||||||
|
|
||||||
|
function refresh() {
|
||||||
|
if (!jsonProc.running) jsonProc.running = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function openReminderFlow() {
|
||||||
|
Quickshell.execDetached(["omarchy-reminder", "-i"])
|
||||||
|
}
|
||||||
|
|
||||||
|
function update(raw) {
|
||||||
|
var data = extractData(raw)
|
||||||
|
reminderCount = Number(data.count || 0)
|
||||||
|
tooltip = String(data.tooltip || "")
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: refresh()
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: root.indicatorHost
|
||||||
|
ignoreUnknownSignals: true
|
||||||
|
function onRefreshRequested() { root.refresh() }
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: jsonProc
|
||||||
|
command: ["omarchy-reminder", "show", "--json"]
|
||||||
|
stdout: StdioCollector {
|
||||||
|
waitForEnd: true
|
||||||
|
onStreamFinished: root.update(text)
|
||||||
|
}
|
||||||
|
onExited: function(exitCode) {
|
||||||
|
if (exitCode !== 0) {
|
||||||
|
root.reminderCount = 0
|
||||||
|
root.tooltip = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onPressed: function() {
|
||||||
|
if (root.reminderCount > 0) Quickshell.execDetached(["omarchy-reminder", "show"])
|
||||||
|
else root.openReminderFlow()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,6 +31,11 @@
|
|||||||
"label": "Do not disturb",
|
"label": "Do not disturb",
|
||||||
"description": "Notification silencing"
|
"description": "Notification silencing"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"value": "Reminder",
|
||||||
|
"label": "Reminder",
|
||||||
|
"description": "Queued reminder status"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"value": "NightLight",
|
"value": "NightLight",
|
||||||
"label": "Night light",
|
"label": "Night light",
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ BarWidget {
|
|||||||
moduleName: "omarchy.indicators"
|
moduleName: "omarchy.indicators"
|
||||||
|
|
||||||
readonly property int indicatorSlotExtent: Style.space(22)
|
readonly property int indicatorSlotExtent: Style.space(22)
|
||||||
readonly property var defaultIndicatorEntries: [ "Dnd", "NightLight", "StayAwake", "ScreenRecording", "Dictation" ]
|
readonly property var defaultIndicatorEntries: [ "Dnd", "Reminder", "NightLight", "StayAwake", "ScreenRecording", "Dictation" ]
|
||||||
readonly property int inactiveSlotExtent: indicatorEntries.length * indicatorSlotExtent
|
readonly property int inactiveSlotExtent: indicatorEntries.length * indicatorSlotExtent
|
||||||
readonly property var indicatorEntries: indicatorEntriesFromSettings(settings)
|
readonly property var indicatorEntries: indicatorEntriesFromSettings(settings)
|
||||||
property var activeIndicatorIds: []
|
property var activeIndicatorIds: []
|
||||||
|
|||||||
@@ -116,6 +116,13 @@ Item {
|
|||||||
resultProc.running = true
|
resultProc.running = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function runAction(action) {
|
||||||
|
var command = String(action || "")
|
||||||
|
if (!command) return
|
||||||
|
|
||||||
|
Quickshell.execDetached(["bash", "-lc", command])
|
||||||
|
}
|
||||||
|
|
||||||
function rowHeightForDetail(detail) {
|
function rowHeightForDetail(detail) {
|
||||||
return root.filterText && detail ? root.detailRowHeight : root.baseRowHeight
|
return root.filterText && detail ? root.detailRowHeight : root.baseRowHeight
|
||||||
}
|
}
|
||||||
@@ -733,10 +740,11 @@ Item {
|
|||||||
|
|
||||||
function applySelected(id, action) {
|
function applySelected(id, action) {
|
||||||
if (!id) { cancel(); return }
|
if (!id) { cancel(); return }
|
||||||
|
|
||||||
applySerial = requestSerial
|
applySerial = requestSerial
|
||||||
opened = false
|
opened = false
|
||||||
filterText = ""
|
filterText = ""
|
||||||
if (action) Quickshell.execDetached(["bash", "-lc", action])
|
root.runAction(action)
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancel() {
|
function cancel() {
|
||||||
@@ -815,7 +823,7 @@ Item {
|
|||||||
// instead of opening an action with no children.
|
// instead of opening an action with no children.
|
||||||
if (entry && entry.kind === "action" && entry.action) {
|
if (entry && entry.kind === "action" && entry.action) {
|
||||||
root.cancel()
|
root.cancel()
|
||||||
Quickshell.execDetached(["bash", "-lc", entry.action])
|
root.runAction(entry.action)
|
||||||
return "ok"
|
return "ok"
|
||||||
}
|
}
|
||||||
// If it's a link (a redirect to another menu), follow the link.
|
// If it's a link (a redirect to another menu), follow the link.
|
||||||
|
|||||||
@@ -0,0 +1,168 @@
|
|||||||
|
import Quickshell
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import QtQuick
|
||||||
|
import qs.Commons
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property var shell: null
|
||||||
|
property var manifest: null
|
||||||
|
|
||||||
|
property bool opened: false
|
||||||
|
property string step: "minutes"
|
||||||
|
property string minutes: ""
|
||||||
|
property string filterText: ""
|
||||||
|
property string fontFamily: Style.font.menuFamily
|
||||||
|
|
||||||
|
property color background: Color.menu.background
|
||||||
|
property color foreground: Color.menu.text
|
||||||
|
property color border: Color.menu.border
|
||||||
|
property color scrim: Color.menu.scrim
|
||||||
|
readonly property int cornerRadius: Style.cornerRadius
|
||||||
|
property int contentMargin: Style.spacing.panelPadding
|
||||||
|
property int headerHeight: Math.max(Style.space(34), Style.font.title + Style.spacing.controlPaddingY * 2)
|
||||||
|
property int cardWidth: Math.min(Style.space(300), panel.width - Style.gapsOut * 2)
|
||||||
|
property int cardHeight: Math.min(contentMargin * 2 + headerHeight, panel.height - Style.gapsOut * 2)
|
||||||
|
readonly property string promptText: root.step === "message" ? "Reminder message" : "Remind in minutes"
|
||||||
|
|
||||||
|
function open(payloadJson) {
|
||||||
|
var payload = ({})
|
||||||
|
try { payload = JSON.parse(payloadJson || "{}") } catch (e) { payload = ({}) }
|
||||||
|
if (payload.fontFamily) root.fontFamily = payload.fontFamily
|
||||||
|
|
||||||
|
root.opened = true
|
||||||
|
root.step = "minutes"
|
||||||
|
root.minutes = ""
|
||||||
|
root.filterText = ""
|
||||||
|
|
||||||
|
Qt.callLater(function() { keyCatcher.forceActiveFocus() })
|
||||||
|
}
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
root.opened = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function dismiss() {
|
||||||
|
root.opened = false
|
||||||
|
if (root.shell && typeof root.shell.hide === "function")
|
||||||
|
root.shell.hide((root.manifest && root.manifest.id) || "omarchy.reminders")
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggle() {
|
||||||
|
if (root.opened) root.dismiss()
|
||||||
|
else root.open("{}")
|
||||||
|
}
|
||||||
|
|
||||||
|
function setFilter(nextFilter) {
|
||||||
|
root.filterText = nextFilter
|
||||||
|
}
|
||||||
|
|
||||||
|
function submit() {
|
||||||
|
var selection = root.filterText
|
||||||
|
|
||||||
|
if (root.step === "minutes") {
|
||||||
|
var nextMinutes = selection.trim()
|
||||||
|
|
||||||
|
if (!nextMinutes) {
|
||||||
|
root.dismiss()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!/^[0-9]+$/.test(nextMinutes) || Number(nextMinutes) <= 0) {
|
||||||
|
Quickshell.execDetached(["bash", "-lc", "omarchy-notification-send 'Invalid reminder' 'Enter the number of minutes'"])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
root.minutes = nextMinutes
|
||||||
|
root.step = "message"
|
||||||
|
root.filterText = ""
|
||||||
|
Qt.callLater(function() { keyCatcher.forceActiveFocus() })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (root.step === "message") {
|
||||||
|
var command = "omarchy-reminder " + Util.shellQuote(root.minutes)
|
||||||
|
if (selection.length > 0)
|
||||||
|
command += " " + Util.shellQuote(selection)
|
||||||
|
|
||||||
|
root.dismiss()
|
||||||
|
Quickshell.execDetached(["bash", "-lc", command])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PanelWindow {
|
||||||
|
id: panel
|
||||||
|
visible: root.opened
|
||||||
|
anchors { top: true; bottom: true; left: true; right: true }
|
||||||
|
color: "transparent"
|
||||||
|
WlrLayershell.namespace: "omarchy-reminders"
|
||||||
|
WlrLayershell.layer: WlrLayer.Overlay
|
||||||
|
WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
|
||||||
|
exclusionMode: ExclusionMode.Ignore
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: root.scrim
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: root.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: card
|
||||||
|
width: root.cardWidth
|
||||||
|
height: root.cardHeight
|
||||||
|
radius: root.cornerRadius
|
||||||
|
anchors.centerIn: parent
|
||||||
|
color: root.background
|
||||||
|
border.color: root.border
|
||||||
|
border.width: Math.max(1, Style.space(2))
|
||||||
|
|
||||||
|
MouseArea { anchors.fill: parent; onClicked: {} }
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: keyCatcher
|
||||||
|
anchors.fill: parent
|
||||||
|
focus: true
|
||||||
|
|
||||||
|
Keys.priority: Keys.BeforeItem
|
||||||
|
Keys.onPressed: function(event) {
|
||||||
|
if (event.key === Qt.Key_Escape) {
|
||||||
|
if (root.filterText) root.setFilter("")
|
||||||
|
else root.dismiss()
|
||||||
|
event.accepted = true
|
||||||
|
} else if (event.key === Qt.Key_Backspace) {
|
||||||
|
if (root.filterText.length > 0) root.setFilter(root.filterText.slice(0, -1))
|
||||||
|
event.accepted = true
|
||||||
|
} else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
|
||||||
|
root.submit()
|
||||||
|
event.accepted = true
|
||||||
|
} else if (event.text && event.text.length === 1 && event.text.charCodeAt(0) >= 32 && event.text.charCodeAt(0) !== 127) {
|
||||||
|
root.setFilter(root.filterText + event.text)
|
||||||
|
event.accepted = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: root.contentMargin
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
text: root.filterText || (root.promptText + "...")
|
||||||
|
color: root.foreground
|
||||||
|
opacity: root.filterText ? 1 : 0.58
|
||||||
|
font.family: root.fontFamily
|
||||||
|
font.pixelSize: Style.font.heading
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"id": "omarchy.reminders",
|
||||||
|
"name": "Reminders",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"author": "Omarchy",
|
||||||
|
"description": "Interactive reminder setup flow",
|
||||||
|
"kinds": [
|
||||||
|
"overlay"
|
||||||
|
],
|
||||||
|
"keepLoaded": true,
|
||||||
|
"entryPoints": {
|
||||||
|
"overlay": "ReminderFlow.qml"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user