feat: initial list view version

This commit is contained in:
Nikita Semenov 2022-09-29 15:44:27 +03:00
parent 31582b3bc5
commit ff720fca0d
4 changed files with 212 additions and 0 deletions

View File

@ -0,0 +1,10 @@
import TIUIKitCore
import TIUIElements
import OSLog
@available(iOS 15, *)
open class LogEntryTableViewCell: BaseInitializableCell, ConfigurableView {
open func configure(with entry: OSLogEntryLog) {
textLabel?.text = entry.composedMessage
}
}

View File

@ -0,0 +1,118 @@
import TIUIKitCore
import OSLog
import UIKit
@available(iOS 15, *)
open class LogsListView: BaseInitializeableViewController, LogsListViewOutput {
public enum TableSection: String, Hashable {
case main
}
private let searchView = UITextField()
private let segmentView = UISegmentedControl()
private let tableView = UITableView()
lazy private var dataSource = createDataSource()
public typealias DataSource = UITableViewDiffableDataSource<String, OSLogEntryLog>
public typealias Snapshot = NSDiffableDataSourceSnapshot<String, OSLogEntryLog>
public let viewModel = LogsStorageViewModel()
// MARK: - Life cycle
open override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
applySnapshot()
}
open override func addViews() {
super.addViews()
view.addSubview(searchView)
view.addSubview(segmentView)
view.addSubview(tableView)
}
open override func configureLayout() {
super.configureLayout()
[searchView, segmentView, tableView]
.forEach { $0.translatesAutoresizingMaskIntoConstraints = false }
NSLayoutConstraint.activate([
searchView.topAnchor.constraint(equalTo: view.topAnchor, constant: 8),
searchView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
searchView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
searchView.heightAnchor.constraint(equalToConstant: 32),
segmentView.topAnchor.constraint(equalTo: searchView.bottomAnchor),
segmentView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
segmentView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
segmentView.heightAnchor.constraint(equalToConstant: 32),
tableView.topAnchor.constraint(equalTo: segmentView.bottomAnchor, constant: 8),
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
}
open override func bindViews() {
super.bindViews()
viewModel.logsListView = self
tableView.register(LogEntryTableViewCell.self, forCellReuseIdentifier: "identifier")
}
open override func configureAppearance() {
super.configureAppearance()
configureSegmentView()
view.backgroundColor = .systemBackground
tableView.backgroundColor = .systemBackground
}
// MARK: - LogsListViewOutput
open func reloadTableView() {
applySnapshot()
}
// MARK: - Open methods
open func createDataSource() -> DataSource {
let cellProvider: DataSource.CellProvider = { collectionView, indexPath, itemIdentifier in
let cell = collectionView.dequeueReusableCell(withIdentifier: "identifier",
for: indexPath) as? LogEntryTableViewCell
cell?.configure(with: itemIdentifier)
return cell
}
return .init(tableView: tableView, cellProvider: cellProvider)
}
open func applySnapshot() {
var snapshot = Snapshot()
snapshot.appendSections([TableSection.main.rawValue])
snapshot.appendItems(viewModel.filteredLogs, toSection: TableSection.main.rawValue)
dataSource.apply(snapshot, animatingDifferences: true)
}
// MARK: - Private methods
private func configureSegmentView() {
for (index, segment) in LogsStorageViewModel.LevelType.allCases.enumerated() {
let action = UIAction(title: segment.rawValue, handler: viewModel.actionHandler(for:))
segmentView.insertSegment(action: action, at: index, animated: false)
}
segmentView.selectedSegmentIndex = 0
}
}

View File

@ -0,0 +1,80 @@
import TISwiftUtils
import UIKit
import OSLog
public protocol LogsListViewOutput: AnyObject {
func reloadTableView()
}
@available(iOS 15, *)
open class LogsStorageViewModel {
public enum LevelType: String, CaseIterable {
case all
case `default`
case info
case debug
case error
case fault
}
private var allLogs: [OSLogEntryLog] = [] {
didSet {
filterLogs()
}
}
public var filteredLogs: [OSLogEntryLog] = [] {
didSet {
logsListView?.reloadTableView()
}
}
weak public var logsListView: LogsListViewOutput?
public init() {
loadLogs()
}
open func loadLogs() {
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
let logStore = try? OSLogStore(scope: .currentProcessIdentifier)
let entries = try? logStore?.getEntries()
let logs = entries?
.compactMap { $0 as? OSLogEntryLog }
DispatchQueue.main.async {
self?.allLogs = logs ?? []
}
}
}
open func filterLogs(filter: Closure<OSLogEntryLog, Bool>? = nil) {
filteredLogs = allLogs.filter { filter?($0) ?? true }
}
open func actionHandler(for action: UIAction) {
guard let level = LevelType(rawValue: action.title) else { return }
switch level {
case .all:
loadLogs()
case .info:
filterLogs(filter: { $0.level == .info })
case .default:
filterLogs(filter: { $0.level == .notice })
case .debug:
filterLogs(filter: { $0.level == .debug })
case .error:
filterLogs(filter: { $0.level == .error })
case .fault:
filterLogs(filter: { $0.level == .fault })
}
}
}

View File

@ -12,4 +12,8 @@ Pod::Spec.new do |s|
s.source_files = s.name + '/Sources/**/*'
s.dependency 'TIUIKitCore', s.version.to_s
s.dependency 'TISwiftUtils', s.version.to_s
s.dependency 'TIUIElements', s.version.to_s
end