feat: add counter and emoji picker activity indicator
This commit is contained in:
parent
59889cd683
commit
87a6a4df77
|
@ -1171,8 +1171,8 @@
|
|||
DB789A2125F9F76D0071ACA0 /* CollectionViewCell */,
|
||||
DB789A0A25F9F2950071ACA0 /* ComposeViewController.swift */,
|
||||
DB789A1125F9F2CC0071ACA0 /* ComposeViewModel.swift */,
|
||||
DB9A488926034D40008B817C /* ComposeViewModel+PublishState.swift */,
|
||||
DB66728B25F9F8DC00D60309 /* ComposeViewModel+Diffable.swift */,
|
||||
DB9A488926034D40008B817C /* ComposeViewModel+PublishState.swift */,
|
||||
);
|
||||
path = Compose;
|
||||
sourceTree = "<group>";
|
||||
|
|
|
@ -85,15 +85,8 @@ extension ComposeStatusSection {
|
|||
UIView.animate(withDuration: 0.33, delay: 0, options: [.curveEaseOut]) {
|
||||
cell.statusContentWarningEditorView.alpha = 1
|
||||
} completion: { _ in
|
||||
if isContentWarningComposing {
|
||||
cell.statusContentWarningEditorView.textView.becomeFirstResponder()
|
||||
}
|
||||
// do nothing
|
||||
}
|
||||
// restore responder if needs
|
||||
if cell.statusContentWarningEditorView.textView.isFirstResponder {
|
||||
cell.textEditorView.isEditing = true
|
||||
}
|
||||
}
|
||||
.store(in: &cell.disposeBag)
|
||||
cell.contentWarningContent
|
||||
|
|
|
@ -75,10 +75,10 @@ internal enum Asset {
|
|||
internal static let buttonDefault = ColorAsset(name: "Colors/buttonDefault")
|
||||
internal static let buttonDisabled = ColorAsset(name: "Colors/buttonDisabled")
|
||||
internal static let buttonInactive = ColorAsset(name: "Colors/buttonInactive")
|
||||
internal static let danger = ColorAsset(name: "Colors/danger")
|
||||
internal static let lightAlertYellow = ColorAsset(name: "Colors/lightAlertYellow")
|
||||
internal static let lightBackground = ColorAsset(name: "Colors/lightBackground")
|
||||
internal static let lightBrandBlue = ColorAsset(name: "Colors/lightBrandBlue")
|
||||
internal static let lightDangerRed = ColorAsset(name: "Colors/lightDangerRed")
|
||||
internal static let lightDarkGray = ColorAsset(name: "Colors/lightDarkGray")
|
||||
internal static let lightDisabled = ColorAsset(name: "Colors/lightDisabled")
|
||||
internal static let lightInactive = ColorAsset(name: "Colors/lightInactive")
|
||||
|
|
|
@ -10,6 +10,7 @@ import UIKit
|
|||
import Combine
|
||||
|
||||
protocol ComposeStatusPollOptionCollectionViewCellDelegate: class {
|
||||
func composeStatusPollOptionCollectionViewCell(_ cell: ComposeStatusPollOptionCollectionViewCell, textFieldDidBeginEditing textField: UITextField)
|
||||
func composeStatusPollOptionCollectionViewCell(_ cell: ComposeStatusPollOptionCollectionViewCell, textBeforeDeleteBackward text: String?)
|
||||
func composeStatusPollOptionCollectionViewCell(_ cell: ComposeStatusPollOptionCollectionViewCell, pollOptionTextFieldDidReturn: UITextField)
|
||||
}
|
||||
|
@ -132,6 +133,12 @@ extension ComposeStatusPollOptionCollectionViewCell: DeleteBackwardResponseTextF
|
|||
|
||||
// MARK: - UITextFieldDelegate
|
||||
extension ComposeStatusPollOptionCollectionViewCell: UITextFieldDelegate {
|
||||
|
||||
func textFieldDidBeginEditing(_ textField: UITextField) {
|
||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
delegate?.composeStatusPollOptionCollectionViewCell(self, textFieldDidBeginEditing: textField)
|
||||
}
|
||||
|
||||
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
|
||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
if textField === pollOptionView.optionTextField {
|
||||
|
|
|
@ -10,6 +10,7 @@ import UIKit
|
|||
import Combine
|
||||
import PhotosUI
|
||||
import Kingfisher
|
||||
import MastodonSDK
|
||||
import TwitterTextEditor
|
||||
|
||||
final class ComposeViewController: UIViewController, NeedsDependency {
|
||||
|
@ -102,14 +103,18 @@ final class ComposeViewController: UIViewController, NeedsDependency {
|
|||
return documentPickerController
|
||||
}()
|
||||
|
||||
deinit {
|
||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ComposeViewController {
|
||||
private static func createLayout() -> UICollectionViewLayout {
|
||||
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(100))
|
||||
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(44))
|
||||
let item = NSCollectionLayoutItem(layoutSize: itemSize)
|
||||
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(100))
|
||||
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
|
||||
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(44))
|
||||
let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [item])
|
||||
let section = NSCollectionLayoutSection(group: group)
|
||||
section.contentInsetsReference = .readableContent
|
||||
// section.interGroupSpacing = 10
|
||||
|
@ -232,22 +237,61 @@ extension ComposeViewController {
|
|||
})
|
||||
.store(in: &disposeBag)
|
||||
|
||||
// bind publish bar button state
|
||||
viewModel.isPublishBarButtonItemEnabled
|
||||
.receive(on: DispatchQueue.main)
|
||||
.assign(to: \.isEnabled, on: publishBarButtonItem)
|
||||
.store(in: &disposeBag)
|
||||
|
||||
// bind media button toolbar state
|
||||
viewModel.isMediaToolbarButtonEnabled
|
||||
.receive(on: DispatchQueue.main)
|
||||
.assign(to: \.isEnabled, on: composeToolbarView.mediaButton)
|
||||
.store(in: &disposeBag)
|
||||
|
||||
// bind poll button toolbar state
|
||||
viewModel.isPollToolbarButtonEnabled
|
||||
.receive(on: DispatchQueue.main)
|
||||
.assign(to: \.isEnabled, on: composeToolbarView.pollButton)
|
||||
.store(in: &disposeBag)
|
||||
|
||||
// bind custom emojis
|
||||
// bind image picker toolbar state
|
||||
viewModel.attachmentServices
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] attachmentServices in
|
||||
guard let self = self else { return }
|
||||
self.composeToolbarView.mediaButton.isEnabled = attachmentServices.count < 4
|
||||
self.resetImagePicker()
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
// bind visibility toolbar UI
|
||||
viewModel.selectedStatusVisibility
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] type in
|
||||
guard let self = self else { return }
|
||||
self.composeToolbarView.visibilityButton.setImage(type.image, for: .normal)
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
viewModel.characterCount
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] characterCount in
|
||||
guard let self = self else { return }
|
||||
let count = ComposeViewModel.composeContentLimit - characterCount
|
||||
self.composeToolbarView.characterCountLabel.text = "\(count)"
|
||||
switch count {
|
||||
case _ where count < 0:
|
||||
self.composeToolbarView.characterCountLabel.font = .systemFont(ofSize: 24, weight: .bold)
|
||||
self.composeToolbarView.characterCountLabel.textColor = Asset.Colors.danger.color
|
||||
default:
|
||||
self.composeToolbarView.characterCountLabel.font = .systemFont(ofSize: 15, weight: .regular)
|
||||
self.composeToolbarView.characterCountLabel.textColor = Asset.Colors.Label.secondary.color
|
||||
}
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
// bind text editor for custom emojis update event
|
||||
viewModel.customEmojiViewModel
|
||||
.compactMap { $0?.emojis }
|
||||
.switchToLatest()
|
||||
|
@ -261,22 +305,24 @@ extension ComposeViewController {
|
|||
})
|
||||
.store(in: &disposeBag)
|
||||
|
||||
// bind image picker toolbar state
|
||||
viewModel.attachmentServices
|
||||
// bind custom emoji picker UI
|
||||
viewModel.customEmojiViewModel
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] attachmentServices in
|
||||
guard let self = self else { return }
|
||||
self.composeToolbarView.mediaButton.isEnabled = attachmentServices.count < 4
|
||||
self.resetImagePicker()
|
||||
.map { viewModel -> AnyPublisher<[Mastodon.Entity.Emoji], Never> in
|
||||
guard let viewModel = viewModel else {
|
||||
return Just([]).eraseToAnyPublisher()
|
||||
}
|
||||
return viewModel.emojis.eraseToAnyPublisher()
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
viewModel.selectedStatusVisibility
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] type in
|
||||
.switchToLatest()
|
||||
.sink(receiveValue: { [weak self] emojis in
|
||||
guard let self = self else { return }
|
||||
self.composeToolbarView.visibilityButton.setImage(type.image, for: .normal)
|
||||
}
|
||||
if emojis.isEmpty {
|
||||
self.customEmojiPickerInputView.activityIndicatorView.startAnimating()
|
||||
} else {
|
||||
self.customEmojiPickerInputView.activityIndicatorView.stopAnimating()
|
||||
}
|
||||
})
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
|
@ -317,6 +363,25 @@ extension ComposeViewController {
|
|||
textEditorView()?.isEditing = true
|
||||
}
|
||||
|
||||
private func contentWarningEditorTextView() -> UITextView? {
|
||||
guard let diffableDataSource = viewModel.diffableDataSource else { return nil }
|
||||
let items = diffableDataSource.snapshot().itemIdentifiers
|
||||
for item in items {
|
||||
switch item {
|
||||
case .input:
|
||||
guard let indexPath = diffableDataSource.indexPath(for: item),
|
||||
let cell = collectionView.cellForItem(at: indexPath) as? ComposeStatusContentCollectionViewCell else {
|
||||
continue
|
||||
}
|
||||
return cell.statusContentWarningEditorView.textView
|
||||
default:
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
private func pollOptionCollectionViewCell(of item: ComposeStatusItem) -> ComposeStatusPollOptionCollectionViewCell? {
|
||||
guard case .pollOption = item else { return nil }
|
||||
guard let diffableDataSource = viewModel.diffableDataSource else { return nil }
|
||||
|
@ -398,7 +463,7 @@ extension ComposeViewController {
|
|||
imagePicker.delegate = self
|
||||
return imagePicker
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
extension ComposeViewController {
|
||||
|
@ -587,6 +652,15 @@ extension ComposeViewController: TextEditorViewTextAttributesDelegate {
|
|||
attributedString.addAttributes(attributes, range: match.range)
|
||||
}
|
||||
|
||||
if string.count > ComposeViewModel.composeContentLimit {
|
||||
var attributes = [NSAttributedString.Key: Any]()
|
||||
attributes[.foregroundColor] = Asset.Colors.danger.color
|
||||
let boundStart = string.index(string.startIndex, offsetBy: ComposeViewModel.composeContentLimit)
|
||||
let boundEnd = string.endIndex
|
||||
let range = boundStart..<boundEnd
|
||||
attributedString.addAttributes(attributes, range: NSRange(range, in: string))
|
||||
}
|
||||
|
||||
completion(attributedString)
|
||||
}
|
||||
}
|
||||
|
@ -631,7 +705,20 @@ extension ComposeViewController: ComposeToolbarViewDelegate {
|
|||
}
|
||||
|
||||
func composeToolbarView(_ composeToolbarView: ComposeToolbarView, contentWarningButtonDidPressed sender: UIButton) {
|
||||
// restore first responder for text editor when content warning dismiss
|
||||
if viewModel.isContentWarningComposing.value {
|
||||
if contentWarningEditorTextView()?.isFirstResponder == true {
|
||||
markTextEditorViewBecomeFirstResponser()
|
||||
}
|
||||
}
|
||||
|
||||
// toggle composing status
|
||||
viewModel.isContentWarningComposing.value.toggle()
|
||||
|
||||
// active content warning after toggled
|
||||
if viewModel.isContentWarningComposing.value {
|
||||
contentWarningEditorTextView()?.becomeFirstResponder()
|
||||
}
|
||||
}
|
||||
|
||||
func composeToolbarView(_ composeToolbarView: ComposeToolbarView, visibilityButtonDidPressed sender: UIButton, visibilitySelectionType type: ComposeToolbarView.VisibilitySelectionType) {
|
||||
|
@ -773,6 +860,14 @@ extension ComposeViewController: ComposeStatusAttachmentCollectionViewCellDelega
|
|||
// MARK: - ComposeStatusPollOptionCollectionViewCellDelegate
|
||||
extension ComposeViewController: ComposeStatusPollOptionCollectionViewCellDelegate {
|
||||
|
||||
func composeStatusPollOptionCollectionViewCell(_ cell: ComposeStatusPollOptionCollectionViewCell, textFieldDidBeginEditing textField: UITextField) {
|
||||
// FIXME: make poll section visible
|
||||
// DispatchQueue.main.async {
|
||||
// self.collectionView.scroll(to: .bottom, animated: true)
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
// handle delete backward event for poll option input
|
||||
func composeStatusPollOptionCollectionViewCell(_ cell: ComposeStatusPollOptionCollectionViewCell, textBeforeDeleteBackward text: String?) {
|
||||
guard (text ?? "").isEmpty else { return }
|
||||
|
|
|
@ -55,7 +55,6 @@ extension ComposeViewModel {
|
|||
self.pollOptionAttributes.value = pollOptionAttributes
|
||||
}
|
||||
|
||||
|
||||
self.diffableDataSource = diffableDataSource
|
||||
var snapshot = NSDiffableDataSourceSnapshot<ComposeStatusSection, ComposeStatusItem>()
|
||||
snapshot.appendSections([.repliedTo, .status, .attachment, .poll])
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
// Created by MainasuK Cirno on 2021-3-11.
|
||||
//
|
||||
|
||||
import os.log
|
||||
import UIKit
|
||||
import Combine
|
||||
import CoreData
|
||||
|
@ -14,6 +15,8 @@ import MastodonSDK
|
|||
|
||||
final class ComposeViewModel {
|
||||
|
||||
static let composeContentLimit: Int = 500
|
||||
|
||||
var disposeBag = Set<AnyCancellable>()
|
||||
|
||||
// input
|
||||
|
@ -48,11 +51,13 @@ final class ComposeViewModel {
|
|||
let isPublishBarButtonItemEnabled = CurrentValueSubject<Bool, Never>(false)
|
||||
let isMediaToolbarButtonEnabled = CurrentValueSubject<Bool, Never>(true)
|
||||
let isPollToolbarButtonEnabled = CurrentValueSubject<Bool, Never>(true)
|
||||
let characterCount = CurrentValueSubject<Int, Never>(0)
|
||||
|
||||
// custom emojis
|
||||
var customEmojiViewModelSubscription: AnyCancellable?
|
||||
let customEmojiViewModel = CurrentValueSubject<EmojiService.CustomEmojiViewModel?, Never>(nil)
|
||||
let customEmojiPickerInputViewModel = CustomEmojiPickerInputViewModel()
|
||||
let isLoadingCustomEmoji = CurrentValueSubject<Bool, Never>(false)
|
||||
|
||||
// attachment
|
||||
let attachmentServices = CurrentValueSubject<[MastodonAttachmentService], Never>([])
|
||||
|
@ -109,10 +114,30 @@ final class ComposeViewModel {
|
|||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
// bind character count
|
||||
Publishers.CombineLatest3(
|
||||
composeStatusAttribute.composeContent.eraseToAnyPublisher(),
|
||||
composeStatusAttribute.isContentWarningComposing.eraseToAnyPublisher(),
|
||||
composeStatusAttribute.contentWarningContent.eraseToAnyPublisher()
|
||||
)
|
||||
.map { composeContent, isContentWarningComposing, contentWarningContent -> Int in
|
||||
let composeContent = composeContent ?? ""
|
||||
var count = composeContent.count
|
||||
if isContentWarningComposing {
|
||||
count += contentWarningContent.count
|
||||
}
|
||||
return count
|
||||
}
|
||||
.assign(to: \.value, on: characterCount)
|
||||
.store(in: &disposeBag)
|
||||
// bind compose bar button item UI state
|
||||
let isComposeContentEmpty = composeStatusAttribute.composeContent
|
||||
.map { ($0 ?? "").isEmpty }
|
||||
let isComposeContentValid = Just(true).eraseToAnyPublisher()
|
||||
let isComposeContentValid = composeStatusAttribute.composeContent
|
||||
.map { composeContent -> Bool in
|
||||
let composeContent = composeContent ?? ""
|
||||
return composeContent.count <= ComposeViewModel.composeContentLimit
|
||||
}
|
||||
let isMediaEmpty = attachmentServices
|
||||
.map { $0.isEmpty }
|
||||
let isMediaUploadAllSuccess = attachmentServices
|
||||
|
@ -278,6 +303,10 @@ final class ComposeViewModel {
|
|||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
deinit {
|
||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ComposeViewModel {
|
||||
|
@ -301,6 +330,6 @@ extension ComposeViewModel: MastodonAttachmentServiceDelegate {
|
|||
extension ComposeViewModel: ComposePollAttributeDelegate {
|
||||
func composePollAttribute(_ attribute: ComposeStatusItem.ComposePollOptionAttribute, pollOptionDidChange: String?) {
|
||||
// trigger update
|
||||
pollOptionAttributes.value = pollOptionAttributes.value
|
||||
// pollOptionAttributes.value = pollOptionAttributes.value
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,6 +59,14 @@ final class ComposeToolbarView: UIView {
|
|||
return button
|
||||
}()
|
||||
|
||||
let characterCountLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .systemFont(ofSize: 15, weight: .regular)
|
||||
label.text = "500"
|
||||
label.textColor = Asset.Colors.Label.secondary.color
|
||||
return label
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
_init()
|
||||
|
@ -102,6 +110,16 @@ extension ComposeToolbarView {
|
|||
])
|
||||
}
|
||||
|
||||
characterCountLabel.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(characterCountLabel)
|
||||
NSLayoutConstraint.activate([
|
||||
characterCountLabel.topAnchor.constraint(equalTo: topAnchor),
|
||||
characterCountLabel.leadingAnchor.constraint(greaterThanOrEqualTo: stackView.trailingAnchor, constant: 8),
|
||||
characterCountLabel.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor),
|
||||
characterCountLabel.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||
])
|
||||
characterCountLabel.setContentHuggingPriority(.defaultHigh, for: .horizontal)
|
||||
|
||||
mediaButton.menu = createMediaContextMenu()
|
||||
mediaButton.showsMenuAsPrimaryAction = true
|
||||
pollButton.addTarget(self, action: #selector(ComposeToolbarView.pollButtonDidPressed(_:)), for: .touchUpInside)
|
||||
|
|
|
@ -17,6 +17,8 @@ final class CustomEmojiPickerInputView: UIInputView {
|
|||
return collectionView
|
||||
}()
|
||||
|
||||
let activityIndicatorView = UIActivityIndicatorView(style: .large)
|
||||
|
||||
override init(frame: CGRect, inputViewStyle: UIInputView.Style) {
|
||||
super.init(frame: frame, inputViewStyle: inputViewStyle)
|
||||
_init()
|
||||
|
@ -33,6 +35,13 @@ extension CustomEmojiPickerInputView {
|
|||
private func _init() {
|
||||
allowsSelfSizing = true
|
||||
|
||||
activityIndicatorView.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(activityIndicatorView)
|
||||
NSLayoutConstraint.activate([
|
||||
activityIndicatorView.centerXAnchor.constraint(equalTo: centerXAnchor),
|
||||
activityIndicatorView.centerYAnchor.constraint(equalTo: centerYAnchor),
|
||||
])
|
||||
|
||||
collectionView.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(collectionView)
|
||||
NSLayoutConstraint.activate([
|
||||
|
@ -41,6 +50,9 @@ extension CustomEmojiPickerInputView {
|
|||
collectionView.trailingAnchor.constraint(equalTo: trailingAnchor),
|
||||
collectionView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||
])
|
||||
|
||||
activityIndicatorView.hidesWhenStopped = true
|
||||
activityIndicatorView.startAnimating()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ final class HomeTimelineNavigationBarView {
|
|||
}()
|
||||
|
||||
static let offlineView: UIView = {
|
||||
let view = HomeTimelineNavigationBarView.backgroundViewWithColor(color: Asset.Colors.lightDangerRed.color)
|
||||
let view = HomeTimelineNavigationBarView.backgroundViewWithColor(color: Asset.Colors.danger.color)
|
||||
let label = HomeTimelineNavigationBarView.contentLabel(text: L10n.Scene.HomeTimeline.NavigationBarState.offline)
|
||||
HomeTimelineNavigationBarView.addLabelToView(label: label, view: view)
|
||||
return view
|
||||
|
|
|
@ -106,7 +106,7 @@ final class MastodonRegisterViewController: UIViewController, NeedsDependency, O
|
|||
|
||||
let usernameErrorPromptLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
let color = Asset.Colors.lightDangerRed.color
|
||||
let color = Asset.Colors.danger.color
|
||||
let font = UIFont.preferredFont(forTextStyle: .caption1)
|
||||
return label
|
||||
}()
|
||||
|
@ -146,7 +146,7 @@ final class MastodonRegisterViewController: UIViewController, NeedsDependency, O
|
|||
|
||||
let emailErrorPromptLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
let color = Asset.Colors.lightDangerRed.color
|
||||
let color = Asset.Colors.danger.color
|
||||
let font = UIFont.preferredFont(forTextStyle: .caption1)
|
||||
return label
|
||||
}()
|
||||
|
@ -177,7 +177,7 @@ final class MastodonRegisterViewController: UIViewController, NeedsDependency, O
|
|||
|
||||
let passwordErrorPromptLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
let color = Asset.Colors.lightDangerRed.color
|
||||
let color = Asset.Colors.danger.color
|
||||
let font = UIFont.preferredFont(forTextStyle: .caption1)
|
||||
return label
|
||||
}()
|
||||
|
@ -201,7 +201,7 @@ final class MastodonRegisterViewController: UIViewController, NeedsDependency, O
|
|||
|
||||
let reasonErrorPromptLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
let color = Asset.Colors.lightDangerRed.color
|
||||
let color = Asset.Colors.danger.color
|
||||
let font = UIFont.preferredFont(forTextStyle: .caption1)
|
||||
return label
|
||||
}()
|
||||
|
|
|
@ -198,10 +198,10 @@ extension MastodonRegisterViewModel {
|
|||
let attributeString = NSMutableAttributedString()
|
||||
|
||||
let image = MastodonRegisterViewModel.xmarkImage(font: font)
|
||||
attributeString.append(attributedStringImage(with: image, tintColor: Asset.Colors.lightDangerRed.color))
|
||||
attributeString.append(attributedStringImage(with: image, tintColor: Asset.Colors.danger.color))
|
||||
attributeString.append(NSAttributedString(string: " "))
|
||||
|
||||
let promptAttributedString = NSAttributedString(string: prompt, attributes: [NSAttributedString.Key.font: font, NSAttributedString.Key.foregroundColor: Asset.Colors.lightDangerRed.color])
|
||||
let promptAttributedString = NSAttributedString(string: prompt, attributes: [NSAttributedString.Key.font: font, NSAttributedString.Key.foregroundColor: Asset.Colors.danger.color])
|
||||
attributeString.append(promptAttributedString)
|
||||
|
||||
return attributeString
|
||||
|
|
Loading…
Reference in New Issue