-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathtodo_rofi.sh
More file actions
executable file
·280 lines (236 loc) · 8.15 KB
/
todo_rofi.sh
File metadata and controls
executable file
·280 lines (236 loc) · 8.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
# this script is sourced by the main todo.sh
theme_main="$todo_dir/todo.rasi"
theme_input="$todo_dir/placeholder.rasi"
theme_input2="$todo_dir/placeholder2.rasi"
theme_choice="$todo_dir/horizontal_menu.rasi"
temp_file=$(mktemp)
trap 'rm -f "$temp_file"' EXIT
rofi_choice() {
local msg="$1"
local opt1="$2"
local opt2="$3"
echo -e "$opt1\n$opt2" | rofi -dmenu -theme "$theme_choice" -mesg "$msg"
}
# Generates a visually aligned list of tasks for Rofi using column + awk
generate_task_list_rofi() {
local show_id="${1:-false}"
local task_count
task_count=$(jq '.tasks | length' "$json_file")
if [[ "$task_count" -eq 0 ]]; then
echo '<tt>No tasks yet!</tt>'
return
fi
local rows_pending=""
local rows_completed=""
local i=1
while IFS=$'\t' read -r status desc; do
local id_str="$i."
local stat_icon="[ ]"
if [[ "$status" -eq 1 ]]; then
stat_icon="[X]"
rows_completed+=$'\n'"C|$id_str|$stat_icon|$desc"
else
rows_pending+=$'\n'"P|$id_str|$stat_icon|$desc"
fi
((i++))
done < <(jq -r '.tasks | sort_by(.priority)[] | "\(.status)\t\(.description)"' "$json_file")
# Construct Raw Table
local raw_data=""
if [[ "$show_id" == "true" ]]; then
raw_data="H|ID|STAT|TASK"
else
raw_data="H|STAT|TASK"
fi
if [[ "$show_id" == "false" ]]; then
# remove ID column from rows
rows_pending=$(echo "$rows_pending" | sed 's/|[^|]*|/|/')
rows_completed=$(echo "$rows_completed" | sed 's/|[^|]*|/|/')
fi
if [ -n "$rows_pending" ]; then raw_data+="$rows_pending"; fi
if [ -n "$rows_completed" ]; then raw_data+="$rows_completed"; fi
echo "$raw_data" | column -t -s '|' | awk -v pc="$pending_color" -v dc="$done_color" '
BEGIN {
}
/^H/ {
sub(/^H /, "");
print "<tt><b>" $0 "</b></tt>"
next
}
/^P/ {
sub(/^P /, "");
print "<span foreground=\"" pc "\"><tt>" $0 "</tt></span>"
}
/^C/ {
sub(/^C /, "");
print "<span foreground=\"" dc "\"><tt>" $0 "</tt></span>"
}
END {
# Added padding at the bottom to prevent text cutoff
print "<tt> </tt>"
}
'
}
# Task selection for toggle/delete actions
select_task_id() {
local action_verb="$1"
local task_count
task_count=$(jq '.tasks | length' "$json_file")
if [[ "$task_count" -eq 0 ]]; then
rofi_choice "No tasks to $action_verb" "Ok" "Back" >/dev/null
echo "0"
return
fi
local header="Enter Task ID to $action_verb"
local task_view
task_view=$(generate_task_list_rofi "true")
local full_msg="${header}"$'\n\n'"${task_view}"
local selection
selection=$(echo -e " Back" | rofi -dmenu -theme "$theme_input2" -mesg "$full_msg")
if [[ "$selection" == " Back" || -z "$selection" ]]; then
echo "0"
elif [[ "$selection" =~ ^[0-9]+$ ]]; then
if [[ "$selection" -ge 1 && "$selection" -le "$task_count" ]]; then
echo "$selection"
else
echo "0"
fi
else
echo "0"
fi
}
add_task_rofi() {
local desc
desc=$(echo -e " Back" | rofi -dmenu -theme "$theme_input" -mesg "Enter new task description:")
if [[ "$desc" == " Back" || -z "$desc" ]]; then return; fi
local prio
prio=$(echo -e " Back" | rofi -dmenu -theme "$theme_input" -mesg "Enter priority (number):")
if [[ "$prio" == " Back" ]]; then return; fi
if ! [[ "$prio" =~ ^[0-9]+$ ]]; then return; fi
read -r conflict_desc < <(jq -r --argjson p "$prio" '.tasks[] | select(.priority == $p) | .description' "$json_file")
local insert_mode="false"
if [[ -n "$conflict_desc" ]]; then
local choice_str
choice_str=$(rofi_choice "Priority $prio exists ('$conflict_desc'). Make '$desc' more prior?" "Yes" "No")
if [[ "$choice_str" == "Yes" ]]; then insert_mode="true"; else insert_mode="false"; fi
else
insert_mode="true"
fi
# Call shared function
json_add_task "$prio" "$desc" "$insert_mode"
}
delete_task() {
local num
num=$(select_task_id "delete")
if [[ "$num" -eq 0 ]]; then return; fi
local idx=$((num - 1))
# Call shared function
json_delete_task "$idx"
}
toggle_status() {
local num
num=$(select_task_id "toggle")
if [[ "$num" -eq 0 ]]; then return; fi
local idx=$((num - 1))
# Call shared function
json_toggle_task "$idx"
}
# --- settings functions ---
delete_all_tasks() {
local choice_str
choice_str=$(rofi_choice "Delete ALL tasks? Cannot be undone." "Yes" "No")
if [[ "$choice_str" == "Yes" ]]; then
jq '.tasks = []' "$json_file" >"$temp_file" && mv "$temp_file" "$json_file"
fi
}
delete_completed_tasks() {
local choice_str
choice_str=$(rofi_choice "Delete all COMPLETED tasks?" "Yes" "No")
if [[ "$choice_str" == "Yes" ]]; then
jq '.tasks |= map(select(.status == 0))' "$json_file" >"$temp_file" && mv "$temp_file" "$json_file"
fi
}
set_auto_delete() {
local time_input
time_input=$(echo -e " Back" | rofi -dmenu -theme "$theme_input" -mesg "Enter daily deletion time (e.g., 14:10 or 2:10pm)\nType 'disable' to disable auto-delete")
if [[ "$time_input" == " Back" || -z "$time_input" ]]; then return; fi
if [[ "$time_input" == "disable" ]]; then
update_config "scheduled_time" "none"
update_config "scheduled_action" "none"
return
fi
local valid_time
valid_time=$(date -d "$time_input" +%H:%M 2>/dev/null)
if [[ -z "$valid_time" ]]; then
rofi -e "Invalid time format."
return
fi
local choice_str
choice_str=$(rofi_choice "What to delete daily at $valid_time?" "Completed" "All")
if [[ "$choice_str" == "Completed" ]]; then
update_config "scheduled_time" "$valid_time"
update_config "scheduled_action" "completed"
elif [[ "$choice_str" == "All" ]]; then
update_config "scheduled_time" "$valid_time"
update_config "scheduled_action" "all"
fi
}
set_middle_click() {
local choice_str
choice_str=$(rofi_choice "Middle-click Action" "Delete Completed" "Delete All")
if [[ "$choice_str" == "Delete Completed" ]]; then update_config "middle_click_action" "completed"; fi
if [[ "$choice_str" == "Delete All" ]]; then update_config "middle_click_action" "all"; fi
}
settings_menu_rofi() {
while true; do
local s_action
s_action=$(get_config "scheduled_action")
local s_time
s_time=$(get_config "scheduled_time")
local m_action
m_action=$(get_config "middle_click_action")
local msg="Settings"
msg+=$'\n\n'
msg+="Auto-Delete: ${s_action} at ${s_time}"
msg+=$'\n'
msg+="Middle-Click: Deletes ${m_action} tasks"
msg+=$'\n\n'
msg+='(1) Delete ALL tasks now'
msg+=$'\n'
msg+='(2) Delete COMPLETED tasks now'
msg+=$'\n'
msg+='(3) Set daily auto-delete time'
msg+=$'\n'
msg+='(4) Configure middle-click action'
local choice
choice=$(echo " Back" | rofi -dmenu -theme "$theme_input2" -mesg "$msg")
case "$choice" in
1) delete_all_tasks ;;
2) delete_completed_tasks ;;
3) set_auto_delete ;;
4) set_middle_click ;;
" Back" | "") break ;;
*) ;;
esac
done
}
# Main app loop
run_rofi_main() {
ensure_json_exists
while true; do
local view_header="Waybar Todo Manager"
local view_tasks
view_tasks=$(generate_task_list_rofi "false")
local full_message="${view_header}"$'\n\n'"${view_tasks}"
local options=" Add Task\n Toggle Status\n Delete Task\n Settings\n Quit"
local selection
selection=$(echo -e "$options" | rofi -dmenu -i -theme "$theme_main" -mesg "$full_message" -markup-rows)
if [[ -z "$selection" ]]; then break; fi
case "$selection" in
*"Add Task") add_task_rofi ;;
*"Toggle Status") toggle_status ;;
*"Delete Task") delete_task ;;
*"Settings") settings_menu_rofi ;;
*"Quit") break ;;
esac
done
}