| @@ -261,59 +261,115 @@ struct SettingsView: View { |
| 261 | @AppStorage("reminders") private var reminders = true |
261 | @AppStorage("reminders") private var reminders = true |
| 262 | @AppStorage("reminderLead") private var reminderLead = 12 |
262 | @AppStorage("reminderLead") private var reminderLead = 12 |
| 263 | @AppStorage("globalCapture") private var globalCapture = true |
263 | @AppStorage("globalCapture") private var globalCapture = true |
| |
264 | @AppStorage("settingsTab") private var tab = "general" |
| 264 | |
265 | |
| 265 | var body: some View { |
266 | var body: some View { |
| |
267 | TabView(selection: $tab) { |
| |
268 | Tab("General", systemImage: "gearshape", value: "general") { general } |
| |
269 | Tab("Editing", systemImage: "text.alignleft", value: "editing") { editing } |
| |
270 | Tab("Agenda", systemImage: "calendar", value: "agenda") { agenda } |
| |
271 | Tab("Capture", systemImage: "tray.and.arrow.down", value: "capture") { capture } |
| |
272 | } |
| |
273 | .frame(width: 600) |
| |
274 | } |
| |
275 | |
| |
276 | private var general: some View { |
| 266 | Form { |
277 | Form { |
| 267 | Picker("Save files:", selection: $saveMode) { |
278 | Section { |
| 268 | Text("Automatically, when typing stops").tag(SaveMode.automatic) |
279 | Picker("Save files", selection: $saveMode) { |
| 269 | Text("Only with File ▸ Save (⌘S)").tag(SaveMode.explicit) |
280 | Text("Automatically, when typing stops").tag(SaveMode.automatic) |
| |
281 | Text("Only with File ▸ Save (⌘S)").tag(SaveMode.explicit) |
| |
282 | } |
| |
283 | .pickerStyle(.radioGroup) |
| |
284 | } |
| |
285 | Section { |
| |
286 | Picker("Keys", selection: $preset) { |
| |
287 | ForEach(KeymapPreset.allCases, id: \.self) { Text($0.title).tag($0) } |
| |
288 | } |
| |
289 | Picker("Option as Meta", selection: $optionAsMeta) { |
| |
290 | Text("Left Option").tag(OptionAsMeta.left.rawValue) |
| |
291 | Text("Right Option").tag(OptionAsMeta.right.rawValue) |
| |
292 | Text("Both").tag(OptionAsMeta([.left, .right]).rawValue) |
| |
293 | Text("Neither").tag(0) |
| |
294 | } |
| |
295 | } footer: { |
| |
296 | Text("Your own bindings go in \(KeymapLoader.userFile.path), on top of the preset.") |
| |
297 | .settingsFooter() |
| |
298 | } |
| |
299 | } |
| |
300 | .formStyle(.grouped) |
| |
301 | .frame(height: 250) |
| |
302 | } |
| |
303 | |
| |
304 | private var editing: some View { |
| |
305 | Form { |
| |
306 | Section { |
| |
307 | Picker("Tags", selection: $tagsColumn) { |
| |
308 | Text("Aligned to end at column 77").tag(-77) |
| |
309 | Text("One space after the title").tag(0) |
| |
310 | } |
| |
311 | Toggle("M-RET adds the new heading after the subtree", isOn: $headingAfterSubtree) |
| |
312 | Toggle("M-RET splits the line at the caret", isOn: $splitLine) |
| |
313 | Toggle("Lists can use letters (a. b. c.)", isOn: $alphabeticalLists) |
| |
314 | Stepper("M-q fills to column \(fillColumn)", value: $fillColumn, in: 40...200) |
| 270 | } |
315 | } |
| 271 | .pickerStyle(.radioGroup) |
316 | Section { |
| 272 | Picker("Keys:", selection: $preset) { |
317 | Toggle("Emacs hides emphasis markers (org-hide-emphasis-markers)", isOn: $hiddenMarkers) |
| 273 | ForEach(KeymapPreset.allCases, id: \.self) { Text($0.title).tag($0) } |
318 | Toggle("Emacs shows entities as characters (org-pretty-entities)", isOn: $prettyEntities) |
| |
319 | } footer: { |
| |
320 | Text("Tags, tables and M-q measure text as your Emacs displays it, so both write the same file.") |
| |
321 | .settingsFooter() |
| 274 | } |
322 | } |
| 275 | Picker("Option as Meta:", selection: $optionAsMeta) { |
323 | Section { |
| 276 | Text("Left Option").tag(OptionAsMeta.left.rawValue) |
324 | TextField("Default TODO keywords", text: $todoKeywords) |
| 277 | Text("Right Option").tag(OptionAsMeta.right.rawValue) |
325 | } footer: { |
| 278 | Text("Both").tag(OptionAsMeta([.left, .right]).rawValue) |
326 | Text("For files without #+TODO, in #+TODO syntax. Takes effect when Orgstar restarts.") |
| 279 | Text("Neither").tag(0) |
327 | .settingsFooter() |
| 280 | } |
328 | } |
| 281 | Text("Your own bindings go in \(KeymapLoader.userFile.path), on top of the preset.") |
329 | } |
| 282 | .font(.caption) |
330 | .formStyle(.grouped) |
| 283 | .foregroundStyle(.secondary) |
331 | .frame(height: 450) |
| 284 | .textSelection(.enabled) |
332 | } |
| 285 | Divider() |
333 | |
| 286 | Picker("Tags:", selection: $tagsColumn) { |
334 | private var agenda: some View { |
| 287 | Text("Aligned to end at column 77").tag(-77) |
335 | Form { |
| 288 | Text("One space after the title").tag(0) |
336 | Section { |
| |
337 | Stepper("Agenda shows \(agendaSpan) days", value: $agendaSpan, in: 1...31) |
| |
338 | Stepper(agendaStartOffset == 0 ? "Agenda starts today" : "Agenda starts \(-agendaStartOffset) days before today", value: $agendaStartOffset, in: -14...0) |
| |
339 | Toggle("Include files in subfolders", isOn: $agendaSubfolders) |
| |
340 | } |
| |
341 | Section { |
| |
342 | Toggle("Notify before timed agenda entries", isOn: $reminders) |
| |
343 | Stepper("\(reminderLead) minutes before", value: $reminderLead, in: 0...120) |
| |
344 | .disabled(!reminders) |
| |
345 | } footer: { |
| |
346 | Text("An entry's APPT_WARNTIME property overrides the lead time.") |
| |
347 | .settingsFooter() |
| 289 | } |
348 | } |
| 290 | Toggle("M-RET adds the new heading after the subtree", isOn: $headingAfterSubtree) |
| |
| 291 | Toggle("M-RET splits the line at the caret", isOn: $splitLine) |
| |
| 292 | Toggle("Lists can use letters (a. b. c.)", isOn: $alphabeticalLists) |
| |
| 293 | Stepper("M-q fills to column \(fillColumn)", value: $fillColumn, in: 40...200) |
| |
| 294 | Toggle("Emacs hides emphasis markers (org-hide-emphasis-markers)", isOn: $hiddenMarkers) |
| |
| 295 | Toggle("Emacs shows entities as characters (org-pretty-entities)", isOn: $prettyEntities) |
| |
| 296 | Text("Tags, tables and M-q measure text as your Emacs displays it, so both write the same file.") |
| |
| 297 | .font(.caption) |
| |
| 298 | .foregroundStyle(.secondary) |
| |
| 299 | TextField("Default TODO keywords:", text: $todoKeywords) |
| |
| 300 | Text("For files without #+TODO, in #+TODO syntax. Takes effect when Orgstar restarts.") |
| |
| 301 | .font(.caption) |
| |
| 302 | .foregroundStyle(.secondary) |
| |
| 303 | Divider() |
| |
| 304 | Stepper("Agenda shows \(agendaSpan) days", value: $agendaSpan, in: 1...31) |
| |
| 305 | Stepper(agendaStartOffset == 0 ? "Agenda starts today" : "Agenda starts \(-agendaStartOffset) days before today", value: $agendaStartOffset, in: -14...0) |
| |
| 306 | Toggle("Agenda includes files in subfolders", isOn: $agendaSubfolders) |
| |
| 307 | Toggle("Notify before timed agenda entries", isOn: $reminders) |
| |
| 308 | Stepper("\(reminderLead) minutes before (APPT_WARNTIME overrides)", value: $reminderLead, in: 0...120) |
| |
| 309 | .disabled(!reminders) |
| |
| 310 | Toggle("⌃⌥Space opens Capture from any app", isOn: $globalCapture) |
| |
| 311 | Text("Templates go in \(CaptureTemplates.userFile.path).") |
| |
| 312 | .font(.caption) |
| |
| 313 | .foregroundStyle(.secondary) |
| |
| 314 | .textSelection(.enabled) |
| |
| 315 | } |
349 | } |
| 316 | .padding(20) |
350 | .formStyle(.grouped) |
| 317 | .frame(width: 480) |
351 | .frame(height: 290) |
| |
352 | } |
| |
353 | |
| |
354 | private var capture: some View { |
| |
355 | Form { |
| |
356 | Section { |
| |
357 | Toggle("⌃⌥Space opens Capture from any app", isOn: $globalCapture) |
| |
358 | } footer: { |
| |
359 | Text("Templates go in \(CaptureTemplates.userFile.path).") |
| |
360 | .settingsFooter() |
| |
361 | } |
| |
362 | } |
| |
363 | .formStyle(.grouped) |
| |
364 | .frame(height: 160) |
| |
365 | } |
| |
366 | } |
| |
367 | |
| |
368 | private extension Text { |
| |
369 | func settingsFooter() -> some View { |
| |
370 | font(.caption) |
| |
371 | .foregroundStyle(.secondary) |
| |
372 | .textSelection(.enabled) |
| |
373 | .frame(maxWidth: .infinity, alignment: .leading) |
| 318 | } |
374 | } |
| 319 | } |
375 | } |