mirror of
https://github.com/metabolist/metatext.git
synced 2024-05-19 08:48:12 +00:00
Merge branch 'develop' into labels-in-tab-bar
This commit is contained in:
commit
1201a342c6
|
@ -207,6 +207,7 @@
|
|||
"preferences.app.color-scheme.system" = "System";
|
||||
"preferences.blocked-domains" = "Blocked Domains";
|
||||
"preferences.blocked-users" = "Blocked Users";
|
||||
"preferences.edge-to-edge-view" = "Edge to edge view";
|
||||
"preferences.media" = "Media";
|
||||
"preferences.show-labels-in-tab-bar" = "Show labels in tab bar (requires restart)";
|
||||
"preferences.media.avatars" = "Avatars";
|
||||
|
@ -236,6 +237,7 @@
|
|||
"preferences.notification-types" = "Notification Types";
|
||||
"preferences.notification-types.follow" = "Follow";
|
||||
"preferences.notification-types.favourite" = "Favorite";
|
||||
"preferences.notification-types.like" = "Like";
|
||||
"preferences.notification-types.follow-request" = "Follow Request";
|
||||
"preferences.notification-types.reblog" = "Reblog";
|
||||
"preferences.notification-types.mention" = "Mention";
|
||||
|
@ -254,6 +256,7 @@
|
|||
"preferences.require-double-tap-to-favorite" = "Require double tap to favorite";
|
||||
"preferences.show-reblog-and-favorite-counts" = "Show boost and favorite counts";
|
||||
"preferences.status-word" = "Status word";
|
||||
"preferences.display-favorites-as" = "Display favorites as";
|
||||
"filters.active" = "Active";
|
||||
"filters.expired" = "Expired";
|
||||
"filter.add-new" = "Add New Filter";
|
||||
|
@ -280,6 +283,7 @@
|
|||
"notifications" = "Notifications";
|
||||
"notifications.reblogged-your-status-%@" = "%@ boosted your status";
|
||||
"notifications.favourited-your-status-%@" = "%@ favorited your status";
|
||||
"notifications.liked-your-status-%@" = "%@ liked your status";
|
||||
"notifications.followed-you-%@" = "%@ followed you";
|
||||
"notifications.poll-ended" = "A poll you have voted in has ended";
|
||||
"notifications.your-poll-ended" = "Your poll has ended";
|
||||
|
@ -312,8 +316,11 @@
|
|||
"status.delete.confirm.post" = "Are you sure you want to delete this post?";
|
||||
"status.delete.confirm.toot" = "Are you sure you want to delete this toot?";
|
||||
"status.delete-and-redraft" = "Delete & re-draft";
|
||||
"status.delete-and-redraft.confirm.post" = "Are you sure you want to delete this post and re-draft it? Favorites and boosts will be lost, and replies to the original post will be orphaned.";
|
||||
"status.delete-and-redraft.confirm.toot" = "Are you sure you want to delete this toot and re-draft it? Favorites and boosts will be lost, and replies to the original toot will be orphaned.";
|
||||
"status.delete-and-redraft.confirm.post-favorites" = "Are you sure you want to delete this post and re-draft it? Favorites and boosts will be lost, and replies to the original post will be orphaned.";
|
||||
"status.delete-and-redraft.confirm.toot-favorites" = "Are you sure you want to delete this toot and re-draft it? Favorites and boosts will be lost, and replies to the original toot will be orphaned.";
|
||||
"status.delete-and-redraft.confirm.post-likes" = "Are you sure you want to delete this post and re-draft it? Likes and boosts will be lost, and replies to the original post will be orphaned.";
|
||||
"status.delete-and-redraft.confirm.toot-likes" = "Are you sure you want to delete this toot and re-draft it? Likes and boosts will be lost, and replies to the original toot will be orphaned.";
|
||||
|
||||
"status.mute" = "Mute conversation";
|
||||
"status.new-items.post" = "New posts";
|
||||
"status.new-items.toot" = "New toots";
|
||||
|
@ -332,6 +339,8 @@
|
|||
"status.reblog-button.undo.accessibility-label" = "Unboost";
|
||||
"status.favorite-button.accessibility-label" = "Favorite";
|
||||
"status.favorite-button.undo.accessibility-label" = "Unfavorite";
|
||||
"status.like-button.accessibility-label" = "Like";
|
||||
"status.like-button.undo.accessibility-label" = "Unlike";
|
||||
"status.show-more" = "Show More";
|
||||
"status.show-more-all-button.accessibilty-label" = "Show more for all";
|
||||
"status.show-less" = "Show Less";
|
||||
|
@ -357,3 +366,4 @@
|
|||
"timelines.local" = "Local";
|
||||
"timelines.federated" = "Federated";
|
||||
"toot" = "Toot";
|
||||
"likes" = "Likes";
|
||||
|
|
|
@ -66,6 +66,22 @@
|
|||
<string>%ld Favorites</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>status.likes-count-%ld</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@likes@</string>
|
||||
<key>likes</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>ld</string>
|
||||
<key>one</key>
|
||||
<string>%ld Like</string>
|
||||
<key>other</key>
|
||||
<string>%ld Likes</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>status.replies-count-%ld</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
|
|
|
@ -32,6 +32,13 @@ public extension AppPreferences {
|
|||
public var id: String { rawValue }
|
||||
}
|
||||
|
||||
enum DisplayFavoritesAs: String, CaseIterable, Identifiable {
|
||||
case favorites
|
||||
case likes
|
||||
|
||||
public var id: String { rawValue }
|
||||
}
|
||||
|
||||
enum AnimateAvatars: String, CaseIterable, Identifiable {
|
||||
case everywhere
|
||||
case profiles
|
||||
|
@ -79,6 +86,18 @@ public extension AppPreferences {
|
|||
set { self[.statusWord] = newValue.rawValue }
|
||||
}
|
||||
|
||||
var displayFavoritesAs: DisplayFavoritesAs {
|
||||
get {
|
||||
if let rawValue = self[.displayFavoritesAs] as String?,
|
||||
let value = DisplayFavoritesAs(rawValue: rawValue) {
|
||||
return value
|
||||
}
|
||||
|
||||
return .favorites
|
||||
}
|
||||
set { self[.displayFavoritesAs] = newValue.rawValue }
|
||||
}
|
||||
|
||||
var animateAvatars: AnimateAvatars {
|
||||
get {
|
||||
if let rawValue = self[.animateAvatars] as String?,
|
||||
|
@ -171,6 +190,11 @@ public extension AppPreferences {
|
|||
get { self[.showReblogAndFavoriteCounts] ?? false }
|
||||
set { self[.showReblogAndFavoriteCounts] = newValue }
|
||||
}
|
||||
|
||||
var edgeToEdgeView: Bool {
|
||||
get { self[.edgeToEdgeView] ?? false }
|
||||
set { self[.edgeToEdgeView] = newValue }
|
||||
}
|
||||
|
||||
var requireDoubleTapToReblog: Bool {
|
||||
get { self[.requireDoubleTapToReblog] ?? false }
|
||||
|
@ -212,6 +236,7 @@ private extension AppPreferences {
|
|||
enum Item: String {
|
||||
case colorScheme
|
||||
case statusWord
|
||||
case displayFavoritesAs
|
||||
case requireDoubleTapToReblog
|
||||
case requireDoubleTapToFavorite
|
||||
case animateAvatars
|
||||
|
@ -229,6 +254,7 @@ private extension AppPreferences {
|
|||
case openLinksInDefaultBrowser
|
||||
case useUniversalLinks
|
||||
case showLabelsInTabBar
|
||||
case edgeToEdgeView
|
||||
}
|
||||
|
||||
subscript<T>(index: Item) -> T? {
|
||||
|
|
|
@ -687,12 +687,17 @@ private extension TableViewController {
|
|||
let deleteAndRedraftConfirmMessage: String
|
||||
let deleteConfirmMessage: String
|
||||
|
||||
let favoritesNoun = viewModel.identityContext.appPreferences.displayFavoritesAs.rawValue
|
||||
|
||||
switch viewModel.identityContext.appPreferences.statusWord {
|
||||
case .toot:
|
||||
deleteAndRedraftConfirmMessage = NSLocalizedString("status.delete-and-redraft.confirm.toot", comment: "")
|
||||
deleteAndRedraftConfirmMessage = NSLocalizedString(
|
||||
"status.delete-and-redraft.confirm.toot-".appending(favoritesNoun),
|
||||
comment: "")
|
||||
deleteConfirmMessage = NSLocalizedString("status.delete.confirm.toot", comment: "")
|
||||
case .post:
|
||||
deleteAndRedraftConfirmMessage = NSLocalizedString("status.delete-and-redraft.confirm.post", comment: "")
|
||||
deleteAndRedraftConfirmMessage = NSLocalizedString(
|
||||
"status.delete-and-redraft.confirm.post-".appending(favoritesNoun), comment: "")
|
||||
deleteConfirmMessage = NSLocalizedString("status.delete.confirm.post", comment: "")
|
||||
}
|
||||
|
||||
|
|
|
@ -101,6 +101,14 @@ struct PreferencesView: View {
|
|||
Text(option.localizedStringKey).tag(option)
|
||||
}
|
||||
}
|
||||
Toggle("preferences.edge-to-edge-view",
|
||||
isOn: $identityContext.appPreferences.edgeToEdgeView)
|
||||
Picker("preferences.display-favorites-as",
|
||||
selection: $identityContext.appPreferences.displayFavoritesAs) {
|
||||
ForEach(AppPreferences.DisplayFavoritesAs.allCases) { option in
|
||||
Text(option.localizedStringKey).tag(option)
|
||||
}
|
||||
}
|
||||
Toggle("preferences.show-reblog-and-favorite-counts",
|
||||
isOn: $identityContext.appPreferences.showReblogAndFavoriteCounts)
|
||||
Toggle("preferences.require-double-tap-to-reblog",
|
||||
|
@ -184,6 +192,17 @@ extension AppPreferences.StatusWord {
|
|||
}
|
||||
}
|
||||
|
||||
extension AppPreferences.DisplayFavoritesAs {
|
||||
var localizedStringKey: LocalizedStringKey {
|
||||
switch self {
|
||||
case .favorites:
|
||||
return "favorites"
|
||||
case .likes:
|
||||
return "likes"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension AppPreferences.AnimateAvatars {
|
||||
var localizedStringKey: LocalizedStringKey {
|
||||
switch self {
|
||||
|
|
|
@ -15,6 +15,7 @@ final class AttachmentsView: UIView {
|
|||
private let hideButton = UIButton()
|
||||
private var aspectRatioConstraint: NSLayoutConstraint?
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
var identityContext: IdentityContext?
|
||||
|
||||
var viewModel: AttachmentsRenderingViewModel? {
|
||||
didSet {
|
||||
|
@ -104,7 +105,7 @@ final class AttachmentsView: UIView {
|
|||
|
||||
initialSetup()
|
||||
}
|
||||
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
|
@ -126,6 +127,11 @@ extension AttachmentsView {
|
|||
|
||||
return height
|
||||
}
|
||||
|
||||
func displayEdgeToEdge(_ edgeToEdge: Bool) {
|
||||
layer.cornerRadius = edgeToEdge ? 0 : .defaultCornerRadius
|
||||
}
|
||||
|
||||
var shouldAutoplay: Bool {
|
||||
guard !isHidden, let viewModel = viewModel, viewModel.shouldShowAttachments else { return false }
|
||||
|
||||
|
@ -148,10 +154,11 @@ extension AttachmentsView {
|
|||
private extension AttachmentsView {
|
||||
// swiftlint:disable:next function_body_length
|
||||
func initialSetup() {
|
||||
let isEdgeToEdge = identityContext?.appPreferences.edgeToEdgeView ?? false
|
||||
backgroundColor = .clear
|
||||
layoutMargins = .zero
|
||||
clipsToBounds = true
|
||||
layer.cornerRadius = .defaultCornerRadius
|
||||
layer.cornerRadius = isEdgeToEdge ? 0 : .defaultCornerRadius
|
||||
addSubview(containerStackView)
|
||||
containerStackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
containerStackView.distribution = .fillEqually
|
||||
|
|
|
@ -88,7 +88,7 @@ private extension CompositionView {
|
|||
parentViewModel: parentViewModel,
|
||||
autocompleteQueryPublisher: viewModel.$contentWarningAutocompleteQuery.eraseToAnyPublisher())
|
||||
|
||||
stackView.addArrangedSubview(spoilerTextField)
|
||||
stackView.addSubview(spoilerTextField)
|
||||
spoilerTextField.borderStyle = .roundedRect
|
||||
spoilerTextField.adjustsFontForContentSizeCategory = true
|
||||
spoilerTextField.font = .preferredFont(forTextStyle: .body)
|
||||
|
@ -106,7 +106,7 @@ private extension CompositionView {
|
|||
parentViewModel: parentViewModel,
|
||||
autocompleteQueryPublisher: viewModel.$autocompleteQuery.eraseToAnyPublisher())
|
||||
|
||||
stackView.addArrangedSubview(textView)
|
||||
addSubview(textView)
|
||||
textView.keyboardType = .twitter
|
||||
textView.isScrollEnabled = false
|
||||
textView.adjustsFontForContentSizeCategory = true
|
||||
|
@ -125,6 +125,7 @@ private extension CompositionView {
|
|||
textViewPlaceholder.textColor = .secondaryLabel
|
||||
textViewPlaceholder.text = NSLocalizedString("compose.prompt", comment: "")
|
||||
|
||||
attachmentsView.displayEdgeToEdge(parentViewModel.identityContext.appPreferences.edgeToEdgeView)
|
||||
stackView.addArrangedSubview(attachmentsView)
|
||||
attachmentsView.isHidden_stackViewSafe = true
|
||||
stackView.addArrangedSubview(attachmentUploadsStackView)
|
||||
|
@ -282,8 +283,8 @@ private extension CompositionView {
|
|||
changeIdentityButton.bottomAnchor.constraint(equalTo: avatarImageView.bottomAnchor),
|
||||
changeIdentityButton.trailingAnchor.constraint(equalTo: avatarImageView.trailingAnchor),
|
||||
stackView.leadingAnchor.constraint(equalTo: avatarImageView.trailingAnchor, constant: .defaultSpacing),
|
||||
stackView.topAnchor.constraint(greaterThanOrEqualTo: guide.topAnchor),
|
||||
stackView.bottomAnchor.constraint(lessThanOrEqualTo: guide.bottomAnchor),
|
||||
// stackView.topAnchor.constraint(greaterThanOrEqualTo: guide.topAnchor),
|
||||
// stackView.bottomAnchor.constraint(lessThanOrEqualTo: guide.bottomAnchor),
|
||||
textViewPlaceholder.leadingAnchor.constraint(equalTo: textView.leadingAnchor),
|
||||
textViewPlaceholder.topAnchor.constraint(equalTo: textView.topAnchor),
|
||||
textViewPlaceholder.trailingAnchor.constraint(equalTo: textView.trailingAnchor),
|
||||
|
|
|
@ -163,9 +163,36 @@ private extension NotificationView {
|
|||
isAccessibilityElement = true
|
||||
}
|
||||
|
||||
var colorForFavoriteView: UIColor {
|
||||
switch notificationConfiguration.viewModel.identityContext.appPreferences.displayFavoritesAs {
|
||||
case .favorites:
|
||||
return .systemYellow
|
||||
case .likes:
|
||||
return .systemRed
|
||||
}
|
||||
}
|
||||
|
||||
var labelForFavoriteView: String {
|
||||
switch notificationConfiguration.viewModel.identityContext.appPreferences.displayFavoritesAs {
|
||||
case .favorites:
|
||||
return "notifications.favourited-your-status-%@"
|
||||
case .likes:
|
||||
return "notifications.liked-your-status-%@"
|
||||
}
|
||||
}
|
||||
|
||||
var imageNameForFavoriteView: String {
|
||||
switch notificationConfiguration.viewModel.identityContext.appPreferences.displayFavoritesAs {
|
||||
case .favorites:
|
||||
return "star.fill"
|
||||
case .likes:
|
||||
return "heart.fill"
|
||||
}
|
||||
}
|
||||
|
||||
func applyNotificationConfiguration() {
|
||||
let viewModel = notificationConfiguration.viewModel
|
||||
|
||||
var imageName = viewModel.type.systemImageName
|
||||
avatarImageView.sd_setImage(with: viewModel.accountViewModel.avatarURL())
|
||||
|
||||
switch viewModel.type {
|
||||
|
@ -184,12 +211,13 @@ private extension NotificationView {
|
|||
identityContext: viewModel.identityContext)
|
||||
iconImageView.tintColor = .systemGreen
|
||||
case .favourite:
|
||||
typeLabel.attributedText = "notifications.favourited-your-status-%@".localizedBolding(
|
||||
imageName = imageNameForFavoriteView
|
||||
typeLabel.attributedText = labelForFavoriteView.localizedBolding(
|
||||
displayName: viewModel.accountViewModel.displayName,
|
||||
emojis: viewModel.accountViewModel.emojis,
|
||||
label: typeLabel,
|
||||
identityContext: viewModel.identityContext)
|
||||
iconImageView.tintColor = .systemYellow
|
||||
iconImageView.tintColor = colorForFavoriteView
|
||||
case .poll:
|
||||
typeLabel.text = NSLocalizedString(
|
||||
viewModel.accountViewModel.isSelf
|
||||
|
@ -229,7 +257,7 @@ private extension NotificationView {
|
|||
timeLabel.accessibilityLabel = viewModel.accessibilityTime
|
||||
|
||||
iconImageView.image = UIImage(
|
||||
systemName: viewModel.type.systemImageName,
|
||||
systemName: imageName,
|
||||
withConfiguration: UIImage.SymbolConfiguration(scale: .medium))
|
||||
|
||||
let accessibilityAttributedLabel = NSMutableAttributedString(string: "")
|
||||
|
|
|
@ -18,6 +18,7 @@ final class StatusView: UIView {
|
|||
let accountLabel = UILabel()
|
||||
let nameButton = UIButton()
|
||||
let timeLabel = UILabel()
|
||||
let timeSeparatorLabel = UILabel()
|
||||
let bodyView = StatusBodyView()
|
||||
let showThreadIndicator = UIButton(type: .system)
|
||||
let contextParentTimeLabel = UILabel()
|
||||
|
@ -39,6 +40,7 @@ final class StatusView: UIView {
|
|||
private let avatarContainerView = UIView()
|
||||
private let nameAccountContainerStackView = UIStackView()
|
||||
private let nameAccountTimeStackView = UIStackView()
|
||||
private let nameTimeStackView = UIStackView()
|
||||
private let contextParentTimeApplicationStackView = UIStackView()
|
||||
private let timeVisibilityDividerLabel = UILabel()
|
||||
private let visibilityApplicationDividerLabel = UILabel()
|
||||
|
@ -211,14 +213,21 @@ private extension StatusView {
|
|||
displayNameLabel.setContentHuggingPriority(.required, for: .horizontal)
|
||||
displayNameLabel.setContentHuggingPriority(.required, for: .vertical)
|
||||
displayNameLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
|
||||
nameAccountTimeStackView.addArrangedSubview(displayNameLabel)
|
||||
// nameTimeStackView.addArrangedSubview(displayNameLabel)
|
||||
|
||||
accountLabel.font = .preferredFont(forTextStyle: .subheadline)
|
||||
accountLabel.adjustsFontForContentSizeCategory = true
|
||||
accountLabel.textColor = .secondaryLabel
|
||||
accountLabel.setContentHuggingPriority(.required, for: .horizontal)
|
||||
accountLabel.setContentHuggingPriority(.required, for: .vertical)
|
||||
nameAccountTimeStackView.addArrangedSubview(accountLabel)
|
||||
|
||||
timeSeparatorLabel.text = "∙ "
|
||||
timeSeparatorLabel.font = .preferredFont(forTextStyle: .subheadline)
|
||||
timeSeparatorLabel.adjustsFontForContentSizeCategory = true
|
||||
timeSeparatorLabel.textColor = .secondaryLabel
|
||||
timeSeparatorLabel.textAlignment = .right
|
||||
timeSeparatorLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
|
||||
timeSeparatorLabel.setContentHuggingPriority(.required, for: .vertical)
|
||||
|
||||
timeLabel.font = .preferredFont(forTextStyle: .subheadline)
|
||||
timeLabel.adjustsFontForContentSizeCategory = true
|
||||
|
@ -226,10 +235,14 @@ private extension StatusView {
|
|||
timeLabel.textAlignment = .right
|
||||
timeLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
|
||||
timeLabel.setContentHuggingPriority(.required, for: .vertical)
|
||||
nameAccountTimeStackView.addArrangedSubview(timeLabel)
|
||||
nameTimeStackView.addArrangedSubview(displayNameLabel)
|
||||
nameTimeStackView.addArrangedSubview(timeSeparatorLabel)
|
||||
nameTimeStackView.addArrangedSubview(timeLabel)
|
||||
|
||||
nameAccountTimeStackView.addArrangedSubview(nameTimeStackView)
|
||||
nameAccountContainerStackView.spacing = .defaultSpacing
|
||||
nameAccountContainerStackView.addArrangedSubview(nameAccountTimeStackView)
|
||||
nameAccountTimeStackView.addArrangedSubview(accountLabel)
|
||||
mainStackView.addArrangedSubview(nameAccountContainerStackView)
|
||||
|
||||
nameButton.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
@ -451,6 +464,15 @@ private extension StatusView {
|
|||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
var favoriteCountLabel: String {
|
||||
switch statusConfiguration.viewModel.identityContext.appPreferences.displayFavoritesAs {
|
||||
case .favorites:
|
||||
return "status.favorites-count-%ld"
|
||||
case .likes:
|
||||
return "status.likes-count-%ld"
|
||||
}
|
||||
}
|
||||
|
||||
func applyStatusConfiguration() {
|
||||
let viewModel = statusConfiguration.viewModel
|
||||
let isContextParent = viewModel.configuration.isContextParent
|
||||
|
@ -475,7 +497,10 @@ private extension StatusView {
|
|||
rebloggerAvatarImageView.isHidden = !viewModel.isReblog
|
||||
rebloggerAvatarImageView.sd_setImage(with: viewModel.isReblog ? viewModel.rebloggerAvatarURL : nil)
|
||||
|
||||
if isContextParent, avatarContainerView.superview !== nameAccountContainerStackView {
|
||||
if viewModel.identityContext.appPreferences.edgeToEdgeView {
|
||||
nameAccountContainerStackView.insertArrangedSubview(avatarContainerView, at: 0)
|
||||
sideStackView.isHidden = true
|
||||
} else if isContextParent, avatarContainerView.superview !== nameAccountContainerStackView {
|
||||
nameAccountContainerStackView.insertArrangedSubview(avatarContainerView, at: 0)
|
||||
} else if avatarContainerView.superview !== sideStackView {
|
||||
sideStackView.insertArrangedSubview(avatarContainerView, at: 1)
|
||||
|
@ -553,9 +578,9 @@ private extension StatusView {
|
|||
nameButtonAccessibilityAttributedLabel.appendWithSeparator(viewModel.accountName)
|
||||
nameButton.accessibilityAttributedLabel = nameButtonAccessibilityAttributedLabel
|
||||
|
||||
nameAccountTimeStackView.axis = isContextParent ? .vertical : .horizontal
|
||||
nameAccountTimeStackView.alignment = isContextParent ? .leading : .fill
|
||||
nameAccountTimeStackView.spacing = isContextParent ? 0 : .compactSpacing
|
||||
nameAccountTimeStackView.axis = .vertical
|
||||
nameAccountTimeStackView.alignment = .leading
|
||||
nameAccountTimeStackView.spacing = 0
|
||||
|
||||
contextParentTopNameAccountSpacingView.removeFromSuperview()
|
||||
contextParentBottomNameAccountSpacingView.removeFromSuperview()
|
||||
|
@ -571,6 +596,8 @@ private extension StatusView {
|
|||
timeLabel.accessibilityLabel = viewModel.accessibilityTime
|
||||
timeLabel.isHidden = isContextParent
|
||||
|
||||
timeSeparatorLabel.isHidden = isContextParent
|
||||
|
||||
bodyView.viewModel = viewModel
|
||||
|
||||
showThreadIndicator.isHidden = !viewModel.configuration.isReplyOutOfContext
|
||||
|
@ -593,8 +620,9 @@ private extension StatusView {
|
|||
localizationKey: "status.reblogs-count-%ld",
|
||||
count: viewModel.reblogsCount)
|
||||
rebloggedByButton.isHidden = noReblogs
|
||||
|
||||
favoritedByButton.setAttributedLocalizedTitle(
|
||||
localizationKey: "status.favorites-count-%ld",
|
||||
localizationKey: favoriteCountLabel,
|
||||
count: viewModel.favoritesCount)
|
||||
favoritedByButton.isHidden = noFavorites
|
||||
|
||||
|
@ -822,7 +850,7 @@ private extension StatusView {
|
|||
if statusConfiguration.viewModel.favoritesCount > 0 {
|
||||
accessibilityAttributedLabel.appendWithSeparator(
|
||||
String.localizedStringWithFormat(
|
||||
NSLocalizedString("status.favorites-count-%ld", comment: ""),
|
||||
NSLocalizedString(favoriteCountLabel, comment: ""),
|
||||
statusConfiguration.viewModel.favoritesCount))
|
||||
}
|
||||
}
|
||||
|
@ -835,10 +863,24 @@ private extension StatusView {
|
|||
return accessibilityAttributedLabel
|
||||
}
|
||||
|
||||
var favoriteIcon: String {
|
||||
switch statusConfiguration.viewModel.identityContext.appPreferences.displayFavoritesAs {
|
||||
case .favorites: return "star"
|
||||
case .likes: return "heart"
|
||||
}
|
||||
}
|
||||
|
||||
var favoritedIcon: String {
|
||||
switch statusConfiguration.viewModel.identityContext.appPreferences.displayFavoritesAs {
|
||||
case .favorites: return "star.fill"
|
||||
case .likes: return "heart.fill"
|
||||
}
|
||||
}
|
||||
|
||||
func setButtonImages(font: UIFont) {
|
||||
let visibility = statusConfiguration.viewModel.visibility
|
||||
let reblogSystemImageName: String
|
||||
|
||||
let isFavorited = statusConfiguration.viewModel.favorited
|
||||
if statusConfiguration.viewModel.configuration.isContextParent {
|
||||
reblogSystemImageName = "arrow.2.squarepath"
|
||||
} else {
|
||||
|
@ -858,7 +900,7 @@ private extension StatusView {
|
|||
pointSize: font.pointSize,
|
||||
weight: statusConfiguration.viewModel.reblogged ? .bold : .regular)),
|
||||
for: .normal)
|
||||
favoriteButton.setImage(UIImage(systemName: statusConfiguration.viewModel.favorited ? "star.fill" : "star",
|
||||
favoriteButton.setImage(UIImage(systemName: isFavorited ? favoritedIcon : favoriteIcon,
|
||||
withConfiguration: UIImage.SymbolConfiguration(pointSize: font.pointSize)),
|
||||
for: .normal)
|
||||
shareButton.setImage(UIImage(systemName: "square.and.arrow.up",
|
||||
|
@ -905,17 +947,29 @@ private extension StatusView {
|
|||
}
|
||||
|
||||
func setFavoriteButtonColor(favorited: Bool) {
|
||||
let favoriteColor: UIColor = favorited ? .systemYellow : .secondaryLabel
|
||||
var favoriteColor: UIColor
|
||||
var favoriteLabel: String
|
||||
var undoFavoriteLabel: String
|
||||
switch statusConfiguration.viewModel.identityContext.appPreferences.displayFavoritesAs {
|
||||
case .favorites:
|
||||
favoriteColor = favorited ? .systemYellow : .secondaryLabel
|
||||
favoriteLabel = "status.favorite-button.undo.accessibility-label"
|
||||
undoFavoriteLabel = "status.favorite-button.accessibility-label"
|
||||
case .likes:
|
||||
favoriteColor = favorited ? .systemRed : .secondaryLabel
|
||||
favoriteLabel = "status.like-button.undo.accessibility-label"
|
||||
undoFavoriteLabel = "status.like-button.accessibility-label"
|
||||
}
|
||||
|
||||
favoriteButton.tintColor = favoriteColor
|
||||
favoriteButton.setTitleColor(favoriteColor, for: .normal)
|
||||
|
||||
if favorited {
|
||||
favoriteButton.accessibilityLabel =
|
||||
NSLocalizedString("status.favorite-button.undo.accessibility-label", comment: "")
|
||||
NSLocalizedString(undoFavoriteLabel, comment: "")
|
||||
} else {
|
||||
favoriteButton.accessibilityLabel =
|
||||
NSLocalizedString("status.favorite-button.accessibility-label", comment: "")
|
||||
NSLocalizedString(favoriteLabel, comment: "")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -938,20 +992,47 @@ private extension StatusView {
|
|||
statusConfiguration.viewModel.toggleReblogged()
|
||||
}
|
||||
|
||||
func animateFavorite() {
|
||||
switch statusConfiguration.viewModel.identityContext.appPreferences.displayFavoritesAs {
|
||||
|
||||
case .favorites:
|
||||
self.animateAsFavorite()
|
||||
case .likes:
|
||||
self.animateAsLike()
|
||||
}
|
||||
}
|
||||
|
||||
func animateAsFavorite() {
|
||||
UIViewPropertyAnimator.runningPropertyAnimator(
|
||||
withDuration: .defaultAnimationDuration,
|
||||
delay: 0,
|
||||
options: .curveLinear) {
|
||||
self.setFavoriteButtonColor(favorited: !self.statusConfiguration.viewModel.favorited)
|
||||
self.favoriteButton.imageView?.transform =
|
||||
self.favoriteButton.imageView?.transform.rotated(by: .pi) ?? .identity
|
||||
} completion: { _ in
|
||||
self.favoriteButton.imageView?.transform = .identity
|
||||
}
|
||||
}
|
||||
|
||||
func animateAsLike() {
|
||||
UIViewPropertyAnimator.runningPropertyAnimator(
|
||||
withDuration: .defaultAnimationDuration,
|
||||
delay: 0,
|
||||
options: .curveEaseInOut) {
|
||||
self.setFavoriteButtonColor(favorited: !self.statusConfiguration.viewModel.favorited)
|
||||
self.favoriteButton.imageView?.transform =
|
||||
self.favoriteButton.imageView?.transform.scaledBy(x: 0.7, y: 0.7) ?? .identity
|
||||
} completion: { _ in
|
||||
self.favoriteButton.imageView?.transform = .identity
|
||||
}
|
||||
}
|
||||
|
||||
func favorite() {
|
||||
UIImpactFeedbackGenerator(style: .medium).impactOccurred()
|
||||
|
||||
if !UIAccessibility.isReduceMotionEnabled {
|
||||
UIViewPropertyAnimator.runningPropertyAnimator(
|
||||
withDuration: .defaultAnimationDuration,
|
||||
delay: 0,
|
||||
options: .curveLinear) {
|
||||
self.setFavoriteButtonColor(favorited: !self.statusConfiguration.viewModel.favorited)
|
||||
self.favoriteButton.imageView?.transform =
|
||||
self.favoriteButton.imageView?.transform.rotated(by: .pi) ?? .identity
|
||||
} completion: { _ in
|
||||
self.favoriteButton.imageView?.transform = .identity
|
||||
}
|
||||
self.animateFavorite()
|
||||
}
|
||||
|
||||
statusConfiguration.viewModel.toggleFavorited()
|
||||
|
|
|
@ -51,6 +51,7 @@ final class StatusBodyView: UIView {
|
|||
|
||||
contentTextView.isHidden = !viewModel.shouldShowContent
|
||||
|
||||
attachmentsView.displayEdgeToEdge(viewModel.identityContext.appPreferences.edgeToEdgeView)
|
||||
attachmentsView.isHidden = viewModel.attachmentViewModels.isEmpty
|
||||
attachmentsView.viewModel = viewModel
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ extension CGFloat {
|
|||
static let defaultShadowRadius: Self = 2
|
||||
static let systemMenuWidth: Self = 250
|
||||
static let systemMenuInset: Self = 15
|
||||
static let tabBarEdgeInsetSize: Self = 64
|
||||
}
|
||||
|
||||
extension Float {
|
||||
|
|
Loading…
Reference in a new issue