feat: initial list view version
This commit is contained in:
parent
31582b3bc5
commit
ff720fca0d
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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 })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue