krz/orgstar

A native macOS editor for org-mode files. editor org-mode swift

Commit ab6ccec56e

ab6ccec56eca03d0dadf2c9332aab10c4490eb62

parent: 469ca131b7

Verified · cmc

cmc <hello@cleberg.net> · 2026-10-09 06:15 UTC

Fix agenda log details and make the iOS and Mac agendas match

- Log mode shows the time clocked again (AgendaRow.detail).
- iOS keeps the last calendar checked instead of saving an empty list.
- iOS weeks start on Monday; day headers name Tomorrow and Yesterday
  and grey past days.
- The Mac remembers whether Overdue is collapsed.
- iOS calendar events open Calendar on their day.
- iOS Next Week moves to next Monday.
- iOS Settings has Show days without entries.
- The Mac editor colors TODO keywords by class.

Layout: unified · split

Sources/OrgEditorAppKit/Theme.swift +1 −1
@@ -89,7 +89,7 @@ struct Theme {
89 if let custom = spec.todo[keyword] { 89 if let custom = spec.todo[keyword] {
90 storage.addAttribute(.foregroundColor, value: Self.dynamic(custom, custom), range: range) 90 storage.addAttribute(.foregroundColor, value: Self.dynamic(custom, custom), range: range)
91 } else { 91 } else {
92 fg(role == .todo ? "todo" : "done") 92 fg(ThemeSpec.TodoClass.of(keyword, isDone: role == .done).key)
93 } 93 }
94 case .priority: fg("priority") 94 case .priority: fg("priority")
95 case .tags: fg("tags") 95 case .tags: fg("tags")
Sources/OrgPresentation/AgendaRows.swift +23
@@ -76,6 +76,8 @@ public struct AgendaRow: Sendable, Equatable, Identifiable {
76 public let priority: String? 76 public let priority: String?
77 /// The statistics cookie: `1/3`, `50%`. 77 /// The statistics cookie: `1/3`, `50%`.
78 public let progress: String? 78 public let progress: String?
79 /// Log mode: the time clocked (`1:30`) or the state set (`DONE`).
80 public let detail: String?
79 /// `HHMM` of the start and the end, when timed. 81 /// `HHMM` of the start and the end, when timed.
80 public let start: Int? 82 public let start: Int?
81 public let end: Int? 83 public let end: Int?
@@ -146,6 +148,7 @@ public struct AgendaRow: Sendable, Equatable, Identifiable {
146 self.isDone = item.isDone 148 self.isDone = item.isDone
147 self.priority = item.priorityLetter 149 self.priority = item.priorityLetter
148 self.progress = item.progress 150 self.progress = item.progress
151 self.detail = item.kind == .clock || item.kind == .state ? Self.logDetail(item.extra) : nil
149 self.start = timed?.0 152 self.start = timed?.0
150 self.end = timed?.1 153 self.end = timed?.1
151 self.planningDay = planning 154 self.planningDay = planning
@@ -184,6 +187,7 @@ public struct AgendaRow: Sendable, Equatable, Identifiable {
184 self.isDone = false 187 self.isDone = false
185 self.priority = nil 188 self.priority = nil
186 self.progress = nil 189 self.progress = nil
190 self.detail = nil
187 self.start = start 191 self.start = start
188 self.end = end 192 self.end = end
189 self.planningDay = nil 193 self.planningDay = nil
@@ -192,8 +196,17 @@ public struct AgendaRow: Sendable, Equatable, Identifiable {
192 } 196 }
193 197
194 static let rangeDay = try! NSRegularExpression(pattern: "^\\(([0-9]+/[0-9]+)\\)") 198 static let rangeDay = try! NSRegularExpression(pattern: "^\\(([0-9]+/[0-9]+)\\)")
199 static let logParen = try! NSRegularExpression(pattern: "\\(([^)]+)\\)")
195 static let rangeEnd = try! NSRegularExpression(pattern: "-\\+?([0-9]{1,2}):([0-9]{2})") 200 static let rangeEnd = try! NSRegularExpression(pattern: "-\\+?([0-9]{1,2}):([0-9]{2})")
196 201
202 /// The text in parentheses of a log row's `extra`: `Clocked: (1:30)`.
203 static func logDetail(_ extra: String) -> String? {
204 let ns = extra as NSString
205 guard let m = logParen.firstMatch(in: extra, range: NSRange(location: 0, length: ns.length)) else { return nil }
206 let text = ns.substring(with: m.range(at: 1)).trimmingCharacters(in: .whitespaces)
207 return text.isEmpty ? nil : text
208 }
209
197 /// The end of a `%t` time range (` 9:00-10:30`), as `HHMM`; past midnight (`+1:00`) adds 24 hours. 210 /// The end of a `%t` time range (` 9:00-10:30`), as `HHMM`; past midnight (`+1:00`) adds 24 hours.
198 static func endTime(_ time: String) -> Int? { 211 static func endTime(_ time: String) -> Int? {
199 let ns = time as NSString 212 let ns = time as NSString
@@ -224,6 +237,16 @@ public struct AgendaDayGroup: Sendable, Equatable, Identifiable {
224 public var id: Int { day } 237 public var id: Int { day }
225 public var isEmpty: Bool { overdue.isEmpty && rows.isEmpty } 238 public var isEmpty: Bool { overdue.isEmpty && rows.isEmpty }
226 239
240 /// `Today`, `Tomorrow`, `Yesterday`, or nil.
241 public func relativeName(today: Int) -> String? {
242 switch day - today {
243 case 0: "Today"
244 case 1: "Tomorrow"
245 case -1: "Yesterday"
246 default: nil
247 }
248 }
249
227 /// Midnight starting the day. 250 /// Midnight starting the day.
228 public func date(calendar: Calendar) -> Date { 251 public func date(calendar: Calendar) -> Date {
229 let d = Days.date(day) 252 let d = Days.date(day)
Sources/Orgstar/AgendaView.swift +3 −12
@@ -64,7 +64,7 @@ struct AgendaView: View {
64 @State private var spanKind: AgendaSpan? 64 @State private var spanKind: AgendaSpan?
65 @State private var showingDatePicker = false 65 @State private var showingDatePicker = false
66 @State private var pickedDate = Date() 66 @State private var pickedDate = Date()
67 @State private var overdueShown = true 67 @AppStorage("agendaOverdueExpanded") private var overdueShown = true
68 @State private var hovered: String? 68 @State private var hovered: String?
69 @FocusState private var focused: Bool 69 @FocusState private var focused: Bool
70 @AppStorage("agendaSpan") private var span = 10 70 @AppStorage("agendaSpan") private var span = 10
@@ -350,7 +350,7 @@ struct AgendaView: View {
350 let past = group.day < agenda.today 350 let past = group.day < agenda.today
351 let color = group.isToday ? todayColor : past ? Color.secondary : theme.color("agenda-date") ?? .primary 351 let color = group.isToday ? todayColor : past ? Color.secondary : theme.color("agenda-date") ?? .primary
352 return header { 352 return header {
353 if let relative = Self.relativeName(group.day, today: agenda.today) { 353 if let relative = group.relativeName(today: agenda.today) {
354 Text(relative) 354 Text(relative)
355 .font(.system(size: 13, weight: .bold)) 355 .font(.system(size: 13, weight: .bold))
356 .foregroundStyle(color) 356 .foregroundStyle(color)
@@ -614,15 +614,6 @@ struct AgendaView: View {
614 return formatter.string(from: date(day)) 614 return formatter.string(from: date(day))
615 } 615 }
616 616
617 static func relativeName(_ day: Int, today: Int) -> String? {
618 switch day - today {
619 case 0: "Today"
620 case 1: "Tomorrow"
621 case -1: "Yesterday"
622 default: nil
623 }
624 }
625
626 static func hhmm(_ date: Date) -> Int { 617 static func hhmm(_ date: Date) -> Int {
627 let c = Calendar.current.dateComponents([.hour, .minute], from: date) 618 let c = Calendar.current.dateComponents([.hour, .minute], from: date)
628 return (c.hour ?? 0) * 100 + (c.minute ?? 0) 619 return (c.hour ?? 0) * 100 + (c.minute ?? 0)
@@ -1170,7 +1161,7 @@ struct AgendaRowView: View {
1170 .foregroundStyle(row.isDone ? AnyShapeStyle(.secondary) : AnyShapeStyle(theme.color("foreground") ?? .primary)) 1161 .foregroundStyle(row.isDone ? AnyShapeStyle(.secondary) : AnyShapeStyle(theme.color("foreground") ?? .primary))
1171 .lineLimit(1) 1162 .lineLimit(1)
1172 .truncationMode(.tail) 1163 .truncationMode(.tail)
1173 if let progress = row.progress { 1164 ForEach([row.progress, row.detail].compactMap { $0 }, id: \.self) { progress in
1174 Text(progress) 1165 Text(progress)
1175 .font(.system(size: 10, weight: .semibold).monospacedDigit()) 1166 .font(.system(size: 10, weight: .semibold).monospacedDigit())
1176 .foregroundStyle(.secondary) 1167 .foregroundStyle(.secondary)
Sources/OrgstarMobile/AgendaScreen.swift +16 −6
@@ -17,6 +17,7 @@ struct AgendaScreen: View {
17 @Environment(ClockModel.self) private var clock 17 @Environment(ClockModel.self) private var clock
18 @Environment(MobileModel.self) private var model 18 @Environment(MobileModel.self) private var model
19 @Environment(\.colorScheme) private var colorScheme 19 @Environment(\.colorScheme) private var colorScheme
20 @Environment(\.openURL) private var openURL
20 @State private var tick = 0 21 @State private var tick = 0
21 /// The time the now line shows, kept to the minute while the agenda is open. 22 /// The time the now line shows, kept to the minute while the agenda is open.
22 @State private var now = Date() 23 @State private var now = Date()
@@ -261,10 +262,11 @@ struct AgendaScreen: View {
261 262
262 private func header(_ group: AgendaDayGroup) -> some View { 263 private func header(_ group: AgendaDayGroup) -> some View {
263 let day = date(group.day).formatted(.dateTime.weekday(.abbreviated).day().month(.abbreviated)) 264 let day = date(group.day).formatted(.dateTime.weekday(.abbreviated).day().month(.abbreviated))
265 let color = group.isToday ? todayColor : group.day < agenda.today ? Color.secondary : themed(theme.color("agenda-date", dark: isDark), .primary)
264 return HStack(alignment: .firstTextBaseline) { 266 return HStack(alignment: .firstTextBaseline) {
265 Text(group.isToday ? "Today · " + day : day) 267 Text(group.relativeName(today: agenda.today).map { $0 + " · " + day } ?? day)
266 .font(.subheadline.weight(group.isToday ? .bold : .semibold)) 268 .font(.subheadline.weight(group.isToday ? .bold : .semibold))
267 .foregroundStyle(group.isToday ? todayColor : .primary) 269 .foregroundStyle(color)
268 Spacer() 270 Spacer()
269 Button("Add to \(day)", systemImage: "plus.circle") { model.captureRequest = CaptureRequest(day: group.day) } 271 Button("Add to \(day)", systemImage: "plus.circle") { model.captureRequest = CaptureRequest(day: group.day) }
270 .labelStyle(.iconOnly) 272 .labelStyle(.iconOnly)
@@ -305,7 +307,7 @@ struct AgendaScreen: View {
305 } 307 }
306 308
307 private func weekStart(_ day: Int) -> Int { 309 private func weekStart(_ day: Int) -> Int {
308 day - (Days.weekday(day) - (Calendar.current.firstWeekday - 1) + 7) % 7 310 day - (Days.weekday(day) + 6) % 7
309 } 311 }
310 312
311 /// Shows `range` around `day`; nil returns to the configured span. 313 /// Shows `range` around `day`; nil returns to the configured span.
@@ -403,6 +405,14 @@ struct AgendaScreen: View {
403 Group { 405 Group {
404 if let item = row.item, let path = item.path, let offset = item.headingOffset ?? item.markerOffset { 406 if let item = row.item, let path = item.path, let offset = item.headingOffset ?? item.markerOffset {
405 NavigationLink(value: ReaderRoute.offset(path, offset)) { AgendaRowView(row: row, day: day, theme: theme, dark: isDark) } 407 NavigationLink(value: ReaderRoute.offset(path, offset)) { AgendaRowView(row: row, day: day, theme: theme, dark: isDark) }
408 } else if let event = row.event {
409 // Calendar can't be asked for one event by URL; it opens on the event's day.
410 Button {
411 if let url = URL(string: "calshow:\(event.start.timeIntervalSinceReferenceDate)") { openURL(url) }
412 } label: {
413 AgendaRowView(row: row, day: day, theme: theme, dark: isDark)
414 }
415 .tint(.primary)
406 } else { 416 } else {
407 AgendaRowView(row: row, day: day, theme: theme, dark: isDark) 417 AgendaRowView(row: row, day: day, theme: theme, dark: isDark)
408 } 418 }
@@ -416,7 +426,7 @@ struct AgendaScreen: View {
416 .swipeActions(edge: .leading) { 426 .swipeActions(edge: .leading) {
417 if canReschedule(row), let item = row.item { 427 if canReschedule(row), let item = row.item {
418 Button("Tomorrow", systemImage: "sunrise") { reschedule(row, item, to: agenda.today + 1) }.tint(.orange) 428 Button("Tomorrow", systemImage: "sunrise") { reschedule(row, item, to: agenda.today + 1) }.tint(.orange)
419 Button("Next Week", systemImage: "calendar.badge.plus") { reschedule(row, item, to: agenda.today + 7) }.tint(.indigo) 429 Button("Next Week", systemImage: "calendar.badge.plus") { reschedule(row, item, to: weekStart(agenda.today) + 7) }.tint(.indigo)
420 Button("Pick Date", systemImage: "calendar") { rescheduling = row }.tint(.gray) 430 Button("Pick Date", systemImage: "calendar") { rescheduling = row }.tint(.gray)
421 } 431 }
422 } 432 }
@@ -426,7 +436,7 @@ struct AgendaScreen: View {
426 if canReschedule(row) { 436 if canReschedule(row) {
427 Menu("Reschedule", systemImage: "calendar.badge.clock") { 437 Menu("Reschedule", systemImage: "calendar.badge.clock") {
428 Button("Tomorrow") { reschedule(row, item, to: agenda.today + 1) } 438 Button("Tomorrow") { reschedule(row, item, to: agenda.today + 1) }
429 Button("Next Week") { reschedule(row, item, to: agenda.today + 7) } 439 Button("Next Week") { reschedule(row, item, to: weekStart(agenda.today) + 7) }
430 Button("Pick Date…") { rescheduling = row } 440 Button("Pick Date…") { rescheduling = row }
431 } 441 }
432 } 442 }
@@ -572,7 +582,7 @@ struct AgendaRowView: View {
572 Circle().fill(categoryColor).frame(width: 7, height: 7) 582 Circle().fill(categoryColor).frame(width: 7, height: 7)
573 Text(row.category).lineLimit(1).layoutPriority(1) 583 Text(row.category).lineLimit(1).layoutPriority(1)
574 } 584 }
575 if let progress = row.progress { 585 ForEach([row.progress, row.detail].compactMap { $0 }, id: \.self) { progress in
576 Text(progress).monospacedDigit() 586 Text(progress).monospacedDigit()
577 .padding(.horizontal, 5) 587 .padding(.horizontal, 5)
578 .background(.quaternary.opacity(0.7), in: Capsule()) 588 .background(.quaternary.opacity(0.7), in: Capsule())
Sources/OrgstarMobile/SettingsScreen.swift +11 −2
@@ -32,6 +32,12 @@ struct SettingsScreen: View {
32 } footer: { 32 } footer: {
33 Text("A folder with config.toml and capture.toml, such as a synced copy of ~/.config/orgstar from your Mac. Changes to them apply as they sync.") 33 Text("A folder with config.toml and capture.toml, such as a synced copy of ~/.config/orgstar from your Mac. Changes to them apply as they sync.")
34 } 34 }
35 Section("Agenda") {
36 let _ = model.settingsVersion
37 Toggle("Show days without entries", isOn: Binding {
38 OrgPreferences.agendaShowAllDates()
39 } set: { model.set("agendaShowAllDates", to: .bool($0)) })
40 }
35 calendarSection 41 calendarSection
36 Section("In use") { 42 Section("In use") {
37 let _ = model.settingsVersion 43 let _ = model.settingsVersion
@@ -101,9 +107,12 @@ struct SettingsScreen: View {
101 } 107 }
102 108
103 /// Shows or hides a calendar's events; with every calendar checked the setting is empty. 109 /// Shows or hides a calendar's events; with every calendar checked the setting is empty.
110 /// The last checked calendar stays checked, as an empty list means every calendar.
104 private func toggle(_ title: String, shown: Bool, chosen: [String]) { 111 private func toggle(_ title: String, shown: Bool, chosen: [String]) {
105 var titles = chosen.isEmpty ? calendars.map(\.title) : chosen 112 var titles = calendars.filter { CalendarEvents.chooses(id: $0.id, title: $0.title, chosen: chosen) }.map(\.title)
106 if shown { titles.removeAll { $0 == title } } else { titles.append(title) } 113 titles.removeAll { $0 == title }
114 if !shown { titles.append(title) }
115 guard !titles.isEmpty else { return }
107 let value = Set(titles) == Set(calendars.map(\.title)) ? "" : titles.joined(separator: ", ") 116 let value = Set(titles) == Set(calendars.map(\.title)) ? "" : titles.joined(separator: ", ")
108 model.set("calendarEventCalendars", to: .string(value)) 117 model.set("calendarEventCalendars", to: .string(value))
109 } 118 }
Tests/OrgPresentationTests/AgendaRowsTests.swift +20
@@ -86,6 +86,26 @@ struct AgendaRowsTests {
86 #expect(!rent.isEvent && rent.item != nil) 86 #expect(!rent.isEvent && rent.item != nil)
87 } 87 }
88 88
89 @Test func logRowsKeepTheDurationAndState() {
90 let text = """
91 * DONE Write report
92 CLOSED: [2026-10-05 Mon 11:00]
93 :LOGBOOK:
94 - State "DONE" from "TODO" [2026-10-05 Mon 11:00]
95 CLOCK: [2026-10-05 Mon 09:00]--[2026-10-05 Mon 10:30] => 1:30
96 :END:
97 """
98 var options = AgendaOptions()
99 options.logMode = true
100 options.logItems = ["closed", "clock", "state"]
101 let source = AgendaSource(path: "w.org", text: text, defaults: OrgSettings.default.withTodoKeywords("TODO | DONE")!)
102 let items = Agenda.list([source], start: Self.today, days: 1, today: Self.today, now: (12, 0), options: options)[0].items
103 let rows = items.compactMap { AgendaRow(item: $0, day: Self.today, today: Self.today) }
104 #expect(rows.first { $0.item?.kind == .clock }?.detail == "1:30")
105 #expect(rows.first { $0.item?.kind == .state }?.detail == "DONE")
106 #expect(rows.first { $0.item?.kind == .closed }?.detail == nil)
107 }
108
89 @Test func guttersOnOtherDays() { 109 @Test func guttersOnOtherDays() {
90 let later = Self.rows(day: Self.today + 4) 110 let later = Self.rows(day: Self.today + 4)
91 #expect(later["Renew passport"]?.gutter == "Due" && later["Renew passport"]?.status == .normal) 111 #expect(later["Renew passport"]?.gutter == "Due" && later["Renew passport"]?.status == .normal)
docs/manual/guide/07-agenda.org +7 −7
@@ -106,13 +106,13 @@ A time can come from the timestamp (=<2026-10-05 Mon 14:00-15:30>=) or from the
106 106
107** Today, overdue entries and empty days 107** Today, overdue entries and empty days
108 108
109Days without entries are left out. Today always shows, with =Nothing scheduled= when it has no entries. To show every day of the span, as Org does by default, turn on Settings ▸ Agenda ▸ Show days without entries, or set this in =config.toml=: 109Days without entries are left out. Today always shows, with =Nothing scheduled= when it has no entries. To show every day of the span, as Org does by default, turn on Settings ▸ Agenda ▸ Show days without entries (on iOS, Settings ▸ Agenda), or set this in =config.toml=:
110 110
111#+BEGIN_SRC toml 111#+BEGIN_SRC toml
112org-agenda-show-all-dates = true 112org-agenda-show-all-dates = true
113#+END_SRC 113#+END_SRC
114 114
115Today's past deadlines and entries scheduled on earlier days, habits excepted, go in a group headed =Overdue= with their count, above today's other entries. The oldest date comes first; entries with the same date keep Org's order. Click or tap the header to collapse or expand the group. 115Today's past deadlines and entries scheduled on earlier days, habits excepted, go in a group headed =Overdue= with their count, above today's other entries. The oldest date comes first; entries with the same date keep Org's order. Click or tap the header to collapse or expand the group; it stays as you left it.
116 116
117On today, a line marked with the current time sits between the timed entries: before the first entry that starts later, or after the last one when all have started. It shows only when today has timed entries, as Org's =now= line does. Org's time grid (the lines at 8:00, 10:00 and so on) isn't shown. 117On today, a line marked with the current time sits between the timed entries: before the first entry that starts later, or after the last one when all have started. It shows only when today has timed entries, as Org's =now= line does. Org's time grid (the lines at 8:00, 10:00 and so on) isn't shown.
118 118
@@ -125,7 +125,7 @@ Days are sorted as =org-agenda-sorting-strategy= sorts them by default for the a
125Press =l= to turn log mode (=org-agenda-log-mode=) on or off. Each day then also shows: 125Press =l= to turn log mode (=org-agenda-log-mode=) on or off. Each day then also shows:
126 126
127- =Closed= entries whose =CLOSED:= timestamp is on that day; 127- =Closed= entries whose =CLOSED:= timestamp is on that day;
128- =Clocked= entries for each =CLOCK:= line that starts on that day, with the clock's start and end times in the left column. 128- =Clocked= entries for each =CLOCK:= line that starts on that day, with the clock's start and end times in the left column and the time clocked, such as =1:30=, after the title.
129 129
130A note under a clock line (a list item directly below it) is added to the title after a =-=. These are the default =org-agenda-log-mode-items=, =(closed clock)=; state changes are not shown and there is no setting for that. 130A note under a clock line (a list item directly below it) is added to the title after a =-=. These are the default =org-agenda-log-mode-items=, =(closed clock)=; state changes are not shown and there is no setting for that.
131 131
@@ -530,14 +530,14 @@ The board is not available on iOS.
530The Agenda tab shows the same views from the same files, using the settings in the synced =config.toml= and the views in =views.toml= (see [[file:14-ios.org][iOS]]). Differences from the Mac: 530The Agenda tab shows the same views from the same files, using the settings in the synced =config.toml= and the views in =views.toml= (see [[file:14-ios.org][iOS]]). Differences from the Mac:
531 531
532- The Views menu, at the top left, lists the built-in views, your saved views, and Tags and Properties…, which asks for a match string. There is no TODO-only match from the menu; use =/!= in the match or a =todo-match= view. 532- The Views menu, at the top left, lists the built-in views, your saved views, and Tags and Properties…, which asks for a match string. There is no TODO-only match from the menu; use =/!= in the match or a =todo-match= view.
533- A bar floats at the bottom of the screen with Earlier, Filter, Today, Go to Date, the span and Later. The span menu switches between Day, Week, Month and the configured span (=10 Days= by default). Weeks start on the first day of the week in the device's region settings. In the TODO list and match views the bar has Filter and Agenda, which returns to the day view. Messages show above the bar; tap one to dismiss it. 533- A bar floats at the bottom of the screen with Earlier, Filter, Today, Go to Date, the span and Later. The span menu switches between Day, Week, Month and the configured span (=10 Days= by default). Weeks start on Monday, as on the Mac. In the TODO list and match views the bar has Filter and Agenda, which returns to the day view. Messages show above the bar; tap one to dismiss it.
534- The title names the days shown: =Thu 8 Oct=, =Week of 5 Oct=, =October 2026=, or =5 Oct – 14 Oct=. 534- The title names the days shown: =Thu 8 Oct=, =Week of 5 Oct=, =October 2026=, or =5 Oct – 14 Oct=.
535- Day headers read =Today · Thu 8 Oct= or =Fri 9 Oct=, with a + that captures onto that day. The Overdue group stays collapsed or expanded as you left it. 535- Day headers read =Today · Thu 8 Oct=, =Tomorrow · Fri 9 Oct= or =Mon 12 Oct=, with a + that captures onto that day. Days before today are grey.
536- Pull down to refresh. 536- Pull down to refresh.
537- The Filter button opens a sheet: type a filter as for =/=, or tap a tag or category to cycle between Keep, Leave out and no filter. 537- The Filter button opens a sheet: type a filter as for =/=, or tap a tag or category to cycle between Keep, Leave out and no filter.
538- Tap an entry to open it. Calendar events don't open. 538- Tap an entry to open it. Tap a calendar event to open Calendar on the event's day; iOS can't open Calendar at one event.
539- Swipe left on an open TODO entry for Done, which sets the first done keyword of its sequence, and Next State, which moves to the next keyword. The sequence is the one the file defines: the default keywords from =config.toml=, the file's own =#+TODO= lines, and those of its setup files, with unsaved edits in an open buffer included. 539- Swipe left on an open TODO entry for Done, which sets the first done keyword of its sequence, and Next State, which moves to the next keyword. The sequence is the one the file defines: the default keywords from =config.toml=, the file's own =#+TODO= lines, and those of its setup files, with unsaved edits in an open buffer included.
540- Swipe right on a scheduled entry, a deadline, a habit or a TODO entry, when it isn't done, for Tomorrow, Next Week and Pick Date. Tomorrow and Next Week are one day and seven days after today. On a deadline row these move the deadline; on other rows they set the scheduled date. A timed row keeps its times. 540- Swipe right on a scheduled entry, a deadline, a habit or a TODO entry, when it isn't done, for Tomorrow, Next Week and Pick Date. Tomorrow is the day after today and Next Week is next Monday. On a deadline row these move the deadline; on other rows they set the scheduled date. A timed row keeps its times.
541- Touch and hold an entry for TODO State…, Reschedule (Tomorrow, Next Week, Pick Date…), Schedule…, Deadline…, Tags…, Priority…, Clock In, Refile… and Archive…. 541- Touch and hold an entry for TODO State…, Reschedule (Tomorrow, Next Week, Pick Date…), Schedule…, Deadline…, Tags…, Priority…, Clock In, Refile… and Archive….
542- Marking an entry done and rescheduling one give haptic feedback. 542- Marking an entry done and rescheduling one give haptic feedback.
543- There are no keyboard commands, log mode or bulk marks. 543- There are no keyboard commands, log mode or bulk marks.
docs/manual/guide/13-configuration.org +1 −1
@@ -493,7 +493,7 @@ A keyword without its own color takes its class's color. Case doesn't matter in
493| Other open | =todo= | Any other keyword that isn't done | 493| Other open | =todo= | Any other keyword that isn't done |
494| Other done | =done= | Any other done keyword | 494| Other done | =done= | Any other done keyword |
495 495
496The classes color keywords in the agenda and its widgets on both platforms, and in the iOS editor and reader. The Mac editor colors keywords with =todo= and =done= only. 496The classes color keywords in the editors, the iOS reader, the agenda and its widgets.
497 497
498A category without its own color gets a hue worked out from its name, the same on every run and device, at a lightness that reads on the appearance's background. 498A category without its own color gets a hue worked out from its name, the same on every run and device, at a lightness that reads on the appearance's background.
499 499
docs/manual/guide/14-ios.org +3 −2
@@ -160,7 +160,7 @@ The Agenda tab shows the agenda over all your folders, with the span and start d
160- + on a day's header :: captures an entry scheduled on that day (see [[file:08-capture.org][Capture]]). 160- + on a day's header :: captures an entry scheduled on that day (see [[file:08-capture.org][Capture]]).
161- Tap :: an entry to read it, at its heading. 161- Tap :: an entry to read it, at its heading.
162- Swipe left :: on a TODO entry for Done, which sets the first done keyword of its sequence, or Next State. 162- Swipe left :: on a TODO entry for Done, which sets the first done keyword of its sequence, or Next State.
163- Swipe right :: for Tomorrow, Next Week or Pick Date, which move the entry's scheduled date, or its deadline on a deadline row. 163- Swipe right :: for Tomorrow, Next Week (next Monday) or Pick Date, which move the entry's scheduled date, or its deadline on a deadline row.
164- Touch and hold :: an entry for TODO State…, Reschedule, Schedule…, Deadline…, Tags…, Priority…, Clock In, Refile…, and Archive…. 164- Touch and hold :: an entry for TODO State…, Reschedule, Schedule…, Deadline…, Tags…, Priority…, Clock In, Refile…, and Archive….
165 165
166Commands from the agenda change the file directly when it isn't open, and through the editor when it is. If the heading changed since the agenda was built, nothing runs. 166Commands from the agenda change the file directly when it isn't open, and through the editor when it is. If the heading changed since the agenda was built, nothing runs.
@@ -311,8 +311,9 @@ Changes to the files apply as they sync, and again each time you return to the a
311 311
312Stop Using This Folder returns every setting to its default. 312Stop Using This Folder returns every setting to its default.
313 313
314The Calendar section is the one place the app changes a setting itself: 314The Agenda and Calendar sections are the only places the app changes a setting itself:
315 315
316- Show days without entries :: turns =org-agenda-show-all-dates= on or off.
316- Show Calendar Events :: turns on =calendar-events=, and asks for access to your calendars. iOS asks for full access, as Calendar has no read-only level; Orgstar only reads. While access is missing the section shows Allow Access to Calendars…; if you declined, allow it in the Settings app under Privacy & Security ▸ Calendars. 317- Show Calendar Events :: turns on =calendar-events=, and asks for access to your calendars. iOS asks for full access, as Calendar has no read-only level; Orgstar only reads. While access is missing the section shows Allow Access to Calendars…; if you declined, allow it in the Settings app under Privacy & Security ▸ Calendars.
317- The calendars :: tap one to show or hide its events (=calendar-event-calendars=). With every calendar checked the setting is empty, so calendars added later show too. 318- The calendars :: tap one to show or hide its events (=calendar-event-calendars=). With every calendar checked the setting is empty, so calendars added later show too.
318 319