import UIKit @MainActor final class ServerActivityViewController: RefreshingTableViewController { private let context: AppContext private var rows: [ActivityRow] = [] private var nextPage: UInt32? private var loaded = false init(context: AppContext) { self.context = context super.init() setPanelTitle(self, "Server Activity", server: context.core.activeServerName()) } @available(*, unavailable) required init?(coder: NSCoder) { fatalError("init(coder:) is not supported") } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) guard !loaded else { return } loadContent(refreshing: false) } override func loadContent(refreshing: Bool) { loadPage(1, refreshing: refreshing) } override func loadMoreContent() { guard let nextPage else { return } loadPage(nextPage, refreshing: false) } private func loadPage(_ requestedPage: UInt32, refreshing: Bool) { if requestedPage == 1 { resetPagination() beginLoading(refreshing: refreshing) } loadingTask?.cancel() loadingTask = Task { do { let page = try await context.core.serverActivity(page: requestedPage) if requestedPage == 1 { rows = page.rows loaded = true } else { rows.append(contentsOf: page.rows) } nextPage = page.hasMore ? requestedPage + 1 : nil finishPagination(hasMore: page.hasMore) updateRows() } catch { if !Task.isCancelled { show(error: error) failPagination() } } if requestedPage == 1 { endLoading() } } } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { rows.count } override func tableView( _ tableView: UITableView, cellForRowAt indexPath: IndexPath ) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "server-activity") ?? UITableViewCell(style: .subtitle, reuseIdentifier: "server-activity") let row = rows[indexPath.row] configureTextCell( cell, title: row.title, detail: "\(row.detail)\n\(row.meta)", image: context.symbol(activitySymbolName(for: row.icon)) ) cell.accessoryType = row.target == .none ? .none : .disclosureIndicator cell.selectionStyle = row.target == .none ? .none : .default return cell } override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 92 } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let row = rows[indexPath.row] guard row.target != .none else { return } tableView.deselectRow(at: indexPath, animated: true) context.route(row) } private func updateRows() { tableView.reloadData() tableView.backgroundView = rows.isEmpty ? EmptyBackgroundView( title: "No server activity", detail: "No activity is visible to this server account." ) : nil } }