iOS drawer: flat reorderable calendars, long-press menu, left-swipe close, header actions
Testing feedback: - calendars are now one flat, drag-reorderable list (no per-source grouping); order is device-local (CalendarStore.calendarOrder, mirrors the web cal_order). Reordering is done via a 'Sort' toggle (native edit mode with drag handles). - banish + reminder-mute moved from row swipe actions to a long-press context menu, which frees the horizontal swipe: swiping the drawer left closes it. - the hamburger moved to the LEFT (drawer opens left); new device-local setting 'Hide menu button' (open via edge-swipe only), not synced. - the settings entry moved from the footer into the header as an icon, next to a restored manual-sync icon and the close button; the footer button is gone. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -165,6 +165,49 @@ class CalendarStore {
|
||||
return "\(source):\(id)"
|
||||
}
|
||||
|
||||
// MARK: – Calendar order (device-local, mirrors the web `cal_order`)
|
||||
|
||||
private static let orderDefaultsKey = "calendarOrder"
|
||||
|
||||
/// Persisted display order of calendar keys ("source:id"). Device-local; the
|
||||
/// drawer's flat calendar list is sorted by this.
|
||||
private(set) var calendarOrder: [String] = CalendarStore.loadOrder()
|
||||
|
||||
private static func loadOrder() -> [String] {
|
||||
guard let raw = UserDefaults.standard.string(forKey: orderDefaultsKey),
|
||||
let data = raw.data(using: .utf8),
|
||||
let arr = try? JSONDecoder().decode([String].self, from: data)
|
||||
else { return [] }
|
||||
return arr
|
||||
}
|
||||
|
||||
private func saveOrder() {
|
||||
if let data = try? JSONEncoder().encode(calendarOrder),
|
||||
let s = String(data: data, encoding: .utf8) {
|
||||
UserDefaults.standard.set(s, forKey: Self.orderDefaultsKey)
|
||||
}
|
||||
}
|
||||
|
||||
/// Replace the stored order (after a drag-reorder).
|
||||
func setCalendarOrder(_ keys: [String]) {
|
||||
calendarOrder = keys
|
||||
saveOrder()
|
||||
}
|
||||
|
||||
/// Sort the given keys by the stored order (unknown keys → end), then persist
|
||||
/// the normalized order so newly-added calendars stick (mirrors the web).
|
||||
func ordered(_ keys: [String]) -> [String] {
|
||||
let current = calendarOrder
|
||||
func idx(_ key: String) -> Int { current.firstIndex(of: key) ?? Int.max }
|
||||
let sorted = keys.sorted { a, b in
|
||||
let ia = idx(a), ib = idx(b)
|
||||
return ia != ib ? ia < ib : a < b
|
||||
}
|
||||
calendarOrder = sorted
|
||||
saveOrder()
|
||||
return sorted
|
||||
}
|
||||
|
||||
// MARK: – Banished-calendar persistence
|
||||
|
||||
private static let banishedKeysDefaultsKey = "banishedCalendarKeys"
|
||||
|
||||
@@ -89,6 +89,7 @@ private let strings: [String: [String: String]] = [
|
||||
"settings.color.surface": "Topbar-/Oberflächenfarbe",
|
||||
"settings.surface.auto": "Auto (Milchglas)",
|
||||
"settings.device": "Nur auf diesem Gerät",
|
||||
"settings.hide_menu_button": "Menü-Button ausblenden",
|
||||
"settings.device.footer": "Diese Einstellungen gelten nur auf diesem Gerät und werden nicht synchronisiert.",
|
||||
|
||||
"settings.cache.header": "Vorladen",
|
||||
@@ -331,6 +332,8 @@ private let strings: [String: [String: String]] = [
|
||||
"filter.empty": "Keine Kalender vorhanden",
|
||||
"filter.show_all": "Alle anzeigen",
|
||||
"filter.hide_all": "Alle ausblenden",
|
||||
"filter.sort": "Sortieren",
|
||||
"filter.done": "Fertig",
|
||||
"filter.button": "Kalender ein-/ausblenden",
|
||||
"filter.banish": "Dauerhaft ausblenden",
|
||||
"filter.reminders_on": "Benachrichtigungen an",
|
||||
@@ -460,6 +463,7 @@ private let strings: [String: [String: String]] = [
|
||||
"settings.color.surface": "Top bar / surface color",
|
||||
"settings.surface.auto": "Auto (translucent)",
|
||||
"settings.device": "This device only",
|
||||
"settings.hide_menu_button": "Hide menu button",
|
||||
"settings.device.footer": "These settings apply to this device only and are not synced.",
|
||||
|
||||
"settings.cache.header": "Preloading",
|
||||
@@ -702,6 +706,8 @@ private let strings: [String: [String: String]] = [
|
||||
"filter.empty": "No calendars available",
|
||||
"filter.show_all": "Show all",
|
||||
"filter.hide_all": "Hide all",
|
||||
"filter.sort": "Sort",
|
||||
"filter.done": "Done",
|
||||
"filter.button": "Show/hide calendars",
|
||||
"filter.banish": "Hide permanently",
|
||||
"filter.reminders_on": "Reminders on",
|
||||
|
||||
Reference in New Issue
Block a user