94 lines
3.9 KiB
Swift
94 lines
3.9 KiB
Swift
import UIKit
|
|
|
|
final class WordCardCell: UITableViewCell {
|
|
private let cardView = UIView()
|
|
private let wordLabel = UILabel()
|
|
private let phoneticLabel = UILabel()
|
|
private let meaningLabel = UILabel()
|
|
private let speakerButton = UIButton(type: .system)
|
|
private var word: Word?
|
|
|
|
var onSpeak: ((Word) -> Void)?
|
|
|
|
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
|
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
|
backgroundColor = .clear
|
|
contentView.backgroundColor = .clear
|
|
selectionStyle = .none
|
|
|
|
cardView.backgroundColor = Theme.Color.cardBackground
|
|
cardView.layer.cornerRadius = Theme.Metrics.cardRadius
|
|
contentView.addSubview(cardView)
|
|
cardView.translatesAutoresizingMaskIntoConstraints = false
|
|
NSLayoutConstraint.activate([
|
|
cardView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 5),
|
|
cardView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),
|
|
cardView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16),
|
|
cardView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -5)
|
|
])
|
|
|
|
wordLabel.font = .preferredFont(forTextStyle: .headline)
|
|
phoneticLabel.font = .preferredFont(forTextStyle: .caption1)
|
|
phoneticLabel.textColor = .tertiaryLabel
|
|
meaningLabel.font = .preferredFont(forTextStyle: .subheadline)
|
|
meaningLabel.textColor = .secondaryLabel
|
|
|
|
let titleRow = UIStackView(arrangedSubviews: [wordLabel, phoneticLabel, UIView()])
|
|
titleRow.axis = .horizontal
|
|
titleRow.alignment = .firstBaseline
|
|
titleRow.spacing = 6
|
|
|
|
let textStack = UIStackView(arrangedSubviews: [titleRow, meaningLabel])
|
|
textStack.axis = .vertical
|
|
textStack.spacing = 2
|
|
|
|
speakerButton.tintColor = Theme.Color.accent
|
|
speakerButton.addAction(UIAction { [weak self] _ in
|
|
guard let self, let word else { return }
|
|
onSpeak?(word)
|
|
}, for: .touchUpInside)
|
|
speakerButton.setContentHuggingPriority(.required, for: .horizontal)
|
|
|
|
let row = UIStackView(arrangedSubviews: [textStack, speakerButton])
|
|
row.axis = .horizontal
|
|
row.alignment = .center
|
|
row.spacing = 8
|
|
cardView.addSubview(row)
|
|
row.translatesAutoresizingMaskIntoConstraints = false
|
|
NSLayoutConstraint.activate([
|
|
row.topAnchor.constraint(equalTo: cardView.topAnchor, constant: 10),
|
|
row.leadingAnchor.constraint(equalTo: cardView.leadingAnchor, constant: 14),
|
|
row.trailingAnchor.constraint(equalTo: cardView.trailingAnchor, constant: -8),
|
|
row.bottomAnchor.constraint(equalTo: cardView.bottomAnchor, constant: -10),
|
|
speakerButton.widthAnchor.constraint(equalToConstant: 44),
|
|
speakerButton.heightAnchor.constraint(equalToConstant: 44)
|
|
])
|
|
}
|
|
|
|
@available(*, unavailable)
|
|
required init?(coder: NSCoder) { fatalError() }
|
|
|
|
func configure(with word: Word) {
|
|
self.word = word
|
|
wordLabel.text = word.word
|
|
phoneticLabel.text = word.phonetic
|
|
meaningLabel.text = word.meaning
|
|
updateSpeakerState()
|
|
}
|
|
|
|
func updateSpeakerState() {
|
|
guard let word else { return }
|
|
let speaking = SpeechService.shared.isSpeaking(word.word)
|
|
let symbol = speaking ? "speaker.wave.3.fill" : "speaker.wave.2.fill"
|
|
speakerButton.setImage(UIImage(systemName: symbol,
|
|
withConfiguration: UIImage.SymbolConfiguration(pointSize: 15, weight: .medium)),
|
|
for: .normal)
|
|
speakerButton.isEnabled = !speaking
|
|
}
|
|
|
|
override func setHighlighted(_ highlighted: Bool, animated: Bool) {
|
|
super.setHighlighted(highlighted, animated: animated)
|
|
cardView.setPressed(highlighted, animated: animated)
|
|
}
|
|
}
|