Repo created

This commit is contained in:
Fr4nz D13trich 2025-11-22 13:58:55 +01:00
parent 4af19165ec
commit 68073add76
12458 changed files with 12350765 additions and 2 deletions

View file

@ -0,0 +1,65 @@
class DifficultyView: UIView {
private let stackView = UIStackView()
private var views:[UIView] = []
var difficulty: ElevationDifficulty = .easy {
didSet {
updateView()
}
}
var colors: [UIColor] = [.gray, .green, .orange, .red]
{
didSet {
updateView()
}
}
var emptyColor: UIColor = UIColor.gray {
didSet {
updateView()
}
}
private let bulletSize = CGSize(width: 10, height: 10)
private let bulletSpacing: CGFloat = 5
private let difficultyLevelCount = 3
override init(frame: CGRect) {
super.init(frame: frame)
initComponent()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
initComponent()
}
private func initComponent() {
self.addSubview(stackView)
stackView.frame = bounds
stackView.distribution = .fillEqually
stackView.axis = .horizontal
stackView.spacing = bulletSpacing
stackView.alignment = .fill
for _ in 0..<difficultyLevelCount {
let view = UIView()
stackView.addArrangedSubview(view)
view.layer.setCornerRadius(.custom(bulletSize.height / 2))
views.append(view)
}
}
private func updateView() {
guard colors.count > difficulty.rawValue else {
assertionFailure("No fill color")
return
}
let fillColor = colors[difficulty.rawValue]
for (idx, view) in views.enumerated() {
if idx < difficulty.rawValue {
view.backgroundColor = fillColor
} else {
view.backgroundColor = emptyColor
}
}
}
}

View file

