mirror of
https://github.com/divkit/divkit.git
synced 2026-06-06 20:07:59 +00:00
a2ed8633cc
Избавляюсь от условной компиляции INTERNAL_BUILD, потому что непонятно, как этим пользоваться на клиентах в условиях библиотеки.
154 lines
4.2 KiB
Swift
154 lines
4.2 KiB
Swift
import Foundation
|
|
import UIKit
|
|
|
|
import BaseUI
|
|
import LayoutKit
|
|
|
|
final class ErrorListView: UIView {
|
|
private let listView: UIView
|
|
private let errorString: String
|
|
|
|
init(errors: [String]) {
|
|
errorString = errors.joined(separator: "\n")
|
|
self.listView = makeErrorListView(errorsString: errorString, errorsCount: errors.count)
|
|
super.init(frame: .zero)
|
|
|
|
backgroundColor = .white
|
|
addSubview(listView)
|
|
}
|
|
|
|
public override func layoutSubviews() {
|
|
if #available(iOS 11.0, *) {
|
|
self.listView.frame = self.bounds.inset(by: safeAreaInsets)
|
|
}
|
|
}
|
|
|
|
@available(*, unavailable)
|
|
required init?(coder _: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
private func copyToPasteboard() {
|
|
UIPasteboard.general.string = errorString
|
|
}
|
|
}
|
|
|
|
extension ErrorListView: UIActionEventPerforming {
|
|
func perform(uiActionEvent event: LayoutKit.UIActionEvent, from _: AnyObject) {
|
|
guard case let .url(url) = event.payload else {
|
|
event.sendFrom(self)
|
|
return
|
|
}
|
|
if url == copyActionURL {
|
|
copyToPasteboard()
|
|
} else if url == closeActionURL {
|
|
removeFromSuperview()
|
|
}
|
|
}
|
|
}
|
|
|
|
private func makeErrorListView(errorsString: String, errorsCount: Int) -> UIView {
|
|
try! ContainerBlock(
|
|
layoutDirection: .vertical,
|
|
widthTrait: .resizable,
|
|
heightTrait: .resizable,
|
|
children: [
|
|
.init(content: makeHeaderBlock(errorsCount: errorsCount)),
|
|
.init(content: makeErrorListBlock(errorString: errorsString)),
|
|
]
|
|
).addingDecorations(backgroundColor: .white).makeBlockView()
|
|
}
|
|
|
|
private func makeCopyButtonBlock() -> Block {
|
|
let copyText = "Copy".with(typo: headerTypo)
|
|
|
|
let copyTextBlock = TextBlock(
|
|
widthTrait: .intrinsic,
|
|
heightTrait: .fixed(headerHeight),
|
|
text: copyText,
|
|
verticalAlignment: .center,
|
|
maxIntrinsicNumberOfLines: 1
|
|
).addingDecorations(
|
|
action: UserInterfaceAction(url: copyActionURL, path: rootPath)
|
|
)
|
|
return copyTextBlock
|
|
}
|
|
|
|
private func makeCloseButtonBlock() -> Block {
|
|
TextBlock(
|
|
widthTrait: .intrinsic,
|
|
heightTrait: .fixed(headerHeight),
|
|
text: "Close".with(typo: headerTypo),
|
|
verticalAlignment: .center,
|
|
maxIntrinsicNumberOfLines: 1
|
|
).addingDecorations(
|
|
action: UserInterfaceAction(url: closeActionURL, path: rootPath)
|
|
)
|
|
}
|
|
|
|
private func makeTitleBlock(errorsCount: Int) -> Block {
|
|
let titleText = ("\(errorsCount) " + (errorsCount == 1 ? "error" : "errors"))
|
|
.with(typo: headerTypo)
|
|
|
|
let errorsBlock = TextBlock(
|
|
widthTrait: .intrinsic,
|
|
heightTrait: .fixed(headerHeight),
|
|
text: titleText,
|
|
verticalAlignment: .center,
|
|
maxIntrinsicNumberOfLines: 1
|
|
)
|
|
|
|
return try! ContainerBlock(
|
|
layoutDirection: .horizontal,
|
|
widthTrait: .resizable,
|
|
heightTrait: .fixed(headerHeight),
|
|
axialAlignment: .center,
|
|
children: [.init(content: errorsBlock)]
|
|
)
|
|
}
|
|
|
|
private func makeHeaderBlock(errorsCount: Int) -> Block {
|
|
try! ContainerBlock(
|
|
layoutDirection: .horizontal,
|
|
widthTrait: .resizable,
|
|
heightTrait: .fixed(headerHeight),
|
|
axialAlignment: .leading,
|
|
gaps: [16, 20, 20, 16],
|
|
children: [
|
|
.init(content: makeCloseButtonBlock()),
|
|
.init(content: makeCopyButtonBlock()),
|
|
.init(content: makeTitleBlock(errorsCount: errorsCount)),
|
|
]
|
|
)
|
|
}
|
|
|
|
private func makeErrorListBlock(errorString: String) -> Block {
|
|
let textBlock = TextBlock(
|
|
widthTrait: .resizable,
|
|
heightTrait: .intrinsic,
|
|
text: errorString.with(typo: errorsTypo),
|
|
verticalAlignment: .leading,
|
|
minNumberOfHiddenLines: 0
|
|
)
|
|
|
|
return try! GalleryBlock(
|
|
gaps: [.zero, .zero],
|
|
children: [textBlock],
|
|
path: rootPath,
|
|
direction: .vertical,
|
|
crossAlignment: .leading,
|
|
widthTrait: .resizable,
|
|
heightTrait: .resizable
|
|
).addingEdgeInsets(insets, clipsToBounds: true, forceWrapping: true)
|
|
}
|
|
|
|
private let closeActionURL = URL(string: "errorList://close")!
|
|
private let copyActionURL = URL(string: "errorList://copy")!
|
|
private let rootPath: UIElementPath = "ErrorList"
|
|
|
|
private let insets = EdgeInsets(vertical: 0, horizontal: 16)
|
|
private let headerHeight: CGFloat = 56
|
|
private let headerTypo = Typo(size: .textL, weight: .medium).with(height: .textL)
|
|
private let errorsTypo = Typo(size: .textM, weight: .regular)
|
|
.with(height: FontLineHeight(rawValue: 18))
|