From 5f03ce7d8b208f63d306125640de5545fdb5f0bc Mon Sep 17 00:00:00 2001 From: Justin Mazzocchi <2831158+jzzocc@users.noreply.github.com> Date: Sat, 30 Jan 2021 17:43:48 -0800 Subject: [PATCH] Status word preference --- DB/Sources/DB/Content/ContentDatabase.swift | 6 ++-- .../DB/Entities/CollectionSection.swift | 6 ++-- Data Sources/TableViewDataSource.swift | 14 +++++--- Extensions/CollectionSection+Extensions.swift | 4 +-- Extensions/ProfileCollection+Extensions.swift | 16 +++++++-- Extensions/SearchScope+Extensions.swift | 19 +++++++--- Localizations/Localizable.strings | 28 +++++++++------ .../Utilities/AppPreferences.swift | 35 +++++++++++-------- View Controllers/ExploreViewController.swift | 8 ++++- .../NewStatusViewController.swift | 14 ++++++-- View Controllers/ProfileViewController.swift | 5 +-- View Controllers/TableViewController.swift | 18 ++++++++-- Views/SwiftUI/PreferencesView.swift | 17 +++++++++ Views/UIKit/AccountHeaderView.swift | 33 +++++++++-------- Views/UIKit/Content Views/StatusView.swift | 11 +++++- 15 files changed, 163 insertions(+), 71 deletions(-) diff --git a/DB/Sources/DB/Content/ContentDatabase.swift b/DB/Sources/DB/Content/ContentDatabase.swift index c73a402..2332350 100644 --- a/DB/Sources/DB/Content/ContentDatabase.swift +++ b/DB/Sources/DB/Content/ContentDatabase.swift @@ -573,9 +573,9 @@ public extension ContentDatabase { return accountsPublisher.combineLatest(statusesPublisher) .map { accounts, statuses in - [.init(items: accounts, titleLocalizedStringKey: "search.scope.accounts"), - .init(items: statuses, titleLocalizedStringKey: "search.scope.statuses"), - .init(items: hashtags, titleLocalizedStringKey: "search.scope.tags")] + [.init(items: accounts, searchScope: .accounts), + .init(items: statuses, searchScope: .statuses), + .init(items: hashtags, searchScope: .tags)] .filter { !$0.items.isEmpty } } .removeDuplicates() diff --git a/DB/Sources/DB/Entities/CollectionSection.swift b/DB/Sources/DB/Entities/CollectionSection.swift index e35e52c..008c11c 100644 --- a/DB/Sources/DB/Entities/CollectionSection.swift +++ b/DB/Sources/DB/Entities/CollectionSection.swift @@ -4,10 +4,10 @@ import Foundation public struct CollectionSection: Hashable { public let items: [CollectionItem] - public let titleLocalizedStringKey: String? + public let searchScope: SearchScope? - public init(items: [CollectionItem], titleLocalizedStringKey: String? = nil) { + public init(items: [CollectionItem], searchScope: SearchScope? = nil) { self.items = items - self.titleLocalizedStringKey = titleLocalizedStringKey + self.searchScope = searchScope } } diff --git a/Data Sources/TableViewDataSource.swift b/Data Sources/TableViewDataSource.swift index ec01300..07c4371 100644 --- a/Data Sources/TableViewDataSource.swift +++ b/Data Sources/TableViewDataSource.swift @@ -6,8 +6,11 @@ import ViewModels final class TableViewDataSource: UITableViewDiffableDataSource { private let updateQueue = DispatchQueue(label: "com.metabolist.metatext.collection-data-source.update-queue") + private let viewModel: CollectionViewModel + + init(tableView: UITableView, viewModel: CollectionViewModel) { + self.viewModel = viewModel - init(tableView: UITableView, viewModelProvider: @escaping (IndexPath) -> CollectionItemViewModel) { for cellClass in CollectionItem.cellClasses { tableView.register(cellClass, forCellReuseIdentifier: String(describing: cellClass)) } @@ -17,7 +20,7 @@ final class TableViewDataSource: UITableViewDiffableDataSource 0, - let localizedStringKey = section.titleLocalizedStringKey { - return NSLocalizedString(localizedStringKey, comment: "") + let searchScope = section.searchScope { + return searchScope.title(statusWord: viewModel.identityContext.appPreferences.statusWord) } return nil diff --git a/Extensions/CollectionSection+Extensions.swift b/Extensions/CollectionSection+Extensions.swift index 4b0b365..19a3a3a 100644 --- a/Extensions/CollectionSection+Extensions.swift +++ b/Extensions/CollectionSection+Extensions.swift @@ -6,7 +6,7 @@ import ViewModels extension CollectionSection { struct Identifier: Hashable { let index: Int - let titleLocalizedStringKey: String? + let searchScope: SearchScope? } } @@ -17,7 +17,7 @@ extension Array where Element == CollectionSection { for (index, section) in enumerated() { let identifier = CollectionSection.Identifier( index: index, - titleLocalizedStringKey: section.titleLocalizedStringKey) + searchScope: section.searchScope) snapshot.appendSections([identifier]) snapshot.appendItems(section.items, toSection: identifier) } diff --git a/Extensions/ProfileCollection+Extensions.swift b/Extensions/ProfileCollection+Extensions.swift index 79f2fe9..c423100 100644 --- a/Extensions/ProfileCollection+Extensions.swift +++ b/Extensions/ProfileCollection+Extensions.swift @@ -4,12 +4,22 @@ import Foundation import ViewModels extension ProfileCollection { - var title: String { + func title(statusWord: AppPreferences.StatusWord) -> String { switch self { case .statuses: - return NSLocalizedString("account.statuses", comment: "") + switch statusWord { + case .toot: + return NSLocalizedString("account.statuses.toot", comment: "") + case .post: + return NSLocalizedString("account.statuses.post", comment: "") + } case .statusesAndReplies: - return NSLocalizedString("account.statuses-and-replies", comment: "") + switch statusWord { + case .toot: + return NSLocalizedString("account.statuses-and-replies.toot", comment: "") + default: + return NSLocalizedString("account.statuses-and-replies.post", comment: "") + } case .media: return NSLocalizedString("account.media", comment: "") } diff --git a/Extensions/SearchScope+Extensions.swift b/Extensions/SearchScope+Extensions.swift index ade46b2..9065bc7 100644 --- a/Extensions/SearchScope+Extensions.swift +++ b/Extensions/SearchScope+Extensions.swift @@ -4,27 +4,38 @@ import Foundation import ViewModels extension SearchScope { - var title: String { + func title(statusWord: AppPreferences.StatusWord) -> String { switch self { case .all: return NSLocalizedString("search.scope.all", comment: "") case .accounts: return NSLocalizedString("search.scope.accounts", comment: "") case .statuses: - return NSLocalizedString("search.scope.statuses", comment: "") + switch statusWord { + case .toot: + return NSLocalizedString("search.scope.statuses.toot", comment: "") + case .post: + return NSLocalizedString("search.scope.statuses.post", comment: "") + } case .tags: return NSLocalizedString("search.scope.tags", comment: "") } } - var moreDescription: String? { + func moreDescription(statusWord: AppPreferences.StatusWord) -> String? { switch self { case .all: return nil case .accounts: return NSLocalizedString("more-results.accounts", comment: "") case .statuses: - return NSLocalizedString("more-results.statuses", comment: "") + switch statusWord { + case .toot: + return NSLocalizedString("more-results.statuses.toot", comment: "") + case .post: + return NSLocalizedString("more-results.statuses.post", comment: "") + } + case .tags: return NSLocalizedString("more-results.tags", comment: "") } diff --git a/Localizations/Localizable.strings b/Localizations/Localizable.strings index 5dd34fe..fc49560 100644 --- a/Localizations/Localizable.strings +++ b/Localizations/Localizable.strings @@ -17,8 +17,10 @@ "account.hide-reblogs" = "Hide boosts"; "account.mute" = "Mute"; "account.request" = "Request"; -"account.statuses" = "Posts"; -"account.statuses-and-replies" = "Posts & Replies"; +"account.statuses.post" = "Posts"; +"account.statuses.toot" = "Toots"; +"account.statuses-and-replies.post" = "Posts & Replies"; +"account.statuses-and-replies.toot" = "Toots & Replies"; "account.media" = "Media"; "account.show-reblogs" = "Show boosts"; "account.unavailable" = "Profile unavailable"; @@ -129,12 +131,9 @@ "preferences.media.autoplay.always" = "Always"; "preferences.media.autoplay.wifi" = "On Wi-Fi"; "preferences.media.autoplay.never" = "Never"; -"preferences.posting-reading" = "Posting and Reading"; -"preferences.posting" = "Posting"; "preferences.use-preferences-from-server" = "Use preferences from server"; "preferences.posting-default-visiblility" = "Default visibility"; "preferences.posting-default-sensitive" = "Mark content sensitive by default"; -"preferences.reading" = "Reading"; "preferences.reading-expand-media" = "Expand media"; "preferences.expand-media.default" = "Hide sensitive"; "preferences.expand-media.show-all" = "Show all"; @@ -156,6 +155,7 @@ "preferences.position.sync-position" = "Sync position with web and other devices"; "preferences.position.newest" = "Load newest"; "preferences.show-reblog-and-favorite-counts" = "Show reblog and favorite counts"; +"preferences.status-word" = "Status word"; "filters.active" = "Active"; "filters.expired" = "Expired"; "filter.add-new" = "Add New Filter"; @@ -165,7 +165,7 @@ "filter.expire-after" = "Expire after"; "filter.contexts" = "Filter contexts"; "filter.irreversible" = "Drop instead of hide"; -"filter.irreversible-explanation" = "Filtered posts will disappear irreversibly, even if filter is later removed"; +"filter.irreversible-explanation" = "Filtered statuses will disappear irreversibly, even if filter is later removed"; "filter.whole-word" = "Whole word"; "filter.whole-word-explanation" = "When the keyword or phrase is alphanumeric only, it will only be applied if it matches the whole word"; "filter.save-changes" = "Save Changes"; @@ -176,7 +176,8 @@ "filter.context.account" = "Profiles"; "filter.context.unknown" = "Unknown context"; "more-results.accounts" = "More people"; -"more-results.statuses" = "More posts"; +"more-results.statuses.post" = "More posts"; +"more-results.statuses.toot" = "More toots"; "more-results.tags" = "More hashtags"; "notifications" = "Notifications"; "notifications.reblogged-your-status" = "%@ boosted your status"; @@ -194,18 +195,22 @@ "report.forward-%@" = "Forward report to %@"; "search.scope.all" = "All"; "search.scope.accounts" = "People"; -"search.scope.statuses" = "Posts"; +"search.scope.statuses.post" = "Posts"; +"search.scope.statuses.toot" = "Toots"; "search.scope.tags" = "Hashtags"; "share-extension-error.no-account-found" = "No account found"; "status.bookmark" = "Bookmark"; "status.content-warning-abbreviation" = "CW"; "status.delete" = "Delete"; -"status.delete.confirm" = "Are you sure you want to delete this post?"; +"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" = "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.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.mute" = "Mute conversation"; "status.pin" = "Pin on profile"; -"status.pinned-post" = "Pinned post"; +"status.pinned.post" = "Pinned post"; +"status.pinned.toot" = "Pinned toot"; "status.poll.vote" = "Vote"; "status.poll.time-left" = "%@ left"; "status.poll.refresh" = "Refresh"; @@ -229,3 +234,4 @@ "timelines.home" = "Home"; "timelines.local" = "Local"; "timelines.federated" = "Federated"; +"toot" = "Toot"; diff --git a/ServiceLayer/Sources/ServiceLayer/Utilities/AppPreferences.swift b/ServiceLayer/Sources/ServiceLayer/Utilities/AppPreferences.swift index f2b7f16..9acede2 100644 --- a/ServiceLayer/Sources/ServiceLayer/Utilities/AppPreferences.swift +++ b/ServiceLayer/Sources/ServiceLayer/Utilities/AppPreferences.swift @@ -15,6 +15,13 @@ public struct AppPreferences { } public extension AppPreferences { + enum StatusWord: String, CaseIterable, Identifiable { + case toot + case post + + public var id: String { rawValue } + } + enum AnimateAvatars: String, CaseIterable, Identifiable { case everywhere case profiles @@ -44,6 +51,18 @@ public extension AppPreferences { set { self[.useSystemReduceMotionForMedia] = newValue } } + var statusWord: StatusWord { + get { + if let rawValue = self[.statusWord] as String?, + let value = StatusWord(rawValue: rawValue) { + return value + } + + return .toot + } + set { self[.statusWord] = newValue.rawValue } + } + var animateAvatars: AnimateAvatars { get { if let rawValue = self[.animateAvatars] as String?, @@ -140,23 +159,9 @@ public extension AppPreferences { } } -extension AppPreferences { - var updatedInstanceFilter: BloomFilter? { - guard let data = self[.updatedFilter] as Data? else { - return nil - } - - return try? JSONDecoder().decode(BloomFilter.self, from: data) - } - - func updateInstanceFilter( _ filter: BloomFilter) { - userDefaults.set(try? JSONEncoder().encode(filter), forKey: Item.updatedFilter.rawValue) - } -} - private extension AppPreferences { enum Item: String { - case updatedFilter + case statusWord case useSystemReduceMotionForMedia case animateAvatars case animateHeaders diff --git a/View Controllers/ExploreViewController.swift b/View Controllers/ExploreViewController.swift index f7d036a..e95ff32 100644 --- a/View Controllers/ExploreViewController.swift +++ b/View Controllers/ExploreViewController.swift @@ -53,10 +53,16 @@ final class ExploreViewController: UICollectionViewController { let searchController = UISearchController(searchResultsController: searchResultsController) - searchController.searchBar.scopeButtonTitles = SearchScope.allCases.map(\.title) searchController.searchResultsUpdater = self navigationItem.searchController = searchController + viewModel.identityContext.$appPreferences.sink { appPreferences in + searchController.searchBar.scopeButtonTitles = SearchScope.allCases.map { + $0.title(statusWord: appPreferences.statusWord) + } + } + .store(in: &cancellables) + viewModel.events.sink { [weak self] in self?.handle(event: $0) }.store(in: &cancellables) viewModel.$loading.sink { [weak self] in diff --git a/View Controllers/NewStatusViewController.swift b/View Controllers/NewStatusViewController.swift index 0d86bac..07cbff4 100644 --- a/View Controllers/NewStatusViewController.swift +++ b/View Controllers/NewStatusViewController.swift @@ -15,7 +15,7 @@ final class NewStatusViewController: UIViewController { private let stackView = UIStackView() private let activityIndicatorView = UIActivityIndicatorView(style: .large) private let postButton = UIBarButtonItem( - title: NSLocalizedString("post", comment: ""), + title: nil, style: .done, target: nil, action: nil) @@ -40,6 +40,7 @@ final class NewStatusViewController: UIViewController { fatalError("init(coder:) has not been implemented") } + // swiftlint:disable:next function_body_length override func viewDidLoad() { super.viewDidLoad() @@ -76,7 +77,16 @@ final class NewStatusViewController: UIViewController { primaryAction: UIAction { [weak self] _ in self?.dismiss() }) navigationItem.rightBarButtonItem = postButton - postButton.primaryAction = UIAction(title: NSLocalizedString("post", comment: "")) { [weak self] _ in + let postActionTitle: String + + switch viewModel.identityContext.appPreferences.statusWord { + case .toot: + postActionTitle = NSLocalizedString("toot", comment: "") + case .post: + postActionTitle = NSLocalizedString("post", comment: "") + } + + postButton.primaryAction = UIAction(title: postActionTitle) { [weak self] _ in self?.viewModel.post() } diff --git a/View Controllers/ProfileViewController.swift b/View Controllers/ProfileViewController.swift index bb6182e..4fe62bc 100644 --- a/View Controllers/ProfileViewController.swift +++ b/View Controllers/ProfileViewController.swift @@ -25,10 +25,7 @@ final class ProfileViewController: TableViewController { override func viewDidLoad() { super.viewDidLoad() - // Initial size is to avoid unsatisfiable constraint warning - let accountHeaderView = AccountHeaderView(frame: .init(origin: .zero, size: .init(width: 300, height: 300))) - - accountHeaderView.viewModel = viewModel + let accountHeaderView = AccountHeaderView(viewModel: viewModel) viewModel.$accountViewModel .receive(on: DispatchQueue.main) diff --git a/View Controllers/TableViewController.swift b/View Controllers/TableViewController.swift index bcc9cf3..409dce2 100644 --- a/View Controllers/TableViewController.swift +++ b/View Controllers/TableViewController.swift @@ -24,7 +24,7 @@ class TableViewController: UITableViewController { private weak var parentNavigationController: UINavigationController? private lazy var dataSource: TableViewDataSource = { - .init(tableView: tableView, viewModelProvider: viewModel.viewModel(indexPath:)) + .init(tableView: tableView, viewModel: viewModel) }() init(viewModel: CollectionViewModel, @@ -441,11 +441,23 @@ private extension TableViewController { } func confirmDelete(statusViewModel: StatusViewModel, redraft: Bool) { + let deleteAndRedraftConfirmMessage: String + let deleteConfirmMessage: String + + switch viewModel.identityContext.appPreferences.statusWord { + case .toot: + deleteAndRedraftConfirmMessage = NSLocalizedString("status.delete-and-redraft.confirm.toot", comment: "") + deleteConfirmMessage = NSLocalizedString("status.delete.confirm.toot", comment: "") + case .post: + deleteAndRedraftConfirmMessage = NSLocalizedString("status.delete-and-redraft.confirm.post", comment: "") + deleteConfirmMessage = NSLocalizedString("status.delete.confirm.post", comment: "") + } + let alertController = UIAlertController( title: nil, message: redraft - ? NSLocalizedString("status.delete-and-redraft.confirm", comment: "") - : NSLocalizedString("status.delete.confirm", comment: ""), + ? deleteAndRedraftConfirmMessage + : deleteConfirmMessage, preferredStyle: .alert) let deleteAction = UIAlertAction( diff --git a/Views/SwiftUI/PreferencesView.swift b/Views/SwiftUI/PreferencesView.swift index 0d0382a..ded7a54 100644 --- a/Views/SwiftUI/PreferencesView.swift +++ b/Views/SwiftUI/PreferencesView.swift @@ -62,6 +62,12 @@ struct PreferencesView: View { .disabled(viewModel.preferences.useServerPostingReadingPreferences) } Section(header: Text("preferences.app")) { + Picker("preferences.status-word", + selection: $identityContext.appPreferences.statusWord) { + ForEach(AppPreferences.StatusWord.allCases) { option in + Text(option.localizedStringKey).tag(option) + } + } if accessibilityReduceMotion { Toggle("preferences.media.use-system-reduce-motion", isOn: $identityContext.appPreferences.useSystemReduceMotionForMedia) @@ -119,6 +125,17 @@ private extension PreferencesView { } } +extension AppPreferences.StatusWord { + var localizedStringKey: LocalizedStringKey { + switch self { + case .toot: + return "toot" + case .post: + return "post" + } + } +} + extension AppPreferences.AnimateAvatars { var localizedStringKey: LocalizedStringKey { switch self { diff --git a/Views/UIKit/AccountHeaderView.swift b/Views/UIKit/AccountHeaderView.swift index 2f6737e..eb51d06 100644 --- a/Views/UIKit/AccountHeaderView.swift +++ b/Views/UIKit/AccountHeaderView.swift @@ -26,9 +26,9 @@ final class AccountHeaderView: UIView { let segmentedControl = UISegmentedControl() let unavailableLabel = UILabel() - var viewModel: ProfileViewModel? { + var viewModel: ProfileViewModel { didSet { - if let accountViewModel = viewModel?.accountViewModel { + if let accountViewModel = viewModel.accountViewModel { headerImageView.kf.setImage(with: accountViewModel.headerURL) { [weak self] in if case let .success(result) = $0, result.image.size != Self.missingHeaderImageSize { self?.headerButton.isEnabled = true @@ -127,8 +127,11 @@ final class AccountHeaderView: UIView { } } - override init(frame: CGRect) { - super.init(frame: frame) + init(viewModel: ProfileViewModel) { + self.viewModel = viewModel + + // Initial size is to avoid unsatisfiable constraint warning + super.init(frame: .init(origin: .zero, size: .init(width: 300, height: 300))) initialSetup() } @@ -158,7 +161,7 @@ extension AccountHeaderView: UITextViewDelegate { interaction: UITextItemInteraction) -> Bool { switch interaction { case .invokeDefaultAction: - viewModel?.accountViewModel?.urlSelected(URL) + viewModel.accountViewModel?.urlSelected(URL) return false case .preview: return false case .presentActions: return false @@ -189,7 +192,7 @@ private extension AccountHeaderView { headerButton.translatesAutoresizingMaskIntoConstraints = false headerButton.setBackgroundImage(.highlightedButtonBackground, for: .highlighted) - headerButton.addAction(UIAction { [weak self] _ in self?.viewModel?.presentHeader() }, for: .touchUpInside) + headerButton.addAction(UIAction { [weak self] _ in self?.viewModel.presentHeader() }, for: .touchUpInside) headerButton.isEnabled = false let avatarBackgroundViewDimension = Self.avatarDimension + .compactSpacing * 2 @@ -210,7 +213,7 @@ private extension AccountHeaderView { avatarButton.translatesAutoresizingMaskIntoConstraints = false avatarButton.setBackgroundImage(.highlightedButtonBackground, for: .highlighted) - avatarButton.addAction(UIAction { [weak self] _ in self?.viewModel?.presentAvatar() }, for: .touchUpInside) + avatarButton.addAction(UIAction { [weak self] _ in self?.viewModel.presentAvatar() }, for: .touchUpInside) addSubview(relationshipButtonsStackView) relationshipButtonsStackView.translatesAutoresizingMaskIntoConstraints = false @@ -230,7 +233,7 @@ private extension AccountHeaderView { withConfiguration: UIImage.SymbolConfiguration(scale: .small)), for: .normal) followButton.addAction( - UIAction { [weak self] _ in self?.viewModel?.accountViewModel?.follow() }, + UIAction { [weak self] _ in self?.viewModel.accountViewModel?.follow() }, for: .touchUpInside) unfollowButton.setImage( @@ -241,7 +244,7 @@ private extension AccountHeaderView { unfollowButton.setTitle(NSLocalizedString("account.following", comment: ""), for: .normal) unfollowButton.showsMenuAsPrimaryAction = true unfollowButton.menu = UIMenu(children: [UIDeferredMenuElement { [weak self] completion in - guard let accountViewModel = self?.viewModel?.accountViewModel else { return } + guard let accountViewModel = self?.viewModel.accountViewModel else { return } let unfollowAction = UIAction( title: NSLocalizedString("account.unfollow", comment: ""), @@ -299,20 +302,22 @@ private extension AccountHeaderView { followStackView.distribution = .fillEqually followingButton.addAction( - UIAction { [weak self] _ in self?.viewModel?.accountViewModel?.followingSelected() }, + UIAction { [weak self] _ in self?.viewModel.accountViewModel?.followingSelected() }, for: .touchUpInside) followStackView.addArrangedSubview(followingButton) followersButton.addAction( - UIAction { [weak self] _ in self?.viewModel?.accountViewModel?.followersSelected() }, + UIAction { [weak self] _ in self?.viewModel.accountViewModel?.followersSelected() }, for: .touchUpInside) followStackView.addArrangedSubview(followersButton) + let statusWord = viewModel.identityContext.appPreferences.statusWord + for (index, collection) in ProfileCollection.allCases.enumerated() { segmentedControl.insertSegment( - action: UIAction(title: collection.title) { [weak self] _ in - self?.viewModel?.collection = collection - self?.viewModel?.request(maxId: nil, minId: nil, search: nil) + action: UIAction(title: collection.title(statusWord: statusWord)) { [weak self] _ in + self?.viewModel.collection = collection + self?.viewModel.request(maxId: nil, minId: nil, search: nil) }, at: index, animated: false) diff --git a/Views/UIKit/Content Views/StatusView.swift b/Views/UIKit/Content Views/StatusView.swift index 772764c..7c85679 100644 --- a/Views/UIKit/Content Views/StatusView.swift +++ b/Views/UIKit/Content Views/StatusView.swift @@ -354,7 +354,16 @@ private extension StatusView { infoLabel.isHidden = false infoIcon.isHidden = false } else if viewModel.configuration.isPinned { - infoLabel.text = NSLocalizedString("status.pinned-post", comment: "") + let pinnedText: String + + switch viewModel.identityContext.appPreferences.statusWord { + case .toot: + pinnedText = NSLocalizedString("status.pinned.toot", comment: "") + case .post: + pinnedText = NSLocalizedString("status.pinned.post", comment: "") + } + + infoLabel.text = pinnedText infoIcon.image = UIImage( systemName: "pin", withConfiguration: UIImage.SymbolConfiguration(scale: .small))