@ -0,0 +1,167 @@
final class ExpandableLabel: UIView {
typealias OnExpandClosure = (() -> Void) -> Void
private let stackView = UIStackView()
private let textView = UITextView()
private let expandLabel = UILabel()
var onExpandClosure: OnExpandClosure?
var font = UIFont.systemFont(ofSize: 16) {
didSet {
textView.font = font
expandLabel.font = font
}
}
var textColor = UIColor.black {
didSet {
textView.textColor = textColor
}
}
var expandColor = UIColor.systemBlue {
didSet {
expandLabel.textColor = expandColor
}
}
var text: String? {
didSet {
containerText = text
textView.text = text
if let text = text {
isHidden = text.isEmpty
} else {
isHidden = true
}
}
}
var attributedText: NSAttributedString? {
didSet {
containerText = attributedText?.string
textView.attributedText = attributedText
if let attributedText = attributedText {
isHidden = attributedText.length == 0
} else {
isHidden = true
}
}
}
var expandText = "More" {
didSet {
expandLabel.text = expandText
}
}
var numberOfLines = 2 {
didSet {
containerMaximumNumberOfLines = numberOfLines > 0 ? numberOfLines + 1 : 0
}
}
private var containerText: String?
private var containerMaximumNumberOfLines = 2 {
didSet {
textView.textContainer.maximumNumberOfLines = containerMaximumNumberOfLines
textView.invalidateIntrinsicContentSize()
}
}
private var oldWidth: CGFloat = 0
override func setContentHuggingPriority(_ priority: UILayoutPriority, for axis: NSLayoutConstraint.Axis) {
super.setContentHuggingPriority(priority, for: axis)
textView.setContentHuggingPriority(priority, for: axis)
expandLabel.setContentHuggingPriority(priority, for: axis)
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
private func commonInit() {
stackView.axis = .vertical
stackView.alignment = .leading
containerMaximumNumberOfLines = numberOfLines > 0 ? numberOfLines + 1 : 0
textView.textContainer.lineFragmentPadding = 0
textView.isScrollEnabled = false
textView.isEditable = false
textView.textContainerInset = .zero
textView.contentMode = .topLeft
textView.font = font
textView.textColor = textColor
textView.text = text
textView.attributedText = attributedText
textView.setContentHuggingPriority(contentHuggingPriority(for: .vertical), for: .vertical)
textView.backgroundColor = .clear
textView.dataDetectorTypes = [.link, .phoneNumber]
expandLabel.setContentHuggingPriority(contentHuggingPriority(for: .vertical), for: .vertical)
expandLabel.font = font
expandLabel.textColor = expandColor
expandLabel.text = expandText
expandLabel.isHidden = true
addSubview(stackView)
stackView.addArrangedSubview(textView)
stackView.addArrangedSubview(expandLabel)
stackView.alignToSuperview()
let gr = UITapGestureRecognizer(target: self, action: #selector(onExpand(_:)))
addGestureRecognizer(gr)
}
@objc func onExpand(_ sender: UITapGestureRecognizer) {
if expandLabel.isHidden { return }
let expandClosure = {
UIView.animate(withDuration: kDefaultAnimationDuration) {
self.containerMaximumNumberOfLines = 0
self.expandLabel.isHidden = true
self.stackView.layoutIfNeeded()
}
}
if let onExpandClosure = onExpandClosure {
onExpandClosure(expandClosure)
} else {
expandClosure()
}
}
override func layoutSubviews() {
super.layoutSubviews()
if oldWidth != bounds.width, let attributedText = attributedText?.mutableCopy() as? NSMutableAttributedString {
attributedText.enumerateAttachments(estimatedWidth: bounds.width)
self.attributedText = attributedText
oldWidth = bounds.width
}
guard containerMaximumNumberOfLines > 0,
containerMaximumNumberOfLines != numberOfLines,
let s = containerText,
!s.isEmpty else {
return
}
let textRect = s.boundingRect(with: CGSize(width: width, height: CGFloat.greatestFiniteMagnitude),
options: .usesLineFragmentOrigin,
attributes: [.font: font],
context: nil)
let lineHeight = font.lineHeight
if Int(lineHeight * CGFloat(numberOfLines + 1)) >= Int(textRect.height) {
expandLabel.isHidden = true
containerMaximumNumberOfLines = 0
} else {
expandLabel.isHidden = false
containerMaximumNumberOfLines = numberOfLines
}
layoutIfNeeded()
}
}

View file

@ -0,0 +1,80 @@
final class InfoView: UIView {
private let stackView = UIStackView()
private let imageView = UIImageView()
private let titleLabel = UILabel()
private lazy var imageViewWidthConstrain = imageView.widthAnchor.constraint(equalToConstant: 0)
init() {
super.init(frame: .zero)
self.setupView()
self.layoutViews()
}
convenience init(image: UIImage?, title: String) {
self.init()
self.set(image: image, title: title)
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
if #available(iOS 13.0, *), traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
imageView.applyTheme()
}
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupView() {
setStyle(.clearBackground)
stackView.axis = .horizontal
stackView.distribution = .fill
stackView.alignment = .center
stackView.spacing = 16
titleLabel.setFontStyle(.regular16, color: .blackPrimary)
titleLabel.lineBreakMode = .byWordWrapping
titleLabel.numberOfLines = .zero
imageView.setStyle(.black)
imageView.contentMode = .scaleAspectFit
}
private func layoutViews() {
addSubview(stackView)
stackView.addArrangedSubview(imageView)
stackView.addArrangedSubview(titleLabel)
stackView.translatesAutoresizingMaskIntoConstraints = false
imageView.translatesAutoresizingMaskIntoConstraints = false
titleLabel.translatesAutoresizingMaskIntoConstraints = false
imageView.setContentHuggingPriority(.defaultHigh, for: .vertical)
imageView.setContentHuggingPriority(.defaultHigh, for: .horizontal)
titleLabel.setContentHuggingPriority(.defaultLow, for: .horizontal)
NSLayoutConstraint.activate([
stackView.leadingAnchor.constraint(equalTo: leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: trailingAnchor),
stackView.topAnchor.constraint(equalTo: topAnchor),
stackView.bottomAnchor.constraint(equalTo: bottomAnchor),
imageView.heightAnchor.constraint(equalToConstant: 24),
imageViewWidthConstrain
])
updateImageWidth()
}
private func updateImageWidth() {
imageViewWidthConstrain.constant = imageView.image == nil ? 0 : 24
imageView.isHidden = imageView.image == nil
}
// MARK: - Public
func set(image: UIImage?, title: String) {
imageView.image = image
titleLabel.text = title
updateImageWidth()
}
}

View file

@ -0,0 +1,9 @@
final class TouchTransparentView: UIView {
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let view = super.hitTest(point, with: event)
if view === self {
return nil
}
return view
}
}