From f27bb3b532418ebfda647249f64782cc68f2a562 Mon Sep 17 00:00:00 2001 From: Balazs Perlaki-Horvath Date: Sat, 19 Apr 2025 16:46:13 +0200 Subject: [PATCH 1/5] Remove article title from outline --- Views/Buttons/OutlineButton.swift | 3 --- 1 file changed, 3 deletions(-) diff --git a/Views/Buttons/OutlineButton.swift b/Views/Buttons/OutlineButton.swift index 828b4710..8bb917ed 100644 --- a/Views/Buttons/OutlineButton.swift +++ b/Views/Buttons/OutlineButton.swift @@ -19,14 +19,12 @@ struct OutlineButton: View { private let items: [OutlineItem] private let itemTree: [OutlineItem] private let scrollTo: (_ itemID: String) -> Void - private let articleTitle: String @Environment(\.dismissSearch) private var dismissSearch @State private var isShowingOutline = false init(browser: BrowserViewModel) { items = browser.outlineItems itemTree = browser.outlineItemTree - articleTitle = browser.articleTitle scrollTo = { [weak browser] itemID in browser?.scrollTo(outlineItemID: itemID) } @@ -69,7 +67,6 @@ struct OutlineButton: View { }.listStyle(.plain) } } - .navigationTitle(articleTitle) .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .cancellationAction) { From 25bba5a23ae430777cf8b4dfeecac6520200ecf0 Mon Sep 17 00:00:00 2001 From: Balazs Perlaki-Horvath Date: Sat, 19 Apr 2025 19:54:04 +0200 Subject: [PATCH 2/5] Revert "Use a single instance of WebViewConfiguration" This reverts commit 8d567833cde13dd066dab1ae1727e5fbc23dc636. --- ViewModel/BrowserViewModel.swift | 2 +- Views/BuildingBlocks/WebView.swift | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/ViewModel/BrowserViewModel.swift b/ViewModel/BrowserViewModel.swift index 09349056..9bdd9ef8 100644 --- a/ViewModel/BrowserViewModel.swift +++ b/ViewModel/BrowserViewModel.swift @@ -114,7 +114,7 @@ final class BrowserViewModel: NSObject, ObservableObject, // swiftlint:disable:next function_body_length @MainActor private init(tabID: NSManagedObjectID) { self.tabID = tabID - webView = WKWebView(frame: .zero, configuration: WebViewConfigCache.config) + webView = WKWebView(frame: .zero, configuration: WebViewConfiguration()) if !Bundle.main.isProduction, #available(iOS 16.4, macOS 13.3, *) { webView.isInspectable = true } diff --git a/Views/BuildingBlocks/WebView.swift b/Views/BuildingBlocks/WebView.swift index 6d95d229..0a299312 100644 --- a/Views/BuildingBlocks/WebView.swift +++ b/Views/BuildingBlocks/WebView.swift @@ -226,10 +226,6 @@ extension WKWebView { } #endif -enum WebViewConfigCache { - static let config = WebViewConfiguration() -} - final class WebViewConfiguration: WKWebViewConfiguration { override init() { super.init() From 11644256240200efc2b97cf60adf3b637fc98eef Mon Sep 17 00:00:00 2001 From: Balazs Perlaki-Horvath Date: Sun, 20 Apr 2025 11:21:02 +0200 Subject: [PATCH 3/5] Make first and single item non-collapsible --- Model/Entities/Entities.swift | 12 ++++++++++-- ViewModel/BrowserViewModel.swift | 5 ++--- Views/Buttons/OutlineButton.swift | 3 ++- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/Model/Entities/Entities.swift b/Model/Entities/Entities.swift index 58538668..f003b84d 100644 --- a/Model/Entities/Entities.swift +++ b/Model/Entities/Entities.swift @@ -86,20 +86,28 @@ struct Language: Identifiable, Comparable { } } -class OutlineItem: ObservableObject, Identifiable { +final class OutlineItem: ObservableObject, Identifiable { let id: String let index: Int let text: String let level: Int + let isCollapsible: Bool private(set) var children: [OutlineItem]? @Published var isExpanded = true + + func asNonCollapsible() -> OutlineItem { + let copy = OutlineItem(id: id, index: index, text: text, level: level, isCollapsible: false) + copy.children = children + return copy + } - init(id: String, index: Int, text: String, level: Int) { + init(id: String, index: Int, text: String, level: Int, isCollapsible: Bool = true) { self.id = id self.index = index self.text = text self.level = level + self.isCollapsible = isCollapsible } convenience init(index: Int, text: String, level: Int) { diff --git a/ViewModel/BrowserViewModel.swift b/ViewModel/BrowserViewModel.swift index 9bdd9ef8..12dc2f59 100644 --- a/ViewModel/BrowserViewModel.swift +++ b/ViewModel/BrowserViewModel.swift @@ -760,10 +760,9 @@ final class BrowserViewModel: NSObject, ObservableObject, } } - // if there is only one h1, flatten one level + // if there is only one h1, make the first item non collapsible if let rootChildren = root.children, rootChildren.count == 1, let rootFirstChild = rootChildren.first { - let children = rootFirstChild.removeAllChildren() - self.outlineItemTree = [rootFirstChild] + children + self.outlineItemTree = [rootFirstChild.asNonCollapsible()] } else { self.outlineItemTree = root.children ?? [] } diff --git a/Views/Buttons/OutlineButton.swift b/Views/Buttons/OutlineButton.swift index 8bb917ed..9e2ec6d3 100644 --- a/Views/Buttons/OutlineButton.swift +++ b/Views/Buttons/OutlineButton.swift @@ -90,7 +90,8 @@ struct OutlineButton: View { var body: some View { if let children = item.children { - DisclosureGroup(isExpanded: $item.isExpanded) { + let isExpanded = item.isCollapsible ? $item.isExpanded : .constant(true) + DisclosureGroup(isExpanded: isExpanded) { ForEach(children) { child in OutlineNode(item: child, action: action) } From 6c5344e4a31bb3c1b78fc50f1aacf2cb2d198d2c Mon Sep 17 00:00:00 2001 From: Balazs Perlaki-Horvath Date: Sun, 20 Apr 2025 14:30:03 +0200 Subject: [PATCH 4/5] Remove top level only item from OutlineTree --- Model/Entities/Entities.swift | 10 +--------- ViewModel/BrowserViewModel.swift | 6 ++---- Views/Buttons/OutlineButton.swift | 3 +-- 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/Model/Entities/Entities.swift b/Model/Entities/Entities.swift index f003b84d..88c0a57c 100644 --- a/Model/Entities/Entities.swift +++ b/Model/Entities/Entities.swift @@ -91,23 +91,15 @@ final class OutlineItem: ObservableObject, Identifiable { let index: Int let text: String let level: Int - let isCollapsible: Bool private(set) var children: [OutlineItem]? @Published var isExpanded = true - - func asNonCollapsible() -> OutlineItem { - let copy = OutlineItem(id: id, index: index, text: text, level: level, isCollapsible: false) - copy.children = children - return copy - } - init(id: String, index: Int, text: String, level: Int, isCollapsible: Bool = true) { + init(id: String, index: Int, text: String, level: Int) { self.id = id self.index = index self.text = text self.level = level - self.isCollapsible = isCollapsible } convenience init(index: Int, text: String, level: Int) { diff --git a/ViewModel/BrowserViewModel.swift b/ViewModel/BrowserViewModel.swift index 12dc2f59..f9d98c99 100644 --- a/ViewModel/BrowserViewModel.swift +++ b/ViewModel/BrowserViewModel.swift @@ -732,14 +732,12 @@ final class BrowserViewModel: NSObject, ObservableObject, @MainActor private func generateOutlineTree(headings: [[String: String]]) { let root = OutlineItem(index: -1, text: "", level: 0) var stack: [OutlineItem] = [root] - var all = [String: OutlineItem]() headings.enumerated().forEach { index, heading in guard let id = heading["id"], let text = heading["text"], let tag = heading["tag"], let level = Int(tag.suffix(1)) else { return } let item = OutlineItem(id: id, index: index, text: text, level: level) - all[item.id] = item // get last item in stack // if last item is child of item's sibling, unwind stack until a sibling is found @@ -760,9 +758,9 @@ final class BrowserViewModel: NSObject, ObservableObject, } } - // if there is only one h1, make the first item non collapsible + // if there is only one item at top level, do not display it only it's children if let rootChildren = root.children, rootChildren.count == 1, let rootFirstChild = rootChildren.first { - self.outlineItemTree = [rootFirstChild.asNonCollapsible()] + self.outlineItemTree = rootFirstChild.children ?? [] } else { self.outlineItemTree = root.children ?? [] } diff --git a/Views/Buttons/OutlineButton.swift b/Views/Buttons/OutlineButton.swift index 9e2ec6d3..8bb917ed 100644 --- a/Views/Buttons/OutlineButton.swift +++ b/Views/Buttons/OutlineButton.swift @@ -90,8 +90,7 @@ struct OutlineButton: View { var body: some View { if let children = item.children { - let isExpanded = item.isCollapsible ? $item.isExpanded : .constant(true) - DisclosureGroup(isExpanded: isExpanded) { + DisclosureGroup(isExpanded: $item.isExpanded) { ForEach(children) { child in OutlineNode(item: child, action: action) } From 222f8a468080f8277d275b39ea9af9f37ab1c0e0 Mon Sep 17 00:00:00 2001 From: Balazs Perlaki-Horvath Date: Mon, 21 Apr 2025 17:21:52 +0200 Subject: [PATCH 5/5] Remote top level only item from OutlineTree if matches the article title --- ViewModel/BrowserViewModel.swift | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ViewModel/BrowserViewModel.swift b/ViewModel/BrowserViewModel.swift index f9d98c99..031650a8 100644 --- a/ViewModel/BrowserViewModel.swift +++ b/ViewModel/BrowserViewModel.swift @@ -758,8 +758,11 @@ final class BrowserViewModel: NSObject, ObservableObject, } } - // if there is only one item at top level, do not display it only it's children - if let rootChildren = root.children, rootChildren.count == 1, let rootFirstChild = rootChildren.first { + // if there is only one item at top level, with the same text as the article title + // do not display it only it's children + if let rootChildren = root.children, rootChildren.count == 1, + let rootFirstChild = rootChildren.first, + rootFirstChild.text.lowercased() == articleTitle.lowercased() { self.outlineItemTree = rootFirstChild.children ?? [] } else { self.outlineItemTree = root.children ?? []