From c62f0f0f6d84dc5cea05b8397030fd3f7cebbdea Mon Sep 17 00:00:00 2001 From: Roopesh Chander Date: Mon, 1 Apr 2019 22:36:16 +0530 Subject: [PATCH] macOS: Log view: Fix autoscroll to end of log Looks like the tableview doesn't know how much to scroll to get to the end when we use usesAutomaticRowHeights. So we wait for the tableview to realize its frame has changed and then scroll to the bottom of the frame explicitly. Also, we keep track of whether the scroll view is scrolled to the end or not every time scrolling happens, not just when we add log entries to the table. --- .../ViewController/LogViewController.swift | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/WireGuard/WireGuard/UI/macOS/ViewController/LogViewController.swift b/WireGuard/WireGuard/UI/macOS/ViewController/LogViewController.swift index ddc8c31..3f3a14b 100644 --- a/WireGuard/WireGuard/UI/macOS/ViewController/LogViewController.swift +++ b/WireGuard/WireGuard/UI/macOS/ViewController/LogViewController.swift @@ -76,6 +76,7 @@ class LogViewController: NSViewController { let logViewHelper: LogViewHelper? var logEntries = [LogViewHelper.LogEntry]() var isFetchingLogEntries = false + var isInScrolledToEndMode = true private var updateLogEntriesTimer: Timer? @@ -103,6 +104,21 @@ class LogViewController: NSViewController { clipView.documentView = tableView scrollView.contentView = clipView + _ = NotificationCenter.default.addObserver(forName: NSView.boundsDidChangeNotification, object: clipView, queue: OperationQueue.main) { [weak self] _ in + guard let self = self else { return } + let lastVisibleRowIndex = self.tableView.row(at: NSPoint(x: 0, y: self.scrollView.contentView.documentVisibleRect.maxY - 1)) + self.isInScrolledToEndMode = lastVisibleRowIndex < 0 || lastVisibleRowIndex == self.logEntries.count - 1 + } + + _ = NotificationCenter.default.addObserver(forName: NSView.frameDidChangeNotification, object: tableView, queue: OperationQueue.main) { [weak self] _ in + guard let self = self else { return } + if self.isInScrolledToEndMode { + DispatchQueue.main.async { + self.tableView.scroll(NSPoint(x: 0, y: self.tableView.frame.maxY - clipView.documentVisibleRect.height)) + } + } + } + let margin: CGFloat = 20 let internalSpacing: CGFloat = 10 @@ -155,14 +171,9 @@ class LogViewController: NSViewController { self.saveButton.isEnabled = true } guard !fetchedLogEntries.isEmpty else { return } - let numOfEntries = self.logEntries.count - let lastVisibleRowIndex = self.tableView.row(at: NSPoint(x: 0, y: self.scrollView.contentView.documentVisibleRect.maxY - 1)) - let isScrolledToEnd = lastVisibleRowIndex == numOfEntries - 1 + let oldCount = self.logEntries.count self.logEntries.append(contentsOf: fetchedLogEntries) - self.tableView.insertRows(at: IndexSet(integersIn: numOfEntries ..< numOfEntries + fetchedLogEntries.count), withAnimation: .slideDown) - if isScrolledToEnd { - self.tableView.scrollRowToVisible(self.logEntries.count - 1) - } + self.tableView.insertRows(at: IndexSet(integersIn: oldCount ..< oldCount + fetchedLogEntries.count), withAnimation: .slideDown) } }