From bbddc1d8dcd98c29c6a8f5bc70e7fcda937b24ce Mon Sep 17 00:00:00 2001 From: Daniele Date: Tue, 15 Nov 2022 16:08:09 -0800 Subject: [PATCH 1/3] Add edge-to-edge view --- Localizations/en.lproj/Localizable.strings | 4 +++ .../Utilities/AppPreferences.swift | 27 ++++++++++++++++ Views/SwiftUI/PreferencesView.swift | 2 ++ Views/UIKit/AttachmentsView.swift | 11 +++++-- Views/UIKit/CompositionView.swift | 9 +++--- Views/UIKit/Content Views/StatusView.swift | 32 +++++++++++++++---- Views/UIKit/StatusBodyView.swift | 1 + Views/ViewConstants.swift | 1 + 8 files changed, 74 insertions(+), 13 deletions(-) diff --git a/Localizations/en.lproj/Localizable.strings b/Localizations/en.lproj/Localizable.strings index f7f6054..ca5f7b0 100644 --- a/Localizations/en.lproj/Localizable.strings +++ b/Localizations/en.lproj/Localizable.strings @@ -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.media.avatars" = "Avatars"; "preferences.media.avatars.animate" = "Animate avatars"; @@ -235,6 +236,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"; @@ -253,6 +255,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.favorite-word" = "Favorite word"; "filters.active" = "Active"; "filters.expired" = "Expired"; "filter.add-new" = "Add New Filter"; @@ -279,6 +282,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"; diff --git a/ServiceLayer/Sources/ServiceLayer/Utilities/AppPreferences.swift b/ServiceLayer/Sources/ServiceLayer/Utilities/AppPreferences.swift index 828fa03..96faeb8 100644 --- a/ServiceLayer/Sources/ServiceLayer/Utilities/AppPreferences.swift +++ b/ServiceLayer/Sources/ServiceLayer/Utilities/AppPreferences.swift @@ -32,6 +32,14 @@ public extension AppPreferences { public var id: String { rawValue } } + enum FavoriteWord: String, CaseIterable, Identifiable { + case favorite + case favourite + case like + + public var id: String { rawValue } + } + enum AnimateAvatars: String, CaseIterable, Identifiable { case everywhere case profiles @@ -79,6 +87,18 @@ public extension AppPreferences { set { self[.statusWord] = newValue.rawValue } } + var favoriteWord: FavoriteWord { + get { + if let rawValue = self[.favoriteWord] as String?, + let value = FavoriteWord(rawValue: rawValue) { + return value + } + + return .favorite + } + set { self[.favoriteWord] = newValue.rawValue } + } + var animateAvatars: AnimateAvatars { get { if let rawValue = self[.animateAvatars] as String?, @@ -171,6 +191,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 } @@ -207,6 +232,7 @@ private extension AppPreferences { enum Item: String { case colorScheme case statusWord + case favoriteWord case requireDoubleTapToReblog case requireDoubleTapToFavorite case animateAvatars @@ -223,6 +249,7 @@ private extension AppPreferences { case notificationSounds case openLinksInDefaultBrowser case useUniversalLinks + case edgeToEdgeView } subscript(index: Item) -> T? { diff --git a/Views/SwiftUI/PreferencesView.swift b/Views/SwiftUI/PreferencesView.swift index 296e58d..ac1ba5e 100644 --- a/Views/SwiftUI/PreferencesView.swift +++ b/Views/SwiftUI/PreferencesView.swift @@ -101,6 +101,8 @@ struct PreferencesView: View { Text(option.localizedStringKey).tag(option) } } + Toggle("preferences.edge-to-edge-view", + isOn: $identityContext.appPreferences.edgeToEdgeView) Toggle("preferences.show-reblog-and-favorite-counts", isOn: $identityContext.appPreferences.showReblogAndFavoriteCounts) Toggle("preferences.require-double-tap-to-reblog", diff --git a/Views/UIKit/AttachmentsView.swift b/Views/UIKit/AttachmentsView.swift index 2c9e50d..0383d91 100644 --- a/Views/UIKit/AttachmentsView.swift +++ b/Views/UIKit/AttachmentsView.swift @@ -15,6 +15,7 @@ final class AttachmentsView: UIView { private let hideButton = UIButton() private var aspectRatioConstraint: NSLayoutConstraint? private var cancellables = Set() + 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 diff --git a/Views/UIKit/CompositionView.swift b/Views/UIKit/CompositionView.swift index 5c0cda0..fcac212 100644 --- a/Views/UIKit/CompositionView.swift +++ b/Views/UIKit/CompositionView.swift @@ -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), diff --git a/Views/UIKit/Content Views/StatusView.swift b/Views/UIKit/Content Views/StatusView.swift index 89a103e..ae99e78 100644 --- a/Views/UIKit/Content Views/StatusView.swift +++ b/Views/UIKit/Content Views/StatusView.swift @@ -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 @@ -475,7 +488,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 +569,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 +587,8 @@ private extension StatusView { timeLabel.accessibilityLabel = viewModel.accessibilityTime timeLabel.isHidden = isContextParent + timeSeparatorLabel.isHidden = isContextParent + bodyView.viewModel = viewModel showThreadIndicator.isHidden = !viewModel.configuration.isReplyOutOfContext diff --git a/Views/UIKit/StatusBodyView.swift b/Views/UIKit/StatusBodyView.swift index 6573c71..30aea27 100644 --- a/Views/UIKit/StatusBodyView.swift +++ b/Views/UIKit/StatusBodyView.swift @@ -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 diff --git a/Views/ViewConstants.swift b/Views/ViewConstants.swift index cdc8c20..15ad34f 100644 --- a/Views/ViewConstants.swift +++ b/Views/ViewConstants.swift @@ -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 { From bd466deb74fe98134637e7a253eb47505f28c8ed Mon Sep 17 00:00:00 2001 From: Daniele Date: Sun, 20 Nov 2022 16:38:15 -0800 Subject: [PATCH 2/3] display favorites as likes --- Localizations/en.lproj/Localizable.strings | 3 + .../Utilities/AppPreferences.swift | 20 ++++++ Views/SwiftUI/PreferencesView.swift | 17 +++++ .../Content Views/NotificationView.swift | 19 +++-- Views/UIKit/Content Views/StatusView.swift | 71 +++++++++++++++---- 5 files changed, 113 insertions(+), 17 deletions(-) diff --git a/Localizations/en.lproj/Localizable.strings b/Localizations/en.lproj/Localizable.strings index f7f6054..bf32305 100644 --- a/Localizations/en.lproj/Localizable.strings +++ b/Localizations/en.lproj/Localizable.strings @@ -253,6 +253,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"; @@ -279,6 +280,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"; @@ -356,3 +358,4 @@ "timelines.local" = "Local"; "timelines.federated" = "Federated"; "toot" = "Toot"; +"likes" = "Likes"; diff --git a/ServiceLayer/Sources/ServiceLayer/Utilities/AppPreferences.swift b/ServiceLayer/Sources/ServiceLayer/Utilities/AppPreferences.swift index 828fa03..c77b6b4 100644 --- a/ServiceLayer/Sources/ServiceLayer/Utilities/AppPreferences.swift +++ b/ServiceLayer/Sources/ServiceLayer/Utilities/AppPreferences.swift @@ -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?, @@ -207,6 +226,7 @@ private extension AppPreferences { enum Item: String { case colorScheme case statusWord + case displayFavoritesAs case requireDoubleTapToReblog case requireDoubleTapToFavorite case animateAvatars diff --git a/Views/SwiftUI/PreferencesView.swift b/Views/SwiftUI/PreferencesView.swift index 296e58d..24b1dfd 100644 --- a/Views/SwiftUI/PreferencesView.swift +++ b/Views/SwiftUI/PreferencesView.swift @@ -101,6 +101,12 @@ struct PreferencesView: View { Text(option.localizedStringKey).tag(option) } } + 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", @@ -182,6 +188,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 { diff --git a/Views/UIKit/Content Views/NotificationView.swift b/Views/UIKit/Content Views/NotificationView.swift index 0e29641..7127a26 100644 --- a/Views/UIKit/Content Views/NotificationView.swift +++ b/Views/UIKit/Content Views/NotificationView.swift @@ -165,7 +165,7 @@ private extension NotificationView { func applyNotificationConfiguration() { let viewModel = notificationConfiguration.viewModel - + var imageName = viewModel.type.systemImageName avatarImageView.sd_setImage(with: viewModel.accountViewModel.avatarURL()) switch viewModel.type { @@ -184,12 +184,23 @@ private extension NotificationView { identityContext: viewModel.identityContext) iconImageView.tintColor = .systemGreen case .favourite: - typeLabel.attributedText = "notifications.favourited-your-status-%@".localizedBolding( + let label: String + let color: UIColor + switch viewModel.identityContext.appPreferences.displayFavoritesAs { + case .favorites: + label = "notifications.favourited-your-status-%@" + color = .systemYellow + case .likes: + label = "notifications.liked-your-status-%@" + color = .systemRed + imageName = "heart.fill" + } + typeLabel.attributedText = label.localizedBolding( displayName: viewModel.accountViewModel.displayName, emojis: viewModel.accountViewModel.emojis, label: typeLabel, identityContext: viewModel.identityContext) - iconImageView.tintColor = .systemYellow + iconImageView.tintColor = color case .poll: typeLabel.text = NSLocalizedString( viewModel.accountViewModel.isSelf @@ -229,7 +240,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: "") diff --git a/Views/UIKit/Content Views/StatusView.swift b/Views/UIKit/Content Views/StatusView.swift index 89a103e..ce10687 100644 --- a/Views/UIKit/Content Views/StatusView.swift +++ b/Views/UIKit/Content Views/StatusView.swift @@ -835,10 +835,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 +872,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,7 +919,11 @@ private extension StatusView { } func setFavoriteButtonColor(favorited: Bool) { - let favoriteColor: UIColor = favorited ? .systemYellow : .secondaryLabel + var favoriteColor: UIColor + switch statusConfiguration.viewModel.identityContext.appPreferences.displayFavoritesAs { + case .favorites: favoriteColor = favorited ? .systemYellow : .secondaryLabel + case .likes: favoriteColor = favorited ? .systemRed : .secondaryLabel + } favoriteButton.tintColor = favoriteColor favoriteButton.setTitleColor(favoriteColor, for: .normal) @@ -938,20 +956,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() From e95975be005013a96abeb7e4f81586873bba08a2 Mon Sep 17 00:00:00 2001 From: Daniele Date: Sun, 20 Nov 2022 17:40:45 -0800 Subject: [PATCH 3/3] fix linting --- Localizations/en.lproj/Localizable.strings | 9 +++- .../en.lproj/Localizable.stringsdict | 16 +++++++ View Controllers/TableViewController.swift | 9 +++- .../Content Views/NotificationView.swift | 43 +++++++++++++------ Views/UIKit/Content Views/StatusView.swift | 30 ++++++++++--- 5 files changed, 84 insertions(+), 23 deletions(-) diff --git a/Localizations/en.lproj/Localizable.strings b/Localizations/en.lproj/Localizable.strings index bf32305..12c7a4d 100644 --- a/Localizations/en.lproj/Localizable.strings +++ b/Localizations/en.lproj/Localizable.strings @@ -313,8 +313,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"; @@ -333,6 +336,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"; diff --git a/Localizations/en.lproj/Localizable.stringsdict b/Localizations/en.lproj/Localizable.stringsdict index 2cef6d1..05bc76f 100644 --- a/Localizations/en.lproj/Localizable.stringsdict +++ b/Localizations/en.lproj/Localizable.stringsdict @@ -66,6 +66,22 @@ %ld Favorites + status.likes-count-%ld + + NSStringLocalizedFormatKey + %#@likes@ + likes + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + %ld Like + other + %ld Likes + + status.replies-count-%ld NSStringLocalizedFormatKey diff --git a/View Controllers/TableViewController.swift b/View Controllers/TableViewController.swift index 0759127..44e2d80 100644 --- a/View Controllers/TableViewController.swift +++ b/View Controllers/TableViewController.swift @@ -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: "") } diff --git a/Views/UIKit/Content Views/NotificationView.swift b/Views/UIKit/Content Views/NotificationView.swift index 7127a26..6b854dd 100644 --- a/Views/UIKit/Content Views/NotificationView.swift +++ b/Views/UIKit/Content Views/NotificationView.swift @@ -163,6 +163,33 @@ 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 @@ -184,23 +211,13 @@ private extension NotificationView { identityContext: viewModel.identityContext) iconImageView.tintColor = .systemGreen case .favourite: - let label: String - let color: UIColor - switch viewModel.identityContext.appPreferences.displayFavoritesAs { - case .favorites: - label = "notifications.favourited-your-status-%@" - color = .systemYellow - case .likes: - label = "notifications.liked-your-status-%@" - color = .systemRed - imageName = "heart.fill" - } - typeLabel.attributedText = label.localizedBolding( + imageName = imageNameForFavoriteView + typeLabel.attributedText = labelForFavoriteView.localizedBolding( displayName: viewModel.accountViewModel.displayName, emojis: viewModel.accountViewModel.emojis, label: typeLabel, identityContext: viewModel.identityContext) - iconImageView.tintColor = color + iconImageView.tintColor = colorForFavoriteView case .poll: typeLabel.text = NSLocalizedString( viewModel.accountViewModel.isSelf diff --git a/Views/UIKit/Content Views/StatusView.swift b/Views/UIKit/Content Views/StatusView.swift index ce10687..9eb5c34 100644 --- a/Views/UIKit/Content Views/StatusView.swift +++ b/Views/UIKit/Content Views/StatusView.swift @@ -451,6 +451,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 @@ -593,8 +602,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 +832,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)) } } @@ -920,9 +930,17 @@ private extension StatusView { func setFavoriteButtonColor(favorited: Bool) { var favoriteColor: UIColor + var favoriteLabel: String + var undoFavoriteLabel: String switch statusConfiguration.viewModel.identityContext.appPreferences.displayFavoritesAs { - case .favorites: favoriteColor = favorited ? .systemYellow : .secondaryLabel - case .likes: favoriteColor = favorited ? .systemRed : .secondaryLabel + 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 @@ -930,10 +948,10 @@ private extension StatusView { 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: "") } }