From 1c981910c65a3b9baca587f426b7f0bd29fcf0f1 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 30 Mar 2022 15:23:22 +0800 Subject: [PATCH 001/101] feat: make the text input hover when keyboard display --- .../MastodonRegisterViewController.swift | 75 ++----------------- 1 file changed, 7 insertions(+), 68 deletions(-) diff --git a/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift b/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift index bd2db3d45..26060c2c5 100644 --- a/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift +++ b/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift @@ -11,6 +11,7 @@ import MastodonSDK import os.log import PhotosUI import UIKit +import MastodonUI import MastodonAsset import MastodonLocalization @@ -132,12 +133,12 @@ extension MastodonRegisterViewController { viewModel.setupDiffableDataSource(tableView: tableView) -// KeyboardResponderService -// .configure( -// scrollView: tableView, -// layoutNeedsUpdate: viewModel.viewDidAppear.eraseToAnyPublisher() -// ) -// .store(in: &disposeBag) + KeyboardResponderService + .configure( + scrollView: tableView, + layoutNeedsUpdate: viewModel.viewDidAppear.eraseToAnyPublisher() + ) + .store(in: &disposeBag) // gesture view.addGestureRecognizer(tapGestureRecognizer) @@ -403,65 +404,3 @@ extension MastodonRegisterViewController { } } - -extension MastodonRegisterViewController: UITextFieldDelegate { -// func textFieldDidBeginEditing(_ textField: UITextField) { -// let text = textField.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "" -// -// switch textField { -// case usernameTextField: -// viewModel.username.value = text -// case displayNameTextField: -// viewModel.displayName.value = text -// case emailTextField: -// viewModel.email.value = text -// case passwordTextField: -// viewModel.password.value = text -// case reasonTextField: -// viewModel.reason.value = text -// default: -// break -// } -// } -// -// func textFieldDidEndEditing(_ textField: UITextField) { -// let text = textField.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "" -// -// switch textField { -// case usernameTextField: -// viewModel.username.value = text -// case displayNameTextField: -// viewModel.displayName.value = text -// case emailTextField: -// viewModel.email.value = text -// case passwordTextField: -// viewModel.password.value = text -// case reasonTextField: -// viewModel.reason.value = text -// default: -// break -// } -// } -// -// func textFieldShouldReturn(_ textField: UITextField) -> Bool { -// switch textField { -// case usernameTextField: -// displayNameTextField.becomeFirstResponder() -// case displayNameTextField: -// emailTextField.becomeFirstResponder() -// case emailTextField: -// passwordTextField.becomeFirstResponder() -// case passwordTextField: -// if viewModel.approvalRequired { -// reasonTextField.becomeFirstResponder() -// } else { -// passwordTextField.resignFirstResponder() -// } -// case reasonTextField: -// reasonTextField.resignFirstResponder() -// default: -// break -// } -// return true -// } -} From 116e9c143ca2863aa4cedfdfd16c778b83771761 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 30 Mar 2022 15:23:59 +0800 Subject: [PATCH 002/101] chore: fix the username text field right label too long in sign-up form --- .../Register/Cell/MastodonRegisterTextFieldTableViewCell.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Mastodon/Scene/Onboarding/Register/Cell/MastodonRegisterTextFieldTableViewCell.swift b/Mastodon/Scene/Onboarding/Register/Cell/MastodonRegisterTextFieldTableViewCell.swift index 3daa2eb18..15f234834 100644 --- a/Mastodon/Scene/Onboarding/Register/Cell/MastodonRegisterTextFieldTableViewCell.swift +++ b/Mastodon/Scene/Onboarding/Register/Cell/MastodonRegisterTextFieldTableViewCell.swift @@ -115,6 +115,7 @@ extension MastodonRegisterTextFieldTableViewCell { label.font = MastodonRegisterTextFieldTableViewCell.textFieldLabelFont label.textColor = Asset.Colors.Label.primary.color label.text = text + label.lineBreakMode = .byTruncatingMiddle label.translatesAutoresizingMaskIntoConstraints = false containerView.addSubview(label) @@ -123,6 +124,7 @@ extension MastodonRegisterTextFieldTableViewCell { label.leadingAnchor.constraint(equalTo: paddingView.trailingAnchor), containerView.trailingAnchor.constraint(equalTo: label.trailingAnchor, constant: 16), label.bottomAnchor.constraint(equalTo: containerView.bottomAnchor), + label.widthAnchor.constraint(lessThanOrEqualToConstant: 180).priority(.required - 1), ]) return containerView }() From 2ecf92dbe5e9a0e770bc7d49a12314e91f229a24 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 7 Apr 2022 19:27:47 +0800 Subject: [PATCH 003/101] chore: update secondary label color --- .../Colors/Label/primary.colorset/Contents.json | 6 +++--- .../Colors/Label/secondary.colorset/Contents.json | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Colors/Label/primary.colorset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Colors/Label/primary.colorset/Contents.json index a36ab82ce..0c0c8af04 100644 --- a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Colors/Label/primary.colorset/Contents.json +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Colors/Label/primary.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "0.216", - "green" : "0.173", - "red" : "0.157" + "blue" : "55", + "green" : "44", + "red" : "40" } }, "idiom" : "universal" diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Colors/Label/secondary.colorset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Colors/Label/secondary.colorset/Contents.json index cd123376b..b23080b6b 100644 --- a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Colors/Label/secondary.colorset/Contents.json +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Colors/Label/secondary.colorset/Contents.json @@ -4,10 +4,10 @@ "color" : { "color-space" : "srgb", "components" : { - "alpha" : "0.600", - "blue" : "67", - "green" : "60", - "red" : "60" + "alpha" : "1.000", + "blue" : "133", + "green" : "112", + "red" : "102" } }, "idiom" : "universal" From 4c1870f921be9ad4692dce98897f341f72862236 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 7 Apr 2022 19:28:06 +0800 Subject: [PATCH 004/101] chore: update body font size to 17pt --- MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift index b938f2b97..30e05d866 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift @@ -141,11 +141,11 @@ public final class StatusView: UIView { return style }() metaText.textAttributes = [ - .font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 15, weight: .regular)), + .font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)), .foregroundColor: Asset.Colors.Label.primary.color, ] metaText.linkAttributes = [ - .font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 15, weight: .semibold)), + .font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold)), .foregroundColor: Asset.Colors.brandBlue.color, ] return metaText From 2a986ec1ce82efd5e68ad630bf4df89167d8a43a Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 7 Apr 2022 19:49:04 +0800 Subject: [PATCH 005/101] fix: media sensitive button logic issue --- .../View/Content/StatusView+ViewModel.swift | 42 +++++++------------ 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift index f848b37e1..b09fdb44e 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift @@ -321,9 +321,6 @@ extension StatusView.ViewModel { statusView.setSpoilerOverlayViewHidden(isHidden: isContentReveal) - let image = isContentReveal ? UIImage(systemName: "eye.slash.fill") : UIImage(systemName: "eye.fill") - statusView.contentSensitiveeToggleButton.setImage(image, for: .normal) - self.logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): isContentReveal: \(isContentReveal)") } .store(in: &disposeBag) @@ -335,29 +332,22 @@ extension StatusView.ViewModel { } .store(in: &disposeBag) -// // visibility -// Publishers.CombineLatest( -// $visibility, -// $isMyself -// ) -// .sink { visibility, isMyself in -// switch visibility { -// case .public: -// break -// case .unlisted: -// statusView.statusVisibilityView.label.text = "Everyone can see this post but not display in the public timeline." -// statusView.setVisibilityDisplay() -// case .private: -// statusView.statusVisibilityView.label.text = isMyself ? "Only my followers can see this post." : "Only their followers can see this post." -// statusView.setVisibilityDisplay() -// case .direct: -// statusView.statusVisibilityView.label.text = "Only mentioned user can see this post." -// statusView.setVisibilityDisplay() -// case ._other: -// break -// } -// } -// .store(in: &disposeBag) + // There are 2 conditions: + // 1. The content may non-sensitive with sensitive media + // 2. The content and media both senstivie + Publishers.CombineLatest( + $isContentSensitiveToggled, + $isMediaSensitiveToggled + ) + .map { $0 || $1 } + .sink { isSensitiveToggled in + // The button indicator go-to state for button action direction + // eye: when media is hidden + // eye-slash: when media display + let image = isSensitiveToggled ? UIImage(systemName: "eye.slash.fill") : UIImage(systemName: "eye.fill") + statusView.contentSensitiveeToggleButton.setImage(image, for: .normal) + } + .store(in: &disposeBag) } private func bindMedia(statusView: StatusView) { From 33d68e8b6dd0344b88a1fbe3a82cfb369ddb4bdf Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 7 Apr 2022 20:04:06 +0800 Subject: [PATCH 006/101] fix: grouped style default corner radius applied to appearance setting issue. resolve #350 --- .../Scene/Settings/Cell/SettingsAppearanceTableViewCell.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Mastodon/Scene/Settings/Cell/SettingsAppearanceTableViewCell.swift b/Mastodon/Scene/Settings/Cell/SettingsAppearanceTableViewCell.swift index 3760fd8ed..44b6b39c3 100644 --- a/Mastodon/Scene/Settings/Cell/SettingsAppearanceTableViewCell.swift +++ b/Mastodon/Scene/Settings/Cell/SettingsAppearanceTableViewCell.swift @@ -85,6 +85,9 @@ class SettingsAppearanceTableViewCell: UITableViewCell { subview.removeFromSuperview() } } + + // remove grouped style table corner radius + layer.cornerRadius = 0 } } From 67aa1d670b54b25fd21ac7b7f20a63b08f613b54 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 11 Apr 2022 12:27:26 +0800 Subject: [PATCH 007/101] fix: non-ascii character in URL can not open issue. resolve #304 --- Mastodon/Diffiable/Search/SearchHistorySection.swift | 8 ++++---- Mastodon/Protocol/Provider/DataSourceFacade+Meta.swift | 10 +++++++--- .../Sources/MastodonUI/View/Content/StatusView.swift | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Mastodon/Diffiable/Search/SearchHistorySection.swift b/Mastodon/Diffiable/Search/SearchHistorySection.swift index dba1dc18a..557b49f2b 100644 --- a/Mastodon/Diffiable/Search/SearchHistorySection.swift +++ b/Mastodon/Diffiable/Search/SearchHistorySection.swift @@ -69,10 +69,10 @@ extension SearchHistorySection { let trendHeaderRegister = UICollectionView.SupplementaryRegistration(elementKind: UICollectionView.elementKindSectionHeader) { [weak dataSource] supplementaryView, elementKind, indexPath in supplementaryView.delegate = configuration.searchHistorySectionHeaderCollectionReusableViewDelegate - guard let dataSource = dataSource else { return } - let sections = dataSource.snapshot().sectionIdentifiers - guard indexPath.section < sections.count else { return } - let section = sections[indexPath.section] + guard let _ = dataSource else { return } + // let sections = dataSource.snapshot().sectionIdentifiers + // guard indexPath.section < sections.count else { return } + // let section = sections[indexPath.section] } dataSource.supplementaryViewProvider = { (collectionView: UICollectionView, elementKind: String, indexPath: IndexPath) in diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Meta.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Meta.swift index bf54f70ad..7e376ed0f 100644 --- a/Mastodon/Protocol/Provider/DataSourceFacade+Meta.swift +++ b/Mastodon/Protocol/Provider/DataSourceFacade+Meta.swift @@ -38,11 +38,15 @@ extension DataSourceFacade { meta: Meta ) async { switch meta { + // note: + // some server mark the normal url as "u-url" class. highlighted content is a URL case .url(_, _, let url, _), .mention(_, let url, _) where url.lowercased().hasPrefix("http"): - // note: - // some server mark the normal url as "u-url" class. highlighted content is a URL - guard let url = URL(string: url) else { return } + // fix non-ascii character URL link can not open issue + guard let url = URL(string: url) ?? URL(string: url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? url) else { + assertionFailure() + return + } if let domain = provider.context.authenticationService.activeMastodonAuthenticationBox.value?.domain, url.host == domain, url.pathComponents.count >= 4, url.pathComponents[0] == "/", diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift index 30e05d866..eb3a69354 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift @@ -757,7 +757,7 @@ extension StatusView: UITextViewDelegate { // MARK: - MetaTextViewDelegate extension StatusView: MetaTextViewDelegate { public func metaTextView(_ metaTextView: MetaTextView, didSelectMeta meta: Meta) { - logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)") + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): meta: \(String(describing: meta))") switch metaTextView { case contentMetaText.textView: delegate?.statusView(self, metaText: contentMetaText, didSelectMeta: meta) From af619e198a77bbec5216bf0c742ebcb3ac5dceaa Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 12 Apr 2022 17:32:38 +0800 Subject: [PATCH 008/101] feat: add Discovery page with posts segment --- Localization/app.json | 8 + Mastodon.xcodeproj/project.pbxproj | 44 ++++ .../xcschemes/xcschememanagement.plist | 6 +- .../Discovery/DiscoveryViewController.swift | 94 ++++++++ .../Scene/Discovery/DiscoveryViewModel.swift | 72 ++++++ ...stsViewController+DataSourceProvider.swift | 34 +++ .../Posts/DiscoveryPostsViewController.swift | 118 ++++++++++ .../DiscoveryPostsViewModel+Diffable.swift | 63 ++++++ .../Posts/DiscoveryPostsViewModel+State.swift | 208 ++++++++++++++++++ .../Posts/DiscoveryPostsViewModel.swift | 59 +++++ .../Scene/Profile/ProfileViewController.swift | 1 + .../Timeline/UserTimelineViewController.swift | 2 +- .../Search/Search/SearchViewController.swift | 17 ++ .../Scene/Search/Search/SearchViewModel.swift | 2 +- .../Service/APIService/APIService+Trend.swift | 38 +++- .../MastodonSDK/API/Mastodon+API+Trends.swift | 74 ++++++- .../Response/Mastodon+Response+Content.swift | 10 + 17 files changed, 837 insertions(+), 13 deletions(-) create mode 100644 Mastodon/Scene/Discovery/DiscoveryViewController.swift create mode 100644 Mastodon/Scene/Discovery/DiscoveryViewModel.swift create mode 100644 Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController+DataSourceProvider.swift create mode 100644 Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift create mode 100644 Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+Diffable.swift create mode 100644 Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift create mode 100644 Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift diff --git a/Localization/app.json b/Localization/app.json index f0dc0ebf1..548c5adae 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -492,6 +492,14 @@ "clear": "Clear" } }, + "discovery": { + "tabs": { + "posts": "Posts", + "hashtags": "Hashtags", + "news": "News", + "for_you": "For You" + } + }, "favorite": { "title": "Your Favorites" }, diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index cbcd948b6..98da13748 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -550,6 +550,13 @@ DBD5B1F827BCFD9D00BD6B38 /* DataSourceProvider+TableViewControllerNavigateable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBD5B1F727BCFD9D00BD6B38 /* DataSourceProvider+TableViewControllerNavigateable.swift */; }; DBD5B1FA27BD013700BD6B38 /* DataSourceProvider+StatusTableViewControllerNavigateable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBD5B1F927BD013700BD6B38 /* DataSourceProvider+StatusTableViewControllerNavigateable.swift */; }; DBD9149025DF6D8D00903DFD /* APIService+Onboarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBD9148F25DF6D8D00903DFD /* APIService+Onboarding.swift */; }; + DBDFF1902805543100557A48 /* DiscoveryPostsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBDFF18F2805543100557A48 /* DiscoveryPostsViewController.swift */; }; + DBDFF1932805554900557A48 /* DiscoveryPostsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBDFF1922805554900557A48 /* DiscoveryPostsViewModel.swift */; }; + DBDFF1952805561700557A48 /* DiscoveryPostsViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBDFF1942805561700557A48 /* DiscoveryPostsViewModel+Diffable.swift */; }; + DBDFF197280556D900557A48 /* DiscoveryPostsViewModel+State.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBDFF196280556D900557A48 /* DiscoveryPostsViewModel+State.swift */; }; + DBDFF19A28055A1400557A48 /* DiscoveryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBDFF19928055A1400557A48 /* DiscoveryViewController.swift */; }; + DBDFF19C28055BD600557A48 /* DiscoveryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBDFF19B28055BD600557A48 /* DiscoveryViewModel.swift */; }; + DBDFF19E2805703700557A48 /* DiscoveryPostsViewController+DataSourceProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBDFF19D2805703700557A48 /* DiscoveryPostsViewController+DataSourceProvider.swift */; }; DBE0821525CD382600FD6BBD /* MastodonRegisterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE0821425CD382600FD6BBD /* MastodonRegisterViewController.swift */; }; DBE0822425CD3F1E00FD6BBD /* MastodonRegisterViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE0822325CD3F1E00FD6BBD /* MastodonRegisterViewModel.swift */; }; DBE3CA6827A39CAB00AFE27B /* AppShared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB68047F2637CD4C00430867 /* AppShared.framework */; }; @@ -1293,6 +1300,13 @@ DBD5B1F727BCFD9D00BD6B38 /* DataSourceProvider+TableViewControllerNavigateable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DataSourceProvider+TableViewControllerNavigateable.swift"; sourceTree = ""; }; DBD5B1F927BD013700BD6B38 /* DataSourceProvider+StatusTableViewControllerNavigateable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DataSourceProvider+StatusTableViewControllerNavigateable.swift"; sourceTree = ""; }; DBD9148F25DF6D8D00903DFD /* APIService+Onboarding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Onboarding.swift"; sourceTree = ""; }; + DBDFF18F2805543100557A48 /* DiscoveryPostsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryPostsViewController.swift; sourceTree = ""; }; + DBDFF1922805554900557A48 /* DiscoveryPostsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryPostsViewModel.swift; sourceTree = ""; }; + DBDFF1942805561700557A48 /* DiscoveryPostsViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiscoveryPostsViewModel+Diffable.swift"; sourceTree = ""; }; + DBDFF196280556D900557A48 /* DiscoveryPostsViewModel+State.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiscoveryPostsViewModel+State.swift"; sourceTree = ""; }; + DBDFF19928055A1400557A48 /* DiscoveryViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryViewController.swift; sourceTree = ""; }; + DBDFF19B28055BD600557A48 /* DiscoveryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryViewModel.swift; sourceTree = ""; }; + DBDFF19D2805703700557A48 /* DiscoveryPostsViewController+DataSourceProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiscoveryPostsViewController+DataSourceProvider.swift"; sourceTree = ""; }; DBE0821425CD382600FD6BBD /* MastodonRegisterViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonRegisterViewController.swift; sourceTree = ""; }; DBE0822325CD3F1E00FD6BBD /* MastodonRegisterViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonRegisterViewModel.swift; sourceTree = ""; }; DBE3CDBA261C427900430CC6 /* TimelineHeaderTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineHeaderTableViewCell.swift; sourceTree = ""; }; @@ -2682,6 +2696,7 @@ 2DAC9E36262FC20B0062E1A6 /* SuggestionAccount */, DB9D6C0825E4F5A60051B173 /* Profile */, DB9D6BEE25E4F5370051B173 /* Search */, + DBDFF1912805544800557A48 /* Discovery */, 5B90C455262599800002E742 /* Settings */, ); path = Scene; @@ -3068,6 +3083,28 @@ path = FetchedResultsController; sourceTree = ""; }; + DBDFF1912805544800557A48 /* Discovery */ = { + isa = PBXGroup; + children = ( + DBDFF19828055A0900557A48 /* Posts */, + DBDFF19928055A1400557A48 /* DiscoveryViewController.swift */, + DBDFF19B28055BD600557A48 /* DiscoveryViewModel.swift */, + ); + path = Discovery; + sourceTree = ""; + }; + DBDFF19828055A0900557A48 /* Posts */ = { + isa = PBXGroup; + children = ( + DBDFF18F2805543100557A48 /* DiscoveryPostsViewController.swift */, + DBDFF19D2805703700557A48 /* DiscoveryPostsViewController+DataSourceProvider.swift */, + DBDFF1922805554900557A48 /* DiscoveryPostsViewModel.swift */, + DBDFF1942805561700557A48 /* DiscoveryPostsViewModel+Diffable.swift */, + DBDFF196280556D900557A48 /* DiscoveryPostsViewModel+State.swift */, + ); + path = Posts; + sourceTree = ""; + }; DBE0821A25CD382900FD6BBD /* Register */ = { isa = PBXGroup; children = ( @@ -3797,6 +3834,7 @@ buildActionMask = 2147483647; files = ( DBB525212611EBD6002F1F29 /* ProfilePagingViewController.swift in Sources */, + DBDFF19E2805703700557A48 /* DiscoveryPostsViewController+DataSourceProvider.swift in Sources */, DB6180EB26391C140018D199 /* MediaPreviewTransitionItem.swift in Sources */, DB63F74727990B0600455B82 /* DataSourceFacade+Hashtag.swift in Sources */, DB98337125C9443200AD9700 /* APIService+Authentication.swift in Sources */, @@ -3858,6 +3896,7 @@ DB697DD6278F4C29004EF2F7 /* DataSourceProvider.swift in Sources */, DB0FCB8E2796C0B7006C02E2 /* TrendCollectionViewCell.swift in Sources */, 0F1E2D0B2615C39400C38565 /* DoubleTitleLabelNavigationBarTitleView.swift in Sources */, + DBDFF1902805543100557A48 /* DiscoveryPostsViewController.swift in Sources */, DB697DD9278F4CED004EF2F7 /* HomeTimelineViewController+DataSourceProvider.swift in Sources */, DB9A488A26034D40008B817C /* ComposeViewModel+PublishState.swift in Sources */, DB45FAD725CA6C76005A8AC7 /* UIBarButtonItem.swift in Sources */, @@ -3878,7 +3917,9 @@ DB297B1B2679FAE200704C90 /* PlaceholderImageCacheService.swift in Sources */, DB0FCB8C2796BF8D006C02E2 /* SearchViewModel+Diffable.swift in Sources */, 2D8FCA082637EABB00137F46 /* APIService+FollowRequest.swift in Sources */, + DBDFF1952805561700557A48 /* DiscoveryPostsViewModel+Diffable.swift in Sources */, DB03A795272A981400EE37C5 /* ContentSplitViewController.swift in Sources */, + DBDFF19C28055BD600557A48 /* DiscoveryViewModel.swift in Sources */, DBBC24DE26A54BCB00398BB9 /* MastodonMetricFormatter.swift in Sources */, DB06180A2785B2AB0030EE79 /* MastodonRegisterAvatarTableViewCell.swift in Sources */, DBB45B6227B51112002DC5A7 /* SuggestionAccountViewModel+Diffable.swift in Sources */, @@ -4012,6 +4053,7 @@ DB1D843026566512000346B3 /* KeyboardPreference.swift in Sources */, DB852D1926FAEB6B00FC9D81 /* SidebarViewController.swift in Sources */, 2D206B9225F60EA700143C56 /* UIControl.swift in Sources */, + DBDFF1932805554900557A48 /* DiscoveryPostsViewModel.swift in Sources */, 2D9DB96B263A91D1007C1D71 /* APIService+DomainBlock.swift in Sources */, DBBF1DC92652538500E5B703 /* AutoCompleteSection.swift in Sources */, DB8AF55D25C138B7002E6C99 /* UIViewController.swift in Sources */, @@ -4069,6 +4111,7 @@ 2D5981A125E4A593000FB903 /* MastodonConfirmEmailViewModel.swift in Sources */, DB6B74F6272FBCDB00C70B6E /* FollowerListViewModel+State.swift in Sources */, DB87D4452609BE0500D12C0D /* ComposeStatusPollOptionCollectionViewCell.swift in Sources */, + DBDFF197280556D900557A48 /* DiscoveryPostsViewModel+State.swift in Sources */, DB336F2C278D6FC30031E64B /* Persistence+Status.swift in Sources */, DB336F2A278D6F2B0031E64B /* MastodonField.swift in Sources */, DB0FCB7A279576A2006C02E2 /* DataSourceFacade+Thread.swift in Sources */, @@ -4246,6 +4289,7 @@ DB6F5E38264E994A009108F4 /* AutoCompleteTopChevronView.swift in Sources */, DB6746F0278F463B008A6B94 /* AutoGenerateProtocolDelegate.swift in Sources */, DBB525412611ED54002F1F29 /* ProfileHeaderViewController.swift in Sources */, + DBDFF19A28055A1400557A48 /* DiscoveryViewController.swift in Sources */, DB9D6BFF25E4F5940051B173 /* ProfileViewController.swift in Sources */, DB63F756279949BD00455B82 /* Persistence+SearchHistory.swift in Sources */, 2D4AD8A226316CD200613EFC /* SelectedAccountSection.swift in Sources */, diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index ad09868c8..92edf05db 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 24 + 23 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 22 + 24 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 23 + 22 SuppressBuildableAutocreation diff --git a/Mastodon/Scene/Discovery/DiscoveryViewController.swift b/Mastodon/Scene/Discovery/DiscoveryViewController.swift new file mode 100644 index 000000000..4f909d6c2 --- /dev/null +++ b/Mastodon/Scene/Discovery/DiscoveryViewController.swift @@ -0,0 +1,94 @@ +// +// DiscoveryViewController.swift +// Mastodon +// +// Created by MainasuK on 2022-4-12. +// + +import os.log +import UIKit +import Combine +import Tabman +import MastodonAsset + +public class DiscoveryViewController: TabmanViewController, NeedsDependency { + + public static let containerViewMarginForRegularHorizontalSizeClass: CGFloat = 64 + public static let containerViewMarginForCompactHorizontalSizeClass: CGFloat = 16 + + var disposeBag = Set() + + let logger = Logger(subsystem: "DiscoveryViewController", category: "ViewController") + + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } + weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + + private(set) lazy var viewModel = DiscoveryViewModel( + context: context, + coordinator: coordinator + ) + + let buttonBar: TMBar.ButtonBar = { + let buttonBar = TMBar.ButtonBar() + buttonBar.indicator.backgroundColor = Asset.Colors.Label.primary.color + buttonBar.layout.contentInset = .zero + return buttonBar + }() + +} + +extension DiscoveryViewController { + + public override func viewDidLoad() { + super.viewDidLoad() + + setupAppearance(theme: ThemeService.shared.currentTheme.value) + ThemeService.shared.currentTheme + .receive(on: DispatchQueue.main) + .sink { [weak self] theme in + guard let self = self else { return } + self.setupAppearance(theme: theme) + } + .store(in: &disposeBag) + + dataSource = viewModel + addBar( + buttonBar, + dataSource: viewModel, + at: .top + ) + updateBarButtonInsets() + } + + public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + + updateBarButtonInsets() + } + +} + +extension DiscoveryViewController { + + private func setupAppearance(theme: Theme) { + view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor + buttonBar.backgroundView.style = .flat(color: theme.systemBackgroundColor) + } + + private func updateBarButtonInsets() { + let margin: CGFloat = { + switch traitCollection.userInterfaceIdiom { + case .phone: + return DiscoveryViewController.containerViewMarginForCompactHorizontalSizeClass + default: + return traitCollection.horizontalSizeClass == .regular ? + DiscoveryViewController.containerViewMarginForRegularHorizontalSizeClass : + DiscoveryViewController.containerViewMarginForCompactHorizontalSizeClass + } + }() + + buttonBar.layout.contentInset.left = margin + buttonBar.layout.contentInset.right = margin + } + +} diff --git a/Mastodon/Scene/Discovery/DiscoveryViewModel.swift b/Mastodon/Scene/Discovery/DiscoveryViewModel.swift new file mode 100644 index 000000000..137b86825 --- /dev/null +++ b/Mastodon/Scene/Discovery/DiscoveryViewModel.swift @@ -0,0 +1,72 @@ +// +// DiscoveryViewModel.swift +// Mastodon +// +// Created by MainasuK on 2022-4-12. +// + +import UIKit +import Tabman +import Pageboy + +final class DiscoveryViewModel { + + // input + let context: AppContext + let discoveryViewController: DiscoveryPostsViewController + + // output + let barItems: [TMBarItemable] = { + let items = [ + TMBarItem(title: "Posts"), + TMBarItem(title: "Hashtags"), + TMBarItem(title: "News"), + TMBarItem(title: "For You"), + ] + return items + }() + + var viewControllers: [ScrollViewContainer] { + return [ + discoveryViewController, + ] + } + + init(context: AppContext, coordinator: SceneCoordinator) { + self.context = context + discoveryViewController = { + let viewController = DiscoveryPostsViewController() + viewController.context = context + viewController.coordinator = coordinator + viewController.viewModel = DiscoveryPostsViewModel(context: context) + return viewController + }() + // end init + } + +} + + +// MARK: - PageboyViewControllerDataSource +extension DiscoveryViewModel: PageboyViewControllerDataSource { + + func numberOfViewControllers(in pageboyViewController: PageboyViewController) -> Int { + return viewControllers.count + } + + func viewController(for pageboyViewController: PageboyViewController, at index: PageboyViewController.PageIndex) -> UIViewController? { + return viewControllers[index] + } + + func defaultPage(for pageboyViewController: PageboyViewController) -> PageboyViewController.Page? { + return .first + } + +} + +// MARK: - TMBarDataSource +extension DiscoveryViewModel: TMBarDataSource { + func barItem(for bar: TMBar, at index: Int) -> TMBarItemable { + return barItems[index] + } +} diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController+DataSourceProvider.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController+DataSourceProvider.swift new file mode 100644 index 000000000..c3495b245 --- /dev/null +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController+DataSourceProvider.swift @@ -0,0 +1,34 @@ +// +// DiscoveryPostsViewController+DataSourceProvider.swift +// Mastodon +// +// Created by MainasuK on 2022-4-12. +// + +import UIKit + +extension DiscoveryPostsViewController: DataSourceProvider { + func item(from source: DataSourceItem.Source) async -> DataSourceItem? { + var _indexPath = source.indexPath + if _indexPath == nil, let cell = source.tableViewCell { + _indexPath = await self.indexPath(for: cell) + } + guard let indexPath = _indexPath else { return nil } + + guard let item = viewModel.diffableDataSource?.itemIdentifier(for: indexPath) else { + return nil + } + + switch item { + case .status(let record): + return .status(record: record) + default: + return nil + } + } + + @MainActor + private func indexPath(for cell: UITableViewCell) async -> IndexPath? { + return tableView.indexPath(for: cell) + } +} diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift new file mode 100644 index 000000000..3e813dbd8 --- /dev/null +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift @@ -0,0 +1,118 @@ +// +// DiscoveryPostsViewController.swift +// Mastodon +// +// Created by MainasuK on 2022-4-12. +// + +import os.log +import UIKit +import Combine + +final class DiscoveryPostsViewController: UIViewController, NeedsDependency, MediaPreviewableViewController { + + let logger = Logger(subsystem: "TrendPostsViewController", category: "ViewController") + + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } + weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + + var disposeBag = Set() + var viewModel: DiscoveryPostsViewModel! + + let mediaPreviewTransitionController = MediaPreviewTransitionController() + + lazy var tableView: UITableView = { + let tableView = UITableView() + tableView.rowHeight = UITableView.automaticDimension + tableView.estimatedRowHeight = 100 + tableView.separatorStyle = .none + tableView.backgroundColor = .clear + return tableView + }() + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } + +} + +extension DiscoveryPostsViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor + ThemeService.shared.currentTheme + .receive(on: DispatchQueue.main) + .sink { [weak self] theme in + guard let self = self else { return } + self.view.backgroundColor = theme.secondarySystemBackgroundColor + } + .store(in: &disposeBag) + + tableView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(tableView) + NSLayoutConstraint.activate([ + tableView.topAnchor.constraint(equalTo: view.topAnchor), + tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + ]) + + tableView.delegate = self + viewModel.setupDiffableDataSource( + tableView: tableView, + statusTableViewCellDelegate: self + ) + + // setup batch fetch + viewModel.listBatchFetchViewModel.setup(scrollView: tableView) + viewModel.listBatchFetchViewModel.shouldFetch + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in + guard let self = self else { return } + guard self.view.window != nil else { return } + self.viewModel.stateMachine.enter(DiscoveryPostsViewModel.State.Loading.self) + } + .store(in: &disposeBag) + } + +} + +// MARK: - UITableViewDelegate +extension DiscoveryPostsViewController: UITableViewDelegate, AutoGenerateTableViewDelegate { + // sourcery:inline:DiscoveryPostsViewController.AutoGenerateTableViewDelegate + + // Generated using Sourcery + // DO NOT EDIT + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + aspectTableView(tableView, didSelectRowAt: indexPath) + } + + func tableView(_ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? { + return aspectTableView(tableView, contextMenuConfigurationForRowAt: indexPath, point: point) + } + + func tableView(_ tableView: UITableView, previewForHighlightingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? { + return aspectTableView(tableView, previewForHighlightingContextMenuWithConfiguration: configuration) + } + + func tableView(_ tableView: UITableView, previewForDismissingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? { + return aspectTableView(tableView, previewForDismissingContextMenuWithConfiguration: configuration) + } + + func tableView(_ tableView: UITableView, willPerformPreviewActionForMenuWith configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionCommitAnimating) { + aspectTableView(tableView, willPerformPreviewActionForMenuWith: configuration, animator: animator) + } + // sourcery:end +} + +// MARK: - StatusTableViewCellDelegate +extension DiscoveryPostsViewController: StatusTableViewCellDelegate { } + +// MARK: ScrollViewContainer +extension DiscoveryPostsViewController: ScrollViewContainer { + var scrollView: UIScrollView? { + tableView + } +} diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+Diffable.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+Diffable.swift new file mode 100644 index 000000000..3abb4a21b --- /dev/null +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+Diffable.swift @@ -0,0 +1,63 @@ +// +// DiscoveryPostsViewModel+Diffable.swift +// Mastodon +// +// Created by MainasuK on 2022-4-12. +// + +import UIKit +import Combine + +extension DiscoveryPostsViewModel { + + func setupDiffableDataSource( + tableView: UITableView, + statusTableViewCellDelegate: StatusTableViewCellDelegate + ) { + diffableDataSource = StatusSection.diffableDataSource( + tableView: tableView, + context: context, + configuration: StatusSection.Configuration( + statusTableViewCellDelegate: statusTableViewCellDelegate, + timelineMiddleLoaderTableViewCellDelegate: nil, + filterContext: .none, + activeFilters: nil + ) + ) + + stateMachine.enter(State.Reloading.self) + + statusFetchedResultsController.$records + .debounce(for: .milliseconds(300), scheduler: DispatchQueue.main) + .sink { [weak self] records in + guard let self = self else { return } + guard let diffableDataSource = self.diffableDataSource else { return } + + var snapshot = NSDiffableDataSourceSnapshot() + snapshot.appendSections([.main]) + + let items = records.map { StatusItem.status(record: $0) } + snapshot.appendItems(items, toSection: .main) + + if let currentState = self.stateMachine.currentState { + switch currentState { + case is State.Initial, + is State.Reloading, + is State.Loading, + is State.Idle, + is State.Fail: + snapshot.appendItems([.bottomLoader], toSection: .main) + case is State.NoMore: + break + default: + assertionFailure() + break + } + } + + diffableDataSource.applySnapshot(snapshot, animated: false) + } + .store(in: &disposeBag) + } + +} diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift new file mode 100644 index 000000000..0a2178685 --- /dev/null +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift @@ -0,0 +1,208 @@ +// +// DiscoveryPostsViewModel+State.swift +// Mastodon +// +// Created by MainasuK on 2022-4-12. +// + +import os.log +import Foundation +import GameplayKit +import MastodonSDK + +extension DiscoveryPostsViewModel { + class State: GKState, NamingState { + + let logger = Logger(subsystem: "TrendPostsViewModel.State", category: "StateMachine") + + let id = UUID() + + var name: String { + String(describing: Self.self) + } + + weak var viewModel: DiscoveryPostsViewModel? + + init(viewModel: DiscoveryPostsViewModel) { + self.viewModel = viewModel + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + let previousState = previousState as? DiscoveryPostsViewModel.State + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [\(self.id.uuidString)] enter \(self.name), previous: \(previousState?.name ?? "")") + } + + @MainActor + func enter(state: State.Type) { + stateMachine?.enter(state) + } + + deinit { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [\(self.id.uuidString)] \(self.name)") + } + } +} + +extension DiscoveryPostsViewModel.State { + class Initial: DiscoveryPostsViewModel.State { + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Reloading.Type: + return true + default: + return false + } + } + } + + class Reloading: DiscoveryPostsViewModel.State { + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Loading.Type: + return true + default: + return false + } + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + guard let viewModel = viewModel, let stateMachine = stateMachine else { return } + + // reset + viewModel.statusFetchedResultsController.statusIDs.value = [] + + stateMachine.enter(Loading.self) + } + } + + class Fail: DiscoveryPostsViewModel.State { + + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Loading.Type: + return true + default: + return false + } + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + guard let _ = viewModel, let stateMachine = stateMachine else { return } + + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: retry loading 3s later…", ((#file as NSString).lastPathComponent), #line, #function) + DispatchQueue.main.asyncAfter(deadline: .now() + 3) { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: retry loading", ((#file as NSString).lastPathComponent), #line, #function) + stateMachine.enter(Loading.self) + } + } + } + + class Idle: DiscoveryPostsViewModel.State { + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Reloading.Type, is Loading.Type: + return true + default: + return false + } + } + } + + class Loading: DiscoveryPostsViewModel.State { + + var offset: Int? + + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Fail.Type: + return true + case is Idle.Type: + return true + case is NoMore.Type: + return true + default: + return false + } + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + guard let viewModel = viewModel, let stateMachine = stateMachine else { return } + + + switch previousState { + case is Reloading: + offset = nil + default: + break + } + + guard let authenticationBox = viewModel.context.authenticationService.activeMastodonAuthenticationBox.value else { + stateMachine.enter(Fail.self) + return + } + + let offset = self.offset + + Task { + do { + let response = try await viewModel.context.apiService.trendStatuses( + domain: authenticationBox.domain, + query: Mastodon.API.Trends.StatusQuery( + offset: offset, + limit: nil + ) + ) + let newOffset: Int? = { + guard let offset = response.link?.offset else { return nil } + return self.offset.flatMap { max($0, offset) } ?? offset + }() + + let hasMore: Bool = { + guard let newOffset = newOffset else { return false } + return newOffset != self.offset // not the same one + }() + + self.offset = newOffset + + var hasNewStatusesAppend = false + var statusIDs = viewModel.statusFetchedResultsController.statusIDs.value + for status in response.value { + guard !statusIDs.contains(status.id) else { continue } + statusIDs.append(status.id) + hasNewStatusesAppend = true + } + + if hasNewStatusesAppend, hasMore { + await enter(state: Idle.self) + } else { + await enter(state: NoMore.self) + } + viewModel.statusFetchedResultsController.statusIDs.value = statusIDs + + } catch { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): fetch user timeline fail: \(error.localizedDescription)") + await enter(state: Fail.self) + } + } // end Task + } // end func + } + + class NoMore: DiscoveryPostsViewModel.State { + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Reloading.Type: + return true + default: + return false + } + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + } + } +} diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift new file mode 100644 index 000000000..100a2a347 --- /dev/null +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift @@ -0,0 +1,59 @@ +// +// DiscoveryPostsViewModel.swift +// Mastodon +// +// Created by MainasuK on 2022-4-12. +// + +import os.log +import UIKit +import Combine +import GameplayKit +import CoreData +import CoreDataStack +import MastodonSDK + +final class DiscoveryPostsViewModel { + + var disposeBag = Set() + + // input + let context: AppContext + let statusFetchedResultsController: StatusFetchedResultsController + let listBatchFetchViewModel = ListBatchFetchViewModel() + + // output + var diffableDataSource: UITableViewDiffableDataSource? + private(set) lazy var stateMachine: GKStateMachine = { + let stateMachine = GKStateMachine(states: [ + State.Initial(viewModel: self), + State.Reloading(viewModel: self), + State.Fail(viewModel: self), + State.Idle(viewModel: self), + State.Loading(viewModel: self), + State.NoMore(viewModel: self), + ]) + stateMachine.enter(State.Initial.self) + return stateMachine + }() + + init(context: AppContext) { + self.context = context + self.statusFetchedResultsController = StatusFetchedResultsController( + managedObjectContext: context.managedObjectContext, + domain: nil, + additionalTweetPredicate: nil + ) + // end init + + context.authenticationService.activeMastodonAuthentication + .map { $0?.domain } + .assign(to: \.value, on: statusFetchedResultsController.domain) + .store(in: &disposeBag) + } + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } + +} diff --git a/Mastodon/Scene/Profile/ProfileViewController.swift b/Mastodon/Scene/Profile/ProfileViewController.swift index a890505ef..55a952b0e 100644 --- a/Mastodon/Scene/Profile/ProfileViewController.swift +++ b/Mastodon/Scene/Profile/ProfileViewController.swift @@ -402,6 +402,7 @@ extension ProfileViewController { } extension ProfileViewController { + private func updateBarButtonInsets() { let margin: CGFloat = { switch traitCollection.userInterfaceIdiom { diff --git a/Mastodon/Scene/Profile/Timeline/UserTimelineViewController.swift b/Mastodon/Scene/Profile/Timeline/UserTimelineViewController.swift index 12925ca41..d9e52a8c7 100644 --- a/Mastodon/Scene/Profile/Timeline/UserTimelineViewController.swift +++ b/Mastodon/Scene/Profile/Timeline/UserTimelineViewController.swift @@ -36,7 +36,7 @@ final class UserTimelineViewController: UIViewController, NeedsDependency, Media let cellFrameCache = NSCache() deinit { - os_log("%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) } } diff --git a/Mastodon/Scene/Search/Search/SearchViewController.swift b/Mastodon/Scene/Search/Search/SearchViewController.swift index d1bed9484..6f4d22009 100644 --- a/Mastodon/Scene/Search/Search/SearchViewController.swift +++ b/Mastodon/Scene/Search/Search/SearchViewController.swift @@ -48,6 +48,13 @@ final class SearchViewController: UIViewController, NeedsDependency { let searchBarTapPublisher = PassthroughSubject() + private(set) lazy var trendViewController: DiscoveryViewController = { + let viewController = DiscoveryViewController() + viewController.context = context + viewController.coordinator = coordinator + return viewController + }() + deinit { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) } @@ -84,6 +91,16 @@ extension SearchViewController { viewModel.setupDiffableDataSource( collectionView: collectionView ) + + addChild(trendViewController) + trendViewController.view.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(trendViewController.view) + NSLayoutConstraint.activate([ + trendViewController.view.topAnchor.constraint(equalTo: view.topAnchor), + trendViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), + trendViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), + trendViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor), + ]) } override func viewDidAppear(_ animated: Bool) { diff --git a/Mastodon/Scene/Search/Search/SearchViewModel.swift b/Mastodon/Scene/Search/Search/SearchViewModel.swift index 2776713df..84e097250 100644 --- a/Mastodon/Scene/Search/Search/SearchViewModel.swift +++ b/Mastodon/Scene/Search/Search/SearchViewModel.swift @@ -38,7 +38,7 @@ final class SearchViewModel: NSObject { } .throttle(for: 3, scheduler: DispatchQueue.main, latest: true) .asyncMap { authenticationBox in - try await context.apiService.trends(domain: authenticationBox.domain, query: nil) + try await context.apiService.trendHashtags(domain: authenticationBox.domain, query: nil) } .retry(3) .map { response in Result, Error> { response } } diff --git a/Mastodon/Service/APIService/APIService+Trend.swift b/Mastodon/Service/APIService/APIService+Trend.swift index 0ce2a86a8..34edae09e 100644 --- a/Mastodon/Service/APIService/APIService+Trend.swift +++ b/Mastodon/Service/APIService/APIService+Trend.swift @@ -9,11 +9,12 @@ import Foundation import MastodonSDK extension APIService { - func trends( + + func trendHashtags( domain: String, - query: Mastodon.API.Trends.Query? + query: Mastodon.API.Trends.HashtagQuery? ) async throws -> Mastodon.Response.Content<[Mastodon.Entity.Tag]> { - let response = try await Mastodon.API.Trends.get( + let response = try await Mastodon.API.Trends.hashtags( session: session, domain: domain, query: query @@ -21,4 +22,35 @@ extension APIService { return response } + + func trendStatuses( + domain: String, + query: Mastodon.API.Trends.StatusQuery + ) async throws -> Mastodon.Response.Content<[Mastodon.Entity.Status]> { + let response = try await Mastodon.API.Trends.statuses( + session: session, + domain: domain, + query: query + ).singleOutput() + + let managedObjectContext = backgroundManagedObjectContext + try await managedObjectContext.performChanges { + for entity in response.value { + _ = Persistence.Status.createOrMerge( + in: managedObjectContext, + context: Persistence.Status.PersistContext( + domain: domain, + entity: entity, + me: nil, + statusCache: nil, + userCache: nil, + networkDate: response.networkDate + ) + ) + } // end for … in + } + + return response + } + } diff --git a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Trends.swift b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Trends.swift index 385e3d756..25e130e32 100644 --- a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Trends.swift +++ b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Trends.swift @@ -9,6 +9,7 @@ import Combine import Foundation extension Mastodon.API.Trends { + static func trendsURL(domain: String) -> URL { Mastodon.API.endpointURL(domain: domain).appendingPathComponent("trends") } @@ -27,10 +28,10 @@ extension Mastodon.API.Trends { /// - query: query /// - Returns: `AnyPublisher` contains `Hashtags` nested in the response - public static func get( + public static func hashtags( session: URLSession, domain: String, - query: Mastodon.API.Trends.Query? + query: Mastodon.API.Trends.HashtagQuery? ) -> AnyPublisher, Error> { let request = Mastodon.API.get( url: trendsURL(domain: domain), @@ -44,10 +45,8 @@ extension Mastodon.API.Trends { } .eraseToAnyPublisher() } -} -extension Mastodon.API.Trends { - public struct Query: Codable, GetQuery { + public struct HashtagQuery: Codable, GetQuery { public init(limit: Int?) { self.limit = limit } @@ -61,4 +60,69 @@ extension Mastodon.API.Trends { return items } } + +} + +extension Mastodon.API.Trends { + + static func trendStatusesURL(domain: String) -> URL { + Mastodon.API.endpointURL(domain: domain) + .appendingPathComponent("trends") + .appendingPathComponent("statuses") + } + + /// Trending tags + /// + /// Tags that are being used more frequently within the past week. + /// + /// Version history: + /// 3.?.? + /// # Reference + /// [Document](https://docs.joinmastodon.org/methods/instance/trends/) + /// - Parameters: + /// - session: `URLSession` + /// - domain: Mastodon instance domain. e.g. "example.com" + /// - query: query + /// - Returns: `AnyPublisher` contains `Hashtags` nested in the response + + public static func statuses( + session: URLSession, + domain: String, + query: Mastodon.API.Trends.StatusQuery? + ) -> AnyPublisher, Error> { + let request = Mastodon.API.get( + url: trendStatusesURL(domain: domain), + query: query, + authorization: nil + ) + return session.dataTaskPublisher(for: request) + .tryMap { data, response in + let value = try Mastodon.API.decode(type: [Mastodon.Entity.Status].self, from: data, response: response) + return Mastodon.Response.Content(value: value, response: response) + } + .eraseToAnyPublisher() + } + + public struct StatusQuery: Codable, GetQuery { + + public let offset: Int? + public let limit: Int? // Maximum number of results to return. Defaults to 10. + + public init( + offset: Int?, + limit: Int? + ) { + self.offset = offset + self.limit = limit + } + + var queryItems: [URLQueryItem]? { + var items: [URLQueryItem] = [] + offset.flatMap { items.append(URLQueryItem(name: "offset", value: String($0))) } + limit.flatMap { items.append(URLQueryItem(name: "limit", value: String($0))) } + guard !items.isEmpty else { return nil } + return items + } + } + } diff --git a/MastodonSDK/Sources/MastodonSDK/Response/Mastodon+Response+Content.swift b/MastodonSDK/Sources/MastodonSDK/Response/Mastodon+Response+Content.swift index db42169d8..6cf95752b 100644 --- a/MastodonSDK/Sources/MastodonSDK/Response/Mastodon+Response+Content.swift +++ b/MastodonSDK/Sources/MastodonSDK/Response/Mastodon+Response+Content.swift @@ -106,6 +106,7 @@ extension Mastodon.Response { public struct Link { public let maxID: Mastodon.Entity.Status.ID? public let minID: Mastodon.Entity.Status.ID? + public let offset: Int? init(link: String) { self.maxID = { @@ -125,6 +126,15 @@ extension Mastodon.Response { let id = link[range] return String(id) }() + + self.offset = { + guard let regex = try? NSRegularExpression(pattern: "offset=([[:digit:]]+)", options: []) else { return nil } + let results = regex.matches(in: link, options: [], range: NSRange(link.startIndex.. Date: Wed, 13 Apr 2022 20:43:16 +0800 Subject: [PATCH 009/101] feat: add hashtag and news list for Discovery scene --- Mastodon.xcodeproj/project.pbxproj | 120 ++++++---- .../xcshareddata/xcschemes/Mastodon.xcscheme | 8 + .../xcschemes/xcschememanagement.plist | 4 +- .../Diffiable/Discovery/DiscoveryItem.swift | 15 ++ .../Discovery/DiscoverySection.swift | 52 +++++ Mastodon/Diffiable/Search/SearchSection.swift | 19 -- .../MastodonSDK/Mastodon+Entity+Tag.swift | 11 - .../MastodonUI/ThemeService.swift} | 6 +- Mastodon/Extension/UIView.swift | 70 ------ Mastodon/Preference/ThemePreference.swift | 14 -- ...seStatusPollOptionCollectionViewCell.swift | 1 + .../Discovery/DiscoveryViewController.swift | 1 + .../Scene/Discovery/DiscoveryViewModel.swift | 30 ++- .../DiscoveryHashtagsViewController.swift | 113 ++++++++++ .../DiscoveryHashtagsViewModel+Diffable.swift | 42 ++++ .../Hashtags/DiscoveryHashtagsViewModel.swift | 63 ++++++ .../News/DiscoveryNewsViewController.swift | 133 +++++++++++ .../DiscoveryNewsViewModel+Diffable.swift | 60 +++++ .../News/DiscoveryNewsViewModel+State.swift | 209 ++++++++++++++++++ .../News/DiscoveryNewsViewModel.swift | 51 +++++ .../Posts/DiscoveryPostsViewController.swift | 30 +++ .../DiscoveryPostsViewModel+Diffable.swift | 8 +- .../Posts/DiscoveryPostsViewModel+State.swift | 8 +- .../Posts/DiscoveryPostsViewModel.swift | 2 + .../HomeTimelineViewController.swift | 3 +- .../Root/MainTab/MainTabBarController.swift | 1 + .../Root/Sidebar/SidebarViewController.swift | 1 + .../Search/Cell/TrendCollectionViewCell.swift | 79 +------ .../View/SearchHistoryTableHeaderView.swift | 1 + .../Content/ContentWarningOverlayView.swift | 1 + .../Content/MediaView+Configuration.swift | 2 +- .../Share/View/Content/ThreadMetaView.swift | 1 + .../Service/APIService/APIService+Trend.swift | 13 ++ Mastodon/Service/SettingService.swift | 15 +- .../Preference/Preference+Theme.swift | 26 +++ .../Sources/MastodonExtension/UIView.swift | 34 +++ .../Sources/MastodonExtension/UInt64.swift | 12 + .../MastodonSDK/API/Mastodon+API+Trends.swift | 50 ++++- .../Entity/Mastodon+Entity+Link.swift | 54 +++++ .../Entity/Mastodon+Entity+Tag.swift | 1 + .../MastodonSDK/Mastodon+Entity+Link.swift | 21 ++ .../MastodonSDK/Mastodon+Entity+Tag.swift | 21 ++ .../Sources/MastodonUI/Extension/UIView.swift | 34 +++ .../Service/ThemeService/MastodonTheme.swift | 1 + .../Service/ThemeService/SystemTheme.swift | 1 + .../Service/ThemeService/Theme.swift | 15 +- .../Service/ThemeService/ThemeService.swift | 16 +- .../MastodonUI/Vendor}/CurveAlgorithm.swift | 0 .../View/Content/NewsView+Configuration.swift | 43 ++++ .../MastodonUI/View/Content/NewsView.swift | 102 +++++++++ .../Content/TrendView+Configuration.swift | 35 +++ .../MastodonUI/View/Content/TrendView.swift | 100 +++++++++ .../View/Control}/LineChartView.swift | 20 +- .../TableViewCell/NewsTableViewCell.swift | 56 +++++ .../TableViewCell/TrendTableViewCell.swift | 86 +++++++ .../Scene/ShareViewController.swift | 1 + .../Scene/ShareViewModel.swift | 1 + .../Scene/View/ComposeToolbarView.swift | 1 + 58 files changed, 1619 insertions(+), 299 deletions(-) create mode 100644 Mastodon/Diffiable/Discovery/DiscoveryItem.swift create mode 100644 Mastodon/Diffiable/Discovery/DiscoverySection.swift rename Mastodon/{Service/ThemeService/ThemeService+Appearance.swift => Extension/MastodonUI/ThemeService.swift} (97%) delete mode 100644 Mastodon/Extension/UIView.swift create mode 100644 Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift create mode 100644 Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel+Diffable.swift create mode 100644 Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel.swift create mode 100644 Mastodon/Scene/Discovery/News/DiscoveryNewsViewController.swift create mode 100644 Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+Diffable.swift create mode 100644 Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift create mode 100644 Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel.swift create mode 100644 MastodonSDK/Sources/MastodonCommon/Preference/Preference+Theme.swift create mode 100644 MastodonSDK/Sources/MastodonExtension/UInt64.swift create mode 100644 MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Link.swift create mode 100644 MastodonSDK/Sources/MastodonUI/Extension/MastodonSDK/Mastodon+Entity+Link.swift create mode 100644 MastodonSDK/Sources/MastodonUI/Extension/MastodonSDK/Mastodon+Entity+Tag.swift create mode 100644 MastodonSDK/Sources/MastodonUI/Extension/UIView.swift rename {Mastodon => MastodonSDK/Sources/MastodonUI}/Service/ThemeService/MastodonTheme.swift (98%) rename {Mastodon => MastodonSDK/Sources/MastodonUI}/Service/ThemeService/SystemTheme.swift (98%) rename {Mastodon => MastodonSDK/Sources/MastodonUI}/Service/ThemeService/Theme.swift (82%) rename {Mastodon => MastodonSDK/Sources/MastodonUI}/Service/ThemeService/ThemeService.swift (57%) rename {Mastodon/Vender => MastodonSDK/Sources/MastodonUI/Vendor}/CurveAlgorithm.swift (100%) create mode 100644 MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift create mode 100644 MastodonSDK/Sources/MastodonUI/View/Content/NewsView.swift create mode 100644 MastodonSDK/Sources/MastodonUI/View/Content/TrendView+Configuration.swift create mode 100644 MastodonSDK/Sources/MastodonUI/View/Content/TrendView.swift rename {Mastodon/Scene/Search/Search/View => MastodonSDK/Sources/MastodonUI/View/Control}/LineChartView.swift (85%) create mode 100644 MastodonSDK/Sources/MastodonUI/View/TableViewCell/NewsTableViewCell.swift create mode 100644 MastodonSDK/Sources/MastodonUI/View/TableViewCell/TrendTableViewCell.swift diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 98da13748..73332bab8 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -31,7 +31,6 @@ 2D206B9225F60EA700143C56 /* UIControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D206B9125F60EA700143C56 /* UIControl.swift */; }; 2D24E1232626ED9D00A59D4F /* UIView+Gesture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D24E1222626ED9D00A59D4F /* UIView+Gesture.swift */; }; 2D32EAAC25CB96DC00C9ED86 /* TimelineMiddleLoaderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D32EAAB25CB96DC00C9ED86 /* TimelineMiddleLoaderTableViewCell.swift */; }; - 2D32EABA25CB9B0500C9ED86 /* UIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D32EAB925CB9B0500C9ED86 /* UIView.swift */; }; 2D34D9D126148D9E0081BFC0 /* APIService+Recommend.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D34D9D026148D9E0081BFC0 /* APIService+Recommend.swift */; }; 2D34D9DB261494120081BFC0 /* APIService+Search.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D34D9DA261494120081BFC0 /* APIService+Search.swift */; }; 2D35237A26256D920031AF25 /* NotificationSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D35237926256D920031AF25 /* NotificationSection.swift */; }; @@ -223,6 +222,16 @@ DB3667A6268AE2620027D07F /* ComposeStatusPollSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3667A5268AE2620027D07F /* ComposeStatusPollSection.swift */; }; DB3667A8268AE2900027D07F /* ComposeStatusPollItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3667A7268AE2900027D07F /* ComposeStatusPollItem.swift */; }; DB3D0FF325BAA61700EAA174 /* AlamofireImage in Frameworks */ = {isa = PBXBuildFile; productRef = DB3D0FF225BAA61700EAA174 /* AlamofireImage */; }; + DB3E6FDD2806A40F00B035AE /* DiscoveryHashtagsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FDC2806A40F00B035AE /* DiscoveryHashtagsViewController.swift */; }; + DB3E6FE02806A4ED00B035AE /* DiscoveryHashtagsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FDF2806A4ED00B035AE /* DiscoveryHashtagsViewModel.swift */; }; + DB3E6FE22806A50100B035AE /* DiscoveryHashtagsViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FE12806A50100B035AE /* DiscoveryHashtagsViewModel+Diffable.swift */; }; + DB3E6FE42806A5B800B035AE /* DiscoverySection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FE32806A5B800B035AE /* DiscoverySection.swift */; }; + DB3E6FE72806A7A200B035AE /* DiscoveryItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FE62806A7A200B035AE /* DiscoveryItem.swift */; }; + DB3E6FE92806BD2200B035AE /* ThemeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FE82806BD2200B035AE /* ThemeService.swift */; }; + DB3E6FEC2806D7F100B035AE /* DiscoveryNewsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FEB2806D7F100B035AE /* DiscoveryNewsViewController.swift */; }; + DB3E6FEF2806D82600B035AE /* DiscoveryNewsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FEE2806D82600B035AE /* DiscoveryNewsViewModel.swift */; }; + DB3E6FF12806D96900B035AE /* DiscoveryNewsViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FF02806D96900B035AE /* DiscoveryNewsViewModel+Diffable.swift */; }; + DB3E6FF32806D97400B035AE /* DiscoveryNewsViewModel+State.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FF22806D97400B035AE /* DiscoveryNewsViewModel+State.swift */; }; DB427DD625BAA00100D1B89D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB427DD525BAA00100D1B89D /* AppDelegate.swift */; }; DB427DD825BAA00100D1B89D /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB427DD725BAA00100D1B89D /* SceneDelegate.swift */; }; DB427DDD25BAA00100D1B89D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DB427DDB25BAA00100D1B89D /* Main.storyboard */; }; @@ -376,8 +385,6 @@ DB6D9F9726367249008423CD /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6D9F9626367249008423CD /* SettingsViewController.swift */; }; DB6F5E35264E78E7009108F4 /* AutoCompleteViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6F5E34264E78E7009108F4 /* AutoCompleteViewController.swift */; }; DB6F5E38264E994A009108F4 /* AutoCompleteTopChevronView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6F5E37264E994A009108F4 /* AutoCompleteTopChevronView.swift */; }; - DB71C7CB271D5A0300BE3819 /* LineChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB71C7CA271D5A0300BE3819 /* LineChartView.swift */; }; - DB71C7CD271D7F4300BE3819 /* CurveAlgorithm.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB71C7CC271D7F4300BE3819 /* CurveAlgorithm.swift */; }; DB71FD5225F8CCAA00512AE1 /* APIService+Status.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB71FD5125F8CCAA00512AE1 /* APIService+Status.swift */; }; DB72601C25E36A2100235243 /* MastodonServerRulesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB72601B25E36A2100235243 /* MastodonServerRulesViewController.swift */; }; DB72602725E36A6F00235243 /* MastodonServerRulesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB72602625E36A6F00235243 /* MastodonServerRulesViewModel.swift */; }; @@ -508,16 +515,7 @@ DBBC24AA26A5301B00398BB9 /* MastodonSDK in Frameworks */ = {isa = PBXBuildFile; productRef = DBBC24A926A5301B00398BB9 /* MastodonSDK */; }; DBBC24AC26A53D9300398BB9 /* ComposeStatusContentTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24AB26A53D9300398BB9 /* ComposeStatusContentTableViewCell.swift */; }; DBBC24B826A5421800398BB9 /* CommonOSLog in Frameworks */ = {isa = PBXBuildFile; productRef = DBBC24B726A5421800398BB9 /* CommonOSLog */; }; - DBBC24BC26A542F500398BB9 /* ThemeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24BB26A542F500398BB9 /* ThemeService.swift */; }; - DBBC24C026A5443100398BB9 /* MastodonTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24BE26A5443100398BB9 /* MastodonTheme.swift */; }; - DBBC24C126A5443100398BB9 /* SystemTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24BF26A5443100398BB9 /* SystemTheme.swift */; }; - DBBC24C426A544B900398BB9 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24C326A544B900398BB9 /* Theme.swift */; }; - DBBC24C626A5456000398BB9 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24C326A544B900398BB9 /* Theme.swift */; }; - DBBC24C726A5456400398BB9 /* SystemTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24BF26A5443100398BB9 /* SystemTheme.swift */; }; - DBBC24C826A5456400398BB9 /* ThemeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24BB26A542F500398BB9 /* ThemeService.swift */; }; - DBBC24C926A5456400398BB9 /* MastodonTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24BE26A5443100398BB9 /* MastodonTheme.swift */; }; DBBC24CB26A546C000398BB9 /* ThemePreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBD376AB2692ECDB007FEC24 /* ThemePreference.swift */; }; - DBBC24CF26A547AE00398BB9 /* ThemeService+Appearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24CE26A547AE00398BB9 /* ThemeService+Appearance.swift */; }; DBBC24D126A5484F00398BB9 /* UITextView+Placeholder in Frameworks */ = {isa = PBXBuildFile; productRef = DBBC24D026A5484F00398BB9 /* UITextView+Placeholder */; }; DBBC24DC26A54BCB00398BB9 /* MastodonRegex.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24D626A54BCB00398BB9 /* MastodonRegex.swift */; }; DBBC24DE26A54BCB00398BB9 /* MastodonMetricFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24D826A54BCB00398BB9 /* MastodonMetricFormatter.swift */; }; @@ -735,7 +733,6 @@ 2D206B9125F60EA700143C56 /* UIControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIControl.swift; sourceTree = ""; }; 2D24E1222626ED9D00A59D4F /* UIView+Gesture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Gesture.swift"; sourceTree = ""; }; 2D32EAAB25CB96DC00C9ED86 /* TimelineMiddleLoaderTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineMiddleLoaderTableViewCell.swift; sourceTree = ""; }; - 2D32EAB925CB9B0500C9ED86 /* UIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIView.swift; sourceTree = ""; }; 2D34D9D026148D9E0081BFC0 /* APIService+Recommend.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Recommend.swift"; sourceTree = ""; }; 2D34D9DA261494120081BFC0 /* APIService+Search.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Search.swift"; sourceTree = ""; }; 2D35237926256D920031AF25 /* NotificationSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSection.swift; sourceTree = ""; }; @@ -956,6 +953,16 @@ DB3667A5268AE2620027D07F /* ComposeStatusPollSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusPollSection.swift; sourceTree = ""; }; DB3667A7268AE2900027D07F /* ComposeStatusPollItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusPollItem.swift; sourceTree = ""; }; DB3D0FED25BAA42200EAA174 /* MastodonSDK */ = {isa = PBXFileReference; lastKnownFileType = folder; path = MastodonSDK; sourceTree = ""; }; + DB3E6FDC2806A40F00B035AE /* DiscoveryHashtagsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryHashtagsViewController.swift; sourceTree = ""; }; + DB3E6FDF2806A4ED00B035AE /* DiscoveryHashtagsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryHashtagsViewModel.swift; sourceTree = ""; }; + DB3E6FE12806A50100B035AE /* DiscoveryHashtagsViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiscoveryHashtagsViewModel+Diffable.swift"; sourceTree = ""; }; + DB3E6FE32806A5B800B035AE /* DiscoverySection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoverySection.swift; sourceTree = ""; }; + DB3E6FE62806A7A200B035AE /* DiscoveryItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryItem.swift; sourceTree = ""; }; + DB3E6FE82806BD2200B035AE /* ThemeService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeService.swift; sourceTree = ""; }; + DB3E6FEB2806D7F100B035AE /* DiscoveryNewsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryNewsViewController.swift; sourceTree = ""; }; + DB3E6FEE2806D82600B035AE /* DiscoveryNewsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryNewsViewModel.swift; sourceTree = ""; }; + DB3E6FF02806D96900B035AE /* DiscoveryNewsViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiscoveryNewsViewModel+Diffable.swift"; sourceTree = ""; }; + DB3E6FF22806D97400B035AE /* DiscoveryNewsViewModel+State.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiscoveryNewsViewModel+State.swift"; sourceTree = ""; }; DB427DD225BAA00100D1B89D /* Mastodon.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Mastodon.app; sourceTree = BUILT_PRODUCTS_DIR; }; DB427DD525BAA00100D1B89D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; DB427DD725BAA00100D1B89D /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; @@ -1126,8 +1133,6 @@ DB6D9F9626367249008423CD /* SettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = ""; }; DB6F5E34264E78E7009108F4 /* AutoCompleteViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoCompleteViewController.swift; sourceTree = ""; }; DB6F5E37264E994A009108F4 /* AutoCompleteTopChevronView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoCompleteTopChevronView.swift; sourceTree = ""; }; - DB71C7CA271D5A0300BE3819 /* LineChartView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineChartView.swift; sourceTree = ""; }; - DB71C7CC271D7F4300BE3819 /* CurveAlgorithm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurveAlgorithm.swift; sourceTree = ""; }; DB71FD5125F8CCAA00512AE1 /* APIService+Status.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Status.swift"; sourceTree = ""; }; DB72601B25E36A2100235243 /* MastodonServerRulesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonServerRulesViewController.swift; sourceTree = ""; }; DB72602625E36A6F00235243 /* MastodonServerRulesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonServerRulesViewModel.swift; sourceTree = ""; }; @@ -1263,11 +1268,6 @@ DBB9759B262462E1004620BD /* ThreadMetaView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadMetaView.swift; sourceTree = ""; }; DBBC24A726A52F9000398BB9 /* ComposeToolbarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeToolbarView.swift; sourceTree = ""; }; DBBC24AB26A53D9300398BB9 /* ComposeStatusContentTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusContentTableViewCell.swift; sourceTree = ""; }; - DBBC24BB26A542F500398BB9 /* ThemeService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeService.swift; sourceTree = ""; }; - DBBC24BE26A5443100398BB9 /* MastodonTheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonTheme.swift; sourceTree = ""; }; - DBBC24BF26A5443100398BB9 /* SystemTheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SystemTheme.swift; sourceTree = ""; }; - DBBC24C326A544B900398BB9 /* Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = ""; }; - DBBC24CE26A547AE00398BB9 /* ThemeService+Appearance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ThemeService+Appearance.swift"; sourceTree = ""; }; DBBC24D626A54BCB00398BB9 /* MastodonRegex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MastodonRegex.swift; sourceTree = ""; }; DBBC24D826A54BCB00398BB9 /* MastodonMetricFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MastodonMetricFormatter.swift; sourceTree = ""; }; DBBC50C0278ED49200AF0CC6 /* MastodonAuthenticationBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonAuthenticationBox.swift; sourceTree = ""; }; @@ -1668,7 +1668,6 @@ 2D5A3D0125CF8640002347D6 /* Vender */ = { isa = PBXGroup; children = ( - DB71C7CC271D7F4300BE3819 /* CurveAlgorithm.swift */, 2D5A3D0225CF8742002347D6 /* ControlContainableScrollViews.swift */, DB51D170262832380062B7A1 /* BlurHashDecode.swift */, DB51D171262832380062B7A1 /* BlurHashEncode.swift */, @@ -1687,7 +1686,6 @@ DB45FB0425CA87B4005A8AC7 /* APIService */, DB49A61925FF327D00B98345 /* EmojiService */, DB9A489B26036E19008B817C /* MastodonAttachmentService */, - DBBC24BD26A5441A00398BB9 /* ThemeService */, DB45FB0E25CA87D0005A8AC7 /* AuthenticationService.swift */, 2DA6054625F716A2006356F9 /* PlaybackState.swift */, DBC7A67B260DFADE00E57475 /* StatusPublishService.swift */, @@ -1731,6 +1729,7 @@ DB4F097626A0398000D62E92 /* Compose */, DB0617F727855B010030EE79 /* Notification */, DB4F097726A039A200D62E92 /* Search */, + DB3E6FE52806A5BA00B035AE /* Discovery */, DB0617FA27855B660030EE79 /* Settings */, DBCBED2226132E1D00B49291 /* FetchedResultsController */, ); @@ -1817,7 +1816,6 @@ isa = PBXGroup; children = ( 2DCB73FC2615C13900EC03D4 /* SearchRecommendCollectionHeader.swift */, - DB71C7CA271D5A0300BE3819 /* LineChartView.swift */, ); path = View; sourceTree = ""; @@ -2111,6 +2109,44 @@ path = Resources; sourceTree = ""; }; + DB3E6FDE2806A41200B035AE /* Hashtags */ = { + isa = PBXGroup; + children = ( + DB3E6FDC2806A40F00B035AE /* DiscoveryHashtagsViewController.swift */, + DB3E6FDF2806A4ED00B035AE /* DiscoveryHashtagsViewModel.swift */, + DB3E6FE12806A50100B035AE /* DiscoveryHashtagsViewModel+Diffable.swift */, + ); + path = Hashtags; + sourceTree = ""; + }; + DB3E6FE52806A5BA00B035AE /* Discovery */ = { + isa = PBXGroup; + children = ( + DB3E6FE32806A5B800B035AE /* DiscoverySection.swift */, + DB3E6FE62806A7A200B035AE /* DiscoveryItem.swift */, + ); + path = Discovery; + sourceTree = ""; + }; + DB3E6FEA2806BD2500B035AE /* MastodonUI */ = { + isa = PBXGroup; + children = ( + DB3E6FE82806BD2200B035AE /* ThemeService.swift */, + ); + path = MastodonUI; + sourceTree = ""; + }; + DB3E6FED2806D7FC00B035AE /* News */ = { + isa = PBXGroup; + children = ( + DB3E6FEB2806D7F100B035AE /* DiscoveryNewsViewController.swift */, + DB3E6FEE2806D82600B035AE /* DiscoveryNewsViewModel.swift */, + DB3E6FF02806D96900B035AE /* DiscoveryNewsViewModel+Diffable.swift */, + DB3E6FF22806D97400B035AE /* DiscoveryNewsViewModel+State.swift */, + ); + path = News; + sourceTree = ""; + }; DB427DC925BAA00100D1B89D = { isa = PBXGroup; children = ( @@ -2706,6 +2742,7 @@ isa = PBXGroup; children = ( DB084B5125CBC56300F898ED /* CoreDataStack */, + DB3E6FEA2806BD2500B035AE /* MastodonUI */, DB6C8C0525F0921200AAA452 /* MastodonSDK */, 2DF123A625C3B0210020F248 /* ActiveLabel.swift */, 5DF1056325F887CB00D6C0D4 /* AVPlayer.swift */, @@ -2723,7 +2760,6 @@ DBD376B1269302A4007FEC24 /* UITableViewCell.swift */, 0FAA101B25E10E760017CCDE /* UIFont.swift */, 2D206B9125F60EA700143C56 /* UIControl.swift */, - 2D32EAB925CB9B0500C9ED86 /* UIView.swift */, 5DA732CB2629CEF500A92342 /* UIView+Remove.swift */, 2D24E1222626ED9D00A59D4F /* UIView+Gesture.swift */, DB8AF55C25C138B7002E6C99 /* UIViewController.swift */, @@ -3020,18 +3056,6 @@ path = Service; sourceTree = ""; }; - DBBC24BD26A5441A00398BB9 /* ThemeService */ = { - isa = PBXGroup; - children = ( - DBBC24C326A544B900398BB9 /* Theme.swift */, - DBBC24BE26A5443100398BB9 /* MastodonTheme.swift */, - DBBC24BF26A5443100398BB9 /* SystemTheme.swift */, - DBBC24BB26A542F500398BB9 /* ThemeService.swift */, - DBBC24CE26A547AE00398BB9 /* ThemeService+Appearance.swift */, - ); - path = ThemeService; - sourceTree = ""; - }; DBBC24D526A54BCB00398BB9 /* Helper */ = { isa = PBXGroup; children = ( @@ -3087,6 +3111,8 @@ isa = PBXGroup; children = ( DBDFF19828055A0900557A48 /* Posts */, + DB3E6FDE2806A41200B035AE /* Hashtags */, + DB3E6FED2806D7FC00B035AE /* News */, DBDFF19928055A1400557A48 /* DiscoveryViewController.swift */, DBDFF19B28055BD600557A48 /* DiscoveryViewModel.swift */, ); @@ -3861,6 +3887,7 @@ DB336F43278EB1690031E64B /* MediaView+Configuration.swift in Sources */, DB66729625F9F91600D60309 /* ComposeStatusSection.swift in Sources */, DB482A3F261331E8008AE74C /* UserTimelineViewModel+State.swift in Sources */, + DB3E6FE02806A4ED00B035AE /* DiscoveryHashtagsViewModel.swift in Sources */, 2D38F1F725CD47AC00561493 /* HomeTimelineViewModel+LoadOldestState.swift in Sources */, DB447681260B3ED600B66B82 /* CustomEmojiPickerSection.swift in Sources */, DB0FCB7427956939006C02E2 /* DataSourceFacade+Status.swift in Sources */, @@ -3924,6 +3951,7 @@ DB06180A2785B2AB0030EE79 /* MastodonRegisterAvatarTableViewCell.swift in Sources */, DBB45B6227B51112002DC5A7 /* SuggestionAccountViewModel+Diffable.swift in Sources */, DBB3BA2A26A81C020004F2D4 /* FLAnimatedImageView.swift in Sources */, + DB3E6FF32806D97400B035AE /* DiscoveryNewsViewModel+State.swift in Sources */, DB6746ED278F45F0008A6B94 /* AutoGenerateProtocolRelayDelegate.swift in Sources */, DB0618032785A7100030EE79 /* RegisterSection.swift in Sources */, DB63F76B279A5ED300455B82 /* NotificationTimelineViewModel+LoadOldestState.swift in Sources */, @@ -3952,6 +3980,7 @@ 2D24E1232626ED9D00A59D4F /* UIView+Gesture.swift in Sources */, DBFEEC9D279C12C1004F81DD /* ProfileFieldEditCollectionViewCell.swift in Sources */, DB45FAE325CA7181005A8AC7 /* MastodonUser.swift in Sources */, + DB3E6FEC2806D7F100B035AE /* DiscoveryNewsViewController.swift in Sources */, DBA088DF26958164003EB4B2 /* UserFetchedResultsController.swift in Sources */, DB2FF510260B113300ADA9FE /* ComposeStatusPollExpiresOptionCollectionViewCell.swift in Sources */, 0F202213261351F5000C64BF /* APIService+HashtagTimeline.swift in Sources */, @@ -3993,7 +4022,6 @@ 2D4AD8A826316D3500613EFC /* SelectedAccountItem.swift in Sources */, DBE3CDFB261C6CA500430CC6 /* FavoriteViewModel.swift in Sources */, DB8AF52F25C13561002E6C99 /* DocumentStore.swift in Sources */, - DBBC24C126A5443100398BB9 /* SystemTheme.swift in Sources */, DBE3CE01261D623D00430CC6 /* FavoriteViewModel+State.swift in Sources */, 2D82BA0525E7897700E36F0F /* MastodonResendEmailViewModelNavigationDelegateShim.swift in Sources */, 2D38F1EB25CD477000561493 /* HomeTimelineViewModel+LoadLatestState.swift in Sources */, @@ -4020,6 +4048,7 @@ DB63F76227996B6600455B82 /* SearchHistoryViewController+DataSourceProvider.swift in Sources */, DB73BF4927140BA300781945 /* UICollectionViewDiffableDataSource.swift in Sources */, DBA5E7AB263BD3F5004598BB /* TimelineTableViewCellContextMenuConfiguration.swift in Sources */, + DB3E6FE92806BD2200B035AE /* ThemeService.swift in Sources */, DB73B490261F030A002E9E9F /* SafariActivity.swift in Sources */, DB63F7492799126300455B82 /* FollowerListViewController+DataSourceProvider.swift in Sources */, DB6D1B44263691CF00ACB481 /* Mastodon+API+Subscriptions+Policy.swift in Sources */, @@ -4056,6 +4085,7 @@ DBDFF1932805554900557A48 /* DiscoveryPostsViewModel.swift in Sources */, 2D9DB96B263A91D1007C1D71 /* APIService+DomainBlock.swift in Sources */, DBBF1DC92652538500E5B703 /* AutoCompleteSection.swift in Sources */, + DB3E6FE72806A7A200B035AE /* DiscoveryItem.swift in Sources */, DB8AF55D25C138B7002E6C99 /* UIViewController.swift in Sources */, DB7F48452620241000796008 /* ProfileHeaderViewModel.swift in Sources */, DB647C5926F1EA2700F7F82C /* WizardPreference.swift in Sources */, @@ -4078,6 +4108,7 @@ 5B90C462262599800002E742 /* SettingsSectionHeader.swift in Sources */, DB44768B260B3F2100B66B82 /* CustomEmojiPickerItem.swift in Sources */, 5DF1056425F887CB00D6C0D4 /* AVPlayer.swift in Sources */, + DB3E6FEF2806D82600B035AE /* DiscoveryNewsViewModel.swift in Sources */, DBBF1DCB2652539E00E5B703 /* AutoCompleteItem.swift in Sources */, DB84811727883C2600BBEABA /* MastodonRegisterPasswordHintTableViewCell.swift in Sources */, 2DA6054725F716A2006356F9 /* PlaybackState.swift in Sources */, @@ -4139,7 +4170,7 @@ DB4AA6B327BA34B6009EC082 /* CellFrameCacheContainer.swift in Sources */, DB0FCB942797E2B0006C02E2 /* SearchResultViewModel+Diffable.swift in Sources */, DB63F752279944AA00455B82 /* SearchHistorySectionHeaderCollectionReusableView.swift in Sources */, - DBBC24C426A544B900398BB9 /* Theme.swift in Sources */, + DB3E6FDD2806A40F00B035AE /* DiscoveryHashtagsViewController.swift in Sources */, DB938EED2623F79B00E5B6C1 /* ThreadViewModel.swift in Sources */, DBBC24AC26A53D9300398BB9 /* ComposeStatusContentTableViewCell.swift in Sources */, DBC7A67C260DFADE00E57475 /* StatusPublishService.swift in Sources */, @@ -4158,7 +4189,6 @@ DBBF1DC5265251C300E5B703 /* AutoCompleteViewModel+Diffable.swift in Sources */, DB603111279EB38500A935FE /* DataSourceFacade+Mute.swift in Sources */, DB68A04A25E9027700CFDF14 /* AdaptiveStatusBarStyleNavigationController.swift in Sources */, - DBBC24BC26A542F500398BB9 /* ThemeService.swift in Sources */, DB336F38278D7AAF0031E64B /* Poll+Property.swift in Sources */, 0FB3D33825E6401400AAD544 /* PickServerCell.swift in Sources */, DB6D9F8426358EEC008423CD /* SettingsItem.swift in Sources */, @@ -4171,7 +4201,6 @@ DB4FFC2C269EC39600D62E92 /* SearchTransitionController.swift in Sources */, DBA5E7A9263BD3A4004598BB /* ContextMenuImagePreviewViewController.swift in Sources */, DBF156E22702DA6900EC00B7 /* UIStatusBarManager+HandleTapAction.m in Sources */, - 2D32EABA25CB9B0500C9ED86 /* UIView.swift in Sources */, 2D38F20825CD491300561493 /* DisposeBagCollectable.swift in Sources */, DB6F5E35264E78E7009108F4 /* AutoCompleteViewController.swift in Sources */, DB697DE1278F5296004EF2F7 /* DataSourceFacade+Model.swift in Sources */, @@ -4179,7 +4208,6 @@ DB4F097526A037F500D62E92 /* SearchHistoryViewModel.swift in Sources */, DB6180F826391D660018D199 /* MediaPreviewingViewController.swift in Sources */, DB0140CF25C42AEE00F9F3CF /* OSLog.swift in Sources */, - DB71C7CB271D5A0300BE3819 /* LineChartView.swift in Sources */, DB98EB5627B0FF1B0082E365 /* ReportViewControllerAppearance.swift in Sources */, DB938F1526241FDF00E5B6C1 /* APIService+Thread.swift in Sources */, 2D206B8625F5FB0900143C56 /* Double.swift in Sources */, @@ -4201,6 +4229,7 @@ DBD376AC2692ECDB007FEC24 /* ThemePreference.swift in Sources */, DB4F097D26A03A5B00D62E92 /* SearchHistoryItem.swift in Sources */, DBD5B1FA27BD013700BD6B38 /* DataSourceProvider+StatusTableViewControllerNavigateable.swift in Sources */, + DB3E6FE22806A50100B035AE /* DiscoveryHashtagsViewModel+Diffable.swift in Sources */, DB68046C2636DC9E00430867 /* MastodonNotification.swift in Sources */, DBAE3F9E2616E308004B8251 /* APIService+Mute.swift in Sources */, DB427DD625BAA00100D1B89D /* AppDelegate.swift in Sources */, @@ -4247,7 +4276,6 @@ DB8AF52E25C13561002E6C99 /* ViewStateStore.swift in Sources */, DB1D61CF26F1B33600DA8662 /* WelcomeViewModel.swift in Sources */, 2DA7D04A25CA52CB00804E11 /* TimelineBottomLoaderTableViewCell.swift in Sources */, - DB71C7CD271D7F4300BE3819 /* CurveAlgorithm.swift in Sources */, DBD376B2269302A4007FEC24 /* UITableViewCell.swift in Sources */, DB4F0966269ED52200D62E92 /* SearchResultViewModel.swift in Sources */, DBBF1DBF2652401B00E5B703 /* AutoCompleteViewModel.swift in Sources */, @@ -4264,25 +4292,25 @@ 0F2021FB2613262F000C64BF /* HashtagTimelineViewController.swift in Sources */, DB697DDD278F521D004EF2F7 /* DataSourceFacade.swift in Sources */, DBCC3B30261440A50045B23D /* UITabBarController.swift in Sources */, + DB3E6FE42806A5B800B035AE /* DiscoverySection.swift in Sources */, DB8190C62601FF0400020C08 /* AttachmentContainerView.swift in Sources */, DB697DDB278F4DE3004EF2F7 /* DataSourceProvider+StatusTableViewCellDelegate.swift in Sources */, DB51D173262832380062B7A1 /* BlurHashEncode.swift in Sources */, 2D32EAAC25CB96DC00C9ED86 /* TimelineMiddleLoaderTableViewCell.swift in Sources */, DB87D4512609CF1E00D12C0D /* ComposeStatusPollOptionAppendEntryCollectionViewCell.swift in Sources */, DBB45B5627B39FC9002DC5A7 /* MediaPreviewVideoViewController.swift in Sources */, - DBBC24C026A5443100398BB9 /* MastodonTheme.swift in Sources */, DB0FCB8027968F70006C02E2 /* MastodonStatusThreadViewModel.swift in Sources */, DB0FCB6E27950E6B006C02E2 /* MastodonMention.swift in Sources */, DB67D08627312E67006A36CF /* WizardViewController.swift in Sources */, DB6746EB278ED8B0008A6B94 /* PollOptionView+Configuration.swift in Sources */, DB9A489026035963008B817C /* APIService+Media.swift in Sources */, DBFEEC99279BDCDE004F81DD /* ProfileAboutViewModel.swift in Sources */, - DBBC24CF26A547AE00398BB9 /* ThemeService+Appearance.swift in Sources */, 2D198649261C0B8500F0B013 /* SearchResultSection.swift in Sources */, DB4F097B26A039FF00D62E92 /* SearchHistorySection.swift in Sources */, DBB525302611EBF3002F1F29 /* ProfilePagingViewModel.swift in Sources */, DB9F58EC26EF435000E7BBE9 /* AccountViewController.swift in Sources */, 2D5A3D6225CFD9CB002347D6 /* HomeTimelineViewController+DebugAction.swift in Sources */, + DB3E6FF12806D96900B035AE /* DiscoveryNewsViewModel+Diffable.swift in Sources */, DB49A62525FF334C00B98345 /* EmojiService+CustomEmojiViewModel+LoadState.swift in Sources */, DB4924E226312AB200E9DB22 /* NotificationService.swift in Sources */, DB6D9F6F2635807F008423CD /* Setting.swift in Sources */, @@ -4390,15 +4418,11 @@ DBFEF07526A69192006D7ED1 /* APIService+Media.swift in Sources */, DBFEF06F26A690C4006D7ED1 /* APIService+APIError.swift in Sources */, DBFEF05C26A57715006D7ED1 /* StatusEditorView.swift in Sources */, - DBBC24C726A5456400398BB9 /* SystemTheme.swift in Sources */, - DBBC24C826A5456400398BB9 /* ThemeService.swift in Sources */, - DBBC24C926A5456400398BB9 /* MastodonTheme.swift in Sources */, DBFEF07C26A6BD0A006D7ED1 /* APIService+Status+Publish.swift in Sources */, DBB3BA2B26A81D060004F2D4 /* FLAnimatedImageView.swift in Sources */, DB6746E8278ED639008A6B94 /* MastodonAuthenticationBox.swift in Sources */, DBBC24A826A52F9000398BB9 /* ComposeToolbarView.swift in Sources */, DBFEF05B26A57715006D7ED1 /* ComposeViewModel.swift in Sources */, - DBBC24C626A5456000398BB9 /* Theme.swift in Sources */, DBFEF06326A577F2006D7ED1 /* StatusAttachmentViewModel.swift in Sources */, DBFEF06926A67E45006D7ED1 /* AppearancePreference.swift in Sources */, DBC6461526A170AB00B0E31B /* ShareViewController.swift in Sources */, diff --git a/Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon.xcscheme b/Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon.xcscheme index 488d5a2da..048ce3cf5 100644 --- a/Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon.xcscheme +++ b/Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon.xcscheme @@ -73,6 +73,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + enableAddressSanitizer = "YES" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" @@ -89,6 +90,13 @@ ReferencedContainer = "container:Mastodon.xcodeproj"> + + + + NotificationService.xcscheme_^#shared#^_ orderHint - 24 + 22 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 22 + 24 SuppressBuildableAutocreation diff --git a/Mastodon/Diffiable/Discovery/DiscoveryItem.swift b/Mastodon/Diffiable/Discovery/DiscoveryItem.swift new file mode 100644 index 000000000..181756d25 --- /dev/null +++ b/Mastodon/Diffiable/Discovery/DiscoveryItem.swift @@ -0,0 +1,15 @@ +// +// DiscoveryItem.swift +// Mastodon +// +// Created by MainasuK on 2022-4-13. +// + +import Foundation +import MastodonSDK + +enum DiscoveryItem: Hashable { + case hashtag(Mastodon.Entity.Tag) + case link(Mastodon.Entity.Link) + case bottomLoader +} diff --git a/Mastodon/Diffiable/Discovery/DiscoverySection.swift b/Mastodon/Diffiable/Discovery/DiscoverySection.swift new file mode 100644 index 000000000..32683609d --- /dev/null +++ b/Mastodon/Diffiable/Discovery/DiscoverySection.swift @@ -0,0 +1,52 @@ +// +// DiscoverySection.swift +// Mastodon +// +// Created by MainasuK on 2022-4-13. +// + +import os.log +import UIKit +import MastodonUI + +enum DiscoverySection: CaseIterable { + // case posts + case hashtags + case news + case forYou +} + +extension DiscoverySection { + + static let logger = Logger(subsystem: "DiscoverySection", category: "logic") + + struct Configuration { } + + static func diffableDataSource( + tableView: UITableView, + context: AppContext, + configuration: Configuration + ) -> UITableViewDiffableDataSource { + tableView.register(TrendTableViewCell.self, forCellReuseIdentifier: String(describing: TrendTableViewCell.self)) + tableView.register(NewsTableViewCell.self, forCellReuseIdentifier: String(describing: NewsTableViewCell.self)) + tableView.register(TimelineBottomLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self)) + + return UITableViewDiffableDataSource(tableView: tableView) { tableView, indexPath, item in + switch item { + case .hashtag(let tag): + let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TrendTableViewCell.self), for: indexPath) as! TrendTableViewCell + cell.trendView.configure(tag: tag) + return cell + case .link(let link): + let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: NewsTableViewCell.self), for: indexPath) as! NewsTableViewCell + cell.newsView.configure(link: link) + return cell + case .bottomLoader: + let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self), for: indexPath) as! TimelineBottomLoaderTableViewCell + cell.activityIndicatorView.startAnimating() + return cell + } + } + } + +} diff --git a/Mastodon/Diffiable/Search/SearchSection.swift b/Mastodon/Diffiable/Search/SearchSection.swift index 21f1d479c..4f550abf7 100644 --- a/Mastodon/Diffiable/Search/SearchSection.swift +++ b/Mastodon/Diffiable/Search/SearchSection.swift @@ -21,26 +21,7 @@ extension SearchSection { ) -> UICollectionViewDiffableDataSource { let trendCellRegister = UICollectionView.CellRegistration { cell, indexPath, item in - let primaryLabelText = "#" + item.name - let secondaryLabelText = L10n.Scene.Search.Recommend.HashTag.peopleTalking(item.talkingPeopleCount ?? 0) - cell.primaryLabel.text = primaryLabelText - cell.secondaryLabel.text = secondaryLabelText - - cell.lineChartView.data = (item.history ?? []) - .sorted(by: { $0.day < $1.day }) // latest last - .map { entry in - guard let point = Int(entry.accounts) else { - return .zero - } - return CGFloat(point) - } - - cell.isAccessibilityElement = true - cell.accessibilityLabel = [ - primaryLabelText, - secondaryLabelText - ].joined(separator: ", ") } let dataSource = UICollectionViewDiffableDataSource( diff --git a/Mastodon/Extension/MastodonSDK/Mastodon+Entity+Tag.swift b/Mastodon/Extension/MastodonSDK/Mastodon+Entity+Tag.swift index 2d0be6965..e217d3a82 100644 --- a/Mastodon/Extension/MastodonSDK/Mastodon+Entity+Tag.swift +++ b/Mastodon/Extension/MastodonSDK/Mastodon+Entity+Tag.swift @@ -17,14 +17,3 @@ extension Mastodon.Entity.Tag: Hashable { } } -extension Mastodon.Entity.Tag { - - /// the sum of recent 2 days - public var talkingPeopleCount: Int? { - return history? - .prefix(2) - .compactMap { Int($0.accounts) } - .reduce(0, +) - } - -} diff --git a/Mastodon/Service/ThemeService/ThemeService+Appearance.swift b/Mastodon/Extension/MastodonUI/ThemeService.swift similarity index 97% rename from Mastodon/Service/ThemeService/ThemeService+Appearance.swift rename to Mastodon/Extension/MastodonUI/ThemeService.swift index 896ed888e..5fe213d06 100644 --- a/Mastodon/Service/ThemeService/ThemeService+Appearance.swift +++ b/Mastodon/Extension/MastodonUI/ThemeService.swift @@ -1,11 +1,13 @@ // -// ThemeService+Appearance.swift +// ThemeService.swift // Mastodon // -// Created by MainasuK Cirno on 2021-7-19. +// Created by MainasuK on 2022-4-13. // import UIKit +import MastodonCommon +import MastodonUI extension ThemeService { func set(themeName: ThemeName) { diff --git a/Mastodon/Extension/UIView.swift b/Mastodon/Extension/UIView.swift deleted file mode 100644 index d4814b7ec..000000000 --- a/Mastodon/Extension/UIView.swift +++ /dev/null @@ -1,70 +0,0 @@ -// -// UIView.swift -// Mastodon -// -// Created by sxiaojian on 2021/2/4. -// - -import UIKit - -// MARK: - Convenience view creation method -extension UIView { - - static let separatorColor: UIColor = { - UIColor(dynamicProvider: { collection in - switch collection.userInterfaceStyle { - case .dark: - return ThemeService.shared.currentTheme.value.separator - default: - return .separator - } - }) - }() - - static var separatorLine: UIView { - let line = UIView() - line.backgroundColor = UIView.separatorColor - return line - } - - static func separatorLineHeight(of view: UIView) -> CGFloat { - return 1.0 / view.traitCollection.displayScale - } - -} - -// MARK: - Convenience view appearance modification method -extension UIView { - @discardableResult - func applyCornerRadius(radius: CGFloat) -> Self { - layer.masksToBounds = true - layer.cornerRadius = radius - layer.cornerCurve = .continuous - return self - } - - @discardableResult - func applyShadow( - color: UIColor, - alpha: Float, - x: CGFloat, - y: CGFloat, - blur: CGFloat, - spread: CGFloat = 0) -> Self - { - layer.masksToBounds = false - layer.shadowColor = color.cgColor - layer.shadowOpacity = alpha - layer.shadowOffset = CGSize(width: x, height: y) - layer.shadowRadius = blur / 2.0 - if spread == 0 { - layer.shadowPath = nil - } else { - let dx = -spread - let rect = bounds.insetBy(dx: dx, dy: dx) - layer.shadowPath = UIBezierPath(rect: rect).cgPath - } - return self - } -} - diff --git a/Mastodon/Preference/ThemePreference.swift b/Mastodon/Preference/ThemePreference.swift index 624047798..5465cb22f 100644 --- a/Mastodon/Preference/ThemePreference.swift +++ b/Mastodon/Preference/ThemePreference.swift @@ -5,17 +5,3 @@ // Created by MainasuK Cirno on 2021-7-5. // -import UIKit -import MastodonExtension - -extension UserDefaults { - - @objc dynamic var currentThemeNameRawValue: String { - get { - register(defaults: [#function: ThemeName.mastodon.rawValue]) - return string(forKey: #function) ?? ThemeName.mastodon.rawValue - } - set { self[#function] = newValue } - } - -} diff --git a/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusPollOptionCollectionViewCell.swift b/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusPollOptionCollectionViewCell.swift index 7ea43f154..c1869669c 100644 --- a/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusPollOptionCollectionViewCell.swift +++ b/Mastodon/Scene/Compose/CollectionViewCell/ComposeStatusPollOptionCollectionViewCell.swift @@ -10,6 +10,7 @@ import UIKit import Combine import MastodonAsset import MastodonLocalization +import MastodonUI protocol ComposeStatusPollOptionCollectionViewCellDelegate: AnyObject { func composeStatusPollOptionCollectionViewCell(_ cell: ComposeStatusPollOptionCollectionViewCell, textFieldDidBeginEditing textField: UITextField) diff --git a/Mastodon/Scene/Discovery/DiscoveryViewController.swift b/Mastodon/Scene/Discovery/DiscoveryViewController.swift index 4f909d6c2..dac2c99c3 100644 --- a/Mastodon/Scene/Discovery/DiscoveryViewController.swift +++ b/Mastodon/Scene/Discovery/DiscoveryViewController.swift @@ -10,6 +10,7 @@ import UIKit import Combine import Tabman import MastodonAsset +import MastodonUI public class DiscoveryViewController: TabmanViewController, NeedsDependency { diff --git a/Mastodon/Scene/Discovery/DiscoveryViewModel.swift b/Mastodon/Scene/Discovery/DiscoveryViewModel.swift index 137b86825..acb92b5f4 100644 --- a/Mastodon/Scene/Discovery/DiscoveryViewModel.swift +++ b/Mastodon/Scene/Discovery/DiscoveryViewModel.swift @@ -13,7 +13,9 @@ final class DiscoveryViewModel { // input let context: AppContext - let discoveryViewController: DiscoveryPostsViewController + let discoveryPostsViewController: DiscoveryPostsViewController + let discoveryHashtagsViewController: DiscoveryHashtagsViewController + let discoveryNewsViewController: DiscoveryNewsViewController // output let barItems: [TMBarItemable] = { @@ -28,19 +30,37 @@ final class DiscoveryViewModel { var viewControllers: [ScrollViewContainer] { return [ - discoveryViewController, + discoveryPostsViewController, + discoveryHashtagsViewController, + discoveryNewsViewController, ] } init(context: AppContext, coordinator: SceneCoordinator) { + func setupDependency(_ needsDependency: NeedsDependency) { + needsDependency.context = context + needsDependency.coordinator = coordinator + } + self.context = context - discoveryViewController = { + discoveryPostsViewController = { let viewController = DiscoveryPostsViewController() - viewController.context = context - viewController.coordinator = coordinator + setupDependency(viewController) viewController.viewModel = DiscoveryPostsViewModel(context: context) return viewController }() + discoveryHashtagsViewController = { + let viewController = DiscoveryHashtagsViewController() + setupDependency(viewController) + viewController.viewModel = DiscoveryHashtagsViewModel(context: context) + return viewController + }() + discoveryNewsViewController = { + let viewController = DiscoveryNewsViewController() + setupDependency(viewController) + viewController.viewModel = DiscoveryNewsViewModel(context: context) + return viewController + }() // end init } diff --git a/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift new file mode 100644 index 000000000..1dca1232a --- /dev/null +++ b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift @@ -0,0 +1,113 @@ +// +// DiscoveryHashtagsViewController.swift +// Mastodon +// +// Created by MainasuK on 2022-4-13. +// + +import os.log +import UIKit +import Combine +import MastodonUI + +final class DiscoveryHashtagsViewController: UIViewController, NeedsDependency, MediaPreviewableViewController { + + let logger = Logger(subsystem: "TrendPostsViewController", category: "ViewController") + + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } + weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + + var disposeBag = Set() + var viewModel: DiscoveryHashtagsViewModel! + + let mediaPreviewTransitionController = MediaPreviewTransitionController() + + lazy var tableView: UITableView = { + let tableView = UITableView() + tableView.rowHeight = UITableView.automaticDimension + tableView.estimatedRowHeight = 100 + tableView.separatorStyle = .none + tableView.backgroundColor = .clear + return tableView + }() + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } + +} + +extension DiscoveryHashtagsViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor + ThemeService.shared.currentTheme + .receive(on: DispatchQueue.main) + .sink { [weak self] theme in + guard let self = self else { return } + self.view.backgroundColor = theme.secondarySystemBackgroundColor + } + .store(in: &disposeBag) + + tableView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(tableView) + NSLayoutConstraint.activate([ + tableView.topAnchor.constraint(equalTo: view.topAnchor), + tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + ]) + + tableView.delegate = self + viewModel.setupDiffableDataSource( + tableView: tableView + ) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + tableView.deselectRow(with: transitionCoordinator, animated: animated) + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + viewModel.viewDidAppeared.send() + } + +} + +// MARK: - UITableViewDelegate +extension DiscoveryHashtagsViewController: UITableViewDelegate { + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): \(indexPath)") + guard case let .hashtag(tag) = viewModel.diffableDataSource?.itemIdentifier(for: indexPath) else { return } + let hashtagTimelineViewModel = HashtagTimelineViewModel(context: context, hashtag: tag.name) + coordinator.present( + scene: .hashtagTimeline(viewModel: hashtagTimelineViewModel), + from: self, + transition: .show + ) + } + + func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { + guard let cell = cell as? TrendTableViewCell else { return } + guard let diffableDataSource = viewModel.diffableDataSource else { return } + guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return } + + if let lastItem = diffableDataSource.snapshot().itemIdentifiers.last, item == lastItem { + cell.configureSeparator(style: .edge) + } + } +} + +// MARK: ScrollViewContainer +extension DiscoveryHashtagsViewController: ScrollViewContainer { + var scrollView: UIScrollView? { + tableView + } +} diff --git a/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel+Diffable.swift b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel+Diffable.swift new file mode 100644 index 000000000..0370f3f58 --- /dev/null +++ b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel+Diffable.swift @@ -0,0 +1,42 @@ +// +// DiscoveryHashtagsViewModel+Diffable.swift +// Mastodon +// +// Created by MainasuK on 2022-4-13. +// + +import UIKit + +extension DiscoveryHashtagsViewModel { + + func setupDiffableDataSource( + tableView: UITableView + ) { + diffableDataSource = DiscoverySection.diffableDataSource( + tableView: tableView, + context: context, + configuration: DiscoverySection.Configuration() + ) + + var snapshot = NSDiffableDataSourceSnapshot() + snapshot.appendSections([.hashtags]) + diffableDataSource?.apply(snapshot) + + $hashtags + .receive(on: DispatchQueue.main) + .sink { [weak self] hashtags in + guard let self = self else { return } + guard let diffableDataSource = self.diffableDataSource else { return } + + var snapshot = NSDiffableDataSourceSnapshot() + snapshot.appendSections([.hashtags]) + + let items = hashtags.map { DiscoveryItem.hashtag($0) } + snapshot.appendItems(items, toSection: .hashtags) + + diffableDataSource.apply(snapshot) + } + .store(in: &disposeBag) + } + +} diff --git a/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel.swift b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel.swift new file mode 100644 index 000000000..5f51d6459 --- /dev/null +++ b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel.swift @@ -0,0 +1,63 @@ +// +// DiscoveryHashtagsViewModel.swift +// Mastodon +// +// Created by MainasuK on 2022-4-13. +// + +import os.log +import UIKit +import Combine +import GameplayKit +import CoreData +import CoreDataStack +import MastodonSDK + +final class DiscoveryHashtagsViewModel { + + var disposeBag = Set() + + // input + let context: AppContext + let viewDidAppeared = PassthroughSubject() + + // output + var diffableDataSource: UITableViewDiffableDataSource? + @Published var hashtags: [Mastodon.Entity.Tag] = [] + + init(context: AppContext) { + self.context = context + // end init + + Publishers.CombineLatest( + context.authenticationService.activeMastodonAuthenticationBox, + viewDidAppeared + ) + .compactMap { authenticationBox, _ -> MastodonAuthenticationBox? in + return authenticationBox + } + .throttle(for: 3, scheduler: DispatchQueue.main, latest: true) + .asyncMap { authenticationBox in + try await context.apiService.trendHashtags(domain: authenticationBox.domain, query: nil) + } + .retry(3) + .map { response in Result, Error> { response } } + .catch { error in Just(Result, Error> { throw error }) } + .receive(on: DispatchQueue.main) + .sink { [weak self] result in + guard let self = self else { return } + switch result { + case .success(let response): + self.hashtags = response.value.filter { !$0.name.isEmpty } + case .failure: + break + } + } + .store(in: &disposeBag) + } + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } + +} diff --git a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewController.swift b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewController.swift new file mode 100644 index 000000000..4042e2cd5 --- /dev/null +++ b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewController.swift @@ -0,0 +1,133 @@ +// +// DiscoveryNewsViewController.swift +// Mastodon +// +// Created by MainasuK on 2022-4-13. +// + +import os.log +import UIKit +import Combine +import MastodonUI + +final class DiscoveryNewsViewController: UIViewController, NeedsDependency, MediaPreviewableViewController { + + let logger = Logger(subsystem: "TrendPostsViewController", category: "ViewController") + + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } + weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + + var disposeBag = Set() + var viewModel: DiscoveryNewsViewModel! + + let mediaPreviewTransitionController = MediaPreviewTransitionController() + + lazy var tableView: UITableView = { + let tableView = UITableView() + tableView.rowHeight = UITableView.automaticDimension + tableView.estimatedRowHeight = 100 + tableView.separatorStyle = .none + tableView.backgroundColor = .clear + return tableView + }() + + let refreshControl = UIRefreshControl() + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } + +} + +extension DiscoveryNewsViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor + ThemeService.shared.currentTheme + .receive(on: DispatchQueue.main) + .sink { [weak self] theme in + guard let self = self else { return } + self.view.backgroundColor = theme.secondarySystemBackgroundColor + } + .store(in: &disposeBag) + + tableView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(tableView) + NSLayoutConstraint.activate([ + tableView.topAnchor.constraint(equalTo: view.topAnchor), + tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + ]) + + tableView.delegate = self + viewModel.setupDiffableDataSource( + tableView: tableView + ) + + tableView.refreshControl = refreshControl + refreshControl.addTarget(self, action: #selector(DiscoveryNewsViewController.refreshControlValueChanged(_:)), for: .valueChanged) + viewModel.didLoadLatest + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in + guard let self = self else { return } + self.refreshControl.endRefreshing() + } + .store(in: &disposeBag) + + // setup batch fetch + viewModel.listBatchFetchViewModel.setup(scrollView: tableView) + viewModel.listBatchFetchViewModel.shouldFetch + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in + guard let self = self else { return } + guard self.view.window != nil else { return } + self.viewModel.stateMachine.enter(DiscoveryNewsViewModel.State.Loading.self) + } + .store(in: &disposeBag) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + refreshControl.endRefreshing() + tableView.deselectRow(with: transitionCoordinator, animated: animated) + } + +} + +extension DiscoveryNewsViewController { + + @objc private func refreshControlValueChanged(_ sender: UIRefreshControl) { + guard viewModel.stateMachine.enter(DiscoveryNewsViewModel.State.Reloading.self) else { + sender.endRefreshing() + return + } + } + +} + +// MARK: - UITableViewDelegate +extension DiscoveryNewsViewController: UITableViewDelegate { + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): \(indexPath)") + guard case let .link(link) = viewModel.diffableDataSource?.itemIdentifier(for: indexPath) else { return } + guard let url = URL(string: link.url) else { return } + coordinator.present( + scene: .safari(url: url), + from: self, + transition: .safariPresent(animated: true, completion: nil) + ) + } + +} + +// MARK: ScrollViewContainer +extension DiscoveryNewsViewController: ScrollViewContainer { + var scrollView: UIScrollView? { + tableView + } +} diff --git a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+Diffable.swift b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+Diffable.swift new file mode 100644 index 000000000..ab3634a3f --- /dev/null +++ b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+Diffable.swift @@ -0,0 +1,60 @@ +// +// DiscoveryNewsViewModel+Diffable.swift +// Mastodon +// +// Created by MainasuK on 2022-4-13. +// + +import UIKit +import Combine + +extension DiscoveryNewsViewModel { + + func setupDiffableDataSource( + tableView: UITableView + ) { + diffableDataSource = DiscoverySection.diffableDataSource( + tableView: tableView, + context: context, + configuration: DiscoverySection.Configuration() + ) + + stateMachine.enter(State.Reloading.self) + + $links + .receive(on: DispatchQueue.main) + .sink { [weak self] links in + guard let self = self else { return } + guard let diffableDataSource = self.diffableDataSource else { return } + + var snapshot = NSDiffableDataSourceSnapshot() + snapshot.appendSections([.news]) + + let items = links.map { DiscoveryItem.link($0) } + snapshot.appendItems(items, toSection: .news) + + if let currentState = self.stateMachine.currentState { + switch currentState { + case is State.Initial, + is State.Loading, + is State.Idle, + is State.Fail: + if !items.isEmpty { + snapshot.appendItems([.bottomLoader], toSection: .news) + } + case is State.Reloading: + break + case is State.NoMore: + break + default: + assertionFailure() + break + } + } + + diffableDataSource.applySnapshot(snapshot, animated: false) + } + .store(in: &disposeBag) + } + +} diff --git a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift new file mode 100644 index 000000000..82d604d64 --- /dev/null +++ b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift @@ -0,0 +1,209 @@ +// +// DiscoveryNewsViewModel+State.swift +// Mastodon +// +// Created by MainasuK on 2022-4-13. +// + +import os.log +import Foundation +import GameplayKit +import MastodonSDK + +extension DiscoveryNewsViewModel { + class State: GKState, NamingState { + + let logger = Logger(subsystem: "DiscoveryNewsViewModel.State", category: "StateMachine") + + let id = UUID() + + var name: String { + String(describing: Self.self) + } + + weak var viewModel: DiscoveryNewsViewModel? + + init(viewModel: DiscoveryNewsViewModel) { + self.viewModel = viewModel + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + let previousState = previousState as? DiscoveryNewsViewModel.State + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [\(self.id.uuidString)] enter \(self.name), previous: \(previousState?.name ?? "")") + } + + @MainActor + func enter(state: State.Type) { + stateMachine?.enter(state) + } + + deinit { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [\(self.id.uuidString)] \(self.name)") + } + } +} + +extension DiscoveryNewsViewModel.State { + class Initial: DiscoveryNewsViewModel.State { + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Reloading.Type: + return true + default: + return false + } + } + } + + class Reloading: DiscoveryNewsViewModel.State { + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Loading.Type: + return true + default: + return false + } + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + guard let viewModel = viewModel, let stateMachine = stateMachine else { return } + + viewModel.links = [] + + stateMachine.enter(Loading.self) + } + } + + class Fail: DiscoveryNewsViewModel.State { + + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Loading.Type: + return true + default: + return false + } + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + guard let _ = viewModel, let stateMachine = stateMachine else { return } + + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: retry loading 3s later…", ((#file as NSString).lastPathComponent), #line, #function) + DispatchQueue.main.asyncAfter(deadline: .now() + 3) { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: retry loading", ((#file as NSString).lastPathComponent), #line, #function) + stateMachine.enter(Loading.self) + } + } + } + + class Idle: DiscoveryNewsViewModel.State { + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Reloading.Type, is Loading.Type: + return true + default: + return false + } + } + } + + class Loading: DiscoveryNewsViewModel.State { + + var offset: Int? + var isReloading: Bool { return offset == nil } + + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Fail.Type: + return true + case is Idle.Type: + return true + case is NoMore.Type: + return true + default: + return false + } + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + guard let viewModel = viewModel, let stateMachine = stateMachine else { return } + + + switch previousState { + case is Reloading: + offset = nil + default: + break + } + + guard let authenticationBox = viewModel.context.authenticationService.activeMastodonAuthenticationBox.value else { + stateMachine.enter(Fail.self) + return + } + + let offset = self.offset + + Task { + do { + let response = try await viewModel.context.apiService.trendLinks( + domain: authenticationBox.domain, + query: Mastodon.API.Trends.StatusQuery( + offset: offset, + limit: nil + ) + ) + let newOffset: Int? = { + guard let offset = response.link?.offset else { return nil } + return self.offset.flatMap { max($0, offset) } ?? offset + }() + + let hasMore: Bool = { + guard let newOffset = newOffset else { return false } + return newOffset != self.offset // not the same one + }() + + self.offset = newOffset + + var hasNewItemsAppend = false + var links = viewModel.links + for link in response.value { + guard !links.contains(link) else { continue } + links.append(link) + hasNewItemsAppend = true + } + + if hasNewItemsAppend, hasMore { + await enter(state: Idle.self) + } else { + await enter(state: NoMore.self) + } + viewModel.links = links + viewModel.didLoadLatest.send() + } catch { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): fetch news fail: \(error.localizedDescription)") + await enter(state: Fail.self) + viewModel.didLoadLatest.send() + } + } // end Task + } // end func + } + + class NoMore: DiscoveryNewsViewModel.State { + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Reloading.Type: + return true + default: + return false + } + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + } + } +} diff --git a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel.swift b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel.swift new file mode 100644 index 000000000..b87e7c050 --- /dev/null +++ b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel.swift @@ -0,0 +1,51 @@ +// +// DiscoveryNewsViewModel.swift +// Mastodon +// +// Created by MainasuK on 2022-4-13. +// + +import os.log +import UIKit +import Combine +import GameplayKit +import CoreData +import CoreDataStack +import MastodonSDK + +final class DiscoveryNewsViewModel { + + var disposeBag = Set() + + // input + let context: AppContext + let listBatchFetchViewModel = ListBatchFetchViewModel() + + // output + @Published var links: [Mastodon.Entity.Link] = [] + var diffableDataSource: UITableViewDiffableDataSource? + private(set) lazy var stateMachine: GKStateMachine = { + let stateMachine = GKStateMachine(states: [ + State.Initial(viewModel: self), + State.Reloading(viewModel: self), + State.Fail(viewModel: self), + State.Idle(viewModel: self), + State.Loading(viewModel: self), + State.NoMore(viewModel: self), + ]) + stateMachine.enter(State.Initial.self) + return stateMachine + }() + + let didLoadLatest = PassthroughSubject() + + init(context: AppContext) { + self.context = context + // end init + } + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } + +} diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift index 3e813dbd8..30e2faf96 100644 --- a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift @@ -30,6 +30,8 @@ final class DiscoveryPostsViewController: UIViewController, NeedsDependency, Med return tableView }() + let refreshControl = UIRefreshControl() + deinit { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) } @@ -65,6 +67,16 @@ extension DiscoveryPostsViewController { statusTableViewCellDelegate: self ) + tableView.refreshControl = refreshControl + refreshControl.addTarget(self, action: #selector(DiscoveryPostsViewController.refreshControlValueChanged(_:)), for: .valueChanged) + viewModel.didLoadLatest + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in + guard let self = self else { return } + self.refreshControl.endRefreshing() + } + .store(in: &disposeBag) + // setup batch fetch viewModel.listBatchFetchViewModel.setup(scrollView: tableView) viewModel.listBatchFetchViewModel.shouldFetch @@ -77,6 +89,24 @@ extension DiscoveryPostsViewController { .store(in: &disposeBag) } + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + refreshControl.endRefreshing() + tableView.deselectRow(with: transitionCoordinator, animated: animated) + } + +} + +extension DiscoveryPostsViewController { + + @objc private func refreshControlValueChanged(_ sender: UIRefreshControl) { + guard viewModel.stateMachine.enter(DiscoveryPostsViewModel.State.Reloading.self) else { + sender.endRefreshing() + return + } + } + } // MARK: - UITableViewDelegate diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+Diffable.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+Diffable.swift index 3abb4a21b..5c82384c7 100644 --- a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+Diffable.swift +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+Diffable.swift @@ -28,7 +28,7 @@ extension DiscoveryPostsViewModel { stateMachine.enter(State.Reloading.self) statusFetchedResultsController.$records - .debounce(for: .milliseconds(300), scheduler: DispatchQueue.main) + .receive(on: DispatchQueue.main) .sink { [weak self] records in guard let self = self else { return } guard let diffableDataSource = self.diffableDataSource else { return } @@ -46,7 +46,9 @@ extension DiscoveryPostsViewModel { is State.Loading, is State.Idle, is State.Fail: - snapshot.appendItems([.bottomLoader], toSection: .main) + if !items.isEmpty { + snapshot.appendItems([.bottomLoader], toSection: .main) + } case is State.NoMore: break default: @@ -54,7 +56,7 @@ extension DiscoveryPostsViewModel { break } } - + diffableDataSource.applySnapshot(snapshot, animated: false) } .store(in: &disposeBag) diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift index 0a2178685..199215d14 100644 --- a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift @@ -13,7 +13,7 @@ import MastodonSDK extension DiscoveryPostsViewModel { class State: GKState, NamingState { - let logger = Logger(subsystem: "TrendPostsViewModel.State", category: "StateMachine") + let logger = Logger(subsystem: "DiscoveryPostsViewModel.State", category: "StateMachine") let id = UUID() @@ -132,7 +132,6 @@ extension DiscoveryPostsViewModel.State { super.didEnter(from: previousState) guard let viewModel = viewModel, let stateMachine = stateMachine else { return } - switch previousState { case is Reloading: offset = nil @@ -182,10 +181,11 @@ extension DiscoveryPostsViewModel.State { await enter(state: NoMore.self) } viewModel.statusFetchedResultsController.statusIDs.value = statusIDs - + viewModel.didLoadLatest.send() } catch { - logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): fetch user timeline fail: \(error.localizedDescription)") + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): fetch posts fail: \(error.localizedDescription)") await enter(state: Fail.self) + viewModel.didLoadLatest.send() } } // end Task } // end func diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift index 100a2a347..590ccc161 100644 --- a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift @@ -37,6 +37,8 @@ final class DiscoveryPostsViewModel { return stateMachine }() + let didLoadLatest = PassthroughSubject() + init(context: AppContext) { self.context = context self.statusFetchedResultsController = StatusFetchedResultsController( diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift index 7b7f35e5d..549552725 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift @@ -17,6 +17,7 @@ import AlamofireImage import StoreKit import MastodonAsset import MastodonLocalization +import MastodonUI final class HomeTimelineViewController: UIViewController, NeedsDependency, MediaPreviewableViewController { @@ -291,7 +292,7 @@ extension HomeTimelineViewController { tableView.deselectRow(with: transitionCoordinator, animated: animated) // needs trigger manually after onboarding dismiss - setNeedsStatusBarAppearanceUpdate() + setNeedsStatusBarAppearanceUpdate() } override func viewDidAppear(_ animated: Bool) { diff --git a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift index db50565aa..f470082f2 100644 --- a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift +++ b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift @@ -11,6 +11,7 @@ import Combine import SafariServices import MastodonAsset import MastodonLocalization +import MastodonUI class MainTabBarController: UITabBarController { diff --git a/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift index 6568ab0cd..7ac0f6e54 100644 --- a/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift +++ b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift @@ -9,6 +9,7 @@ import os.log import UIKit import Combine import CoreDataStack +import MastodonUI protocol SidebarViewControllerDelegate: AnyObject { func sidebarViewController(_ sidebarViewController: SidebarViewController, didSelectTab tab: MainTabBarController.Tab) diff --git a/Mastodon/Scene/Search/Search/Cell/TrendCollectionViewCell.swift b/Mastodon/Scene/Search/Search/Cell/TrendCollectionViewCell.swift index a43d65df4..379cba70d 100644 --- a/Mastodon/Scene/Search/Search/Cell/TrendCollectionViewCell.swift +++ b/Mastodon/Scene/Search/Search/Cell/TrendCollectionViewCell.swift @@ -9,45 +9,13 @@ import UIKit import Combine import MetaTextKit import MastodonAsset +import MastodonUI final class TrendCollectionViewCell: UICollectionViewCell { var _disposeBag = Set() - let container: UIStackView = { - let stackView = UIStackView() - stackView.axis = .horizontal - stackView.spacing = 16 - return stackView - }() - - let infoContainer: UIStackView = { - let stackView = UIStackView() - stackView.axis = .vertical - return stackView - }() - - let lineChartContainer: UIStackView = { - let stackView = UIStackView() - stackView.axis = .vertical - return stackView - }() - - let primaryLabel: UILabel = { - let label = UILabel() - label.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)) - label.textColor = Asset.Colors.Label.primary.color - return label - }() - - let secondaryLabel: UILabel = { - let label = UILabel() - label.font = UIFontMetrics(forTextStyle: .subheadline).scaledFont(for: .systemFont(ofSize: 15, weight: .regular)) - label.textColor = Asset.Colors.Label.secondary.color - return label - }() - - let lineChartView = LineChartView() + let trendView = TrendView() override func prepareForReuse() { super.prepareForReuse() @@ -77,44 +45,13 @@ extension TrendCollectionViewCell { } .store(in: &_disposeBag) - container.translatesAutoresizingMaskIntoConstraints = false - contentView.addSubview(container) + trendView.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(trendView) NSLayoutConstraint.activate([ - container.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 11), - container.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), - container.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), - contentView.bottomAnchor.constraint(equalTo: container.bottomAnchor, constant: 11), - ]) - - container.layoutMargins = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16) - container.isLayoutMarginsRelativeArrangement = true - - // container: H - [ info container | padding | line chart container ] - container.addArrangedSubview(infoContainer) - - // info container: V - [ primary | secondary ] - infoContainer.addArrangedSubview(primaryLabel) - infoContainer.addArrangedSubview(secondaryLabel) - - // padding - let padding = UIView() - container.addArrangedSubview(padding) - - // line chart - container.addArrangedSubview(lineChartContainer) - - let lineChartViewTopPadding = UIView() - let lineChartViewBottomPadding = UIView() - lineChartViewTopPadding.translatesAutoresizingMaskIntoConstraints = false - lineChartViewBottomPadding.translatesAutoresizingMaskIntoConstraints = false - lineChartView.translatesAutoresizingMaskIntoConstraints = false - lineChartContainer.addArrangedSubview(lineChartViewTopPadding) - lineChartContainer.addArrangedSubview(lineChartView) - lineChartContainer.addArrangedSubview(lineChartViewBottomPadding) - NSLayoutConstraint.activate([ - lineChartView.widthAnchor.constraint(equalToConstant: 50), - lineChartView.heightAnchor.constraint(equalToConstant: 26), - lineChartViewTopPadding.heightAnchor.constraint(equalTo: lineChartViewBottomPadding.heightAnchor), + trendView.topAnchor.constraint(equalTo: contentView.topAnchor), + trendView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), + trendView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), + trendView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), ]) } diff --git a/Mastodon/Scene/Search/SearchDetail/SearchHistory/View/SearchHistoryTableHeaderView.swift b/Mastodon/Scene/Search/SearchDetail/SearchHistory/View/SearchHistoryTableHeaderView.swift index 8ac661b18..fc41bdf27 100644 --- a/Mastodon/Scene/Search/SearchDetail/SearchHistory/View/SearchHistoryTableHeaderView.swift +++ b/Mastodon/Scene/Search/SearchDetail/SearchHistory/View/SearchHistoryTableHeaderView.swift @@ -10,6 +10,7 @@ import UIKit import Combine import MastodonAsset import MastodonLocalization +import MastodonUI protocol SearchHistoryTableHeaderViewDelegate: AnyObject { func searchHistoryTableHeaderView(_ searchHistoryTableHeaderView: SearchHistoryTableHeaderView, clearSearchHistoryButtonDidPressed button: UIButton) diff --git a/Mastodon/Scene/Share/View/Content/ContentWarningOverlayView.swift b/Mastodon/Scene/Share/View/Content/ContentWarningOverlayView.swift index 78c5462f5..8300f865a 100644 --- a/Mastodon/Scene/Share/View/Content/ContentWarningOverlayView.swift +++ b/Mastodon/Scene/Share/View/Content/ContentWarningOverlayView.swift @@ -11,6 +11,7 @@ import Combine import UIKit import MastodonAsset import MastodonLocalization +import MastodonUI protocol ContentWarningOverlayViewDelegate: AnyObject { func contentWarningOverlayViewDidPressed(_ contentWarningOverlayView: ContentWarningOverlayView) diff --git a/Mastodon/Scene/Share/View/Content/MediaView+Configuration.swift b/Mastodon/Scene/Share/View/Content/MediaView+Configuration.swift index ad2fa398d..cba1fcf6d 100644 --- a/Mastodon/Scene/Share/View/Content/MediaView+Configuration.swift +++ b/Mastodon/Scene/Share/View/Content/MediaView+Configuration.swift @@ -58,7 +58,7 @@ extension MediaView { }() if let previewURL = configuration.previewURL, - let url = URL(string: previewURL) + let url = URL(string: previewURL) { let placeholder = UIImage.placeholder(color: .systemGray6) let request = URLRequest(url: url) diff --git a/Mastodon/Scene/Share/View/Content/ThreadMetaView.swift b/Mastodon/Scene/Share/View/Content/ThreadMetaView.swift index c339654f5..0953feecd 100644 --- a/Mastodon/Scene/Share/View/Content/ThreadMetaView.swift +++ b/Mastodon/Scene/Share/View/Content/ThreadMetaView.swift @@ -6,6 +6,7 @@ // import UIKit +import MastodonUI final class ThreadMetaView: UIView { diff --git a/Mastodon/Service/APIService/APIService+Trend.swift b/Mastodon/Service/APIService/APIService+Trend.swift index 34edae09e..47dda6bd2 100644 --- a/Mastodon/Service/APIService/APIService+Trend.swift +++ b/Mastodon/Service/APIService/APIService+Trend.swift @@ -53,4 +53,17 @@ extension APIService { return response } + func trendLinks( + domain: String, + query: Mastodon.API.Trends.LinkQuery + ) async throws -> Mastodon.Response.Content<[Mastodon.Entity.Link]> { + let response = try await Mastodon.API.Trends.links( + session: session, + domain: domain, + query: query + ).singleOutput() + + return response + } + } diff --git a/Mastodon/Service/SettingService.swift b/Mastodon/Service/SettingService.swift index 1e8022c59..bd571d8f4 100644 --- a/Mastodon/Service/SettingService.swift +++ b/Mastodon/Service/SettingService.swift @@ -12,6 +12,7 @@ import CoreDataStack import MastodonSDK import MastodonAsset import MastodonLocalization +import MastodonCommon final class SettingService { @@ -190,18 +191,6 @@ extension SettingService { extension SettingService { static func updatePreference(setting: Setting) { - // set appearance -// let userInterfaceStyle: UIUserInterfaceStyle = { -// switch setting.appearance { -// case .automatic: return .unspecified -// case .light: return .light -// case .dark: return .dark -// } -// }() -// if UserDefaults.shared.customUserInterfaceStyle != userInterfaceStyle { -// UserDefaults.shared.customUserInterfaceStyle = userInterfaceStyle -// } - // set theme let themeName: ThemeName = setting.preferredTrueBlackDarkMode ? .system : .mastodon if UserDefaults.shared.currentThemeNameRawValue != themeName.rawValue { @@ -223,6 +212,6 @@ extension SettingService { if UserDefaults.shared.preferredUsingDefaultBrowser != setting.preferredUsingDefaultBrowser { UserDefaults.shared.preferredUsingDefaultBrowser = setting.preferredUsingDefaultBrowser } - } + } diff --git a/MastodonSDK/Sources/MastodonCommon/Preference/Preference+Theme.swift b/MastodonSDK/Sources/MastodonCommon/Preference/Preference+Theme.swift new file mode 100644 index 000000000..a87a8da75 --- /dev/null +++ b/MastodonSDK/Sources/MastodonCommon/Preference/Preference+Theme.swift @@ -0,0 +1,26 @@ +// +// Preference+Theme.swift +// +// +// Created by MainasuK on 2022-4-13. +// + +import UIKit +import MastodonExtension + +public enum ThemeName: String, CaseIterable { + case system + case mastodon +} + +extension UserDefaults { + + @objc public dynamic var currentThemeNameRawValue: String { + get { + register(defaults: [#function: ThemeName.mastodon.rawValue]) + return string(forKey: #function) ?? ThemeName.mastodon.rawValue + } + set { self[#function] = newValue } + } + +} diff --git a/MastodonSDK/Sources/MastodonExtension/UIView.swift b/MastodonSDK/Sources/MastodonExtension/UIView.swift index 5466c464d..f96d1618a 100644 --- a/MastodonSDK/Sources/MastodonExtension/UIView.swift +++ b/MastodonSDK/Sources/MastodonExtension/UIView.swift @@ -12,3 +12,37 @@ extension UIView { return UIScreen.main.scale != UIScreen.main.nativeScale } } + +extension UIView { + @discardableResult + public func applyCornerRadius(radius: CGFloat) -> Self { + layer.masksToBounds = true + layer.cornerRadius = radius + layer.cornerCurve = .continuous + return self + } + + @discardableResult + public func applyShadow( + color: UIColor, + alpha: Float, + x: CGFloat, + y: CGFloat, + blur: CGFloat, + spread: CGFloat = 0 + ) -> Self { + layer.masksToBounds = false + layer.shadowColor = color.cgColor + layer.shadowOpacity = alpha + layer.shadowOffset = CGSize(width: x, height: y) + layer.shadowRadius = blur / 2.0 + if spread == 0 { + layer.shadowPath = nil + } else { + let dx = -spread + let rect = bounds.insetBy(dx: dx, dy: dx) + layer.shadowPath = UIBezierPath(rect: rect).cgPath + } + return self + } +} diff --git a/MastodonSDK/Sources/MastodonExtension/UInt64.swift b/MastodonSDK/Sources/MastodonExtension/UInt64.swift new file mode 100644 index 000000000..03dfbaca7 --- /dev/null +++ b/MastodonSDK/Sources/MastodonExtension/UInt64.swift @@ -0,0 +1,12 @@ +// +// UInt64.swift +// +// +// Created by MainasuK on 2022-4-13. +// + +import Foundation + +extension UInt64 { + public static let second: UInt64 = 1_000_000_000 +} diff --git a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Trends.swift b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Trends.swift index 25e130e32..d2dca8245 100644 --- a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Trends.swift +++ b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Trends.swift @@ -71,9 +71,9 @@ extension Mastodon.API.Trends { .appendingPathComponent("statuses") } - /// Trending tags + /// Trending status /// - /// Tags that are being used more frequently within the past week. + /// TBD /// /// Version history: /// 3.?.? @@ -83,7 +83,7 @@ extension Mastodon.API.Trends { /// - session: `URLSession` /// - domain: Mastodon instance domain. e.g. "example.com" /// - query: query - /// - Returns: `AnyPublisher` contains `Hashtags` nested in the response + /// - Returns: `[Status]` nested in the response public static func statuses( session: URLSession, @@ -126,3 +126,47 @@ extension Mastodon.API.Trends { } } + +extension Mastodon.API.Trends { + + static func trendLinksURL(domain: String) -> URL { + Mastodon.API.endpointURL(domain: domain) + .appendingPathComponent("trends") + .appendingPathComponent("links") + } + + /// Trending links + /// + /// TBD + /// + /// Version history: + /// 3.?.? + /// # Reference + /// [Document](https://docs.joinmastodon.org/methods/instance/trends/) + /// - Parameters: + /// - session: `URLSession` + /// - domain: Mastodon instance domain. e.g. "example.com" + /// - query: query + /// - Returns: `[Link]` nested in the response + + public static func links( + session: URLSession, + domain: String, + query: Mastodon.API.Trends.LinkQuery? + ) -> AnyPublisher, Error> { + let request = Mastodon.API.get( + url: trendLinksURL(domain: domain), + query: query, + authorization: nil + ) + return session.dataTaskPublisher(for: request) + .tryMap { data, response in + let value = try Mastodon.API.decode(type: [Mastodon.Entity.Link].self, from: data, response: response) + return Mastodon.Response.Content(value: value, response: response) + } + .eraseToAnyPublisher() + } + + public typealias LinkQuery = StatusQuery + +} diff --git a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Link.swift b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Link.swift new file mode 100644 index 000000000..d1d7bd673 --- /dev/null +++ b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Link.swift @@ -0,0 +1,54 @@ +// +// Mastodon+Entity+Link.swift +// +// +// Created by MainasuK on 2022-4-13. +// + +import Foundation + +extension Mastodon.Entity { + /// History + /// + /// - Since: 3.5.0 + /// - Version: 3.5.1 + /// # Last Update + /// 2022/4/13 + /// # Reference + /// [Document](TBD) + public struct Link: Codable { + public let url: String + public let title: String + public let description: String + public let providerName: String + public let providerURL: String + public let image: String + public let width: Int + public let height: Int + public let blurhash: String + public let history: [History] + + enum CodingKeys: String, CodingKey { + case url + case title + case description + case providerName = "provider_name" + case providerURL = "provider_url" + case image + case width + case height + case blurhash + case history + } + } +} + +extension Mastodon.Entity.Link: Hashable { + public static func == (lhs: Mastodon.Entity.Link, rhs: Mastodon.Entity.Link) -> Bool { + return lhs.url == rhs.url + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(url) + } +} diff --git a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Tag.swift b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Tag.swift index b017d1551..84875359a 100644 --- a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Tag.swift +++ b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Tag.swift @@ -37,6 +37,7 @@ extension Mastodon.Entity { public func hash(into hasher: inout Hasher) { hasher.combine(name) + hasher.combine(url) } } } diff --git a/MastodonSDK/Sources/MastodonUI/Extension/MastodonSDK/Mastodon+Entity+Link.swift b/MastodonSDK/Sources/MastodonUI/Extension/MastodonSDK/Mastodon+Entity+Link.swift new file mode 100644 index 000000000..8f00911f9 --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/Extension/MastodonSDK/Mastodon+Entity+Link.swift @@ -0,0 +1,21 @@ +// +// Mastodon+Entity+Link.swift +// +// +// Created by MainasuK on 2022-4-13. +// + +import Foundation +import MastodonSDK + +extension Mastodon.Entity.Link { + + /// the sum of recent 2 days + public var talkingPeopleCount: Int? { + return history + .prefix(2) + .compactMap { Int($0.accounts) } + .reduce(0, +) + } + +} diff --git a/MastodonSDK/Sources/MastodonUI/Extension/MastodonSDK/Mastodon+Entity+Tag.swift b/MastodonSDK/Sources/MastodonUI/Extension/MastodonSDK/Mastodon+Entity+Tag.swift new file mode 100644 index 000000000..4d58145e5 --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/Extension/MastodonSDK/Mastodon+Entity+Tag.swift @@ -0,0 +1,21 @@ +// +// Mastodon+Entity+Tag.swift +// +// +// Created by MainasuK on 2022-4-13. +// + +import Foundation +import MastodonSDK + +extension Mastodon.Entity.Tag { + + /// the sum of recent 2 days + public var talkingPeopleCount: Int? { + return history? + .prefix(2) + .compactMap { Int($0.accounts) } + .reduce(0, +) + } + +} diff --git a/MastodonSDK/Sources/MastodonUI/Extension/UIView.swift b/MastodonSDK/Sources/MastodonUI/Extension/UIView.swift new file mode 100644 index 000000000..0489965b5 --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/Extension/UIView.swift @@ -0,0 +1,34 @@ +// +// UIView.swift +// +// +// Created by MainasuK on 2022-4-13. +// + +import UIKit + +extension UIView { + + static let separatorColor: UIColor = { + UIColor(dynamicProvider: { collection in + switch collection.userInterfaceStyle { + case .dark: + return ThemeService.shared.currentTheme.value.separator + default: + return .separator + } + }) + }() + + + public static var separatorLine: UIView { + let line = UIView() + line.backgroundColor = UIView.separatorColor + return line + } + + public static func separatorLineHeight(of view: UIView) -> CGFloat { + return 1.0 / view.traitCollection.displayScale + } + +} diff --git a/Mastodon/Service/ThemeService/MastodonTheme.swift b/MastodonSDK/Sources/MastodonUI/Service/ThemeService/MastodonTheme.swift similarity index 98% rename from Mastodon/Service/ThemeService/MastodonTheme.swift rename to MastodonSDK/Sources/MastodonUI/Service/ThemeService/MastodonTheme.swift index 0dad463b6..76173590e 100644 --- a/Mastodon/Service/ThemeService/MastodonTheme.swift +++ b/MastodonSDK/Sources/MastodonUI/Service/ThemeService/MastodonTheme.swift @@ -7,6 +7,7 @@ import UIKit import MastodonAsset +import MastodonCommon struct MastodonTheme: Theme { diff --git a/Mastodon/Service/ThemeService/SystemTheme.swift b/MastodonSDK/Sources/MastodonUI/Service/ThemeService/SystemTheme.swift similarity index 98% rename from Mastodon/Service/ThemeService/SystemTheme.swift rename to MastodonSDK/Sources/MastodonUI/Service/ThemeService/SystemTheme.swift index 7796fde7b..cea10a281 100644 --- a/Mastodon/Service/ThemeService/SystemTheme.swift +++ b/MastodonSDK/Sources/MastodonUI/Service/ThemeService/SystemTheme.swift @@ -7,6 +7,7 @@ import UIKit import MastodonAsset +import MastodonCommon struct SystemTheme: Theme { diff --git a/Mastodon/Service/ThemeService/Theme.swift b/MastodonSDK/Sources/MastodonUI/Service/ThemeService/Theme.swift similarity index 82% rename from Mastodon/Service/ThemeService/Theme.swift rename to MastodonSDK/Sources/MastodonUI/Service/ThemeService/Theme.swift index 1a3b3c5d1..ae555da00 100644 --- a/Mastodon/Service/ThemeService/Theme.swift +++ b/MastodonSDK/Sources/MastodonUI/Service/ThemeService/Theme.swift @@ -6,6 +6,7 @@ // import UIKit +import MastodonCommon public protocol Theme { @@ -42,17 +43,3 @@ public protocol Theme { var notificationStatusBorderColor: UIColor { get } } - -public enum ThemeName: String, CaseIterable { - case system - case mastodon -} - -extension ThemeName { - public var theme: Theme { - switch self { - case .system: return SystemTheme() - case .mastodon: return MastodonTheme() - } - } -} diff --git a/Mastodon/Service/ThemeService/ThemeService.swift b/MastodonSDK/Sources/MastodonUI/Service/ThemeService/ThemeService.swift similarity index 57% rename from Mastodon/Service/ThemeService/ThemeService.swift rename to MastodonSDK/Sources/MastodonUI/Service/ThemeService/ThemeService.swift index b356d3469..b782c4138 100644 --- a/Mastodon/Service/ThemeService/ThemeService.swift +++ b/MastodonSDK/Sources/MastodonUI/Service/ThemeService/ThemeService.swift @@ -8,16 +8,17 @@ import UIKit import Combine import AppShared +import MastodonCommon // ref: https://zamzam.io/protocol-oriented-themes-for-ios-apps/ -final class ThemeService { +public final class ThemeService { - static let tintColor: UIColor = .label + public static let tintColor: UIColor = .label // MARK: - Singleton public static let shared = ThemeService() - let currentTheme: CurrentValueSubject + public let currentTheme: CurrentValueSubject private init() { let theme = ThemeName(rawValue: UserDefaults.shared.currentThemeNameRawValue)?.theme ?? ThemeName.mastodon.theme @@ -25,3 +26,12 @@ final class ThemeService { } } + +extension ThemeName { + public var theme: Theme { + switch self { + case .system: return SystemTheme() + case .mastodon: return MastodonTheme() + } + } +} diff --git a/Mastodon/Vender/CurveAlgorithm.swift b/MastodonSDK/Sources/MastodonUI/Vendor/CurveAlgorithm.swift similarity index 100% rename from Mastodon/Vender/CurveAlgorithm.swift rename to MastodonSDK/Sources/MastodonUI/Vendor/CurveAlgorithm.swift diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift b/MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift new file mode 100644 index 000000000..3116534a0 --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift @@ -0,0 +1,43 @@ +// +// NewsView+Configuration.swift +// +// +// Created by MainasuK on 2022-4-13. +// + +import UIKit +import MastodonSDK +import MastodonLocalization +import AlamofireImage + +extension NewsView { + public func configure(link: Mastodon.Entity.Link) { + providerNameLabel.text = link.providerName + headlineLabel.text = link.title + footnoteLabel.text = L10n.Scene.Search.Recommend.HashTag.peopleTalking(link.talkingPeopleCount ?? 0) + + let configuration = MediaView.Configuration( + info: .image(info: .init( + aspectRadio: CGSize(width: link.width, height: link.height), + assetURL: link.image + )), + blurhash: link.blurhash + ) + imageView.setup(configuration: configuration) + + if let previewURL = configuration.previewURL, + let url = URL(string: previewURL) + { + let placeholder = UIImage.placeholder(color: .systemGray6) + let request = URLRequest(url: url) + ImageDownloader.default.download(request, completion: { response in + switch response.result { + case .success(let image): + configuration.previewImage = image + case .failure: + configuration.previewImage = placeholder + } + }) + } + } // end func +} diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/NewsView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/NewsView.swift new file mode 100644 index 000000000..ee9506a96 --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/View/Content/NewsView.swift @@ -0,0 +1,102 @@ +// +// NewsView.swift +// +// +// Created by MainasuK on 2022-4-13. +// + +import UIKit +import MastodonAsset + +public final class NewsView: UIView { + + let container = UIStackView() + + let providerNameLabel: UILabel = { + let label = UILabel() + label.font = UIFontMetrics(forTextStyle: .footnote).scaledFont(for: .systemFont(ofSize: 13, weight: .semibold)) + label.textColor = Asset.Colors.Label.primary.color + return label + }() + + let headlineLabel: UILabel = { + let label = UILabel() + label.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold)) + label.textColor = Asset.Colors.Label.primary.color + label.numberOfLines = 0 + return label + }() + + let footnoteLabel: UILabel = { + let label = UILabel() + label.font = UIFontMetrics(forTextStyle: .caption1).scaledFont(for: .systemFont(ofSize: 12, weight: .medium)) + label.textColor = Asset.Colors.Label.secondary.color + return label + }() + + let imageView = MediaView() + + public func prepareForReuse() { + imageView.prepareForReuse() + } + + override init(frame: CGRect) { + super.init(frame: frame) + _init() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + _init() + } + +} + +extension NewsView { + private func _init() { + // container: H - [ textContainer | imageView ] + container.axis = .horizontal + container.spacing = 8 + container.translatesAutoresizingMaskIntoConstraints = false + addSubview(container) + NSLayoutConstraint.activate([ + container.topAnchor.constraint(equalTo: topAnchor), + container.leadingAnchor.constraint(equalTo: leadingAnchor), + container.trailingAnchor.constraint(equalTo: trailingAnchor), + container.bottomAnchor.constraint(equalTo: bottomAnchor), + ]) + + // textContainer: V - [ providerContainer | headlineLabel | (spacer) | footnoteLabel ] + let textContainer = UIStackView() + textContainer.axis = .vertical + textContainer.spacing = 4 + container.addArrangedSubview(textContainer) + + // providerContainer: H - [ providerFavIconImageView | providerNameLabel | (spacer) ] + let providerContainer = UIStackView() + providerContainer.axis = .horizontal + textContainer.addArrangedSubview(providerContainer) + + providerContainer.addArrangedSubview(providerNameLabel) + + // headlineLabel + textContainer.addArrangedSubview(headlineLabel) + let spacer = UIView() + spacer.translatesAutoresizingMaskIntoConstraints = false + textContainer.addArrangedSubview(spacer) + NSLayoutConstraint.activate([ + spacer.heightAnchor.constraint(equalToConstant: 24).priority(.required - 1), + ]) + // footnoteLabel + textContainer.addArrangedSubview(footnoteLabel) + + // imageView + imageView.translatesAutoresizingMaskIntoConstraints = false + container.addArrangedSubview(imageView) + NSLayoutConstraint.activate([ + imageView.widthAnchor.constraint(equalToConstant: 132).priority(.required - 1), + ]) + imageView.isUserInteractionEnabled = false + } +} + diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/TrendView+Configuration.swift b/MastodonSDK/Sources/MastodonUI/View/Content/TrendView+Configuration.swift new file mode 100644 index 000000000..cdd3dfd82 --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/View/Content/TrendView+Configuration.swift @@ -0,0 +1,35 @@ +// +// TrendView+Configuration.swift +// +// +// Created by MainasuK on 2022-4-13. +// + +import UIKit +import MastodonSDK +import MastodonLocalization + +extension TrendView { + public func configure(tag: Mastodon.Entity.Tag) { + let primaryLabelText = "#" + tag.name + let secondaryLabelText = L10n.Scene.Search.Recommend.HashTag.peopleTalking(tag.talkingPeopleCount ?? 0) + + primaryLabel.text = primaryLabelText + secondaryLabel.text = secondaryLabelText + + lineChartView.data = (tag.history ?? []) + .sorted(by: { $0.day < $1.day }) // latest last + .map { entry in + guard let point = Int(entry.accounts) else { + return .zero + } + return CGFloat(point) + } + + isAccessibilityElement = true + accessibilityLabel = [ + primaryLabelText, + secondaryLabelText + ].joined(separator: ", ") + } +} diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/TrendView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/TrendView.swift new file mode 100644 index 000000000..ff1b9b708 --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/View/Content/TrendView.swift @@ -0,0 +1,100 @@ +// +// TrendView.swift +// +// +// Created by MainasuK on 2022-4-13. +// + +import UIKit +import MastodonAsset + +public final class TrendView: UIView { + + let container: UIStackView = { + let stackView = UIStackView() + stackView.axis = .horizontal + stackView.spacing = 16 + return stackView + }() + + let infoContainer: UIStackView = { + let stackView = UIStackView() + stackView.axis = .vertical + return stackView + }() + + let lineChartContainer: UIStackView = { + let stackView = UIStackView() + stackView.axis = .vertical + return stackView + }() + + let primaryLabel: UILabel = { + let label = UILabel() + label.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)) + label.textColor = Asset.Colors.Label.primary.color + return label + }() + + let secondaryLabel: UILabel = { + let label = UILabel() + label.font = UIFontMetrics(forTextStyle: .subheadline).scaledFont(for: .systemFont(ofSize: 15, weight: .regular)) + label.textColor = Asset.Colors.Label.secondary.color + return label + }() + + let lineChartView = LineChartView() + + public override init(frame: CGRect) { + super.init(frame: frame) + _init() + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + _init() + } + +} + +extension TrendView { + private func _init() { + container.translatesAutoresizingMaskIntoConstraints = false + addSubview(container) + NSLayoutConstraint.activate([ + container.topAnchor.constraint(equalTo: topAnchor, constant: 11), + container.leadingAnchor.constraint(equalTo: leadingAnchor), + container.trailingAnchor.constraint(equalTo: trailingAnchor), + bottomAnchor.constraint(equalTo: container.bottomAnchor, constant: 11), + ]) + + // container: H - [ info container | padding | line chart container ] + container.addArrangedSubview(infoContainer) + + // info container: V - [ primary | secondary ] + infoContainer.addArrangedSubview(primaryLabel) + infoContainer.addArrangedSubview(secondaryLabel) + + // padding + let padding = UIView() + container.addArrangedSubview(padding) + + // line chart + container.addArrangedSubview(lineChartContainer) + + let lineChartViewTopPadding = UIView() + let lineChartViewBottomPadding = UIView() + lineChartViewTopPadding.translatesAutoresizingMaskIntoConstraints = false + lineChartViewBottomPadding.translatesAutoresizingMaskIntoConstraints = false + lineChartView.translatesAutoresizingMaskIntoConstraints = false + lineChartContainer.addArrangedSubview(lineChartViewTopPadding) + lineChartContainer.addArrangedSubview(lineChartView) + lineChartContainer.addArrangedSubview(lineChartViewBottomPadding) + NSLayoutConstraint.activate([ + lineChartView.widthAnchor.constraint(equalToConstant: 50), + lineChartView.heightAnchor.constraint(equalToConstant: 26), + lineChartViewTopPadding.heightAnchor.constraint(equalTo: lineChartViewBottomPadding.heightAnchor), + ]) + } +} + diff --git a/Mastodon/Scene/Search/Search/View/LineChartView.swift b/MastodonSDK/Sources/MastodonUI/View/Control/LineChartView.swift similarity index 85% rename from Mastodon/Scene/Search/Search/View/LineChartView.swift rename to MastodonSDK/Sources/MastodonUI/View/Control/LineChartView.swift index cd76fb0c8..c90b59f0e 100644 --- a/Mastodon/Scene/Search/Search/View/LineChartView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Control/LineChartView.swift @@ -7,12 +7,11 @@ import UIKit import Accelerate -import simd import MastodonAsset -final class LineChartView: UIView { +public final class LineChartView: UIView { - var data: [CGFloat] = [] { + public var data: [CGFloat] = [] { didSet { setNeedsLayout() } @@ -20,14 +19,13 @@ final class LineChartView: UIView { let lineShapeLayer = CAShapeLayer() let gradientLayer = CAGradientLayer() -// let dotShapeLayer = CAShapeLayer() - override init(frame: CGRect) { + public override init(frame: CGRect) { super.init(frame: frame) _init() } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) _init() } @@ -38,10 +36,8 @@ extension LineChartView { private func _init() { lineShapeLayer.frame = bounds gradientLayer.frame = bounds -// dotShapeLayer.frame = bounds layer.addSublayer(lineShapeLayer) layer.addSublayer(gradientLayer) -// layer.addSublayer(dotShapeLayer) gradientLayer.colors = [ Asset.Colors.brandBlue.color.withAlphaComponent(0.5).cgColor, // set the same alpha to fill @@ -51,16 +47,14 @@ extension LineChartView { gradientLayer.endPoint = CGPoint(x: 0.5, y: 1) } - override func layoutSubviews() { + public override func layoutSubviews() { super.layoutSubviews() lineShapeLayer.frame = bounds gradientLayer.frame = bounds -// dotShapeLayer.frame = bounds guard data.count > 1 else { lineShapeLayer.path = nil -// dotShapeLayer.path = nil gradientLayer.isHidden = true return } @@ -113,9 +107,5 @@ extension LineChartView { maskLayer.strokeColor = UIColor.clear.cgColor maskLayer.lineWidth = 0.0 gradientLayer.mask = maskLayer - -// dotShapeLayer.lineWidth = 3 -// dotShapeLayer.fillColor = Asset.Colors.brandBlue.color.cgColor -// dotShapeLayer.path = dotPath.cgPath } } diff --git a/MastodonSDK/Sources/MastodonUI/View/TableViewCell/NewsTableViewCell.swift b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/NewsTableViewCell.swift new file mode 100644 index 000000000..3515000f9 --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/NewsTableViewCell.swift @@ -0,0 +1,56 @@ +// +// NewsTableViewCell.swift +// +// +// Created by MainasuK on 2022-4-13. +// + +import UIKit + +public final class NewsTableViewCell: UITableViewCell { + + public let newsView = NewsView() + + let separatorLine = UIView.separatorLine + + public override func prepareForReuse() { + super.prepareForReuse() + + newsView.prepareForReuse() + } + + public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + _init() + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + _init() + } + +} + +extension NewsTableViewCell { + + private func _init() { + newsView.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(newsView) + NSLayoutConstraint.activate([ + newsView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 16), + newsView.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor), + newsView.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor), + contentView.bottomAnchor.constraint(equalTo: newsView.bottomAnchor, constant: 16), + ]) + + separatorLine.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(separatorLine) + NSLayoutConstraint.activate([ + separatorLine.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), + separatorLine.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), + separatorLine.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + separatorLine.heightAnchor.constraint(equalToConstant: UIView.separatorLineHeight(of: contentView)), + ]) + } + +} diff --git a/MastodonSDK/Sources/MastodonUI/View/TableViewCell/TrendTableViewCell.swift b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/TrendTableViewCell.swift new file mode 100644 index 000000000..8c1cebff0 --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/TrendTableViewCell.swift @@ -0,0 +1,86 @@ +// +// TrendTableViewCell.swift +// +// +// Created by MainasuK on 2022-4-13. +// + +import UIKit + +public final class TrendTableViewCell: UITableViewCell { + + public let trendView = TrendView() + + let separatorLine = UIView.separatorLine + + public override func prepareForReuse() { + super.prepareForReuse() + + configureSeparator(style: .inset) + } + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + _init() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + _init() + } + +} + +extension TrendTableViewCell { + + private func _init() { + trendView.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(trendView) + NSLayoutConstraint.activate([ + trendView.topAnchor.constraint(equalTo: contentView.topAnchor), + trendView.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor), + trendView.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor), + trendView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + ]) + + configureSeparator(style: .inset) + + accessibilityElements = [trendView] + } + +} + +extension TrendTableViewCell { + + public enum SeparatorStyle { + case edge + case inset + } + + public func configureSeparator(style: SeparatorStyle) { + separatorLine.removeFromSuperview() + separatorLine.removeConstraints(separatorLine.constraints) + + switch style { + case .edge: + separatorLine.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(separatorLine) + NSLayoutConstraint.activate([ + separatorLine.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), + separatorLine.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), + separatorLine.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + separatorLine.heightAnchor.constraint(equalToConstant: UIView.separatorLineHeight(of: contentView)), + ]) + case .inset: + separatorLine.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(separatorLine) + NSLayoutConstraint.activate([ + separatorLine.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor), + separatorLine.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), + separatorLine.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + separatorLine.heightAnchor.constraint(equalToConstant: UIView.separatorLineHeight(of: contentView)), + ]) + } + } + +} diff --git a/ShareActionExtension/Scene/ShareViewController.swift b/ShareActionExtension/Scene/ShareViewController.swift index d45558f1a..622e0106b 100644 --- a/ShareActionExtension/Scene/ShareViewController.swift +++ b/ShareActionExtension/Scene/ShareViewController.swift @@ -12,6 +12,7 @@ import MastodonUI import SwiftUI import MastodonAsset import MastodonLocalization +import MastodonUI class ShareViewController: UIViewController { diff --git a/ShareActionExtension/Scene/ShareViewModel.swift b/ShareActionExtension/Scene/ShareViewModel.swift index fbad82209..c56f8ecfd 100644 --- a/ShareActionExtension/Scene/ShareViewModel.swift +++ b/ShareActionExtension/Scene/ShareViewModel.swift @@ -16,6 +16,7 @@ import SwiftUI import UniformTypeIdentifiers import MastodonAsset import MastodonLocalization +import MastodonUI final class ShareViewModel { diff --git a/ShareActionExtension/Scene/View/ComposeToolbarView.swift b/ShareActionExtension/Scene/View/ComposeToolbarView.swift index 73caac735..a903d3ebd 100644 --- a/ShareActionExtension/Scene/View/ComposeToolbarView.swift +++ b/ShareActionExtension/Scene/View/ComposeToolbarView.swift @@ -12,6 +12,7 @@ import MastodonSDK import MastodonUI import MastodonAsset import MastodonLocalization +import MastodonUI protocol ComposeToolbarViewDelegate: AnyObject { func composeToolbarView(_ composeToolbarView: ComposeToolbarView, contentWarningButtonDidPressed sender: UIButton) From 8e0d526708f93c8c463137832192bdaafcd41cb7 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 13 Apr 2022 20:54:34 +0800 Subject: [PATCH 010/101] chore: fix CI build issue --- MastodonSDK/Package.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MastodonSDK/Package.swift b/MastodonSDK/Package.swift index af27091fa..d6078090b 100644 --- a/MastodonSDK/Package.swift +++ b/MastodonSDK/Package.swift @@ -60,7 +60,9 @@ let package = Package( ), .target( name: "MastodonCommon", - dependencies: [] + dependencies: [ + "MastodonExtension" + ] ), .target( name: "MastodonExtension", From b0fca49413c220f4b1c0a77c9ec7bf8507ab4258 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 14 Apr 2022 21:15:21 +0800 Subject: [PATCH 011/101] feat: add For You tab for Discovery scene --- Mastodon.xcodeproj/project.pbxproj | 42 ++- .../xcschemes/xcschememanagement.plist | 4 +- .../Diffiable/Discovery/DiscoveryItem.swift | 2 + .../Discovery/DiscoverySection.swift | 14 +- .../CoreDataStack/MastodonUser.swift | 47 ---- .../Persistence/Extension/MastodonEmoji.swift | 10 - .../Scene/Discovery/DiscoveryViewModel.swift | 8 + .../DiscoveryForYouViewController.swift | 127 +++++++++ .../DiscoveryForYouViewModel+Diffable.swift | 43 +++ .../ForYou/DiscoveryForYouViewModel.swift | 75 ++++++ .../News/DiscoveryNewsViewModel+State.swift | 6 +- .../Posts/DiscoveryPostsViewModel+State.swift | 8 +- Mastodon/Scene/Profile/ProfileViewModel.swift | 98 +------ .../APIService/APIService+Recommend.swift | 5 +- MastodonSDK/Package.swift | 1 + .../Scene/Discovery/Contents.json | 9 + .../Contents.json | 38 +++ .../MastodonAsset/Generated/Assets.swift | 3 + .../Preference/Preference+Appearance.swift | 6 +- .../API/Mastodon+API+Suggestions.swift | 2 +- .../API/Mastodon+API+V2+Suggestions.swift | 2 +- .../CoreDataStack/MastodonEmoji.swift | 20 ++ .../CoreDataStack/MastodonUser.swift | 57 ++++ .../MastodonUI/Extension/MetaLabel.swift | 12 +- .../Helper/MastodonMetricFormatter.swift | 4 +- .../ProfileCardView+Configuration.swift | 88 ++++++ .../Content/ProfileCardView+ViewModel.swift | 148 ++++++++++ .../View/Content/ProfileCardView.swift | 235 ++++++++++++++++ .../View/Content/StatusView+ViewModel.swift | 1 + .../ProfileRelationshipActionButton.swift | 18 +- .../ProfileStatusDashboardMeterView.swift | 10 +- .../Control}/ProfileStatusDashboardView.swift | 20 +- .../ProfileCardTableViewCell.swift | 68 +++++ .../ViewModel/RelationshipViewModel.swift | 253 ++++++++++++++++++ 34 files changed, 1261 insertions(+), 223 deletions(-) create mode 100644 Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift create mode 100644 Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel+Diffable.swift create mode 100644 Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel.swift create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Discovery/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Discovery/profile.card.background.colorset/Contents.json rename Mastodon/Preference/AppearancePreference.swift => MastodonSDK/Sources/MastodonCommon/Preference/Preference+Appearance.swift (81%) create mode 100644 MastodonSDK/Sources/MastodonUI/Extension/CoreDataStack/MastodonEmoji.swift create mode 100644 MastodonSDK/Sources/MastodonUI/Extension/CoreDataStack/MastodonUser.swift rename {Mastodon => MastodonSDK/Sources/MastodonUI}/Helper/MastodonMetricFormatter.swift (95%) create mode 100644 MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+Configuration.swift create mode 100644 MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+ViewModel.swift create mode 100644 MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift rename {Mastodon/Scene/Profile/Header/View => MastodonSDK/Sources/MastodonUI/View/Control}/ProfileRelationshipActionButton.swift (80%) rename {Mastodon/Scene/Profile/Header/View => MastodonSDK/Sources/MastodonUI/View/Control}/ProfileStatusDashboardMeterView.swift (91%) rename {Mastodon/Scene/Profile/Header/View => MastodonSDK/Sources/MastodonUI/View/Control}/ProfileStatusDashboardView.swift (85%) create mode 100644 MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift create mode 100644 MastodonSDK/Sources/MastodonUI/ViewModel/RelationshipViewModel.swift diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 73332bab8..678fc7107 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -214,7 +214,6 @@ DB336F3F278E668C0031E64B /* StatusTableViewCell+ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB336F3E278E668C0031E64B /* StatusTableViewCell+ViewModel.swift */; }; DB336F41278E68480031E64B /* StatusView+Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB336F40278E68480031E64B /* StatusView+Configuration.swift */; }; DB336F43278EB1690031E64B /* MediaView+Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB336F42278EB1680031E64B /* MediaView+Configuration.swift */; }; - DB35FC1F2612F1D9006193C9 /* ProfileRelationshipActionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB35FC1E2612F1D9006193C9 /* ProfileRelationshipActionButton.swift */; }; DB36679D268AB91B0027D07F /* ComposeStatusAttachmentTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB36679C268AB91B0027D07F /* ComposeStatusAttachmentTableViewCell.swift */; }; DB36679F268ABAF20027D07F /* ComposeStatusAttachmentSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB36679E268ABAF20027D07F /* ComposeStatusAttachmentSection.swift */; }; DB3667A1268ABB2E0027D07F /* ComposeStatusAttachmentItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3667A0268ABB2E0027D07F /* ComposeStatusAttachmentItem.swift */; }; @@ -232,6 +231,9 @@ DB3E6FEF2806D82600B035AE /* DiscoveryNewsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FEE2806D82600B035AE /* DiscoveryNewsViewModel.swift */; }; DB3E6FF12806D96900B035AE /* DiscoveryNewsViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FF02806D96900B035AE /* DiscoveryNewsViewModel+Diffable.swift */; }; DB3E6FF32806D97400B035AE /* DiscoveryNewsViewModel+State.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FF22806D97400B035AE /* DiscoveryNewsViewModel+State.swift */; }; + DB3E6FF52807C40300B035AE /* DiscoveryForYouViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FF42807C40300B035AE /* DiscoveryForYouViewController.swift */; }; + DB3E6FF82807C45300B035AE /* DiscoveryForYouViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FF72807C45300B035AE /* DiscoveryForYouViewModel.swift */; }; + DB3E6FFA2807C47900B035AE /* DiscoveryForYouViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FF92807C47900B035AE /* DiscoveryForYouViewModel+Diffable.swift */; }; DB427DD625BAA00100D1B89D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB427DD525BAA00100D1B89D /* AppDelegate.swift */; }; DB427DD825BAA00100D1B89D /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB427DD725BAA00100D1B89D /* SceneDelegate.swift */; }; DB427DDD25BAA00100D1B89D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DB427DDB25BAA00100D1B89D /* Main.storyboard */; }; @@ -370,7 +372,6 @@ DB6B7500272FF73800C70B6E /* UserTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6B74FF272FF73800C70B6E /* UserTableViewCell.swift */; }; DB6B750427300B4000C70B6E /* TimelineFooterTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6B750327300B4000C70B6E /* TimelineFooterTableViewCell.swift */; }; DB6C8C0F25F0A6AE00AAA452 /* Mastodon+Entity+Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6C8C0E25F0A6AE00AAA452 /* Mastodon+Entity+Error.swift */; }; - DB6D1B3D2636857500ACB481 /* AppearancePreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6D1B3C2636857500ACB481 /* AppearancePreference.swift */; }; DB6D1B44263691CF00ACB481 /* Mastodon+API+Subscriptions+Policy.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6D1B43263691CF00ACB481 /* Mastodon+API+Subscriptions+Policy.swift */; }; DB6D9F3526351B7A008423CD /* NotificationService+Decrypt.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6D9F3426351B7A008423CD /* NotificationService+Decrypt.swift */; }; DB6D9F42263527CE008423CD /* AlamofireImage in Frameworks */ = {isa = PBXBuildFile; productRef = DB6D9F41263527CE008423CD /* AlamofireImage */; }; @@ -502,8 +503,6 @@ DBB525562611EDCA002F1F29 /* UserTimelineViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB525552611EDCA002F1F29 /* UserTimelineViewModel.swift */; }; DBB5255E2611F07A002F1F29 /* ProfileViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB5255D2611F07A002F1F29 /* ProfileViewModel.swift */; }; DBB525642612C988002F1F29 /* MeProfileViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB525632612C988002F1F29 /* MeProfileViewModel.swift */; }; - DBB5256E2612D5A1002F1F29 /* ProfileStatusDashboardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB5256D2612D5A1002F1F29 /* ProfileStatusDashboardView.swift */; }; - DBB525852612D6DD002F1F29 /* ProfileStatusDashboardMeterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB525842612D6DD002F1F29 /* ProfileStatusDashboardMeterView.swift */; }; DBB8AB4626AECDE200F6D281 /* SendPostIntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB8AB4526AECDE200F6D281 /* SendPostIntentHandler.swift */; }; DBB8AB4826AED09C00F6D281 /* MastodonSDK in Frameworks */ = {isa = PBXBuildFile; productRef = DBB8AB4726AED09C00F6D281 /* MastodonSDK */; }; DBB8AB4A26AED0B500F6D281 /* APIService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB8AB4926AED0B500F6D281 /* APIService.swift */; }; @@ -518,7 +517,6 @@ DBBC24CB26A546C000398BB9 /* ThemePreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBD376AB2692ECDB007FEC24 /* ThemePreference.swift */; }; DBBC24D126A5484F00398BB9 /* UITextView+Placeholder in Frameworks */ = {isa = PBXBuildFile; productRef = DBBC24D026A5484F00398BB9 /* UITextView+Placeholder */; }; DBBC24DC26A54BCB00398BB9 /* MastodonRegex.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24D626A54BCB00398BB9 /* MastodonRegex.swift */; }; - DBBC24DE26A54BCB00398BB9 /* MastodonMetricFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24D826A54BCB00398BB9 /* MastodonMetricFormatter.swift */; }; DBBE1B4525F3474B0081417A /* MastodonPickServerAppearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBE1B4425F3474B0081417A /* MastodonPickServerAppearance.swift */; }; DBBF1DBF2652401B00E5B703 /* AutoCompleteViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBF1DBE2652401B00E5B703 /* AutoCompleteViewModel.swift */; }; DBBF1DC226524D2900E5B703 /* AutoCompleteTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBF1DC126524D2900E5B703 /* AutoCompleteTableViewCell.swift */; }; @@ -594,7 +592,6 @@ DBFEF05F26A57715006D7ED1 /* StatusAuthorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBFEF05926A576EE006D7ED1 /* StatusAuthorView.swift */; }; DBFEF06026A57715006D7ED1 /* StatusAttachmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBFEF05A26A576EE006D7ED1 /* StatusAttachmentView.swift */; }; DBFEF06326A577F2006D7ED1 /* StatusAttachmentViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBFEF06226A577F2006D7ED1 /* StatusAttachmentViewModel.swift */; }; - DBFEF06926A67E45006D7ED1 /* AppearancePreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6D1B3C2636857500ACB481 /* AppearancePreference.swift */; }; DBFEF06D26A67FB7006D7ED1 /* StatusAttachmentViewModel+UploadState.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBFEF06C26A67FB7006D7ED1 /* StatusAttachmentViewModel+UploadState.swift */; }; DBFEF06F26A690C4006D7ED1 /* APIService+APIError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98337E25C9452D00AD9700 /* APIService+APIError.swift */; }; DBFEF07326A6913D006D7ED1 /* APIService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBFEF07226A6913D006D7ED1 /* APIService.swift */; }; @@ -945,7 +942,6 @@ DB336F3E278E668C0031E64B /* StatusTableViewCell+ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StatusTableViewCell+ViewModel.swift"; sourceTree = ""; }; DB336F40278E68480031E64B /* StatusView+Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StatusView+Configuration.swift"; sourceTree = ""; }; DB336F42278EB1680031E64B /* MediaView+Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MediaView+Configuration.swift"; sourceTree = ""; }; - DB35FC1E2612F1D9006193C9 /* ProfileRelationshipActionButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileRelationshipActionButton.swift; sourceTree = ""; }; DB36679C268AB91B0027D07F /* ComposeStatusAttachmentTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusAttachmentTableViewCell.swift; sourceTree = ""; }; DB36679E268ABAF20027D07F /* ComposeStatusAttachmentSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusAttachmentSection.swift; sourceTree = ""; }; DB3667A0268ABB2E0027D07F /* ComposeStatusAttachmentItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusAttachmentItem.swift; sourceTree = ""; }; @@ -963,6 +959,9 @@ DB3E6FEE2806D82600B035AE /* DiscoveryNewsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryNewsViewModel.swift; sourceTree = ""; }; DB3E6FF02806D96900B035AE /* DiscoveryNewsViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiscoveryNewsViewModel+Diffable.swift"; sourceTree = ""; }; DB3E6FF22806D97400B035AE /* DiscoveryNewsViewModel+State.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiscoveryNewsViewModel+State.swift"; sourceTree = ""; }; + DB3E6FF42807C40300B035AE /* DiscoveryForYouViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryForYouViewController.swift; sourceTree = ""; }; + DB3E6FF72807C45300B035AE /* DiscoveryForYouViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryForYouViewModel.swift; sourceTree = ""; }; + DB3E6FF92807C47900B035AE /* DiscoveryForYouViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiscoveryForYouViewModel+Diffable.swift"; sourceTree = ""; }; DB427DD225BAA00100D1B89D /* Mastodon.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Mastodon.app; sourceTree = BUILT_PRODUCTS_DIR; }; DB427DD525BAA00100D1B89D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; DB427DD725BAA00100D1B89D /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; @@ -1119,7 +1118,6 @@ DB6B74FF272FF73800C70B6E /* UserTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserTableViewCell.swift; sourceTree = ""; }; DB6B750327300B4000C70B6E /* TimelineFooterTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineFooterTableViewCell.swift; sourceTree = ""; }; DB6C8C0E25F0A6AE00AAA452 /* Mastodon+Entity+Error.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Mastodon+Entity+Error.swift"; sourceTree = ""; }; - DB6D1B3C2636857500ACB481 /* AppearancePreference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearancePreference.swift; sourceTree = ""; }; DB6D1B43263691CF00ACB481 /* Mastodon+API+Subscriptions+Policy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Mastodon+API+Subscriptions+Policy.swift"; sourceTree = ""; }; DB6D9F3426351B7A008423CD /* NotificationService+Decrypt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NotificationService+Decrypt.swift"; sourceTree = ""; }; DB6D9F4826353FD6008423CD /* Subscription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Subscription.swift; sourceTree = ""; }; @@ -1261,15 +1259,12 @@ DBB525552611EDCA002F1F29 /* UserTimelineViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserTimelineViewModel.swift; sourceTree = ""; }; DBB5255D2611F07A002F1F29 /* ProfileViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileViewModel.swift; sourceTree = ""; }; DBB525632612C988002F1F29 /* MeProfileViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeProfileViewModel.swift; sourceTree = ""; }; - DBB5256D2612D5A1002F1F29 /* ProfileStatusDashboardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileStatusDashboardView.swift; sourceTree = ""; }; - DBB525842612D6DD002F1F29 /* ProfileStatusDashboardMeterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileStatusDashboardMeterView.swift; sourceTree = ""; }; DBB8AB4526AECDE200F6D281 /* SendPostIntentHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendPostIntentHandler.swift; sourceTree = ""; }; DBB8AB4926AED0B500F6D281 /* APIService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIService.swift; sourceTree = ""; }; DBB9759B262462E1004620BD /* ThreadMetaView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadMetaView.swift; sourceTree = ""; }; DBBC24A726A52F9000398BB9 /* ComposeToolbarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeToolbarView.swift; sourceTree = ""; }; DBBC24AB26A53D9300398BB9 /* ComposeStatusContentTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusContentTableViewCell.swift; sourceTree = ""; }; DBBC24D626A54BCB00398BB9 /* MastodonRegex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MastodonRegex.swift; sourceTree = ""; }; - DBBC24D826A54BCB00398BB9 /* MastodonMetricFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MastodonMetricFormatter.swift; sourceTree = ""; }; DBBC50C0278ED49200AF0CC6 /* MastodonAuthenticationBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonAuthenticationBox.swift; sourceTree = ""; }; DBBE1B4425F3474B0081417A /* MastodonPickServerAppearance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonPickServerAppearance.swift; sourceTree = ""; }; DBBF1DBE2652401B00E5B703 /* AutoCompleteViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoCompleteViewModel.swift; sourceTree = ""; }; @@ -2147,6 +2142,16 @@ path = News; sourceTree = ""; }; + DB3E6FF62807C40500B035AE /* ForYou */ = { + isa = PBXGroup; + children = ( + DB3E6FF42807C40300B035AE /* DiscoveryForYouViewController.swift */, + DB3E6FF72807C45300B035AE /* DiscoveryForYouViewModel.swift */, + DB3E6FF92807C47900B035AE /* DiscoveryForYouViewModel+Diffable.swift */, + ); + path = ForYou; + sourceTree = ""; + }; DB427DC925BAA00100D1B89D = { isa = PBXGroup; children = ( @@ -2378,7 +2383,6 @@ children = ( DBA465942696E387002B41DB /* AppPreference.swift */, DB647C5826F1EA2700F7F82C /* WizardPreference.swift */, - DB6D1B3C2636857500ACB481 /* AppearancePreference.swift */, DBE54AC52636C89F004E7C0B /* NotificationPreference.swift */, DB1D842F26566512000346B3 /* KeyboardPreference.swift */, DBCBCC0C2680B908000F5B51 /* HomeTimelinePreference.swift */, @@ -3040,9 +3044,6 @@ isa = PBXGroup; children = ( DBB5254F2611ED6D002F1F29 /* ProfileHeaderView.swift */, - DBB5256D2612D5A1002F1F29 /* ProfileStatusDashboardView.swift */, - DBB525842612D6DD002F1F29 /* ProfileStatusDashboardMeterView.swift */, - DB35FC1E2612F1D9006193C9 /* ProfileRelationshipActionButton.swift */, DBF98149265E24F500E4BA07 /* ProfileFieldCollectionViewHeaderFooterView.swift */, ); path = View; @@ -3061,7 +3062,6 @@ children = ( DBBC24D626A54BCB00398BB9 /* MastodonRegex.swift */, DBBC50C0278ED49200AF0CC6 /* MastodonAuthenticationBox.swift */, - DBBC24D826A54BCB00398BB9 /* MastodonMetricFormatter.swift */, DBF3B7402733EB9400E21627 /* MastodonLocalCode.swift */, ); path = Helper; @@ -3113,6 +3113,7 @@ DBDFF19828055A0900557A48 /* Posts */, DB3E6FDE2806A41200B035AE /* Hashtags */, DB3E6FED2806D7FC00B035AE /* News */, + DB3E6FF62807C40500B035AE /* ForYou */, DBDFF19928055A1400557A48 /* DiscoveryViewController.swift */, DBDFF19B28055BD600557A48 /* DiscoveryViewModel.swift */, ); @@ -3947,7 +3948,6 @@ DBDFF1952805561700557A48 /* DiscoveryPostsViewModel+Diffable.swift in Sources */, DB03A795272A981400EE37C5 /* ContentSplitViewController.swift in Sources */, DBDFF19C28055BD600557A48 /* DiscoveryViewModel.swift in Sources */, - DBBC24DE26A54BCB00398BB9 /* MastodonMetricFormatter.swift in Sources */, DB06180A2785B2AB0030EE79 /* MastodonRegisterAvatarTableViewCell.swift in Sources */, DBB45B6227B51112002DC5A7 /* SuggestionAccountViewModel+Diffable.swift in Sources */, DBB3BA2A26A81C020004F2D4 /* FLAnimatedImageView.swift in Sources */, @@ -3974,7 +3974,6 @@ DBE3CE07261D6A0E00430CC6 /* FavoriteViewModel+Diffable.swift in Sources */, 2D34D9DB261494120081BFC0 /* APIService+Search.swift in Sources */, 5B90C48B26259C120002E742 /* APIService+CoreData+Subscriptions.swift in Sources */, - DBB5256E2612D5A1002F1F29 /* ProfileStatusDashboardView.swift in Sources */, DBA9443E265CFA6400C537E1 /* ProfileFieldCollectionViewCell.swift in Sources */, DB025B93278D6501002F581E /* Persistence.swift in Sources */, 2D24E1232626ED9D00A59D4F /* UIView+Gesture.swift in Sources */, @@ -4066,11 +4065,11 @@ DB697DD4278F4927004EF2F7 /* StatusTableViewCellDelegate.swift in Sources */, DB0FCB902796C5EB006C02E2 /* APIService+Trend.swift in Sources */, DBA5E7A5263BD28C004598BB /* ContextMenuImagePreviewViewModel.swift in Sources */, + DB3E6FF52807C40300B035AE /* DiscoveryForYouViewController.swift in Sources */, DB9D7C21269824B80054B3DF /* APIService+Filter.swift in Sources */, 2D38F1E525CD46C100561493 /* HomeTimelineViewModel.swift in Sources */, DB0FCB842796B2A2006C02E2 /* FavoriteViewController+DataSourceProvider.swift in Sources */, DBCC3B36261440BA0045B23D /* UINavigationController.swift in Sources */, - DBB525852612D6DD002F1F29 /* ProfileStatusDashboardMeterView.swift in Sources */, DB0FCB68279507EF006C02E2 /* DataSourceFacade+Meta.swift in Sources */, DB63F75C279956D000455B82 /* Persistence+Tag.swift in Sources */, 2D84350525FF858100EECE90 /* UIScrollView.swift in Sources */, @@ -4112,7 +4111,6 @@ DBBF1DCB2652539E00E5B703 /* AutoCompleteItem.swift in Sources */, DB84811727883C2600BBEABA /* MastodonRegisterPasswordHintTableViewCell.swift in Sources */, 2DA6054725F716A2006356F9 /* PlaybackState.swift in Sources */, - DB35FC1F2612F1D9006193C9 /* ProfileRelationshipActionButton.swift in Sources */, DB98EB6727B216560082E365 /* ReportResultViewModel+Diffable.swift in Sources */, DBC7A672260C897100E57475 /* StatusContentWarningEditorView.swift in Sources */, DB025B95278D6530002F581E /* Persistence+MastodonUser.swift in Sources */, @@ -4178,6 +4176,7 @@ DB852D1C26FB021500FC9D81 /* RootSplitViewController.swift in Sources */, DB697DD1278F4871004EF2F7 /* AutoGenerateTableViewDelegate.swift in Sources */, DB02CDBF2625AE5000D0A2AF /* AdaptiveUserInterfaceStyleBarButtonItem.swift in Sources */, + DB3E6FFA2807C47900B035AE /* DiscoveryForYouViewModel+Diffable.swift in Sources */, DB1FD44425F26CCC004CFCFC /* PickServerSection.swift in Sources */, DBB45B6027B50A4F002DC5A7 /* RecommendAccountItem.swift in Sources */, 0FB3D30F25E525CD00AAD544 /* PickServerCategoryView.swift in Sources */, @@ -4311,6 +4310,7 @@ DB9F58EC26EF435000E7BBE9 /* AccountViewController.swift in Sources */, 2D5A3D6225CFD9CB002347D6 /* HomeTimelineViewController+DebugAction.swift in Sources */, DB3E6FF12806D96900B035AE /* DiscoveryNewsViewModel+Diffable.swift in Sources */, + DB3E6FF82807C45300B035AE /* DiscoveryForYouViewModel.swift in Sources */, DB49A62525FF334C00B98345 /* EmojiService+CustomEmojiViewModel+LoadState.swift in Sources */, DB4924E226312AB200E9DB22 /* NotificationService.swift in Sources */, DB6D9F6F2635807F008423CD /* Setting.swift in Sources */, @@ -4327,7 +4327,6 @@ DB789A1225F9F2CC0071ACA0 /* ComposeViewModel.swift in Sources */, DB63F74B279914A000455B82 /* FollowingListViewController+DataSourceProvider.swift in Sources */, DBB525362611ECEB002F1F29 /* UserTimelineViewController.swift in Sources */, - DB6D1B3D2636857500ACB481 /* AppearancePreference.swift in Sources */, DB938F3326243D6200E5B6C1 /* TimelineTopLoaderTableViewCell.swift in Sources */, DB98EB4927B0F0CD0082E365 /* ReportStatusTableViewCell.swift in Sources */, DB3667A4268AE2370027D07F /* ComposeStatusPollTableViewCell.swift in Sources */, @@ -4424,7 +4423,6 @@ DBBC24A826A52F9000398BB9 /* ComposeToolbarView.swift in Sources */, DBFEF05B26A57715006D7ED1 /* ComposeViewModel.swift in Sources */, DBFEF06326A577F2006D7ED1 /* StatusAttachmentViewModel.swift in Sources */, - DBFEF06926A67E45006D7ED1 /* AppearancePreference.swift in Sources */, DBC6461526A170AB00B0E31B /* ShareViewController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 55845d580..1444a8b27 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 23 + 22 MastodonIntents.xcscheme_^#shared#^_ @@ -124,7 +124,7 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 22 + 23 ShareActionExtension.xcscheme_^#shared#^_ diff --git a/Mastodon/Diffiable/Discovery/DiscoveryItem.swift b/Mastodon/Diffiable/Discovery/DiscoveryItem.swift index 181756d25..024c4a2da 100644 --- a/Mastodon/Diffiable/Discovery/DiscoveryItem.swift +++ b/Mastodon/Diffiable/Discovery/DiscoveryItem.swift @@ -7,9 +7,11 @@ import Foundation import MastodonSDK +import CoreDataStack enum DiscoveryItem: Hashable { case hashtag(Mastodon.Entity.Tag) case link(Mastodon.Entity.Link) + case user(ManagedObjectRecord) case bottomLoader } diff --git a/Mastodon/Diffiable/Discovery/DiscoverySection.swift b/Mastodon/Diffiable/Discovery/DiscoverySection.swift index 32683609d..f0c358a17 100644 --- a/Mastodon/Diffiable/Discovery/DiscoverySection.swift +++ b/Mastodon/Diffiable/Discovery/DiscoverySection.swift @@ -29,8 +29,9 @@ extension DiscoverySection { ) -> UITableViewDiffableDataSource { tableView.register(TrendTableViewCell.self, forCellReuseIdentifier: String(describing: TrendTableViewCell.self)) tableView.register(NewsTableViewCell.self, forCellReuseIdentifier: String(describing: NewsTableViewCell.self)) + tableView.register(ProfileCardTableViewCell.self, forCellReuseIdentifier: String(describing: ProfileCardTableViewCell.self)) tableView.register(TimelineBottomLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self)) - + return UITableViewDiffableDataSource(tableView: tableView) { tableView, indexPath, item in switch item { case .hashtag(let tag): @@ -41,6 +42,17 @@ extension DiscoverySection { let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: NewsTableViewCell.self), for: indexPath) as! NewsTableViewCell cell.newsView.configure(link: link) return cell + case .user(let record): + let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: ProfileCardTableViewCell.self), for: indexPath) as! ProfileCardTableViewCell + context.managedObjectContext.performAndWait { + guard let user = record.object(in: context.managedObjectContext) else { return } + cell.profileCardView.configure(user: user) + } + context.authenticationService.activeMastodonAuthentication + .map { $0?.user } + .assign(to: \.me, on: cell.profileCardView.viewModel.relationshipViewModel) + .store(in: &cell.disposeBag) + return cell case .bottomLoader: let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self), for: indexPath) as! TimelineBottomLoaderTableViewCell cell.activityIndicatorView.startAnimating() diff --git a/Mastodon/Extension/CoreDataStack/MastodonUser.swift b/Mastodon/Extension/CoreDataStack/MastodonUser.swift index 02a983680..bc5f159d9 100644 --- a/Mastodon/Extension/CoreDataStack/MastodonUser.swift +++ b/Mastodon/Extension/CoreDataStack/MastodonUser.swift @@ -9,53 +9,6 @@ import Foundation import CoreDataStack import MastodonSDK -extension MastodonUser { - - public var displayNameWithFallback: String { - return !displayName.isEmpty ? displayName : username - } - - public var acctWithDomain: String { - if !acct.contains("@") { - // Safe concat due to username cannot contains "@" - return username + "@" + domain - } else { - return acct - } - } - - public var domainFromAcct: String { - if !acct.contains("@") { - return domain - } else { - let domain = acct.split(separator: "@").last - return String(domain!) - } - } - -} - -extension MastodonUser { - - public func headerImageURL() -> URL? { - return URL(string: header) - } - - public func headerImageURLWithFallback(domain: String) -> URL { - return URL(string: header) ?? URL(string: "https://\(domain)/headers/original/missing.png")! - } - - public func avatarImageURL() -> URL? { - let string = UserDefaults.shared.preferredStaticAvatar ? avatarStatic ?? avatar : avatar - return URL(string: string) - } - - public func avatarImageURLWithFallback(domain: String) -> URL { - return avatarImageURL() ?? URL(string: "https://\(domain)/avatars/original/missing.png")! - } - -} - extension MastodonUser { public var profileURL: URL { diff --git a/Mastodon/Persistence/Extension/MastodonEmoji.swift b/Mastodon/Persistence/Extension/MastodonEmoji.swift index e9274a24d..2ea23c67c 100644 --- a/Mastodon/Persistence/Extension/MastodonEmoji.swift +++ b/Mastodon/Persistence/Extension/MastodonEmoji.swift @@ -22,13 +22,3 @@ extension MastodonEmoji { ) } } - -extension Collection where Element == MastodonEmoji { - public var asDictionary: MastodonContent.Emojis { - var dictionary: MastodonContent.Emojis = [:] - for emoji in self { - dictionary[emoji.code] = emoji.url - } - return dictionary - } -} diff --git a/Mastodon/Scene/Discovery/DiscoveryViewModel.swift b/Mastodon/Scene/Discovery/DiscoveryViewModel.swift index acb92b5f4..187d73111 100644 --- a/Mastodon/Scene/Discovery/DiscoveryViewModel.swift +++ b/Mastodon/Scene/Discovery/DiscoveryViewModel.swift @@ -16,6 +16,7 @@ final class DiscoveryViewModel { let discoveryPostsViewController: DiscoveryPostsViewController let discoveryHashtagsViewController: DiscoveryHashtagsViewController let discoveryNewsViewController: DiscoveryNewsViewController + let discoveryForYouViewController: DiscoveryForYouViewController // output let barItems: [TMBarItemable] = { @@ -33,6 +34,7 @@ final class DiscoveryViewModel { discoveryPostsViewController, discoveryHashtagsViewController, discoveryNewsViewController, + discoveryForYouViewController, ] } @@ -61,6 +63,12 @@ final class DiscoveryViewModel { viewController.viewModel = DiscoveryNewsViewModel(context: context) return viewController }() + discoveryForYouViewController = { + let viewController = DiscoveryForYouViewController() + setupDependency(viewController) + viewController.viewModel = DiscoveryForYouViewModel(context: context) + return viewController + }() // end init } diff --git a/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift new file mode 100644 index 000000000..4654769d1 --- /dev/null +++ b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift @@ -0,0 +1,127 @@ +// +// DiscoveryForYouViewController.swift +// Mastodon +// +// Created by MainasuK on 2022-4-14. +// + +import os.log +import UIKit +import Combine +import MastodonUI + +final class DiscoveryForYouViewController: UIViewController, NeedsDependency, MediaPreviewableViewController { + + let logger = Logger(subsystem: "DiscoveryForYouViewController", category: "ViewController") + + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } + weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + + var disposeBag = Set() + var viewModel: DiscoveryForYouViewModel! + + let mediaPreviewTransitionController = MediaPreviewTransitionController() + + lazy var tableView: UITableView = { + let tableView = UITableView() + tableView.rowHeight = UITableView.automaticDimension + tableView.estimatedRowHeight = 100 + tableView.separatorStyle = .none + tableView.backgroundColor = .clear + return tableView + }() + + let refreshControl = UIRefreshControl() + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } + +} + +extension DiscoveryForYouViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor + ThemeService.shared.currentTheme + .receive(on: DispatchQueue.main) + .sink { [weak self] theme in + guard let self = self else { return } + self.view.backgroundColor = theme.secondarySystemBackgroundColor + } + .store(in: &disposeBag) + + tableView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(tableView) + NSLayoutConstraint.activate([ + tableView.topAnchor.constraint(equalTo: view.topAnchor), + tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + ]) + + tableView.delegate = self + viewModel.setupDiffableDataSource( + tableView: tableView + ) + + tableView.refreshControl = refreshControl + refreshControl.addTarget(self, action: #selector(DiscoveryForYouViewController.refreshControlValueChanged(_:)), for: .valueChanged) + viewModel.$isFetching + .receive(on: DispatchQueue.main) + .sink { [weak self] isFetching in + guard let self = self else { return } + if !isFetching { + self.refreshControl.endRefreshing() + } + } + .store(in: &disposeBag) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + refreshControl.endRefreshing() + tableView.deselectRow(with: transitionCoordinator, animated: animated) + } + +} + +extension DiscoveryForYouViewController { + + @objc private func refreshControlValueChanged(_ sender: UIRefreshControl) { + Task { + try await viewModel.fetch() + } + } + +} + +// MARK: - UITableViewDelegate +extension DiscoveryForYouViewController: UITableViewDelegate { + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): \(indexPath)") + guard case let .user(record) = viewModel.diffableDataSource?.itemIdentifier(for: indexPath) else { return } + guard let user = record.object(in: context.managedObjectContext) else { return } + let profileViewModel = CachedProfileViewModel( + context: context, + mastodonUser: user + ) + coordinator.present( + scene: .profile(viewModel: profileViewModel), + from: self, + transition: .show + ) + } + +} + +// MARK: ScrollViewContainer +extension DiscoveryForYouViewController: ScrollViewContainer { + var scrollView: UIScrollView? { + tableView + } +} diff --git a/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel+Diffable.swift b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel+Diffable.swift new file mode 100644 index 000000000..23114073f --- /dev/null +++ b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel+Diffable.swift @@ -0,0 +1,43 @@ +// +// DiscoveryForYouViewModel+Diffable.swift +// Mastodon +// +// Created by MainasuK on 2022-4-14. +// + +import UIKit +import Combine + +extension DiscoveryForYouViewModel { + + func setupDiffableDataSource( + tableView: UITableView + ) { + diffableDataSource = DiscoverySection.diffableDataSource( + tableView: tableView, + context: context, + configuration: DiscoverySection.Configuration() + ) + + Task { + try await fetch() + } + + userFetchedResultsController.$records + .receive(on: DispatchQueue.main) + .sink { [weak self] records in + guard let self = self else { return } + guard let diffableDataSource = self.diffableDataSource else { return } + + var snapshot = NSDiffableDataSourceSnapshot() + snapshot.appendSections([.forYou]) + + let items = records.map { DiscoveryItem.user($0) } + snapshot.appendItems(items, toSection: .forYou) + + diffableDataSource.applySnapshot(snapshot, animated: false) + } + .store(in: &disposeBag) + } + +} diff --git a/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel.swift b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel.swift new file mode 100644 index 000000000..7be4aebaf --- /dev/null +++ b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel.swift @@ -0,0 +1,75 @@ +// +// DiscoveryForYouViewModel.swift +// Mastodon +// +// Created by MainasuK on 2022-4-14. +// + +import os.log +import UIKit +import Combine +import GameplayKit +import CoreData +import CoreDataStack +import MastodonSDK + +final class DiscoveryForYouViewModel { + + var disposeBag = Set() + + // input + let context: AppContext + let userFetchedResultsController: UserFetchedResultsController + @Published var isFetching = false + + // output + var diffableDataSource: UITableViewDiffableDataSource? + let didLoadLatest = PassthroughSubject() + + init(context: AppContext) { + self.context = context + self.userFetchedResultsController = UserFetchedResultsController( + managedObjectContext: context.managedObjectContext, + domain: nil, + additionalPredicate: nil + ) + // end init + + context.authenticationService.activeMastodonAuthenticationBox + .map { $0?.domain } + .assign(to: \.domain, on: userFetchedResultsController) + .store(in: &disposeBag) + } + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } + +} + +extension DiscoveryForYouViewModel { + func fetch() async throws { + guard !isFetching else { return } + isFetching = true + defer { isFetching = false } + + guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return } + + do { + let response = try await context.apiService.suggestionAccountV2( + query: nil, + authenticationBox: authenticationBox + ) + let userIDs = response.value.map { $0.account.id } + userFetchedResultsController.userIDs = userIDs + } catch { + // fallback V1 + let response2 = try await context.apiService.suggestionAccount( + query: nil, + authenticationBox: authenticationBox + ) + let userIDs = response2.value.map { $0.id } + userFetchedResultsController.userIDs = userIDs + } + } +} diff --git a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift index 82d604d64..37d93e5b4 100644 --- a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift +++ b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift @@ -70,8 +70,6 @@ extension DiscoveryNewsViewModel.State { super.didEnter(from: previousState) guard let viewModel = viewModel, let stateMachine = stateMachine else { return } - viewModel.links = [] - stateMachine.enter(Loading.self) } } @@ -113,7 +111,6 @@ extension DiscoveryNewsViewModel.State { class Loading: DiscoveryNewsViewModel.State { var offset: Int? - var isReloading: Bool { return offset == nil } override func isValidNextState(_ stateClass: AnyClass) -> Bool { switch stateClass { @@ -146,6 +143,7 @@ extension DiscoveryNewsViewModel.State { } let offset = self.offset + let isReloading = offset == nil Task { do { @@ -169,7 +167,7 @@ extension DiscoveryNewsViewModel.State { self.offset = newOffset var hasNewItemsAppend = false - var links = viewModel.links + var links = isReloading ? [] : viewModel.links for link in response.value { guard !links.contains(link) else { continue } links.append(link) diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift index 199215d14..a8e2e7c20 100644 --- a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift @@ -68,10 +68,7 @@ extension DiscoveryPostsViewModel.State { override func didEnter(from previousState: GKState?) { super.didEnter(from: previousState) - guard let viewModel = viewModel, let stateMachine = stateMachine else { return } - - // reset - viewModel.statusFetchedResultsController.statusIDs.value = [] + guard let _ = viewModel, let stateMachine = stateMachine else { return } stateMachine.enter(Loading.self) } @@ -145,6 +142,7 @@ extension DiscoveryPostsViewModel.State { } let offset = self.offset + let isReloading = offset == nil Task { do { @@ -168,7 +166,7 @@ extension DiscoveryPostsViewModel.State { self.offset = newOffset var hasNewStatusesAppend = false - var statusIDs = viewModel.statusFetchedResultsController.statusIDs.value + var statusIDs = isReloading ? [] : viewModel.statusFetchedResultsController.statusIDs.value for status in response.value { guard !statusIDs.contains(status.id) else { continue } statusIDs.append(status.id) diff --git a/Mastodon/Scene/Profile/ProfileViewModel.swift b/Mastodon/Scene/Profile/ProfileViewModel.swift index 403437daf..ac8c12e98 100644 --- a/Mastodon/Scene/Profile/ProfileViewModel.swift +++ b/Mastodon/Scene/Profile/ProfileViewModel.swift @@ -13,10 +13,11 @@ import MastodonSDK import MastodonMeta import MastodonAsset import MastodonLocalization +import MastodonUI // please override this base class class ProfileViewModel: NSObject { - + let logger = Logger(subsystem: "ProfileViewModel", category: "ViewModel") typealias UserID = String @@ -372,101 +373,6 @@ extension ProfileViewModel { } -extension ProfileViewModel { - - enum RelationshipAction: Int, CaseIterable { - case none // set hide from UI - case follow - case request - case pending - case following - case muting - case blocked - case blocking - case suspended - case edit - case editing - case updating - - var option: RelationshipActionOptionSet { - return RelationshipActionOptionSet(rawValue: 1 << rawValue) - } - } - - // construct option set on the enum for safe iterator - struct RelationshipActionOptionSet: OptionSet { - let rawValue: Int - - static let none = RelationshipAction.none.option - static let follow = RelationshipAction.follow.option - static let request = RelationshipAction.request.option - static let pending = RelationshipAction.pending.option - static let following = RelationshipAction.following.option - static let muting = RelationshipAction.muting.option - static let blocked = RelationshipAction.blocked.option - static let blocking = RelationshipAction.blocking.option - static let suspended = RelationshipAction.suspended.option - static let edit = RelationshipAction.edit.option - static let editing = RelationshipAction.editing.option - static let updating = RelationshipAction.updating.option - - static let editOptions: RelationshipActionOptionSet = [.edit, .editing, .updating] - - func highPriorityAction(except: RelationshipActionOptionSet) -> RelationshipAction? { - let set = subtracting(except) - for action in RelationshipAction.allCases.reversed() where set.contains(action.option) { - return action - } - - return nil - } - - var title: String { - guard let highPriorityAction = self.highPriorityAction(except: []) else { - assertionFailure() - return " " - } - switch highPriorityAction { - case .none: return " " - case .follow: return L10n.Common.Controls.Friendship.follow - case .request: return L10n.Common.Controls.Friendship.request - case .pending: return L10n.Common.Controls.Friendship.pending - case .following: return L10n.Common.Controls.Friendship.following - case .muting: return L10n.Common.Controls.Friendship.muted - case .blocked: return L10n.Common.Controls.Friendship.follow // blocked by user - case .blocking: return L10n.Common.Controls.Friendship.blocked - case .suspended: return L10n.Common.Controls.Friendship.follow - case .edit: return L10n.Common.Controls.Friendship.editInfo - case .editing: return L10n.Common.Controls.Actions.done - case .updating: return " " - } - } - - @available(*, deprecated, message: "") - var backgroundColor: UIColor { - guard let highPriorityAction = self.highPriorityAction(except: []) else { - assertionFailure() - return Asset.Colors.brandBlue.color - } - switch highPriorityAction { - case .none: return Asset.Colors.brandBlue.color - case .follow: return Asset.Colors.brandBlue.color - case .request: return Asset.Colors.brandBlue.color - case .pending: return Asset.Colors.brandBlue.color - case .following: return Asset.Colors.brandBlue.color - case .muting: return Asset.Colors.alertYellow.color - case .blocked: return Asset.Colors.brandBlue.color - case .blocking: return Asset.Colors.danger.color - case .suspended: return Asset.Colors.brandBlue.color - case .edit: return Asset.Colors.brandBlue.color - case .editing: return Asset.Colors.brandBlue.color - case .updating: return Asset.Colors.brandBlue.color - } - } - - } -} - extension ProfileViewModel { func updateProfileInfo( headerProfileInfo: ProfileHeaderViewModel.ProfileInfo, diff --git a/Mastodon/Service/APIService/APIService+Recommend.swift b/Mastodon/Service/APIService/APIService+Recommend.swift index cb195b608..6e457ad07 100644 --- a/Mastodon/Service/APIService/APIService+Recommend.swift +++ b/Mastodon/Service/APIService/APIService+Recommend.swift @@ -13,12 +13,13 @@ import CoreDataStack import OSLog extension APIService { + func suggestionAccount( query: Mastodon.API.Suggestions.Query?, authenticationBox: MastodonAuthenticationBox ) async throws -> Mastodon.Response.Content<[Mastodon.Entity.Account]> { - let response = try await Mastodon.API.Suggestions.get( + let response = try await Mastodon.API.Suggestions.accounts( session: session, domain: authenticationBox.domain, query: query, @@ -47,7 +48,7 @@ extension APIService { query: Mastodon.API.Suggestions.Query?, authenticationBox: MastodonAuthenticationBox ) async throws -> Mastodon.Response.Content<[Mastodon.Entity.V2.SuggestionAccount]> { - let response = try await Mastodon.API.V2.Suggestions.get( + let response = try await Mastodon.API.V2.Suggestions.accounts( session: session, domain: authenticationBox.domain, query: query, diff --git a/MastodonSDK/Package.swift b/MastodonSDK/Package.swift index d6078090b..dd562f147 100644 --- a/MastodonSDK/Package.swift +++ b/MastodonSDK/Package.swift @@ -94,6 +94,7 @@ let package = Package( .product(name: "Alamofire", package: "Alamofire"), .product(name: "AlamofireImage", package: "AlamofireImage"), .product(name: "MetaTextKit", package: "MetaTextKit"), + .product(name: "MastodonMeta", package: "MetaTextKit"), .product(name: "FLAnimatedImage", package: "FLAnimatedImage"), ] ), diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Discovery/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Discovery/Contents.json new file mode 100644 index 000000000..6e965652d --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Discovery/Contents.json @@ -0,0 +1,9 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "provides-namespace" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Discovery/profile.card.background.colorset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Discovery/profile.card.background.colorset/Contents.json new file mode 100644 index 000000000..1fc21a878 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Scene/Discovery/profile.card.background.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "251", + "green" : "250", + "red" : "249" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "4", + "green" : "5", + "red" : "6" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift b/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift index 26e54900f..3e7fa5c11 100644 --- a/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift +++ b/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift @@ -103,6 +103,9 @@ public enum Asset { public static let star = ImageAsset(name: "ObjectsAndTools/star") } public enum Scene { + public enum Discovery { + public static let profileCardBackground = ColorAsset(name: "Scene/Discovery/profile.card.background") + } public enum Onboarding { public static let avatarPlaceholder = ImageAsset(name: "Scene/Onboarding/avatar.placeholder") public static let background = ColorAsset(name: "Scene/Onboarding/background") diff --git a/Mastodon/Preference/AppearancePreference.swift b/MastodonSDK/Sources/MastodonCommon/Preference/Preference+Appearance.swift similarity index 81% rename from Mastodon/Preference/AppearancePreference.swift rename to MastodonSDK/Sources/MastodonCommon/Preference/Preference+Appearance.swift index 034bf9654..713c926bc 100644 --- a/Mastodon/Preference/AppearancePreference.swift +++ b/MastodonSDK/Sources/MastodonCommon/Preference/Preference+Appearance.swift @@ -9,7 +9,7 @@ import UIKit extension UserDefaults { - @objc dynamic var customUserInterfaceStyle: UIUserInterfaceStyle { + @objc public dynamic var customUserInterfaceStyle: UIUserInterfaceStyle { get { register(defaults: [#function: UIUserInterfaceStyle.unspecified.rawValue]) return UIUserInterfaceStyle(rawValue: integer(forKey: #function)) ?? .unspecified @@ -17,7 +17,7 @@ extension UserDefaults { set { self[#function] = newValue.rawValue } } - @objc dynamic var preferredStaticAvatar: Bool { + @objc public dynamic var preferredStaticAvatar: Bool { get { // default false // without set register to profile timeline performance @@ -26,7 +26,7 @@ extension UserDefaults { set { self[#function] = newValue } } - @objc dynamic var preferredStaticEmoji: Bool { + @objc public dynamic var preferredStaticEmoji: Bool { get { // default false // without set register to profile timeline performance diff --git a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Suggestions.swift b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Suggestions.swift index 558089645..4c424f3be 100644 --- a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Suggestions.swift +++ b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Suggestions.swift @@ -27,7 +27,7 @@ extension Mastodon.API.Suggestions { /// - query: query /// - authorization: User token. /// - Returns: `AnyPublisher` contains `Accounts` nested in the response - public static func get( + public static func accounts( session: URLSession, domain: String, query: Mastodon.API.Suggestions.Query?, diff --git a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+V2+Suggestions.swift b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+V2+Suggestions.swift index 9e6876b41..ed680dbac 100644 --- a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+V2+Suggestions.swift +++ b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+V2+Suggestions.swift @@ -20,7 +20,7 @@ extension Mastodon.API.V2.Suggestions { /// - query: query /// - authorization: User token. /// - Returns: `AnyPublisher` contains `AccountsSuggestion` nested in the response - public static func get( + public static func accounts( session: URLSession, domain: String, query: Mastodon.API.Suggestions.Query?, diff --git a/MastodonSDK/Sources/MastodonUI/Extension/CoreDataStack/MastodonEmoji.swift b/MastodonSDK/Sources/MastodonUI/Extension/CoreDataStack/MastodonEmoji.swift new file mode 100644 index 000000000..4f097759f --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/Extension/CoreDataStack/MastodonEmoji.swift @@ -0,0 +1,20 @@ +// +// MastodonEmoji.swift +// +// +// Created by MainasuK on 2022-4-14. +// + +import Foundation +import CoreDataStack +import MastodonMeta + +extension Collection where Element == MastodonEmoji { + public var asDictionary: MastodonContent.Emojis { + var dictionary: MastodonContent.Emojis = [:] + for emoji in self { + dictionary[emoji.code] = emoji.url + } + return dictionary + } +} diff --git a/MastodonSDK/Sources/MastodonUI/Extension/CoreDataStack/MastodonUser.swift b/MastodonSDK/Sources/MastodonUI/Extension/CoreDataStack/MastodonUser.swift new file mode 100644 index 000000000..9b61ab5f6 --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/Extension/CoreDataStack/MastodonUser.swift @@ -0,0 +1,57 @@ +// +// MastodonUser.swift +// +// +// Created by MainasuK on 2022-4-14. +// + +import Foundation +import CoreDataStack +import MastodonCommon + +extension MastodonUser { + + public var displayNameWithFallback: String { + return !displayName.isEmpty ? displayName : username + } + + public var acctWithDomain: String { + if !acct.contains("@") { + // Safe concat due to username cannot contains "@" + return username + "@" + domain + } else { + return acct + } + } + + public var domainFromAcct: String { + if !acct.contains("@") { + return domain + } else { + let domain = acct.split(separator: "@").last + return String(domain!) + } + } + +} + +extension MastodonUser { + + public func headerImageURL() -> URL? { + return URL(string: header) + } + + public func headerImageURLWithFallback(domain: String) -> URL { + return URL(string: header) ?? URL(string: "https://\(domain)/headers/original/missing.png")! + } + + public func avatarImageURL() -> URL? { + let string = UserDefaults.shared.preferredStaticAvatar ? avatarStatic ?? avatar : avatar + return URL(string: string) + } + + public func avatarImageURLWithFallback(domain: String) -> URL { + return avatarImageURL() ?? URL(string: "https://\(domain)/avatars/original/missing.png")! + } + +} diff --git a/MastodonSDK/Sources/MastodonUI/Extension/MetaLabel.swift b/MastodonSDK/Sources/MastodonUI/Extension/MetaLabel.swift index 119e9e031..24a4027f5 100644 --- a/MastodonSDK/Sources/MastodonUI/Extension/MetaLabel.swift +++ b/MastodonSDK/Sources/MastodonUI/Extension/MetaLabel.swift @@ -20,6 +20,8 @@ extension MetaLabel { case notificationTitle case profileFieldName case profileFieldValue + case profileCardName + case profileCardUsername case recommendAccountName case titleView case settingTableFooter @@ -51,7 +53,7 @@ extension MetaLabel { textColor = Asset.Colors.Label.secondary.color case .statusName: - font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 15, weight: .bold)) + font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 15, weight: .semibold)) textColor = Asset.Colors.Label.primary.color case .statusUsername: @@ -80,6 +82,14 @@ extension MetaLabel { font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)) textColor = Asset.Colors.Label.primary.color + case .profileCardName: + font = .systemFont(ofSize: 17, weight: .semibold) + textColor = Asset.Colors.Label.primary.color + + case .profileCardUsername: + font = .systemFont(ofSize: 15, weight: .regular) + textColor = Asset.Colors.Label.secondary.color + case .titleView: font = .systemFont(ofSize: 17, weight: .semibold) textColor = Asset.Colors.Label.primary.color diff --git a/Mastodon/Helper/MastodonMetricFormatter.swift b/MastodonSDK/Sources/MastodonUI/Helper/MastodonMetricFormatter.swift similarity index 95% rename from Mastodon/Helper/MastodonMetricFormatter.swift rename to MastodonSDK/Sources/MastodonUI/Helper/MastodonMetricFormatter.swift index 3c9c4dd75..50fca8cc9 100644 --- a/Mastodon/Helper/MastodonMetricFormatter.swift +++ b/MastodonSDK/Sources/MastodonUI/Helper/MastodonMetricFormatter.swift @@ -7,8 +7,8 @@ import Foundation -final public class MastodonMetricFormatter: Formatter { - +public final class MastodonMetricFormatter: Formatter { + public func string(from number: Int) -> String? { let isPositive = number >= 0 let symbol = isPositive ? "" : "-" diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+Configuration.swift b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+Configuration.swift new file mode 100644 index 000000000..3964099d8 --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+Configuration.swift @@ -0,0 +1,88 @@ +// +// ProfileCardView+Configuration.swift +// +// +// Created by MainasuK on 2022-4-14. +// + +import Foundation +import Combine +import CoreDataStack +import Meta +import MastodonMeta + +extension ProfileCardView { + + public func configure(user: MastodonUser) { + // banner + user.publisher(for: \.header) + .map { URL(string: $0) } + .assign(to: \.authorBannerImageURL, on: viewModel) + .store(in: &disposeBag) + // author avatar + Publishers.CombineLatest3( + user.publisher(for: \.avatar), + user.publisher(for: \.avatarStatic), + UserDefaults.shared.publisher(for: \.preferredStaticAvatar) + ) + .map { _ in user.avatarImageURL() } + .assign(to: \.authorAvatarImageURL, on: viewModel) + .store(in: &disposeBag) + // name + Publishers.CombineLatest( + user.publisher(for: \.displayName), + user.publisher(for: \.emojis) + ) + .map { _, emojis in + do { + let content = MastodonContent(content: user.displayNameWithFallback, emojis: emojis.asDictionary) + let metaContent = try MastodonMetaContent.convert(document: content) + return metaContent + } catch { + assertionFailure(error.localizedDescription) + return PlaintextMetaContent(string: user.displayNameWithFallback) + } + } + .assign(to: \.authorName, on: viewModel) + .store(in: &disposeBag) + // username + user.publisher(for: \.acct) + .map { $0 as String? } + .assign(to: \.authorUsername, on: viewModel) + .store(in: &disposeBag) + // bio + Publishers.CombineLatest( + user.publisher(for: \.note), + user.publisher(for: \.emojis) + ) + .map { note, emojis in + guard let note = note else { return nil } + do { + let content = MastodonContent(content: note, emojis: emojis.asDictionary) + let metaContent = try MastodonMetaContent.convert(document: content) + return metaContent + } catch { + assertionFailure(error.localizedDescription) + return nil + } + } + .assign(to: \.bioContent, on: viewModel) + .store(in: &disposeBag) + // relationship + viewModel.relationshipViewModel.user = user + // dashboard + user.publisher(for: \.statusesCount) + .map { Int($0) } + .assign(to: \.statusesCount, on: viewModel) + .store(in: &disposeBag) + user.publisher(for: \.followingCount) + .map { Int($0) } + .assign(to: \.followingCount, on: viewModel) + .store(in: &disposeBag) + user.publisher(for: \.followersCount) + .map { Int($0) } + .assign(to: \.followersCount, on: viewModel) + .store(in: &disposeBag) + } + +} diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+ViewModel.swift b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+ViewModel.swift new file mode 100644 index 000000000..0e01161dc --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+ViewModel.swift @@ -0,0 +1,148 @@ +// +// ProfileCardView+ViewModel.swift +// +// +// Created by MainasuK on 2022-4-14. +// + +import os.log +import UIKit +import Combine +import Meta +import AlamofireImage +import CoreDataStack +import MastodonLocalization + +extension ProfileCardView { + public class ViewModel: ObservableObject { + let logger = Logger(subsystem: "ProfileCardView", category: "ViewModel") + var disposeBag = Set() + + public let relationshipViewModel = RelationshipViewModel() + + // Author + @Published public var authorBannerImageURL: URL? + @Published public var authorAvatarImageURL: URL? + @Published public var authorName: MetaContent? + @Published public var authorUsername: String? + + @Published public var bioContent: MetaContent? + + @Published public var statusesCount: Int? + @Published public var followingCount: Int? + @Published public var followersCount: Int? + + @Published public var isUpdating = false + @Published public var isFollowedBy = false + @Published public var isMuting = false + @Published public var isBlocking = false + @Published public var isBlockedBy = false + } +} + +extension ProfileCardView.ViewModel { + func bind(view: ProfileCardView) { + bindHeader(view: view) + bindUser(view: view) + bindBio(view: view) + bindRelationship(view: view) + bindDashboard(view: view) + } + + private func bindHeader(view: ProfileCardView) { + $authorBannerImageURL + .sink { url in + guard let url = url else { return } + view.bannerImageView.af.setImage( + withURL: url, + placeholderImage: .placeholder(color: .systemGray3), + imageTransition: .crossDissolve(0.3) + ) + } + .store(in: &disposeBag) + } + + private func bindUser(view: ProfileCardView) { + $authorAvatarImageURL + .sink { url in + view.avatarButton.avatarImageView.configure( + configuration: .init( + url: url, + placeholder: .placeholder(color: .systemGray3) + ) + ) + view.avatarButton.avatarImageView.configure( + cornerConfiguration: .init(corner: .fixed(radius: 12)) + ) + } + .store(in: &disposeBag) + + // name + $authorName + .sink { metaContent in + let metaContent = metaContent ?? PlaintextMetaContent(string: " ") + view.authorNameLabel.configure(content: metaContent) + } + .store(in: &disposeBag) + // username + $authorUsername + .map { text -> String in + guard let text = text else { return "" } + return "@\(text)" + } + .sink { username in + let metaContent = PlaintextMetaContent(string: username) + view.authorUsernameLabel.configure(content: metaContent) + } + .store(in: &disposeBag) + } + + private func bindBio(view: ProfileCardView) { + $bioContent + .sink { metaContent in + let metaContent = metaContent ?? PlaintextMetaContent(string: " ") + view.bioMetaText.configure(content: metaContent) + } + .store(in: &disposeBag) + } + + private func bindRelationship(view: ProfileCardView) { + relationshipViewModel.$optionSet + .receive(on: DispatchQueue.main) + .sink { relationshipActionSet in + let relationshipActionSet = relationshipActionSet ?? .follow + view.relationshipActionButton.configure(actionOptionSet: relationshipActionSet) + } + .store(in: &disposeBag) + } + + private func bindDashboard(view: ProfileCardView) { + $statusesCount + .receive(on: DispatchQueue.main) + .sink { count in + let text = count.flatMap { MastodonMetricFormatter().string(from: $0) } ?? "-" + view.statusDashboardView.postDashboardMeterView.numberLabel.text = text + view.statusDashboardView.postDashboardMeterView.isAccessibilityElement = true + view.statusDashboardView.postDashboardMeterView.accessibilityLabel = L10n.Plural.Count.post(count ?? 0) + } + .store(in: &disposeBag) + $followingCount + .receive(on: DispatchQueue.main) + .sink { count in + let text = count.flatMap { MastodonMetricFormatter().string(from: $0) } ?? "-" + view.statusDashboardView.followingDashboardMeterView.numberLabel.text = text + view.statusDashboardView.followingDashboardMeterView.isAccessibilityElement = true + view.statusDashboardView.followingDashboardMeterView.accessibilityLabel = L10n.Plural.Count.following(count ?? 0) + } + .store(in: &disposeBag) + $followersCount + .receive(on: DispatchQueue.main) + .sink { count in + let text = count.flatMap { MastodonMetricFormatter().string(from: $0) } ?? "-" + view.statusDashboardView.followersDashboardMeterView.numberLabel.text = text + view.statusDashboardView.followersDashboardMeterView.isAccessibilityElement = true + view.statusDashboardView.followersDashboardMeterView.accessibilityLabel = L10n.Plural.Count.follower(count ?? 0) + } + .store(in: &disposeBag) + } +} diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift new file mode 100644 index 000000000..a8e90906e --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift @@ -0,0 +1,235 @@ +// +// ProfileCardView.swift +// +// +// Created by MainasuK on 2022-4-14. +// + +import UIKit +import Combine +import MetaTextKit +import MastodonAsset + +public final class ProfileCardView: UIView { + + static let avatarSize = CGSize(width: 56, height: 56) + static let friendshipActionButtonSize = CGSize(width: 108, height: 34) + static let contentMargin: CGFloat = 16 + + private var _disposeBag = Set() + var disposeBag = Set() + + let container = UIStackView() + + let bannerImageView: UIImageView = { + let imageView = UIImageView() + imageView.contentMode = .scaleAspectFill + imageView.layer.masksToBounds = true + imageView.layer.cornerRadius = 3 + imageView.layer.cornerCurve = .continuous + return imageView + }() + + // avatar + public let avatarButton = AvatarButton() + + // author name + public let authorNameLabel = MetaLabel(style: .profileCardName) + + // author username + public let authorUsernameLabel = MetaLabel(style: .profileCardUsername) + + let bioMetaText: MetaText = { + let metaText = MetaText() + metaText.textView.backgroundColor = .clear + metaText.textView.isEditable = false + metaText.textView.isSelectable = true + metaText.textView.isScrollEnabled = false + //metaText.textView.textContainer.lineFragmentPadding = 0 + //metaText.textView.textContainerInset = .zero + metaText.textView.layer.masksToBounds = false + metaText.textView.textDragInteraction?.isEnabled = false // disable drag for link and attachment + + metaText.textView.layer.masksToBounds = true + metaText.textView.layer.cornerCurve = .continuous + metaText.textView.layer.cornerRadius = 10 + + metaText.paragraphStyle = { + let style = NSMutableParagraphStyle() + style.lineSpacing = 5 + style.paragraphSpacing = 8 + return style + }() + metaText.textAttributes = [ + .font: UIFont.preferredFont(forTextStyle: .body), + .foregroundColor: Asset.Colors.Label.primary.color, + ] + metaText.linkAttributes = [ + .font: UIFont.preferredFont(forTextStyle: .body), + .foregroundColor: Asset.Colors.brandBlue.color, + ] + return metaText + }() + + let statusDashboardView = ProfileStatusDashboardView() + + let relationshipActionButtonShadowContainer = ShadowBackgroundContainer() + let relationshipActionButton: ProfileRelationshipActionButton = { + let button = ProfileRelationshipActionButton() + button.titleLabel?.font = .systemFont(ofSize: 17, weight: .semibold) + button.titleLabel?.adjustsFontSizeToFitWidth = true + button.titleLabel?.minimumScaleFactor = 0.5 + return button + }() + + public private(set) lazy var viewModel: ViewModel = { + let viewModel = ViewModel() + viewModel.bind(view: self) + return viewModel + }() + + public func prepareForReuse() { + disposeBag.removeAll() + bannerImageView.af.cancelImageRequest() + bannerImageView.image = nil + } + + override init(frame: CGRect) { + super.init(frame: frame) + _init() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + _init() + } + +} + +extension ProfileCardView { + private func _init() { + avatarButton.isUserInteractionEnabled = false + authorNameLabel.isUserInteractionEnabled = false + authorUsernameLabel.isUserInteractionEnabled = false + bioMetaText.textView.isUserInteractionEnabled = false + statusDashboardView.isUserInteractionEnabled = false + + // container: V - [ bannerContainer | authorContainer | bioMetaText | infoContainer ] + container.backgroundColor = Asset.Scene.Discovery.profileCardBackground.color + container.axis = .vertical + container.spacing = 8 + container.translatesAutoresizingMaskIntoConstraints = false + addSubview(container) + NSLayoutConstraint.activate([ + container.topAnchor.constraint(equalTo: topAnchor), + container.leadingAnchor.constraint(equalTo: leadingAnchor), + container.trailingAnchor.constraint(equalTo: trailingAnchor), + container.bottomAnchor.constraint(equalTo: bottomAnchor), + ]) + + // bannerContainer + let bannerContainer = UIView() + bannerContainer.translatesAutoresizingMaskIntoConstraints = false + container.addArrangedSubview(bannerContainer) + container.setCustomSpacing(6, after: bannerContainer) + + // bannerImageView + bannerImageView.translatesAutoresizingMaskIntoConstraints = false + bannerContainer.addSubview(bannerImageView) + NSLayoutConstraint.activate([ + bannerImageView.topAnchor.constraint(equalTo: bannerContainer.topAnchor, constant: 4), + bannerImageView.leadingAnchor.constraint(equalTo: bannerContainer.leadingAnchor, constant: 4), + bannerContainer.trailingAnchor.constraint(equalTo: bannerImageView.trailingAnchor, constant: 4), + bannerImageView.bottomAnchor.constraint(equalTo: bannerContainer.bottomAnchor), + bannerImageView.widthAnchor.constraint(equalTo: bannerImageView.heightAnchor, multiplier: 335.0/128.0).priority(.required - 1), + ]) + + // authorContainer: H - [ avatarPlaceholder | authorInfoContainer ] + let authorContainer = UIStackView() + authorContainer.axis = .horizontal + authorContainer.spacing = 16 + let authorContainerAdaptiveMarginContainerView = AdaptiveMarginContainerView() + authorContainerAdaptiveMarginContainerView.contentView = authorContainer + authorContainerAdaptiveMarginContainerView.margin = ProfileCardView.contentMargin + container.addArrangedSubview(authorContainerAdaptiveMarginContainerView) + + // avatarPlaceholder + let avatarPlaceholder = UIView() + avatarPlaceholder.translatesAutoresizingMaskIntoConstraints = false + authorContainer.addArrangedSubview(avatarPlaceholder) + NSLayoutConstraint.activate([ + avatarPlaceholder.widthAnchor.constraint(equalToConstant: ProfileCardView.avatarSize.width).priority(.required - 1), + avatarPlaceholder.heightAnchor.constraint(equalToConstant: ProfileCardView.avatarSize.height - 14).priority(.required - 1), + ]) + + avatarButton.translatesAutoresizingMaskIntoConstraints = false + authorContainer.addSubview(avatarButton) + NSLayoutConstraint.activate([ + avatarButton.leadingAnchor.constraint(equalTo: avatarPlaceholder.leadingAnchor), + avatarButton.trailingAnchor.constraint(equalTo: avatarPlaceholder.trailingAnchor), + avatarButton.bottomAnchor.constraint(equalTo: avatarPlaceholder.bottomAnchor), + avatarButton.heightAnchor.constraint(equalToConstant: ProfileCardView.avatarSize.height).priority(.required - 1), + ]) + + let avatarButtonBackgroundView = UIView() + avatarButtonBackgroundView.backgroundColor = Asset.Scene.Discovery.profileCardBackground.color + avatarButtonBackgroundView.layer.masksToBounds = true + avatarButtonBackgroundView.layer.cornerCurve = .continuous + avatarButtonBackgroundView.layer.cornerRadius = 12 + avatarButtonBackgroundView.translatesAutoresizingMaskIntoConstraints = false + authorContainer.insertSubview(avatarButtonBackgroundView, belowSubview: avatarButton) + NSLayoutConstraint.activate([ + avatarButtonBackgroundView.centerXAnchor.constraint(equalTo: avatarButton.centerXAnchor), + avatarButtonBackgroundView.centerYAnchor.constraint(equalTo: avatarButton.centerYAnchor), + avatarButtonBackgroundView.widthAnchor.constraint(equalToConstant: ProfileCardView.avatarSize.width + 4).priority(.required - 1), + avatarButtonBackgroundView.heightAnchor.constraint(equalToConstant: ProfileCardView.avatarSize.height + 4).priority(.required - 1), + ]) + + // authorInfoContainer: V - [ authorNameLabel | authorUsernameLabel ] + let authorInfoContainer = UIStackView() + authorInfoContainer.axis = .vertical + authorInfoContainer.spacing = 2 + authorContainer.addArrangedSubview(authorInfoContainer) + + authorInfoContainer.addArrangedSubview(authorNameLabel) + authorInfoContainer.addArrangedSubview(authorUsernameLabel) + + // bioMetaText + let bioMetaTextAdaptiveMarginContainerView = AdaptiveMarginContainerView() + bioMetaTextAdaptiveMarginContainerView.contentView = bioMetaText.textView + bioMetaTextAdaptiveMarginContainerView.margin = ProfileCardView.contentMargin + container.addArrangedSubview(bioMetaTextAdaptiveMarginContainerView) + container.setCustomSpacing(16, after: bioMetaTextAdaptiveMarginContainerView) + + // infoContainer: H - [ statusDashboardView | (spacer) | relationshipActionButton ] + let infoContainer = UIStackView() + infoContainer.axis = .horizontal + let infoContainerAdaptiveMarginContainerView = AdaptiveMarginContainerView() + infoContainerAdaptiveMarginContainerView.contentView = infoContainer + infoContainerAdaptiveMarginContainerView.margin = ProfileCardView.contentMargin + container.addArrangedSubview(infoContainerAdaptiveMarginContainerView) + infoContainer.addArrangedSubview(statusDashboardView) + infoContainer.addArrangedSubview(UIView()) + let relationshipActionButtonShadowContainer = ShadowBackgroundContainer() + infoContainer.addArrangedSubview(relationshipActionButtonShadowContainer) + + relationshipActionButton.translatesAutoresizingMaskIntoConstraints = false + relationshipActionButtonShadowContainer.addSubview(relationshipActionButton) + NSLayoutConstraint.activate([ + relationshipActionButton.topAnchor.constraint(equalTo: relationshipActionButtonShadowContainer.topAnchor), + relationshipActionButton.leadingAnchor.constraint(equalTo: relationshipActionButtonShadowContainer.leadingAnchor), + relationshipActionButton.trailingAnchor.constraint(equalTo: relationshipActionButtonShadowContainer.trailingAnchor), + relationshipActionButton.bottomAnchor.constraint(equalTo: relationshipActionButtonShadowContainer.bottomAnchor), + relationshipActionButton.widthAnchor.constraint(greaterThanOrEqualToConstant: ProfileCardView.friendshipActionButtonSize.width).priority(.required - 1), + relationshipActionButton.heightAnchor.constraint(equalToConstant: ProfileCardView.friendshipActionButtonSize.height).priority(.defaultHigh), + ]) + + let bottomPadding = UIView() + bottomPadding.translatesAutoresizingMaskIntoConstraints = false + container.addArrangedSubview(bottomPadding) + NSLayoutConstraint.activate([ + bottomPadding.heightAnchor.constraint(equalToConstant: 16) + ]) + } + +} diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift index b09fdb44e..67cefa475 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift @@ -14,6 +14,7 @@ import MastodonSDK import MastodonAsset import MastodonLocalization import MastodonExtension +import MastodonCommon import CoreDataStack extension StatusView { diff --git a/Mastodon/Scene/Profile/Header/View/ProfileRelationshipActionButton.swift b/MastodonSDK/Sources/MastodonUI/View/Control/ProfileRelationshipActionButton.swift similarity index 80% rename from Mastodon/Scene/Profile/Header/View/ProfileRelationshipActionButton.swift rename to MastodonSDK/Sources/MastodonUI/View/Control/ProfileRelationshipActionButton.swift index 87c189a45..bdf696e74 100644 --- a/Mastodon/Scene/Profile/Header/View/ProfileRelationshipActionButton.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Control/ProfileRelationshipActionButton.swift @@ -6,23 +6,23 @@ // import UIKit -import MastodonUI import MastodonAsset +import MastodonLocalization -final class ProfileRelationshipActionButton: RoundedEdgesButton { +public final class ProfileRelationshipActionButton: RoundedEdgesButton { - let activityIndicatorView: UIActivityIndicatorView = { + public let activityIndicatorView: UIActivityIndicatorView = { let activityIndicatorView = UIActivityIndicatorView(style: .medium) activityIndicatorView.color = Asset.Colors.Label.primaryReverse.color return activityIndicatorView }() - override init(frame: CGRect) { + public override init(frame: CGRect) { super.init(frame: frame) _init() } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) _init() } @@ -47,7 +47,7 @@ extension ProfileRelationshipActionButton { configureAppearance() } - override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) configureAppearance() @@ -55,7 +55,7 @@ extension ProfileRelationshipActionButton { } extension ProfileRelationshipActionButton { - func configure(actionOptionSet: ProfileViewModel.RelationshipActionOptionSet) { + public func configure(actionOptionSet: RelationshipActionOptionSet) { setTitle(actionOptionSet.title, for: .normal) configureAppearance() @@ -87,9 +87,5 @@ extension ProfileRelationshipActionButton { setBackgroundImage(.placeholder(color: Asset.Scene.Profile.RelationshipButton.backgroundHighlightedLight.color), for: .highlighted) setBackgroundImage(.placeholder(color: Asset.Scene.Profile.RelationshipButton.backgroundHighlightedLight.color), for: .disabled) } -// setBackgroundImage(.placeholder(color: actionOptionSet.backgroundColor), for: .normal) -// setBackgroundImage(.placeholder(color: actionOptionSet.backgroundColor.withAlphaComponent(0.5)), for: .highlighted) -// setBackgroundImage(.placeholder(color: actionOptionSet.backgroundColor.withAlphaComponent(0.5)), for: .disabled) } } - diff --git a/Mastodon/Scene/Profile/Header/View/ProfileStatusDashboardMeterView.swift b/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardMeterView.swift similarity index 91% rename from Mastodon/Scene/Profile/Header/View/ProfileStatusDashboardMeterView.swift rename to MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardMeterView.swift index 9176d7a3c..0c9d243c2 100644 --- a/Mastodon/Scene/Profile/Header/View/ProfileStatusDashboardMeterView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardMeterView.swift @@ -9,9 +9,9 @@ import UIKit import MastodonAsset import MastodonLocalization -final class ProfileStatusDashboardMeterView: UIView { +public final class ProfileStatusDashboardMeterView: UIView { - let numberLabel: UILabel = { + public let numberLabel: UILabel = { let label = UILabel() label.font = { let font = UIFont.systemFont(ofSize: 20, weight: .semibold) @@ -25,7 +25,7 @@ final class ProfileStatusDashboardMeterView: UIView { return label }() - let textLabel: UILabel = { + public let textLabel: UILabel = { let label = UILabel() label.font = .systemFont(ofSize: 13, weight: .regular) label.textColor = Asset.Colors.Label.primary.color @@ -41,12 +41,12 @@ final class ProfileStatusDashboardMeterView: UIView { return label }() - override init(frame: CGRect) { + public override init(frame: CGRect) { super.init(frame: frame) _init() } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) _init() } diff --git a/Mastodon/Scene/Profile/Header/View/ProfileStatusDashboardView.swift b/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardView.swift similarity index 85% rename from Mastodon/Scene/Profile/Header/View/ProfileStatusDashboardView.swift rename to MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardView.swift index 9448f1964..7d8e4fbcd 100644 --- a/Mastodon/Scene/Profile/Header/View/ProfileStatusDashboardView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardView.swift @@ -10,24 +10,24 @@ import UIKit import MastodonAsset import MastodonLocalization -protocol ProfileStatusDashboardViewDelegate: AnyObject { +public protocol ProfileStatusDashboardViewDelegate: AnyObject { func profileStatusDashboardView(_ dashboardView: ProfileStatusDashboardView, dashboardMeterViewDidPressed dashboardMeterView: ProfileStatusDashboardMeterView, meter: ProfileStatusDashboardView.Meter) } -final class ProfileStatusDashboardView: UIView { +public final class ProfileStatusDashboardView: UIView { - let postDashboardMeterView = ProfileStatusDashboardMeterView() - let followingDashboardMeterView = ProfileStatusDashboardMeterView() - let followersDashboardMeterView = ProfileStatusDashboardMeterView() + public let postDashboardMeterView = ProfileStatusDashboardMeterView() + public let followingDashboardMeterView = ProfileStatusDashboardMeterView() + public let followersDashboardMeterView = ProfileStatusDashboardMeterView() - weak var delegate: ProfileStatusDashboardViewDelegate? + public weak var delegate: ProfileStatusDashboardViewDelegate? - override init(frame: CGRect) { + public override init(frame: CGRect) { super.init(frame: frame) _init() } - required init?(coder: NSCoder) { + public required init?(coder: NSCoder) { super.init(coder: coder) _init() } @@ -35,7 +35,7 @@ final class ProfileStatusDashboardView: UIView { } extension ProfileStatusDashboardView { - enum Meter: Hashable { + public enum Meter: Hashable { case post case following case follower @@ -83,7 +83,7 @@ extension ProfileStatusDashboardView { extension ProfileStatusDashboardView { @objc private func tapGestureRecognizerHandler(_ sender: UITapGestureRecognizer) { - os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + os_log(.debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) guard let sourceView = sender.view as? ProfileStatusDashboardMeterView else { assertionFailure() return diff --git a/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift new file mode 100644 index 000000000..a793482ad --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift @@ -0,0 +1,68 @@ +// +// ProfileCardTableViewCell.swift +// +// +// Created by MainasuK on 2022-4-14. +// + +import UIKit +import Combine + +public final class ProfileCardTableViewCell: UITableViewCell { + + public var disposeBag = Set() + + public let profileCardView: ProfileCardView = { + let profileCardView = ProfileCardView() + profileCardView.layer.masksToBounds = true + profileCardView.layer.cornerRadius = 6 + profileCardView.layer.cornerCurve = .continuous + return profileCardView + }() + + public override func prepareForReuse() { + super.prepareForReuse() + + disposeBag.removeAll() + profileCardView.prepareForReuse() + } + + public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + _init() + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + _init() + } + +} + +extension ProfileCardTableViewCell { + + private func _init() { + selectionStyle = .none + + let shadowBackgroundContainer = ShadowBackgroundContainer() + shadowBackgroundContainer.cornerRadius = 6 + shadowBackgroundContainer.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(shadowBackgroundContainer) + NSLayoutConstraint.activate([ + shadowBackgroundContainer.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10), + shadowBackgroundContainer.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor), + shadowBackgroundContainer.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor), + contentView.bottomAnchor.constraint(equalTo: shadowBackgroundContainer.bottomAnchor, constant: 10), + ]) + + profileCardView.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(profileCardView) + NSLayoutConstraint.activate([ + profileCardView.topAnchor.constraint(equalTo: shadowBackgroundContainer.topAnchor), + profileCardView.leadingAnchor.constraint(equalTo: shadowBackgroundContainer.leadingAnchor), + profileCardView.trailingAnchor.constraint(equalTo: shadowBackgroundContainer.trailingAnchor), + profileCardView.bottomAnchor.constraint(equalTo: shadowBackgroundContainer.bottomAnchor), + ]) + } + +} diff --git a/MastodonSDK/Sources/MastodonUI/ViewModel/RelationshipViewModel.swift b/MastodonSDK/Sources/MastodonUI/ViewModel/RelationshipViewModel.swift new file mode 100644 index 000000000..cee31c14a --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/ViewModel/RelationshipViewModel.swift @@ -0,0 +1,253 @@ +// +// RelationshipViewModel.swift +// +// +// Created by MainasuK on 2022-4-14. +// + +import UIKit +import Combine +import MastodonAsset +import MastodonLocalization +import CoreDataStack + +public enum RelationshipAction: Int, CaseIterable { + case isMyself + case followingBy + case blockingBy + case none // set hide from UI + case follow + case request + case pending + case following + case muting + case blocked + case blocking + case suspended + case edit + case editing + case updating + + public var option: RelationshipActionOptionSet { + return RelationshipActionOptionSet(rawValue: 1 << rawValue) + } +} + +// construct option set on the enum for safe iterator +public struct RelationshipActionOptionSet: OptionSet { + + public let rawValue: Int + + public init(rawValue: Int) { + self.rawValue = rawValue + } + + public static let isMyself = RelationshipAction.isMyself.option + public static let followingBy = RelationshipAction.followingBy.option + public static let blockingBy = RelationshipAction.blockingBy.option + public static let none = RelationshipAction.none.option + public static let follow = RelationshipAction.follow.option + public static let request = RelationshipAction.request.option + public static let pending = RelationshipAction.pending.option + public static let following = RelationshipAction.following.option + public static let muting = RelationshipAction.muting.option + public static let blocked = RelationshipAction.blocked.option + public static let blocking = RelationshipAction.blocking.option + public static let suspended = RelationshipAction.suspended.option + public static let edit = RelationshipAction.edit.option + public static let editing = RelationshipAction.editing.option + public static let updating = RelationshipAction.updating.option + + public static let editOptions: RelationshipActionOptionSet = [.edit, .editing, .updating] + + public func highPriorityAction(except: RelationshipActionOptionSet) -> RelationshipAction? { + let set = subtracting(except) + for action in RelationshipAction.allCases.reversed() where set.contains(action.option) { + return action + } + + return nil + } + + public var title: String { + guard let highPriorityAction = self.highPriorityAction(except: []) else { + assertionFailure() + return " " + } + switch highPriorityAction { + case .isMyself: return "" + case .followingBy: return " " + case .blockingBy: return " " + case .none: return " " + case .follow: return L10n.Common.Controls.Friendship.follow + case .request: return L10n.Common.Controls.Friendship.request + case .pending: return L10n.Common.Controls.Friendship.pending + case .following: return L10n.Common.Controls.Friendship.following + case .muting: return L10n.Common.Controls.Friendship.muted + case .blocked: return L10n.Common.Controls.Friendship.follow // blocked by user + case .blocking: return L10n.Common.Controls.Friendship.blocked + case .suspended: return L10n.Common.Controls.Friendship.follow + case .edit: return L10n.Common.Controls.Friendship.editInfo + case .editing: return L10n.Common.Controls.Actions.done + case .updating: return " " + } + } + +} + +public final class RelationshipViewModel { + + var disposeBag = Set() + + public var userObserver: AnyCancellable? + public var meObserver: AnyCancellable? + + // input + @Published public var user: MastodonUser? + @Published public var me: MastodonUser? + public let relationshipUpdatePublisher = CurrentValueSubject(Void()) // needs initial event + + // output + @Published public var isMyself = false + @Published public var optionSet: RelationshipActionOptionSet? + + @Published public var isFollowing = false + @Published public var isFollowingBy = false + @Published public var isMuting = false + @Published public var isBlocking = false + @Published public var isBlockingBy = false + + public init() { + Publishers.CombineLatest3( + $user, + $me, + relationshipUpdatePublisher + ) + .sink { [weak self] user, me, _ in + guard let self = self else { return } + self.update(user: user, me: me) + + guard let user = user, let me = me else { + self.userObserver = nil + self.meObserver = nil + return + } + + // do not modify object to prevent infinity loop + self.userObserver = RelationshipViewModel.createObjectChangePublisher(user: user) + .sink { [weak self] _ in + guard let self = self else { return } + self.relationshipUpdatePublisher.send() + } + + self.meObserver = RelationshipViewModel.createObjectChangePublisher(user: me) + .sink { [weak self] _ in + guard let self = self else { return } + self.relationshipUpdatePublisher.send() + } + } + .store(in: &disposeBag) + } + +} + +extension RelationshipViewModel { + + public static func createObjectChangePublisher(user: MastodonUser) -> AnyPublisher { + return ManagedObjectObserver + .observe(object: user) + .map { _ in Void() } + .catch { error in + return Just(Void()) + } + .eraseToAnyPublisher() + } + +} + +extension RelationshipViewModel { + private func update(user: MastodonUser?, me: MastodonUser?) { + guard let user = user, + let me = me + else { + reset() + return + } + + let optionSet = RelationshipViewModel.optionSet(user: user, me: me) + + self.isMyself = optionSet.contains(.isMyself) + self.isFollowingBy = optionSet.contains(.followingBy) + self.isFollowing = optionSet.contains(.following) + self.isMuting = optionSet.contains(.muting) + self.isBlockingBy = optionSet.contains(.blockingBy) + self.isBlocking = optionSet.contains(.blocking) + + + self.optionSet = optionSet + } + + private func reset() { + isMyself = false + isFollowingBy = false + isFollowing = false + isMuting = false + isBlockingBy = false + isBlocking = false + optionSet = nil + } +} + +extension RelationshipViewModel { + + public static func optionSet(user: MastodonUser, me: MastodonUser) -> RelationshipActionOptionSet { + let isMyself = user.id == me.id && user.domain == me.domain + guard !isMyself else { + return [.isMyself] + } + + let isProtected = user.locked + let isFollowingBy = me.followingBy.contains(user) + let isFollowing = user.followingBy.contains(me) + let isPending = user.followRequestedBy.contains(me) + let isMuting = user.mutingBy.contains(me) + let isBlockingBy = me.blockingBy.contains(user) + let isBlocking = user.blockingBy.contains(me) + + var optionSet: RelationshipActionOptionSet = [.follow] + + if isMyself { + optionSet.insert(.isMyself) + } + + if isProtected { + optionSet.insert(.request) + } + + if isFollowingBy { + optionSet.insert(.followingBy) + } + + if isFollowing { + optionSet.insert(.following) + } + + if isPending { + optionSet.insert(.pending) + } + + if isMuting { + optionSet.insert(.muting) + } + + if isBlockingBy { + optionSet.insert(.blockingBy) + } + + if isBlocking { + optionSet.insert(.blocking) + } + + return optionSet + } +} From f5aaf2737f3c85814c24c1c9eceb17ce75cf0dc8 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 15 Apr 2022 17:17:39 +0800 Subject: [PATCH 012/101] feat: add discovery endpoint check logic and handle relationship action --- .../Discovery/DiscoverySection.swift | 9 +- .../Provider/DataSourceFacade+Profile.swift | 18 ++-- .../Discovery/DiscoveryViewController.swift | 79 ++++++++++----- .../Scene/Discovery/DiscoveryViewModel.swift | 96 +++++++++++++++---- .../DiscoveryForYouViewController.swift | 21 +++- .../DiscoveryForYouViewModel+Diffable.swift | 8 +- .../News/DiscoveryNewsViewModel+State.swift | 8 +- .../News/DiscoveryNewsViewModel.swift | 25 ++++- .../Posts/DiscoveryPostsViewModel+State.swift | 9 +- .../Posts/DiscoveryPostsViewModel.swift | 22 +++++ .../Content/ProfileCardView+ViewModel.swift | 40 ++++++++ .../View/Content/ProfileCardView.swift | 26 ++++- .../ProfileCardTableViewCell.swift | 14 +++ 13 files changed, 313 insertions(+), 62 deletions(-) diff --git a/Mastodon/Diffiable/Discovery/DiscoverySection.swift b/Mastodon/Diffiable/Discovery/DiscoverySection.swift index f0c358a17..76cc9c030 100644 --- a/Mastodon/Diffiable/Discovery/DiscoverySection.swift +++ b/Mastodon/Diffiable/Discovery/DiscoverySection.swift @@ -20,7 +20,13 @@ extension DiscoverySection { static let logger = Logger(subsystem: "DiscoverySection", category: "logic") - struct Configuration { } + class Configuration { + weak var profileCardTableViewCellDelegate: ProfileCardTableViewCellDelegate? + + public init(profileCardTableViewCellDelegate: ProfileCardTableViewCellDelegate? = nil) { + self.profileCardTableViewCellDelegate = profileCardTableViewCellDelegate + } + } static func diffableDataSource( tableView: UITableView, @@ -52,6 +58,7 @@ extension DiscoverySection { .map { $0?.user } .assign(to: \.me, on: cell.profileCardView.viewModel.relationshipViewModel) .store(in: &cell.disposeBag) + cell.delegate = configuration.profileCardTableViewCellDelegate return cell case .bottomLoader: let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self), for: indexPath) as! TimelineBottomLoaderTableViewCell diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Profile.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Profile.swift index 36eaab621..66259a099 100644 --- a/Mastodon/Protocol/Provider/DataSourceFacade+Profile.swift +++ b/Mastodon/Protocol/Provider/DataSourceFacade+Profile.swift @@ -122,12 +122,12 @@ extension DataSourceFacade { let barButtonItem: UIBarButtonItem? } - @MainActor - static func createProfileActionMenu( - dependency: NeedsDependency, - user: ManagedObjectRecord - ) -> UIMenu { - var children: [UIMenuElement] = [] +// @MainActor +// static func createProfileActionMenu( +// dependency: NeedsDependency, +// user: ManagedObjectRecord +// ) -> UIMenu { +// var children: [UIMenuElement] = [] // let name = mastodonUser.displayNameWithFallback // // if let shareUser = shareUser { @@ -339,9 +339,9 @@ extension DataSourceFacade { // } // children.append(deleteAction) // } - - return UIMenu(title: "", options: [], children: children) - } +// +// return UIMenu(title: "", options: [], children: children) +// } static func createActivityViewController( dependency: NeedsDependency, diff --git a/Mastodon/Scene/Discovery/DiscoveryViewController.swift b/Mastodon/Scene/Discovery/DiscoveryViewController.swift index dac2c99c3..8e3aab647 100644 --- a/Mastodon/Scene/Discovery/DiscoveryViewController.swift +++ b/Mastodon/Scene/Discovery/DiscoveryViewController.swift @@ -29,13 +29,54 @@ public class DiscoveryViewController: TabmanViewController, NeedsDependency { coordinator: coordinator ) - let buttonBar: TMBar.ButtonBar = { + private(set) lazy var buttonBar: TMBar.ButtonBar = { let buttonBar = TMBar.ButtonBar() - buttonBar.indicator.backgroundColor = Asset.Colors.Label.primary.color + buttonBar.backgroundView.style = .custom(view: buttonBarBackgroundView) + buttonBar.layout.interButtonSpacing = 0 buttonBar.layout.contentInset = .zero + buttonBar.indicator.backgroundColor = Asset.Colors.Label.primary.color + buttonBar.indicator.weight = .custom(value: 2) return buttonBar }() + let buttonBarBackgroundView: UIView = { + let view = UIView() + let barBottomLine = UIView.separatorLine + barBottomLine.backgroundColor = Asset.Colors.Label.secondary.color.withAlphaComponent(0.5) + barBottomLine.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(barBottomLine) + NSLayoutConstraint.activate([ + barBottomLine.leadingAnchor.constraint(equalTo: view.leadingAnchor), + barBottomLine.trailingAnchor.constraint(equalTo: view.trailingAnchor), + barBottomLine.bottomAnchor.constraint(equalTo: view.bottomAnchor), + barBottomLine.heightAnchor.constraint(equalToConstant: 2).priority(.required - 1), + ]) + return view + }() + + func customizeButtonBarAppearance() { + // The implmention use CATextlayer. Adapt for Dark Mode without dynamic colors + // Needs trigger update when `userInterfaceStyle` chagnes + let userInterfaceStyle = traitCollection.userInterfaceStyle + buttonBar.buttons.customize { button in + switch userInterfaceStyle { + case .dark: + // Asset.Colors.Label.primary.color + button.selectedTintColor = UIColor(red: 238.0/255.0, green: 238.0/255.0, blue: 238.0/255.0, alpha: 1.0) + // Asset.Colors.Label.secondary.color + button.tintColor = UIColor(red: 151.0/255.0, green: 157.0/255.0, blue: 173.0/255.0, alpha: 1.0) + default: + // Asset.Colors.Label.primary.color + button.selectedTintColor = UIColor(red: 40.0/255.0, green: 44.0/255.0, blue: 55.0/255.0, alpha: 1.0) + // Asset.Colors.Label.secondary.color + button.tintColor = UIColor(red: 60.0/255.0, green: 60.0/255.0, blue: 67.0/255.0, alpha: 0.6) + } + + button.backgroundColor = .clear + button.contentInset = UIEdgeInsets(top: 12, left: 26, bottom: 12, right: 26) + } + } + } extension DiscoveryViewController { @@ -58,13 +99,21 @@ extension DiscoveryViewController { dataSource: viewModel, at: .top ) - updateBarButtonInsets() + customizeButtonBarAppearance() + + viewModel.$viewControllers + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in + guard let self = self else { return } + self.reloadData() + } + .store(in: &disposeBag) } public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { super.traitCollectionDidChange(previousTraitCollection) - - updateBarButtonInsets() + + customizeButtonBarAppearance() } } @@ -72,24 +121,8 @@ extension DiscoveryViewController { extension DiscoveryViewController { private func setupAppearance(theme: Theme) { - view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor - buttonBar.backgroundView.style = .flat(color: theme.systemBackgroundColor) - } - - private func updateBarButtonInsets() { - let margin: CGFloat = { - switch traitCollection.userInterfaceIdiom { - case .phone: - return DiscoveryViewController.containerViewMarginForCompactHorizontalSizeClass - default: - return traitCollection.horizontalSizeClass == .regular ? - DiscoveryViewController.containerViewMarginForRegularHorizontalSizeClass : - DiscoveryViewController.containerViewMarginForCompactHorizontalSizeClass - } - }() - - buttonBar.layout.contentInset.left = margin - buttonBar.layout.contentInset.right = margin + view.backgroundColor = theme.secondarySystemBackgroundColor + buttonBarBackgroundView.backgroundColor = theme.systemBackgroundColor } } diff --git a/Mastodon/Scene/Discovery/DiscoveryViewModel.swift b/Mastodon/Scene/Discovery/DiscoveryViewModel.swift index 187d73111..ae31797e5 100644 --- a/Mastodon/Scene/Discovery/DiscoveryViewModel.swift +++ b/Mastodon/Scene/Discovery/DiscoveryViewModel.swift @@ -6,11 +6,14 @@ // import UIKit +import Combine import Tabman import Pageboy final class DiscoveryViewModel { + var disposeBag = Set() + // input let context: AppContext let discoveryPostsViewController: DiscoveryPostsViewController @@ -18,25 +21,7 @@ final class DiscoveryViewModel { let discoveryNewsViewController: DiscoveryNewsViewController let discoveryForYouViewController: DiscoveryForYouViewController - // output - let barItems: [TMBarItemable] = { - let items = [ - TMBarItem(title: "Posts"), - TMBarItem(title: "Hashtags"), - TMBarItem(title: "News"), - TMBarItem(title: "For You"), - ] - return items - }() - - var viewControllers: [ScrollViewContainer] { - return [ - discoveryPostsViewController, - discoveryHashtagsViewController, - discoveryNewsViewController, - discoveryForYouViewController, - ] - } + @Published var viewControllers: [ScrollViewContainer & PageViewController] init(context: AppContext, coordinator: SceneCoordinator) { func setupDependency(_ needsDependency: NeedsDependency) { @@ -69,7 +54,35 @@ final class DiscoveryViewModel { viewController.viewModel = DiscoveryForYouViewModel(context: context) return viewController }() + self.viewControllers = [ + discoveryPostsViewController, + discoveryHashtagsViewController, + discoveryNewsViewController, + discoveryForYouViewController, + ] // end init + + discoveryPostsViewController.viewModel.$isServerSupportEndpoint + .receive(on: DispatchQueue.main) + .sink { [weak self] isServerSupportEndpoint in + guard let self = self else { return } + if !isServerSupportEndpoint { + self.viewControllers.removeAll(where: { + $0 === self.discoveryPostsViewController || $0 === self.discoveryPostsViewController + }) + } + } + .store(in: &disposeBag) + + discoveryNewsViewController.viewModel.$isServerSupportEndpoint + .receive(on: DispatchQueue.main) + .sink { [weak self] isServerSupportEndpoint in + guard let self = self else { return } + if !isServerSupportEndpoint { + self.viewControllers.removeAll(where: { $0 === self.discoveryNewsViewController }) + } + } + .store(in: &disposeBag) } } @@ -95,6 +108,49 @@ extension DiscoveryViewModel: PageboyViewControllerDataSource { // MARK: - TMBarDataSource extension DiscoveryViewModel: TMBarDataSource { func barItem(for bar: TMBar, at index: Int) -> TMBarItemable { - return barItems[index] + guard !viewControllers.isEmpty, index < viewControllers.count else { + assertionFailure() + return TMBarItem(title: "") + } + return viewControllers[index].tabItem + } +} + +protocol PageViewController: UIViewController { + var tabItemTitle: String { get } + var tabItem: TMBarItemable { get } +} + +// MARK: - PageViewController +extension DiscoveryPostsViewController: PageViewController { + var tabItemTitle: String { "Posts" } + var tabItem: TMBarItemable { + return TMBarItem(title: tabItemTitle) + } +} + + +// MARK: - PageViewController +extension DiscoveryHashtagsViewController: PageViewController { + var tabItemTitle: String { "Hashtags" } + var tabItem: TMBarItemable { + + return TMBarItem(title: tabItemTitle) + } +} + +// MARK: - PageViewController +extension DiscoveryNewsViewController: PageViewController { + var tabItemTitle: String { "News" } + var tabItem: TMBarItemable { + return TMBarItem(title: tabItemTitle) + } +} + +// MARK: - PageViewController +extension DiscoveryForYouViewController: PageViewController { + var tabItemTitle: String { "For You" } + var tabItem: TMBarItemable { + return TMBarItem(title: tabItemTitle) } } diff --git a/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift index 4654769d1..b8b8f25a7 100644 --- a/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift +++ b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewController.swift @@ -64,7 +64,8 @@ extension DiscoveryForYouViewController { tableView.delegate = self viewModel.setupDiffableDataSource( - tableView: tableView + tableView: tableView, + profileCardTableViewCellDelegate: self ) tableView.refreshControl = refreshControl @@ -119,9 +120,27 @@ extension DiscoveryForYouViewController: UITableViewDelegate { } +// MARK: - ProfileCardTableViewCellDelegate +extension DiscoveryForYouViewController: ProfileCardTableViewCellDelegate { + func profileCardTableViewCell(_ cell: ProfileCardTableViewCell, profileCardView: ProfileCardView, relationshipButtonDidPressed button: ProfileRelationshipActionButton) { + guard let authenticationBox = viewModel.context.authenticationService.activeMastodonAuthenticationBox.value else { return } + guard let indexPath = tableView.indexPath(for: cell) else { return } + guard case let .user(record) = viewModel.diffableDataSource?.itemIdentifier(for: indexPath) else { return } + + Task { + try await DataSourceFacade.responseToUserFollowAction( + dependency: self, + user: record, + authenticationBox: authenticationBox + ) + } // end Task + } +} + // MARK: ScrollViewContainer extension DiscoveryForYouViewController: ScrollViewContainer { var scrollView: UIScrollView? { tableView } } + diff --git a/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel+Diffable.swift b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel+Diffable.swift index 23114073f..fe53cf221 100644 --- a/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel+Diffable.swift +++ b/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel+Diffable.swift @@ -7,16 +7,20 @@ import UIKit import Combine +import MastodonUI extension DiscoveryForYouViewModel { func setupDiffableDataSource( - tableView: UITableView + tableView: UITableView, + profileCardTableViewCellDelegate: ProfileCardTableViewCellDelegate ) { diffableDataSource = DiscoverySection.diffableDataSource( tableView: tableView, context: context, - configuration: DiscoverySection.Configuration() + configuration: DiscoverySection.Configuration( + profileCardTableViewCellDelegate: profileCardTableViewCellDelegate + ) ) Task { diff --git a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift index 37d93e5b4..8da975de2 100644 --- a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift +++ b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift @@ -183,7 +183,13 @@ extension DiscoveryNewsViewModel.State { viewModel.didLoadLatest.send() } catch { logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): fetch news fail: \(error.localizedDescription)") - await enter(state: Fail.self) + if let error = error as? Mastodon.API.Error, error.httpResponseStatus.code == 404 { + viewModel.isServerSupportEndpoint = false + await enter(state: NoMore.self) + } else { + await enter(state: Fail.self) + } + viewModel.didLoadLatest.send() } } // end Task diff --git a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel.swift b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel.swift index b87e7c050..2c4d89dc8 100644 --- a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel.swift +++ b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel.swift @@ -38,10 +38,15 @@ final class DiscoveryNewsViewModel { }() let didLoadLatest = PassthroughSubject() - + @Published var isServerSupportEndpoint = true + init(context: AppContext) { self.context = context // end init + + Task { + await checkServerEndpoint() + } // end Task } deinit { @@ -49,3 +54,21 @@ final class DiscoveryNewsViewModel { } } + + +extension DiscoveryNewsViewModel { + func checkServerEndpoint() async { + guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return } + + do { + _ = try await context.apiService.trendLinks( + domain: authenticationBox.domain, + query: .init(offset: nil, limit: nil) + ) + } catch let error as Mastodon.API.Error where error.httpResponseStatus.code == 404 { + isServerSupportEndpoint = false + } catch { + // do nothing + } + } +} diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift index a8e2e7c20..d91c5adc2 100644 --- a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift @@ -180,9 +180,16 @@ extension DiscoveryPostsViewModel.State { } viewModel.statusFetchedResultsController.statusIDs.value = statusIDs viewModel.didLoadLatest.send() +// } catch let error as? } catch { logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): fetch posts fail: \(error.localizedDescription)") - await enter(state: Fail.self) + if let error = error as? Mastodon.API.Error, error.httpResponseStatus.code == 404 { + viewModel.isServerSupportEndpoint = false + await enter(state: NoMore.self) + } else { + await enter(state: Fail.self) + } + viewModel.didLoadLatest.send() } } // end Task diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift index 590ccc161..c001bb7b3 100644 --- a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel.swift @@ -38,6 +38,7 @@ final class DiscoveryPostsViewModel { }() let didLoadLatest = PassthroughSubject() + @Published var isServerSupportEndpoint = true init(context: AppContext) { self.context = context @@ -52,6 +53,10 @@ final class DiscoveryPostsViewModel { .map { $0?.domain } .assign(to: \.value, on: statusFetchedResultsController.domain) .store(in: &disposeBag) + + Task { + await checkServerEndpoint() + } // end Task } deinit { @@ -59,3 +64,20 @@ final class DiscoveryPostsViewModel { } } + +extension DiscoveryPostsViewModel { + func checkServerEndpoint() async { + guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return } + + do { + _ = try await context.apiService.trendStatuses( + domain: authenticationBox.domain, + query: .init(offset: nil, limit: nil) + ) + } catch let error as Mastodon.API.Error where error.httpResponseStatus.code == 404 { + isServerSupportEndpoint = false + } catch { + // do nothing + } + } +} diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+ViewModel.swift b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+ViewModel.swift index 0e01161dc..99eb27a52 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+ViewModel.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+ViewModel.swift @@ -12,6 +12,7 @@ import Meta import AlamofireImage import CoreDataStack import MastodonLocalization +import MastodonAsset extension ProfileCardView { public class ViewModel: ObservableObject { @@ -19,6 +20,9 @@ extension ProfileCardView { var disposeBag = Set() public let relationshipViewModel = RelationshipViewModel() + + @Published public var userInterfaceStyle: UIUserInterfaceStyle? + @Published public var backgroundColor: UIColor? // Author @Published public var authorBannerImageURL: URL? @@ -37,11 +41,35 @@ extension ProfileCardView { @Published public var isMuting = false @Published public var isBlocking = false @Published public var isBlockedBy = false + + init() { + backgroundColor = ThemeService.shared.currentTheme.value.systemBackgroundColor + Publishers.CombineLatest( + ThemeService.shared.currentTheme, + $userInterfaceStyle + ) + .sink { [weak self] theme, userInterfaceStyle in + guard let self = self else { return } + guard let userInterfaceStyle = userInterfaceStyle else { return } + switch userInterfaceStyle { + case .dark: + self.backgroundColor = theme.systemBackgroundColor + case .light, .unspecified: + self.backgroundColor = Asset.Scene.Discovery.profileCardBackground.color + @unknown default: + self.backgroundColor = Asset.Scene.Discovery.profileCardBackground.color + assertionFailure() + // do nothing + } + } + .store(in: &disposeBag) + } } } extension ProfileCardView.ViewModel { func bind(view: ProfileCardView) { + bindAppearacne(view: view) bindHeader(view: view) bindUser(view: view) bindBio(view: view) @@ -49,6 +77,18 @@ extension ProfileCardView.ViewModel { bindDashboard(view: view) } + private func bindAppearacne(view: ProfileCardView) { + userInterfaceStyle = view.traitCollection.userInterfaceStyle + + $backgroundColor + .assign(to: \.backgroundColor, on: view.container) + .store(in: &disposeBag) + $backgroundColor + .assign(to: \.backgroundColor, on: view.avatarButtonBackgroundView) + .store(in: &disposeBag) + } + + private func bindHeader(view: ProfileCardView) { $authorBannerImageURL .sink { url in diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift index a8e90906e..eb500b7c4 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift @@ -5,17 +5,23 @@ // Created by MainasuK on 2022-4-14. // +import os.log import UIKit import Combine import MetaTextKit import MastodonAsset +public protocol ProfileCardViewDelegate: AnyObject { + func profileCardView(_ profileCardView: ProfileCardView, relationshipButtonDidPressed button: ProfileRelationshipActionButton) +} + public final class ProfileCardView: UIView { static let avatarSize = CGSize(width: 56, height: 56) static let friendshipActionButtonSize = CGSize(width: 108, height: 34) static let contentMargin: CGFloat = 16 + weak var delegate: ProfileCardViewDelegate? private var _disposeBag = Set() var disposeBag = Set() @@ -31,6 +37,7 @@ public final class ProfileCardView: UIView { }() // avatar + public let avatarButtonBackgroundView = UIView() public let avatarButton = AvatarButton() // author name @@ -115,7 +122,6 @@ extension ProfileCardView { statusDashboardView.isUserInteractionEnabled = false // container: V - [ bannerContainer | authorContainer | bioMetaText | infoContainer ] - container.backgroundColor = Asset.Scene.Discovery.profileCardBackground.color container.axis = .vertical container.spacing = 8 container.translatesAutoresizingMaskIntoConstraints = false @@ -171,8 +177,6 @@ extension ProfileCardView { avatarButton.heightAnchor.constraint(equalToConstant: ProfileCardView.avatarSize.height).priority(.required - 1), ]) - let avatarButtonBackgroundView = UIView() - avatarButtonBackgroundView.backgroundColor = Asset.Scene.Discovery.profileCardBackground.color avatarButtonBackgroundView.layer.masksToBounds = true avatarButtonBackgroundView.layer.cornerCurve = .continuous avatarButtonBackgroundView.layer.cornerRadius = 12 @@ -230,6 +234,22 @@ extension ProfileCardView { NSLayoutConstraint.activate([ bottomPadding.heightAnchor.constraint(equalToConstant: 16) ]) + + relationshipActionButton.addTarget(self, action: #selector(ProfileCardView.relationshipActionButtonDidPressed(_:)), for: .touchUpInside) + } + + public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + + viewModel.userInterfaceStyle = traitCollection.userInterfaceStyle } } + +extension ProfileCardView { + @objc private func relationshipActionButtonDidPressed(_ sender: UIButton) { + os_log(.debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + assert(sender === relationshipActionButton) + delegate?.profileCardView(self, relationshipButtonDidPressed: relationshipActionButton) + } +} diff --git a/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift index a793482ad..d3c8f223c 100644 --- a/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift +++ b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift @@ -8,8 +8,13 @@ import UIKit import Combine +public protocol ProfileCardTableViewCellDelegate: AnyObject { + func profileCardTableViewCell(_ cell: ProfileCardTableViewCell, profileCardView: ProfileCardView, relationshipButtonDidPressed button: ProfileRelationshipActionButton) +} + public final class ProfileCardTableViewCell: UITableViewCell { + public weak var delegate: ProfileCardTableViewCellDelegate? public var disposeBag = Set() public let profileCardView: ProfileCardView = { @@ -63,6 +68,15 @@ extension ProfileCardTableViewCell { profileCardView.trailingAnchor.constraint(equalTo: shadowBackgroundContainer.trailingAnchor), profileCardView.bottomAnchor.constraint(equalTo: shadowBackgroundContainer.bottomAnchor), ]) + + profileCardView.delegate = self } } + +// MARK: - ProfileCardViewDelegate +extension ProfileCardTableViewCell: ProfileCardViewDelegate { + public func profileCardView(_ profileCardView: ProfileCardView, relationshipButtonDidPressed button: ProfileRelationshipActionButton) { + delegate?.profileCardTableViewCell(self, profileCardView: profileCardView, relationshipButtonDidPressed: button) + } +} From 8a33ed9f9fca2ffc6e4ffcf5b140932f5a4d9b36 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 15 Apr 2022 17:20:41 +0800 Subject: [PATCH 013/101] fix: search bar active with re-layout animation on iPad device issue --- Mastodon/Coordinator/SceneCoordinator.swift | 6 +- .../Search/Search/SearchViewController.swift | 110 ++++++++++-------- .../Search/SearchViewModel+Diffable.swift | 64 +++++----- .../Scene/Search/Search/SearchViewModel.swift | 50 ++++---- .../SearchDetailViewController.swift | 26 ++++- ...lViewControllerAnimatedTransitioning.swift | 7 +- 6 files changed, 144 insertions(+), 119 deletions(-) diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index c8ce4acbd..1f8030014 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -144,7 +144,7 @@ extension SceneCoordinator { case popover(sourceView: UIView) case panModal case custom(transitioningDelegate: UIViewControllerTransitioningDelegate) - case customPush + case customPush(animated: Bool) case safariPresent(animated: Bool, completion: (() -> Void)? = nil) case alertController(animated: Bool, completion: (() -> Void)? = nil) case activityViewControllerPresent(animated: Bool, completion: (() -> Void)? = nil) @@ -339,10 +339,10 @@ extension SceneCoordinator { viewController.transitioningDelegate = transitioningDelegate (splitViewController ?? presentingViewController)?.present(viewController, animated: true, completion: nil) - case .customPush: + case .customPush(let animated): // set delegate in view controller assert(sender?.navigationController?.delegate != nil) - sender?.navigationController?.pushViewController(viewController, animated: true) + sender?.navigationController?.pushViewController(viewController, animated: animated) case .safariPresent(let animated, let completion): if UserDefaults.shared.preferredUsingDefaultBrowser, case let .safari(url) = scene { diff --git a/Mastodon/Scene/Search/Search/SearchViewController.swift b/Mastodon/Scene/Search/Search/SearchViewController.swift index 6f4d22009..7594eb478 100644 --- a/Mastodon/Scene/Search/Search/SearchViewController.swift +++ b/Mastodon/Scene/Search/Search/SearchViewController.swift @@ -15,7 +15,7 @@ import MastodonLocalization final class HeightFixedSearchBar: UISearchBar { override var intrinsicContentSize: CGSize { - return CGSize(width: CGFloat.greatestFiniteMagnitude, height: 44) + return CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude) } } @@ -35,20 +35,20 @@ final class SearchViewController: UIViewController, NeedsDependency { // layout alongside with split mode button (on iPad) let titleViewContainer = UIView() let searchBar = HeightFixedSearchBar() - - let collectionView: UICollectionView = { - var configuration = UICollectionLayoutListConfiguration(appearance: .insetGrouped) - configuration.backgroundColor = .clear - configuration.headerMode = .supplementary - let layout = UICollectionViewCompositionalLayout.list(using: configuration) - let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) - collectionView.backgroundColor = .clear - return collectionView - }() + +// let collectionView: UICollectionView = { +// var configuration = UICollectionLayoutListConfiguration(appearance: .insetGrouped) +// configuration.backgroundColor = .clear +// configuration.headerMode = .supplementary +// let layout = UICollectionViewCompositionalLayout.list(using: configuration) +// let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) +// collectionView.backgroundColor = .clear +// return collectionView +// }() let searchBarTapPublisher = PassthroughSubject() - private(set) lazy var trendViewController: DiscoveryViewController = { + private(set) lazy var discoveryViewController: DiscoveryViewController = { let viewController = DiscoveryViewController() viewController.context = context viewController.coordinator = coordinator @@ -78,29 +78,31 @@ extension SearchViewController { setupSearchBar() - collectionView.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(collectionView) +// collectionView.translatesAutoresizingMaskIntoConstraints = false +// view.addSubview(collectionView) +// NSLayoutConstraint.activate([ +// collectionView.topAnchor.constraint(equalTo: view.topAnchor), +// collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor), +// collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor), +// collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor), +// ]) +// +// collectionView.delegate = self +// viewModel.setupDiffableDataSource( +// collectionView: collectionView +// ) + + addChild(discoveryViewController) + discoveryViewController.view.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(discoveryViewController.view) NSLayoutConstraint.activate([ - collectionView.topAnchor.constraint(equalTo: view.topAnchor), - collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor), - collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor), - collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + discoveryViewController.view.topAnchor.constraint(equalTo: view.topAnchor), + discoveryViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), + discoveryViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), + discoveryViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor), ]) - collectionView.delegate = self - viewModel.setupDiffableDataSource( - collectionView: collectionView - ) - - addChild(trendViewController) - trendViewController.view.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(trendViewController.view) - NSLayoutConstraint.activate([ - trendViewController.view.topAnchor.constraint(equalTo: view.topAnchor), - trendViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), - trendViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), - trendViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor), - ]) +// discoveryViewController.view.isHidden = true } override func viewDidAppear(_ animated: Bool) { @@ -130,7 +132,10 @@ extension SearchViewController { searchBar.trailingAnchor.constraint(equalTo: titleViewContainer.trailingAnchor), searchBar.bottomAnchor.constraint(equalTo: titleViewContainer.bottomAnchor), ]) + searchBar.setContentHuggingPriority(.required, for: .horizontal) + searchBar.setContentHuggingPriority(.required, for: .vertical) navigationItem.titleView = titleViewContainer +// navigationItem.titleView = searchBar searchBarTapPublisher .throttle(for: 0.5, scheduler: DispatchQueue.main, latest: false) @@ -140,7 +145,10 @@ extension SearchViewController { let searchDetailViewModel = SearchDetailViewModel() searchDetailViewModel.needsBecomeFirstResponder = true self.navigationController?.delegate = self.searchTransitionController - self.coordinator.present(scene: .searchDetail(viewModel: searchDetailViewModel), from: self, transition: .customPush) + // FIXME: + // use `.customPush(animated: false)` false to disable navigation bar animation for searchBar layout + // but that should be a fade transition whe fixed size searchBar + self.coordinator.present(scene: .searchDetail(viewModel: searchDetailViewModel), from: self, transition: .customPush(animated: false)) } .store(in: &disposeBag) } @@ -168,21 +176,21 @@ extension SearchViewController: UISearchControllerDelegate { } // MARK: - UICollectionViewDelegate -extension SearchViewController: UICollectionViewDelegate { - func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): select item at: \(indexPath.debugDescription)") - - defer { - collectionView.deselectItem(at: indexPath, animated: true) - } - - guard let diffableDataSource = viewModel.diffableDataSource else { return } - guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return } - - switch item { - case .trend(let hashtag): - let viewModel = HashtagTimelineViewModel(context: context, hashtag: hashtag.name) - coordinator.present(scene: .hashtagTimeline(viewModel: viewModel), from: self, transition: .show) - } - } -} +//extension SearchViewController: UICollectionViewDelegate { +// func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { +// logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): select item at: \(indexPath.debugDescription)") +// +// defer { +// collectionView.deselectItem(at: indexPath, animated: true) +// } +// +// guard let diffableDataSource = viewModel.diffableDataSource else { return } +// guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return } +// +// switch item { +// case .trend(let hashtag): +// let viewModel = HashtagTimelineViewModel(context: context, hashtag: hashtag.name) +// coordinator.present(scene: .hashtagTimeline(viewModel: viewModel), from: self, transition: .show) +// } +// } +//} diff --git a/Mastodon/Scene/Search/Search/SearchViewModel+Diffable.swift b/Mastodon/Scene/Search/Search/SearchViewModel+Diffable.swift index ca741b7f3..3f448289a 100644 --- a/Mastodon/Scene/Search/Search/SearchViewModel+Diffable.swift +++ b/Mastodon/Scene/Search/Search/SearchViewModel+Diffable.swift @@ -8,35 +8,35 @@ import UIKit import MastodonSDK -extension SearchViewModel { - - func setupDiffableDataSource( - collectionView: UICollectionView - ) { - diffableDataSource = SearchSection.diffableDataSource( - collectionView: collectionView, - context: context - ) - - var snapshot = NSDiffableDataSourceSnapshot() - snapshot.appendSections([.trend]) - diffableDataSource?.apply(snapshot) - - $hashtags - .receive(on: DispatchQueue.main) - .sink { [weak self] hashtags in - guard let self = self else { return } - guard let diffableDataSource = self.diffableDataSource else { return } - - var snapshot = NSDiffableDataSourceSnapshot() - snapshot.appendSections([.trend]) - - let trendItems = hashtags.map { SearchItem.trend($0) } - snapshot.appendItems(trendItems, toSection: .trend) - - diffableDataSource.apply(snapshot) - } - .store(in: &disposeBag) - } - -} +//extension SearchViewModel { +// +// func setupDiffableDataSource( +// collectionView: UICollectionView +// ) { +// diffableDataSource = SearchSection.diffableDataSource( +// collectionView: collectionView, +// context: context +// ) +// +// var snapshot = NSDiffableDataSourceSnapshot() +// snapshot.appendSections([.trend]) +// diffableDataSource?.apply(snapshot) +// +// $hashtags +// .receive(on: DispatchQueue.main) +// .sink { [weak self] hashtags in +// guard let self = self else { return } +// guard let diffableDataSource = self.diffableDataSource else { return } +// +// var snapshot = NSDiffableDataSourceSnapshot() +// snapshot.appendSections([.trend]) +// +// let trendItems = hashtags.map { SearchItem.trend($0) } +// snapshot.appendItems(trendItems, toSection: .trend) +// +// diffableDataSource.apply(snapshot) +// } +// .store(in: &disposeBag) +// } +// +//} diff --git a/Mastodon/Scene/Search/Search/SearchViewModel.swift b/Mastodon/Scene/Search/Search/SearchViewModel.swift index 84e097250..b47bc2e88 100644 --- a/Mastodon/Scene/Search/Search/SearchViewModel.swift +++ b/Mastodon/Scene/Search/Search/SearchViewModel.swift @@ -29,31 +29,31 @@ final class SearchViewModel: NSObject { self.context = context super.init() - Publishers.CombineLatest( - context.authenticationService.activeMastodonAuthenticationBox, - viewDidAppeared - ) - .compactMap { authenticationBox, _ -> MastodonAuthenticationBox? in - return authenticationBox - } - .throttle(for: 3, scheduler: DispatchQueue.main, latest: true) - .asyncMap { authenticationBox in - try await context.apiService.trendHashtags(domain: authenticationBox.domain, query: nil) - } - .retry(3) - .map { response in Result, Error> { response } } - .catch { error in Just(Result, Error> { throw error }) } - .receive(on: DispatchQueue.main) - .sink { [weak self] result in - guard let self = self else { return } - switch result { - case .success(let response): - self.hashtags = response.value - case .failure: - break - } - } - .store(in: &disposeBag) +// Publishers.CombineLatest( +// context.authenticationService.activeMastodonAuthenticationBox, +// viewDidAppeared +// ) +// .compactMap { authenticationBox, _ -> MastodonAuthenticationBox? in +// return authenticationBox +// } +// .throttle(for: 3, scheduler: DispatchQueue.main, latest: true) +// .asyncMap { authenticationBox in +// try await context.apiService.trendHashtags(domain: authenticationBox.domain, query: nil) +// } +// .retry(3) +// .map { response in Result, Error> { response } } +// .catch { error in Just(Result, Error> { throw error }) } +// .receive(on: DispatchQueue.main) +// .sink { [weak self] result in +// guard let self = self else { return } +// switch result { +// case .success(let response): +// self.hashtags = response.value +// case .failure: +// break +// } +// } +// .store(in: &disposeBag) } } diff --git a/Mastodon/Scene/Search/SearchDetail/SearchDetailViewController.swift b/Mastodon/Scene/Search/SearchDetail/SearchDetailViewController.swift index 5e143a33c..ecc1c0c02 100644 --- a/Mastodon/Scene/Search/SearchDetail/SearchDetailViewController.swift +++ b/Mastodon/Scene/Search/SearchDetail/SearchDetailViewController.swift @@ -12,6 +12,14 @@ import Pageboy import MastodonAsset import MastodonLocalization +final class CustomSearchController: UISearchController { + + let customSearchBar = UISearchBar(frame: CGRect(x: 0, y: 0, width: 300, height: 100)) + + override var searchBar: UISearchBar { customSearchBar } + +} + // Fake search bar not works on iPad with UISplitViewController // check device and fallback to standard UISearchController final class SearchDetailViewController: PageboyViewController, NeedsDependency { @@ -48,8 +56,8 @@ final class SearchDetailViewController: PageboyViewController, NeedsDependency { return navigationBar }() - let searchController: UISearchController = { - let searchController = UISearchController() + let searchController: CustomSearchController = { + let searchController = CustomSearchController() searchController.automaticallyShowsScopeBar = false searchController.dimsBackgroundDuringPresentation = false return searchController @@ -235,11 +243,17 @@ extension SearchDetailViewController { if isPhoneDevice { searchBar.setShowsCancelButton(true, animated: animated) - searchBar.becomeFirstResponder() + UIView.performWithoutAnimation { + self.searchBar.becomeFirstResponder() + } } else { - searchController.isActive = true - DispatchQueue.main.asyncAfter(deadline: .now() + 0.33) { - self.searchController.searchBar.becomeFirstResponder() + searchController.searchBar.setShowsCancelButton(true, animated: false) + searchController.searchBar.setShowsScope(true, animated: false) + UIView.performWithoutAnimation { + self.searchController.isActive = true + } + DispatchQueue.main.async { + self.searchController.searchBar.becomeFirstResponder() } } } diff --git a/Mastodon/Scene/Transition/Search/SearchToSearchDetailViewControllerAnimatedTransitioning.swift b/Mastodon/Scene/Transition/Search/SearchToSearchDetailViewControllerAnimatedTransitioning.swift index f06d04d9a..e060acc83 100644 --- a/Mastodon/Scene/Transition/Search/SearchToSearchDetailViewControllerAnimatedTransitioning.swift +++ b/Mastodon/Scene/Transition/Search/SearchToSearchDetailViewControllerAnimatedTransitioning.swift @@ -46,14 +46,17 @@ extension SearchToSearchDetailViewControllerAnimatedTransitioning { let toViewEndFrame = transitionContext.finalFrame(for: toVC) transitionContext.containerView.addSubview(toView) toView.frame = toViewEndFrame + toView.setNeedsLayout() + toView.layoutIfNeeded() + toVC.searchBar.setNeedsLayout() + toVC.searchBar.layoutIfNeeded() toView.alpha = 0 let animator = UIViewPropertyAnimator(duration: transitionDuration(using: transitionContext), curve: curve) animator.addAnimations { - + toView.alpha = 1 } animator.addCompletion { position in - toView.alpha = 1 transitionContext.completeTransition(true) } return animator From 9477071556aaca00a1db0dec46f2a9eff716011b Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 15 Apr 2022 17:22:30 +0800 Subject: [PATCH 014/101] chore: update i18n --- .../MastodonUI/View/Content/NewsView+Configuration.swift | 2 +- .../MastodonUI/View/Content/TrendView+Configuration.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift b/MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift index 3116534a0..e045eafe7 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift @@ -14,7 +14,7 @@ extension NewsView { public func configure(link: Mastodon.Entity.Link) { providerNameLabel.text = link.providerName headlineLabel.text = link.title - footnoteLabel.text = L10n.Scene.Search.Recommend.HashTag.peopleTalking(link.talkingPeopleCount ?? 0) + footnoteLabel.text = L10n.Plural.peopleTalking(link.talkingPeopleCount ?? 0) let configuration = MediaView.Configuration( info: .image(info: .init( diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/TrendView+Configuration.swift b/MastodonSDK/Sources/MastodonUI/View/Content/TrendView+Configuration.swift index cdd3dfd82..fd5ddb245 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/TrendView+Configuration.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/TrendView+Configuration.swift @@ -12,7 +12,7 @@ import MastodonLocalization extension TrendView { public func configure(tag: Mastodon.Entity.Tag) { let primaryLabelText = "#" + tag.name - let secondaryLabelText = L10n.Scene.Search.Recommend.HashTag.peopleTalking(tag.talkingPeopleCount ?? 0) + let secondaryLabelText = L10n.Plural.peopleTalking(tag.talkingPeopleCount ?? 0) primaryLabel.text = primaryLabelText secondaryLabel.text = secondaryLabelText From c3bd5528fa4d7ff1cefe60593e45c3c48dcec05f Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 15 Apr 2022 17:34:58 +0800 Subject: [PATCH 015/101] feat: add reload to Hashtags tab for Discovery scene --- .../DiscoveryHashtagsViewController.swift | 20 +++++++++++++++++++ .../Hashtags/DiscoveryHashtagsViewModel.swift | 13 ++++++++++++ 2 files changed, 33 insertions(+) diff --git a/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift index 1dca1232a..91ab5036c 100644 --- a/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift +++ b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift @@ -31,6 +31,8 @@ final class DiscoveryHashtagsViewController: UIViewController, NeedsDependency, return tableView }() + let refreshControl = UIRefreshControl() + deinit { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) } @@ -59,6 +61,9 @@ extension DiscoveryHashtagsViewController { tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), ]) + + tableView.refreshControl = refreshControl + refreshControl.addTarget(self, action: #selector(DiscoveryHashtagsViewController.refreshControlValueChanged(_:)), for: .valueChanged) tableView.delegate = self viewModel.setupDiffableDataSource( @@ -80,6 +85,21 @@ extension DiscoveryHashtagsViewController { } +extension DiscoveryHashtagsViewController { + + @objc private func refreshControlValueChanged(_ sender: UIRefreshControl) { + Task { @MainActor in + do { + try await viewModel.fetch() + } catch { + // do nothing + } + sender.endRefreshing() + } // end Task + } + +} + // MARK: - UITableViewDelegate extension DiscoveryHashtagsViewController: UITableViewDelegate { diff --git a/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel.swift b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel.swift index 5f51d6459..bb30ec9ee 100644 --- a/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel.swift +++ b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel.swift @@ -15,6 +15,8 @@ import MastodonSDK final class DiscoveryHashtagsViewModel { + let logger = Logger(subsystem: "DiscoveryHashtagsViewModel", category: "ViewModel") + var disposeBag = Set() // input @@ -61,3 +63,14 @@ final class DiscoveryHashtagsViewModel { } } + +extension DiscoveryHashtagsViewModel { + + @MainActor + func fetch() async throws { + guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return } + let response = try await context.apiService.trendHashtags(domain: authenticationBox.domain, query: nil) + hashtags = response.value.filter { !$0.name.isEmpty } + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): fetch tags: \(response.value.count)") + } +} From 5c1f5eb8f0bdb0cedb3e2a931f857220d2afa7dc Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 15 Apr 2022 17:36:37 +0800 Subject: [PATCH 016/101] chore: update version to 1.3.1 (110) --- AppShared/Info.plist | 4 +-- Mastodon.xcodeproj/project.pbxproj | 36 +++++++++---------- .../xcschemes/xcschememanagement.plist | 6 ++-- Mastodon/Info.plist | 4 +-- MastodonIntent/Info.plist | 4 +-- MastodonTests/Info.plist | 4 +-- MastodonUITests/Info.plist | 4 +-- NotificationService/Info.plist | 4 +-- ShareActionExtension/Info.plist | 4 +-- 9 files changed, 35 insertions(+), 35 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 73f11cd26..66a4b22f5 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.0 + 1.3.1 CFBundleVersion - 109 + 110 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 678fc7107..54c682956 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4728,7 +4728,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 109; + CURRENT_PROJECT_VERSION = 110; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4757,7 +4757,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 109; + CURRENT_PROJECT_VERSION = 110; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4865,11 +4865,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 109; + CURRENT_PROJECT_VERSION = 110; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 109; + DYLIB_CURRENT_VERSION = 110; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4896,11 +4896,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 109; + CURRENT_PROJECT_VERSION = 110; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 109; + DYLIB_CURRENT_VERSION = 110; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4925,7 +4925,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 109; + CURRENT_PROJECT_VERSION = 110; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4950,7 +4950,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 109; + CURRENT_PROJECT_VERSION = 110; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4975,7 +4975,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 109; + CURRENT_PROJECT_VERSION = 110; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5000,7 +5000,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 109; + CURRENT_PROJECT_VERSION = 110; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5086,7 +5086,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 109; + CURRENT_PROJECT_VERSION = 110; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5153,11 +5153,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 109; + CURRENT_PROJECT_VERSION = 110; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 109; + DYLIB_CURRENT_VERSION = 110; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5182,7 +5182,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 109; + CURRENT_PROJECT_VERSION = 110; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5206,7 +5206,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 109; + CURRENT_PROJECT_VERSION = 110; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5231,7 +5231,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 109; + CURRENT_PROJECT_VERSION = 110; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5256,7 +5256,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 109; + CURRENT_PROJECT_VERSION = 110; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5280,7 +5280,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 109; + CURRENT_PROJECT_VERSION = 110; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 1444a8b27..e45da3c0d 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 22 + 33 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 23 + 32 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 24 + 31 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 311ee390b..88b45ec38 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -30,7 +30,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.0 + 1.3.1 CFBundleURLTypes @@ -43,7 +43,7 @@ CFBundleVersion - 109 + 110 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 02385f4e6..797487637 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.0 + 1.3.1 CFBundleVersion - 109 + 110 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 73f11cd26..66a4b22f5 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.0 + 1.3.1 CFBundleVersion - 109 + 110 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 73f11cd26..66a4b22f5 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.0 + 1.3.1 CFBundleVersion - 109 + 110 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index 215b572b5..7301c57de 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.0 + 1.3.1 CFBundleVersion - 109 + 110 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 82ba5658a..856818817 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.0 + 1.3.1 CFBundleVersion - 109 + 110 NSExtension NSExtensionAttributes From 8a95563976579af9841fb97724ebca28bc045e8f Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 18 Apr 2022 10:39:28 +0800 Subject: [PATCH 017/101] chore: use fixed height searchBar --- Mastodon/Scene/Search/Search/SearchViewController.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Mastodon/Scene/Search/Search/SearchViewController.swift b/Mastodon/Scene/Search/Search/SearchViewController.swift index 7594eb478..982844f51 100644 --- a/Mastodon/Scene/Search/Search/SearchViewController.swift +++ b/Mastodon/Scene/Search/Search/SearchViewController.swift @@ -15,7 +15,7 @@ import MastodonLocalization final class HeightFixedSearchBar: UISearchBar { override var intrinsicContentSize: CGSize { - return CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude) + return CGSize(width: CGFloat.greatestFiniteMagnitude, height: 36) } } @@ -179,14 +179,14 @@ extension SearchViewController: UISearchControllerDelegate { //extension SearchViewController: UICollectionViewDelegate { // func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { // logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): select item at: \(indexPath.debugDescription)") -// +// // defer { // collectionView.deselectItem(at: indexPath, animated: true) // } -// +// // guard let diffableDataSource = viewModel.diffableDataSource else { return } // guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return } -// +// // switch item { // case .trend(let hashtag): // let viewModel = HashtagTimelineViewModel(context: context, hashtag: hashtag.name) From c57c3b430491b9a19c71c07a8da1788f250c7594 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 18 Apr 2022 10:47:55 +0800 Subject: [PATCH 018/101] feat: make adaptive profile card layout on iPad when search tab display as compact column --- .../MastodonUI/View/Content/ProfileCardView.swift | 13 +++++++++++-- .../View/Control/ProfileStatusDashboardView.swift | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift index eb500b7c4..95424b7ee 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift @@ -78,6 +78,8 @@ public final class ProfileCardView: UIView { return metaText }() + let infoContainer = UIStackView() + let statusDashboardView = ProfileStatusDashboardView() let relationshipActionButtonShadowContainer = ShadowBackgroundContainer() @@ -206,8 +208,8 @@ extension ProfileCardView { container.setCustomSpacing(16, after: bioMetaTextAdaptiveMarginContainerView) // infoContainer: H - [ statusDashboardView | (spacer) | relationshipActionButton ] - let infoContainer = UIStackView() infoContainer.axis = .horizontal + infoContainer.spacing = 8 let infoContainerAdaptiveMarginContainerView = AdaptiveMarginContainerView() infoContainerAdaptiveMarginContainerView.contentView = infoContainer infoContainerAdaptiveMarginContainerView.margin = ProfileCardView.contentMargin @@ -225,7 +227,7 @@ extension ProfileCardView { relationshipActionButton.trailingAnchor.constraint(equalTo: relationshipActionButtonShadowContainer.trailingAnchor), relationshipActionButton.bottomAnchor.constraint(equalTo: relationshipActionButtonShadowContainer.bottomAnchor), relationshipActionButton.widthAnchor.constraint(greaterThanOrEqualToConstant: ProfileCardView.friendshipActionButtonSize.width).priority(.required - 1), - relationshipActionButton.heightAnchor.constraint(equalToConstant: ProfileCardView.friendshipActionButtonSize.height).priority(.defaultHigh), + relationshipActionButton.heightAnchor.constraint(equalToConstant: ProfileCardView.friendshipActionButtonSize.height).priority(.required - 10), ]) let bottomPadding = UIView() @@ -243,6 +245,13 @@ extension ProfileCardView { viewModel.userInterfaceStyle = traitCollection.userInterfaceStyle } + + public override func layoutSubviews() { + super.layoutSubviews() + + let isCompactAdaptive = bounds.width < 350 + infoContainer.axis = isCompactAdaptive ? .vertical : .horizontal + } } diff --git a/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardView.swift b/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardView.swift index 7d8e4fbcd..320c1e903 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardView.swift @@ -55,7 +55,7 @@ extension ProfileStatusDashboardView { containerStackView.heightAnchor.constraint(equalToConstant: 44).priority(.defaultHigh), ]) - let spacing: CGFloat = UIView.isZoomedMode ? 4 : 16 + let spacing: CGFloat = UIView.isZoomedMode ? 4 : 12 containerStackView.spacing = spacing containerStackView.axis = .horizontal containerStackView.distribution = .fillEqually From c4ab4f68c6a24b24e0009c4946500ff941c71862 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 18 Apr 2022 15:33:29 +0800 Subject: [PATCH 019/101] fix: status sensitive toggle logic issue --- Mastodon.xcodeproj/project.pbxproj | 42 +++++------- .../xcschemes/xcschememanagement.plist | 14 ++-- .../xcshareddata/swiftpm/Package.resolved | 20 +++--- .../Provider/DataSourceFacade+Status.swift | 18 +----- ...er+NotificationTableViewCellDelegate.swift | 4 +- ...Provider+StatusTableViewCellDelegate.swift | 7 +- .../Content/MediaView+Configuration.swift | 8 +-- .../Content/StatusView+Configuration.swift | 15 ++--- .../TableviewCell/StatusTableViewCell.swift | 2 +- .../StatusThreadRootTableViewCell.swift | 2 +- MastodonSDK/Package.swift | 3 +- .../CoreData 3.xcdatamodel/contents | 7 +- .../Entity/Mastodon/Status.swift | 15 ++--- .../CoreDataStack/MastodonStatus.swift | 28 ++++++++ .../View/Content/StatusView+ViewModel.swift | 64 +++++++------------ .../MastodonUI/View/Content/StatusView.swift | 1 + .../View/Control/ActionToolbarContainer.swift | 2 +- .../Control/ProfileStatusDashboardView.swift | 6 +- 18 files changed, 111 insertions(+), 147 deletions(-) create mode 100644 MastodonSDK/Sources/MastodonUI/Extension/CoreDataStack/MastodonStatus.swift diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 54c682956..83cbb62ac 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -115,9 +115,7 @@ DB0009A626AEE5DC009B9D2D /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = DB0009A926AEE5DC009B9D2D /* Intents.intentdefinition */; settings = {ATTRIBUTES = (no_codegen, ); }; }; DB0009A726AEE5DC009B9D2D /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = DB0009A926AEE5DC009B9D2D /* Intents.intentdefinition */; }; DB00CA972632DDB600A54956 /* CommonOSLog in Frameworks */ = {isa = PBXBuildFile; productRef = DB00CA962632DDB600A54956 /* CommonOSLog */; }; - DB0140BD25C40D7500F9F3CF /* CommonOSLog in Frameworks */ = {isa = PBXBuildFile; productRef = DB0140BC25C40D7500F9F3CF /* CommonOSLog */; }; DB0140CF25C42AEE00F9F3CF /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0140CE25C42AEE00F9F3CF /* OSLog.swift */; }; - DB01E23326A98F0900C3965B /* MastodonMeta in Frameworks */ = {isa = PBXBuildFile; productRef = DB01E23226A98F0900C3965B /* MastodonMeta */; }; DB01E23526A98F0900C3965B /* MetaTextKit in Frameworks */ = {isa = PBXBuildFile; productRef = DB01E23426A98F0900C3965B /* MetaTextKit */; }; DB023D26279FFB0A005AC798 /* ShareActivityProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB023D25279FFB0A005AC798 /* ShareActivityProvider.swift */; }; DB023D2827A0FABD005AC798 /* NotificationTableViewCellDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB023D2727A0FABD005AC798 /* NotificationTableViewCellDelegate.swift */; }; @@ -130,6 +128,8 @@ DB029E95266A20430062874E /* MastodonAuthenticationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB029E94266A20430062874E /* MastodonAuthenticationController.swift */; }; DB02CDAB26256A9500D0A2AF /* ThreadReplyLoaderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB02CDAA26256A9500D0A2AF /* ThreadReplyLoaderTableViewCell.swift */; }; DB02CDBF2625AE5000D0A2AF /* AdaptiveUserInterfaceStyleBarButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB02CDBE2625AE5000D0A2AF /* AdaptiveUserInterfaceStyleBarButtonItem.swift */; }; + DB02EA0B280D180D00E751C5 /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = DB02EA0A280D180D00E751C5 /* KeychainAccess */; }; + DB02EA0D280D184B00E751C5 /* CommonOSLog in Frameworks */ = {isa = PBXBuildFile; productRef = DB02EA0C280D184B00E751C5 /* CommonOSLog */; }; DB03A793272A7E5700EE37C5 /* SidebarListHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB03A792272A7E5700EE37C5 /* SidebarListHeaderView.swift */; }; DB03A795272A981400EE37C5 /* ContentSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB03A794272A981400EE37C5 /* ContentSplitViewController.swift */; }; DB03F7F32689AEA3007B274C /* ComposeRepliedToStatusContentTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB03F7F22689AEA3007B274C /* ComposeRepliedToStatusContentTableViewCell.swift */; }; @@ -347,7 +347,6 @@ DB6804872637CD4C00430867 /* AppShared.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = DB68047F2637CD4C00430867 /* AppShared.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; DB6804D12637CE4700430867 /* UserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6804D02637CE4700430867 /* UserDefaults.swift */; }; DB6804FD2637CFEC00430867 /* AppSecret.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6804FC2637CFEC00430867 /* AppSecret.swift */; }; - DB6805102637D0F800430867 /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = DB68050F2637D0F800430867 /* KeychainAccess */; }; DB68586425E619B700F0A850 /* NSKeyValueObservation.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB68586325E619B700F0A850 /* NSKeyValueObservation.swift */; }; DB68A04A25E9027700CFDF14 /* AdaptiveStatusBarStyleNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB68A04925E9027700CFDF14 /* AdaptiveStatusBarStyleNavigationController.swift */; }; DB68A05D25E9055900CFDF14 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = DB68A05C25E9055900CFDF14 /* Settings.bundle */; }; @@ -1372,7 +1371,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - DB0140BD25C40D7500F9F3CF /* CommonOSLog in Frameworks */, DB9A487E2603456B008B817C /* UITextView+Placeholder in Frameworks */, 2D939AC825EE14620076FA61 /* CropViewController in Frameworks */, DBB525082611EAC0002F1F29 /* Tabman in Frameworks */, @@ -1382,10 +1380,10 @@ DBAC6483267D0B21007FE9FD /* DifferenceKit in Frameworks */, DB552D4F26BBD10C00E481F6 /* OrderedCollections in Frameworks */, 2D61336925C18A4F00CAE157 /* AlamofireNetworkActivityIndicator in Frameworks */, - DB01E23326A98F0900C3965B /* MastodonMeta in Frameworks */, DBAC64A1267E6D02007FE9FD /* Fuzi in Frameworks */, DB3D0FF325BAA61700EAA174 /* AlamofireImage in Frameworks */, DBAC649E267DFE43007FE9FD /* DiffableDataSources in Frameworks */, + DB02EA0D280D184B00E751C5 /* CommonOSLog in Frameworks */, 2D5981BA25E4D7F8000FB903 /* ThirdPartyMailer in Frameworks */, 87FFDA5D898A5C42ADCB35E7 /* Pods_Mastodon.framework in Frameworks */, DBF7A0FC26830C33004176A2 /* FPSIndicator in Frameworks */, @@ -1415,7 +1413,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - DB6805102637D0F800430867 /* KeychainAccess in Frameworks */, + DB02EA0B280D180D00E751C5 /* KeychainAccess in Frameworks */, EE93E8E8F9E0C39EAAEBD92F /* Pods_AppShared.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -3303,7 +3301,6 @@ DB3D0FF225BAA61700EAA174 /* AlamofireImage */, 5D526FE125BE9AC400460CB9 /* MastodonSDK */, 2D61336825C18A4F00CAE157 /* AlamofireNetworkActivityIndicator */, - DB0140BC25C40D7500F9F3CF /* CommonOSLog */, 2D5981B925E4D7F8000FB903 /* ThirdPartyMailer */, 2D939AC725EE14620076FA61 /* CropViewController */, DB9A487D2603456B008B817C /* UITextView+Placeholder */, @@ -3312,10 +3309,10 @@ DBAC649D267DFE43007FE9FD /* DiffableDataSources */, DBAC64A0267E6D02007FE9FD /* Fuzi */, DBF7A0FB26830C33004176A2 /* FPSIndicator */, - DB01E23226A98F0900C3965B /* MastodonMeta */, DB01E23426A98F0900C3965B /* MetaTextKit */, DB552D4E26BBD10C00E481F6 /* OrderedCollections */, DBA5A52E26F07ED800CACBAA /* PanModal */, + DB02EA0C280D184B00E751C5 /* CommonOSLog */, ); productName = Mastodon; productReference = DB427DD225BAA00100D1B89D /* Mastodon.app */; @@ -3376,7 +3373,7 @@ ); name = AppShared; packageProductDependencies = ( - DB68050F2637D0F800430867 /* KeychainAccess */, + DB02EA0A280D180D00E751C5 /* KeychainAccess */, ); productName = AppShared; productReference = DB68047F2637CD4C00430867 /* AppShared.framework */; @@ -5421,7 +5418,7 @@ repositoryURL = "https://github.com/TwidereProject/MetaTextKit.git"; requirement = { kind = exactVersion; - version = 2.2.1; + version = 2.2.2; }; }; DB0E2D2C26833FF600865C3C /* XCRemoteSwiftPackageReference "Nuke-FLAnimatedImage-Plugin" */ = { @@ -5539,21 +5536,21 @@ package = DB0140BB25C40D7500F9F3CF /* XCRemoteSwiftPackageReference "CommonOSLog" */; productName = CommonOSLog; }; - DB0140BC25C40D7500F9F3CF /* CommonOSLog */ = { - isa = XCSwiftPackageProductDependency; - package = DB0140BB25C40D7500F9F3CF /* XCRemoteSwiftPackageReference "CommonOSLog" */; - productName = CommonOSLog; - }; - DB01E23226A98F0900C3965B /* MastodonMeta */ = { - isa = XCSwiftPackageProductDependency; - package = DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit" */; - productName = MastodonMeta; - }; DB01E23426A98F0900C3965B /* MetaTextKit */ = { isa = XCSwiftPackageProductDependency; package = DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit" */; productName = MetaTextKit; }; + DB02EA0A280D180D00E751C5 /* KeychainAccess */ = { + isa = XCSwiftPackageProductDependency; + package = DB6804722637CC1200430867 /* XCRemoteSwiftPackageReference "KeychainAccess" */; + productName = KeychainAccess; + }; + DB02EA0C280D184B00E751C5 /* CommonOSLog */ = { + isa = XCSwiftPackageProductDependency; + package = DB0140BB25C40D7500F9F3CF /* XCRemoteSwiftPackageReference "CommonOSLog" */; + productName = CommonOSLog; + }; DB0C946426A6FD4D0088FB11 /* AlamofireImage */ = { isa = XCSwiftPackageProductDependency; package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */; @@ -5573,11 +5570,6 @@ package = DB552D4D26BBD10C00E481F6 /* XCRemoteSwiftPackageReference "swift-collections" */; productName = OrderedCollections; }; - DB68050F2637D0F800430867 /* KeychainAccess */ = { - isa = XCSwiftPackageProductDependency; - package = DB6804722637CC1200430867 /* XCRemoteSwiftPackageReference "KeychainAccess" */; - productName = KeychainAccess; - }; DB6D9F41263527CE008423CD /* AlamofireImage */ = { isa = XCSwiftPackageProductDependency; package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */; diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index e45da3c0d..0d22a2264 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -9,7 +9,7 @@ isShown orderHint - 4 + 5 CoreDataStack.xcscheme_^#shared#^_ @@ -19,7 +19,7 @@ Mastodon - RTL.xcscheme_^#shared#^_ orderHint - 19 + 20 Mastodon - Release.xcscheme_^#shared#^_ @@ -29,12 +29,12 @@ Mastodon - Snapshot.xcscheme_^#shared#^_ orderHint - 2 + 3 Mastodon - ar.xcscheme orderHint - 3 + 4 Mastodon - ar.xcscheme_^#shared#^_ @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 33 + 26 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 32 + 23 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 31 + 24 SuppressBuildableAutocreation diff --git a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved index 11d453883..8dd69150f 100644 --- a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -6,8 +6,8 @@ "repositoryURL": "https://github.com/Alamofire/Alamofire.git", "state": { "branch": null, - "revision": "f82c23a8a7ef8dc1a49a8bfc6a96883e79121864", - "version": "5.5.0" + "revision": "354dda32d89fc8cd4f5c46487f64957d355f53d8", + "version": "5.6.1" } }, { @@ -96,8 +96,8 @@ "repositoryURL": "https://github.com/TwidereProject/MetaTextKit.git", "state": { "branch": null, - "revision": "3ea336d3de7938dc112084c596a646e697b0feee", - "version": "2.2.1" + "revision": "8074400b3819ef0395550082e6e8e960ef22e1f3", + "version": "2.2.2" } }, { @@ -105,8 +105,8 @@ "repositoryURL": "https://github.com/kean/Nuke.git", "state": { "branch": null, - "revision": "0db18dd34998cca18e9a28bcee136f84518007a0", - "version": "10.4.1" + "revision": "78fa963b8491fc520791d8c2a509f1b8593d8aae", + "version": "10.7.1" } }, { @@ -141,8 +141,8 @@ "repositoryURL": "https://github.com/SDWebImage/SDWebImage.git", "state": { "branch": null, - "revision": "2c53f531f1bedd253f55d85105409c28ed4a922c", - "version": "5.12.3" + "revision": "2e63d0061da449ad0ed130768d05dceb1496de44", + "version": "5.12.5" } }, { @@ -177,8 +177,8 @@ "repositoryURL": "https://github.com/siteline/SwiftUI-Introspect.git", "state": { "branch": null, - "revision": "2e09be8af614401bc9f87d40093ec19ce56ccaf2", - "version": "0.1.3" + "revision": "f2616860a41f9d9932da412a8978fec79c06fe24", + "version": "0.1.4" } }, { diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift index eab85e95e..36ceb6dd6 100644 --- a/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift +++ b/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift @@ -286,24 +286,8 @@ extension DataSourceFacade { try await dependency.context.managedObjectContext.perform { guard let _status = status.object(in: dependency.context.managedObjectContext) else { return } let status = _status.reblog ?? _status - - let allToggled = status.isContentSensitiveToggled && status.isMediaSensitiveToggled - - status.update(isContentSensitiveToggled: !allToggled) - status.update(isMediaSensitiveToggled: !allToggled) + status.update(isSensitiveToggled: !status.isSensitiveToggled) } } -// static func responseToToggleMediaSensitiveAction( -// dependency: NeedsDependency, -// status: ManagedObjectRecord -// ) async throws { -// try await dependency.context.managedObjectContext.perform { -// guard let _status = status.object(in: dependency.context.managedObjectContext) else { return } -// let status = _status.reblog ?? _status -// -// status.update(isMediaSensitiveToggled: !status.isMediaSensitiveToggled) -// } -// } - } diff --git a/Mastodon/Protocol/Provider/DataSourceProvider+NotificationTableViewCellDelegate.swift b/Mastodon/Protocol/Provider/DataSourceProvider+NotificationTableViewCellDelegate.swift index 0924028ff..f6e58673b 100644 --- a/Mastodon/Protocol/Provider/DataSourceProvider+NotificationTableViewCellDelegate.swift +++ b/Mastodon/Protocol/Provider/DataSourceProvider+NotificationTableViewCellDelegate.swift @@ -135,7 +135,7 @@ extension NotificationTableViewCellDelegate where Self: DataSourceProvider & Med let status = _status.reblog ?? _status return NotificationMediaTransitionContext( status: .init(objectID: status.objectID), - needsToggleMediaSensitive: status.isMediaSensitiveToggled ? !status.sensitive : status.sensitive + needsToggleMediaSensitive: status.isSensitiveToggled ? !status.sensitive : status.sensitive ) } @@ -187,7 +187,7 @@ extension NotificationTableViewCellDelegate where Self: DataSourceProvider & Med let status = _status.reblog ?? _status return NotificationMediaTransitionContext( status: .init(objectID: status.objectID), - needsToggleMediaSensitive: status.isMediaSensitiveToggled ? !status.sensitive : status.sensitive + needsToggleMediaSensitive: status.isMediaSensitive ? !status.isSensitiveToggled : false ) } diff --git a/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift b/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift index d14b5c346..9e5838e77 100644 --- a/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift +++ b/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift @@ -143,12 +143,7 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider & MediaPrev return } - let managedObjectContext = self.context.managedObjectContext - let needsToggleMediaSensitive: Bool = try await managedObjectContext.perform { - guard let _status = status.object(in: managedObjectContext) else { return false } - let status = _status.reblog ?? _status - return status.isMediaSensitiveToggled ? !status.sensitive : status.sensitive - } + let needsToggleMediaSensitive = await !statusView.viewModel.isMediaReveal guard !needsToggleMediaSensitive else { try await DataSourceFacade.responseToToggleSensitiveAction( diff --git a/Mastodon/Scene/Share/View/Content/MediaView+Configuration.swift b/Mastodon/Scene/Share/View/Content/MediaView+Configuration.swift index cba1fcf6d..02f9ad5a4 100644 --- a/Mastodon/Scene/Share/View/Content/MediaView+Configuration.swift +++ b/Mastodon/Scene/Share/View/Content/MediaView+Configuration.swift @@ -62,14 +62,14 @@ extension MediaView { { let placeholder = UIImage.placeholder(color: .systemGray6) let request = URLRequest(url: url) - ImageDownloader.default.download(request) { response in + ImageDownloader.default.download(request, completion: { response in switch response.result { case .success(let image): configuration.previewImage = image - case .failure(let error): + case .failure: configuration.previewImage = placeholder } - } + }) } if let assetURL = configuration.assetURL, @@ -84,7 +84,7 @@ extension MediaView { .store(in: &configuration.blurhashImageDisposeBag) } - configuration.isReveal = status.sensitive ? status.isMediaSensitiveToggled : true + configuration.isReveal = status.isMediaSensitive ? status.isSensitiveToggled : true return configuration } diff --git a/Mastodon/Scene/Share/View/Content/StatusView+Configuration.swift b/Mastodon/Scene/Share/View/Content/StatusView+Configuration.swift index 1a90c69af..ab4fea1ab 100644 --- a/Mastodon/Scene/Share/View/Content/StatusView+Configuration.swift +++ b/Mastodon/Scene/Share/View/Content/StatusView+Configuration.swift @@ -156,7 +156,6 @@ extension StatusView { .map { _ in author.avatarImageURL() } .assign(to: \.authorAvatarImageURL, on: viewModel) .store(in: &disposeBag) - // author name Publishers.CombineLatest( author.publisher(for: \.displayName), @@ -268,25 +267,19 @@ extension StatusView { .assign(to: \.visibility, on: viewModel) .store(in: &disposeBag) // sensitive - status.publisher(for: \.isContentSensitiveToggled) - .assign(to: \.isContentSensitiveToggled, on: viewModel) + viewModel.isContentSensitive = status.isContentSensitive + status.publisher(for: \.isSensitiveToggled) + .assign(to: \.isSensitiveToggled, on: viewModel) .store(in: &disposeBag) - - -// viewModel.source = status.source } private func configureMedia(status: Status) { let status = status.reblog ?? status - viewModel.isMediaSensitive = status.sensitive && !status.attachments.isEmpty // some servers set media sensitive even empty attachments + viewModel.isMediaSensitive = status.isMediaSensitive let configurations = MediaView.configuration(status: status) viewModel.mediaViewConfigurations = configurations - - status.publisher(for: \.isMediaSensitiveToggled) - .assign(to: \.isMediaSensitiveToggled, on: viewModel) - .store(in: &disposeBag) } private func configurePoll(status: Status) { diff --git a/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift b/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift index a1033f052..a3315211e 100644 --- a/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift +++ b/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift @@ -61,7 +61,7 @@ extension StatusTableViewCell { statusView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 16), containerViewLeadingLayoutConstraint, containerViewTrailingLayoutConstraint, - statusView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + contentView.bottomAnchor.constraint(equalTo: statusView.bottomAnchor, constant: 10), ]) statusView.setup(style: .inline) updateContainerViewMarginConstraints() diff --git a/Mastodon/Scene/Share/View/TableviewCell/StatusThreadRootTableViewCell.swift b/Mastodon/Scene/Share/View/TableviewCell/StatusThreadRootTableViewCell.swift index e27cc2dd3..115175800 100644 --- a/Mastodon/Scene/Share/View/TableviewCell/StatusThreadRootTableViewCell.swift +++ b/Mastodon/Scene/Share/View/TableviewCell/StatusThreadRootTableViewCell.swift @@ -112,7 +112,7 @@ extension StatusThreadRootTableViewCell { statusView.statusMetricView ] - if !statusView.viewModel.isSensitive { + if !statusView.viewModel.isMediaSensitive { elements.removeAll(where: { $0 === statusView.contentSensitiveeToggleButton }) } diff --git a/MastodonSDK/Package.swift b/MastodonSDK/Package.swift index dd562f147..ed4a13d55 100644 --- a/MastodonSDK/Package.swift +++ b/MastodonSDK/Package.swift @@ -32,7 +32,7 @@ let package = Package( .package(url: "https://github.com/apple/swift-nio.git", from: "1.0.0"), .package(url: "https://github.com/kean/Nuke.git", from: "10.3.1"), .package(url: "https://github.com/Flipboard/FLAnimatedImage.git", from: "1.0.0"), - .package(url: "https://github.com/TwidereProject/MetaTextKit.git", .exact("2.2.1")), + .package(url: "https://github.com/TwidereProject/MetaTextKit.git", .exact("2.2.2")), .package(url: "https://github.com/Alamofire/Alamofire.git", from: "5.4.0"), .package(url: "https://github.com/Alamofire/AlamofireImage.git", from: "4.1.0"), .package(name: "NukeFLAnimatedImagePlugin", url: "https://github.com/kean/Nuke-FLAnimatedImage-Plugin.git", from: "8.0.0"), @@ -94,7 +94,6 @@ let package = Package( .product(name: "Alamofire", package: "Alamofire"), .product(name: "AlamofireImage", package: "AlamofireImage"), .product(name: "MetaTextKit", package: "MetaTextKit"), - .product(name: "MastodonMeta", package: "MetaTextKit"), .product(name: "FLAnimatedImage", package: "FLAnimatedImage"), ] ), diff --git a/MastodonSDK/Sources/CoreDataStack/CoreData.xcdatamodeld/CoreData 3.xcdatamodel/contents b/MastodonSDK/Sources/CoreDataStack/CoreData.xcdatamodeld/CoreData 3.xcdatamodel/contents index a6f0ee0ce..16a1c7c84 100644 --- a/MastodonSDK/Sources/CoreDataStack/CoreData.xcdatamodeld/CoreData 3.xcdatamodel/contents +++ b/MastodonSDK/Sources/CoreDataStack/CoreData.xcdatamodeld/CoreData 3.xcdatamodel/contents @@ -1,5 +1,5 @@ - + @@ -185,8 +185,7 @@ - - + @@ -262,7 +261,7 @@ - + diff --git a/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/Status.swift b/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/Status.swift index d17d1c616..0c7291913 100644 --- a/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/Status.swift +++ b/MastodonSDK/Sources/CoreDataStack/Entity/Mastodon/Status.swift @@ -42,9 +42,7 @@ public final class Status: NSManagedObject { @NSManaged public private(set) var spoilerText: String? // sourcery: autoUpdatableObject - @NSManaged public private(set) var isContentSensitiveToggled: Bool - // sourcery: autoUpdatableObject - @NSManaged public private(set) var isMediaSensitiveToggled: Bool + @NSManaged public private(set) var isSensitiveToggled: Bool @NSManaged public private(set) var application: Application? @@ -432,14 +430,9 @@ extension Status: AutoUpdatableObject { self.spoilerText = spoilerText } } - public func update(isContentSensitiveToggled: Bool) { - if self.isContentSensitiveToggled != isContentSensitiveToggled { - self.isContentSensitiveToggled = isContentSensitiveToggled - } - } - public func update(isMediaSensitiveToggled: Bool) { - if self.isMediaSensitiveToggled != isMediaSensitiveToggled { - self.isMediaSensitiveToggled = isMediaSensitiveToggled + public func update(isSensitiveToggled: Bool) { + if self.isSensitiveToggled != isSensitiveToggled { + self.isSensitiveToggled = isSensitiveToggled } } public func update(reblogsCount: Int64) { diff --git a/MastodonSDK/Sources/MastodonUI/Extension/CoreDataStack/MastodonStatus.swift b/MastodonSDK/Sources/MastodonUI/Extension/CoreDataStack/MastodonStatus.swift new file mode 100644 index 000000000..b7d33712f --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/Extension/CoreDataStack/MastodonStatus.swift @@ -0,0 +1,28 @@ +// +// MastodonStatus.swift +// +// +// Created by MainasuK on 2022-4-18. +// + +import Foundation +import CoreDataStack + +extension Status { + + // mark content sensitive when status contains spoilerText + public var isContentSensitive: Bool { + if let spoilerText = spoilerText, !spoilerText.isEmpty { + return true + } else { + return false + } + } + + // mark media sensitive when `isContentSensitive` or media marked sensitive + public var isMediaSensitive: Bool { + // some servers set media sensitive even empty attachments + return isContentSensitive || (sensitive && !attachments.isEmpty) + } + +} diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift index 67cefa475..ea80a61d8 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift @@ -74,11 +74,9 @@ extension StatusView { // Sensitive @Published public var isContentSensitive: Bool = false - @Published public var isContentSensitiveToggled: Bool = false @Published public var isMediaSensitive: Bool = false - @Published public var isMediaSensitiveToggled: Bool = false - - @Published public var isSensitive: Bool = false // isContentSensitive || isMediaSensitive + @Published public var isSensitiveToggled = false + @Published public var isContentReveal: Bool = true @Published public var isMediaReveal: Bool = true @@ -130,9 +128,8 @@ extension StatusView { authorAvatarImageURL = nil isContentSensitive = false - isContentSensitiveToggled = false isMediaSensitive = false - isMediaSensitiveToggled = false + isSensitiveToggled = false activeFilters = [] filterContext = nil @@ -161,28 +158,18 @@ extension StatusView { $spoilerContent .map { $0 != nil } .assign(to: &$isContentSensitive) - // isSensitive - Publishers.CombineLatest( + // isReveal + Publishers.CombineLatest3( $isContentSensitive, - $isMediaSensitive - ) - .map { $0 || $1 } - .assign(to: &$isSensitive) - // $isContentReveal - Publishers.CombineLatest( - $isContentSensitive, - $isContentSensitiveToggled - ) - .map { $0 ? $1 : true } - .assign(to: &$isContentReveal) - // $isMediaReveal - Publishers.CombineLatest( $isMediaSensitive, - $isMediaSensitiveToggled + $isSensitiveToggled ) - .map { $1 ? !$0 : $0 } - .map { !$0 } - .assign(to: &$isMediaReveal) + .sink { [weak self] isContentSensitive, isMediaSensitive, isSensitiveToggled in + guard let self = self else { return } + self.isContentReveal = isContentSensitive ? isSensitiveToggled : true + self.isMediaReveal = isMediaSensitive ? isSensitiveToggled : true + } + .store(in: &disposeBag) } } } @@ -326,29 +313,22 @@ extension StatusView.ViewModel { } .store(in: &disposeBag) - $isSensitive + $isMediaSensitive .sink { isSensitive in guard isSensitive else { return } statusView.setContentSensitiveeToggleButtonDisplay() } .store(in: &disposeBag) - // There are 2 conditions: - // 1. The content may non-sensitive with sensitive media - // 2. The content and media both senstivie - Publishers.CombineLatest( - $isContentSensitiveToggled, - $isMediaSensitiveToggled - ) - .map { $0 || $1 } - .sink { isSensitiveToggled in - // The button indicator go-to state for button action direction - // eye: when media is hidden - // eye-slash: when media display - let image = isSensitiveToggled ? UIImage(systemName: "eye.slash.fill") : UIImage(systemName: "eye.fill") - statusView.contentSensitiveeToggleButton.setImage(image, for: .normal) - } - .store(in: &disposeBag) + $isSensitiveToggled + .sink { isSensitiveToggled in + // The button indicator go-to state for button action direction + // eye: when media is hidden + // eye-slash: when media display + let image = isSensitiveToggled ? UIImage(systemName: "eye.slash.fill") : UIImage(systemName: "eye.fill") + statusView.contentSensitiveeToggleButton.setImage(image, for: .normal) + } + .store(in: &disposeBag) } private func bindMedia(statusView: StatusView) { diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift index eb3a69354..7b96fe0b5 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift @@ -508,6 +508,7 @@ extension StatusView.Style { // status content statusView.contentContainer.addArrangedSubview(statusView.contentMetaText.textView) + statusView.containerStackView.setCustomSpacing(16, after: statusView.contentMetaText.textView) statusView.spoilerOverlayView.translatesAutoresizingMaskIntoConstraints = false statusView.containerStackView.addSubview(statusView.spoilerOverlayView) diff --git a/MastodonSDK/Sources/MastodonUI/View/Control/ActionToolbarContainer.swift b/MastodonSDK/Sources/MastodonUI/View/Control/ActionToolbarContainer.swift index 449254d20..c3a9b96f3 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Control/ActionToolbarContainer.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Control/ActionToolbarContainer.swift @@ -114,7 +114,7 @@ extension ActionToolbarContainer { container.addArrangedSubview(favoriteButton) container.addArrangedSubview(shareButton) NSLayoutConstraint.activate([ - replyButton.heightAnchor.constraint(equalToConstant: 44).priority(.defaultHigh), + replyButton.heightAnchor.constraint(equalToConstant: 36).priority(.defaultHigh), replyButton.heightAnchor.constraint(equalTo: reblogButton.heightAnchor).priority(.defaultHigh), replyButton.heightAnchor.constraint(equalTo: favoriteButton.heightAnchor).priority(.defaultHigh), replyButton.heightAnchor.constraint(equalTo: shareButton.heightAnchor).priority(.defaultHigh), diff --git a/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardView.swift b/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardView.swift index 320c1e903..a45e8ef6a 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Control/ProfileStatusDashboardView.swift @@ -75,9 +75,9 @@ extension ProfileStatusDashboardView { tapGestureRecognizer.addTarget(self, action: #selector(ProfileStatusDashboardView.tapGestureRecognizerHandler(_:))) meterView.addGestureRecognizer(tapGestureRecognizer) } - - followingDashboardMeterView.accessibilityHint = "Double tap to open the list" // TODO: i18n - followersDashboardMeterView.accessibilityHint = "Double tap to open the list" + + followingDashboardMeterView.accessibilityHint = L10n.Scene.Profile.Accessibility.doubleTapToOpenTheList + followersDashboardMeterView.accessibilityHint = L10n.Scene.Profile.Accessibility.doubleTapToOpenTheList } } From 41e1b75c62248c64349513bb969ab31462ec78db Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 18 Apr 2022 16:15:24 +0800 Subject: [PATCH 020/101] feat: add sensitive hint label for status media --- Localization/app.json | 1 + .../NotificationTimelineViewController.swift | 23 ++++++ .../Container/MediaGridContainerView.swift | 66 +++++------------ .../View/Content/StatusView+ViewModel.swift | 1 + .../Control/ContentWarningOverlayView.swift | 70 +++++-------------- 5 files changed, 61 insertions(+), 100 deletions(-) diff --git a/Localization/app.json b/Localization/app.json index 548c5adae..6c4aae7a9 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -129,6 +129,7 @@ "show_post": "Show Post", "show_user_profile": "Show user profile", "content_warning": "Content Warning", + "sensitive_content": "Sensitive Content", "media_content_warning": "Tap anywhere to reveal", "tap_to_reveal": "Tap to reveal", "poll": { diff --git a/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewController.swift b/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewController.swift index bdb4d05cb..16130251c 100644 --- a/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewController.swift +++ b/Mastodon/Scene/Notification/NotificationTimeline/NotificationTimelineViewController.swift @@ -39,6 +39,8 @@ final class NotificationTimelineViewController: UIViewController, NeedsDependenc return tableView }() + let cellFrameCache = NSCache() + deinit { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) } @@ -122,6 +124,16 @@ extension NotificationTimelineViewController { } +// MARK: - CellFrameCacheContainer +extension NotificationTimelineViewController: CellFrameCacheContainer { + func keyForCache(tableView: UITableView, indexPath: IndexPath) -> NSNumber? { + guard let diffableDataSource = viewModel.diffableDataSource else { return nil } + guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return nil } + let key = NSNumber(value: item.hashValue) + return key + } +} + extension NotificationTimelineViewController { @objc private func refreshControlValueChanged(_ sender: UIRefreshControl) { @@ -162,6 +174,13 @@ extension NotificationTimelineViewController: UITableViewDelegate, AutoGenerateT // sourcery:end + func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { + guard let frame = retrieveCellFrame(tableView: tableView, indexPath: indexPath) else { + return 300 + } + return ceil(frame.height) + } + func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { guard let item = viewModel.diffableDataSource?.itemIdentifier(for: indexPath) else { return @@ -172,6 +191,10 @@ extension NotificationTimelineViewController: UITableViewDelegate, AutoGenerateT await viewModel.loadMore(item: item) } } + + func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) { + cacheCellFrame(tableView: tableView, didEndDisplaying: cell, forRowAt: indexPath) + } } diff --git a/MastodonSDK/Sources/MastodonUI/View/Container/MediaGridContainerView.swift b/MastodonSDK/Sources/MastodonUI/View/Container/MediaGridContainerView.swift index cb9c53f35..e3359fb58 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Container/MediaGridContainerView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Container/MediaGridContainerView.swift @@ -48,22 +48,7 @@ public final class MediaGridContainerView: UIView { return mediaViews }() - -// let sensitiveToggleButtonBlurVisualEffectView: UIVisualEffectView = { -// let visualEffectView = UIVisualEffectView(effect: ContentWarningOverlayView.blurVisualEffect) -// visualEffectView.layer.masksToBounds = true -// visualEffectView.layer.cornerRadius = MediaGridContainerView.sensitiveToggleButtonSize.width / 2 -// visualEffectView.layer.cornerCurve = .continuous -// return visualEffectView -// }() -// let sensitiveToggleButtonVibrancyVisualEffectView = UIVisualEffectView(effect: UIVibrancyEffect(blurEffect: ContentWarningOverlayView.blurVisualEffect)) -// let sensitiveToggleButton: HitTestExpandedButton = { -// let button = HitTestExpandedButton(type: .system) -// button.contentEdgeInsets = UIEdgeInsets(top: 4, left: 4, bottom: 4, right: 4) -// button.imageView?.contentMode = .scaleAspectFit -// button.setImage(UIImage(systemName: "eye.slash.fill"), for: .normal) -// return button -// }() + let contentWarningOverlay = ContentWarningOverlayView() public override init(frame: CGRect) { super.init(frame: frame) @@ -86,7 +71,8 @@ public final class MediaGridContainerView: UIView { extension MediaGridContainerView { private func _init() { -// sensitiveToggleButton.addTarget(self, action: #selector(MediaGridContainerView.sensitiveToggleButtonDidPressed(_:)), for: .touchUpInside) + contentWarningOverlay.isUserInteractionEnabled = false + contentWarningOverlay.isHidden = true } } @@ -112,8 +98,8 @@ extension MediaGridContainerView { let mediaView = _mediaViews[0] layout.layout(in: self, mediaView: mediaView) -// layoutSensitiveToggleButton() -// bringSubviewToFront(sensitiveToggleButtonBlurVisualEffectView) + layoutContentWarningOverlay() + bringSubviewToFront(contentWarningOverlay) return mediaView } @@ -124,8 +110,8 @@ extension MediaGridContainerView { let mediaViews = Array(_mediaViews[0.. Date: Mon, 18 Apr 2022 16:56:29 +0800 Subject: [PATCH 021/101] fix: pick sever search bar accessible a11y issue --- .../xcshareddata/xcschemes/Mastodon.xcscheme | 8 -------- .../View/PickServerServerSectionTableHeaderView.swift | 6 +++--- .../MastodonUI/View/TableViewCell/NewsTableViewCell.swift | 5 +++++ 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon.xcscheme b/Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon.xcscheme index 048ce3cf5..488d5a2da 100644 --- a/Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon.xcscheme +++ b/Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon.xcscheme @@ -73,7 +73,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - enableAddressSanitizer = "YES" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" @@ -90,13 +89,6 @@ ReferencedContainer = "container:Mastodon.xcodeproj"> - - - - Int { guard let diffableDataSource = diffableDataSource else { return 0 } - return diffableDataSource.snapshot().itemIdentifiers.count + return diffableDataSource.snapshot().itemIdentifiers.count + 1 } override func accessibilityElement(at index: Int) -> Any? { - guard let item = collectionView.cellForItem(at: IndexPath(item: index, section: 0)) else { return nil } - return item + if let item = collectionView.cellForItem(at: IndexPath(item: index, section: 0)) { return item } + return searchTextField } } diff --git a/MastodonSDK/Sources/MastodonUI/View/TableViewCell/NewsTableViewCell.swift b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/NewsTableViewCell.swift index 3515000f9..f0b2aec8f 100644 --- a/MastodonSDK/Sources/MastodonUI/View/TableViewCell/NewsTableViewCell.swift +++ b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/NewsTableViewCell.swift @@ -51,6 +51,11 @@ extension NewsTableViewCell { separatorLine.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), separatorLine.heightAnchor.constraint(equalToConstant: UIView.separatorLineHeight(of: contentView)), ]) + + isAccessibilityElement = true + accessibilityElements = [ + newsView + ] } } From 03af68924ce36ed4e198025602f54f627ca1d375 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 18 Apr 2022 17:14:49 +0800 Subject: [PATCH 022/101] feat: add favicon for NewsView --- .../xcshareddata/swiftpm/Package.resolved | 18 ++++++++++++ MastodonSDK/Package.swift | 4 ++- .../View/Content/NewsView+Configuration.swift | 19 ++++++++++++ .../MastodonUI/View/Content/NewsView.swift | 29 +++++++++++++++++-- 4 files changed, 67 insertions(+), 3 deletions(-) diff --git a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved index 8dd69150f..53f6a3a4c 100644 --- a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -55,6 +55,15 @@ "version": "1.2.0" } }, + { + "package": "FaviconFinder", + "repositoryURL": "https://github.com/will-lumley/FaviconFinder.git", + "state": { + "branch": null, + "revision": "1f74844f77f79b95c0bb0130b3a87d4f340e6d3a", + "version": "3.3.0" + } + }, { "package": "FLAnimatedImage", "repositoryURL": "https://github.com/Flipboard/FLAnimatedImage.git", @@ -172,6 +181,15 @@ "version": "1.0.0" } }, + { + "package": "SwiftSoup", + "repositoryURL": "https://github.com/scinfu/SwiftSoup.git", + "state": { + "branch": null, + "revision": "41e7c263fb8c277e980ebcb9b0b5f6031d3d4886", + "version": "2.4.2" + } + }, { "package": "Introspect", "repositoryURL": "https://github.com/siteline/SwiftUI-Introspect.git", diff --git a/MastodonSDK/Package.swift b/MastodonSDK/Package.swift index ed4a13d55..8b007c2a6 100644 --- a/MastodonSDK/Package.swift +++ b/MastodonSDK/Package.swift @@ -37,7 +37,8 @@ let package = Package( .package(url: "https://github.com/Alamofire/AlamofireImage.git", from: "4.1.0"), .package(name: "NukeFLAnimatedImagePlugin", url: "https://github.com/kean/Nuke-FLAnimatedImage-Plugin.git", from: "8.0.0"), .package(name: "UITextView+Placeholder", url: "https://github.com/MainasuK/UITextView-Placeholder.git", from: "1.4.1"), - .package(name: "Introspect", url: "https://github.com/siteline/SwiftUI-Introspect.git", from: "0.1.3") + .package(name: "Introspect", url: "https://github.com/siteline/SwiftUI-Introspect.git", from: "0.1.3"), + .package(name: "FaviconFinder", url: "https://github.com/will-lumley/FaviconFinder.git", from: "3.2.2"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. @@ -95,6 +96,7 @@ let package = Package( .product(name: "AlamofireImage", package: "AlamofireImage"), .product(name: "MetaTextKit", package: "MetaTextKit"), .product(name: "FLAnimatedImage", package: "FLAnimatedImage"), + .product(name: "FaviconFinder", package: "FaviconFinder"), ] ), .testTarget( diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift b/MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift index e045eafe7..397982aaf 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift @@ -9,9 +9,28 @@ import UIKit import MastodonSDK import MastodonLocalization import AlamofireImage +import FaviconFinder extension NewsView { public func configure(link: Mastodon.Entity.Link) { + let faviconPlaceholder = UIImage(systemName: "network") + providerFaviconImageView.image = faviconPlaceholder + if let url = URL(string: link.url) { + let token = providerFaviconImageView.tag + FaviconFinder(url: url).downloadFavicon { [weak self] result in + guard let self = self else { return } + switch result { + case .success(let favicon): + DispatchQueue.main.async { [weak self] in + guard let self = self else { return } + guard self.providerFaviconImageView.tag == token else { return } + self.providerFaviconImageView.image = favicon.image + } + case .failure: + break + } + } + } providerNameLabel.text = link.providerName headlineLabel.text = link.title footnoteLabel.text = L10n.Plural.peopleTalking(link.talkingPeopleCount ?? 0) diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/NewsView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/NewsView.swift index ee9506a96..6d4cf3fd7 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/NewsView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/NewsView.swift @@ -12,6 +12,15 @@ public final class NewsView: UIView { let container = UIStackView() + let providerFaviconImageView: UIImageView = { + let imageView = UIImageView() + imageView.contentMode = .scaleAspectFit + imageView.layer.masksToBounds = true + imageView.layer.cornerRadius = 2 + imageView.layer.cornerCurve = .continuous + return imageView + }() + let providerNameLabel: UILabel = { let label = UILabel() label.font = UIFontMetrics(forTextStyle: .footnote).scaledFont(for: .systemFont(ofSize: 13, weight: .semibold)) @@ -37,6 +46,7 @@ public final class NewsView: UIView { let imageView = MediaView() public func prepareForReuse() { + providerFaviconImageView.tag = (0.. Date: Mon, 18 Apr 2022 17:18:24 +0800 Subject: [PATCH 023/101] fix: extend corner radius for ProfileCard avatar background --- .../Sources/MastodonUI/View/Content/ProfileCardView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift index 95424b7ee..ddc9afe41 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift @@ -181,7 +181,7 @@ extension ProfileCardView { avatarButtonBackgroundView.layer.masksToBounds = true avatarButtonBackgroundView.layer.cornerCurve = .continuous - avatarButtonBackgroundView.layer.cornerRadius = 12 + avatarButtonBackgroundView.layer.cornerRadius = 12 + 1 avatarButtonBackgroundView.translatesAutoresizingMaskIntoConstraints = false authorContainer.insertSubview(avatarButtonBackgroundView, belowSubview: avatarButton) NSLayoutConstraint.activate([ From 64640edd2b3ef0c466be5053418f0c4fdd1e2653 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 18 Apr 2022 17:44:19 +0800 Subject: [PATCH 024/101] feat: add ProfileCardView a11y supports --- .../Content/ProfileCardView+ViewModel.swift | 26 +++++++++++++++++++ .../View/Content/ProfileCardView.swift | 14 +++++++--- .../ProfileCardTableViewCell.swift | 6 +++++ 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+ViewModel.swift b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+ViewModel.swift index 99eb27a52..5b6c4c59c 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+ViewModel.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView+ViewModel.swift @@ -42,6 +42,8 @@ extension ProfileCardView { @Published public var isBlocking = false @Published public var isBlockedBy = false + @Published public var groupedAccessibilityLabel = "" + init() { backgroundColor = ThemeService.shared.currentTheme.value.systemBackgroundColor Publishers.CombineLatest( @@ -75,6 +77,7 @@ extension ProfileCardView.ViewModel { bindBio(view: view) bindRelationship(view: view) bindDashboard(view: view) + bindAccessibility(view: view) } private func bindAppearacne(view: ProfileCardView) { @@ -185,4 +188,27 @@ extension ProfileCardView.ViewModel { } .store(in: &disposeBag) } + + private func bindAccessibility(view: ProfileCardView) { + let authorAccessibilityLabel = Publishers.CombineLatest( + $authorName, + $bioContent + ) + .map { authorName, bioContent -> String? in + var strings: [String?] = [] + strings.append(authorName?.string) + strings.append(bioContent?.string) + return strings.compactMap { $0 }.joined(separator: ", ") + } + + authorAccessibilityLabel + .map { $0 ?? "" } + .assign(to: &$groupedAccessibilityLabel) + + $groupedAccessibilityLabel + .sink { accessibilityLabel in + view.accessibilityLabel = accessibilityLabel + } + .store(in: &disposeBag) + } } diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift index ddc9afe41..16351ebe1 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift @@ -204,6 +204,8 @@ extension ProfileCardView { let bioMetaTextAdaptiveMarginContainerView = AdaptiveMarginContainerView() bioMetaTextAdaptiveMarginContainerView.contentView = bioMetaText.textView bioMetaTextAdaptiveMarginContainerView.margin = ProfileCardView.contentMargin + bioMetaText.textView.setContentHuggingPriority(.required - 1, for: .vertical) + bioMetaText.textView.setContentCompressionResistancePriority(.required - 1, for: .vertical) container.addArrangedSubview(bioMetaTextAdaptiveMarginContainerView) container.setCustomSpacing(16, after: bioMetaTextAdaptiveMarginContainerView) @@ -218,6 +220,7 @@ extension ProfileCardView { infoContainer.addArrangedSubview(UIView()) let relationshipActionButtonShadowContainer = ShadowBackgroundContainer() infoContainer.addArrangedSubview(relationshipActionButtonShadowContainer) + updateInfoContainerLayout() relationshipActionButton.translatesAutoresizingMaskIntoConstraints = false relationshipActionButtonShadowContainer.addSubview(relationshipActionButton) @@ -227,7 +230,7 @@ extension ProfileCardView { relationshipActionButton.trailingAnchor.constraint(equalTo: relationshipActionButtonShadowContainer.trailingAnchor), relationshipActionButton.bottomAnchor.constraint(equalTo: relationshipActionButtonShadowContainer.bottomAnchor), relationshipActionButton.widthAnchor.constraint(greaterThanOrEqualToConstant: ProfileCardView.friendshipActionButtonSize.width).priority(.required - 1), - relationshipActionButton.heightAnchor.constraint(equalToConstant: ProfileCardView.friendshipActionButtonSize.height).priority(.required - 10), + relationshipActionButton.heightAnchor.constraint(equalToConstant: ProfileCardView.friendshipActionButtonSize.height).priority(.required - 2), ]) let bottomPadding = UIView() @@ -247,12 +250,17 @@ extension ProfileCardView { } public override func layoutSubviews() { + updateInfoContainerLayout() super.layoutSubviews() - + } + +} + +extension ProfileCardView { + private func updateInfoContainerLayout() { let isCompactAdaptive = bounds.width < 350 infoContainer.axis = isCompactAdaptive ? .vertical : .horizontal } - } extension ProfileCardView { diff --git a/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift index d3c8f223c..5961ad109 100644 --- a/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift +++ b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift @@ -70,6 +70,12 @@ extension ProfileCardTableViewCell { ]) profileCardView.delegate = self + + profileCardView.isAccessibilityElement = true + accessibilityElements = [ + profileCardView, + profileCardView.relationshipActionButton + ] } } From 5133ba3fcb34d85591121bbf4b7b0474654ae39f Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 18 Apr 2022 17:53:52 +0800 Subject: [PATCH 025/101] chore: update i18n resources --- .../Generated/Strings.swift | 12 ++++ .../Resources/ar.lproj/Localizable.strings | 4 ++ .../ar.lproj/Localizable.stringsdict | 60 +++++++++---------- .../Resources/ca.lproj/Localizable.strings | 46 +++++++------- .../Resources/de.lproj/Localizable.strings | 24 ++++---- .../de.lproj/Localizable.stringsdict | 4 +- .../Resources/en.lproj/Localizable.strings | 4 ++ .../es-419.lproj/Localizable.strings | 6 +- .../Resources/es.lproj/Localizable.strings | 4 ++ .../Resources/eu-ES.lproj/Localizable.strings | 28 +++++---- .../eu-ES.lproj/Localizable.stringsdict | 4 +- .../Resources/fr.lproj/Localizable.strings | 22 ++++--- .../fr.lproj/Localizable.stringsdict | 4 +- .../Resources/gd-GB.lproj/Localizable.strings | 4 ++ .../Resources/ja.lproj/Localizable.strings | 4 ++ .../Resources/kab.lproj/Localizable.strings | 4 ++ .../Resources/ku.lproj/Localizable.strings | 4 ++ .../Resources/nl.lproj/Localizable.strings | 4 ++ .../Resources/ru.lproj/Localizable.strings | 32 +++++----- .../Resources/sv_FI.lproj/Localizable.strings | 4 ++ .../Resources/th.lproj/Localizable.strings | 24 ++++---- .../th.lproj/Localizable.stringsdict | 2 +- .../Resources/vi.lproj/Localizable.strings | 12 ++-- .../zh-Hans.lproj/Localizable.strings | 24 ++++---- .../zh-Hans.lproj/Localizable.stringsdict | 2 +- 25 files changed, 212 insertions(+), 130 deletions(-) diff --git a/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift b/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift index 15d786efb..f2bec6b01 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift +++ b/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift @@ -543,6 +543,18 @@ public enum L10n { public static let title = L10n.tr("Localizable", "Scene.ConfirmEmail.OpenEmailApp.Title") } } + public enum Discovery { + public enum Tabs { + /// For You + public static let forYou = L10n.tr("Localizable", "Scene.Discovery.Tabs.ForYou") + /// Hashtags + public static let hashtags = L10n.tr("Localizable", "Scene.Discovery.Tabs.Hashtags") + /// News + public static let news = L10n.tr("Localizable", "Scene.Discovery.Tabs.News") + /// Posts + public static let posts = L10n.tr("Localizable", "Scene.Discovery.Tabs.Posts") + } + } public enum Favorite { /// Your Favorites public static let title = L10n.tr("Localizable", "Scene.Favorite.Title") diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings index f26554fe5..bf6ab09e6 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings @@ -201,6 +201,10 @@ "Scene.ConfirmEmail.Subtitle" = "لقد أرسلنا للتو بريد إلكتروني إلى %@، انقر على الرابط لتأكيد حسابك."; "Scene.ConfirmEmail.Title" = "شيءٌ أخير."; +"Scene.Discovery.Tabs.ForYou" = "For You"; +"Scene.Discovery.Tabs.Hashtags" = "الوسوم"; +"Scene.Discovery.Tabs.News" = "الأخبار"; +"Scene.Discovery.Tabs.Posts" = "المنشورات"; "Scene.Favorite.Title" = "مُفضَّلَتُك"; "Scene.Follower.Footer" = "لا يُمكِن عَرض المُتابِعين مِنَ الخوادم الأُخرى."; "Scene.Following.Footer" = "لا يُمكِن عَرض المُتابَعات مِنَ الخوادم الأُخرى."; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.stringsdict index 32782f1c0..c2f641720 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.stringsdict @@ -471,15 +471,15 @@ zero مُنذُ لَحظة one - مُنذُ سنة + مُنذُ %ldع two - مُنذُ سنتين + مُنذُ %ldع few - مُنذُ %ld سنين + مُنذُ %ldع many - مُنذُ %ld سنةً + مُنذُ %ldع other - مُنذُ %ld سنة + مُنذُ %ldع date.month.ago.abbr @@ -495,15 +495,15 @@ zero مُنذُ لَحظة one - مُنذُ شهر + مُنذُ %ldش two - مُنذُ شهرين + مُنذُ %ldش few - مُنذُ %ld أشهُر + مُنذُ %ldش many - مُنذُ %ld شهرًا + مُنذُ %ldش other - مُنذُ %ld شهر + مُنذُ %ldش date.day.ago.abbr @@ -519,15 +519,15 @@ zero مُنذُ لَحظة one - مُنذُ يوم + مُنذُ %ldي two - مُنذُ يومين + مُنذُ %ldي few - مُنذُ %ld أيام + مُنذُ %ldي many - مُنذُ %ld يومًا + مُنذُ %ldي other - مُنذُ %ld يوم + مُنذُ %ldي date.hour.ago.abbr @@ -543,15 +543,15 @@ zero مُنذُ لَحظة one - مُنذُ ساعة + مُنذُ %ldس two - مُنذُ ساعتين + مُنذُ %ldس few - مُنذُ %ld ساعات + مُنذُ %ldس many - مُنذُ %ld ساعةًَ + مُنذُ %ldس other - مُنذُ %ld ساعة + مُنذُ %ldس date.minute.ago.abbr @@ -567,15 +567,15 @@ zero مُنذُ لَحظة one - مُنذُ دقيقة + مُنذُ %ldد two - مُنذُ دقيقتان + مُنذُ %ldد few - مُنذُ %ld دقائق + مُنذُ %ldد many - مُنذُ %ld دقيقةً + مُنذُ %ldد other - مُنذُ %ld دقيقة + مُنذُ %ldد date.second.ago.abbr @@ -591,15 +591,15 @@ zero مُنذُ لَحظة one - مُنذُ ثانية + مُنذُ %ldث two - مُنذُ ثانيتين + مُنذُ %ldث few - مُنذُ %ld ثوان + مُنذُ %ldث many - مُنذُ %ld ثانية + مُنذُ %ldث other - مُنذُ %ld ثانية + مُنذُ %ldث diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings index 0cb63f34b..4e10ce165 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings @@ -5,7 +5,7 @@ "Common.Alerts.Common.PleaseTryAgain" = "Si us plau intenta-ho de nou."; "Common.Alerts.Common.PleaseTryAgainLater" = "Si us plau, prova-ho més tard."; "Common.Alerts.DeletePost.Message" = "Estàs segur que vols suprimir aquesta publicació?"; -"Common.Alerts.DeletePost.Title" = "Estàs segur que vols suprimir aquesta publicació?"; +"Common.Alerts.DeletePost.Title" = "Esborrar Publicació"; "Common.Alerts.DiscardPostContent.Message" = "Confirma per a descartar el contingut de la publicació composta."; "Common.Alerts.DiscardPostContent.Title" = "Descarta l'esborrany"; "Common.Alerts.EditProfileFailure.Message" = "No es pot editar el perfil. Si us plau torna-ho a provar."; @@ -16,7 +16,7 @@ Comprova la teva connexió a Internet."; "Common.Alerts.PublishPostFailure.Title" = "Error de Publicació"; "Common.Alerts.SavePhotoFailure.Message" = "Activa el permís d'accés a la biblioteca de fotos per desar-la."; -"Common.Alerts.SavePhotoFailure.Title" = "Desa l'Error de la Foto"; +"Common.Alerts.SavePhotoFailure.Title" = "Error al Desar la Foto"; "Common.Alerts.ServerError.Title" = "Error del Servidor"; "Common.Alerts.SignOut.Confirm" = "Tancar Sessió"; "Common.Alerts.SignOut.Message" = "Estàs segur que vols tancar la sessió?"; @@ -36,7 +36,7 @@ Comprova la teva connexió a Internet."; "Common.Controls.Actions.Discard" = "Descarta"; "Common.Controls.Actions.Done" = "Fet"; "Common.Controls.Actions.Edit" = "Edita"; -"Common.Controls.Actions.FindPeople" = "Busca persones per seguir"; +"Common.Controls.Actions.FindPeople" = "Busca persones a seguir"; "Common.Controls.Actions.ManuallySearch" = "Cerca manualment a canvi"; "Common.Controls.Actions.Next" = "Següent"; "Common.Controls.Actions.Ok" = "D'acord"; @@ -81,18 +81,18 @@ Comprova la teva connexió a Internet."; "Common.Controls.Keyboard.Common.OpenSettings" = "Obre la configuració"; "Common.Controls.Keyboard.Common.ShowFavorites" = "Mostra els Favorits"; "Common.Controls.Keyboard.Common.SwitchToTab" = "Canviar a %@"; -"Common.Controls.Keyboard.SegmentedControl.NextSection" = "Secció següent"; -"Common.Controls.Keyboard.SegmentedControl.PreviousSection" = "Secció anterior"; +"Common.Controls.Keyboard.SegmentedControl.NextSection" = "Secció Següent"; +"Common.Controls.Keyboard.SegmentedControl.PreviousSection" = "Secció Anterior"; "Common.Controls.Keyboard.Timeline.NextStatus" = "Publicació següent"; -"Common.Controls.Keyboard.Timeline.OpenAuthorProfile" = "Obre el perfil de l'autor"; -"Common.Controls.Keyboard.Timeline.OpenRebloggerProfile" = "Obre el perfil del impulsor"; +"Common.Controls.Keyboard.Timeline.OpenAuthorProfile" = "Obre el Perfil de l'Autor"; +"Common.Controls.Keyboard.Timeline.OpenRebloggerProfile" = "Obre el Perfil del Impulsor"; "Common.Controls.Keyboard.Timeline.OpenStatus" = "Obre la publicació"; "Common.Controls.Keyboard.Timeline.PreviewImage" = "Vista prèvia de l'Imatge"; "Common.Controls.Keyboard.Timeline.PreviousStatus" = "Publicació anterior"; -"Common.Controls.Keyboard.Timeline.ReplyStatus" = "Respon a la publicació"; +"Common.Controls.Keyboard.Timeline.ReplyStatus" = "Respon a la Publicació"; "Common.Controls.Keyboard.Timeline.ToggleContentWarning" = "Commuta l'Avís de Contingut"; -"Common.Controls.Keyboard.Timeline.ToggleFavorite" = "Commuta el Favorit de la publicació"; -"Common.Controls.Keyboard.Timeline.ToggleReblog" = "Commuta l'impuls de la publicació"; +"Common.Controls.Keyboard.Timeline.ToggleFavorite" = "Commuta el Favorit de la Publicació"; +"Common.Controls.Keyboard.Timeline.ToggleReblog" = "Commuta l'Impuls de la Publicació"; "Common.Controls.Status.Actions.Favorite" = "Favorit"; "Common.Controls.Status.Actions.Hide" = "Amaga"; "Common.Controls.Status.Actions.Menu" = "Menú"; @@ -105,10 +105,10 @@ Comprova la teva connexió a Internet."; "Common.Controls.Status.Actions.Unfavorite" = "Desfer Favorit"; "Common.Controls.Status.Actions.Unreblog" = "Desfer l'impuls"; "Common.Controls.Status.ContentWarning" = "Advertència de Contingut"; -"Common.Controls.Status.MediaContentWarning" = "Toca qualsevol lloc per mostrar"; +"Common.Controls.Status.MediaContentWarning" = "Toca qualsevol lloc per a mostrar"; "Common.Controls.Status.Poll.Closed" = "Finalitzada"; "Common.Controls.Status.Poll.Vote" = "Vota"; -"Common.Controls.Status.ShowPost" = "Mostra la publicació"; +"Common.Controls.Status.ShowPost" = "Mostra la Publicació"; "Common.Controls.Status.ShowUserProfile" = "Mostra el perfil de l'usuari"; "Common.Controls.Status.Tag.Email" = "Correu electrònic"; "Common.Controls.Status.Tag.Emoji" = "Emoji"; @@ -129,7 +129,7 @@ Comprova la teva connexió a Internet."; "Common.Controls.Tabs.Search" = "Cerca"; "Common.Controls.Timeline.Filtered" = "Filtrat"; "Common.Controls.Timeline.Header.BlockedWarning" = "No pots veure el perfil d'aquest usuari - fins que et desbloquegi."; +fins que et desbloquegi."; "Common.Controls.Timeline.Header.BlockingWarning" = "No pots veure el perfil d'aquest usuari fins que el desbloquegis. El teu perfil els sembla així."; @@ -141,8 +141,8 @@ El teu perfil els sembla així."; fins que el desbloquegis. El teu perfil els sembla així."; "Common.Controls.Timeline.Header.UserSuspendedWarning" = "El compte de %@ ha estat suspès."; -"Common.Controls.Timeline.Loader.LoadMissingPosts" = "Carrega les publicacions que falten"; -"Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Carregant les publicacions que falten..."; +"Common.Controls.Timeline.Loader.LoadMissingPosts" = "Carrega les publicacions faltants"; +"Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Carregant les publicacions faltants..."; "Common.Controls.Timeline.Loader.ShowMoreReplies" = "Mostra més respostes"; "Common.Controls.Timeline.Timestamp.Now" = "Ara"; "Scene.AccountList.AddAccount" = "Afegir compte"; @@ -198,9 +198,12 @@ carregat a Mastodon."; "Scene.ConfirmEmail.OpenEmailApp.Mail" = "Correu electrònic"; "Scene.ConfirmEmail.OpenEmailApp.OpenEmailClient" = "Obre el Client de Correu electrònic"; "Scene.ConfirmEmail.OpenEmailApp.Title" = "Comprova la teva safata d'entrada."; -"Scene.ConfirmEmail.Subtitle" = "Acabem d'enviar un correu electrònic a %@, -toca l'enllaç per a confirmar el teu compte."; +"Scene.ConfirmEmail.Subtitle" = "Toca l'enllaç del correu electrònic que t'hem enviat per a confirmar el teu compte."; "Scene.ConfirmEmail.Title" = "Una última cosa."; +"Scene.Discovery.Tabs.ForYou" = "Per a tu"; +"Scene.Discovery.Tabs.Hashtags" = "Etiquetes"; +"Scene.Discovery.Tabs.News" = "Notícies"; +"Scene.Discovery.Tabs.Posts" = "Publicacions"; "Scene.Favorite.Title" = "Els teus Favorits"; "Scene.Follower.Footer" = "Els seguidors d'altres servidors no son mostrats."; "Scene.Following.Footer" = "Els seguits d'altres servidors no son mostrats."; @@ -263,7 +266,7 @@ toca l'enllaç per a confirmar el teu compte."; "Scene.Register.Error.Reason.Unreachable" = "%@ sembla que no existeix"; "Scene.Register.Error.Special.EmailInvalid" = "Aquesta no és una adreça de correu electrònic vàlida"; "Scene.Register.Error.Special.PasswordTooShort" = "La contrasenya és massa curta (ha de tenir 8 caràcters com a mínim)"; -"Scene.Register.Error.Special.UsernameInvalid" = "El nom d'usuari només ha de contenir caràcters alfanumèrics i guions baixos"; +"Scene.Register.Error.Special.UsernameInvalid" = "El nom d'usuari ha de contenir només caràcters alfanumèrics i guions baixos"; "Scene.Register.Error.Special.UsernameTooLong" = "El nom d'usuari és massa llarg (no pot ser més llarg de 30 caràcters)"; "Scene.Register.Input.Avatar.Delete" = "Suprimeix"; "Scene.Register.Input.DisplayName.Placeholder" = "nom visible"; @@ -272,7 +275,7 @@ toca l'enllaç per a confirmar el teu compte."; "Scene.Register.Input.Password.Accessibility.Checked" = "verificat"; "Scene.Register.Input.Password.Accessibility.Unchecked" = "no verificat"; "Scene.Register.Input.Password.CharacterLimit" = "8 caràcters"; -"Scene.Register.Input.Password.Hint" = "La teva contrasenya ha de tenir com a mínim buit caràcters"; +"Scene.Register.Input.Password.Hint" = "La teva contrasenya ha de tenir com a mínim vuit caràcters"; "Scene.Register.Input.Password.Placeholder" = "contrasenya"; "Scene.Register.Input.Password.Require" = "La teva contrasenya com a mínim necessita:"; "Scene.Register.Input.Username.DuplicatePrompt" = "Aquest nom d'usuari ja està en ús."; @@ -331,8 +334,7 @@ toca l'enllaç per a confirmar el teu compte."; "Scene.ServerPicker.Label.Users" = "USUARIS"; "Scene.ServerPicker.Subtitle" = "Tria una comunitat segons els teus interessos, regió o una de propòsit general."; "Scene.ServerPicker.SubtitleExtend" = "Tria una comunitat segons els teus interessos, regió o una de propòsit general. Cada comunitat és operada per una organització totalment independent o individualment."; -"Scene.ServerPicker.Title" = "Tria un servidor, -qualsevol servidor."; +"Scene.ServerPicker.Title" = "Mastodon està fet d'usuaris en diferents comunitats."; "Scene.ServerRules.Button.Confirm" = "Hi estic d'acord"; "Scene.ServerRules.PrivacyPolicy" = "política de privadesa"; "Scene.ServerRules.Prompt" = "Al continuar, estàs subjecte als termes de servei i a la política de privacitat de %@."; @@ -362,7 +364,7 @@ qualsevol servidor."; "Scene.Settings.Section.Notifications.Trigger.Anyone" = "algú"; "Scene.Settings.Section.Notifications.Trigger.Follow" = "a qualsevol que segueixi"; "Scene.Settings.Section.Notifications.Trigger.Follower" = "un seguidor"; -"Scene.Settings.Section.Notifications.Trigger.Noone" = "algú"; +"Scene.Settings.Section.Notifications.Trigger.Noone" = "ningú"; "Scene.Settings.Section.Notifications.Trigger.Title" = "Notifica'm quan"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Desactiva avatars animats"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Desactiva emojis animats"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings index 325b1e949..06f5eedff 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings @@ -98,10 +98,10 @@ Bitte überprüfe deine Internetverbindung."; "Common.Controls.Status.Actions.Menu" = "Menü"; "Common.Controls.Status.Actions.Reblog" = "Teilen"; "Common.Controls.Status.Actions.Reply" = "Antworten"; -"Common.Controls.Status.Actions.ShowGif" = "Show GIF"; -"Common.Controls.Status.Actions.ShowImage" = "Show image"; -"Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; -"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tap then hold to show menu"; +"Common.Controls.Status.Actions.ShowGif" = "GIF anzeigen"; +"Common.Controls.Status.Actions.ShowImage" = "Bild anzeigen"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Zeige Video-Player"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Halte gedrückt um das Menü anzuzeigen"; "Common.Controls.Status.Actions.Unfavorite" = "Aus Favoriten entfernen"; "Common.Controls.Status.Actions.Unreblog" = "Nicht mehr teilen"; "Common.Controls.Status.ContentWarning" = "Inhaltswarnung"; @@ -116,7 +116,7 @@ Bitte überprüfe deine Internetverbindung."; "Common.Controls.Status.Tag.Link" = "Link"; "Common.Controls.Status.Tag.Mention" = "Erwähnung"; "Common.Controls.Status.Tag.Url" = "URL"; -"Common.Controls.Status.TapToReveal" = "Tap to reveal"; +"Common.Controls.Status.TapToReveal" = "Zum Anzeigen tippen"; "Common.Controls.Status.UserReblogged" = "%@ teilte"; "Common.Controls.Status.UserRepliedTo" = "Antwortet auf %@"; "Common.Controls.Status.Visibility.Direct" = "Nur erwähnte Benutzer können diesen Beitrag sehen."; @@ -201,6 +201,10 @@ kann nicht auf Mastodon hochgeladen werden."; "Scene.ConfirmEmail.Subtitle" = "Wir haben gerade eine E-Mail an %@ gesendet, tippe darin auf den Link, um Dein Konto zu bestätigen."; "Scene.ConfirmEmail.Title" = "Noch eine letzte Sache."; +"Scene.Discovery.Tabs.ForYou" = "Für dich"; +"Scene.Discovery.Tabs.Hashtags" = "Hashtags"; +"Scene.Discovery.Tabs.News" = "Nachrichten"; +"Scene.Discovery.Tabs.Posts" = "Beiträge"; "Scene.Favorite.Title" = "Deine Favoriten"; "Scene.Follower.Footer" = "Follower von anderen Servern werden nicht angezeigt."; "Scene.Following.Footer" = "Wem das Konto folgt wird von anderen Servern werden nicht angezeigt."; @@ -222,10 +226,10 @@ tippe darin auf den Link, um Dein Konto zu bestätigen."; "Scene.Preview.Keyboard.ClosePreview" = "Vorschau schließen"; "Scene.Preview.Keyboard.ShowNext" = "Nächstes anzeigen"; "Scene.Preview.Keyboard.ShowPrevious" = "Vorheriges anzeigen"; -"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Double tap to open the list"; -"Scene.Profile.Accessibility.EditAvatarImage" = "Edit avatar image"; -"Scene.Profile.Accessibility.ShowAvatarImage" = "Show avatar image"; -"Scene.Profile.Accessibility.ShowBannerImage" = "Show banner image"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Doppeltippen, um die Liste zu öffnen"; +"Scene.Profile.Accessibility.EditAvatarImage" = "Profilbild bearbeiten"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "Profilbild anzeigen"; +"Scene.Profile.Accessibility.ShowBannerImage" = "Bannerbild anzeigen"; "Scene.Profile.Dashboard.Followers" = "Folger"; "Scene.Profile.Dashboard.Following" = "Gefolgte"; "Scene.Profile.Dashboard.Posts" = "Beiträge"; @@ -366,7 +370,7 @@ beliebigen Server."; "Scene.Settings.Section.Notifications.Trigger.Title" = "Benachrichtige mich, wenn"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Animierte Profilbilder deaktivieren"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Animierte Emojis deaktivieren"; -"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Open links in Mastodon"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Links in Mastodon öffnen"; "Scene.Settings.Section.Preference.Title" = "Präferenzen"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "Vollständig dunkler Dunkelmodus"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Standardbrowser zum Öffnen von Links verwenden"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.stringsdict index cd7218623..20e8b615e 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.stringsdict @@ -125,9 +125,9 @@ NSStringFormatValueTypeKey ld one - 1 reply + 1 Antwort other - %ld replies + %ld Antworten plural.count.vote diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings index 285c185bc..4edf4702f 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings @@ -200,6 +200,10 @@ uploaded to Mastodon."; "Scene.ConfirmEmail.OpenEmailApp.Title" = "Check your inbox."; "Scene.ConfirmEmail.Subtitle" = "Tap the link we emailed to you to verify your account."; "Scene.ConfirmEmail.Title" = "One last thing."; +"Scene.Discovery.Tabs.ForYou" = "For You"; +"Scene.Discovery.Tabs.Hashtags" = "Hashtags"; +"Scene.Discovery.Tabs.News" = "News"; +"Scene.Discovery.Tabs.Posts" = "Posts"; "Scene.Favorite.Title" = "Your Favorites"; "Scene.Follower.Footer" = "Followers from other servers are not displayed."; "Scene.Following.Footer" = "Follows from other servers are not displayed."; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.strings index f3670fb6b..0782206f4 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.strings @@ -5,7 +5,7 @@ "Common.Alerts.Common.PleaseTryAgain" = "Por favor, intentá de nuevo."; "Common.Alerts.Common.PleaseTryAgainLater" = "Por favor, intentá de nuevo más tarde."; "Common.Alerts.DeletePost.Message" = "¿Estás seguro que querés eliminar este mensaje?"; -"Common.Alerts.DeletePost.Title" = "¿Estás seguro que querés eliminar este mensaje?"; +"Common.Alerts.DeletePost.Title" = "Eliminar mensaje"; "Common.Alerts.DiscardPostContent.Message" = "Confirmá para descartar el contenido del mensaje redactado."; "Common.Alerts.DiscardPostContent.Title" = "Descartar borrador"; "Common.Alerts.EditProfileFailure.Message" = "No se pudo editar el perfil. Por favor, intentá de nuevo."; @@ -201,6 +201,10 @@ y no se puede subir a Mastodon."; "Scene.ConfirmEmail.Subtitle" = "Acabamos de enviar un correo electrónico a %@, pulsá en el enlace para confirmar tu cuenta."; "Scene.ConfirmEmail.Title" = "Una última cosa."; +"Scene.Discovery.Tabs.ForYou" = "Para vos"; +"Scene.Discovery.Tabs.Hashtags" = "Etiquetas"; +"Scene.Discovery.Tabs.News" = "Novedades"; +"Scene.Discovery.Tabs.Posts" = "Mensajes"; "Scene.Favorite.Title" = "Tus favoritos"; "Scene.Follower.Footer" = "No se muestran los seguidores de otros servidores."; "Scene.Following.Footer" = "No se muestran las cuentas de otros servidores que seguís."; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.strings index 4cbebb3e5..544a0b86c 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.strings @@ -201,6 +201,10 @@ subirse a Mastodon."; "Scene.ConfirmEmail.Subtitle" = "Te acabamos de enviar un correo a %@, pulsa en el enlace para confirmar tu cuenta."; "Scene.ConfirmEmail.Title" = "Una última cosa."; +"Scene.Discovery.Tabs.ForYou" = "For You"; +"Scene.Discovery.Tabs.Hashtags" = "Hashtags"; +"Scene.Discovery.Tabs.News" = "News"; +"Scene.Discovery.Tabs.Posts" = "Posts"; "Scene.Favorite.Title" = "Tus Favoritos"; "Scene.Follower.Footer" = "No se muestran los seguidores de otros servidores."; "Scene.Following.Footer" = "No se muestran los seguidos de otros servidores."; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.strings index 341f4862a..42b3bfb6c 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.strings @@ -98,10 +98,10 @@ Egiaztatu Interneteko konexioa."; "Common.Controls.Status.Actions.Menu" = "Menua"; "Common.Controls.Status.Actions.Reblog" = "Bultzada"; "Common.Controls.Status.Actions.Reply" = "Erantzun"; -"Common.Controls.Status.Actions.ShowGif" = "Show GIF"; -"Common.Controls.Status.Actions.ShowImage" = "Show image"; -"Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; -"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tap then hold to show menu"; +"Common.Controls.Status.Actions.ShowGif" = "Erakutsi GIFa"; +"Common.Controls.Status.Actions.ShowImage" = "Erakutsi irudia"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Erakutsi bideo-erreproduzigailua"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Sakatu eta eutsi menua erakusteko"; "Common.Controls.Status.Actions.Unfavorite" = "Kendu gogokoa"; "Common.Controls.Status.Actions.Unreblog" = "Desegin bultzada"; "Common.Controls.Status.ContentWarning" = "Edukiaren abisua"; @@ -116,7 +116,7 @@ Egiaztatu Interneteko konexioa."; "Common.Controls.Status.Tag.Link" = "Esteka"; "Common.Controls.Status.Tag.Mention" = "Aipatu"; "Common.Controls.Status.Tag.Url" = "URLa"; -"Common.Controls.Status.TapToReveal" = "Tap to reveal"; +"Common.Controls.Status.TapToReveal" = "Sakatu erakusteko"; "Common.Controls.Status.UserReblogged" = "%@ erabiltzaileak bultzada eman dio"; "Common.Controls.Status.UserRepliedTo" = "%@(r)i erantzuten"; "Common.Controls.Status.Visibility.Direct" = "Aipatutako erabiltzaileek soilik ikus dezakete bidalketa hau."; @@ -201,6 +201,10 @@ Mastodonera igo."; "Scene.ConfirmEmail.Subtitle" = "Eposta bat bidali dizugu %@ helbidera, sakatu kontua berresteko esteka."; "Scene.ConfirmEmail.Title" = "Eta azkenik..."; +"Scene.Discovery.Tabs.ForYou" = "For You"; +"Scene.Discovery.Tabs.Hashtags" = "Hashtags"; +"Scene.Discovery.Tabs.News" = "News"; +"Scene.Discovery.Tabs.Posts" = "Posts"; "Scene.Favorite.Title" = "Zure gogokoak"; "Scene.Follower.Footer" = "Beste zerbitzarietako jarraitzaileak ez dira bistaratzen."; "Scene.Following.Footer" = "Beste zerbitzarietan jarraitutakoak ez dira bistaratzen."; @@ -211,21 +215,21 @@ sakatu kontua berresteko esteka."; "Scene.HomeTimeline.Title" = "Hasiera"; "Scene.Notification.Keyobard.ShowEverything" = "Erakutsi guztia"; "Scene.Notification.Keyobard.ShowMentions" = "Erakutsi aipamenak"; -"Scene.Notification.NotificationDescription.FavoritedYourPost" = "erabiltzaileak zure bidalketa gogoko du"; +"Scene.Notification.NotificationDescription.FavoritedYourPost" = "(e)k zure bidalketa gogoko du"; "Scene.Notification.NotificationDescription.FollowedYou" = "zu jarraitzen hasi da"; "Scene.Notification.NotificationDescription.MentionedYou" = "erabiltzaileak aipatu zaitu"; "Scene.Notification.NotificationDescription.PollHasEnded" = "inkesta amaitu da"; -"Scene.Notification.NotificationDescription.RebloggedYourPost" = "erabiltzaileak bultzada eman dio zure bidalketari"; +"Scene.Notification.NotificationDescription.RebloggedYourPost" = "(e)k bultzada eman dio zure bidalketari"; "Scene.Notification.NotificationDescription.RequestToFollowYou" = "erabiltzaileak zu jarraitzea eskatu du"; "Scene.Notification.Title.Everything" = "Dena"; "Scene.Notification.Title.Mentions" = "Aipamenak"; "Scene.Preview.Keyboard.ClosePreview" = "Itxi aurrebista"; "Scene.Preview.Keyboard.ShowNext" = "Erakutsi hurrengoa"; "Scene.Preview.Keyboard.ShowPrevious" = "Erakutsi aurrekoa"; -"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Double tap to open the list"; -"Scene.Profile.Accessibility.EditAvatarImage" = "Edit avatar image"; -"Scene.Profile.Accessibility.ShowAvatarImage" = "Show avatar image"; -"Scene.Profile.Accessibility.ShowBannerImage" = "Show banner image"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Sakatu birritan zerrenda irekitzeko"; +"Scene.Profile.Accessibility.EditAvatarImage" = "Editatu abatarra"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "Erakutsi abatarra"; +"Scene.Profile.Accessibility.ShowBannerImage" = "Erakutsi banner irudia"; "Scene.Profile.Dashboard.Followers" = "jarraitzaile"; "Scene.Profile.Dashboard.Following" = "jarraitzen"; "Scene.Profile.Dashboard.Posts" = "bidalketa"; @@ -366,7 +370,7 @@ edozein zerbitzari."; "Scene.Settings.Section.Notifications.Trigger.Title" = "Noiz jakinarazi:"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Desgaitu abatar animatuak"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Desgaitu emoji animatuak"; -"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Open links in Mastodon"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Ireki estekak Mastodonen"; "Scene.Settings.Section.Preference.Title" = "Hobespenak"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "Benetako modu beltz iluna"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Erabili nabigatzaile lehenetsia estekak irekitzeko"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.stringsdict index 2069e27a3..871fb10bc 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.stringsdict @@ -125,9 +125,9 @@ NSStringFormatValueTypeKey ld one - 1 reply + Erantzun bat other - %ld replies + %ld erantzun plural.count.vote diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.strings index 69aa3172a..0ed3a271a 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.strings @@ -98,9 +98,9 @@ Veuillez vérifier votre accès à Internet."; "Common.Controls.Status.Actions.Menu" = "Menu"; "Common.Controls.Status.Actions.Reblog" = "Rebloguer"; "Common.Controls.Status.Actions.Reply" = "Répondre"; -"Common.Controls.Status.Actions.ShowGif" = "Show GIF"; -"Common.Controls.Status.Actions.ShowImage" = "Show image"; -"Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; +"Common.Controls.Status.Actions.ShowGif" = "Afficher le GIF"; +"Common.Controls.Status.Actions.ShowImage" = "Afficher l’image"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Afficher le lecteur vidéo"; "Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tap then hold to show menu"; "Common.Controls.Status.Actions.Unfavorite" = "Retirer des favoris"; "Common.Controls.Status.Actions.Unreblog" = "Annuler le reblog"; @@ -116,7 +116,7 @@ Veuillez vérifier votre accès à Internet."; "Common.Controls.Status.Tag.Link" = "Lien"; "Common.Controls.Status.Tag.Mention" = "Mention"; "Common.Controls.Status.Tag.Url" = "URL"; -"Common.Controls.Status.TapToReveal" = "Tap to reveal"; +"Common.Controls.Status.TapToReveal" = "Appuyer pour afficher"; "Common.Controls.Status.UserReblogged" = "%@ a reblogué"; "Common.Controls.Status.UserRepliedTo" = "À répondu à %@"; "Common.Controls.Status.Visibility.Direct" = "Seul·e l’utilisateur·rice mentionnée peut voir ce message."; @@ -201,6 +201,10 @@ téléversé sur Mastodon."; "Scene.ConfirmEmail.Subtitle" = "Nous venons d’envoyer un courriel à %@, tapotez le lien pour confirmer votre compte."; "Scene.ConfirmEmail.Title" = "Une dernière chose."; +"Scene.Discovery.Tabs.ForYou" = "Pour vous"; +"Scene.Discovery.Tabs.Hashtags" = "Hashtags"; +"Scene.Discovery.Tabs.News" = "Actualité"; +"Scene.Discovery.Tabs.Posts" = "Messages"; "Scene.Favorite.Title" = "Vos favoris"; "Scene.Follower.Footer" = "Les abonné·e·s issus des autres serveurs ne sont pas affiché·e·s."; "Scene.Following.Footer" = "Les abonnés issus des autres serveurs ne sont pas affichés."; @@ -222,10 +226,10 @@ tapotez le lien pour confirmer votre compte."; "Scene.Preview.Keyboard.ClosePreview" = "Fermer l'aperçu"; "Scene.Preview.Keyboard.ShowNext" = "Afficher le suivant"; "Scene.Preview.Keyboard.ShowPrevious" = "Afficher le précédent"; -"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Double tap to open the list"; -"Scene.Profile.Accessibility.EditAvatarImage" = "Edit avatar image"; -"Scene.Profile.Accessibility.ShowAvatarImage" = "Show avatar image"; -"Scene.Profile.Accessibility.ShowBannerImage" = "Show banner image"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Appuyer deux fois pour ouvrir la liste"; +"Scene.Profile.Accessibility.EditAvatarImage" = "Modifier l’avatar"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "Afficher l’avatar"; +"Scene.Profile.Accessibility.ShowBannerImage" = "Afficher l’image de la bannière"; "Scene.Profile.Dashboard.Followers" = "abonnés"; "Scene.Profile.Dashboard.Following" = "abonnements"; "Scene.Profile.Dashboard.Posts" = "publications"; @@ -366,7 +370,7 @@ n'importe quel serveur."; "Scene.Settings.Section.Notifications.Trigger.Title" = "Me notifier lorsque"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Désactiver les avatars animés"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Désactiver les émojis animées"; -"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Open links in Mastodon"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Ouvrir les liens dans Mastodon"; "Scene.Settings.Section.Preference.Title" = "Préférences"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "Vrai mode sombre"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Utiliser le navigateur par défaut pour ouvrir les liens"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.stringsdict index 93ee696f2..5c2b14978 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.stringsdict @@ -125,9 +125,9 @@ NSStringFormatValueTypeKey ld one - 1 reply + 1 réponse other - %ld replies + %ld réponses plural.count.vote diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.strings index 9e4ab6029..91bc13736 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.strings @@ -201,6 +201,10 @@ a luchdadh suas gu Mastodon."; "Scene.ConfirmEmail.Subtitle" = "Tha sinn air post-d a chur gu %@, thoir gnogag air a’ chunntas a dhearbhadh a’ chunntais agad."; "Scene.ConfirmEmail.Title" = "Aon rud eile."; +"Scene.Discovery.Tabs.ForYou" = "For You"; +"Scene.Discovery.Tabs.Hashtags" = "Hashtags"; +"Scene.Discovery.Tabs.News" = "News"; +"Scene.Discovery.Tabs.Posts" = "Posts"; "Scene.Favorite.Title" = "Na h-annsachdan agad"; "Scene.Follower.Footer" = "Cha dèid luchd-leantainn o fhrithealaichean eile a shealltainn."; "Scene.Following.Footer" = "Cha dèid cò air a leanas tu air frithealaichean eile a shealltainn."; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings index a8164db9d..339e23f1c 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings @@ -195,6 +195,10 @@ "Scene.ConfirmEmail.OpenEmailApp.Title" = "メールを確認"; "Scene.ConfirmEmail.Subtitle" = "先程 %@ にメールを送信しました。リンクをタップしてアカウントを確認してください。"; "Scene.ConfirmEmail.Title" = "さいごにもうひとつ。"; +"Scene.Discovery.Tabs.ForYou" = "For You"; +"Scene.Discovery.Tabs.Hashtags" = "Hashtags"; +"Scene.Discovery.Tabs.News" = "News"; +"Scene.Discovery.Tabs.Posts" = "Posts"; "Scene.Favorite.Title" = "お気に入り"; "Scene.Follower.Footer" = "他のサーバーからのフォロワーは表示されません。"; "Scene.Following.Footer" = "他のサーバーにいるフォローは表示されません。"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.strings index 55b8a3a62..792cf3681 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.strings @@ -200,6 +200,10 @@ Ad d-yettwasali ɣef Mastodon."; "Scene.ConfirmEmail.OpenEmailApp.Title" = "Sefqed Tanaka-inek."; "Scene.ConfirmEmail.Subtitle" = "Sit ɣef useɣwen i ak-n-uznen i wakken ad tesneqdeḍ amiḍan-ik."; "Scene.ConfirmEmail.Title" = "Taɣawsa taneggarut."; +"Scene.Discovery.Tabs.ForYou" = "For You"; +"Scene.Discovery.Tabs.Hashtags" = "Hashtags"; +"Scene.Discovery.Tabs.News" = "News"; +"Scene.Discovery.Tabs.Posts" = "Posts"; "Scene.Favorite.Title" = "Ismenyifen-ik·im"; "Scene.Follower.Footer" = "Ineḍfaren seg yiqeddacen-nniḍen ur d-ttwaskanen ara."; "Scene.Following.Footer" = "Ineḍfaren seg yiqeddacen-nniḍen ur d-ttwaskanen ara."; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings index 608163f4e..dcc8dae64 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings @@ -201,6 +201,10 @@ Profîla te ji wan ra wiha xuya dike."; "Scene.ConfirmEmail.Subtitle" = "Me tenê e-nameyek ji %@ re şand, girêdanê bitikne da ku ajimêra xwe bidî piştrastkirin."; "Scene.ConfirmEmail.Title" = "Tiştekî dawî."; +"Scene.Discovery.Tabs.ForYou" = "Ji bo te"; +"Scene.Discovery.Tabs.Hashtags" = "Hashtag"; +"Scene.Discovery.Tabs.News" = "Nûçe"; +"Scene.Discovery.Tabs.Posts" = "Şandî"; "Scene.Favorite.Title" = "Bijarteyên te"; "Scene.Follower.Footer" = "Şopîner ji rajekerên din nayê dîtin."; "Scene.Following.Footer" = "Şopandin ji rajekerên din nayê dîtin."; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.strings index 6a19a4bf6..31148373f 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.strings @@ -195,6 +195,10 @@ Uw profiel ziet er zo uit voor hen."; "Scene.ConfirmEmail.Subtitle" = "We hebben een e-mail gestuurd naar %@, klik op de link om uw account te bevestigen."; "Scene.ConfirmEmail.Title" = "Nog één ding."; +"Scene.Discovery.Tabs.ForYou" = "For You"; +"Scene.Discovery.Tabs.Hashtags" = "Hashtags"; +"Scene.Discovery.Tabs.News" = "News"; +"Scene.Discovery.Tabs.Posts" = "Posts"; "Scene.Favorite.Title" = "Uw favorieten"; "Scene.Follower.Footer" = "Followers from other servers are not displayed."; "Scene.Following.Footer" = "Follows from other servers are not displayed."; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings index 6913d753f..d7ed34c30 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings @@ -4,7 +4,7 @@ "Common.Alerts.CleanCache.Title" = "Очистка кэша"; "Common.Alerts.Common.PleaseTryAgain" = "Пожалуйста, попробуйте ещё раз."; "Common.Alerts.Common.PleaseTryAgainLater" = "Пожалуйста, попробуйте позже."; -"Common.Alerts.DeletePost.Message" = "Are you sure you want to delete this post?"; +"Common.Alerts.DeletePost.Message" = "Вы уверены, что хотите удалить этот пост?"; "Common.Alerts.DeletePost.Title" = "Вы уверены, что хотите удалить этот пост?"; "Common.Alerts.DiscardPostContent.Message" = "Вы действительно хотите удалить набранное содержимое поста?"; "Common.Alerts.DiscardPostContent.Title" = "Удалить черновик"; @@ -69,7 +69,7 @@ "Common.Controls.Friendship.Follow" = "Подписаться"; "Common.Controls.Friendship.Following" = "В подписках"; "Common.Controls.Friendship.Mute" = "Игнорировать"; -"Common.Controls.Friendship.MuteUser" = "Добавить %@ в игнорируемые"; +"Common.Controls.Friendship.MuteUser" = "Игнорировать %@"; "Common.Controls.Friendship.Muted" = "В игнорируемых"; "Common.Controls.Friendship.Pending" = "Отправлен"; "Common.Controls.Friendship.Request" = "Отправить запрос"; @@ -94,14 +94,14 @@ "Common.Controls.Keyboard.Timeline.ToggleFavorite" = "Добавить или убрать из избранного"; "Common.Controls.Keyboard.Timeline.ToggleReblog" = "Продвинуть или убрать продвижение"; "Common.Controls.Status.Actions.Favorite" = "Добавить в избранное"; -"Common.Controls.Status.Actions.Hide" = "Hide"; +"Common.Controls.Status.Actions.Hide" = "Скрыть"; "Common.Controls.Status.Actions.Menu" = "Меню"; "Common.Controls.Status.Actions.Reblog" = "Продвинуть"; "Common.Controls.Status.Actions.Reply" = "Ответить"; -"Common.Controls.Status.Actions.ShowGif" = "Show GIF"; -"Common.Controls.Status.Actions.ShowImage" = "Show image"; -"Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; -"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tap then hold to show menu"; +"Common.Controls.Status.Actions.ShowGif" = "Показать GIF"; +"Common.Controls.Status.Actions.ShowImage" = "Показать изображение"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Показать видеопроигрыватель"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Нажмите и удерживайте, чтобы показать меню"; "Common.Controls.Status.Actions.Unfavorite" = "Убрать из избранного"; "Common.Controls.Status.Actions.Unreblog" = "Убрать продвижение"; "Common.Controls.Status.ContentWarning" = "Предупреждение о содержании"; @@ -116,7 +116,7 @@ "Common.Controls.Status.Tag.Link" = "Ссылка"; "Common.Controls.Status.Tag.Mention" = "Упоминание"; "Common.Controls.Status.Tag.Url" = "Ссылка"; -"Common.Controls.Status.TapToReveal" = "Tap to reveal"; +"Common.Controls.Status.TapToReveal" = "Нажмите, чтобы показать"; "Common.Controls.Status.UserReblogged" = "%@ продвинул(а)"; "Common.Controls.Status.UserRepliedTo" = "Ответил(а) %@"; "Common.Controls.Status.Visibility.Direct" = "Only mentioned user can see this post."; @@ -198,7 +198,7 @@ "Scene.Compose.Visibility.Public" = "Публичный"; "Scene.Compose.Visibility.Unlisted" = "Скрытый"; "Scene.ConfirmEmail.Button.OpenEmailApp" = "Открыть приложение почты"; -"Scene.ConfirmEmail.Button.Resend" = "Resend"; +"Scene.ConfirmEmail.Button.Resend" = "Отправить заново"; "Scene.ConfirmEmail.DontReceiveEmail.Description" = "Проверьте, правильно ли указан ваш e-mail адрес, а также папку «спам», если ещё не сделали этого."; "Scene.ConfirmEmail.DontReceiveEmail.ResendEmail" = "Отправить ещё раз"; "Scene.ConfirmEmail.DontReceiveEmail.Title" = "Проверьте свой e-mail адрес"; @@ -211,6 +211,10 @@ Нажмите на ссылку в нём, чтобы подтвердить свою учётную запись."; "Scene.ConfirmEmail.Title" = "И ещё кое-что."; +"Scene.Discovery.Tabs.ForYou" = "For You"; +"Scene.Discovery.Tabs.Hashtags" = "Hashtags"; +"Scene.Discovery.Tabs.News" = "News"; +"Scene.Discovery.Tabs.Posts" = "Posts"; "Scene.Favorite.Title" = "Ваше избранное"; "Scene.Follower.Footer" = "Followers from other servers are not displayed."; "Scene.Following.Footer" = "Follows from other servers are not displayed."; @@ -253,7 +257,7 @@ "Scene.Profile.SegmentedControl.About" = "About"; "Scene.Profile.SegmentedControl.Media" = "Медиа"; "Scene.Profile.SegmentedControl.Posts" = "Посты"; -"Scene.Profile.SegmentedControl.PostsAndReplies" = "Posts and Replies"; +"Scene.Profile.SegmentedControl.PostsAndReplies" = "Посты и ответы"; "Scene.Profile.SegmentedControl.Replies" = "Ответы"; "Scene.Register.Error.Item.Agreement" = "Соглашение"; "Scene.Register.Error.Item.Email" = "E-mail"; @@ -298,7 +302,7 @@ "Scene.Report.Step2" = "Шаг 2 из 2"; "Scene.Report.TextPlaceholder" = "Дополнительные комментарии"; "Scene.Report.Title" = "Пожаловаться на %@"; -"Scene.Report.TitleReport" = "Report"; +"Scene.Report.TitleReport" = "Жалоба"; "Scene.Search.Recommend.Accounts.Description" = "Возможно, вы захотите подписаться на эти профили"; "Scene.Search.Recommend.Accounts.Follow" = "Подписаться"; "Scene.Search.Recommend.Accounts.Title" = "Вам может понравится"; @@ -376,7 +380,7 @@ "Scene.Settings.Section.Notifications.Trigger.Title" = "Уведомлять меня, когда"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Отключить анимацию аватарок"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Отключить анимацию эмодзи"; -"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Open links in Mastodon"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Открывать ссылки в Мастодоне"; "Scene.Settings.Section.Preference.Title" = "Предпочтения"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "Полноценно чёрный режим"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Использовать браузер по умолчанию для открытия ссылок"; @@ -388,10 +392,10 @@ "Scene.SuggestionAccount.Title" = "Подпишитесь на людей"; "Scene.Thread.BackTitle" = "Пост"; "Scene.Thread.Title" = "Пост %@"; -"Scene.Welcome.GetStarted" = "Get Started"; +"Scene.Welcome.GetStarted" = "Присоединиться"; "Scene.Welcome.LogIn" = "Вход"; "Scene.Welcome.Slogan" = "Социальная сеть под вашим контролем."; "Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard"; "Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button."; -"Scene.Wizard.NewInMastodon" = "New in Mastodon"; \ No newline at end of file +"Scene.Wizard.NewInMastodon" = "Новое в Мастодоне"; \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/sv_FI.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/sv_FI.lproj/Localizable.strings index 07d5aa5e7..434303e3d 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/sv_FI.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/sv_FI.lproj/Localizable.strings @@ -200,6 +200,10 @@ uploaded to Mastodon."; "Scene.ConfirmEmail.OpenEmailApp.Title" = "Tarkasta postilaatikkosi."; "Scene.ConfirmEmail.Subtitle" = "Lähetimme juuri sähköpostin osoitteeseen %@, napauta siinä olevaa linkkiä vahvistaaksesi tilisi."; "Scene.ConfirmEmail.Title" = "Viimeinen asia."; +"Scene.Discovery.Tabs.ForYou" = "For You"; +"Scene.Discovery.Tabs.Hashtags" = "Hashtags"; +"Scene.Discovery.Tabs.News" = "News"; +"Scene.Discovery.Tabs.Posts" = "Posts"; "Scene.Favorite.Title" = "Omat suosikit"; "Scene.Follower.Footer" = "Seuraajia muilta palvelimilta ei näytetä."; "Scene.Following.Footer" = "Seurauksia muilta palvelimilta ei näytetä."; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings index de50842f2..5dfb5134a 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings @@ -98,10 +98,10 @@ "Common.Controls.Status.Actions.Menu" = "เมนู"; "Common.Controls.Status.Actions.Reblog" = "ดัน"; "Common.Controls.Status.Actions.Reply" = "ตอบกลับ"; -"Common.Controls.Status.Actions.ShowGif" = "Show GIF"; -"Common.Controls.Status.Actions.ShowImage" = "Show image"; -"Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; -"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tap then hold to show menu"; +"Common.Controls.Status.Actions.ShowGif" = "แสดง GIF"; +"Common.Controls.Status.Actions.ShowImage" = "แสดงภาพ"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "แสดงตัวเล่นวิดีโอ"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "แตะค้างไว้เพื่อแสดงเมนู"; "Common.Controls.Status.Actions.Unfavorite" = "เลิกชื่นชอบ"; "Common.Controls.Status.Actions.Unreblog" = "เลิกทำการดัน"; "Common.Controls.Status.ContentWarning" = "คำเตือนเนื้อหา"; @@ -116,7 +116,7 @@ "Common.Controls.Status.Tag.Link" = "ลิงก์"; "Common.Controls.Status.Tag.Mention" = "กล่าวถึง"; "Common.Controls.Status.Tag.Url" = "URL"; -"Common.Controls.Status.TapToReveal" = "Tap to reveal"; +"Common.Controls.Status.TapToReveal" = "แตะเพื่อเปิดเผย"; "Common.Controls.Status.UserReblogged" = "%@ ได้ดัน"; "Common.Controls.Status.UserRepliedTo" = "ตอบกลับ %@"; "Common.Controls.Status.Visibility.Direct" = "เฉพาะผู้ใช้ที่กล่าวถึงเท่านั้นที่สามารถเห็นโพสต์นี้"; @@ -200,6 +200,10 @@ "Scene.ConfirmEmail.OpenEmailApp.Title" = "ตรวจสอบกล่องขาเข้าของคุณ"; "Scene.ConfirmEmail.Subtitle" = "แตะลิงก์ที่เราส่งอีเมลถึงคุณเพื่อยืนยันบัญชีของคุณ"; "Scene.ConfirmEmail.Title" = "หนึ่งสิ่งสุดท้าย"; +"Scene.Discovery.Tabs.ForYou" = "สำหรับคุณ"; +"Scene.Discovery.Tabs.Hashtags" = "แฮชแท็ก"; +"Scene.Discovery.Tabs.News" = "ข่าว"; +"Scene.Discovery.Tabs.Posts" = "โพสต์"; "Scene.Favorite.Title" = "รายการโปรดของคุณ"; "Scene.Follower.Footer" = "ไม่ได้แสดงผู้ติดตามจากเซิร์ฟเวอร์อื่น ๆ"; "Scene.Following.Footer" = "ไม่ได้แสดงการติดตามจากเซิร์ฟเวอร์อื่น ๆ"; @@ -221,10 +225,10 @@ "Scene.Preview.Keyboard.ClosePreview" = "ปิดตัวอย่าง"; "Scene.Preview.Keyboard.ShowNext" = "แสดงถัดไป"; "Scene.Preview.Keyboard.ShowPrevious" = "แสดงก่อนหน้า"; -"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Double tap to open the list"; -"Scene.Profile.Accessibility.EditAvatarImage" = "Edit avatar image"; -"Scene.Profile.Accessibility.ShowAvatarImage" = "Show avatar image"; -"Scene.Profile.Accessibility.ShowBannerImage" = "Show banner image"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "แตะสองครั้งเพื่อเปิดรายการ"; +"Scene.Profile.Accessibility.EditAvatarImage" = "แก้ไขภาพประจำตัว"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "แสดงภาพประจำตัว"; +"Scene.Profile.Accessibility.ShowBannerImage" = "แสดงภาพแบนเนอร์"; "Scene.Profile.Dashboard.Followers" = "ผู้ติดตาม"; "Scene.Profile.Dashboard.Following" = "กำลังติดตาม"; "Scene.Profile.Dashboard.Posts" = "โพสต์"; @@ -364,7 +368,7 @@ "Scene.Settings.Section.Notifications.Trigger.Title" = "แจ้งเตือนฉันเมื่อ"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "ปิดใช้งานภาพประจำตัวแบบเคลื่อนไหว"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "ปิดใช้งานอีโมจิแบบเคลื่อนไหว"; -"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Open links in Mastodon"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "เปิดลิงก์ใน Mastodon"; "Scene.Settings.Section.Preference.Title" = "การกำหนดลักษณะ"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "โหมดมืดดำสนิท"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "ใช้เบราว์เซอร์เริ่มต้นเพื่อเปิดลิงก์"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.stringsdict index 3895c3993..8ae8feb7b 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.stringsdict @@ -111,7 +111,7 @@ NSStringFormatValueTypeKey ld other - %ld replies + %ld การตอบกลับ plural.count.vote diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.strings index 95eef33b0..407c4f9cb 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.strings @@ -8,8 +8,8 @@ "Common.Alerts.DeletePost.Title" = "Xóa tút"; "Common.Alerts.DiscardPostContent.Message" = "Xác nhận bỏ qua nội dung tút đã viết."; "Common.Alerts.DiscardPostContent.Title" = "Hủy bản nháp"; -"Common.Alerts.EditProfileFailure.Message" = "Không thể chỉnh sửa trang cá nhân. Vui lòng thử lại."; -"Common.Alerts.EditProfileFailure.Title" = "Lỗi chỉnh sửa trang cá nhân"; +"Common.Alerts.EditProfileFailure.Message" = "Không thể chỉnh sửa hồ sơ. Vui lòng thử lại."; +"Common.Alerts.EditProfileFailure.Title" = "Lỗi chỉnh sửa hồ sơ"; "Common.Alerts.PublishPostFailure.AttachmentsMessage.MoreThanOneVideo" = "Không thể đính kèm nhiều video."; "Common.Alerts.PublishPostFailure.AttachmentsMessage.VideoAttachWithPhoto" = "Không thể đính kèm video cùng với hình ảnh."; "Common.Alerts.PublishPostFailure.Message" = "Không thể đăng tút. @@ -109,7 +109,7 @@ Vui lòng kiểm tra kết nối mạng."; "Common.Controls.Status.Poll.Closed" = "Kết thúc"; "Common.Controls.Status.Poll.Vote" = "Bình chọn"; "Common.Controls.Status.ShowPost" = "Xem tút"; -"Common.Controls.Status.ShowUserProfile" = "Xem trang cá nhân"; +"Common.Controls.Status.ShowUserProfile" = "Xem trang hồ sơ"; "Common.Controls.Status.Tag.Email" = "Email"; "Common.Controls.Status.Tag.Emoji" = "Emoji"; "Common.Controls.Status.Tag.Hashtag" = "Hashtag"; @@ -125,7 +125,7 @@ Vui lòng kiểm tra kết nối mạng."; "Common.Controls.Status.Visibility.Unlisted" = "Ai cũng thấy tút này nhưng không hiện trên bảng tin máy chủ."; "Common.Controls.Tabs.Home" = "Bảng tin"; "Common.Controls.Tabs.Notification" = "Thông báo"; -"Common.Controls.Tabs.Profile" = "Trang cá nhân"; +"Common.Controls.Tabs.Profile" = "Trang hồ sơ"; "Common.Controls.Tabs.Search" = "Tìm kiếm"; "Common.Controls.Timeline.Filtered" = "Bộ lọc"; "Common.Controls.Timeline.Header.BlockedWarning" = "Bạn không thể xem trang người này @@ -200,6 +200,10 @@ tải lên Mastodon."; "Scene.ConfirmEmail.OpenEmailApp.Title" = "Kiểm tra hộp thư của bạn."; "Scene.ConfirmEmail.Subtitle" = "Nhấn vào liên kết chúng tôi gửi qua email để xác thực tài khoản."; "Scene.ConfirmEmail.Title" = "Còn điều này nữa."; +"Scene.Discovery.Tabs.ForYou" = "Dành cho bạn"; +"Scene.Discovery.Tabs.Hashtags" = "Hashtag"; +"Scene.Discovery.Tabs.News" = "Tin tức"; +"Scene.Discovery.Tabs.Posts" = "Tút"; "Scene.Favorite.Title" = "Lượt thích"; "Scene.Follower.Footer" = "Không hiển thị người theo dõi từ máy chủ khác."; "Scene.Following.Footer" = "Không hiển thị người bạn theo dõi từ máy chủ khác."; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.strings index f4a90541d..f9ec487c4 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.strings @@ -98,10 +98,10 @@ "Common.Controls.Status.Actions.Menu" = "菜单"; "Common.Controls.Status.Actions.Reblog" = "转发"; "Common.Controls.Status.Actions.Reply" = "回复"; -"Common.Controls.Status.Actions.ShowGif" = "Show GIF"; -"Common.Controls.Status.Actions.ShowImage" = "Show image"; -"Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; -"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tap then hold to show menu"; +"Common.Controls.Status.Actions.ShowGif" = "显示 GIF"; +"Common.Controls.Status.Actions.ShowImage" = "显示图片"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "显示视频播放器"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "长按以显示菜单"; "Common.Controls.Status.Actions.Unfavorite" = "取消喜欢"; "Common.Controls.Status.Actions.Unreblog" = "取消转发"; "Common.Controls.Status.ContentWarning" = "内容警告"; @@ -116,7 +116,7 @@ "Common.Controls.Status.Tag.Link" = "链接"; "Common.Controls.Status.Tag.Mention" = "提及"; "Common.Controls.Status.Tag.Url" = "URL"; -"Common.Controls.Status.TapToReveal" = "Tap to reveal"; +"Common.Controls.Status.TapToReveal" = "点击以显示"; "Common.Controls.Status.UserReblogged" = "%@ 转发"; "Common.Controls.Status.UserRepliedTo" = "回复给 %@"; "Common.Controls.Status.Visibility.Direct" = "只有提到的用户才能看到此帖子。"; @@ -201,6 +201,10 @@ "Scene.ConfirmEmail.Subtitle" = "我们刚刚向 %@ 发送了一封电子邮件, 点击链接确认你的帐户。"; "Scene.ConfirmEmail.Title" = "最后一件事。"; +"Scene.Discovery.Tabs.ForYou" = "为你推荐"; +"Scene.Discovery.Tabs.Hashtags" = "话题"; +"Scene.Discovery.Tabs.News" = "新闻"; +"Scene.Discovery.Tabs.Posts" = "帖子"; "Scene.Favorite.Title" = "你的喜欢"; "Scene.Follower.Footer" = "不会显示来自其它服务器的关注者"; "Scene.Following.Footer" = "不会显示来自其它服务器的关注"; @@ -222,10 +226,10 @@ "Scene.Preview.Keyboard.ClosePreview" = "关闭预览"; "Scene.Preview.Keyboard.ShowNext" = "显示下一个"; "Scene.Preview.Keyboard.ShowPrevious" = "显示前一个"; -"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Double tap to open the list"; -"Scene.Profile.Accessibility.EditAvatarImage" = "Edit avatar image"; -"Scene.Profile.Accessibility.ShowAvatarImage" = "Show avatar image"; -"Scene.Profile.Accessibility.ShowBannerImage" = "Show banner image"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "双击打开列表"; +"Scene.Profile.Accessibility.EditAvatarImage" = "编辑头像"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "显示头像"; +"Scene.Profile.Accessibility.ShowBannerImage" = "显示顶部横幅图片"; "Scene.Profile.Dashboard.Followers" = "关注者"; "Scene.Profile.Dashboard.Following" = "正在关注"; "Scene.Profile.Dashboard.Posts" = "帖子"; @@ -366,7 +370,7 @@ "Scene.Settings.Section.Notifications.Trigger.Title" = "提示通知来自"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "禁用动画头像"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "禁用动画表情"; -"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Open links in Mastodon"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "在 Mastodon 中打开链接"; "Scene.Settings.Section.Preference.Title" = "偏好"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "纯黑模式"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "使用默认浏览器打开链接"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.stringsdict index 418903836..6c2661ee5 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.stringsdict @@ -111,7 +111,7 @@ NSStringFormatValueTypeKey ld other - %ld replies + %ld 条回复 plural.count.vote From c9a8834ff7e628d862211d4e6ba01abae6bfa786 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 18 Apr 2022 17:58:44 +0800 Subject: [PATCH 026/101] chore: update version to 1.3.1 (111) --- AppShared/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 36 +++++++++---------- .../xcschemes/xcschememanagement.plist | 14 ++++---- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 9 files changed, 32 insertions(+), 32 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 66a4b22f5..f6306ed3a 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 110 + 111 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 83cbb62ac..9343658e6 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4725,7 +4725,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 110; + CURRENT_PROJECT_VERSION = 111; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4754,7 +4754,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 110; + CURRENT_PROJECT_VERSION = 111; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4862,11 +4862,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 110; + CURRENT_PROJECT_VERSION = 111; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 110; + DYLIB_CURRENT_VERSION = 111; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4893,11 +4893,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 110; + CURRENT_PROJECT_VERSION = 111; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 110; + DYLIB_CURRENT_VERSION = 111; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4922,7 +4922,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 110; + CURRENT_PROJECT_VERSION = 111; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4947,7 +4947,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 110; + CURRENT_PROJECT_VERSION = 111; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4972,7 +4972,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 110; + CURRENT_PROJECT_VERSION = 111; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4997,7 +4997,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 110; + CURRENT_PROJECT_VERSION = 111; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5083,7 +5083,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 110; + CURRENT_PROJECT_VERSION = 111; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5150,11 +5150,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 110; + CURRENT_PROJECT_VERSION = 111; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 110; + DYLIB_CURRENT_VERSION = 111; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5179,7 +5179,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 110; + CURRENT_PROJECT_VERSION = 111; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5203,7 +5203,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 110; + CURRENT_PROJECT_VERSION = 111; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5228,7 +5228,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 110; + CURRENT_PROJECT_VERSION = 111; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5253,7 +5253,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 110; + CURRENT_PROJECT_VERSION = 111; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5277,7 +5277,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 110; + CURRENT_PROJECT_VERSION = 111; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 0d22a2264..b7da04206 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -9,7 +9,7 @@ isShown orderHint - 5 + 4 CoreDataStack.xcscheme_^#shared#^_ @@ -19,7 +19,7 @@ Mastodon - RTL.xcscheme_^#shared#^_ orderHint - 20 + 19 Mastodon - Release.xcscheme_^#shared#^_ @@ -29,12 +29,12 @@ Mastodon - Snapshot.xcscheme_^#shared#^_ orderHint - 3 + 2 Mastodon - ar.xcscheme orderHint - 4 + 3 Mastodon - ar.xcscheme_^#shared#^_ @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 26 + 30 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 23 + 31 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 24 + 29 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 88b45ec38..efd0d4f7d 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -43,7 +43,7 @@ CFBundleVersion - 110 + 111 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 797487637..4842779e1 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 110 + 111 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 66a4b22f5..f6306ed3a 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 110 + 111 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 66a4b22f5..f6306ed3a 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 110 + 111 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index 7301c57de..82097f0e5 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 110 + 111 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 856818817..8c23d89f1 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 110 + 111 NSExtension NSExtensionAttributes From a9a83315b212a66101d94c76d5036dfeca390766 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 18 Apr 2022 18:11:31 +0800 Subject: [PATCH 027/101] fix: searchTextField cover by keyboard issue. resolve #375 --- .../MastodonPickServerViewController.swift | 31 ++++++------------- .../MastodonPickServerViewModel.swift | 3 +- 2 files changed, 11 insertions(+), 23 deletions(-) diff --git a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift index 2d43faa56..b86c952a4 100644 --- a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift +++ b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift @@ -12,6 +12,7 @@ import GameController import AuthenticationServices import MastodonAsset import MastodonLocalization +import MastodonUI final class MastodonPickServerViewController: UIViewController, NeedsDependency { @@ -144,6 +145,13 @@ extension MastodonPickServerViewController { pickServerServerSectionTableHeaderViewDelegate: self, pickServerCellDelegate: self ) + + KeyboardResponderService + .configure( + scrollView: tableView, + layoutNeedsUpdate: viewModel.viewDidAppear.eraseToAnyPublisher() + ) + .store(in: &disposeBag) viewModel .selectedServer @@ -238,6 +246,7 @@ extension MastodonPickServerViewController { super.viewDidAppear(animated) tableView.flashScrollIndicators() + viewModel.viewDidAppear.send() } override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { @@ -416,28 +425,6 @@ extension MastodonPickServerViewController: UITableViewDelegate { viewModel.selectedServer.send(nil) } - func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { - guard let diffableDataSource = viewModel.diffableDataSource else { return } - guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return } - - switch item { -// case .categoryPicker: -// guard let cell = cell as? PickServerCategoriesCell else { return } -// guard let diffableDataSource = cell.diffableDataSource else { return } -// let snapshot = diffableDataSource.snapshot() -// -// let item = viewModel.selectCategoryItem.value -// guard let section = snapshot.indexOfSection(.main), -// let row = snapshot.indexOfItem(item) else { return } -// cell.collectionView.selectItem(at: IndexPath(item: row, section: section), animated: false, scrollPosition: .centeredHorizontally) -// case .search: -// guard let cell = cell as? PickServerSearchCell else { return } -// cell.searchTextField.text = viewModel.searchText.value - default: - break - } - } - func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { guard let diffableDataSource = viewModel.diffableDataSource else { return nil } let snapshot = diffableDataSource.snapshot() diff --git a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift index af38b110b..59008c530 100644 --- a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift +++ b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift @@ -45,7 +45,8 @@ class MastodonPickServerViewModel: NSObject { let indexedServers = CurrentValueSubject<[Mastodon.Entity.Server], Never>([]) let unindexedServers = CurrentValueSubject<[Mastodon.Entity.Server]?, Never>([]) // set nil when loading let viewWillAppear = PassthroughSubject() - + let viewDidAppear = CurrentValueSubject(Void()) + // output var diffableDataSource: UITableViewDiffableDataSource? private(set) lazy var loadIndexedServerStateMachine: GKStateMachine = { From 063119337d37623abf311cc302b12121f291a976 Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 18 Apr 2022 18:23:11 +0800 Subject: [PATCH 028/101] chore: update version to 1.3.1 (112) --- AppShared/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 36 +++++++++---------- .../xcschemes/xcschememanagement.plist | 6 ++-- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 9 files changed, 28 insertions(+), 28 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index f6306ed3a..a16d6ce25 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 111 + 112 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 9343658e6..d7e76cd30 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4725,7 +4725,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 111; + CURRENT_PROJECT_VERSION = 112; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4754,7 +4754,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 111; + CURRENT_PROJECT_VERSION = 112; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4862,11 +4862,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 111; + CURRENT_PROJECT_VERSION = 112; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 111; + DYLIB_CURRENT_VERSION = 112; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4893,11 +4893,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 111; + CURRENT_PROJECT_VERSION = 112; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 111; + DYLIB_CURRENT_VERSION = 112; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4922,7 +4922,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 111; + CURRENT_PROJECT_VERSION = 112; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4947,7 +4947,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 111; + CURRENT_PROJECT_VERSION = 112; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4972,7 +4972,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 111; + CURRENT_PROJECT_VERSION = 112; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4997,7 +4997,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 111; + CURRENT_PROJECT_VERSION = 112; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5083,7 +5083,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 111; + CURRENT_PROJECT_VERSION = 112; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5150,11 +5150,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 111; + CURRENT_PROJECT_VERSION = 112; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 111; + DYLIB_CURRENT_VERSION = 112; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5179,7 +5179,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 111; + CURRENT_PROJECT_VERSION = 112; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5203,7 +5203,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 111; + CURRENT_PROJECT_VERSION = 112; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5228,7 +5228,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 111; + CURRENT_PROJECT_VERSION = 112; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5253,7 +5253,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 111; + CURRENT_PROJECT_VERSION = 112; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5277,7 +5277,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 111; + CURRENT_PROJECT_VERSION = 112; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index b7da04206..ae6e60405 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 30 + 33 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 31 + 32 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 29 + 34 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index efd0d4f7d..aa2be51b2 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -43,7 +43,7 @@ CFBundleVersion - 111 + 112 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 4842779e1..974ce601b 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 111 + 112 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index f6306ed3a..a16d6ce25 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 111 + 112 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index f6306ed3a..a16d6ce25 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 111 + 112 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index 82097f0e5..20fbcea39 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 111 + 112 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 8c23d89f1..1325a3482 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 111 + 112 NSExtension NSExtensionAttributes From 1d966090032865362f1ec01442395889e26238ba Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 19 Apr 2022 20:57:21 +0800 Subject: [PATCH 029/101] fix: ProfileCardView layout initial setup failure issue --- .../xcschemes/xcschememanagement.plist | 6 +-- .../Discovery/DiscoverySection.swift | 7 +++- .../View/Content/ProfileCardView.swift | 39 ++++++++++++------- ...ofileCardTableViewCell+Configuration.swift | 30 ++++++++++++++ .../ProfileCardTableViewCell.swift | 10 +++-- 5 files changed, 71 insertions(+), 21 deletions(-) create mode 100644 MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell+Configuration.swift diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index ae6e60405..55845d580 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 33 + 23 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 32 + 22 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 34 + 24 SuppressBuildableAutocreation diff --git a/Mastodon/Diffiable/Discovery/DiscoverySection.swift b/Mastodon/Diffiable/Discovery/DiscoverySection.swift index 76cc9c030..cab2eb82b 100644 --- a/Mastodon/Diffiable/Discovery/DiscoverySection.swift +++ b/Mastodon/Diffiable/Discovery/DiscoverySection.swift @@ -52,13 +52,16 @@ extension DiscoverySection { let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: ProfileCardTableViewCell.self), for: indexPath) as! ProfileCardTableViewCell context.managedObjectContext.performAndWait { guard let user = record.object(in: context.managedObjectContext) else { return } - cell.profileCardView.configure(user: user) + cell.configure( + tableView: tableView, + user: user, + profileCardTableViewCellDelegate: configuration.profileCardTableViewCellDelegate + ) } context.authenticationService.activeMastodonAuthentication .map { $0?.user } .assign(to: \.me, on: cell.profileCardView.viewModel.relationshipViewModel) .store(in: &cell.disposeBag) - cell.delegate = configuration.profileCardTableViewCellDelegate return cell case .bottomLoader: let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self), for: indexPath) as! TimelineBottomLoaderTableViewCell diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift index 16351ebe1..07f441500 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/ProfileCardView.swift @@ -46,6 +46,8 @@ public final class ProfileCardView: UIView { // author username public let authorUsernameLabel = MetaLabel(style: .profileCardUsername) + // bio + let bioMetaTextAdaptiveMarginContainerView = AdaptiveMarginContainerView() let bioMetaText: MetaText = { let metaText = MetaText() metaText.textView.backgroundColor = .clear @@ -78,6 +80,7 @@ public final class ProfileCardView: UIView { return metaText }() + let infoContainerAdaptiveMarginContainerView = AdaptiveMarginContainerView() let infoContainer = UIStackView() let statusDashboardView = ProfileStatusDashboardView() @@ -194,34 +197,36 @@ extension ProfileCardView { // authorInfoContainer: V - [ authorNameLabel | authorUsernameLabel ] let authorInfoContainer = UIStackView() authorInfoContainer.axis = .vertical - authorInfoContainer.spacing = 2 + // authorInfoContainer.spacing = 2 authorContainer.addArrangedSubview(authorInfoContainer) authorInfoContainer.addArrangedSubview(authorNameLabel) authorInfoContainer.addArrangedSubview(authorUsernameLabel) // bioMetaText - let bioMetaTextAdaptiveMarginContainerView = AdaptiveMarginContainerView() bioMetaTextAdaptiveMarginContainerView.contentView = bioMetaText.textView bioMetaTextAdaptiveMarginContainerView.margin = ProfileCardView.contentMargin bioMetaText.textView.setContentHuggingPriority(.required - 1, for: .vertical) bioMetaText.textView.setContentCompressionResistancePriority(.required - 1, for: .vertical) container.addArrangedSubview(bioMetaTextAdaptiveMarginContainerView) container.setCustomSpacing(16, after: bioMetaTextAdaptiveMarginContainerView) - + // infoContainer: H - [ statusDashboardView | (spacer) | relationshipActionButton ] infoContainer.axis = .horizontal infoContainer.spacing = 8 - let infoContainerAdaptiveMarginContainerView = AdaptiveMarginContainerView() infoContainerAdaptiveMarginContainerView.contentView = infoContainer infoContainerAdaptiveMarginContainerView.margin = ProfileCardView.contentMargin container.addArrangedSubview(infoContainerAdaptiveMarginContainerView) - infoContainer.addArrangedSubview(statusDashboardView) - infoContainer.addArrangedSubview(UIView()) - let relationshipActionButtonShadowContainer = ShadowBackgroundContainer() - infoContainer.addArrangedSubview(relationshipActionButtonShadowContainer) - updateInfoContainerLayout() + infoContainer.addArrangedSubview(statusDashboardView) + let infoContainerSpacer = UIView() + infoContainer.addArrangedSubview(UIView()) + infoContainerSpacer.setContentHuggingPriority(.defaultLow - 100, for: .vertical) + infoContainerSpacer.setContentHuggingPriority(.defaultLow - 100, for: .horizontal) + let relationshipActionButtonShadowContainer = ShadowBackgroundContainer() + relationshipActionButtonShadowContainer.translatesAutoresizingMaskIntoConstraints = false + infoContainer.addArrangedSubview(relationshipActionButtonShadowContainer) + relationshipActionButton.translatesAutoresizingMaskIntoConstraints = false relationshipActionButtonShadowContainer.addSubview(relationshipActionButton) NSLayoutConstraint.activate([ @@ -229,15 +234,15 @@ extension ProfileCardView { relationshipActionButton.leadingAnchor.constraint(equalTo: relationshipActionButtonShadowContainer.leadingAnchor), relationshipActionButton.trailingAnchor.constraint(equalTo: relationshipActionButtonShadowContainer.trailingAnchor), relationshipActionButton.bottomAnchor.constraint(equalTo: relationshipActionButtonShadowContainer.bottomAnchor), - relationshipActionButton.widthAnchor.constraint(greaterThanOrEqualToConstant: ProfileCardView.friendshipActionButtonSize.width).priority(.required - 1), - relationshipActionButton.heightAnchor.constraint(equalToConstant: ProfileCardView.friendshipActionButtonSize.height).priority(.required - 2), + relationshipActionButtonShadowContainer.widthAnchor.constraint(greaterThanOrEqualToConstant: ProfileCardView.friendshipActionButtonSize.width).priority(.required - 1), + relationshipActionButtonShadowContainer.heightAnchor.constraint(equalToConstant: ProfileCardView.friendshipActionButtonSize.height).priority(.required - 1), ]) - + let bottomPadding = UIView() bottomPadding.translatesAutoresizingMaskIntoConstraints = false container.addArrangedSubview(bottomPadding) NSLayoutConstraint.activate([ - bottomPadding.heightAnchor.constraint(equalToConstant: 16) + bottomPadding.heightAnchor.constraint(equalToConstant: 16).priority(.required - 10), ]) relationshipActionButton.addTarget(self, action: #selector(ProfileCardView.relationshipActionButtonDidPressed(_:)), for: .touchUpInside) @@ -257,6 +262,14 @@ extension ProfileCardView { } extension ProfileCardView { + public func setupLayoutFrame(_ rect: CGRect) { + frame.size.width = rect.width + bioMetaTextAdaptiveMarginContainerView.frame.size.width = frame.width + bioMetaTextAdaptiveMarginContainerView.contentView?.frame.size.width = frame.width - 2 * bioMetaTextAdaptiveMarginContainerView.margin + infoContainerAdaptiveMarginContainerView.frame.size.width = frame.width + infoContainerAdaptiveMarginContainerView.contentView?.frame.size.width = frame.width - 2 * infoContainerAdaptiveMarginContainerView.margin + } + private func updateInfoContainerLayout() { let isCompactAdaptive = bounds.width < 350 infoContainer.axis = isCompactAdaptive ? .vertical : .horizontal diff --git a/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell+Configuration.swift b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell+Configuration.swift new file mode 100644 index 000000000..061af0f48 --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell+Configuration.swift @@ -0,0 +1,30 @@ +// +// ProfileCardTableViewCell+Configuration.swift +// +// +// Created by MainasuK on 2022-4-19. +// + +import UIKit +import CoreDataStack + +extension ProfileCardTableViewCell { + + public func configure( + tableView: UITableView, + user: MastodonUser, + profileCardTableViewCellDelegate: ProfileCardTableViewCellDelegate? + ) { + if profileCardView.frame == .zero { + // set content view width + assert(layoutMarginsGuide.layoutFrame.width > .zero) + shadowBackgroundContainer.frame.size.width = layoutMarginsGuide.layoutFrame.width + profileCardView.setupLayoutFrame(layoutMarginsGuide.layoutFrame) + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): did layout for new cell") + } + + profileCardView.configure(user: user) + delegate = profileCardTableViewCellDelegate + } + +} diff --git a/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift index 5961ad109..aff7b6feb 100644 --- a/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift +++ b/MastodonSDK/Sources/MastodonUI/View/TableViewCell/ProfileCardTableViewCell.swift @@ -5,6 +5,7 @@ // Created by MainasuK on 2022-4-14. // +import os.log import UIKit import Combine @@ -14,9 +15,13 @@ public protocol ProfileCardTableViewCellDelegate: AnyObject { public final class ProfileCardTableViewCell: UITableViewCell { + let logger = Logger(subsystem: "ProfileCardTableViewCell", category: "Cell") + public weak var delegate: ProfileCardTableViewCellDelegate? public var disposeBag = Set() + public let shadowBackgroundContainer = ShadowBackgroundContainer() + public let profileCardView: ProfileCardView = { let profileCardView = ProfileCardView() profileCardView.layer.masksToBounds = true @@ -49,15 +54,14 @@ extension ProfileCardTableViewCell { private func _init() { selectionStyle = .none - let shadowBackgroundContainer = ShadowBackgroundContainer() shadowBackgroundContainer.cornerRadius = 6 shadowBackgroundContainer.translatesAutoresizingMaskIntoConstraints = false contentView.addSubview(shadowBackgroundContainer) NSLayoutConstraint.activate([ - shadowBackgroundContainer.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10), + shadowBackgroundContainer.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10).priority(.required - 1), shadowBackgroundContainer.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor), shadowBackgroundContainer.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor), - contentView.bottomAnchor.constraint(equalTo: shadowBackgroundContainer.bottomAnchor, constant: 10), + contentView.bottomAnchor.constraint(equalTo: shadowBackgroundContainer.bottomAnchor, constant: 10).priority(.required - 1), ]) profileCardView.translatesAutoresizingMaskIntoConstraints = false From d70f734957e900f3794c3b27a3480e0a2b8fc57b Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 19 Apr 2022 21:34:49 +0800 Subject: [PATCH 030/101] feat: add discovery intro banner --- Localization/app.json | 3 +- Mastodon.xcodeproj/project.pbxproj | 12 +++ .../Posts/DiscoveryPostsViewController.swift | 25 +++++ .../View/DiscoveryIntroBannerView.swift | 101 ++++++++++++++++++ .../Preference/Preference+Discovery.swift | 19 ++++ 5 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 Mastodon/Scene/Discovery/View/DiscoveryIntroBannerView.swift create mode 100644 MastodonSDK/Sources/MastodonCommon/Preference/Preference+Discovery.swift diff --git a/Localization/app.json b/Localization/app.json index 6c4aae7a9..a8fc9031f 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -499,7 +499,8 @@ "hashtags": "Hashtags", "news": "News", "for_you": "For You" - } + }, + "intro": "These are the posts gaining traction in your corner of Mastodon." }, "favorite": { "title": "Your Favorites" diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index d7e76cd30..6686f1e7d 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -148,6 +148,7 @@ DB0618072785A8880030EE79 /* MastodonRegisterViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0618062785A8880030EE79 /* MastodonRegisterViewModel+Diffable.swift */; }; DB06180A2785B2AB0030EE79 /* MastodonRegisterAvatarTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0618092785B2AB0030EE79 /* MastodonRegisterAvatarTableViewCell.swift */; }; DB084B5725CBC56C00F898ED /* Status.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB084B5625CBC56C00F898ED /* Status.swift */; }; + DB0A322E280EE9FD001729D2 /* DiscoveryIntroBannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0A322D280EE9FD001729D2 /* DiscoveryIntroBannerView.swift */; }; DB0AC6FC25CD02E600D75117 /* APIService+Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0AC6FB25CD02E600D75117 /* APIService+Instance.swift */; }; DB0C946526A6FD4D0088FB11 /* AlamofireImage in Frameworks */ = {isa = PBXBuildFile; productRef = DB0C946426A6FD4D0088FB11 /* AlamofireImage */; }; DB0C947726A7FE840088FB11 /* NotificationAvatarButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0C947626A7FE840088FB11 /* NotificationAvatarButton.swift */; }; @@ -870,6 +871,7 @@ DB0618062785A8880030EE79 /* MastodonRegisterViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MastodonRegisterViewModel+Diffable.swift"; sourceTree = ""; }; DB0618092785B2AB0030EE79 /* MastodonRegisterAvatarTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonRegisterAvatarTableViewCell.swift; sourceTree = ""; }; DB084B5625CBC56C00F898ED /* Status.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Status.swift; sourceTree = ""; }; + DB0A322D280EE9FD001729D2 /* DiscoveryIntroBannerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryIntroBannerView.swift; sourceTree = ""; }; DB0AC6FB25CD02E600D75117 /* APIService+Instance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Instance.swift"; sourceTree = ""; }; DB0C947626A7FE840088FB11 /* NotificationAvatarButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationAvatarButton.swift; sourceTree = ""; }; DB0EF72A26FDB1D200347686 /* SidebarListCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarListCollectionViewCell.swift; sourceTree = ""; }; @@ -2023,6 +2025,14 @@ path = CoreDataStack; sourceTree = ""; }; + DB0A322F280EEA00001729D2 /* View */ = { + isa = PBXGroup; + children = ( + DB0A322D280EE9FD001729D2 /* DiscoveryIntroBannerView.swift */, + ); + path = View; + sourceTree = ""; + }; DB0C947826A7FE950088FB11 /* Button */ = { isa = PBXGroup; children = ( @@ -3108,6 +3118,7 @@ DBDFF1912805544800557A48 /* Discovery */ = { isa = PBXGroup; children = ( + DB0A322F280EEA00001729D2 /* View */, DBDFF19828055A0900557A48 /* Posts */, DB3E6FDE2806A41200B035AE /* Hashtags */, DB3E6FED2806D7FC00B035AE /* News */, @@ -4085,6 +4096,7 @@ DB8AF55D25C138B7002E6C99 /* UIViewController.swift in Sources */, DB7F48452620241000796008 /* ProfileHeaderViewModel.swift in Sources */, DB647C5926F1EA2700F7F82C /* WizardPreference.swift in Sources */, + DB0A322E280EE9FD001729D2 /* DiscoveryIntroBannerView.swift in Sources */, 2D3F9E0425DFA133004262D9 /* UITapGestureRecognizer.swift in Sources */, 5DDDF1992617447F00311060 /* Mastodon+Entity+Tag.swift in Sources */, 5B90C45F262599800002E742 /* SettingsToggleTableViewCell.swift in Sources */, diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift index 30e2faf96..259b21d36 100644 --- a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift @@ -8,6 +8,7 @@ import os.log import UIKit import Combine +import MastodonUI final class DiscoveryPostsViewController: UIViewController, NeedsDependency, MediaPreviewableViewController { @@ -31,6 +32,8 @@ final class DiscoveryPostsViewController: UIViewController, NeedsDependency, Med }() let refreshControl = UIRefreshControl() + + let discoveryIntroBannerView = DiscoveryIntroBannerView() deinit { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) @@ -60,6 +63,21 @@ extension DiscoveryPostsViewController { tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), ]) + + discoveryIntroBannerView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(discoveryIntroBannerView) + NSLayoutConstraint.activate([ + discoveryIntroBannerView.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor), + discoveryIntroBannerView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + discoveryIntroBannerView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + ]) + + discoveryIntroBannerView.delegate = self + discoveryIntroBannerView.isHidden = UserDefaults.shared.discoveryIntroBannerNeedsHidden + UserDefaults.shared.publisher(for: \.discoveryIntroBannerNeedsHidden) + .receive(on: DispatchQueue.main) + .assign(to: \.isHidden, on: discoveryIntroBannerView) + .store(in: &disposeBag) tableView.delegate = self viewModel.setupDiffableDataSource( @@ -146,3 +164,10 @@ extension DiscoveryPostsViewController: ScrollViewContainer { tableView } } + +// MARK: - DiscoveryIntroBannerViewDelegate +extension DiscoveryPostsViewController: DiscoveryIntroBannerViewDelegate { + func discoveryIntroBannerView(_ bannerView: DiscoveryIntroBannerView, closeButtonDidPressed button: UIButton) { + UserDefaults.shared.discoveryIntroBannerNeedsHidden = true + } +} diff --git a/Mastodon/Scene/Discovery/View/DiscoveryIntroBannerView.swift b/Mastodon/Scene/Discovery/View/DiscoveryIntroBannerView.swift new file mode 100644 index 000000000..e3e1c4547 --- /dev/null +++ b/Mastodon/Scene/Discovery/View/DiscoveryIntroBannerView.swift @@ -0,0 +1,101 @@ +// +// DiscoveryIntroBannerView.swift +// Mastodon +// +// Created by MainasuK on 2022-4-19. +// + +import os.log +import UIKit +import Combine +import MastodonAsset + +public protocol DiscoveryIntroBannerViewDelegate: AnyObject { + func discoveryIntroBannerView(_ bannerView: DiscoveryIntroBannerView, closeButtonDidPressed button: UIButton) +} + +public final class DiscoveryIntroBannerView: UIView { + + let logger = Logger(subsystem: "DiscoveryIntroBannerView", category: "View") + + var _disposeBag = Set() + + public weak var delegate: DiscoveryIntroBannerViewDelegate? + + let label: UILabel = { + let label = UILabel() + label.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 16, weight: .regular)) + label.textColor = Asset.Colors.Label.primary.color + label.text = "These are the posts gaining traction in your corner of Mastodon." // TODO: i18n + label.numberOfLines = 0 + return label + }() + + let closeButton: HitTestExpandedButton = { + let button = HitTestExpandedButton(type: .system) + button.setImage(UIImage(systemName: "xmark.circle.fill"), for: .normal) + button.tintColor = Asset.Colors.Label.secondary.color + return button + }() + + public override init(frame: CGRect) { + super.init(frame: frame) + _init() + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + _init() + } + +} + +extension DiscoveryIntroBannerView { + private func _init() { + preservesSuperviewLayoutMargins = true + + setupAppearance(theme: ThemeService.shared.currentTheme.value) + ThemeService.shared.currentTheme + .receive(on: DispatchQueue.main) + .sink { [weak self] theme in + guard let self = self else { return } + self.setupAppearance(theme: theme) + } + .store(in: &_disposeBag) + + closeButton.translatesAutoresizingMaskIntoConstraints = false + addSubview(closeButton) + NSLayoutConstraint.activate([ + closeButton.topAnchor.constraint(equalTo: topAnchor, constant: 16).priority(.required - 1), + layoutMarginsGuide.trailingAnchor.constraint(equalTo: closeButton.trailingAnchor), + closeButton.heightAnchor.constraint(equalToConstant: 20).priority(.required - 1), + closeButton.widthAnchor.constraint(equalToConstant: 20).priority(.required - 1), + ]) + + label.translatesAutoresizingMaskIntoConstraints = false + addSubview(label) + NSLayoutConstraint.activate([ + label.topAnchor.constraint(equalTo: topAnchor, constant: 16).priority(.required - 1), + label.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor), + closeButton.leadingAnchor.constraint(equalTo: label.trailingAnchor, constant: 10), + bottomAnchor.constraint(equalTo: label.bottomAnchor, constant: 16).priority(.required - 1), + ]) + + closeButton.addTarget(self, action: #selector(DiscoveryIntroBannerView.closeButtonDidPressed(_:)), for: .touchUpInside) + } +} + +extension DiscoveryIntroBannerView { + @objc private func closeButtonDidPressed(_ sender: UIButton) { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)") + delegate?.discoveryIntroBannerView(self, closeButtonDidPressed: sender) + } +} + +extension DiscoveryIntroBannerView { + + private func setupAppearance(theme: Theme) { + backgroundColor = theme.systemBackgroundColor + } + +} diff --git a/MastodonSDK/Sources/MastodonCommon/Preference/Preference+Discovery.swift b/MastodonSDK/Sources/MastodonCommon/Preference/Preference+Discovery.swift new file mode 100644 index 000000000..0c6a9c544 --- /dev/null +++ b/MastodonSDK/Sources/MastodonCommon/Preference/Preference+Discovery.swift @@ -0,0 +1,19 @@ +// +// Preference+Discovery.swift +// +// +// Created by MainasuK on 2022-4-19. +// + +import Foundation + +extension UserDefaults { + + @objc public dynamic var discoveryIntroBannerNeedsHidden: Bool { + get { + return bool(forKey: #function) + } + set { self[#function] = newValue } + } + +} From 7ea26aad9002ffef90db90a37f0ae4e0f5997082 Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 19 Apr 2022 21:35:28 +0800 Subject: [PATCH 031/101] chore: update version to 1.3.1 (113) --- AppShared/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 36 +++++++++---------- .../xcschemes/xcschememanagement.plist | 6 ++-- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 9 files changed, 28 insertions(+), 28 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index a16d6ce25..920eaff87 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 112 + 113 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 6686f1e7d..8b212674c 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4737,7 +4737,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 113; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4766,7 +4766,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 113; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4874,11 +4874,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 113; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 112; + DYLIB_CURRENT_VERSION = 113; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4905,11 +4905,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 113; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 112; + DYLIB_CURRENT_VERSION = 113; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4934,7 +4934,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 113; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4959,7 +4959,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 113; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4984,7 +4984,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 113; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5009,7 +5009,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 113; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5095,7 +5095,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 113; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5162,11 +5162,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 113; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 112; + DYLIB_CURRENT_VERSION = 113; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5191,7 +5191,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 113; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5215,7 +5215,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 113; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5240,7 +5240,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 113; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5265,7 +5265,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 113; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5289,7 +5289,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 113; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 55845d580..7d7900034 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 23 + 30 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 22 + 31 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 24 + 23 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index aa2be51b2..0bd118781 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -43,7 +43,7 @@ CFBundleVersion - 112 + 113 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 974ce601b..0d11fe1f3 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 112 + 113 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index a16d6ce25..920eaff87 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 112 + 113 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index a16d6ce25..920eaff87 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 112 + 113 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index 20fbcea39..fa92e4a24 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 112 + 113 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 1325a3482..9ee97c1e1 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.3.1 CFBundleVersion - 112 + 113 NSExtension NSExtensionAttributes From 2288efc11366d5ce5f616568210e270009303628 Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 26 Apr 2022 16:48:06 +0800 Subject: [PATCH 032/101] fix: sign up error alert missing issue --- .../MastodonRegisterViewController.swift | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift b/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift index 26060c2c5..903c9fbca 100644 --- a/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift +++ b/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift @@ -208,22 +208,22 @@ extension MastodonRegisterViewController { // self.reasonErrorPromptLabel.attributedText = prompt // } // .store(in: &disposeBag) -// viewModel.error -// .receive(on: DispatchQueue.main) -// .sink { [weak self] error in -// guard let self = self else { return } -// guard let error = error as? Mastodon.API.Error else { return } -// let alertController = UIAlertController(for: error, title: "Sign Up Failure", preferredStyle: .alert) -// let okAction = UIAlertAction(title: L10n.Common.Controls.Actions.ok, style: .default, handler: nil) -// alertController.addAction(okAction) -// self.coordinator.present( -// scene: .alertController(alertController: alertController), -// from: nil, -// transition: .alertController(animated: true, completion: nil) -// ) -// } -// .store(in: &disposeBag) -// + + viewModel.$error + .receive(on: DispatchQueue.main) + .sink { [weak self] error in + guard let self = self else { return } + guard let error = error as? Mastodon.API.Error else { return } + let alertController = UIAlertController(for: error, title: "Sign Up Failure", preferredStyle: .alert) + let okAction = UIAlertAction(title: L10n.Common.Controls.Actions.ok, style: .default, handler: nil) + alertController.addAction(okAction) + self.coordinator.present( + scene: .alertController(alertController: alertController), + from: nil, + transition: .alertController(animated: true, completion: nil) + ) + } + .store(in: &disposeBag) viewModel.avatarMediaMenuActionPublisher .receive(on: DispatchQueue.main) From 033c584eb45586da4ff65189e2c72bb13505627b Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 26 Apr 2022 17:02:17 +0800 Subject: [PATCH 033/101] chore: update version to 1.3.2 (114) --- AppShared/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 36 +++++++++---------- .../xcschemes/xcschememanagement.plist | 6 ++-- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 9 files changed, 28 insertions(+), 28 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 920eaff87..57f861546 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.1 + 1.3.2 CFBundleVersion 113 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 8b212674c..3cb611c51 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4737,7 +4737,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 113; + CURRENT_PROJECT_VERSION = 114; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4766,7 +4766,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 113; + CURRENT_PROJECT_VERSION = 114; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4874,11 +4874,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 113; + CURRENT_PROJECT_VERSION = 114; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 113; + DYLIB_CURRENT_VERSION = 114; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4905,11 +4905,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 113; + CURRENT_PROJECT_VERSION = 114; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 113; + DYLIB_CURRENT_VERSION = 114; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4934,7 +4934,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 113; + CURRENT_PROJECT_VERSION = 114; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4959,7 +4959,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 113; + CURRENT_PROJECT_VERSION = 114; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4984,7 +4984,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 113; + CURRENT_PROJECT_VERSION = 114; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5009,7 +5009,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 113; + CURRENT_PROJECT_VERSION = 114; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5095,7 +5095,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 113; + CURRENT_PROJECT_VERSION = 114; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5162,11 +5162,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 113; + CURRENT_PROJECT_VERSION = 114; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 113; + DYLIB_CURRENT_VERSION = 114; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5191,7 +5191,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 113; + CURRENT_PROJECT_VERSION = 114; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5215,7 +5215,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 113; + CURRENT_PROJECT_VERSION = 114; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5240,7 +5240,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 113; + CURRENT_PROJECT_VERSION = 114; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5265,7 +5265,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 113; + CURRENT_PROJECT_VERSION = 114; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5289,7 +5289,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 113; + CURRENT_PROJECT_VERSION = 114; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 7d7900034..dd92d9e44 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 30 + 34 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 31 + 29 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 23 + 33 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 0bd118781..15aa3c303 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -30,7 +30,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.1 + 1.3.2 CFBundleURLTypes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 0d11fe1f3..24aa97d11 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.1 + 1.3.2 CFBundleVersion 113 NSExtension diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 920eaff87..57f861546 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.1 + 1.3.2 CFBundleVersion 113 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 920eaff87..57f861546 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.1 + 1.3.2 CFBundleVersion 113 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index fa92e4a24..06f7249fd 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.1 + 1.3.2 CFBundleVersion 113 NSExtension diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 9ee97c1e1..ebde7beda 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.1 + 1.3.2 CFBundleVersion 113 NSExtension From 2ae3f21a990e0cfc076e027ae2be38a9e29d77ab Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 27 Apr 2022 17:37:03 +0800 Subject: [PATCH 034/101] fix: add missing error prompt for sign up scene --- Mastodon.xcodeproj/project.pbxproj | 33 +- .../xcschemes/xcschememanagement.plist | 6 +- ...meTimelineViewController+DebugAction.swift | 31 ++ .../MastodonPickServerViewController.swift | 13 +- .../Register/MastodonRegisterView.swift | 304 ++++++++++++++++++ .../MastodonRegisterViewController.swift | 117 ++----- .../MastodonRegisterViewModel+Diffable.swift | 47 +-- .../Register/MastodonRegisterViewModel.swift | 190 +++++++---- ...todonServerRulesViewController+Debug.swift | 50 +++ .../Root/MainTab/MainTabBarController.swift | 10 +- .../APIService/APIService+HomeTimeline.swift | 2 +- .../Entity/Mastodon+Entity+Instance.swift | 4 +- 12 files changed, 581 insertions(+), 226 deletions(-) create mode 100644 Mastodon/Scene/Onboarding/Register/MastodonRegisterView.swift create mode 100644 Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewController+Debug.swift diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 3cb611c51..23d536ddd 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -145,8 +145,6 @@ DB0618012785732C0030EE79 /* ServerRulesTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0618002785732C0030EE79 /* ServerRulesTableViewCell.swift */; }; DB0618032785A7100030EE79 /* RegisterSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0618022785A7100030EE79 /* RegisterSection.swift */; }; DB0618052785A73D0030EE79 /* RegisterItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0618042785A73D0030EE79 /* RegisterItem.swift */; }; - DB0618072785A8880030EE79 /* MastodonRegisterViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0618062785A8880030EE79 /* MastodonRegisterViewModel+Diffable.swift */; }; - DB06180A2785B2AB0030EE79 /* MastodonRegisterAvatarTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0618092785B2AB0030EE79 /* MastodonRegisterAvatarTableViewCell.swift */; }; DB084B5725CBC56C00F898ED /* Status.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB084B5625CBC56C00F898ED /* Status.swift */; }; DB0A322E280EE9FD001729D2 /* DiscoveryIntroBannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0A322D280EE9FD001729D2 /* DiscoveryIntroBannerView.swift */; }; DB0AC6FC25CD02E600D75117 /* APIService+Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0AC6FB25CD02E600D75117 /* APIService+Instance.swift */; }; @@ -400,10 +398,10 @@ DB75BF1E263C1C1B00EDBF1F /* CustomScheduler.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB75BF1D263C1C1B00EDBF1F /* CustomScheduler.swift */; }; DB789A0B25F9F2950071ACA0 /* ComposeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB789A0A25F9F2950071ACA0 /* ComposeViewController.swift */; }; DB789A1225F9F2CC0071ACA0 /* ComposeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB789A1125F9F2CC0071ACA0 /* ComposeViewModel.swift */; }; + DB7A9F912818EAF10016AF98 /* MastodonRegisterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB7A9F902818EAF10016AF98 /* MastodonRegisterView.swift */; }; + DB7A9F932818F33C0016AF98 /* MastodonServerRulesViewController+Debug.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB7A9F922818F33C0016AF98 /* MastodonServerRulesViewController+Debug.swift */; }; DB7F48452620241000796008 /* ProfileHeaderViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB7F48442620241000796008 /* ProfileHeaderViewModel.swift */; }; DB8190C62601FF0400020C08 /* AttachmentContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB8190C52601FF0400020C08 /* AttachmentContainerView.swift */; }; - DB8481152788121200BBEABA /* MastodonRegisterTextFieldTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB8481142788121200BBEABA /* MastodonRegisterTextFieldTableViewCell.swift */; }; - DB84811727883C2600BBEABA /* MastodonRegisterPasswordHintTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB84811627883C2600BBEABA /* MastodonRegisterPasswordHintTableViewCell.swift */; }; DB852D1926FAEB6B00FC9D81 /* SidebarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB852D1826FAEB6B00FC9D81 /* SidebarViewController.swift */; }; DB852D1C26FB021500FC9D81 /* RootSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB852D1B26FB021500FC9D81 /* RootSplitViewController.swift */; }; DB852D1F26FB037800FC9D81 /* SidebarViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB852D1E26FB037800FC9D81 /* SidebarViewModel.swift */; }; @@ -417,6 +415,7 @@ DB8AF54525C13647002E6C99 /* NeedsDependency.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB8AF54325C13647002E6C99 /* NeedsDependency.swift */; }; DB8AF55025C13703002E6C99 /* MainTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB8AF54F25C13703002E6C99 /* MainTabBarController.swift */; }; DB8AF55D25C138B7002E6C99 /* UIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB8AF55C25C138B7002E6C99 /* UIViewController.swift */; }; + DB8D8E2F28192EED009FD90F /* Introspect in Frameworks */ = {isa = PBXBuildFile; productRef = DB8D8E2E28192EED009FD90F /* Introspect */; }; DB8F7076279E954700E1225B /* DataSourceFacade+Follow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB8F7075279E954700E1225B /* DataSourceFacade+Follow.swift */; }; DB8FABC726AEC7B2008E5AF4 /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB8FAB9E26AEC3A2008E5AF4 /* Intents.framework */; }; DB8FABCA26AEC7B2008E5AF4 /* IntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB8FABC926AEC7B2008E5AF4 /* IntentHandler.swift */; }; @@ -1146,6 +1145,8 @@ DB75BF1D263C1C1B00EDBF1F /* CustomScheduler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomScheduler.swift; sourceTree = ""; }; DB789A0A25F9F2950071ACA0 /* ComposeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeViewController.swift; sourceTree = ""; }; DB789A1125F9F2CC0071ACA0 /* ComposeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeViewModel.swift; sourceTree = ""; }; + DB7A9F902818EAF10016AF98 /* MastodonRegisterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonRegisterView.swift; sourceTree = ""; }; + DB7A9F922818F33C0016AF98 /* MastodonServerRulesViewController+Debug.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MastodonServerRulesViewController+Debug.swift"; sourceTree = ""; }; DB7F48442620241000796008 /* ProfileHeaderViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileHeaderViewModel.swift; sourceTree = ""; }; DB8190C52601FF0400020C08 /* AttachmentContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentContainerView.swift; sourceTree = ""; }; DB8481142788121200BBEABA /* MastodonRegisterTextFieldTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonRegisterTextFieldTableViewCell.swift; sourceTree = ""; }; @@ -1379,6 +1380,7 @@ 5D526FE225BE9AC400460CB9 /* MastodonSDK in Frameworks */, DB6804862637CD4C00430867 /* AppShared.framework in Frameworks */, DBF96326262EC0A6001D8D25 /* AuthenticationServices.framework in Frameworks */, + DB8D8E2F28192EED009FD90F /* Introspect in Frameworks */, DBAC6483267D0B21007FE9FD /* DifferenceKit in Frameworks */, DB552D4F26BBD10C00E481F6 /* OrderedCollections in Frameworks */, 2D61336925C18A4F00CAE157 /* AlamofireNetworkActivityIndicator in Frameworks */, @@ -2633,6 +2635,7 @@ children = ( DB0618082785B2790030EE79 /* Cell */, DB72601B25E36A2100235243 /* MastodonServerRulesViewController.swift */, + DB7A9F922818F33C0016AF98 /* MastodonServerRulesViewController+Debug.swift */, DB72602625E36A6F00235243 /* MastodonServerRulesViewModel.swift */, DB0617FE27855D6C0030EE79 /* MastodonServerRulesViewModel+Diffable.swift */, ); @@ -3149,6 +3152,7 @@ 2D939AE725EE1CF80076FA61 /* MastodonRegisterViewController+Avatar.swift */, DBE0822325CD3F1E00FD6BBD /* MastodonRegisterViewModel.swift */, DB0618062785A8880030EE79 /* MastodonRegisterViewModel+Diffable.swift */, + DB7A9F902818EAF10016AF98 /* MastodonRegisterView.swift */, ); path = Register; sourceTree = ""; @@ -3324,6 +3328,7 @@ DB552D4E26BBD10C00E481F6 /* OrderedCollections */, DBA5A52E26F07ED800CACBAA /* PanModal */, DB02EA0C280D184B00E751C5 /* CommonOSLog */, + DB8D8E2E28192EED009FD90F /* Introspect */, ); productName = Mastodon; productReference = DB427DD225BAA00100D1B89D /* Mastodon.app */; @@ -3540,6 +3545,7 @@ DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit" */, DB552D4D26BBD10C00E481F6 /* XCRemoteSwiftPackageReference "swift-collections" */, DBA5A52D26F07ED800CACBAA /* XCRemoteSwiftPackageReference "PanModal" */, + DB8D8E2D28192EED009FD90F /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */, ); productRefGroup = DB427DD325BAA00100D1B89D /* Products */; projectDirPath = ""; @@ -3904,7 +3910,6 @@ DB63F75A279953F200455B82 /* SearchHistoryUserCollectionViewCell+ViewModel.swift in Sources */, DB023D26279FFB0A005AC798 /* ShareActivityProvider.swift in Sources */, DB71FD5225F8CCAA00512AE1 /* APIService+Status.swift in Sources */, - DB8481152788121200BBEABA /* MastodonRegisterTextFieldTableViewCell.swift in Sources */, 5D0393962612D266007FE196 /* WebViewModel.swift in Sources */, 5B24BBDA262DB14800A9381B /* ReportViewModel.swift in Sources */, 2D5A3D3825CF8D9F002347D6 /* ScrollViewContainer.swift in Sources */, @@ -3956,7 +3961,6 @@ DBDFF1952805561700557A48 /* DiscoveryPostsViewModel+Diffable.swift in Sources */, DB03A795272A981400EE37C5 /* ContentSplitViewController.swift in Sources */, DBDFF19C28055BD600557A48 /* DiscoveryViewModel.swift in Sources */, - DB06180A2785B2AB0030EE79 /* MastodonRegisterAvatarTableViewCell.swift in Sources */, DBB45B6227B51112002DC5A7 /* SuggestionAccountViewModel+Diffable.swift in Sources */, DBB3BA2A26A81C020004F2D4 /* FLAnimatedImageView.swift in Sources */, DB3E6FF32806D97400B035AE /* DiscoveryNewsViewModel+State.swift in Sources */, @@ -4024,6 +4028,7 @@ DB36679F268ABAF20027D07F /* ComposeStatusAttachmentSection.swift in Sources */, 2DA7D04425CA52B200804E11 /* TimelineLoaderTableViewCell.swift in Sources */, DB63F7542799491600455B82 /* DataSourceFacade+SearchHistory.swift in Sources */, + DB7A9F912818EAF10016AF98 /* MastodonRegisterView.swift in Sources */, DBF1572F27046F1A00EC00B7 /* SecondaryPlaceholderViewController.swift in Sources */, DB03F7F32689AEA3007B274C /* ComposeRepliedToStatusContentTableViewCell.swift in Sources */, 2D4AD8A826316D3500613EFC /* SelectedAccountItem.swift in Sources */, @@ -4118,7 +4123,6 @@ 5DF1056425F887CB00D6C0D4 /* AVPlayer.swift in Sources */, DB3E6FEF2806D82600B035AE /* DiscoveryNewsViewModel.swift in Sources */, DBBF1DCB2652539E00E5B703 /* AutoCompleteItem.swift in Sources */, - DB84811727883C2600BBEABA /* MastodonRegisterPasswordHintTableViewCell.swift in Sources */, 2DA6054725F716A2006356F9 /* PlaybackState.swift in Sources */, DB98EB6727B216560082E365 /* ReportResultViewModel+Diffable.swift in Sources */, DBC7A672260C897100E57475 /* StatusContentWarningEditorView.swift in Sources */, @@ -4274,10 +4278,10 @@ DB0FCB6C27950E29006C02E2 /* MastodonMentionContainer.swift in Sources */, DB6D9F502635761F008423CD /* SubscriptionAlerts.swift in Sources */, 0F20220726134DA4000C64BF /* HashtagTimelineViewModel+Diffable.swift in Sources */, + DB7A9F932818F33C0016AF98 /* MastodonServerRulesViewController+Debug.swift in Sources */, DBE54AC62636C89F004E7C0B /* NotificationPreference.swift in Sources */, 2D5A3D2825CF8BC9002347D6 /* HomeTimelineViewModel+Diffable.swift in Sources */, DB98339C25C96DE600AD9700 /* APIService+Account.swift in Sources */, - DB0618072785A8880030EE79 /* MastodonRegisterViewModel+Diffable.swift in Sources */, DB6B74FC272FF55800C70B6E /* UserSection.swift in Sources */, 2DF75BA725D10E1000694EC8 /* APIService+Favorite.swift in Sources */, DB0FCB862796BDA1006C02E2 /* SearchSection.swift in Sources */, @@ -5465,6 +5469,14 @@ minimumVersion = 4.2.2; }; }; + DB8D8E2D28192EED009FD90F /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/siteline/SwiftUI-Introspect.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 0.1.4; + }; + }; DB9A487C2603456B008B817C /* XCRemoteSwiftPackageReference "UITextView-Placeholder" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/MainasuK/UITextView-Placeholder"; @@ -5587,6 +5599,11 @@ package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */; productName = AlamofireImage; }; + DB8D8E2E28192EED009FD90F /* Introspect */ = { + isa = XCSwiftPackageProductDependency; + package = DB8D8E2D28192EED009FD90F /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */; + productName = Introspect; + }; DB9A487D2603456B008B817C /* UITextView+Placeholder */ = { isa = XCSwiftPackageProductDependency; package = DB9A487C2603456B008B817C /* XCRemoteSwiftPackageReference "UITextView-Placeholder" */; diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index dd92d9e44..df6f38a96 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 34 + 24 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 29 + 23 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 33 + 22 SuppressBuildableAutocreation diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift index 8b1d390f5..8b6eb9f42 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift @@ -58,6 +58,10 @@ extension HomeTimelineViewController { guard let self = self else { return } self.showWelcomeAction(action) }, + UIAction(title: "Register", image: UIImage(systemName: "list.bullet.rectangle.portrait.fill"), attributes: []) { [weak self] action in + guard let self = self else { return } + self.showRegisterAction(action) + }, UIAction(title: "Confirm Email", image: UIImage(systemName: "envelope"), attributes: []) { [weak self] action in guard let self = self else { return } self.showConfirmEmail(action) @@ -294,6 +298,33 @@ extension HomeTimelineViewController { @objc private func showWelcomeAction(_ sender: UIAction) { coordinator.present(scene: .welcome, from: self, transition: .modal(animated: true, completion: nil)) } + + @objc private func showRegisterAction(_ sender: UIAction) { + Task { @MainActor in + try await showRegisterController() + } // end Task + } + + @MainActor + func showRegisterController(domain: String = "mstdn.jp") async throws { + let viewController = try await MastodonRegisterViewController.create( + context: context, + coordinator: coordinator, + domain: "mstdn.jp" + ) + let navigationController = UINavigationController(rootViewController: viewController) + navigationController.modalPresentationStyle = .fullScreen + present(navigationController, animated: true) { + viewController.navigationItem.leftBarButtonItem = UIBarButtonItem( + systemItem: .close, + primaryAction: UIAction(handler: { [weak viewController] _ in + guard let viewController = viewController else { return } + viewController.dismiss(animated: true) + }), + menu: nil + ) + } + } @objc private func showConfirmEmail(_ sender: UIAction) { let mastodonConfirmEmailViewModel = MastodonConfirmEmailViewModel() diff --git a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift index b86c952a4..ffc7708f5 100644 --- a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift +++ b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift @@ -341,7 +341,10 @@ extension MastodonPickServerViewController { ) else { throw APIService.APIError.explicit(.badResponse) } - return MastodonPickServerViewModel.SignUpResponseSecond(instance: response.instance, authenticateInfo: authenticateInfo) + return MastodonPickServerViewModel.SignUpResponseSecond( + instance: response.instance, + authenticateInfo: authenticateInfo + ) } .compactMap { [weak self] response -> AnyPublisher? in guard let self = self else { return nil } @@ -353,7 +356,13 @@ extension MastodonPickServerViewController { clientSecret: authenticateInfo.clientSecret, redirectURI: authenticateInfo.redirectURI ) - .map { MastodonPickServerViewModel.SignUpResponseThird(instance: instance, authenticateInfo: authenticateInfo, applicationToken: $0) } + .map { + MastodonPickServerViewModel.SignUpResponseThird( + instance: instance, + authenticateInfo: authenticateInfo, + applicationToken: $0 + ) + } .eraseToAnyPublisher() } .switchToLatest() diff --git a/Mastodon/Scene/Onboarding/Register/MastodonRegisterView.swift b/Mastodon/Scene/Onboarding/Register/MastodonRegisterView.swift new file mode 100644 index 000000000..1a47de22f --- /dev/null +++ b/Mastodon/Scene/Onboarding/Register/MastodonRegisterView.swift @@ -0,0 +1,304 @@ +// +// MastodonRegisterView.swift +// Mastodon +// +// Created by MainasuK on 2022-4-27. +// + +import UIKit +import SwiftUI +import MastodonLocalization +import MastodonSDK +import MastodonAsset + +struct MastodonRegisterView: View { + + @ObservedObject var viewModel: MastodonRegisterViewModel + + @State var usernameRightViewWidth: CGFloat = 300 + + var body: some View { + ScrollView(.vertical) { + let margin: CGFloat = 16 + + // header + HStack { + Text(L10n.Scene.Register.title(viewModel.domain)) + .font(Font(MastodonPickServerViewController.largeTitleFont as CTFont)) + .foregroundColor(Color(Asset.Colors.Label.primary.color)) + Spacer() + } + .padding(.horizontal, margin) + + // Avatar selector + Menu { + // Photo Library + Button { + viewModel.avatarMediaMenuActionPublisher.send(.photoLibrary) + } label: { + Label(L10n.Scene.Compose.MediaSelection.photoLibrary, systemImage: "photo") + } + // Camera + if UIImagePickerController.isSourceTypeAvailable(.camera) { + Button { + viewModel.avatarMediaMenuActionPublisher.send(.camera) + } label: { + Label(L10n.Scene.Compose.MediaSelection.camera, systemImage: "camera") + } + } + // Browse + Button { + viewModel.avatarMediaMenuActionPublisher.send(.browse) + } label: { + Label(L10n.Scene.Compose.MediaSelection.browse, systemImage: "folder") + } + // Delete + if viewModel.avatarImage != nil { + Divider() + if #available(iOS 15.0, *) { + Button(role: .destructive) { + viewModel.avatarMediaMenuActionPublisher.send(.delete) + } label: { + Label(L10n.Scene.Register.Input.Avatar.delete, systemImage: "delete.left") + } + } else { + // Fallback on earlier ve rsions + Button { + viewModel.avatarMediaMenuActionPublisher.send(.delete) + } label: { + Label(L10n.Scene.Register.Input.Avatar.delete, systemImage: "delete.left") + } + } + } + } label: { + let avatarImage = viewModel.avatarImage ?? Asset.Scene.Onboarding.avatarPlaceholder.image + Image(uiImage: avatarImage) + .resizable() + .frame(width: 88, height: 88, alignment: .center) + .overlay(ZStack { + Color.black.opacity(0.5) + .frame(height: 22, alignment: .bottom) + Text(L10n.Common.Controls.Actions.edit) + .font(.system(size: 13, weight: .semibold)) + .foregroundColor(.white) + }, alignment: .bottom) + .cornerRadius(22) + } + .padding(EdgeInsets(top: 20, leading: 0, bottom: 20, trailing: 0)) + + // Display Name & Uesrname + VStack(alignment: .leading, spacing: 11) { + TextField(L10n.Scene.Register.Input.DisplayName.placeholder.localizedCapitalized, text: $viewModel.name) + .textContentType(.name) + .disableAutocorrection(true) + .modifier(FormTextFieldModifier(validateState: viewModel.displayNameValidateState)) + HStack { + TextField(L10n.Scene.Register.Input.Username.placeholder.localizedCapitalized, text: $viewModel.username) + .textContentType(.username) + .autocapitalization(.none) + .disableAutocorrection(true) + .keyboardType(.asciiCapable) + Text("@\(viewModel.domain)") + .lineLimit(1) + .truncationMode(.middle) + .measureWidth { usernameRightViewWidth = $0 } + .frame(width: min(300.0, usernameRightViewWidth), alignment: .trailing) + } + .modifier(FormTextFieldModifier(validateState: viewModel.usernameValidateState)) + .environment(\.layoutDirection, .leftToRight) // force LTR + if let errorPrompt = viewModel.usernameErrorPrompt { + Text(errorPrompt) + .modifier(FormFootnoteModifier()) + } + } + .padding(.horizontal, margin) + .padding(.bottom, 22) + + // Email & Password & Password hint + VStack(alignment: .leading, spacing: 11) { + TextField(L10n.Scene.Register.Input.Email.placeholder.localizedCapitalized, text: $viewModel.email) + .textContentType(.emailAddress) + .autocapitalization(.none) + .disableAutocorrection(true) + .keyboardType(.emailAddress) + .modifier(FormTextFieldModifier(validateState: viewModel.emailValidateState)) + if let errorPrompt = viewModel.emailErrorPrompt { + Text(errorPrompt) + .modifier(FormFootnoteModifier()) + } + SecureField(L10n.Scene.Register.Input.Password.placeholder.localizedCapitalized, text: $viewModel.password) + .textContentType(.newPassword) + .modifier(FormTextFieldModifier(validateState: viewModel.passwordValidateState)) + Text(L10n.Scene.Register.Input.Password.hint) + .modifier(FormFootnoteModifier(foregroundColor: .secondary)) + if let errorPrompt = viewModel.passwordErrorPrompt { + Text(errorPrompt) + .modifier(FormFootnoteModifier()) + } + } + .padding(.horizontal, margin) + .padding(.bottom, 22) + + // Reason + if viewModel.approvalRequired { + VStack(alignment: .leading, spacing: 11) { + TextField(L10n.Scene.Register.Input.Invite.registrationUserInviteRequest.localizedCapitalized, text: $viewModel.reason) + .modifier(FormTextFieldModifier(validateState: viewModel.reasonValidateState)) + if let errorPrompt = viewModel.reasonErrorPrompt { + Text(errorPrompt) + .modifier(FormFootnoteModifier()) + } + } + .padding(.horizontal, margin) + } + + Spacer() + .frame(minHeight: viewModel.bottomPaddingHeight) + } + .background( + Color(viewModel.backgroundColor) + .onTapGesture { + viewModel.endEditing.send() + } + ) + } + + struct FormTextFieldModifier: ViewModifier { + var validateState: MastodonRegisterViewModel.ValidateState + + func body(content: Content) -> some View { + ZStack { + let shadowColor: Color = { + switch validateState { + case .empty: return .black.opacity(0.125) + case .invalid: return Color(Asset.Colors.TextField.invalid.color) + case .valid: return Color(Asset.Colors.TextField.valid.color) + } + }() + Color(Asset.Scene.Onboarding.textFieldBackground.color) + .cornerRadius(10) + .shadow(color: shadowColor, radius: 1, x: 0, y: 2) + .animation(.easeInOut, value: validateState) + content + .padding() + .background(Color(Asset.Scene.Onboarding.textFieldBackground.color)) + .cornerRadius(10) + } + } + } + + struct FormFootnoteModifier: ViewModifier { + var foregroundColor = Color(Asset.Colors.TextField.invalid.color) + func body(content: Content) -> some View { + content + .font(.footnote) + .foregroundColor(foregroundColor) + .padding(.horizontal) + } + } + + + + +} + +struct WidthKey: PreferenceKey { + static let defaultValue: CGFloat = 0 + static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { + value = nextValue() + } +} + +extension View { + func measureWidth(_ f: @escaping (CGFloat) -> ()) -> some View { + overlay(GeometryReader { proxy in + Color.clear.preference(key: WidthKey.self, value: proxy.size.width) + } + .onPreferenceChange(WidthKey.self, perform: f)) + } +} + +#if DEBUG +struct MastodonRegisterView_Previews: PreviewProvider { + static var viewMdoel: MastodonRegisterViewModel { + let domain = "mstdn.jp" + return MastodonRegisterViewModel( + context: .shared, + domain: domain, + authenticateInfo: AuthenticationViewModel.AuthenticateInfo( + domain: domain, + application: Mastodon.Entity.Application( + name: "Preview", + website: nil, + vapidKey: nil, + redirectURI: nil, + clientID: "", + clientSecret: "" + ), + redirectURI: "" + )!, + instance: Mastodon.Entity.Instance(domain: "mstdn.jp"), + applicationToken: Mastodon.Entity.Token( + accessToken: "", + tokenType: "", + scope: "", + createdAt: Date() + ) + ) + } + + static var viewMdoel2: MastodonRegisterViewModel { + let domain = "mstdn.jp" + return MastodonRegisterViewModel( + context: .shared, + domain: domain, + authenticateInfo: AuthenticationViewModel.AuthenticateInfo( + domain: domain, + application: Mastodon.Entity.Application( + name: "Preview", + website: nil, + vapidKey: nil, + redirectURI: nil, + clientID: "", + clientSecret: "" + ), + redirectURI: "" + )!, + instance: Mastodon.Entity.Instance(domain: "mstdn.jp", approvalRequired: true), + applicationToken: Mastodon.Entity.Token( + accessToken: "", + tokenType: "", + scope: "", + createdAt: Date() + ) + ) + } + + static var previews: some View { + Group { + NavigationView { + MastodonRegisterView(viewModel: viewMdoel) + .navigationBarTitle(Text("")) + .navigationBarTitleDisplayMode(.inline) + } + NavigationView { + MastodonRegisterView(viewModel: viewMdoel) + .navigationBarTitle(Text("")) + .navigationBarTitleDisplayMode(.inline) + } + .preferredColorScheme(.dark) + NavigationView { + MastodonRegisterView(viewModel: viewMdoel) + .navigationBarTitle(Text("")) + .navigationBarTitleDisplayMode(.inline) + } + .environment(\.sizeCategory, .accessibilityExtraLarge) + NavigationView { + MastodonRegisterView(viewModel: viewMdoel2) + .navigationBarTitle(Text("")) + .navigationBarTitleDisplayMode(.inline) + } + } + } +} +#endif diff --git a/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift b/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift index 903c9fbca..89c98759f 100644 --- a/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift +++ b/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewController.swift @@ -11,6 +11,7 @@ import MastodonSDK import os.log import PhotosUI import UIKit +import SwiftUI import MastodonUI import MastodonAsset import MastodonLocalization @@ -28,6 +29,7 @@ final class MastodonRegisterViewController: UIViewController, NeedsDependency, O weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } var viewModel: MastodonRegisterViewModel! + private(set) lazy var mastodonRegisterView = MastodonRegisterView(viewModel: viewModel) // picker private(set) lazy var imagePicker: PHPickerViewController = { @@ -52,22 +54,6 @@ final class MastodonRegisterViewController: UIViewController, NeedsDependency, O return documentPickerController }() - let tapGestureRecognizer = UITapGestureRecognizer.singleTapGestureRecognizer - - let tableView: UITableView = { - let tableView = UITableView() - tableView.rowHeight = UITableView.automaticDimension - tableView.separatorStyle = .none - tableView.backgroundColor = .clear - tableView.keyboardDismissMode = .onDrag - if #available(iOS 15.0, *) { - tableView.sectionHeaderTopPadding = .leastNonzeroMagnitude - } else { - // Fallback on earlier versions - } - return tableView - }() - let navigationActionView: NavigationActionView = { let navigationActionView = NavigationActionView() navigationActionView.backgroundColor = Asset.Scene.Onboarding.background.color @@ -88,17 +74,21 @@ extension MastodonRegisterViewController { navigationItem.leftBarButtonItem = UIBarButtonItem() setupOnboardingAppearance() + viewModel.backgroundColor = view.backgroundColor ?? .clear defer { setupNavigationBarBackgroundView() } - tableView.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(tableView) + let hostingViewController = UIHostingController(rootView: mastodonRegisterView) + hostingViewController.view.preservesSuperviewLayoutMargins = true + addChild(hostingViewController) + hostingViewController.view.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(hostingViewController.view) NSLayoutConstraint.activate([ - tableView.topAnchor.constraint(equalTo: view.topAnchor), - tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), - tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), - tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + hostingViewController.view.topAnchor.constraint(equalTo: view.topAnchor), + hostingViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), + hostingViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), + hostingViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor), ]) navigationActionView.translatesAutoresizingMaskIntoConstraints = false @@ -116,7 +106,7 @@ extension MastodonRegisterViewController { .observe(\.bounds, options: [.initial, .new]) { [weak self] navigationActionView, _ in guard let self = self else { return } let inset = navigationActionView.frame.height - self.tableView.contentInset.bottom = inset + self.viewModel.bottomPaddingHeight = inset } .store(in: &observations) @@ -130,19 +120,14 @@ extension MastodonRegisterViewController { self.navigationActionView.nextButton.isEnabled = isAllValid } .store(in: &disposeBag) - - viewModel.setupDiffableDataSource(tableView: tableView) - - KeyboardResponderService - .configure( - scrollView: tableView, - layoutNeedsUpdate: viewModel.viewDidAppear.eraseToAnyPublisher() - ) - .store(in: &disposeBag) - // gesture - view.addGestureRecognizer(tapGestureRecognizer) - tapGestureRecognizer.addTarget(self, action: #selector(tapGestureRecognizerHandler)) + viewModel.endEditing + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in + guard let self = self else { return } + self.view.endEditing(true) + } + .store(in: &disposeBag) // // return // if viewModel.approvalRequired { @@ -150,64 +135,6 @@ extension MastodonRegisterViewController { // } else { // passwordTextField.returnKeyType = .done // } -// -// viewModel.usernameValidateState -// .receive(on: DispatchQueue.main) -// .sink { [weak self] validateState in -// guard let self = self else { return } -// self.setTextFieldValidAppearance(self.usernameTextField, validateState: validateState) -// } -// .store(in: &disposeBag) -// viewModel.usernameErrorPrompt -// .receive(on: DispatchQueue.main) -// .sink { [weak self] prompt in -// guard let self = self else { return } -// self.usernameErrorPromptLabel.attributedText = prompt -// } -// .store(in: &disposeBag) -// viewModel.displayNameValidateState -// .receive(on: DispatchQueue.main) -// .sink { [weak self] validateState in -// guard let self = self else { return } -// self.setTextFieldValidAppearance(self.displayNameTextField, validateState: validateState) -// } -// .store(in: &disposeBag) -// viewModel.emailValidateState -// .receive(on: DispatchQueue.main) -// .sink { [weak self] validateState in -// guard let self = self else { return } -// self.setTextFieldValidAppearance(self.emailTextField, validateState: validateState) -// } -// .store(in: &disposeBag) -// viewModel.emailErrorPrompt -// .receive(on: DispatchQueue.main) -// .sink { [weak self] prompt in -// guard let self = self else { return } -// self.emailErrorPromptLabel.attributedText = prompt -// } -// .store(in: &disposeBag) -// viewModel.passwordValidateState -// .receive(on: DispatchQueue.main) -// .sink { [weak self] validateState in -// guard let self = self else { return } -// self.setTextFieldValidAppearance(self.passwordTextField, validateState: validateState) -// self.passwordCheckLabel.attributedText = MastodonRegisterViewModel.attributeStringForPassword(validateState: validateState) -// } -// .store(in: &disposeBag) -// viewModel.passwordErrorPrompt -// .receive(on: DispatchQueue.main) -// .sink { [weak self] prompt in -// guard let self = self else { return } -// self.passwordErrorPromptLabel.attributedText = prompt -// } -// .store(in: &disposeBag) -// viewModel.reasonErrorPrompt -// .receive(on: DispatchQueue.main) -// .sink { [weak self] prompt in -// guard let self = self else { return } -// self.reasonErrorPromptLabel.attributedText = prompt -// } -// .store(in: &disposeBag) viewModel.$error .receive(on: DispatchQueue.main) @@ -261,10 +188,6 @@ extension MastodonRegisterViewController { extension MastodonRegisterViewController { - @objc private func tapGestureRecognizerHandler(_ sender: UITapGestureRecognizer) { - view.endEditing(true) - } - @objc private func backButtonPressed(_ sender: UIButton) { logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)") navigationController?.popViewController(animated: true) diff --git a/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewModel+Diffable.swift b/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewModel+Diffable.swift index beb16890b..d8dc8943d 100644 --- a/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewModel+Diffable.swift +++ b/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewModel+Diffable.swift @@ -143,7 +143,7 @@ extension MastodonRegisterViewModel { snapshot.appendItems([.header(domain: domain)], toSection: .main) snapshot.appendItems([.avatar, .name, .username, .email, .password, .hint], toSection: .main) if approvalRequired { - snapshot.appendItems([.reason], toSection: .main) + snapshot.appendItems([.reason], toSection: .main) } diffableDataSource?.applySnapshot(snapshot, animated: false, completion: nil) } @@ -164,51 +164,6 @@ extension MastodonRegisterViewModel { .store(in: &cell.disposeBag) } - enum AvatarMediaMenuAction { - case photoLibrary - case camera - case browse - case delete - } - - private func createAvatarMediaContextMenu() -> UIMenu { - var children: [UIMenuElement] = [] - - // Photo Library - let photoLibraryAction = UIAction(title: L10n.Scene.Compose.MediaSelection.photoLibrary, image: UIImage(systemName: "rectangle.on.rectangle"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off) { [weak self] _ in - guard let self = self else { return } - self.avatarMediaMenuActionPublisher.send(.photoLibrary) - } - children.append(photoLibraryAction) - - // Camera - if UIImagePickerController.isSourceTypeAvailable(.camera) { - let cameraAction = UIAction(title: L10n.Scene.Compose.MediaSelection.camera, image: UIImage(systemName: "camera"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off, handler: { [weak self] _ in - guard let self = self else { return } - self.avatarMediaMenuActionPublisher.send(.camera) - }) - children.append(cameraAction) - } - - // Browse - let browseAction = UIAction(title: L10n.Scene.Compose.MediaSelection.browse, image: UIImage(systemName: "ellipsis"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off) { [weak self] _ in - guard let self = self else { return } - self.avatarMediaMenuActionPublisher.send(.browse) - } - children.append(browseAction) - - // Delete - if avatarImage != nil { - let deleteAction = UIAction(title: L10n.Scene.Register.Input.Avatar.delete, image: UIImage(systemName: "delete.left"), identifier: nil, discoverabilityTitle: nil, attributes: [.destructive], state: .off) { [weak self] _ in - guard let self = self else { return } - self.avatarMediaMenuActionPublisher.send(.delete) - } - children.append(deleteAction) - } - - return UIMenu(title: "", image: nil, identifier: nil, options: .displayInline, children: children) - } - private func configureTextFieldCell( cell: MastodonRegisterTextFieldTableViewCell, validateState: Published.Publisher diff --git a/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewModel.swift b/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewModel.swift index 1ef9cf47a..e7fbd307d 100644 --- a/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewModel.swift +++ b/Mastodon/Scene/Onboarding/Register/MastodonRegisterViewModel.swift @@ -12,7 +12,7 @@ import UIKit import MastodonAsset import MastodonLocalization -final class MastodonRegisterViewModel { +final class MastodonRegisterViewModel: ObservableObject { var disposeBag = Set() // input @@ -23,6 +23,7 @@ final class MastodonRegisterViewModel { let applicationToken: Mastodon.Entity.Token let viewDidAppear = CurrentValueSubject(Void()) + @Published var backgroundColor: UIColor = Asset.Scene.Onboarding.background.color @Published var avatarImage: UIImage? = nil @Published var name = "" @Published var username = "" @@ -30,10 +31,12 @@ final class MastodonRegisterViewModel { @Published var password = "" @Published var reason = "" - let usernameErrorPrompt = CurrentValueSubject(nil) - let emailErrorPrompt = CurrentValueSubject(nil) - let passwordErrorPrompt = CurrentValueSubject(nil) - let reasonErrorPrompt = CurrentValueSubject(nil) + @Published var usernameErrorPrompt: String? = nil + @Published var emailErrorPrompt: String? = nil + @Published var passwordErrorPrompt: String? = nil + @Published var reasonErrorPrompt: String? = nil + + @Published var bottomPaddingHeight: CGFloat = .zero // output var diffableDataSource: UITableViewDiffableDataSource? @@ -51,6 +54,7 @@ final class MastodonRegisterViewModel { @Published var error: Error? = nil let avatarMediaMenuActionPublisher = PassthroughSubject() + let endEditing = PassthroughSubject() init( context: AppContext, @@ -97,45 +101,46 @@ final class MastodonRegisterViewModel { .assign(to: \.usernameValidateState, on: self) .store(in: &disposeBag) - // TODO: check username available -// username -// .filter { !$0.isEmpty } -// .debounce(for: .milliseconds(300), scheduler: DispatchQueue.main) -// .removeDuplicates() -// .compactMap { [weak self] text -> AnyPublisher, Error>, Never>? in -// guard let self = self else { return nil } -// let query = Mastodon.API.Account.AccountLookupQuery(acct: text) -// return context.apiService.accountLookup(domain: domain, query: query, authorization: self.applicationAuthorization) -// .map { -// response -> Result, Error> in -// Result.success(response) -// } -// .catch { error in -// Just(Result.failure(error)) -// } -// .eraseToAnyPublisher() -// } -// .switchToLatest() -// .sink { [weak self] result in -// guard let self = self else { return } -// switch result { -// case .success: -// let text = L10n.Scene.Register.Error.Reason.taken(L10n.Scene.Register.Error.Item.username) -// self.usernameErrorPrompt.value = MastodonRegisterViewModel.errorPromptAttributedString(for: text) -// self.usernameValidateState.value = .invalid -// case .failure: -// break -// } -// } -// .store(in: &disposeBag) -// -// usernameValidateState -// .sink { [weak self] validateState in -// if validateState == .valid { -// self?.usernameErrorPrompt.value = nil -// } -// } -// .store(in: &disposeBag) + // check username available + $username + .filter { !$0.isEmpty } + .debounce(for: .milliseconds(300), scheduler: DispatchQueue.main) + .removeDuplicates() + .compactMap { [weak self] text -> AnyPublisher, Error>, Never>? in + guard let self = self else { return nil } + let query = Mastodon.API.Account.AccountLookupQuery(acct: text) + return context.apiService.accountLookup(domain: domain, query: query, authorization: self.applicationAuthorization) + .map { + response -> Result, Error> in + Result.success(response) + } + .catch { error in + Just(Result.failure(error)) + } + .eraseToAnyPublisher() + } + .switchToLatest() + .receive(on: DispatchQueue.main) + .sink { [weak self] result in + guard let self = self else { return } + switch result { + case .success: + let text = L10n.Scene.Register.Error.Reason.taken(L10n.Scene.Register.Error.Item.username) + self.usernameErrorPrompt = text + self.usernameValidateState = .invalid + case .failure: + break + } + } + .store(in: &disposeBag) + + $usernameValidateState + .sink { [weak self] validateState in + if validateState == .valid { + self?.usernameErrorPrompt = nil + } + } + .store(in: &disposeBag) $email .map { email in @@ -163,27 +168,31 @@ final class MastodonRegisterViewModel { .store(in: &disposeBag) } -// error -// .sink { [weak self] error in -// guard let self = self else { return } -// let error = error as? Mastodon.API.Error -// let mastodonError = error?.mastodonError -// if case let .generic(genericMastodonError) = mastodonError, -// let details = genericMastodonError.details -// { -// self.usernameErrorPrompt.value = details.usernameErrorDescriptions.first.flatMap { MastodonRegisterViewModel.errorPromptAttributedString(for: $0) } -// self.emailErrorPrompt.value = details.emailErrorDescriptions.first.flatMap { MastodonRegisterViewModel.errorPromptAttributedString(for: $0) } -// self.passwordErrorPrompt.value = details.passwordErrorDescriptions.first.flatMap { MastodonRegisterViewModel.errorPromptAttributedString(for: $0) } -// self.reasonErrorPrompt.value = details.reasonErrorDescriptions.first.flatMap { MastodonRegisterViewModel.errorPromptAttributedString(for: $0) } -// } else { -// self.usernameErrorPrompt.value = nil -// self.emailErrorPrompt.value = nil -// self.passwordErrorPrompt.value = nil -// self.reasonErrorPrompt.value = nil -// } -// } -// .store(in: &disposeBag) -// + $error + .sink { [weak self] error in + guard let self = self else { return } + let error = error as? Mastodon.API.Error + let mastodonError = error?.mastodonError + if case let .generic(genericMastodonError) = mastodonError, + let details = genericMastodonError.details + { + self.usernameErrorPrompt = details.usernameErrorDescriptions.first + details.usernameErrorDescriptions.first.flatMap { _ in self.usernameValidateState = .invalid } + self.emailErrorPrompt = details.emailErrorDescriptions.first + details.emailErrorDescriptions.first.flatMap { _ in self.emailValidateState = .invalid } + self.passwordErrorPrompt = details.passwordErrorDescriptions.first + details.passwordErrorDescriptions.first.flatMap { _ in self.passwordValidateState = .invalid } + self.reasonErrorPrompt = details.reasonErrorDescriptions.first + details.reasonErrorDescriptions.first.flatMap { _ in self.reasonValidateState = .invalid } + } else { + self.usernameErrorPrompt = nil + self.emailErrorPrompt = nil + self.passwordErrorPrompt = nil + self.reasonErrorPrompt = nil + } + } + .store(in: &disposeBag) + let publisherOne = Publishers.CombineLatest4( $usernameValidateState, $displayNameValidateState, @@ -213,7 +222,7 @@ final class MastodonRegisterViewModel { } extension MastodonRegisterViewModel { - enum ValidateState { + enum ValidateState: Hashable { case empty case invalid case valid @@ -271,3 +280,52 @@ extension MastodonRegisterViewModel { return attributeString } } + +extension MastodonRegisterViewModel { + + enum AvatarMediaMenuAction { + case photoLibrary + case camera + case browse + case delete + } + + private func createAvatarMediaContextMenu() -> UIMenu { + var children: [UIMenuElement] = [] + + // Photo Library + let photoLibraryAction = UIAction(title: L10n.Scene.Compose.MediaSelection.photoLibrary, image: UIImage(systemName: "rectangle.on.rectangle"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off) { [weak self] _ in + guard let self = self else { return } + self.avatarMediaMenuActionPublisher.send(.photoLibrary) + } + children.append(photoLibraryAction) + + // Camera + if UIImagePickerController.isSourceTypeAvailable(.camera) { + let cameraAction = UIAction(title: L10n.Scene.Compose.MediaSelection.camera, image: UIImage(systemName: "camera"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off, handler: { [weak self] _ in + guard let self = self else { return } + self.avatarMediaMenuActionPublisher.send(.camera) + }) + children.append(cameraAction) + } + + // Browse + let browseAction = UIAction(title: L10n.Scene.Compose.MediaSelection.browse, image: UIImage(systemName: "ellipsis"), identifier: nil, discoverabilityTitle: nil, attributes: [], state: .off) { [weak self] _ in + guard let self = self else { return } + self.avatarMediaMenuActionPublisher.send(.browse) + } + children.append(browseAction) + + // Delete + if avatarImage != nil { + let deleteAction = UIAction(title: L10n.Scene.Register.Input.Avatar.delete, image: UIImage(systemName: "delete.left"), identifier: nil, discoverabilityTitle: nil, attributes: [.destructive], state: .off) { [weak self] _ in + guard let self = self else { return } + self.avatarMediaMenuActionPublisher.send(.delete) + } + children.append(deleteAction) + } + + return UIMenu(title: "", image: nil, identifier: nil, options: .displayInline, children: children) + } + +} diff --git a/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewController+Debug.swift b/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewController+Debug.swift new file mode 100644 index 000000000..f6aaf5fba --- /dev/null +++ b/Mastodon/Scene/Onboarding/ServerRules/MastodonServerRulesViewController+Debug.swift @@ -0,0 +1,50 @@ +// +// MastodonServerRulesViewController+Debug.swift +// Mastodon +// +// Created by MainasuK on 2022-4-27. +// + +import UIKit + +#if DEBUG + +extension MastodonRegisterViewController { + + @MainActor + static func create( + context: AppContext, + coordinator: SceneCoordinator, + domain: String + ) async throws -> MastodonRegisterViewController { + let viewController = MastodonRegisterViewController() + viewController.context = context + viewController.coordinator = coordinator + + let instanceResponse = try await context.apiService.instance(domain: domain).singleOutput() + let applicationResponse = try await context.apiService.createApplication(domain: domain).singleOutput() + let accessTokenResponse = try await context.apiService.applicationAccessToken( + domain: domain, + clientID: applicationResponse.value.clientID!, + clientSecret: applicationResponse.value.clientSecret!, + redirectURI: applicationResponse.value.redirectURI! + ).singleOutput() + + viewController.viewModel = MastodonRegisterViewModel( + context: context, + domain: domain, + authenticateInfo: .init( + domain: domain, + application: applicationResponse.value + )!, + instance: instanceResponse.value, + applicationToken: accessTokenResponse.value + ) + + return viewController + } + +} + +#endif + diff --git a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift index f470082f2..1b08722d5 100644 --- a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift +++ b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift @@ -270,7 +270,15 @@ extension MainTabBarController { updateTabBarDisplay() #if DEBUG -// selectedIndex = 1 + // Debug Register viewController + // Task { @MainActor in + // let _homeTimelineViewController = viewControllers + // .compactMap { $0 as? UINavigationController } + // .compactMap { $0.topViewController } + // .compactMap { $0 as? HomeTimelineViewController } + // .first + // try await _homeTimelineViewController?.showRegisterController() + // } // end Task #endif } diff --git a/Mastodon/Service/APIService/APIService+HomeTimeline.swift b/Mastodon/Service/APIService/APIService+HomeTimeline.swift index 39d4cf6e1..863510af4 100644 --- a/Mastodon/Service/APIService/APIService+HomeTimeline.swift +++ b/Mastodon/Service/APIService/APIService+HomeTimeline.swift @@ -1,5 +1,5 @@ // -// APIService+HomeTimeline.swift +// µ.swift // Mastodon // // Created by MainasuK Cirno on 2021/2/3. diff --git a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Instance.swift b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Instance.swift index 7cf4890bc..5d649a841 100644 --- a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Instance.swift +++ b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Instance.swift @@ -38,7 +38,7 @@ extension Mastodon.Entity { // https://github.com/mastodon/mastodon/pull/16485 public let configuration: Configuration? - public init(domain: String) { + public init(domain: String, approvalRequired: Bool? = nil) { self.uri = domain self.title = domain self.description = "" @@ -47,7 +47,7 @@ extension Mastodon.Entity { self.version = nil self.languages = nil self.registrations = nil - self.approvalRequired = nil + self.approvalRequired = approvalRequired self.invitesEnabled = nil self.urls = nil self.statistics = nil From 090f847fa88709a9f66215ea0ef48786d8ca1e1c Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 27 Apr 2022 17:38:50 +0800 Subject: [PATCH 035/101] chore: update version to 1.3.3 (115) --- AppShared/Info.plist | 4 +-- Mastodon.xcodeproj/project.pbxproj | 36 +++++++++---------- .../xcschemes/xcschememanagement.plist | 6 ++-- Mastodon/Info.plist | 4 +-- MastodonIntent/Info.plist | 4 +-- MastodonTests/Info.plist | 4 +-- MastodonUITests/Info.plist | 4 +-- NotificationService/Info.plist | 4 +-- ShareActionExtension/Info.plist | 4 +-- 9 files changed, 35 insertions(+), 35 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 57f861546..1f75bbd84 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.2 + 1.3.3 CFBundleVersion - 113 + 115 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 23d536ddd..3cace6ad8 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4741,7 +4741,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 114; + CURRENT_PROJECT_VERSION = 115; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4770,7 +4770,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 114; + CURRENT_PROJECT_VERSION = 115; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4878,11 +4878,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 114; + CURRENT_PROJECT_VERSION = 115; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 114; + DYLIB_CURRENT_VERSION = 115; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4909,11 +4909,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 114; + CURRENT_PROJECT_VERSION = 115; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 114; + DYLIB_CURRENT_VERSION = 115; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4938,7 +4938,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 114; + CURRENT_PROJECT_VERSION = 115; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4963,7 +4963,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 114; + CURRENT_PROJECT_VERSION = 115; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4988,7 +4988,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 114; + CURRENT_PROJECT_VERSION = 115; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5013,7 +5013,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 114; + CURRENT_PROJECT_VERSION = 115; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5099,7 +5099,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 114; + CURRENT_PROJECT_VERSION = 115; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5166,11 +5166,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 114; + CURRENT_PROJECT_VERSION = 115; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 114; + DYLIB_CURRENT_VERSION = 115; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5195,7 +5195,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 114; + CURRENT_PROJECT_VERSION = 115; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5219,7 +5219,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 114; + CURRENT_PROJECT_VERSION = 115; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5244,7 +5244,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 114; + CURRENT_PROJECT_VERSION = 115; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5269,7 +5269,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 114; + CURRENT_PROJECT_VERSION = 115; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5293,7 +5293,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 114; + CURRENT_PROJECT_VERSION = 115; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index df6f38a96..40155e274 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 24 + 34 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 23 + 33 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 22 + 32 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 15aa3c303..ed0bf25d2 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -30,7 +30,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.2 + 1.3.3 CFBundleURLTypes @@ -43,7 +43,7 @@ CFBundleVersion - 113 + 115 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 24aa97d11..86d1d76a1 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.2 + 1.3.3 CFBundleVersion - 113 + 115 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 57f861546..1f75bbd84 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.2 + 1.3.3 CFBundleVersion - 113 + 115 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 57f861546..1f75bbd84 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.2 + 1.3.3 CFBundleVersion - 113 + 115 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index 06f7249fd..497e092e5 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.2 + 1.3.3 CFBundleVersion - 113 + 115 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index ebde7beda..0296bd970 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.2 + 1.3.3 CFBundleVersion - 113 + 115 NSExtension NSExtensionAttributes From f365b51e418d358b35119cb66a2d7669dc0f0808 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 27 Apr 2022 20:34:21 +0800 Subject: [PATCH 036/101] chore: add Swedish language --- .../Sources/StringsConvertor/main.swift | 1 + Mastodon.xcodeproj/project.pbxproj | 7 +++ Mastodon/Resources/sv.lproj/InfoPlist.strings | 4 ++ MastodonIntent/sv.lproj/Intents.strings | 52 ++++++++++++++++++ MastodonIntent/sv.lproj/Intents.stringsdict | 54 +++++++++++++++++++ 5 files changed, 118 insertions(+) create mode 100644 Mastodon/Resources/sv.lproj/InfoPlist.strings create mode 100644 MastodonIntent/sv.lproj/Intents.strings create mode 100644 MastodonIntent/sv.lproj/Intents.stringsdict diff --git a/Localization/StringsConvertor/Sources/StringsConvertor/main.swift b/Localization/StringsConvertor/Sources/StringsConvertor/main.swift index 606a95200..92a858829 100644 --- a/Localization/StringsConvertor/Sources/StringsConvertor/main.swift +++ b/Localization/StringsConvertor/Sources/StringsConvertor/main.swift @@ -62,6 +62,7 @@ private func map(language: String) -> String? { case "gd_GB": return "gd-GB" // Scottish Gaelic case "es_ES": return "es" // Spanish case "es_AR": return "es-419" // Spanish, Argentina + case "sv-SE": return "sv" // Swedish case "sv_FI": return "sv_FI" // Swedish, Finland case "th_TH": return "th" // Thai case "vi_VN": return "vi" // Vietnamese diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 3cace6ad8..153d74e44 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -1165,6 +1165,9 @@ DB8AF54325C13647002E6C99 /* NeedsDependency.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NeedsDependency.swift; sourceTree = ""; }; DB8AF54F25C13703002E6C99 /* MainTabBarController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainTabBarController.swift; sourceTree = ""; }; DB8AF55C25C138B7002E6C99 /* UIViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIViewController.swift; sourceTree = ""; }; + DB8D8E3128196FA0009FD90F /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Intents.strings; sourceTree = ""; }; + DB8D8E3228196FA0009FD90F /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/InfoPlist.strings; sourceTree = ""; }; + DB8D8E3328196FA0009FD90F /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = sv; path = sv.lproj/Intents.stringsdict; sourceTree = ""; }; DB8F7075279E954700E1225B /* DataSourceFacade+Follow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DataSourceFacade+Follow.swift"; sourceTree = ""; }; DB8FAB9E26AEC3A2008E5AF4 /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; }; DB8FABA926AEC3A2008E5AF4 /* IntentsUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IntentsUI.framework; path = System/Library/Frameworks/IntentsUI.framework; sourceTree = SDKROOT; }; @@ -3526,6 +3529,7 @@ ku, kab, vi, + sv, ); mainGroup = DB427DC925BAA00100D1B89D; packageReferences = ( @@ -4531,6 +4535,7 @@ DBEB19E927E4F37B00B0E80E /* ku */, DBF81C7427F68F5A00004A56 /* kab */, DBF81C7727F6913300004A56 /* vi */, + DB8D8E3128196FA0009FD90F /* sv */, ); name = Intents.intentdefinition; sourceTree = ""; @@ -4556,6 +4561,7 @@ DBEB19EA27E4F37B00B0E80E /* ku */, DBF81C7527F68F5A00004A56 /* kab */, DBF81C7827F6913300004A56 /* vi */, + DB8D8E3228196FA0009FD90F /* sv */, ); name = InfoPlist.strings; sourceTree = ""; @@ -4597,6 +4603,7 @@ DBEB19EB27E4F37B00B0E80E /* ku */, DBF81C7627F68F5A00004A56 /* kab */, DBF81C7927F6913300004A56 /* vi */, + DB8D8E3328196FA0009FD90F /* sv */, ); name = Intents.stringsdict; sourceTree = ""; diff --git a/Mastodon/Resources/sv.lproj/InfoPlist.strings b/Mastodon/Resources/sv.lproj/InfoPlist.strings new file mode 100644 index 000000000..710865573 --- /dev/null +++ b/Mastodon/Resources/sv.lproj/InfoPlist.strings @@ -0,0 +1,4 @@ +"NSCameraUsageDescription" = "Used to take photo for post status"; +"NSPhotoLibraryAddUsageDescription" = "Used to save photo into the Photo Library"; +"NewPostShortcutItemTitle" = "New Post"; +"SearchShortcutItemTitle" = "Search"; \ No newline at end of file diff --git a/MastodonIntent/sv.lproj/Intents.strings b/MastodonIntent/sv.lproj/Intents.strings new file mode 100644 index 000000000..b85bec4c5 --- /dev/null +++ b/MastodonIntent/sv.lproj/Intents.strings @@ -0,0 +1,52 @@ +"16wxgf" = "Post on Mastodon"; + +"751xkl" = "Text Content"; + +"CsR7G2" = "Post on Mastodon"; + +"HZSGTr" = "What content to post?"; + +"HdGikU" = "Posting failed"; + +"KDNTJ4" = "Failure Reason"; + +"RHxKOw" = "Send Post with text content"; + +"RxSqsb" = "Post"; + +"WCIR3D" = "Post ${content} on Mastodon"; + +"ZKJSNu" = "Post"; + +"ZS1XaK" = "${content}"; + +"ZbSjzC" = "Visibility"; + +"Zo4jgJ" = "Post Visibility"; + +"apSxMG-dYQ5NN" = "There are ${count} options matching ‘Public’."; + +"apSxMG-ehFLjY" = "There are ${count} options matching ‘Followers Only’."; + +"ayoYEb-dYQ5NN" = "${content}, Public"; + +"ayoYEb-ehFLjY" = "${content}, Followers Only"; + +"dUyuGg" = "Post on Mastodon"; + +"dYQ5NN" = "Public"; + +"ehFLjY" = "Followers Only"; + +"gfePDu" = "Posting failed. ${failureReason}"; + +"k7dbKQ" = "Post was sent successfully."; + +"oGiqmY-dYQ5NN" = "Just to confirm, you wanted ‘Public’?"; + +"oGiqmY-ehFLjY" = "Just to confirm, you wanted ‘Followers Only’?"; + +"rM6dvp" = "URL"; + +"ryJLwG" = "Post was sent successfully."; + diff --git a/MastodonIntent/sv.lproj/Intents.stringsdict b/MastodonIntent/sv.lproj/Intents.stringsdict new file mode 100644 index 000000000..5a39d5e64 --- /dev/null +++ b/MastodonIntent/sv.lproj/Intents.stringsdict @@ -0,0 +1,54 @@ + + + + + There are ${count} options matching ‘${content}’. - 2 + + NSStringLocalizedFormatKey + There are %#@count_option@ matching ‘${content}’. + count_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + %ld + zero + 0 options + one + 1 option + two + 2 options + few + %ld options + many + %ld options + other + %ld options + + + There are ${count} options matching ‘${visibility}’. + + NSStringLocalizedFormatKey + There are %#@count_option@ matching ‘${visibility}’. + count_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + %ld + zero + 0 options + one + 1 option + two + 2 options + few + %ld options + many + %ld options + other + %ld options + + + + From afc424e6103924e37235509dc38af44937e04f4d Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 27 Apr 2022 20:37:04 +0800 Subject: [PATCH 037/101] chore: update i18n resources --- .../Generated/Strings.swift | 4 + .../Resources/ar.lproj/Localizable.strings | 4 +- .../Resources/ca.lproj/Localizable.strings | 2 + .../Resources/de.lproj/Localizable.strings | 2 + .../Resources/en.lproj/Localizable.strings | 2 + .../es-419.lproj/Localizable.strings | 10 +- .../Resources/es.lproj/Localizable.strings | 30 +-- .../es.lproj/Localizable.stringsdict | 4 +- .../Resources/eu-ES.lproj/Localizable.strings | 10 +- .../Resources/fr.lproj/Localizable.strings | 2 + .../Resources/gd-GB.lproj/Localizable.strings | 10 +- .../Resources/ja.lproj/Localizable.strings | 32 ++-- .../Resources/kab.lproj/Localizable.strings | 32 ++-- .../kab.lproj/Localizable.stringsdict | 4 +- .../Resources/ku.lproj/Localizable.strings | 2 + .../Resources/nl.lproj/Localizable.strings | 180 +++++++++--------- .../Resources/ru.lproj/Localizable.strings | 2 + .../Resources/sv_FI.lproj/Localizable.strings | 2 + .../Resources/th.lproj/Localizable.strings | 2 + .../Resources/vi.lproj/Localizable.strings | 16 +- .../zh-Hans.lproj/Localizable.strings | 8 +- 21 files changed, 200 insertions(+), 160 deletions(-) diff --git a/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift b/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift index f2bec6b01..36ddc8ffe 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift +++ b/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift @@ -270,6 +270,8 @@ public enum L10n { public static let contentWarning = L10n.tr("Localizable", "Common.Controls.Status.ContentWarning") /// Tap anywhere to reveal public static let mediaContentWarning = L10n.tr("Localizable", "Common.Controls.Status.MediaContentWarning") + /// Sensitive Content + public static let sensitiveContent = L10n.tr("Localizable", "Common.Controls.Status.SensitiveContent") /// Show Post public static let showPost = L10n.tr("Localizable", "Common.Controls.Status.ShowPost") /// Show user profile @@ -544,6 +546,8 @@ public enum L10n { } } public enum Discovery { + /// These are the posts gaining traction in your corner of Mastodon. + public static let intro = L10n.tr("Localizable", "Scene.Discovery.Intro") public enum Tabs { /// For You public static let forYou = L10n.tr("Localizable", "Scene.Discovery.Tabs.ForYou") diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings index bf6ab09e6..2cb63b209 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings @@ -108,6 +108,7 @@ "Common.Controls.Status.MediaContentWarning" = "اُنقُر لِلكَشف"; "Common.Controls.Status.Poll.Closed" = "انتهى"; "Common.Controls.Status.Poll.Vote" = "صَوِّت"; +"Common.Controls.Status.SensitiveContent" = "مُحتَوى حَسَّاس"; "Common.Controls.Status.ShowPost" = "أظْهِر مَنشور"; "Common.Controls.Status.ShowUserProfile" = "أظْهِر المِلَفَّ التَّعريفِيَّ لِلمُستَخدِم"; "Common.Controls.Status.Tag.Email" = "بَريدٌ إلِكتُرُونِيّ"; @@ -201,7 +202,8 @@ "Scene.ConfirmEmail.Subtitle" = "لقد أرسلنا للتو بريد إلكتروني إلى %@، انقر على الرابط لتأكيد حسابك."; "Scene.ConfirmEmail.Title" = "شيءٌ أخير."; -"Scene.Discovery.Tabs.ForYou" = "For You"; +"Scene.Discovery.Intro" = "هَذِهِ هِيَ المَنشُوراتُ الَّتي تَكْتَسِبُ شَعبِيَّةً فِي الرُّكنِ الخاصِّ بِكَ مِن مَاستُودون."; +"Scene.Discovery.Tabs.ForYou" = "لَك"; "Scene.Discovery.Tabs.Hashtags" = "الوسوم"; "Scene.Discovery.Tabs.News" = "الأخبار"; "Scene.Discovery.Tabs.Posts" = "المنشورات"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings index 4e10ce165..62ddadfaf 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings @@ -108,6 +108,7 @@ Comprova la teva connexió a Internet."; "Common.Controls.Status.MediaContentWarning" = "Toca qualsevol lloc per a mostrar"; "Common.Controls.Status.Poll.Closed" = "Finalitzada"; "Common.Controls.Status.Poll.Vote" = "Vota"; +"Common.Controls.Status.SensitiveContent" = "Contingut sensible"; "Common.Controls.Status.ShowPost" = "Mostra la Publicació"; "Common.Controls.Status.ShowUserProfile" = "Mostra el perfil de l'usuari"; "Common.Controls.Status.Tag.Email" = "Correu electrònic"; @@ -200,6 +201,7 @@ carregat a Mastodon."; "Scene.ConfirmEmail.OpenEmailApp.Title" = "Comprova la teva safata d'entrada."; "Scene.ConfirmEmail.Subtitle" = "Toca l'enllaç del correu electrònic que t'hem enviat per a confirmar el teu compte."; "Scene.ConfirmEmail.Title" = "Una última cosa."; +"Scene.Discovery.Intro" = "Aquestes son les publicacions que criden l'atenció en el teu racó de Mastodon."; "Scene.Discovery.Tabs.ForYou" = "Per a tu"; "Scene.Discovery.Tabs.Hashtags" = "Etiquetes"; "Scene.Discovery.Tabs.News" = "Notícies"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings index 06f5eedff..71dd59d0f 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings @@ -108,6 +108,7 @@ Bitte überprüfe deine Internetverbindung."; "Common.Controls.Status.MediaContentWarning" = "Tippe irgendwo zum Anzeigen"; "Common.Controls.Status.Poll.Closed" = "Beendet"; "Common.Controls.Status.Poll.Vote" = "Abstimmen"; +"Common.Controls.Status.SensitiveContent" = "Sensitive Content"; "Common.Controls.Status.ShowPost" = "Beitrag anzeigen"; "Common.Controls.Status.ShowUserProfile" = "Benutzerprofil anzeigen"; "Common.Controls.Status.Tag.Email" = "E-Mail"; @@ -201,6 +202,7 @@ kann nicht auf Mastodon hochgeladen werden."; "Scene.ConfirmEmail.Subtitle" = "Wir haben gerade eine E-Mail an %@ gesendet, tippe darin auf den Link, um Dein Konto zu bestätigen."; "Scene.ConfirmEmail.Title" = "Noch eine letzte Sache."; +"Scene.Discovery.Intro" = "These are the posts gaining traction in your corner of Mastodon."; "Scene.Discovery.Tabs.ForYou" = "Für dich"; "Scene.Discovery.Tabs.Hashtags" = "Hashtags"; "Scene.Discovery.Tabs.News" = "Nachrichten"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings index 4edf4702f..eb1838e34 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings @@ -108,6 +108,7 @@ Please check your internet connection."; "Common.Controls.Status.MediaContentWarning" = "Tap anywhere to reveal"; "Common.Controls.Status.Poll.Closed" = "Closed"; "Common.Controls.Status.Poll.Vote" = "Vote"; +"Common.Controls.Status.SensitiveContent" = "Sensitive Content"; "Common.Controls.Status.ShowPost" = "Show Post"; "Common.Controls.Status.ShowUserProfile" = "Show user profile"; "Common.Controls.Status.Tag.Email" = "Email"; @@ -200,6 +201,7 @@ uploaded to Mastodon."; "Scene.ConfirmEmail.OpenEmailApp.Title" = "Check your inbox."; "Scene.ConfirmEmail.Subtitle" = "Tap the link we emailed to you to verify your account."; "Scene.ConfirmEmail.Title" = "One last thing."; +"Scene.Discovery.Intro" = "These are the posts gaining traction in your corner of Mastodon."; "Scene.Discovery.Tabs.ForYou" = "For You"; "Scene.Discovery.Tabs.Hashtags" = "Hashtags"; "Scene.Discovery.Tabs.News" = "News"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.strings index 0782206f4..0203cd195 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.strings @@ -90,9 +90,9 @@ Por favor, revisá tu conexión a Internet."; "Common.Controls.Keyboard.Timeline.PreviewImage" = "Previsualizar imagen"; "Common.Controls.Keyboard.Timeline.PreviousStatus" = "Mensaje anterior"; "Common.Controls.Keyboard.Timeline.ReplyStatus" = "Responder al mensaje"; -"Common.Controls.Keyboard.Timeline.ToggleContentWarning" = "Cambiar la advertencia de contenido"; -"Common.Controls.Keyboard.Timeline.ToggleFavorite" = "Cambiar la marca de favorito en el mensaje"; -"Common.Controls.Keyboard.Timeline.ToggleReblog" = "Cambiar la adhesión en el mensaje"; +"Common.Controls.Keyboard.Timeline.ToggleContentWarning" = "Cambiar modo de advertencia de contenido"; +"Common.Controls.Keyboard.Timeline.ToggleFavorite" = "Cambiar marca de favorito del mensaje"; +"Common.Controls.Keyboard.Timeline.ToggleReblog" = "Cambiar adhesión al mensaje"; "Common.Controls.Status.Actions.Favorite" = "Marcar como favorito"; "Common.Controls.Status.Actions.Hide" = "Ocultar"; "Common.Controls.Status.Actions.Menu" = "Menú"; @@ -105,9 +105,10 @@ Por favor, revisá tu conexión a Internet."; "Common.Controls.Status.Actions.Unfavorite" = "Dejar de marcar como favorito"; "Common.Controls.Status.Actions.Unreblog" = "Deshacer adhesión"; "Common.Controls.Status.ContentWarning" = "Advertencia de contenido"; -"Common.Controls.Status.MediaContentWarning" = "Toca en cualquier lugar para mostrar"; +"Common.Controls.Status.MediaContentWarning" = "Tocá en cualquier parte para mostrar"; "Common.Controls.Status.Poll.Closed" = "Cerrada"; "Common.Controls.Status.Poll.Vote" = "Votar"; +"Common.Controls.Status.SensitiveContent" = "Contenido sensible"; "Common.Controls.Status.ShowPost" = "Mostrar mensaje"; "Common.Controls.Status.ShowUserProfile" = "Mostrar perfil de usuario"; "Common.Controls.Status.Tag.Email" = "Correo electrónico"; @@ -201,6 +202,7 @@ y no se puede subir a Mastodon."; "Scene.ConfirmEmail.Subtitle" = "Acabamos de enviar un correo electrónico a %@, pulsá en el enlace para confirmar tu cuenta."; "Scene.ConfirmEmail.Title" = "Una última cosa."; +"Scene.Discovery.Intro" = "Estos son los mensajes que están ganando tracción en tu rincón de Mastodon."; "Scene.Discovery.Tabs.ForYou" = "Para vos"; "Scene.Discovery.Tabs.Hashtags" = "Etiquetas"; "Scene.Discovery.Tabs.News" = "Novedades"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.strings index 544a0b86c..9da54c16b 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.strings @@ -98,16 +98,17 @@ Por favor, revise su conexión a internet."; "Common.Controls.Status.Actions.Menu" = "Menú"; "Common.Controls.Status.Actions.Reblog" = "Rebloguear"; "Common.Controls.Status.Actions.Reply" = "Responder"; -"Common.Controls.Status.Actions.ShowGif" = "Show GIF"; -"Common.Controls.Status.Actions.ShowImage" = "Show image"; -"Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; -"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tap then hold to show menu"; +"Common.Controls.Status.Actions.ShowGif" = "Mostrar GIF"; +"Common.Controls.Status.Actions.ShowImage" = "Mostrar imagen"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Mostrar reproductor de vídeo"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Toca, después mantén para mostrar el menú"; "Common.Controls.Status.Actions.Unfavorite" = "No favorito"; "Common.Controls.Status.Actions.Unreblog" = "Deshacer reblogueo"; "Common.Controls.Status.ContentWarning" = "Advertencia de Contenido"; "Common.Controls.Status.MediaContentWarning" = "Pulsa en cualquier sitio para mostrar"; "Common.Controls.Status.Poll.Closed" = "Cerrado"; "Common.Controls.Status.Poll.Vote" = "Vota"; +"Common.Controls.Status.SensitiveContent" = "Sensitive Content"; "Common.Controls.Status.ShowPost" = "Mostrar Publicación"; "Common.Controls.Status.ShowUserProfile" = "Mostrar perfil del usuario"; "Common.Controls.Status.Tag.Email" = "E-mail"; @@ -116,7 +117,7 @@ Por favor, revise su conexión a internet."; "Common.Controls.Status.Tag.Link" = "Enlace"; "Common.Controls.Status.Tag.Mention" = "Mención"; "Common.Controls.Status.Tag.Url" = "URL"; -"Common.Controls.Status.TapToReveal" = "Tap to reveal"; +"Common.Controls.Status.TapToReveal" = "Tocar para revelar"; "Common.Controls.Status.UserReblogged" = "%@ lo reblogueó"; "Common.Controls.Status.UserRepliedTo" = "En respuesta a %@"; "Common.Controls.Status.Visibility.Direct" = "Sólo el usuario mencionado puede ver este mensaje."; @@ -201,10 +202,11 @@ subirse a Mastodon."; "Scene.ConfirmEmail.Subtitle" = "Te acabamos de enviar un correo a %@, pulsa en el enlace para confirmar tu cuenta."; "Scene.ConfirmEmail.Title" = "Una última cosa."; -"Scene.Discovery.Tabs.ForYou" = "For You"; -"Scene.Discovery.Tabs.Hashtags" = "Hashtags"; -"Scene.Discovery.Tabs.News" = "News"; -"Scene.Discovery.Tabs.Posts" = "Posts"; +"Scene.Discovery.Intro" = "These are the posts gaining traction in your corner of Mastodon."; +"Scene.Discovery.Tabs.ForYou" = "Para Ti"; +"Scene.Discovery.Tabs.Hashtags" = "Etiquetas"; +"Scene.Discovery.Tabs.News" = "Noticias"; +"Scene.Discovery.Tabs.Posts" = "Publicaciones"; "Scene.Favorite.Title" = "Tus Favoritos"; "Scene.Follower.Footer" = "No se muestran los seguidores de otros servidores."; "Scene.Following.Footer" = "No se muestran los seguidos de otros servidores."; @@ -226,10 +228,10 @@ pulsa en el enlace para confirmar tu cuenta."; "Scene.Preview.Keyboard.ClosePreview" = "Cerrar Previsualización"; "Scene.Preview.Keyboard.ShowNext" = "Mostrar Siguiente"; "Scene.Preview.Keyboard.ShowPrevious" = "Mostrar Anterior"; -"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Double tap to open the list"; -"Scene.Profile.Accessibility.EditAvatarImage" = "Edit avatar image"; -"Scene.Profile.Accessibility.ShowAvatarImage" = "Show avatar image"; -"Scene.Profile.Accessibility.ShowBannerImage" = "Show banner image"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Pulsa dos veces para abrir la lista"; +"Scene.Profile.Accessibility.EditAvatarImage" = "Editar imagen del avatar"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "Mostrar imagen del avatar"; +"Scene.Profile.Accessibility.ShowBannerImage" = "Mostrar imagen de banner"; "Scene.Profile.Dashboard.Followers" = "seguidores"; "Scene.Profile.Dashboard.Following" = "siguiendo"; "Scene.Profile.Dashboard.Posts" = "publicaciones"; @@ -370,7 +372,7 @@ cualquier servidor."; "Scene.Settings.Section.Notifications.Trigger.Title" = "Recibir notificación cuando"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Deshabilitar avatares animados"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Deshabilitar emojis animados"; -"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Open links in Mastodon"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Abrir links en Mastodon"; "Scene.Settings.Section.Preference.Title" = "Preferencias"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "Modo oscuro negro real"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Usar navegador predeterminado para abrir los enlaces"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.stringsdict index 24e407d03..8f3e94f6b 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.stringsdict @@ -125,9 +125,9 @@ NSStringFormatValueTypeKey ld one - 1 reply + 1 respuesta other - %ld replies + %ld respuestas plural.count.vote diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.strings index 42b3bfb6c..8be5744d5 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.strings @@ -108,6 +108,7 @@ Egiaztatu Interneteko konexioa."; "Common.Controls.Status.MediaContentWarning" = "Ukitu edonon bistaratzeko"; "Common.Controls.Status.Poll.Closed" = "Itxita"; "Common.Controls.Status.Poll.Vote" = "Bozkatu"; +"Common.Controls.Status.SensitiveContent" = "Sensitive Content"; "Common.Controls.Status.ShowPost" = "Erakutsi bidalketa"; "Common.Controls.Status.ShowUserProfile" = "Erakutsi erabiltzailearen profila"; "Common.Controls.Status.Tag.Email" = "Eposta"; @@ -201,10 +202,11 @@ Mastodonera igo."; "Scene.ConfirmEmail.Subtitle" = "Eposta bat bidali dizugu %@ helbidera, sakatu kontua berresteko esteka."; "Scene.ConfirmEmail.Title" = "Eta azkenik..."; -"Scene.Discovery.Tabs.ForYou" = "For You"; -"Scene.Discovery.Tabs.Hashtags" = "Hashtags"; -"Scene.Discovery.Tabs.News" = "News"; -"Scene.Discovery.Tabs.Posts" = "Posts"; +"Scene.Discovery.Intro" = "These are the posts gaining traction in your corner of Mastodon."; +"Scene.Discovery.Tabs.ForYou" = "Zuretzat"; +"Scene.Discovery.Tabs.Hashtags" = "Traolak"; +"Scene.Discovery.Tabs.News" = "Albisteak"; +"Scene.Discovery.Tabs.Posts" = "Argitalpenak"; "Scene.Favorite.Title" = "Zure gogokoak"; "Scene.Follower.Footer" = "Beste zerbitzarietako jarraitzaileak ez dira bistaratzen."; "Scene.Following.Footer" = "Beste zerbitzarietan jarraitutakoak ez dira bistaratzen."; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.strings index 0ed3a271a..ebeba78ac 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.strings @@ -108,6 +108,7 @@ Veuillez vérifier votre accès à Internet."; "Common.Controls.Status.MediaContentWarning" = "Tapotez n’importe où pour révéler la publication"; "Common.Controls.Status.Poll.Closed" = "Fermé"; "Common.Controls.Status.Poll.Vote" = "Voter"; +"Common.Controls.Status.SensitiveContent" = "Sensitive Content"; "Common.Controls.Status.ShowPost" = "Montrer la publication"; "Common.Controls.Status.ShowUserProfile" = "Montrer le profil de l’utilisateur·rice"; "Common.Controls.Status.Tag.Email" = "Courriel"; @@ -201,6 +202,7 @@ téléversé sur Mastodon."; "Scene.ConfirmEmail.Subtitle" = "Nous venons d’envoyer un courriel à %@, tapotez le lien pour confirmer votre compte."; "Scene.ConfirmEmail.Title" = "Une dernière chose."; +"Scene.Discovery.Intro" = "These are the posts gaining traction in your corner of Mastodon."; "Scene.Discovery.Tabs.ForYou" = "Pour vous"; "Scene.Discovery.Tabs.Hashtags" = "Hashtags"; "Scene.Discovery.Tabs.News" = "Actualité"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.strings index 91bc13736..d6dddaf3a 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.strings @@ -108,6 +108,7 @@ Thoir sùil air a’ cheangal agad ris an eadar-lìon."; "Common.Controls.Status.MediaContentWarning" = "Thoir gnogag àite sam bith gus a nochdadh"; "Common.Controls.Status.Poll.Closed" = "Dùinte"; "Common.Controls.Status.Poll.Vote" = "Cuir bhòt"; +"Common.Controls.Status.SensitiveContent" = "Susbaint fhrionasach"; "Common.Controls.Status.ShowPost" = "Seall am post"; "Common.Controls.Status.ShowUserProfile" = "Seall pròifil a’ chleachdaiche"; "Common.Controls.Status.Tag.Email" = "Post-d"; @@ -201,10 +202,11 @@ a luchdadh suas gu Mastodon."; "Scene.ConfirmEmail.Subtitle" = "Tha sinn air post-d a chur gu %@, thoir gnogag air a’ chunntas a dhearbhadh a’ chunntais agad."; "Scene.ConfirmEmail.Title" = "Aon rud eile."; -"Scene.Discovery.Tabs.ForYou" = "For You"; -"Scene.Discovery.Tabs.Hashtags" = "Hashtags"; -"Scene.Discovery.Tabs.News" = "News"; -"Scene.Discovery.Tabs.Posts" = "Posts"; +"Scene.Discovery.Intro" = "Seo na postaichean fèillmhor ’nad cheàrnaidh de Mhastodon."; +"Scene.Discovery.Tabs.ForYou" = "Dhut-sa"; +"Scene.Discovery.Tabs.Hashtags" = "Tagaichean hais"; +"Scene.Discovery.Tabs.News" = "Naidheachdan"; +"Scene.Discovery.Tabs.Posts" = "Postaichean"; "Scene.Favorite.Title" = "Na h-annsachdan agad"; "Scene.Follower.Footer" = "Cha dèid luchd-leantainn o fhrithealaichean eile a shealltainn."; "Scene.Following.Footer" = "Cha dèid cò air a leanas tu air frithealaichean eile a shealltainn."; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings index 339e23f1c..184f53322 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings @@ -46,7 +46,7 @@ "Common.Controls.Actions.Preview" = "プレビュー"; "Common.Controls.Actions.Previous" = "前"; "Common.Controls.Actions.Remove" = "消去"; -"Common.Controls.Actions.Reply" = "リプライ"; +"Common.Controls.Actions.Reply" = "返信"; "Common.Controls.Actions.ReportUser" = "%@を通報"; "Common.Controls.Actions.Save" = "保存"; "Common.Controls.Actions.SavePhoto" = "写真を撮る"; @@ -97,7 +97,7 @@ "Common.Controls.Status.Actions.Hide" = "非表示"; "Common.Controls.Status.Actions.Menu" = "メニュー"; "Common.Controls.Status.Actions.Reblog" = "ブースト"; -"Common.Controls.Status.Actions.Reply" = "リプライ"; +"Common.Controls.Status.Actions.Reply" = "返信"; "Common.Controls.Status.Actions.ShowGif" = "Show GIF"; "Common.Controls.Status.Actions.ShowImage" = "Show image"; "Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; @@ -108,6 +108,7 @@ "Common.Controls.Status.MediaContentWarning" = "どこかをタップして表示"; "Common.Controls.Status.Poll.Closed" = "クローズド"; "Common.Controls.Status.Poll.Vote" = "投票"; +"Common.Controls.Status.SensitiveContent" = "Sensitive Content"; "Common.Controls.Status.ShowPost" = "投稿を見る"; "Common.Controls.Status.ShowUserProfile" = "プロフィールを見る"; "Common.Controls.Status.Tag.Email" = "メール"; @@ -118,7 +119,7 @@ "Common.Controls.Status.Tag.Url" = "URL"; "Common.Controls.Status.TapToReveal" = "Tap to reveal"; "Common.Controls.Status.UserReblogged" = "%@がブースト"; -"Common.Controls.Status.UserRepliedTo" = "%@がリプライ"; +"Common.Controls.Status.UserRepliedTo" = "%@に返信"; "Common.Controls.Status.Visibility.Direct" = "この投稿はメンションされたユーザーに限り見ることができます。"; "Common.Controls.Status.Visibility.Private" = "この投稿はフォロワーに限り見ることができます。"; "Common.Controls.Status.Visibility.PrivateFromMe" = "この投稿はフォロワーに限り見ることができます。"; @@ -139,7 +140,7 @@ "Common.Controls.Timeline.Header.UserSuspendedWarning" = "%@のアカウントは停止されました。"; "Common.Controls.Timeline.Loader.LoadMissingPosts" = "不足している投稿を読み込む"; "Common.Controls.Timeline.Loader.LoadingMissingPosts" = "読込中..."; -"Common.Controls.Timeline.Loader.ShowMoreReplies" = "リプライをもっとみる"; +"Common.Controls.Timeline.Loader.ShowMoreReplies" = "返信をさらに表示"; "Common.Controls.Timeline.Timestamp.Now" = "今"; "Scene.AccountList.AddAccount" = "アカウントを追加"; "Scene.AccountList.DismissAccountSwitcher" = "アカウント切替画面を閉じます"; @@ -177,9 +178,9 @@ "Scene.Compose.Poll.SixHours" = "6時間"; "Scene.Compose.Poll.ThirtyMinutes" = "30分"; "Scene.Compose.Poll.ThreeDays" = "3日"; -"Scene.Compose.ReplyingToUser" = "%@にリプライ"; +"Scene.Compose.ReplyingToUser" = "%@に返信"; "Scene.Compose.Title.NewPost" = "新しい投稿"; -"Scene.Compose.Title.NewReply" = "新しいリプライ"; +"Scene.Compose.Title.NewReply" = "新しい返信"; "Scene.Compose.Visibility.Direct" = "ダイレクト"; "Scene.Compose.Visibility.Private" = "フォロワーのみ"; "Scene.Compose.Visibility.Public" = "パブリック"; @@ -195,10 +196,11 @@ "Scene.ConfirmEmail.OpenEmailApp.Title" = "メールを確認"; "Scene.ConfirmEmail.Subtitle" = "先程 %@ にメールを送信しました。リンクをタップしてアカウントを確認してください。"; "Scene.ConfirmEmail.Title" = "さいごにもうひとつ。"; +"Scene.Discovery.Intro" = "These are the posts gaining traction in your corner of Mastodon."; "Scene.Discovery.Tabs.ForYou" = "For You"; -"Scene.Discovery.Tabs.Hashtags" = "Hashtags"; -"Scene.Discovery.Tabs.News" = "News"; -"Scene.Discovery.Tabs.Posts" = "Posts"; +"Scene.Discovery.Tabs.Hashtags" = "ハッシュタグ"; +"Scene.Discovery.Tabs.News" = "ニュース"; +"Scene.Discovery.Tabs.Posts" = "投稿"; "Scene.Favorite.Title" = "お気に入り"; "Scene.Follower.Footer" = "他のサーバーからのフォロワーは表示されません。"; "Scene.Following.Footer" = "他のサーバーにいるフォローは表示されません。"; @@ -238,11 +240,11 @@ "Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Title" = "Unblock Account"; "Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Message" = "%@をミュートしますか?"; "Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Title" = "ミュートを解除"; -"Scene.Profile.SegmentedControl.About" = "About"; +"Scene.Profile.SegmentedControl.About" = "概要"; "Scene.Profile.SegmentedControl.Media" = "メディア"; "Scene.Profile.SegmentedControl.Posts" = "投稿"; -"Scene.Profile.SegmentedControl.PostsAndReplies" = "Posts and Replies"; -"Scene.Profile.SegmentedControl.Replies" = "リプライ"; +"Scene.Profile.SegmentedControl.PostsAndReplies" = "投稿と返信"; +"Scene.Profile.SegmentedControl.Replies" = "返信"; "Scene.Register.Error.Item.Agreement" = "契約"; "Scene.Register.Error.Item.Email" = "メール"; "Scene.Register.Error.Item.Locale" = "地域"; @@ -278,15 +280,15 @@ "Scene.Register.Title" = "あなたのことを教えてください"; "Scene.Report.Content1" = "他に通報したい投稿はありますか?"; "Scene.Report.Content2" = "この通報についてモデレーターに伝達しておきたい事項はありますか?"; -"Scene.Report.ReportSentTitle" = "Thanks for reporting, we’ll look into this."; -"Scene.Report.Reported" = "REPORTED"; +"Scene.Report.ReportSentTitle" = "ご報告ありがとうございます、追って確認します。"; +"Scene.Report.Reported" = "報告済み"; "Scene.Report.Send" = "通報を送信"; "Scene.Report.SkipToSend" = "コメントなしで送信"; "Scene.Report.Step1" = "ステップ 1/2"; "Scene.Report.Step2" = "ステップ 2/2"; "Scene.Report.TextPlaceholder" = "追加コメントを入力"; "Scene.Report.Title" = "%@を通報"; -"Scene.Report.TitleReport" = "Report"; +"Scene.Report.TitleReport" = "報告する"; "Scene.Search.Recommend.Accounts.Description" = "以下のアカウントをフォローしてみてはいかがでしょうか?"; "Scene.Search.Recommend.Accounts.Follow" = "フォロー"; "Scene.Search.Recommend.Accounts.Title" = "おすすめのアカウント"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.strings index 792cf3681..aa95cfb69 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.strings @@ -98,16 +98,17 @@ Ma ulac aɣilif, senqed tuqqna-inek internet."; "Common.Controls.Status.Actions.Menu" = "Umuɣ"; "Common.Controls.Status.Actions.Reblog" = "Aɛiwed n usuffeɣ"; "Common.Controls.Status.Actions.Reply" = "Err"; -"Common.Controls.Status.Actions.ShowGif" = "Show GIF"; -"Common.Controls.Status.Actions.ShowImage" = "Show image"; -"Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; -"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tap then hold to show menu"; +"Common.Controls.Status.Actions.ShowGif" = "Sken GIF"; +"Common.Controls.Status.Actions.ShowImage" = "Sken tugna"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Sken ameɣri n tvidyut"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Sit teǧǧeḍ aḍad-ik•im i wakken ad d-iffeɣ wumuɣ"; "Common.Controls.Status.Actions.Unfavorite" = "Kkes seg yismenyifen"; "Common.Controls.Status.Actions.Unreblog" = "Sefsex allus n usuffeɣ"; "Common.Controls.Status.ContentWarning" = "Alɣu n ugbur"; "Common.Controls.Status.MediaContentWarning" = "Sit anida tebɣiḍ i wakken ad twaliḍ"; "Common.Controls.Status.Poll.Closed" = "Ifukk"; "Common.Controls.Status.Poll.Vote" = "Dɣeṛ"; +"Common.Controls.Status.SensitiveContent" = "Agbur amḥulfu"; "Common.Controls.Status.ShowPost" = "Sken-d tasuffeɣt"; "Common.Controls.Status.ShowUserProfile" = "Ssken-d amaɣnu n useqdac"; "Common.Controls.Status.Tag.Email" = "Imayl"; @@ -116,7 +117,7 @@ Ma ulac aɣilif, senqed tuqqna-inek internet."; "Common.Controls.Status.Tag.Link" = "Aseɣwen"; "Common.Controls.Status.Tag.Mention" = "Tabdart"; "Common.Controls.Status.Tag.Url" = "URL"; -"Common.Controls.Status.TapToReveal" = "Tap to reveal"; +"Common.Controls.Status.TapToReveal" = "Sit i uskan"; "Common.Controls.Status.UserReblogged" = "Tettwasuffeɣ-d %@ i tikkelt-nniḍen"; "Common.Controls.Status.UserRepliedTo" = "Yerra ɣef %@"; "Common.Controls.Status.Visibility.Direct" = "D ineḍfaren-is kan i izemren ad walin tsuffeɣ-a."; @@ -200,10 +201,11 @@ Ad d-yettwasali ɣef Mastodon."; "Scene.ConfirmEmail.OpenEmailApp.Title" = "Sefqed Tanaka-inek."; "Scene.ConfirmEmail.Subtitle" = "Sit ɣef useɣwen i ak-n-uznen i wakken ad tesneqdeḍ amiḍan-ik."; "Scene.ConfirmEmail.Title" = "Taɣawsa taneggarut."; -"Scene.Discovery.Tabs.ForYou" = "For You"; -"Scene.Discovery.Tabs.Hashtags" = "Hashtags"; -"Scene.Discovery.Tabs.News" = "News"; -"Scene.Discovery.Tabs.Posts" = "Posts"; +"Scene.Discovery.Intro" = "Tigi d tisuffaɣ i d-ijebbden s waṭas deg tama-inek•inem n Mastodon."; +"Scene.Discovery.Tabs.ForYou" = "I kečč·kem"; +"Scene.Discovery.Tabs.Hashtags" = "Ihacṭagen"; +"Scene.Discovery.Tabs.News" = "Isallen"; +"Scene.Discovery.Tabs.Posts" = "Tisuffaɣ"; "Scene.Favorite.Title" = "Ismenyifen-ik·im"; "Scene.Follower.Footer" = "Ineḍfaren seg yiqeddacen-nniḍen ur d-ttwaskanen ara."; "Scene.Following.Footer" = "Ineḍfaren seg yiqeddacen-nniḍen ur d-ttwaskanen ara."; @@ -225,10 +227,10 @@ Ad d-yettwasali ɣef Mastodon."; "Scene.Preview.Keyboard.ClosePreview" = "Mdel timeẓri"; "Scene.Preview.Keyboard.ShowNext" = "Sken uḍfir"; "Scene.Preview.Keyboard.ShowPrevious" = "Sken udfir"; -"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Double tap to open the list"; -"Scene.Profile.Accessibility.EditAvatarImage" = "Edit avatar image"; -"Scene.Profile.Accessibility.ShowAvatarImage" = "Show avatar image"; -"Scene.Profile.Accessibility.ShowBannerImage" = "Show banner image"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Sin isitiyen i twaledyawt n tebdart"; +"Scene.Profile.Accessibility.EditAvatarImage" = "Ẓreg tugna n avaṭar"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "Sken tugna n avaṭar"; +"Scene.Profile.Accessibility.ShowBannerImage" = "Sken tugna n uɣerrac"; "Scene.Profile.Dashboard.Followers" = "imeḍfaren"; "Scene.Profile.Dashboard.Following" = "iṭafaṛ"; "Scene.Profile.Dashboard.Posts" = "tisuffaɣ"; @@ -315,7 +317,7 @@ Ad d-yettwasali ɣef Mastodon."; "Scene.ServerPicker.Button.Category.AllAccessiblityDescription" = "Taggayt: Akk"; "Scene.ServerPicker.Button.Category.Art" = "taẓuri"; "Scene.ServerPicker.Button.Category.Food" = "učči"; -"Scene.ServerPicker.Button.Category.Furry" = "furry"; +"Scene.ServerPicker.Button.Category.Furry" = "s taḍut"; "Scene.ServerPicker.Button.Category.Games" = "uraren"; "Scene.ServerPicker.Button.Category.General" = "amatu"; "Scene.ServerPicker.Button.Category.Journalism" = "taɣamsa"; @@ -368,7 +370,7 @@ Ad d-yettwasali ɣef Mastodon."; "Scene.Settings.Section.Notifications.Trigger.Title" = "Selɣu-yi-d mi ara"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Sens ivaṭaren yettembiwilen"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Sens imujiten yettembiwilen"; -"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Open links in Mastodon"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Ldi iseɣwan deg Mastodon"; "Scene.Settings.Section.Preference.Title" = "Imenyafen"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "Askar aberkan n tidet"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Seqdec iminig amezwer i twaledyawt n yiseɣwan"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.stringsdict index c3d72dda2..4ccb271fa 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.stringsdict @@ -125,9 +125,9 @@ NSStringFormatValueTypeKey ld one - 1 reply + 1 tririt other - %ld replies + %ld tririyin plural.count.vote diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings index dcc8dae64..2444c70c4 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings @@ -108,6 +108,7 @@ Jkx girêdana înternetê xwe kontrol bike."; "Common.Controls.Status.MediaContentWarning" = "Ji bo eşkerekirinê li derekî bitikîne"; "Common.Controls.Status.Poll.Closed" = "Girtî"; "Common.Controls.Status.Poll.Vote" = "Deng bide"; +"Common.Controls.Status.SensitiveContent" = "Naveroka hestiyarî"; "Common.Controls.Status.ShowPost" = "Şandiyê nîşan bide"; "Common.Controls.Status.ShowUserProfile" = "Profîla bikarhêner nîşan bide"; "Common.Controls.Status.Tag.Email" = "E-name"; @@ -201,6 +202,7 @@ Profîla te ji wan ra wiha xuya dike."; "Scene.ConfirmEmail.Subtitle" = "Me tenê e-nameyek ji %@ re şand, girêdanê bitikne da ku ajimêra xwe bidî piştrastkirin."; "Scene.ConfirmEmail.Title" = "Tiştekî dawî."; +"Scene.Discovery.Intro" = "Ev şandiyên ku di quncika Mastodon balê dikişîne."; "Scene.Discovery.Tabs.ForYou" = "Ji bo te"; "Scene.Discovery.Tabs.Hashtags" = "Hashtag"; "Scene.Discovery.Tabs.News" = "Nûçe"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.strings index 31148373f..0a06b59d3 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.strings @@ -1,63 +1,63 @@ -"Common.Alerts.BlockDomain.BlockEntireDomain" = "Domein blokkeren"; -"Common.Alerts.BlockDomain.Title" = "Weet u zeker dat u alles van %@ wilt blokkeren? In de meeste gevallen is het blokkeren of negeren van een paar specifieke personen voldoende en wenselijker. U zult geen berichten meer zien van dit domein en volgers van dit domein worden verwijderd."; +"Common.Alerts.BlockDomain.BlockEntireDomain" = "Blokkeer domein"; +"Common.Alerts.BlockDomain.Title" = "Weet je het echt heel erg zeker dat je alles van %@ wilt negeren? In de meeste gevallen is het blokkeren of negeren van een paar specifieke personen voldoende. Je zult geen berichten van deze server op openbare tijdlijnen zien of in jouw meldingen. Jouw volgers van deze server worden verwijderd."; "Common.Alerts.CleanCache.Message" = "Cache-geheugen (%@) succesvol gewist."; "Common.Alerts.CleanCache.Title" = "Cache-geheugen Wissen"; "Common.Alerts.Common.PleaseTryAgain" = "Probeer het opnieuw."; "Common.Alerts.Common.PleaseTryAgainLater" = "Probeer het later nog eens."; -"Common.Alerts.DeletePost.Message" = "Are you sure you want to delete this post?"; -"Common.Alerts.DeletePost.Title" = "Weet u zeker dat u dit bericht wilt verwijderen?"; +"Common.Alerts.DeletePost.Message" = "Weet je zeker dat je dit bericht wilt verwijderen?"; +"Common.Alerts.DeletePost.Title" = "Verwijder Bericht"; "Common.Alerts.DiscardPostContent.Message" = "Bevestig het verwijderen van het concept bericht."; -"Common.Alerts.DiscardPostContent.Title" = "Concept Verwijderen"; -"Common.Alerts.EditProfileFailure.Message" = "Het profiel kan niet bewerkt worden. Probeer het opnieuw."; +"Common.Alerts.DiscardPostContent.Title" = "Verwijder concept"; +"Common.Alerts.EditProfileFailure.Message" = "Je profiel kan niet bewerkt worden. Probeer het opnieuw."; "Common.Alerts.EditProfileFailure.Title" = "Profiel bewerken mislukt"; -"Common.Alerts.PublishPostFailure.AttachmentsMessage.MoreThanOneVideo" = "Slechts één video kan aan een bericht worden gekoppeld."; +"Common.Alerts.PublishPostFailure.AttachmentsMessage.MoreThanOneVideo" = "Kan niet meer dan één video toevoegen."; "Common.Alerts.PublishPostFailure.AttachmentsMessage.VideoAttachWithPhoto" = "Een video kan niet aan een bericht met afbeeldingen worden gekoppeld."; -"Common.Alerts.PublishPostFailure.Message" = "Het publiceren van het bericht is mislukt. Controleer alstublieft uw internetverbinding."; +"Common.Alerts.PublishPostFailure.Message" = "Het publiceren van het bericht is mislukt. Controleer je internetverbinding."; "Common.Alerts.PublishPostFailure.Title" = "Publicatiefout"; "Common.Alerts.SavePhotoFailure.Message" = "Geef toestemming om de foto op te slaan."; "Common.Alerts.SavePhotoFailure.Title" = "Foto Opslaan Mislukt"; "Common.Alerts.ServerError.Title" = "Serverfout"; -"Common.Alerts.SignOut.Confirm" = "Afmelden"; -"Common.Alerts.SignOut.Message" = "Weet u zeker dat u zich wilt afmelden?"; -"Common.Alerts.SignOut.Title" = "Afmelden"; +"Common.Alerts.SignOut.Confirm" = "Log-uit"; +"Common.Alerts.SignOut.Message" = "Weet je zeker dat je wilt uitloggen?"; +"Common.Alerts.SignOut.Title" = "Log-uit"; "Common.Alerts.SignUpFailure.Title" = "Registratiefout"; "Common.Alerts.VoteFailure.PollEnded" = "De peiling is beëindigd"; "Common.Alerts.VoteFailure.Title" = "Stemmen Mislukt"; -"Common.Controls.Actions.Add" = "Toevoegen"; +"Common.Controls.Actions.Add" = "Voeg toe"; "Common.Controls.Actions.Back" = "Terug"; "Common.Controls.Actions.BlockDomain" = "Blokkeer %@"; -"Common.Controls.Actions.Cancel" = "Annuleren"; -"Common.Controls.Actions.Compose" = "Compose"; +"Common.Controls.Actions.Cancel" = "Annuleer"; +"Common.Controls.Actions.Compose" = "Schrijf bericht"; "Common.Controls.Actions.Confirm" = "Bevestigen"; -"Common.Controls.Actions.Continue" = "Doorgaan"; -"Common.Controls.Actions.CopyPhoto" = "Foto kopiëren"; -"Common.Controls.Actions.Delete" = "Verwijderen"; +"Common.Controls.Actions.Continue" = "Ga verder"; +"Common.Controls.Actions.CopyPhoto" = "Kopieer foto"; +"Common.Controls.Actions.Delete" = "Verwijder"; "Common.Controls.Actions.Discard" = "Weggooien"; "Common.Controls.Actions.Done" = "Klaar"; -"Common.Controls.Actions.Edit" = "Bewerken"; +"Common.Controls.Actions.Edit" = "Bewerk"; "Common.Controls.Actions.FindPeople" = "Zoek mensen om te volgen"; "Common.Controls.Actions.ManuallySearch" = "Handmatig zoeken"; "Common.Controls.Actions.Next" = "Volgende"; -"Common.Controls.Actions.Ok" = "Oké"; +"Common.Controls.Actions.Ok" = "Ok"; "Common.Controls.Actions.Open" = "Open"; -"Common.Controls.Actions.OpenInBrowser" = "Open in Browser"; +"Common.Controls.Actions.OpenInBrowser" = "Open in browser"; "Common.Controls.Actions.OpenInSafari" = "Open in Safari"; "Common.Controls.Actions.Preview" = "Voorvertoning"; "Common.Controls.Actions.Previous" = "Vorige"; -"Common.Controls.Actions.Remove" = "Verwijderen"; -"Common.Controls.Actions.Reply" = "Reageren"; +"Common.Controls.Actions.Remove" = "Verwijder"; +"Common.Controls.Actions.Reply" = "Reageer"; "Common.Controls.Actions.ReportUser" = "Rapporteer %@"; -"Common.Controls.Actions.Save" = "Opslaan"; -"Common.Controls.Actions.SavePhoto" = "Foto Opslaan"; +"Common.Controls.Actions.Save" = "Bewaar"; +"Common.Controls.Actions.SavePhoto" = "Bewaar foto"; "Common.Controls.Actions.SeeMore" = "Meer"; "Common.Controls.Actions.Settings" = "Instellingen"; -"Common.Controls.Actions.Share" = "Delen"; -"Common.Controls.Actions.SharePost" = "Bericht Delen"; +"Common.Controls.Actions.Share" = "Deel"; +"Common.Controls.Actions.SharePost" = "Deel bericht"; "Common.Controls.Actions.ShareUser" = "Delen %@"; "Common.Controls.Actions.SignIn" = "Aanmelden"; "Common.Controls.Actions.SignUp" = "Registreren"; "Common.Controls.Actions.Skip" = "Overslaan"; -"Common.Controls.Actions.TakePhoto" = "Foto Maken"; +"Common.Controls.Actions.TakePhoto" = "Maak foto"; "Common.Controls.Actions.TryAgain" = "Probeer Opnieuw"; "Common.Controls.Actions.UnblockDomain" = "Deblokkeer %@"; "Common.Controls.Friendship.Block" = "Blokkeren"; @@ -79,7 +79,7 @@ "Common.Controls.Keyboard.Common.ComposeNewPost" = "Nieuw Bericht Opstellen"; "Common.Controls.Keyboard.Common.OpenSettings" = "Open Instellingen"; "Common.Controls.Keyboard.Common.ShowFavorites" = "Favorieten Weergeven"; -"Common.Controls.Keyboard.Common.SwitchToTab" = "Wisselen naar %@"; +"Common.Controls.Keyboard.Common.SwitchToTab" = "Overschakelen naar %@"; "Common.Controls.Keyboard.SegmentedControl.NextSection" = "Volgende Sectie"; "Common.Controls.Keyboard.SegmentedControl.PreviousSection" = "Vorige Sectie"; "Common.Controls.Keyboard.Timeline.NextStatus" = "Volgend Bericht"; @@ -88,25 +88,26 @@ "Common.Controls.Keyboard.Timeline.OpenStatus" = "Open Bericht"; "Common.Controls.Keyboard.Timeline.PreviewImage" = "Voorvertoning Afbeelding"; "Common.Controls.Keyboard.Timeline.PreviousStatus" = "Vorig Bericht"; -"Common.Controls.Keyboard.Timeline.ReplyStatus" = "Reageren"; -"Common.Controls.Keyboard.Timeline.ToggleContentWarning" = "Inhoudswaarschuwing Omschakelen"; -"Common.Controls.Keyboard.Timeline.ToggleFavorite" = "Favoriet Omschakelen bij Bericht"; +"Common.Controls.Keyboard.Timeline.ReplyStatus" = "Reageer"; +"Common.Controls.Keyboard.Timeline.ToggleContentWarning" = "Inhoudswaarschuwing"; +"Common.Controls.Keyboard.Timeline.ToggleFavorite" = "Favoriet in-/uitschakelen bij Post"; "Common.Controls.Keyboard.Timeline.ToggleReblog" = "Delen bij berichten omschakelen"; "Common.Controls.Status.Actions.Favorite" = "Toevoegen aan Favorieten"; -"Common.Controls.Status.Actions.Hide" = "Hide"; +"Common.Controls.Status.Actions.Hide" = "Verberg"; "Common.Controls.Status.Actions.Menu" = "Menu"; "Common.Controls.Status.Actions.Reblog" = "Delen"; "Common.Controls.Status.Actions.Reply" = "Reageren"; -"Common.Controls.Status.Actions.ShowGif" = "Show GIF"; -"Common.Controls.Status.Actions.ShowImage" = "Show image"; -"Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; -"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tap then hold to show menu"; +"Common.Controls.Status.Actions.ShowGif" = "GIF weergeven"; +"Common.Controls.Status.Actions.ShowImage" = "Toon afbeelding"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Toon videospeler"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tik en houd vast om menu te tonen"; "Common.Controls.Status.Actions.Unfavorite" = "Verwijderen uit Favorieten"; "Common.Controls.Status.Actions.Unreblog" = "Delen ongedaan maken"; "Common.Controls.Status.ContentWarning" = "Inhoudswaarschuwing"; "Common.Controls.Status.MediaContentWarning" = "Tap hier om te tonen"; "Common.Controls.Status.Poll.Closed" = "Gesloten"; "Common.Controls.Status.Poll.Vote" = "Stemmen"; +"Common.Controls.Status.SensitiveContent" = "Gevoelige inhoud"; "Common.Controls.Status.ShowPost" = "Toon Bericht"; "Common.Controls.Status.ShowUserProfile" = "Toon Gebruikersprofiel"; "Common.Controls.Status.Tag.Email" = "Email"; @@ -115,17 +116,17 @@ "Common.Controls.Status.Tag.Link" = "Link"; "Common.Controls.Status.Tag.Mention" = "Vermelden"; "Common.Controls.Status.Tag.Url" = "URL"; -"Common.Controls.Status.TapToReveal" = "Tap to reveal"; -"Common.Controls.Status.UserReblogged" = "%@ gedeeld"; +"Common.Controls.Status.TapToReveal" = "Tik om te onthullen"; +"Common.Controls.Status.UserReblogged" = "%@ heeft gedeeld"; "Common.Controls.Status.UserRepliedTo" = "Reactie op %@"; -"Common.Controls.Status.Visibility.Direct" = "Only mentioned user can see this post."; -"Common.Controls.Status.Visibility.Private" = "Only their followers can see this post."; -"Common.Controls.Status.Visibility.PrivateFromMe" = "Only my followers can see this post."; -"Common.Controls.Status.Visibility.Unlisted" = "Everyone can see this post but not display in the public timeline."; +"Common.Controls.Status.Visibility.Direct" = "Alleen de vermelde persoon kan dit bericht zien."; +"Common.Controls.Status.Visibility.Private" = "Alleen hun volgers kunnen dit bericht zien."; +"Common.Controls.Status.Visibility.PrivateFromMe" = "Alleen mijn volgers kunnen dit bericht zien."; +"Common.Controls.Status.Visibility.Unlisted" = "Iedereen kan dit bericht zien maar het wordt niet in de publieke tijdlijn getoond."; "Common.Controls.Tabs.Home" = "Start"; "Common.Controls.Tabs.Notification" = "Melding"; "Common.Controls.Tabs.Profile" = "Profiel"; -"Common.Controls.Tabs.Search" = "Zoeken"; +"Common.Controls.Tabs.Search" = "Zoek"; "Common.Controls.Timeline.Filtered" = "Gefilterd"; "Common.Controls.Timeline.Header.BlockedWarning" = "U kunt het profiel van deze gebruiker niet bekijken zolang u geblokkeerd bent."; "Common.Controls.Timeline.Header.BlockingWarning" = "U kunt het profiel van deze geblokkeerde gebruiker niet bekijken. @@ -140,9 +141,9 @@ Uw profiel ziet er zo uit voor hen."; "Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Resterende berichten laden..."; "Common.Controls.Timeline.Loader.ShowMoreReplies" = "Toon meer reacties"; "Common.Controls.Timeline.Timestamp.Now" = "Nu"; -"Scene.AccountList.AddAccount" = "Add Account"; -"Scene.AccountList.DismissAccountSwitcher" = "Dismiss Account Switcher"; -"Scene.AccountList.TabBarHint" = "Current selected profile: %@. Double tap then hold to show account switcher"; +"Scene.AccountList.AddAccount" = "Voeg account toe"; +"Scene.AccountList.DismissAccountSwitcher" = "Annuleer account wisselen"; +"Scene.AccountList.TabBarHint" = "Huidige geselecteerde profiel: %@. Dubbel-tik en houd vast om account te wisselen"; "Scene.Compose.Accessibility.AppendAttachment" = "Bijlage Toevoegen"; "Scene.Compose.Accessibility.AppendPoll" = "Peiling Toevoegen"; "Scene.Compose.Accessibility.CustomEmojiPicker" = "Eigen Emojikiezer"; @@ -184,7 +185,7 @@ Uw profiel ziet er zo uit voor hen."; "Scene.Compose.Visibility.Public" = "Openbaar"; "Scene.Compose.Visibility.Unlisted" = "Niet-vermeld"; "Scene.ConfirmEmail.Button.OpenEmailApp" = "Email Openen"; -"Scene.ConfirmEmail.Button.Resend" = "Resend"; +"Scene.ConfirmEmail.Button.Resend" = "Verstuur opnieuw"; "Scene.ConfirmEmail.DontReceiveEmail.Description" = "Controleer of uw emailadres correct is en of the email in de ongewenste email filter terecht is gekomen."; "Scene.ConfirmEmail.DontReceiveEmail.ResendEmail" = "Email Opnieuw Versturen"; "Scene.ConfirmEmail.DontReceiveEmail.Title" = "Controleer uw emailadres"; @@ -195,13 +196,14 @@ Uw profiel ziet er zo uit voor hen."; "Scene.ConfirmEmail.Subtitle" = "We hebben een e-mail gestuurd naar %@, klik op de link om uw account te bevestigen."; "Scene.ConfirmEmail.Title" = "Nog één ding."; -"Scene.Discovery.Tabs.ForYou" = "For You"; +"Scene.Discovery.Intro" = "Dit zijn de berichten die populair zijn in jouw Mastodon-kringen."; +"Scene.Discovery.Tabs.ForYou" = "Voor jou"; "Scene.Discovery.Tabs.Hashtags" = "Hashtags"; -"Scene.Discovery.Tabs.News" = "News"; -"Scene.Discovery.Tabs.Posts" = "Posts"; +"Scene.Discovery.Tabs.News" = "Nieuws"; +"Scene.Discovery.Tabs.Posts" = "Berichten"; "Scene.Favorite.Title" = "Uw favorieten"; -"Scene.Follower.Footer" = "Followers from other servers are not displayed."; -"Scene.Following.Footer" = "Follows from other servers are not displayed."; +"Scene.Follower.Footer" = "Volgers van andere servers worden niet weergegeven."; +"Scene.Following.Footer" = "Volgers van andere servers worden niet weergegeven."; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Bekijk nieuwe berichten"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Offline"; "Scene.HomeTimeline.NavigationBarState.Published" = "Gepubliceerd!"; @@ -209,39 +211,39 @@ klik op de link om uw account te bevestigen."; "Scene.HomeTimeline.Title" = "Start"; "Scene.Notification.Keyobard.ShowEverything" = "Alles weergeven"; "Scene.Notification.Keyobard.ShowMentions" = "Vermeldingen weergeven"; -"Scene.Notification.NotificationDescription.FavoritedYourPost" = "favorited your post"; -"Scene.Notification.NotificationDescription.FollowedYou" = "followed you"; -"Scene.Notification.NotificationDescription.MentionedYou" = "mentioned you"; -"Scene.Notification.NotificationDescription.PollHasEnded" = "poll has ended"; -"Scene.Notification.NotificationDescription.RebloggedYourPost" = "reblogged your post"; -"Scene.Notification.NotificationDescription.RequestToFollowYou" = "request to follow you"; +"Scene.Notification.NotificationDescription.FavoritedYourPost" = "heeft je bericht als favoriet gemrkeerd"; +"Scene.Notification.NotificationDescription.FollowedYou" = "volgt je"; +"Scene.Notification.NotificationDescription.MentionedYou" = "noemde je"; +"Scene.Notification.NotificationDescription.PollHasEnded" = "de peiling is beëindigd"; +"Scene.Notification.NotificationDescription.RebloggedYourPost" = "deelde je bericht"; +"Scene.Notification.NotificationDescription.RequestToFollowYou" = "verzoek je te volgen"; "Scene.Notification.Title.Everything" = "Alles"; "Scene.Notification.Title.Mentions" = "Vermeldingen"; "Scene.Preview.Keyboard.ClosePreview" = "Voorbeeldweergave Sluiten"; "Scene.Preview.Keyboard.ShowNext" = "Volgende"; "Scene.Preview.Keyboard.ShowPrevious" = "Vorige"; -"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Double tap to open the list"; -"Scene.Profile.Accessibility.EditAvatarImage" = "Edit avatar image"; -"Scene.Profile.Accessibility.ShowAvatarImage" = "Show avatar image"; -"Scene.Profile.Accessibility.ShowBannerImage" = "Show banner image"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Dubbel tikken om de lijst te openen"; +"Scene.Profile.Accessibility.EditAvatarImage" = "Bewerk avatar-afbeelding"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "Toon avatar-afbeelding"; +"Scene.Profile.Accessibility.ShowBannerImage" = "Toon banner-afbeelding"; "Scene.Profile.Dashboard.Followers" = "volgers"; "Scene.Profile.Dashboard.Following" = "volgend"; "Scene.Profile.Dashboard.Posts" = "berichten"; "Scene.Profile.Fields.AddRow" = "Rij Toevoegen"; "Scene.Profile.Fields.Placeholder.Content" = "Inhoud"; "Scene.Profile.Fields.Placeholder.Label" = "Etiket"; -"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Message" = "Confirm to block %@"; -"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Title" = "Block Account"; -"Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Message" = "Confirm to mute %@"; -"Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Title" = "Mute Account"; -"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Message" = "Confirm to unblock %@"; -"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Title" = "Unblock Account"; +"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Message" = "Bevestig om %@ te blokkeren"; +"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Title" = "Blokkeer account"; +"Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Message" = "Bevestig om %@ te negeren"; +"Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Title" = "Negeer account"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Message" = "Bevestig om %@ te deblokkeren"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Title" = "Deblokkeer Account"; "Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Message" = "Bevestig om %@ te negeren"; "Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Title" = "Account Negeren"; -"Scene.Profile.SegmentedControl.About" = "About"; +"Scene.Profile.SegmentedControl.About" = "Informatie"; "Scene.Profile.SegmentedControl.Media" = "Media"; "Scene.Profile.SegmentedControl.Posts" = "Berichten"; -"Scene.Profile.SegmentedControl.PostsAndReplies" = "Posts and Replies"; +"Scene.Profile.SegmentedControl.PostsAndReplies" = "Berichten en reacties"; "Scene.Profile.SegmentedControl.Replies" = "Reacties"; "Scene.Register.Error.Item.Agreement" = "Overeenkomst"; "Scene.Register.Error.Item.Email" = "Email"; @@ -267,26 +269,26 @@ klik op de link om uw account te bevestigen."; "Scene.Register.Input.DisplayName.Placeholder" = "weergavenaam"; "Scene.Register.Input.Email.Placeholder" = "email"; "Scene.Register.Input.Invite.RegistrationUserInviteRequest" = "Waarom wil u zich hier registreren?"; -"Scene.Register.Input.Password.Accessibility.Checked" = "checked"; -"Scene.Register.Input.Password.Accessibility.Unchecked" = "unchecked"; -"Scene.Register.Input.Password.CharacterLimit" = "8 characters"; +"Scene.Register.Input.Password.Accessibility.Checked" = "ingeschakeld"; +"Scene.Register.Input.Password.Accessibility.Unchecked" = "uitgeschakeld"; +"Scene.Register.Input.Password.CharacterLimit" = "8 tekens"; "Scene.Register.Input.Password.Hint" = "Uw wachtwoord moet ten minste acht tekens bevatten"; "Scene.Register.Input.Password.Placeholder" = "wachtwoord"; -"Scene.Register.Input.Password.Require" = "Your password needs at least:"; +"Scene.Register.Input.Password.Require" = "Je wachtwoord moet ten minste:"; "Scene.Register.Input.Username.DuplicatePrompt" = "Deze gebruikersnaam is al in gebruik."; "Scene.Register.Input.Username.Placeholder" = "gebruikersnaam"; "Scene.Register.Title" = "Vertel ons over uzelf."; "Scene.Report.Content1" = "Zijn er nog meer berichten die u aan het rapport wilt toevoegen?"; "Scene.Report.Content2" = "Is er iets anders over dit rapport dat de moderators zouden moeten weten?"; -"Scene.Report.ReportSentTitle" = "Thanks for reporting, we’ll look into this."; -"Scene.Report.Reported" = "REPORTED"; +"Scene.Report.ReportSentTitle" = "Bedankt voor het rapporteren, we zullen hiernaar kijken."; +"Scene.Report.Reported" = "Gerapporteerd"; "Scene.Report.Send" = "Stuur rapport"; "Scene.Report.SkipToSend" = "Verstuur zonder opmerkingen"; "Scene.Report.Step1" = "Stap 1 van 2"; "Scene.Report.Step2" = "Stap 2 van 2"; "Scene.Report.TextPlaceholder" = "Schrijf of plak aanvullende opmerkingen"; "Scene.Report.Title" = "Rapporteer %@"; -"Scene.Report.TitleReport" = "Report"; +"Scene.Report.TitleReport" = "Rapporteer"; "Scene.Search.Recommend.Accounts.Description" = "Misschien dat u geïnteresseerd bent in deze accounts"; "Scene.Search.Recommend.Accounts.Follow" = "Volgen"; "Scene.Search.Recommend.Accounts.Title" = "Interessante accounts voor u"; @@ -327,8 +329,8 @@ klik op de link om uw account te bevestigen."; "Scene.ServerPicker.Label.Category" = "CATEGORIE"; "Scene.ServerPicker.Label.Language" = "TAAL"; "Scene.ServerPicker.Label.Users" = "GEBRUIKERS"; -"Scene.ServerPicker.Subtitle" = "Pick a community based on your interests, region, or a general purpose one."; -"Scene.ServerPicker.SubtitleExtend" = "Pick a community based on your interests, region, or a general purpose one. Each community is operated by an entirely independent organization or individual."; +"Scene.ServerPicker.Subtitle" = "Kies een gemeenschap gebaseerd op jouw interesses, regio of een algemeen doel."; +"Scene.ServerPicker.SubtitleExtend" = "Kies een gemeenschap gebaseerd op jouw interesses, regio, of een algemeen doel. Elke gemeenschap wordt beheerd door een volledig onafhankelijke organisatie of individu."; "Scene.ServerPicker.Title" = "Kies een server, welke dan ook."; "Scene.ServerRules.Button.Confirm" = "Ik Ga Akkoord"; "Scene.ServerRules.PrivacyPolicy" = "privacybeleid"; @@ -346,11 +348,11 @@ klik op de link om uw account te bevestigen."; "Scene.Settings.Section.BoringZone.Privacy" = "Privacybeleid"; "Scene.Settings.Section.BoringZone.Terms" = "Servicevoorwaarden"; "Scene.Settings.Section.BoringZone.Title" = "De Saaie Instellingen"; -"Scene.Settings.Section.LookAndFeel.Light" = "Light"; -"Scene.Settings.Section.LookAndFeel.ReallyDark" = "Really Dark"; -"Scene.Settings.Section.LookAndFeel.SortaDark" = "Sorta Dark"; -"Scene.Settings.Section.LookAndFeel.Title" = "Look and Feel"; -"Scene.Settings.Section.LookAndFeel.UseSystem" = "Use System"; +"Scene.Settings.Section.LookAndFeel.Light" = "Licht"; +"Scene.Settings.Section.LookAndFeel.ReallyDark" = "Echt donker"; +"Scene.Settings.Section.LookAndFeel.SortaDark" = "Donker"; +"Scene.Settings.Section.LookAndFeel.Title" = "Opmaak"; +"Scene.Settings.Section.LookAndFeel.UseSystem" = "Gebruik systeem"; "Scene.Settings.Section.Notifications.Boosts" = "Mijn bericht deelt"; "Scene.Settings.Section.Notifications.Favorites" = "Mijn bericht als favoriet toevoegt"; "Scene.Settings.Section.Notifications.Follows" = "Mij volgt"; @@ -375,9 +377,9 @@ klik op de link om uw account te bevestigen."; "Scene.SuggestionAccount.Title" = "Zoek Mensen om te Volgen"; "Scene.Thread.BackTitle" = "Bericht"; "Scene.Thread.Title" = "Bericht van %@"; -"Scene.Welcome.GetStarted" = "Get Started"; -"Scene.Welcome.LogIn" = "Log In"; +"Scene.Welcome.GetStarted" = "Aan de slag"; +"Scene.Welcome.LogIn" = "Log in"; "Scene.Welcome.Slogan" = "Sociale media terug in uw handen."; -"Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard"; -"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button."; -"Scene.Wizard.NewInMastodon" = "New in Mastodon"; \ No newline at end of file +"Scene.Wizard.AccessibilityHint" = "Tik tweemaal om het popup-scherm te sluiten"; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Schakel tussen meerdere accounts door de profielknop in te drukken en vast te houden."; +"Scene.Wizard.NewInMastodon" = "Nieuw in Mastodon"; \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings index d7ed34c30..051169824 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings @@ -108,6 +108,7 @@ "Common.Controls.Status.MediaContentWarning" = "Нажмите в любом месте, чтобы показать"; "Common.Controls.Status.Poll.Closed" = "Завершён"; "Common.Controls.Status.Poll.Vote" = "Проголосовать"; +"Common.Controls.Status.SensitiveContent" = "Sensitive Content"; "Common.Controls.Status.ShowPost" = "Показать пост"; "Common.Controls.Status.ShowUserProfile" = "Показать профиль пользователя"; "Common.Controls.Status.Tag.Email" = "E-mail"; @@ -211,6 +212,7 @@ Нажмите на ссылку в нём, чтобы подтвердить свою учётную запись."; "Scene.ConfirmEmail.Title" = "И ещё кое-что."; +"Scene.Discovery.Intro" = "These are the posts gaining traction in your corner of Mastodon."; "Scene.Discovery.Tabs.ForYou" = "For You"; "Scene.Discovery.Tabs.Hashtags" = "Hashtags"; "Scene.Discovery.Tabs.News" = "News"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/sv_FI.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/sv_FI.lproj/Localizable.strings index 434303e3d..342b05b23 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/sv_FI.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/sv_FI.lproj/Localizable.strings @@ -108,6 +108,7 @@ Tarkista internet-yhteytesi."; "Common.Controls.Status.MediaContentWarning" = "Napauta mistä tahansa paljastaaksesi"; "Common.Controls.Status.Poll.Closed" = "Suljettu"; "Common.Controls.Status.Poll.Vote" = "Vote"; +"Common.Controls.Status.SensitiveContent" = "Sensitive Content"; "Common.Controls.Status.ShowPost" = "Näytä julkaisu"; "Common.Controls.Status.ShowUserProfile" = "Näytä tili"; "Common.Controls.Status.Tag.Email" = "Sähköposti"; @@ -200,6 +201,7 @@ uploaded to Mastodon."; "Scene.ConfirmEmail.OpenEmailApp.Title" = "Tarkasta postilaatikkosi."; "Scene.ConfirmEmail.Subtitle" = "Lähetimme juuri sähköpostin osoitteeseen %@, napauta siinä olevaa linkkiä vahvistaaksesi tilisi."; "Scene.ConfirmEmail.Title" = "Viimeinen asia."; +"Scene.Discovery.Intro" = "These are the posts gaining traction in your corner of Mastodon."; "Scene.Discovery.Tabs.ForYou" = "For You"; "Scene.Discovery.Tabs.Hashtags" = "Hashtags"; "Scene.Discovery.Tabs.News" = "News"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings index 5dfb5134a..a9846e8e2 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings @@ -108,6 +108,7 @@ "Common.Controls.Status.MediaContentWarning" = "แตะที่ใดก็ตามเพื่อเปิดเผย"; "Common.Controls.Status.Poll.Closed" = "ปิดแล้ว"; "Common.Controls.Status.Poll.Vote" = "ลงคะแนน"; +"Common.Controls.Status.SensitiveContent" = "เนื้อหาที่ละเอียดอ่อน"; "Common.Controls.Status.ShowPost" = "แสดงโพสต์"; "Common.Controls.Status.ShowUserProfile" = "แสดงโปรไฟล์ผู้ใช้"; "Common.Controls.Status.Tag.Email" = "อีเมล"; @@ -200,6 +201,7 @@ "Scene.ConfirmEmail.OpenEmailApp.Title" = "ตรวจสอบกล่องขาเข้าของคุณ"; "Scene.ConfirmEmail.Subtitle" = "แตะลิงก์ที่เราส่งอีเมลถึงคุณเพื่อยืนยันบัญชีของคุณ"; "Scene.ConfirmEmail.Title" = "หนึ่งสิ่งสุดท้าย"; +"Scene.Discovery.Intro" = "นี่คือโพสต์ที่กำลังได้รับความสนใจในมุมของ Mastodon ของคุณ"; "Scene.Discovery.Tabs.ForYou" = "สำหรับคุณ"; "Scene.Discovery.Tabs.Hashtags" = "แฮชแท็ก"; "Scene.Discovery.Tabs.News" = "ข่าว"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.strings index 407c4f9cb..3b853cd6b 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.strings @@ -7,7 +7,7 @@ "Common.Alerts.DeletePost.Message" = "Bạn có chắc muốn xóa tút này không?"; "Common.Alerts.DeletePost.Title" = "Xóa tút"; "Common.Alerts.DiscardPostContent.Message" = "Xác nhận bỏ qua nội dung tút đã viết."; -"Common.Alerts.DiscardPostContent.Title" = "Hủy bản nháp"; +"Common.Alerts.DiscardPostContent.Title" = "Bỏ bản nháp"; "Common.Alerts.EditProfileFailure.Message" = "Không thể chỉnh sửa hồ sơ. Vui lòng thử lại."; "Common.Alerts.EditProfileFailure.Title" = "Lỗi chỉnh sửa hồ sơ"; "Common.Alerts.PublishPostFailure.AttachmentsMessage.MoreThanOneVideo" = "Không thể đính kèm nhiều video."; @@ -108,6 +108,7 @@ Vui lòng kiểm tra kết nối mạng."; "Common.Controls.Status.MediaContentWarning" = "Nhấn để hiển thị"; "Common.Controls.Status.Poll.Closed" = "Kết thúc"; "Common.Controls.Status.Poll.Vote" = "Bình chọn"; +"Common.Controls.Status.SensitiveContent" = "Nội dung nhạy cảm"; "Common.Controls.Status.ShowPost" = "Xem tút"; "Common.Controls.Status.ShowUserProfile" = "Xem trang hồ sơ"; "Common.Controls.Status.Tag.Email" = "Email"; @@ -116,7 +117,7 @@ Vui lòng kiểm tra kết nối mạng."; "Common.Controls.Status.Tag.Link" = "Liên kết"; "Common.Controls.Status.Tag.Mention" = "Nhắc đến"; "Common.Controls.Status.Tag.Url" = "URL"; -"Common.Controls.Status.TapToReveal" = "Nhấn để hiển thị"; +"Common.Controls.Status.TapToReveal" = "Nhấn để xem"; "Common.Controls.Status.UserReblogged" = "%@ đăng lại"; "Common.Controls.Status.UserRepliedTo" = "Trả lời %@"; "Common.Controls.Status.Visibility.Direct" = "Chỉ người được nhắc đến có thể thấy tút."; @@ -174,7 +175,7 @@ tải lên Mastodon."; "Scene.Compose.MediaSelection.Browse" = "Chọn"; "Scene.Compose.MediaSelection.Camera" = "Chụp ảnh"; "Scene.Compose.MediaSelection.PhotoLibrary" = "Thư viện hình ảnh"; -"Scene.Compose.Poll.DurationTime" = "Thời gian: %@"; +"Scene.Compose.Poll.DurationTime" = "Thời hạn: %@"; "Scene.Compose.Poll.OneDay" = "1 ngày"; "Scene.Compose.Poll.OneHour" = "1 giờ"; "Scene.Compose.Poll.OptionNumber" = "Lựa chọn %ld"; @@ -182,10 +183,10 @@ tải lên Mastodon."; "Scene.Compose.Poll.SixHours" = "6 giờ"; "Scene.Compose.Poll.ThirtyMinutes" = "30 phút"; "Scene.Compose.Poll.ThreeDays" = "3 ngày"; -"Scene.Compose.ReplyingToUser" = "trả lời đến %@"; +"Scene.Compose.ReplyingToUser" = "trả lời %@"; "Scene.Compose.Title.NewPost" = "Viết tút"; "Scene.Compose.Title.NewReply" = "Viết trả lời"; -"Scene.Compose.Visibility.Direct" = "Chỉ người được nhắc đến"; +"Scene.Compose.Visibility.Direct" = "Nhắn riêng"; "Scene.Compose.Visibility.Private" = "Riêng tư"; "Scene.Compose.Visibility.Public" = "Công khai"; "Scene.Compose.Visibility.Unlisted" = "Hạn chế"; @@ -200,6 +201,7 @@ tải lên Mastodon."; "Scene.ConfirmEmail.OpenEmailApp.Title" = "Kiểm tra hộp thư của bạn."; "Scene.ConfirmEmail.Subtitle" = "Nhấn vào liên kết chúng tôi gửi qua email để xác thực tài khoản."; "Scene.ConfirmEmail.Title" = "Còn điều này nữa."; +"Scene.Discovery.Intro" = "Đây là những tút thu hút được sự chú ý trong góc Mastodon của bạn."; "Scene.Discovery.Tabs.ForYou" = "Dành cho bạn"; "Scene.Discovery.Tabs.Hashtags" = "Hashtag"; "Scene.Discovery.Tabs.News" = "Tin tức"; @@ -316,7 +318,7 @@ tải lên Mastodon."; "Scene.ServerPicker.Button.Category.Art" = "nghệ thuật"; "Scene.ServerPicker.Button.Category.Food" = "ăn uống"; "Scene.ServerPicker.Button.Category.Furry" = "furry"; -"Scene.ServerPicker.Button.Category.Games" = "trò chơi"; +"Scene.ServerPicker.Button.Category.Games" = "trò chơi điện tử"; "Scene.ServerPicker.Button.Category.General" = "chung"; "Scene.ServerPicker.Button.Category.Journalism" = "tin tức"; "Scene.ServerPicker.Button.Category.Lgbt" = "lgbt"; @@ -363,7 +365,7 @@ tải lên Mastodon."; "Scene.Settings.Section.Notifications.Title" = "Thông báo"; "Scene.Settings.Section.Notifications.Trigger.Anyone" = "ai đó"; "Scene.Settings.Section.Notifications.Trigger.Follow" = "người tôi theo dõi"; -"Scene.Settings.Section.Notifications.Trigger.Follower" = "người theo dõi"; +"Scene.Settings.Section.Notifications.Trigger.Follower" = "người theo dõi tôi"; "Scene.Settings.Section.Notifications.Trigger.Noone" = "không một ai"; "Scene.Settings.Section.Notifications.Trigger.Title" = "Thông báo khi"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Tắt ảnh đại diện GIF"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.strings index f9ec487c4..f0c67ec23 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.strings @@ -108,6 +108,7 @@ "Common.Controls.Status.MediaContentWarning" = "点击任意位置显示"; "Common.Controls.Status.Poll.Closed" = "已关闭"; "Common.Controls.Status.Poll.Vote" = "投票"; +"Common.Controls.Status.SensitiveContent" = "敏感内容"; "Common.Controls.Status.ShowPost" = "显示帖子"; "Common.Controls.Status.ShowUserProfile" = "查看用户个人资料"; "Common.Controls.Status.Tag.Email" = "电子邮箱"; @@ -201,10 +202,11 @@ "Scene.ConfirmEmail.Subtitle" = "我们刚刚向 %@ 发送了一封电子邮件, 点击链接确认你的帐户。"; "Scene.ConfirmEmail.Title" = "最后一件事。"; +"Scene.Discovery.Intro" = "这些嘟文在你的长毛象小宇宙中备受关注。"; "Scene.Discovery.Tabs.ForYou" = "为你推荐"; -"Scene.Discovery.Tabs.Hashtags" = "话题"; -"Scene.Discovery.Tabs.News" = "新闻"; -"Scene.Discovery.Tabs.Posts" = "帖子"; +"Scene.Discovery.Tabs.Hashtags" = "话题标签"; +"Scene.Discovery.Tabs.News" = "最新消息"; +"Scene.Discovery.Tabs.Posts" = "嘟文"; "Scene.Favorite.Title" = "你的喜欢"; "Scene.Follower.Footer" = "不会显示来自其它服务器的关注者"; "Scene.Following.Footer" = "不会显示来自其它服务器的关注"; From 433d2a964b8111c0cb1bae8223162e5a00fc77ea Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 27 Apr 2022 20:37:51 +0800 Subject: [PATCH 038/101] chore: update to version 1.3.3 (116) --- AppShared/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 36 +++++++++---------- .../xcschemes/xcschememanagement.plist | 6 ++-- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 9 files changed, 28 insertions(+), 28 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 1f75bbd84..6dfe3c6ce 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.3.3 CFBundleVersion - 115 + 116 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 153d74e44..df6b7a99b 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4748,7 +4748,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 115; + CURRENT_PROJECT_VERSION = 116; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4777,7 +4777,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 115; + CURRENT_PROJECT_VERSION = 116; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4885,11 +4885,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 115; + CURRENT_PROJECT_VERSION = 116; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 115; + DYLIB_CURRENT_VERSION = 116; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4916,11 +4916,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 115; + CURRENT_PROJECT_VERSION = 116; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 115; + DYLIB_CURRENT_VERSION = 116; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4945,7 +4945,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 115; + CURRENT_PROJECT_VERSION = 116; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4970,7 +4970,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 115; + CURRENT_PROJECT_VERSION = 116; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4995,7 +4995,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 115; + CURRENT_PROJECT_VERSION = 116; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5020,7 +5020,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 115; + CURRENT_PROJECT_VERSION = 116; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5106,7 +5106,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 115; + CURRENT_PROJECT_VERSION = 116; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5173,11 +5173,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 115; + CURRENT_PROJECT_VERSION = 116; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 115; + DYLIB_CURRENT_VERSION = 116; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5202,7 +5202,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 115; + CURRENT_PROJECT_VERSION = 116; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5226,7 +5226,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 115; + CURRENT_PROJECT_VERSION = 116; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5251,7 +5251,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 115; + CURRENT_PROJECT_VERSION = 116; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5276,7 +5276,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 115; + CURRENT_PROJECT_VERSION = 116; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5300,7 +5300,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 115; + CURRENT_PROJECT_VERSION = 116; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 40155e274..25507ae22 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 34 + 35 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 33 + 37 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 32 + 36 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index ed0bf25d2..28692c45c 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -43,7 +43,7 @@ CFBundleVersion - 115 + 116 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 86d1d76a1..c7f719867 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.3.3 CFBundleVersion - 115 + 116 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 1f75bbd84..6dfe3c6ce 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.3.3 CFBundleVersion - 115 + 116 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 1f75bbd84..6dfe3c6ce 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.3.3 CFBundleVersion - 115 + 116 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index 497e092e5..ac5f6640d 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.3.3 CFBundleVersion - 115 + 116 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 0296bd970..90d8a1b88 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.3.3 CFBundleVersion - 115 + 116 NSExtension NSExtensionAttributes From 9ffdd25fdfbb744b80c798822f2cf8e37815dfec Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 28 Apr 2022 07:12:14 +0800 Subject: [PATCH 039/101] chore: update version to 1.3.3 (117) --- AppShared/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 36 +++++++++++++++--------------- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 8 files changed, 25 insertions(+), 25 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 6dfe3c6ce..da1201b7f 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.3.3 CFBundleVersion - 116 + 117 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index df6b7a99b..a9aab17b1 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4748,7 +4748,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 116; + CURRENT_PROJECT_VERSION = 117; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4777,7 +4777,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 116; + CURRENT_PROJECT_VERSION = 117; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4885,11 +4885,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 116; + CURRENT_PROJECT_VERSION = 117; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 116; + DYLIB_CURRENT_VERSION = 117; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4916,11 +4916,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 116; + CURRENT_PROJECT_VERSION = 117; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 116; + DYLIB_CURRENT_VERSION = 117; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4945,7 +4945,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 116; + CURRENT_PROJECT_VERSION = 117; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4970,7 +4970,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 116; + CURRENT_PROJECT_VERSION = 117; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4995,7 +4995,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 116; + CURRENT_PROJECT_VERSION = 117; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5020,7 +5020,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 116; + CURRENT_PROJECT_VERSION = 117; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5106,7 +5106,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 116; + CURRENT_PROJECT_VERSION = 117; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5173,11 +5173,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 116; + CURRENT_PROJECT_VERSION = 117; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 116; + DYLIB_CURRENT_VERSION = 117; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5202,7 +5202,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 116; + CURRENT_PROJECT_VERSION = 117; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5226,7 +5226,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 116; + CURRENT_PROJECT_VERSION = 117; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5251,7 +5251,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 116; + CURRENT_PROJECT_VERSION = 117; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5276,7 +5276,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 116; + CURRENT_PROJECT_VERSION = 117; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5300,7 +5300,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 116; + CURRENT_PROJECT_VERSION = 117; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 28692c45c..22e36efbb 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -43,7 +43,7 @@ CFBundleVersion - 116 + 117 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index c7f719867..c43b12529 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.3.3 CFBundleVersion - 116 + 117 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 6dfe3c6ce..da1201b7f 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.3.3 CFBundleVersion - 116 + 117 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 6dfe3c6ce..da1201b7f 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.3.3 CFBundleVersion - 116 + 117 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index ac5f6640d..d3b7fdfe5 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.3.3 CFBundleVersion - 116 + 117 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 90d8a1b88..565cd561b 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.3.3 CFBundleVersion - 116 + 117 NSExtension NSExtensionAttributes From 6b04bd96fd2b6c8ecd148b10119d9bc0f9cc7224 Mon Sep 17 00:00:00 2001 From: CMK Date: Thu, 28 Apr 2022 07:20:49 +0800 Subject: [PATCH 040/101] chore: change community words to server --- Localization/app.json | 8 ++++---- .../xcschemes/xcschememanagement.plist | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Localization/app.json b/Localization/app.json index a8fc9031f..b6f49fc37 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -211,9 +211,9 @@ "log_in": "Log In" }, "server_picker": { - "title": "Mastodon is made of users in different communities.", - "subtitle": "Pick a community based on your interests, region, or a general purpose one.", - "subtitle_extend": "Pick a community based on your interests, region, or a general purpose one. Each community is operated by an entirely independent organization or individual.", + "title": "Mastodon is made of users in different servers.", + "subtitle": "Pick a server based on your interests, region, or a general purpose one.", + "subtitle_extend": "Pick a server based on your interests, region, or a general purpose one. Each server is operated by an entirely independent organization or individual.", "button": { "category": { "all": "All", @@ -240,7 +240,7 @@ "category": "CATEGORY" }, "input": { - "placeholder": "Search communities" + "placeholder": "Search servers" }, "empty_state": { "finding_servers": "Finding available servers...", diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 25507ae22..ad09868c8 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 35 + 24 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 37 + 22 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 36 + 23 SuppressBuildableAutocreation From 852b91912d69c896ca22372df3bf1de37dae8599 Mon Sep 17 00:00:00 2001 From: Marcus Kida Date: Thu, 28 Apr 2022 21:41:13 +0200 Subject: [PATCH 041/101] fix: cursor jumping when entering text before non-ascii char in share extension (#395) --- ShareActionExtension/Scene/View/StatusEditorView.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ShareActionExtension/Scene/View/StatusEditorView.swift b/ShareActionExtension/Scene/View/StatusEditorView.swift index 595057fa0..f670f6601 100644 --- a/ShareActionExtension/Scene/View/StatusEditorView.swift +++ b/ShareActionExtension/Scene/View/StatusEditorView.swift @@ -54,6 +54,9 @@ public struct StatusEditorView: UIViewRepresentable { } public func updateUIView(_ textView: UITextView, context: Context) { + // preserve currently selected text range to prevent cursor jump + let currentlySelectedRange = textView.selectedRange + // update content // textView.attributedText = attributedString textView.text = string @@ -66,6 +69,9 @@ public struct StatusEditorView: UIViewRepresentable { viewDidAppear = false textView.becomeFirstResponder() } + + // restore selected text range + textView.selectedRange = currentlySelectedRange } public func makeCoordinator() -> Coordinator { From dff4a5f118cd6fc9fc843340b873e929ceb143a2 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 29 Apr 2022 09:02:47 +0800 Subject: [PATCH 042/101] chore: add Community word for i18n --- Localization/app.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Localization/app.json b/Localization/app.json index b6f49fc37..50512250d 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -498,6 +498,7 @@ "posts": "Posts", "hashtags": "Hashtags", "news": "News", + "community": "Community", "for_you": "For You" }, "intro": "These are the posts gaining traction in your corner of Mastodon." From 0548aa5f5670fc5e61cd2abe2fe042b0a2dab39a Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 29 Apr 2022 13:35:03 +0800 Subject: [PATCH 043/101] feat: add Community tab into discovery scene --- Mastodon.xcodeproj/project.pbxproj | 32 +++ ...oGenerateTableViewDelegate.generated.swift | 19 +- .../Community/CommunityViewViewModel.swift | 64 ++++++ ...ityViewController+DataSourceProvider.swift | 34 +++ .../DiscoveryCommunityViewController.swift | 154 +++++++++++++ ...DiscoveryCommunityViewModel+Diffable.swift | 65 ++++++ .../DiscoveryCommunityViewModel+State.swift | 206 ++++++++++++++++++ .../DiscoveryCommunityViewModel.swift | 65 ++++++ .../DiscoveryCommunityViewViewModel.swift | 64 ++++++ .../Scene/Discovery/DiscoveryViewModel.swift | 25 ++- .../Hashtags/DiscoveryHashtagsViewModel.swift | 1 + .../Posts/DiscoveryPostsViewModel+State.swift | 2 +- .../UserTimelineViewModel+State.swift | 6 + .../APIService+PublicTimeline.swift | 52 +++++ .../APIService/APIService+UserTimeline.swift | 2 +- .../API/Mastodon+API+Timeline.swift | 6 +- 16 files changed, 781 insertions(+), 16 deletions(-) create mode 100644 Mastodon/Scene/Discovery/Community/CommunityViewViewModel.swift create mode 100644 Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewController+DataSourceProvider.swift create mode 100644 Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewController.swift create mode 100644 Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel+Diffable.swift create mode 100644 Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel+State.swift create mode 100644 Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel.swift create mode 100644 Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewViewModel.swift create mode 100644 Mastodon/Service/APIService/APIService+PublicTimeline.swift diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index a9aab17b1..833ea24de 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -233,6 +233,12 @@ DB3E6FF52807C40300B035AE /* DiscoveryForYouViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FF42807C40300B035AE /* DiscoveryForYouViewController.swift */; }; DB3E6FF82807C45300B035AE /* DiscoveryForYouViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FF72807C45300B035AE /* DiscoveryForYouViewModel.swift */; }; DB3E6FFA2807C47900B035AE /* DiscoveryForYouViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FF92807C47900B035AE /* DiscoveryForYouViewModel+Diffable.swift */; }; + DB3EA8E6281B79E200598866 /* DiscoveryCommunityViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3EA8E5281B79E200598866 /* DiscoveryCommunityViewController.swift */; }; + DB3EA8E9281B7A3700598866 /* DiscoveryCommunityViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3EA8E8281B7A3700598866 /* DiscoveryCommunityViewModel.swift */; }; + DB3EA8EB281B7E0700598866 /* DiscoveryCommunityViewModel+State.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3EA8EA281B7E0700598866 /* DiscoveryCommunityViewModel+State.swift */; }; + DB3EA8ED281B810100598866 /* APIService+PublicTimeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3EA8EC281B810100598866 /* APIService+PublicTimeline.swift */; }; + DB3EA8EF281B837000598866 /* DiscoveryCommunityViewController+DataSourceProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3EA8EE281B837000598866 /* DiscoveryCommunityViewController+DataSourceProvider.swift */; }; + DB3EA8F1281B9EF600598866 /* DiscoveryCommunityViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3EA8F0281B9EF600598866 /* DiscoveryCommunityViewModel+Diffable.swift */; }; DB427DD625BAA00100D1B89D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB427DD525BAA00100D1B89D /* AppDelegate.swift */; }; DB427DD825BAA00100D1B89D /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB427DD725BAA00100D1B89D /* SceneDelegate.swift */; }; DB427DDD25BAA00100D1B89D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DB427DDB25BAA00100D1B89D /* Main.storyboard */; }; @@ -962,6 +968,12 @@ DB3E6FF42807C40300B035AE /* DiscoveryForYouViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryForYouViewController.swift; sourceTree = ""; }; DB3E6FF72807C45300B035AE /* DiscoveryForYouViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryForYouViewModel.swift; sourceTree = ""; }; DB3E6FF92807C47900B035AE /* DiscoveryForYouViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiscoveryForYouViewModel+Diffable.swift"; sourceTree = ""; }; + DB3EA8E5281B79E200598866 /* DiscoveryCommunityViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryCommunityViewController.swift; sourceTree = ""; }; + DB3EA8E8281B7A3700598866 /* DiscoveryCommunityViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryCommunityViewModel.swift; sourceTree = ""; }; + DB3EA8EA281B7E0700598866 /* DiscoveryCommunityViewModel+State.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiscoveryCommunityViewModel+State.swift"; sourceTree = ""; }; + DB3EA8EC281B810100598866 /* APIService+PublicTimeline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+PublicTimeline.swift"; sourceTree = ""; }; + DB3EA8EE281B837000598866 /* DiscoveryCommunityViewController+DataSourceProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiscoveryCommunityViewController+DataSourceProvider.swift"; sourceTree = ""; }; + DB3EA8F0281B9EF600598866 /* DiscoveryCommunityViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiscoveryCommunityViewModel+Diffable.swift"; sourceTree = ""; }; DB427DD225BAA00100D1B89D /* Mastodon.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Mastodon.app; sourceTree = BUILT_PRODUCTS_DIR; }; DB427DD525BAA00100D1B89D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; DB427DD725BAA00100D1B89D /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; @@ -2165,6 +2177,18 @@ path = ForYou; sourceTree = ""; }; + DB3EA8E7281B79E500598866 /* Community */ = { + isa = PBXGroup; + children = ( + DB3EA8E5281B79E200598866 /* DiscoveryCommunityViewController.swift */, + DB3EA8EE281B837000598866 /* DiscoveryCommunityViewController+DataSourceProvider.swift */, + DB3EA8E8281B7A3700598866 /* DiscoveryCommunityViewModel.swift */, + DB3EA8F0281B9EF600598866 /* DiscoveryCommunityViewModel+Diffable.swift */, + DB3EA8EA281B7E0700598866 /* DiscoveryCommunityViewModel+State.swift */, + ); + path = Community; + sourceTree = ""; + }; DB427DC925BAA00100D1B89D = { isa = PBXGroup; children = ( @@ -2258,6 +2282,7 @@ 2D9DB96A263A91D1007C1D71 /* APIService+DomainBlock.swift */, DB45FB1C25CA9D23005A8AC7 /* APIService+HomeTimeline.swift */, DB482A4A261340A7008AE74C /* APIService+UserTimeline.swift */, + DB3EA8EC281B810100598866 /* APIService+PublicTimeline.swift */, DBA465922696B495002B41DB /* APIService+WebFinger.swift */, DB0AC6FB25CD02E600D75117 /* APIService+Instance.swift */, DB59F10D25EF724F001F1DAB /* APIService+Poll.swift */, @@ -3128,6 +3153,7 @@ DBDFF19828055A0900557A48 /* Posts */, DB3E6FDE2806A41200B035AE /* Hashtags */, DB3E6FED2806D7FC00B035AE /* News */, + DB3EA8E7281B79E500598866 /* Community */, DB3E6FF62807C40500B035AE /* ForYou */, DBDFF19928055A1400557A48 /* DiscoveryViewController.swift */, DBDFF19B28055BD600557A48 /* DiscoveryViewModel.swift */, @@ -4049,6 +4075,7 @@ DB63F7452799056400455B82 /* HashtagTableViewCell.swift in Sources */, DBD9149025DF6D8D00903DFD /* APIService+Onboarding.swift in Sources */, DBAE3FAF26172FC0004B8251 /* RemoteProfileViewModel.swift in Sources */, + DB3EA8EB281B7E0700598866 /* DiscoveryCommunityViewModel+State.swift in Sources */, DB0FCB7227952986006C02E2 /* NamingState.swift in Sources */, DB73BF47271199CA00781945 /* Instance.swift in Sources */, DB0F8150264D1E2500F2A12B /* PickServerLoaderTableViewCell.swift in Sources */, @@ -4181,6 +4208,7 @@ DB040ED126538E3D00BEE9D8 /* Trie.swift in Sources */, DB73BF4B27140C0800781945 /* UITableViewDiffableDataSource.swift in Sources */, DBB525642612C988002F1F29 /* MeProfileViewModel.swift in Sources */, + DB3EA8EF281B837000598866 /* DiscoveryCommunityViewController+DataSourceProvider.swift in Sources */, DB6B74EF272FB55000C70B6E /* FollowerListViewController.swift in Sources */, DB4AA6B327BA34B6009EC082 /* CellFrameCacheContainer.swift in Sources */, DB0FCB942797E2B0006C02E2 /* SearchResultViewModel+Diffable.swift in Sources */, @@ -4222,10 +4250,12 @@ DB697DE1278F5296004EF2F7 /* DataSourceFacade+Model.swift in Sources */, DBCC3B8F26148F7B0045B23D /* CachedProfileViewModel.swift in Sources */, DB4F097526A037F500D62E92 /* SearchHistoryViewModel.swift in Sources */, + DB3EA8E9281B7A3700598866 /* DiscoveryCommunityViewModel.swift in Sources */, DB6180F826391D660018D199 /* MediaPreviewingViewController.swift in Sources */, DB0140CF25C42AEE00F9F3CF /* OSLog.swift in Sources */, DB98EB5627B0FF1B0082E365 /* ReportViewControllerAppearance.swift in Sources */, DB938F1526241FDF00E5B6C1 /* APIService+Thread.swift in Sources */, + DB3EA8E6281B79E200598866 /* DiscoveryCommunityViewController.swift in Sources */, 2D206B8625F5FB0900143C56 /* Double.swift in Sources */, DB9F58F126EF512300E7BBE9 /* AccountListTableViewCell.swift in Sources */, 2D76319F25C1521200929FB9 /* StatusSection.swift in Sources */, @@ -4276,6 +4306,7 @@ DB73BF45271195AC00781945 /* APIService+CoreData+Instance.swift in Sources */, DB336F21278D6D960031E64B /* MastodonEmoji.swift in Sources */, DB1D84382657B275000346B3 /* SegmentedControlNavigateable.swift in Sources */, + DB3EA8ED281B810100598866 /* APIService+PublicTimeline.swift in Sources */, DB447697260B439000B66B82 /* CustomEmojiPickerHeaderCollectionReusableView.swift in Sources */, DB025B97278D66D5002F581E /* MastodonUser+Property.swift in Sources */, DB45FAF925CA80A2005A8AC7 /* APIService+CoreData+MastodonAuthentication.swift in Sources */, @@ -4338,6 +4369,7 @@ DB9D6BFF25E4F5940051B173 /* ProfileViewController.swift in Sources */, DB63F756279949BD00455B82 /* Persistence+SearchHistory.swift in Sources */, 2D4AD8A226316CD200613EFC /* SelectedAccountSection.swift in Sources */, + DB3EA8F1281B9EF600598866 /* DiscoveryCommunityViewModel+Diffable.swift in Sources */, DB63F775279A997D00455B82 /* NotificationTableViewCell+ViewModel.swift in Sources */, DB98EB5927B109890082E365 /* ReportSupplementaryViewController.swift in Sources */, DB0617EB277EF3820030EE79 /* GradientBorderView.swift in Sources */, diff --git a/Mastodon/Generated/AutoGenerateTableViewDelegate.generated.swift b/Mastodon/Generated/AutoGenerateTableViewDelegate.generated.swift index ebf867007..7d6e01cf7 100644 --- a/Mastodon/Generated/AutoGenerateTableViewDelegate.generated.swift +++ b/Mastodon/Generated/AutoGenerateTableViewDelegate.generated.swift @@ -1,14 +1,7 @@ // Generated using Sourcery 1.6.1 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT - - - - - - - -// sourcery:inline:UserTimelineViewController.AutoGenerateTableViewDelegate +// sourcery:inline:DiscoveryCommunityViewController.AutoGenerateTableViewDelegate // Generated using Sourcery // DO NOT EDIT @@ -33,3 +26,13 @@ func tableView(_ tableView: UITableView, willPerformPreviewActionForMenuWith con } // sourcery:end + + + + + + + + + + diff --git a/Mastodon/Scene/Discovery/Community/CommunityViewViewModel.swift b/Mastodon/Scene/Discovery/Community/CommunityViewViewModel.swift new file mode 100644 index 000000000..51eba9b36 --- /dev/null +++ b/Mastodon/Scene/Discovery/Community/CommunityViewViewModel.swift @@ -0,0 +1,64 @@ +// +// DiscoveryCommunityViewViewModel.swift +// Mastodon +// +// Created by MainasuK on 2022-4-29. +// + +import os.log +import UIKit +import Combine +import GameplayKit +import CoreData +import CoreDataStack +import MastodonSDK + +final class DiscoveryCommunityViewViewModel { + + let logger = Logger(subsystem: "DiscoveryCommunityViewViewModel", category: "ViewModel") + + var disposeBag = Set() + + // input + let context: AppContext + let viewDidAppeared = PassthroughSubject() + let statusFetchedResultsController: StatusFetchedResultsController + + // output + var diffableDataSource: UITableViewDiffableDataSource? + private(set) lazy var stateMachine: GKStateMachine = { + let stateMachine = GKStateMachine(states: [ + State.Initial(viewModel: self), + State.Reloading(viewModel: self), + State.Fail(viewModel: self), + State.Idle(viewModel: self), + State.Loading(viewModel: self), + State.NoMore(viewModel: self), + ]) + stateMachine.enter(State.Initial.self) + return stateMachine + }() + + let didLoadLatest = PassthroughSubject() + + init(context: AppContext) { + self.context = context + self.statusFetchedResultsController = StatusFetchedResultsController( + managedObjectContext: context.managedObjectContext, + domain: nil, + additionalTweetPredicate: nil + ) + // end init + + context.authenticationService.activeMastodonAuthentication + .map { $0?.domain } + .assign(to: \.value, on: statusFetchedResultsController.domain) + .store(in: &disposeBag) + + } + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } + +} diff --git a/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewController+DataSourceProvider.swift b/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewController+DataSourceProvider.swift new file mode 100644 index 000000000..e9441b5d3 --- /dev/null +++ b/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewController+DataSourceProvider.swift @@ -0,0 +1,34 @@ +// +// DiscoveryCommunityViewController+DataSourceProvider.swift +// Mastodon +// +// Created by MainasuK on 2022-4-29. +// + +import UIKit + +extension DiscoveryCommunityViewController: DataSourceProvider { + func item(from source: DataSourceItem.Source) async -> DataSourceItem? { + var _indexPath = source.indexPath + if _indexPath == nil, let cell = source.tableViewCell { + _indexPath = await self.indexPath(for: cell) + } + guard let indexPath = _indexPath else { return nil } + + guard let item = viewModel.diffableDataSource?.itemIdentifier(for: indexPath) else { + return nil + } + + switch item { + case .status(let record): + return .status(record: record) + default: + return nil + } + } + + @MainActor + private func indexPath(for cell: UITableViewCell) async -> IndexPath? { + return tableView.indexPath(for: cell) + } +} diff --git a/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewController.swift b/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewController.swift new file mode 100644 index 000000000..eabed7a0e --- /dev/null +++ b/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewController.swift @@ -0,0 +1,154 @@ +// +// DiscoveryCommunityViewController.swift +// Mastodon +// +// Created by MainasuK on 2022-4-29. +// + +import os.log +import UIKit +import Combine +import MastodonUI + +// Local Timeline +final class DiscoveryCommunityViewController: UIViewController, NeedsDependency, MediaPreviewableViewController { + + let logger = Logger(subsystem: "DiscoveryCommunityViewController", category: "ViewController") + + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } + weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + + var disposeBag = Set() + var viewModel: DiscoveryCommunityViewModel! + + let mediaPreviewTransitionController = MediaPreviewTransitionController() + + lazy var tableView: UITableView = { + let tableView = UITableView() + tableView.rowHeight = UITableView.automaticDimension + tableView.estimatedRowHeight = 100 + tableView.separatorStyle = .none + tableView.backgroundColor = .clear + return tableView + }() + + let refreshControl = UIRefreshControl() + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } + +} + +extension DiscoveryCommunityViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor + ThemeService.shared.currentTheme + .receive(on: DispatchQueue.main) + .sink { [weak self] theme in + guard let self = self else { return } + self.view.backgroundColor = theme.secondarySystemBackgroundColor + } + .store(in: &disposeBag) + + tableView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(tableView) + NSLayoutConstraint.activate([ + tableView.topAnchor.constraint(equalTo: view.topAnchor), + tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + ]) + + tableView.refreshControl = refreshControl + refreshControl.addTarget(self, action: #selector(DiscoveryCommunityViewController.refreshControlValueChanged(_:)), for: .valueChanged) + viewModel.didLoadLatest + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in + guard let self = self else { return } + self.refreshControl.endRefreshing() + } + .store(in: &disposeBag) + + tableView.delegate = self + viewModel.setupDiffableDataSource( + tableView: tableView, + statusTableViewCellDelegate: self + ) + + // setup batch fetch + viewModel.listBatchFetchViewModel.setup(scrollView: tableView) + viewModel.listBatchFetchViewModel.shouldFetch + .receive(on: DispatchQueue.main) + .sink { [weak self] _ in + guard let self = self else { return } + guard self.view.window != nil else { return } + self.viewModel.stateMachine.enter(DiscoveryCommunityViewModel.State.Loading.self) + } + .store(in: &disposeBag) + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + tableView.deselectRow(with: transitionCoordinator, animated: animated) + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + viewModel.viewDidAppeared.send() + } + +} + +extension DiscoveryCommunityViewController { + + @objc private func refreshControlValueChanged(_ sender: UIRefreshControl) { + if !viewModel.stateMachine.enter(DiscoveryCommunityViewModel.State.Reloading.self) { + refreshControl.endRefreshing() + } + } + +} + +// MARK: - UITableViewDelegate +extension DiscoveryCommunityViewController: UITableViewDelegate, AutoGenerateTableViewDelegate { + // sourcery:inline:CommunityViewController.AutoGenerateTableViewDelegate + + // Generated using Sourcery + // DO NOT EDIT + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + aspectTableView(tableView, didSelectRowAt: indexPath) + } + + func tableView(_ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? { + return aspectTableView(tableView, contextMenuConfigurationForRowAt: indexPath, point: point) + } + + func tableView(_ tableView: UITableView, previewForHighlightingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? { + return aspectTableView(tableView, previewForHighlightingContextMenuWithConfiguration: configuration) + } + + func tableView(_ tableView: UITableView, previewForDismissingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? { + return aspectTableView(tableView, previewForDismissingContextMenuWithConfiguration: configuration) + } + + func tableView(_ tableView: UITableView, willPerformPreviewActionForMenuWith configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionCommitAnimating) { + aspectTableView(tableView, willPerformPreviewActionForMenuWith: configuration, animator: animator) + } + // sourcery:end +} + +// MARK: - StatusTableViewCellDelegate +extension DiscoveryCommunityViewController: StatusTableViewCellDelegate { } + +// MARK: ScrollViewContainer +extension DiscoveryCommunityViewController: ScrollViewContainer { + var scrollView: UIScrollView? { + tableView + } +} diff --git a/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel+Diffable.swift b/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel+Diffable.swift new file mode 100644 index 000000000..26335ec3d --- /dev/null +++ b/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel+Diffable.swift @@ -0,0 +1,65 @@ +// +// DiscoveryCommunityViewModel+Diffable.swift +// Mastodon +// +// Created by MainasuK on 2022-4-29. +// + +import UIKit +import Combine + +extension DiscoveryCommunityViewModel { + + func setupDiffableDataSource( + tableView: UITableView, + statusTableViewCellDelegate: StatusTableViewCellDelegate + ) { + diffableDataSource = StatusSection.diffableDataSource( + tableView: tableView, + context: context, + configuration: StatusSection.Configuration( + statusTableViewCellDelegate: statusTableViewCellDelegate, + timelineMiddleLoaderTableViewCellDelegate: nil, + filterContext: .none, + activeFilters: nil + ) + ) + + stateMachine.enter(State.Reloading.self) + + statusFetchedResultsController.$records + .receive(on: DispatchQueue.main) + .sink { [weak self] records in + guard let self = self else { return } + guard let diffableDataSource = self.diffableDataSource else { return } + + var snapshot = NSDiffableDataSourceSnapshot() + snapshot.appendSections([.main]) + + let items = records.map { StatusItem.status(record: $0) } + snapshot.appendItems(items, toSection: .main) + + if let currentState = self.stateMachine.currentState { + switch currentState { + case is State.Initial, + is State.Reloading, + is State.Loading, + is State.Idle, + is State.Fail: + if !items.isEmpty { + snapshot.appendItems([.bottomLoader], toSection: .main) + } + case is State.NoMore: + break + default: + assertionFailure() + break + } + } + + diffableDataSource.applySnapshot(snapshot, animated: false) + } + .store(in: &disposeBag) + } + +} diff --git a/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel+State.swift b/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel+State.swift new file mode 100644 index 000000000..a3947e6ab --- /dev/null +++ b/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel+State.swift @@ -0,0 +1,206 @@ +// +// DiscoveryCommunityViewModel+State.swift +// Mastodon +// +// Created by MainasuK on 2022-4-29. +// + +import os.log +import Foundation +import GameplayKit +import MastodonSDK + +extension DiscoveryCommunityViewModel { + class State: GKState, NamingState { + + let logger = Logger(subsystem: "DiscoveryCommunityViewModel.State", category: "StateMachine") + + let id = UUID() + + var name: String { + String(describing: Self.self) + } + + weak var viewModel: DiscoveryCommunityViewModel? + + init(viewModel: DiscoveryCommunityViewModel) { + self.viewModel = viewModel + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + let previousState = previousState as? DiscoveryCommunityViewModel.State + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [\(self.id.uuidString)] enter \(self.name), previous: \(previousState?.name ?? "")") + } + + @MainActor + func enter(state: State.Type) { + stateMachine?.enter(state) + } + + deinit { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [\(self.id.uuidString)] \(self.name)") + } + } +} + +extension DiscoveryCommunityViewModel.State { + class Initial: DiscoveryCommunityViewModel.State { + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Reloading.Type: + return true + default: + return false + } + } + } + + class Reloading: DiscoveryCommunityViewModel.State { + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Loading.Type: + return true + default: + return false + } + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + guard let _ = viewModel, let stateMachine = stateMachine else { return } + + stateMachine.enter(Loading.self) + } + } + + class Fail: DiscoveryCommunityViewModel.State { + + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Loading.Type: + return true + default: + return false + } + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + guard let _ = viewModel, let stateMachine = stateMachine else { return } + + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: retry loading 3s later…", ((#file as NSString).lastPathComponent), #line, #function) + DispatchQueue.main.asyncAfter(deadline: .now() + 3) { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: retry loading", ((#file as NSString).lastPathComponent), #line, #function) + stateMachine.enter(Loading.self) + } + } + } + + class Idle: DiscoveryCommunityViewModel.State { + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Reloading.Type, is Loading.Type: + return true + default: + return false + } + } + } + + class Loading: DiscoveryCommunityViewModel.State { + + var maxID: String? + + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Fail.Type: + return true + case is Idle.Type: + return true + case is NoMore.Type: + return true + default: + return false + } + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + guard let viewModel = viewModel, let stateMachine = stateMachine else { return } + + switch previousState { + case is Reloading: + maxID = nil + default: + break + } + + guard let authenticationBox = viewModel.context.authenticationService.activeMastodonAuthenticationBox.value else { + stateMachine.enter(Fail.self) + return + } + + let maxID = self.maxID + let isReloading = maxID == nil + + Task { + do { + let response = try await viewModel.context.apiService.publicTimeline( + query: .init( + local: true, + remote: nil, + onlyMedia: nil, + maxID: maxID, + sinceID: nil, + minID: nil, + limit: 20 + ), + authenticationBox: authenticationBox + ) + + let newMaxID = response.link?.maxID + let hasMore = newMaxID != nil + self.maxID = newMaxID + + var hasNewStatusesAppend = false + var statusIDs = isReloading ? [] : viewModel.statusFetchedResultsController.statusIDs.value + for status in response.value { + guard !statusIDs.contains(status.id) else { continue } + statusIDs.append(status.id) + hasNewStatusesAppend = true + } + + if hasNewStatusesAppend, hasMore { + self.maxID = response.link?.maxID + await enter(state: Idle.self) + } else { + await enter(state: NoMore.self) + } + viewModel.statusFetchedResultsController.statusIDs.value = statusIDs + viewModel.didLoadLatest.send() + + } catch { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): fetch user timeline fail: \(error.localizedDescription)") + await enter(state: Fail.self) + } + } // end Task + } // end func + } + + class NoMore: DiscoveryCommunityViewModel.State { + override func isValidNextState(_ stateClass: AnyClass) -> Bool { + switch stateClass { + case is Reloading.Type: + return true + default: + return false + } + } + + override func didEnter(from previousState: GKState?) { + super.didEnter(from: previousState) + + } + } +} diff --git a/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel.swift b/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel.swift new file mode 100644 index 000000000..8911a506e --- /dev/null +++ b/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewModel.swift @@ -0,0 +1,65 @@ +// +// DiscoveryCommunityViewModel.swift +// Mastodon +// +// Created by MainasuK on 2022-4-29. +// + +import os.log +import UIKit +import Combine +import GameplayKit +import CoreData +import CoreDataStack +import MastodonSDK + +final class DiscoveryCommunityViewModel { + + let logger = Logger(subsystem: "DiscoveryCommunityViewModel", category: "ViewModel") + + var disposeBag = Set() + + // input + let context: AppContext + let viewDidAppeared = PassthroughSubject() + let statusFetchedResultsController: StatusFetchedResultsController + let listBatchFetchViewModel = ListBatchFetchViewModel() + + // output + var diffableDataSource: UITableViewDiffableDataSource? + private(set) lazy var stateMachine: GKStateMachine = { + let stateMachine = GKStateMachine(states: [ + State.Initial(viewModel: self), + State.Reloading(viewModel: self), + State.Fail(viewModel: self), + State.Idle(viewModel: self), + State.Loading(viewModel: self), + State.NoMore(viewModel: self), + ]) + stateMachine.enter(State.Initial.self) + return stateMachine + }() + + let didLoadLatest = PassthroughSubject() + + init(context: AppContext) { + self.context = context + self.statusFetchedResultsController = StatusFetchedResultsController( + managedObjectContext: context.managedObjectContext, + domain: nil, + additionalTweetPredicate: nil + ) + // end init + + context.authenticationService.activeMastodonAuthentication + .map { $0?.domain } + .assign(to: \.value, on: statusFetchedResultsController.domain) + .store(in: &disposeBag) + + } + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } + +} diff --git a/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewViewModel.swift b/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewViewModel.swift new file mode 100644 index 000000000..bbf508b69 --- /dev/null +++ b/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewViewModel.swift @@ -0,0 +1,64 @@ +// +// DiscoveryCommunityViewModel.swift +// Mastodon +// +// Created by MainasuK on 2022-4-29. +// + +import os.log +import UIKit +import Combine +import GameplayKit +import CoreData +import CoreDataStack +import MastodonSDK + +final class DiscoveryCommunityViewModel { + + let logger = Logger(subsystem: "DiscoveryCommunityViewModel", category: "ViewModel") + + var disposeBag = Set() + + // input + let context: AppContext + let viewDidAppeared = PassthroughSubject() + let statusFetchedResultsController: StatusFetchedResultsController + + // output + var diffableDataSource: UITableViewDiffableDataSource? + private(set) lazy var stateMachine: GKStateMachine = { + let stateMachine = GKStateMachine(states: [ + State.Initial(viewModel: self), + State.Reloading(viewModel: self), + State.Fail(viewModel: self), + State.Idle(viewModel: self), + State.Loading(viewModel: self), + State.NoMore(viewModel: self), + ]) + stateMachine.enter(State.Initial.self) + return stateMachine + }() + + let didLoadLatest = PassthroughSubject() + + init(context: AppContext) { + self.context = context + self.statusFetchedResultsController = StatusFetchedResultsController( + managedObjectContext: context.managedObjectContext, + domain: nil, + additionalTweetPredicate: nil + ) + // end init + + context.authenticationService.activeMastodonAuthentication + .map { $0?.domain } + .assign(to: \.value, on: statusFetchedResultsController.domain) + .store(in: &disposeBag) + + } + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } + +} diff --git a/Mastodon/Scene/Discovery/DiscoveryViewModel.swift b/Mastodon/Scene/Discovery/DiscoveryViewModel.swift index ae31797e5..ca4773fe1 100644 --- a/Mastodon/Scene/Discovery/DiscoveryViewModel.swift +++ b/Mastodon/Scene/Discovery/DiscoveryViewModel.swift @@ -9,6 +9,7 @@ import UIKit import Combine import Tabman import Pageboy +import MastodonLocalization final class DiscoveryViewModel { @@ -19,6 +20,7 @@ final class DiscoveryViewModel { let discoveryPostsViewController: DiscoveryPostsViewController let discoveryHashtagsViewController: DiscoveryHashtagsViewController let discoveryNewsViewController: DiscoveryNewsViewController + let discoveryCommunityViewController: DiscoveryCommunityViewController let discoveryForYouViewController: DiscoveryForYouViewController @Published var viewControllers: [ScrollViewContainer & PageViewController] @@ -48,6 +50,12 @@ final class DiscoveryViewModel { viewController.viewModel = DiscoveryNewsViewModel(context: context) return viewController }() + discoveryCommunityViewController = { + let viewController = DiscoveryCommunityViewController() + setupDependency(viewController) + viewController.viewModel = DiscoveryCommunityViewModel(context: context) + return viewController + }() discoveryForYouViewController = { let viewController = DiscoveryForYouViewController() setupDependency(viewController) @@ -58,6 +66,7 @@ final class DiscoveryViewModel { discoveryPostsViewController, discoveryHashtagsViewController, discoveryNewsViewController, + discoveryCommunityViewController, discoveryForYouViewController, ] // end init @@ -123,7 +132,7 @@ protocol PageViewController: UIViewController { // MARK: - PageViewController extension DiscoveryPostsViewController: PageViewController { - var tabItemTitle: String { "Posts" } + var tabItemTitle: String { L10n.Scene.Discovery.Tabs.posts } var tabItem: TMBarItemable { return TMBarItem(title: tabItemTitle) } @@ -132,7 +141,7 @@ extension DiscoveryPostsViewController: PageViewController { // MARK: - PageViewController extension DiscoveryHashtagsViewController: PageViewController { - var tabItemTitle: String { "Hashtags" } + var tabItemTitle: String { L10n.Scene.Discovery.Tabs.hashtags } var tabItem: TMBarItemable { return TMBarItem(title: tabItemTitle) @@ -141,7 +150,15 @@ extension DiscoveryHashtagsViewController: PageViewController { // MARK: - PageViewController extension DiscoveryNewsViewController: PageViewController { - var tabItemTitle: String { "News" } + var tabItemTitle: String { L10n.Scene.Discovery.Tabs.news } + var tabItem: TMBarItemable { + return TMBarItem(title: tabItemTitle) + } +} + +// MARK: - PageViewController +extension DiscoveryCommunityViewController: PageViewController { + var tabItemTitle: String { "Community" } var tabItem: TMBarItemable { return TMBarItem(title: tabItemTitle) } @@ -149,7 +166,7 @@ extension DiscoveryNewsViewController: PageViewController { // MARK: - PageViewController extension DiscoveryForYouViewController: PageViewController { - var tabItemTitle: String { "For You" } + var tabItemTitle: String { L10n.Scene.Discovery.Tabs.forYou } var tabItem: TMBarItemable { return TMBarItem(title: tabItemTitle) } diff --git a/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel.swift b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel.swift index bb30ec9ee..1b119f3d7 100644 --- a/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel.swift +++ b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewModel.swift @@ -73,4 +73,5 @@ extension DiscoveryHashtagsViewModel { hashtags = response.value.filter { !$0.name.isEmpty } logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): fetch tags: \(response.value.count)") } + } diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift index d91c5adc2..0ff6cbb14 100644 --- a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewModel+State.swift @@ -180,7 +180,7 @@ extension DiscoveryPostsViewModel.State { } viewModel.statusFetchedResultsController.statusIDs.value = statusIDs viewModel.didLoadLatest.send() -// } catch let error as? + } catch { logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): fetch posts fail: \(error.localizedDescription)") if let error = error as? Mastodon.API.Error, error.httpResponseStatus.code == 404 { diff --git a/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel+State.swift b/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel+State.swift index 06f657bad..ae870f7b5 100644 --- a/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel+State.swift +++ b/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel+State.swift @@ -195,6 +195,12 @@ extension UserTimelineViewModel.State { // trigger data source update. otherwise, spinner always display viewModel.isSuspended.value = viewModel.isSuspended.value + + // remove bottom loader + guard let diffableDataSource = viewModel.diffableDataSource else { return } + var snapshot = diffableDataSource.snapshot() + snapshot.deleteItems([.bottomLoader]) + diffableDataSource.apply(snapshot) } } } diff --git a/Mastodon/Service/APIService/APIService+PublicTimeline.swift b/Mastodon/Service/APIService/APIService+PublicTimeline.swift new file mode 100644 index 000000000..fd0c2f0cd --- /dev/null +++ b/Mastodon/Service/APIService/APIService+PublicTimeline.swift @@ -0,0 +1,52 @@ +// +// APIService+PublicTimeline.swift +// Mastodon +// +// Created by MainasuK on 2022-4-29. +// + +import Foundation +import Combine +import CoreData +import CoreDataStack +import CommonOSLog +import MastodonSDK + +extension APIService { + + func publicTimeline( + query: Mastodon.API.Timeline.PublicTimelineQuery, + authenticationBox: MastodonAuthenticationBox + ) async throws -> Mastodon.Response.Content<[Mastodon.Entity.Status]> { + let domain = authenticationBox.domain + let authorization = authenticationBox.userAuthorization + + let response = try await Mastodon.API.Timeline.public( + session: session, + domain: domain, + query: query, + authorization: authorization + ).singleOutput() + + let managedObjectContext = self.backgroundManagedObjectContext + try await managedObjectContext.performChanges { + let me = authenticationBox.authenticationRecord.object(in: managedObjectContext)?.user + for entity in response.value { + _ = Persistence.Status.createOrMerge( + in: managedObjectContext, + context: Persistence.Status.PersistContext( + domain: domain, + entity: entity, + me: me, + statusCache: nil, + userCache: nil, + networkDate: response.networkDate + ) + ) + } + } + + return response + } // end func + +} diff --git a/Mastodon/Service/APIService/APIService+UserTimeline.swift b/Mastodon/Service/APIService/APIService+UserTimeline.swift index c5cb63180..85b8d6153 100644 --- a/Mastodon/Service/APIService/APIService+UserTimeline.swift +++ b/Mastodon/Service/APIService/APIService+UserTimeline.swift @@ -48,7 +48,7 @@ extension APIService { try await managedObjectContext.performChanges { let me = authenticationBox.authenticationRecord.object(in: managedObjectContext)?.user for entity in response.value { - Persistence.Status.createOrMerge( + _ = Persistence.Status.createOrMerge( in: managedObjectContext, context: Persistence.Status.PersistContext( domain: domain, diff --git a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Timeline.swift b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Timeline.swift index c1857ae82..a569f7a66 100644 --- a/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Timeline.swift +++ b/MastodonSDK/Sources/MastodonSDK/API/Mastodon+API+Timeline.swift @@ -33,16 +33,18 @@ extension Mastodon.API.Timeline { /// - session: `URLSession` /// - domain: Mastodon instance domain. e.g. "example.com" /// - query: `PublicTimelineQuery` with query parameters + /// - authorization: required if the instance has disabled public preview /// - Returns: `AnyPublisher` contains `Token` nested in the response public static func `public`( session: URLSession, domain: String, - query: PublicTimelineQuery + query: PublicTimelineQuery, + authorization: Mastodon.API.OAuth.Authorization? ) -> AnyPublisher, Error> { let request = Mastodon.API.get( url: publicTimelineEndpointURL(domain: domain), query: query, - authorization: nil + authorization: authorization ) return session.dataTaskPublisher(for: request) .tryMap { data, response in From 285618d08197705b1765e69ae0600fee343c38ae Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 29 Apr 2022 13:54:20 +0800 Subject: [PATCH 044/101] fix: CI build issue --- .../Sources/MastodonUI/Service/ThemeService/ThemeService.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/MastodonSDK/Sources/MastodonUI/Service/ThemeService/ThemeService.swift b/MastodonSDK/Sources/MastodonUI/Service/ThemeService/ThemeService.swift index b782c4138..394a5f896 100644 --- a/MastodonSDK/Sources/MastodonUI/Service/ThemeService/ThemeService.swift +++ b/MastodonSDK/Sources/MastodonUI/Service/ThemeService/ThemeService.swift @@ -7,7 +7,6 @@ import UIKit import Combine -import AppShared import MastodonCommon // ref: https://zamzam.io/protocol-oriented-themes-for-ios-apps/ From 60a69cff20ead000b5bf57c479e5e5da101b3364 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 29 Apr 2022 14:38:18 +0800 Subject: [PATCH 045/101] chore: rearrange package dependency to fix CI build issue --- AppShared/AppSecret.swift | 5 +- Mastodon.xcodeproj/project.pbxproj | 326 ++++++------------ .../xcschemes/Mastodon - Release.xcscheme | 2 +- .../xcschemes/Mastodon - Snapshot.xcscheme | 2 +- .../xcshareddata/xcschemes/Mastodon.xcscheme | 2 +- .../xcschemes/xcschememanagement.plist | 8 +- MastodonSDK/Package.swift | 17 +- .../Extension}/UserDefaults.swift | 8 +- Podfile | 15 - Podfile.lock | 2 +- 10 files changed, 127 insertions(+), 260 deletions(-) rename {AppShared => MastodonSDK/Sources/MastodonCommon/Extension}/UserDefaults.swift (58%) diff --git a/AppShared/AppSecret.swift b/AppShared/AppSecret.swift index 1fc5495c7..9110f2490 100644 --- a/AppShared/AppSecret.swift +++ b/AppShared/AppSecret.swift @@ -10,10 +10,7 @@ import Foundation import CryptoKit import KeychainAccess import Keys - -enum AppName { - public static let groupID = "group.org.joinmastodon.app" -} +import MastodonCommon public final class AppSecret { diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 833ea24de..2795f6148 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -86,7 +86,6 @@ 2DE0FACE2615F7AD00CDF649 /* RecommendAccountSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DE0FACD2615F7AD00CDF649 /* RecommendAccountSection.swift */; }; 2DF123A725C3B0210020F248 /* ActiveLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DF123A625C3B0210020F248 /* ActiveLabel.swift */; }; 2DF75BA725D10E1000694EC8 /* APIService+Favorite.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DF75BA625D10E1000694EC8 /* APIService+Favorite.swift */; }; - 4278334D6033AEEE0A1C5155 /* Pods_ShareActionExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A32B0CACBF35F4CC3CFAA043 /* Pods_ShareActionExtension.framework */; }; 5B24BBDA262DB14800A9381B /* ReportViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B24BBD7262DB14800A9381B /* ReportViewModel.swift */; }; 5B24BBDB262DB14800A9381B /* ReportViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B24BBD8262DB14800A9381B /* ReportViewModel+Diffable.swift */; }; 5B24BBE2262DB19100A9381B /* APIService+Report.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B24BBE1262DB19100A9381B /* APIService+Report.swift */; }; @@ -101,7 +100,6 @@ 5BB04FF5262F0E6D0043BFF6 /* ReportSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BB04FF4262F0E6D0043BFF6 /* ReportSection.swift */; }; 5D0393902612D259007FE196 /* WebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D03938F2612D259007FE196 /* WebViewController.swift */; }; 5D0393962612D266007FE196 /* WebViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D0393952612D266007FE196 /* WebViewModel.swift */; }; - 5D526FE225BE9AC400460CB9 /* MastodonSDK in Frameworks */ = {isa = PBXBuildFile; productRef = 5D526FE125BE9AC400460CB9 /* MastodonSDK */; }; 5DA732CC2629CEF500A92342 /* UIView+Remove.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DA732CB2629CEF500A92342 /* UIView+Remove.swift */; }; 5DDDF1932617442700311060 /* Mastodon+Entity+Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DDDF1922617442700311060 /* Mastodon+Entity+Account.swift */; }; 5DDDF1992617447F00311060 /* Mastodon+Entity+Tag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DDDF1982617447F00311060 /* Mastodon+Entity+Tag.swift */; }; @@ -110,13 +108,9 @@ 5E0DEC05797A7E6933788DDB /* Pods_MastodonTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 452147B2903DF38070FE56A2 /* Pods_MastodonTests.framework */; }; 5E44BF88AD33646E64727BCF /* Pods_MastodonTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD92E0F10BDE4FE7C4B999F2 /* Pods_MastodonTests.framework */; }; 87FFDA5D898A5C42ADCB35E7 /* Pods_Mastodon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A4ABE34829701A4496C5BB64 /* Pods_Mastodon.framework */; }; - B914FC6B0B8AF18573C0B291 /* Pods_NotificationService.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 374AA339A20E0FAC75BCDA6D /* Pods_NotificationService.framework */; }; - BBAC710E327AF1EE1DB36A4E /* Pods_MastodonIntent.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F4C94BD75C96D0EFF5F6D961 /* Pods_MastodonIntent.framework */; }; DB0009A626AEE5DC009B9D2D /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = DB0009A926AEE5DC009B9D2D /* Intents.intentdefinition */; settings = {ATTRIBUTES = (no_codegen, ); }; }; DB0009A726AEE5DC009B9D2D /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = DB0009A926AEE5DC009B9D2D /* Intents.intentdefinition */; }; - DB00CA972632DDB600A54956 /* CommonOSLog in Frameworks */ = {isa = PBXBuildFile; productRef = DB00CA962632DDB600A54956 /* CommonOSLog */; }; DB0140CF25C42AEE00F9F3CF /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0140CE25C42AEE00F9F3CF /* OSLog.swift */; }; - DB01E23526A98F0900C3965B /* MetaTextKit in Frameworks */ = {isa = PBXBuildFile; productRef = DB01E23426A98F0900C3965B /* MetaTextKit */; }; DB023D26279FFB0A005AC798 /* ShareActivityProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB023D25279FFB0A005AC798 /* ShareActivityProvider.swift */; }; DB023D2827A0FABD005AC798 /* NotificationTableViewCellDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB023D2727A0FABD005AC798 /* NotificationTableViewCellDelegate.swift */; }; DB023D2A27A0FE5C005AC798 /* DataSourceProvider+NotificationTableViewCellDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB023D2927A0FE5C005AC798 /* DataSourceProvider+NotificationTableViewCellDelegate.swift */; }; @@ -129,7 +123,6 @@ DB02CDAB26256A9500D0A2AF /* ThreadReplyLoaderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB02CDAA26256A9500D0A2AF /* ThreadReplyLoaderTableViewCell.swift */; }; DB02CDBF2625AE5000D0A2AF /* AdaptiveUserInterfaceStyleBarButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB02CDBE2625AE5000D0A2AF /* AdaptiveUserInterfaceStyleBarButtonItem.swift */; }; DB02EA0B280D180D00E751C5 /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = DB02EA0A280D180D00E751C5 /* KeychainAccess */; }; - DB02EA0D280D184B00E751C5 /* CommonOSLog in Frameworks */ = {isa = PBXBuildFile; productRef = DB02EA0C280D184B00E751C5 /* CommonOSLog */; }; DB03A793272A7E5700EE37C5 /* SidebarListHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB03A792272A7E5700EE37C5 /* SidebarListHeaderView.swift */; }; DB03A795272A981400EE37C5 /* ContentSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB03A794272A981400EE37C5 /* ContentSplitViewController.swift */; }; DB03F7F32689AEA3007B274C /* ComposeRepliedToStatusContentTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB03F7F22689AEA3007B274C /* ComposeRepliedToStatusContentTableViewCell.swift */; }; @@ -148,7 +141,6 @@ DB084B5725CBC56C00F898ED /* Status.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB084B5625CBC56C00F898ED /* Status.swift */; }; DB0A322E280EE9FD001729D2 /* DiscoveryIntroBannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0A322D280EE9FD001729D2 /* DiscoveryIntroBannerView.swift */; }; DB0AC6FC25CD02E600D75117 /* APIService+Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0AC6FB25CD02E600D75117 /* APIService+Instance.swift */; }; - DB0C946526A6FD4D0088FB11 /* AlamofireImage in Frameworks */ = {isa = PBXBuildFile; productRef = DB0C946426A6FD4D0088FB11 /* AlamofireImage */; }; DB0C947726A7FE840088FB11 /* NotificationAvatarButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0C947626A7FE840088FB11 /* NotificationAvatarButton.swift */; }; DB0EF72B26FDB1D200347686 /* SidebarListCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0EF72A26FDB1D200347686 /* SidebarListCollectionViewCell.swift */; }; DB0EF72E26FDB24F00347686 /* SidebarListContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0EF72D26FDB24F00347686 /* SidebarListContentView.swift */; }; @@ -180,7 +172,6 @@ DB0FCB9C27980AB6006C02E2 /* HashtagTimelineViewController+DataSourceProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0FCB9B27980AB6006C02E2 /* HashtagTimelineViewController+DataSourceProvider.swift */; }; DB118A8225E4B6E600FAB162 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DB118A8125E4B6E600FAB162 /* Preview Assets.xcassets */; }; DB159C2B27A17BAC0068DC77 /* DataSourceFacade+Media.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB159C2A27A17BAC0068DC77 /* DataSourceFacade+Media.swift */; }; - DB179267278D5A4A00B71DEB /* MastodonSDK in Frameworks */ = {isa = PBXBuildFile; productRef = DB179266278D5A4A00B71DEB /* MastodonSDK */; }; DB1D186C25EF5BA7003F1F23 /* PollTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB1D186B25EF5BA7003F1F23 /* PollTableView.swift */; }; DB1D61CF26F1B33600DA8662 /* WelcomeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB1D61CE26F1B33600DA8662 /* WelcomeViewModel.swift */; }; DB1D842E26552C4D000346B3 /* StatusTableViewControllerNavigateable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB1D842D26552C4D000346B3 /* StatusTableViewControllerNavigateable.swift */; }; @@ -219,7 +210,6 @@ DB3667A4268AE2370027D07F /* ComposeStatusPollTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3667A3268AE2370027D07F /* ComposeStatusPollTableViewCell.swift */; }; DB3667A6268AE2620027D07F /* ComposeStatusPollSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3667A5268AE2620027D07F /* ComposeStatusPollSection.swift */; }; DB3667A8268AE2900027D07F /* ComposeStatusPollItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3667A7268AE2900027D07F /* ComposeStatusPollItem.swift */; }; - DB3D0FF325BAA61700EAA174 /* AlamofireImage in Frameworks */ = {isa = PBXBuildFile; productRef = DB3D0FF225BAA61700EAA174 /* AlamofireImage */; }; DB3E6FDD2806A40F00B035AE /* DiscoveryHashtagsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FDC2806A40F00B035AE /* DiscoveryHashtagsViewController.swift */; }; DB3E6FE02806A4ED00B035AE /* DiscoveryHashtagsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FDF2806A4ED00B035AE /* DiscoveryHashtagsViewModel.swift */; }; DB3E6FE22806A50100B035AE /* DiscoveryHashtagsViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3E6FE12806A50100B035AE /* DiscoveryHashtagsViewModel+Diffable.swift */; }; @@ -239,6 +229,20 @@ DB3EA8ED281B810100598866 /* APIService+PublicTimeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3EA8EC281B810100598866 /* APIService+PublicTimeline.swift */; }; DB3EA8EF281B837000598866 /* DiscoveryCommunityViewController+DataSourceProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3EA8EE281B837000598866 /* DiscoveryCommunityViewController+DataSourceProvider.swift */; }; DB3EA8F1281B9EF600598866 /* DiscoveryCommunityViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB3EA8F0281B9EF600598866 /* DiscoveryCommunityViewModel+Diffable.swift */; }; + DB3EA8F5281BB65200598866 /* MastodonSDK in Frameworks */ = {isa = PBXBuildFile; productRef = DB3EA8F4281BB65200598866 /* MastodonSDK */; }; + DB3EA8FC281BBAE100598866 /* AlamofireImage in Frameworks */ = {isa = PBXBuildFile; productRef = DB3EA8FB281BBAE100598866 /* AlamofireImage */; }; + DB3EA8FE281BBAF200598866 /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = DB3EA8FD281BBAF200598866 /* Alamofire */; }; + DB3EA900281BBB1D00598866 /* MetaTextKit in Frameworks */ = {isa = PBXBuildFile; productRef = DB3EA8FF281BBB1D00598866 /* MetaTextKit */; }; + DB3EA902281BBD5D00598866 /* CommonOSLog in Frameworks */ = {isa = PBXBuildFile; productRef = DB3EA901281BBD5D00598866 /* CommonOSLog */; }; + DB3EA904281BBD9400598866 /* Introspect in Frameworks */ = {isa = PBXBuildFile; productRef = DB3EA903281BBD9400598866 /* Introspect */; }; + DB3EA906281BBE8200598866 /* AlamofireImage in Frameworks */ = {isa = PBXBuildFile; productRef = DB3EA905281BBE8200598866 /* AlamofireImage */; }; + DB3EA908281BBE8200598866 /* AlamofireNetworkActivityIndicator in Frameworks */ = {isa = PBXBuildFile; productRef = DB3EA907281BBE8200598866 /* AlamofireNetworkActivityIndicator */; }; + DB3EA90A281BBE8200598866 /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = DB3EA909281BBE8200598866 /* Alamofire */; }; + DB3EA90C281BBE9600598866 /* AlamofireImage in Frameworks */ = {isa = PBXBuildFile; productRef = DB3EA90B281BBE9600598866 /* AlamofireImage */; }; + DB3EA90E281BBE9600598866 /* AlamofireNetworkActivityIndicator in Frameworks */ = {isa = PBXBuildFile; productRef = DB3EA90D281BBE9600598866 /* AlamofireNetworkActivityIndicator */; }; + DB3EA910281BBE9600598866 /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = DB3EA90F281BBE9600598866 /* Alamofire */; }; + DB3EA912281BBEA800598866 /* AlamofireImage in Frameworks */ = {isa = PBXBuildFile; productRef = DB3EA911281BBEA800598866 /* AlamofireImage */; }; + DB3EA914281BBEA800598866 /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = DB3EA913281BBEA800598866 /* Alamofire */; }; DB427DD625BAA00100D1B89D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB427DD525BAA00100D1B89D /* AppDelegate.swift */; }; DB427DD825BAA00100D1B89D /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB427DD725BAA00100D1B89D /* SceneDelegate.swift */; }; DB427DDD25BAA00100D1B89D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DB427DDB25BAA00100D1B89D /* Main.storyboard */; }; @@ -350,7 +354,6 @@ DB6804832637CD4C00430867 /* AppShared.h in Headers */ = {isa = PBXBuildFile; fileRef = DB6804812637CD4C00430867 /* AppShared.h */; settings = {ATTRIBUTES = (Public, ); }; }; DB6804862637CD4C00430867 /* AppShared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB68047F2637CD4C00430867 /* AppShared.framework */; }; DB6804872637CD4C00430867 /* AppShared.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = DB68047F2637CD4C00430867 /* AppShared.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - DB6804D12637CE4700430867 /* UserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6804D02637CE4700430867 /* UserDefaults.swift */; }; DB6804FD2637CFEC00430867 /* AppSecret.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6804FC2637CFEC00430867 /* AppSecret.swift */; }; DB68586425E619B700F0A850 /* NSKeyValueObservation.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB68586325E619B700F0A850 /* NSKeyValueObservation.swift */; }; DB68A04A25E9027700CFDF14 /* AdaptiveStatusBarStyleNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB68A04925E9027700CFDF14 /* AdaptiveStatusBarStyleNavigationController.swift */; }; @@ -378,7 +381,6 @@ DB6C8C0F25F0A6AE00AAA452 /* Mastodon+Entity+Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6C8C0E25F0A6AE00AAA452 /* Mastodon+Entity+Error.swift */; }; DB6D1B44263691CF00ACB481 /* Mastodon+API+Subscriptions+Policy.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6D1B43263691CF00ACB481 /* Mastodon+API+Subscriptions+Policy.swift */; }; DB6D9F3526351B7A008423CD /* NotificationService+Decrypt.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6D9F3426351B7A008423CD /* NotificationService+Decrypt.swift */; }; - DB6D9F42263527CE008423CD /* AlamofireImage in Frameworks */ = {isa = PBXBuildFile; productRef = DB6D9F41263527CE008423CD /* AlamofireImage */; }; DB6D9F4926353FD7008423CD /* Subscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6D9F4826353FD6008423CD /* Subscription.swift */; }; DB6D9F502635761F008423CD /* SubscriptionAlerts.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6D9F4F2635761F008423CD /* SubscriptionAlerts.swift */; }; DB6D9F57263577D2008423CD /* APIService+CoreData+Setting.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6D9F56263577D2008423CD /* APIService+CoreData+Setting.swift */; }; @@ -421,7 +423,6 @@ DB8AF54525C13647002E6C99 /* NeedsDependency.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB8AF54325C13647002E6C99 /* NeedsDependency.swift */; }; DB8AF55025C13703002E6C99 /* MainTabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB8AF54F25C13703002E6C99 /* MainTabBarController.swift */; }; DB8AF55D25C138B7002E6C99 /* UIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB8AF55C25C138B7002E6C99 /* UIViewController.swift */; }; - DB8D8E2F28192EED009FD90F /* Introspect in Frameworks */ = {isa = PBXBuildFile; productRef = DB8D8E2E28192EED009FD90F /* Introspect */; }; DB8F7076279E954700E1225B /* DataSourceFacade+Follow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB8F7075279E954700E1225B /* DataSourceFacade+Follow.swift */; }; DB8FABC726AEC7B2008E5AF4 /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB8FAB9E26AEC3A2008E5AF4 /* Intents.framework */; }; DB8FABCA26AEC7B2008E5AF4 /* IntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB8FABC926AEC7B2008E5AF4 /* IntentHandler.swift */; }; @@ -454,7 +455,6 @@ DB98EB6927B21A7C0082E365 /* ReportResultActionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98EB6827B21A7C0082E365 /* ReportResultActionTableViewCell.swift */; }; DB98EB6B27B243470082E365 /* SettingsAppearanceTableViewCell+ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98EB6A27B243470082E365 /* SettingsAppearanceTableViewCell+ViewModel.swift */; }; DB9A486C26032AC1008B817C /* AttachmentContainerView+EmptyStateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9A486B26032AC1008B817C /* AttachmentContainerView+EmptyStateView.swift */; }; - DB9A487E2603456B008B817C /* UITextView+Placeholder in Frameworks */ = {isa = PBXBuildFile; productRef = DB9A487D2603456B008B817C /* UITextView+Placeholder */; }; DB9A488A26034D40008B817C /* ComposeViewModel+PublishState.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9A488926034D40008B817C /* ComposeViewModel+PublishState.swift */; }; DB9A489026035963008B817C /* APIService+Media.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9A488F26035963008B817C /* APIService+Media.swift */; }; DB9A48962603685D008B817C /* MastodonAttachmentService+UploadState.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9A48952603685D008B817C /* MastodonAttachmentService+UploadState.swift */; }; @@ -509,18 +509,14 @@ DBB5255E2611F07A002F1F29 /* ProfileViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB5255D2611F07A002F1F29 /* ProfileViewModel.swift */; }; DBB525642612C988002F1F29 /* MeProfileViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB525632612C988002F1F29 /* MeProfileViewModel.swift */; }; DBB8AB4626AECDE200F6D281 /* SendPostIntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB8AB4526AECDE200F6D281 /* SendPostIntentHandler.swift */; }; - DBB8AB4826AED09C00F6D281 /* MastodonSDK in Frameworks */ = {isa = PBXBuildFile; productRef = DBB8AB4726AED09C00F6D281 /* MastodonSDK */; }; DBB8AB4A26AED0B500F6D281 /* APIService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB8AB4926AED0B500F6D281 /* APIService.swift */; }; DBB8AB4C26AED11300F6D281 /* APIService+APIError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98337E25C9452D00AD9700 /* APIService+APIError.swift */; }; DBB8AB4F26AED13F00F6D281 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DB427DDE25BAA00100D1B89D /* Assets.xcassets */; }; DBB8AB5226AED1B300F6D281 /* APIService+Status+Publish.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBFEF07A26A6BCE8006D7ED1 /* APIService+Status+Publish.swift */; }; DBB9759C262462E1004620BD /* ThreadMetaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBB9759B262462E1004620BD /* ThreadMetaView.swift */; }; DBBC24A826A52F9000398BB9 /* ComposeToolbarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24A726A52F9000398BB9 /* ComposeToolbarView.swift */; }; - DBBC24AA26A5301B00398BB9 /* MastodonSDK in Frameworks */ = {isa = PBXBuildFile; productRef = DBBC24A926A5301B00398BB9 /* MastodonSDK */; }; DBBC24AC26A53D9300398BB9 /* ComposeStatusContentTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24AB26A53D9300398BB9 /* ComposeStatusContentTableViewCell.swift */; }; - DBBC24B826A5421800398BB9 /* CommonOSLog in Frameworks */ = {isa = PBXBuildFile; productRef = DBBC24B726A5421800398BB9 /* CommonOSLog */; }; DBBC24CB26A546C000398BB9 /* ThemePreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBD376AB2692ECDB007FEC24 /* ThemePreference.swift */; }; - DBBC24D126A5484F00398BB9 /* UITextView+Placeholder in Frameworks */ = {isa = PBXBuildFile; productRef = DBBC24D026A5484F00398BB9 /* UITextView+Placeholder */; }; DBBC24DC26A54BCB00398BB9 /* MastodonRegex.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBC24D626A54BCB00398BB9 /* MastodonRegex.swift */; }; DBBE1B4525F3474B0081417A /* MastodonPickServerAppearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBE1B4425F3474B0081417A /* MastodonPickServerAppearance.swift */; }; DBBF1DBF2652401B00E5B703 /* AutoCompleteViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBBF1DBE2652401B00E5B703 /* AutoCompleteViewModel.swift */; }; @@ -725,10 +721,8 @@ 0FB3D30E25E525CD00AAD544 /* PickServerCategoryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PickServerCategoryView.swift; sourceTree = ""; }; 0FB3D31D25E534C700AAD544 /* PickServerCategoryCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PickServerCategoryCollectionViewCell.swift; sourceTree = ""; }; 0FB3D33725E6401400AAD544 /* PickServerCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PickServerCell.swift; sourceTree = ""; }; - 159AC43EFE0A1F95FCB358A4 /* Pods-MastodonIntent.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonIntent.release.xcconfig"; path = "Target Support Files/Pods-MastodonIntent/Pods-MastodonIntent.release.xcconfig"; sourceTree = ""; }; 164F0EBB267D4FE400249499 /* BoopSound.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = BoopSound.caf; sourceTree = ""; }; 1D6D967E77A5357E2C6110D9 /* Pods-Mastodon.asdk - debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon.asdk - debug.xcconfig"; path = "Target Support Files/Pods-Mastodon/Pods-Mastodon.asdk - debug.xcconfig"; sourceTree = ""; }; - 2C12EB4B3699D5D597027962 /* Pods-MastodonIntent.release snapshot.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonIntent.release snapshot.xcconfig"; path = "Target Support Files/Pods-MastodonIntent/Pods-MastodonIntent.release snapshot.xcconfig"; sourceTree = ""; }; 2D198642261BF09500F0B013 /* SearchResultItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultItem.swift; sourceTree = ""; }; 2D198648261C0B8500F0B013 /* SearchResultSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultSection.swift; sourceTree = ""; }; 2D206B8525F5FB0900143C56 /* Double.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Double.swift; sourceTree = ""; }; @@ -789,7 +783,6 @@ 2DF123A625C3B0210020F248 /* ActiveLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActiveLabel.swift; sourceTree = ""; }; 2DF75BA625D10E1000694EC8 /* APIService+Favorite.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Favorite.swift"; sourceTree = ""; }; 2E1F6A67FDF9771D3E064FDC /* Pods-Mastodon.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon.debug.xcconfig"; path = "Target Support Files/Pods-Mastodon/Pods-Mastodon.debug.xcconfig"; sourceTree = ""; }; - 374AA339A20E0FAC75BCDA6D /* Pods_NotificationService.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_NotificationService.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 3B7FD8F28DDA8FBCE5562B78 /* Pods-NotificationService.asdk - debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.asdk - debug.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.asdk - debug.xcconfig"; sourceTree = ""; }; 3C030226D3C73DCC23D67452 /* Pods_Mastodon_MastodonUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Mastodon_MastodonUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 3E08A432F40BA7B9CAA9DB68 /* Pods-AppShared.release snapshot.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppShared.release snapshot.xcconfig"; path = "Target Support Files/Pods-AppShared/Pods-AppShared.release snapshot.xcconfig"; sourceTree = ""; }; @@ -819,21 +812,14 @@ 5DF1056325F887CB00D6C0D4 /* AVPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AVPlayer.swift; sourceTree = ""; }; 6130CBE4B26E3C976ACC1688 /* Pods-ShareActionExtension.asdk - debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShareActionExtension.asdk - debug.xcconfig"; path = "Target Support Files/Pods-ShareActionExtension/Pods-ShareActionExtension.asdk - debug.xcconfig"; sourceTree = ""; }; 75E3471C898DDD9631729B6E /* Pods-Mastodon.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon.release.xcconfig"; path = "Target Support Files/Pods-Mastodon/Pods-Mastodon.release.xcconfig"; sourceTree = ""; }; - 77EE917BC055E6621C0452B6 /* Pods-ShareActionExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShareActionExtension.debug.xcconfig"; path = "Target Support Files/Pods-ShareActionExtension/Pods-ShareActionExtension.debug.xcconfig"; sourceTree = ""; }; 7CEFFAE9AF9284B13C0A758D /* Pods-MastodonTests.asdk - debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonTests.asdk - debug.xcconfig"; path = "Target Support Files/Pods-MastodonTests/Pods-MastodonTests.asdk - debug.xcconfig"; sourceTree = ""; }; 819CEC9DCAD8E8E7BD85A7BB /* Pods-Mastodon.asdk.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon.asdk.xcconfig"; path = "Target Support Files/Pods-Mastodon/Pods-Mastodon.asdk.xcconfig"; sourceTree = ""; }; - 861BE60ED27430771CFD578D /* Pods-MastodonIntent.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonIntent.debug.xcconfig"; path = "Target Support Files/Pods-MastodonIntent/Pods-MastodonIntent.debug.xcconfig"; sourceTree = ""; }; 8850E70A1D5FF51432E43653 /* Pods-Mastodon-MastodonUITests.asdk - release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-MastodonUITests.asdk - release.xcconfig"; path = "Target Support Files/Pods-Mastodon-MastodonUITests/Pods-Mastodon-MastodonUITests.asdk - release.xcconfig"; sourceTree = ""; }; - 8ADD558BE5B8255E5764A54F /* Pods-NotificationService.release snapshot.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.release snapshot.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.release snapshot.xcconfig"; sourceTree = ""; }; 8E79CCBE51FBC3F7FE8CF49F /* Pods-MastodonTests.release snapshot.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonTests.release snapshot.xcconfig"; path = "Target Support Files/Pods-MastodonTests/Pods-MastodonTests.release snapshot.xcconfig"; sourceTree = ""; }; 8ED8C4B1F1BA2DCFF2926BB1 /* Pods-Mastodon-NotificationService.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-NotificationService.debug.xcconfig"; path = "Target Support Files/Pods-Mastodon-NotificationService/Pods-Mastodon-NotificationService.debug.xcconfig"; sourceTree = ""; }; - 9553C689FFA9EBC880CAB78D /* Pods-NotificationService.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.debug.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.debug.xcconfig"; sourceTree = ""; }; - 95AD0663479892A2109EEFD0 /* Pods-ShareActionExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShareActionExtension.release.xcconfig"; path = "Target Support Files/Pods-ShareActionExtension/Pods-ShareActionExtension.release.xcconfig"; sourceTree = ""; }; - 9776D7C4B79101CF70181127 /* Pods-NotificationService.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.release.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.release.xcconfig"; sourceTree = ""; }; 9780A4C98FFC65B32B50D1C0 /* Pods-MastodonTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonTests.release.xcconfig"; path = "Target Support Files/Pods-MastodonTests/Pods-MastodonTests.release.xcconfig"; sourceTree = ""; }; 9A0982D8F349244EB558CDFD /* Pods-AppShared.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppShared.debug.xcconfig"; path = "Target Support Files/Pods-AppShared/Pods-AppShared.debug.xcconfig"; sourceTree = ""; }; 9CFF58FD900AC059428700E7 /* Pods-NotificationService.asdk - release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.asdk - release.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.asdk - release.xcconfig"; sourceTree = ""; }; - A32B0CACBF35F4CC3CFAA043 /* Pods_ShareActionExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ShareActionExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; }; A4ABE34829701A4496C5BB64 /* Pods_Mastodon.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Mastodon.framework; sourceTree = BUILT_PRODUCTS_DIR; }; A67FD038ECDA0E411AF8DB4D /* Pods-Mastodon-MastodonUITests.asdk.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-MastodonUITests.asdk.xcconfig"; path = "Target Support Files/Pods-Mastodon-MastodonUITests/Pods-Mastodon-MastodonUITests.asdk.xcconfig"; sourceTree = ""; }; A9B1FB898DFD6063B044298C /* Pods-AppShared.asdk - debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppShared.asdk - debug.xcconfig"; path = "Target Support Files/Pods-AppShared/Pods-AppShared.asdk - debug.xcconfig"; sourceTree = ""; }; @@ -1103,7 +1089,6 @@ DB68047F2637CD4C00430867 /* AppShared.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AppShared.framework; sourceTree = BUILT_PRODUCTS_DIR; }; DB6804812637CD4C00430867 /* AppShared.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppShared.h; sourceTree = ""; }; DB6804822637CD4C00430867 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - DB6804D02637CE4700430867 /* UserDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaults.swift; sourceTree = ""; }; DB6804FC2637CFEC00430867 /* AppSecret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSecret.swift; sourceTree = ""; }; DB68053E2638011000430867 /* NotificationService.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NotificationService.entitlements; sourceTree = ""; }; DB68586325E619B700F0A850 /* NSKeyValueObservation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSKeyValueObservation.swift; sourceTree = ""; }; @@ -1378,9 +1363,7 @@ ECA373ABA86BE3C2D7ED878E /* Pods-AppShared.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppShared.release.xcconfig"; path = "Target Support Files/Pods-AppShared/Pods-AppShared.release.xcconfig"; sourceTree = ""; }; EE13214BC0246BE5210CCC10 /* Pods-AppShared.asdk.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppShared.asdk.xcconfig"; path = "Target Support Files/Pods-AppShared/Pods-AppShared.asdk.xcconfig"; sourceTree = ""; }; F31E7502A7E3945B98C6CBAF /* Pods-NotificationService.asdk.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.asdk.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.asdk.xcconfig"; sourceTree = ""; }; - F43DF6E8AB8C87914A64FC48 /* Pods-ShareActionExtension.release snapshot.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShareActionExtension.release snapshot.xcconfig"; path = "Target Support Files/Pods-ShareActionExtension/Pods-ShareActionExtension.release snapshot.xcconfig"; sourceTree = ""; }; F4A2A2D7000E477CA459ADA9 /* Pods_AppShared.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_AppShared.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - F4C94BD75C96D0EFF5F6D961 /* Pods_MastodonIntent.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MastodonIntent.framework; sourceTree = BUILT_PRODUCTS_DIR; }; F920AD4EC23B0D00F5CCA58E /* Pods-MastodonIntent.asdk - release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonIntent.asdk - release.xcconfig"; path = "Target Support Files/Pods-MastodonIntent/Pods-MastodonIntent.asdk - release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -1389,25 +1372,21 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - DB9A487E2603456B008B817C /* UITextView+Placeholder in Frameworks */, + DB3EA914281BBEA800598866 /* Alamofire in Frameworks */, 2D939AC825EE14620076FA61 /* CropViewController in Frameworks */, DBB525082611EAC0002F1F29 /* Tabman in Frameworks */, - 5D526FE225BE9AC400460CB9 /* MastodonSDK in Frameworks */, DB6804862637CD4C00430867 /* AppShared.framework in Frameworks */, DBF96326262EC0A6001D8D25 /* AuthenticationServices.framework in Frameworks */, - DB8D8E2F28192EED009FD90F /* Introspect in Frameworks */, DBAC6483267D0B21007FE9FD /* DifferenceKit in Frameworks */, DB552D4F26BBD10C00E481F6 /* OrderedCollections in Frameworks */, 2D61336925C18A4F00CAE157 /* AlamofireNetworkActivityIndicator in Frameworks */, DBAC64A1267E6D02007FE9FD /* Fuzi in Frameworks */, - DB3D0FF325BAA61700EAA174 /* AlamofireImage in Frameworks */, DBAC649E267DFE43007FE9FD /* DiffableDataSources in Frameworks */, - DB02EA0D280D184B00E751C5 /* CommonOSLog in Frameworks */, 2D5981BA25E4D7F8000FB903 /* ThirdPartyMailer in Frameworks */, 87FFDA5D898A5C42ADCB35E7 /* Pods_Mastodon.framework in Frameworks */, DBF7A0FC26830C33004176A2 /* FPSIndicator in Frameworks */, - DB01E23526A98F0900C3965B /* MetaTextKit in Frameworks */, DBA5A52F26F07ED800CACBAA /* PanModal in Frameworks */, + DB3EA912281BBEA800598866 /* AlamofireImage in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1432,8 +1411,14 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + DB3EA8FE281BBAF200598866 /* Alamofire in Frameworks */, + DB3EA8F5281BB65200598866 /* MastodonSDK in Frameworks */, + DB3EA8FC281BBAE100598866 /* AlamofireImage in Frameworks */, DB02EA0B280D180D00E751C5 /* KeychainAccess in Frameworks */, EE93E8E8F9E0C39EAAEBD92F /* Pods_AppShared.framework in Frameworks */, + DB3EA904281BBD9400598866 /* Introspect in Frameworks */, + DB3EA902281BBD5D00598866 /* CommonOSLog in Frameworks */, + DB3EA900281BBB1D00598866 /* MetaTextKit in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1442,8 +1427,6 @@ buildActionMask = 2147483647; files = ( DB8FABC726AEC7B2008E5AF4 /* Intents.framework in Frameworks */, - DBB8AB4826AED09C00F6D281 /* MastodonSDK in Frameworks */, - BBAC710E327AF1EE1DB36A4E /* Pods_MastodonIntent.framework in Frameworks */, DBE3CA6E27A39CB300AFE27B /* AppShared.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1452,12 +1435,10 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - DBBC24B826A5421800398BB9 /* CommonOSLog in Frameworks */, - DBBC24D126A5484F00398BB9 /* UITextView+Placeholder in Frameworks */, - DBBC24AA26A5301B00398BB9 /* MastodonSDK in Frameworks */, + DB3EA90E281BBE9600598866 /* AlamofireNetworkActivityIndicator in Frameworks */, + DB3EA910281BBE9600598866 /* Alamofire in Frameworks */, DBE3CA6B27A39CAF00AFE27B /* AppShared.framework in Frameworks */, - DB0C946526A6FD4D0088FB11 /* AlamofireImage in Frameworks */, - 4278334D6033AEEE0A1C5155 /* Pods_ShareActionExtension.framework in Frameworks */, + DB3EA90C281BBE9600598866 /* AlamofireImage in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1465,11 +1446,10 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - DB00CA972632DDB600A54956 /* CommonOSLog in Frameworks */, - DB179267278D5A4A00B71DEB /* MastodonSDK in Frameworks */, - DB6D9F42263527CE008423CD /* AlamofireImage in Frameworks */, + DB3EA908281BBE8200598866 /* AlamofireNetworkActivityIndicator in Frameworks */, + DB3EA90A281BBE8200598866 /* Alamofire in Frameworks */, DBE3CA6827A39CAB00AFE27B /* AppShared.framework in Frameworks */, - B914FC6B0B8AF18573C0B291 /* Pods_NotificationService.framework in Frameworks */, + DB3EA906281BBE8200598866 /* AlamofireImage in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1555,8 +1535,6 @@ B31D44635FCF6452F7E1B865 /* Pods-Mastodon-AppShared.release.xcconfig */, 9A0982D8F349244EB558CDFD /* Pods-AppShared.debug.xcconfig */, ECA373ABA86BE3C2D7ED878E /* Pods-AppShared.release.xcconfig */, - 9553C689FFA9EBC880CAB78D /* Pods-NotificationService.debug.xcconfig */, - 9776D7C4B79101CF70181127 /* Pods-NotificationService.release.xcconfig */, EE13214BC0246BE5210CCC10 /* Pods-AppShared.asdk.xcconfig */, 819CEC9DCAD8E8E7BD85A7BB /* Pods-Mastodon.asdk.xcconfig */, A67FD038ECDA0E411AF8DB4D /* Pods-Mastodon-MastodonUITests.asdk.xcconfig */, @@ -1572,21 +1550,14 @@ 46DAB0EBDDFB678347CD96FF /* Pods-MastodonTests.asdk - release.xcconfig */, 3B7FD8F28DDA8FBCE5562B78 /* Pods-NotificationService.asdk - debug.xcconfig */, 9CFF58FD900AC059428700E7 /* Pods-NotificationService.asdk - release.xcconfig */, - 77EE917BC055E6621C0452B6 /* Pods-ShareActionExtension.debug.xcconfig */, 6130CBE4B26E3C976ACC1688 /* Pods-ShareActionExtension.asdk - debug.xcconfig */, 5CE45680252519F42FEA2D13 /* Pods-ShareActionExtension.asdk - release.xcconfig */, - 95AD0663479892A2109EEFD0 /* Pods-ShareActionExtension.release.xcconfig */, - 861BE60ED27430771CFD578D /* Pods-MastodonIntent.debug.xcconfig */, C3789232A52F43529CA67E95 /* Pods-MastodonIntent.asdk - debug.xcconfig */, F920AD4EC23B0D00F5CCA58E /* Pods-MastodonIntent.asdk - release.xcconfig */, - 159AC43EFE0A1F95FCB358A4 /* Pods-MastodonIntent.release.xcconfig */, 3E08A432F40BA7B9CAA9DB68 /* Pods-AppShared.release snapshot.xcconfig */, 0655B257371274BEB7EB1C19 /* Pods-Mastodon.release snapshot.xcconfig */, 0827D1674B2523503E8605F6 /* Pods-Mastodon-MastodonUITests.release snapshot.xcconfig */, - 2C12EB4B3699D5D597027962 /* Pods-MastodonIntent.release snapshot.xcconfig */, 8E79CCBE51FBC3F7FE8CF49F /* Pods-MastodonTests.release snapshot.xcconfig */, - 8ADD558BE5B8255E5764A54F /* Pods-NotificationService.release snapshot.xcconfig */, - F43DF6E8AB8C87914A64FC48 /* Pods-ShareActionExtension.release snapshot.xcconfig */, ); path = Pods; sourceTree = ""; @@ -1848,11 +1819,8 @@ 3C030226D3C73DCC23D67452 /* Pods_Mastodon_MastodonUITests.framework */, 452147B2903DF38070FE56A2 /* Pods_MastodonTests.framework */, F4A2A2D7000E477CA459ADA9 /* Pods_AppShared.framework */, - 374AA339A20E0FAC75BCDA6D /* Pods_NotificationService.framework */, - A32B0CACBF35F4CC3CFAA043 /* Pods_ShareActionExtension.framework */, DB8FAB9E26AEC3A2008E5AF4 /* Intents.framework */, DB8FABA926AEC3A2008E5AF4 /* IntentsUI.framework */, - F4C94BD75C96D0EFF5F6D961 /* Pods_MastodonIntent.framework */, ); name = Frameworks; sourceTree = ""; @@ -2564,7 +2532,6 @@ DB6804812637CD4C00430867 /* AppShared.h */, DB6804822637CD4C00430867 /* Info.plist */, DB6804FC2637CFEC00430867 /* AppSecret.swift */, - DB6804D02637CE4700430867 /* UserDefaults.swift */, DB73BF3A2711885500781945 /* UserDefaults+Notification.swift */, ); path = AppShared; @@ -3342,22 +3309,18 @@ ); name = Mastodon; packageProductDependencies = ( - DB3D0FF225BAA61700EAA174 /* AlamofireImage */, - 5D526FE125BE9AC400460CB9 /* MastodonSDK */, 2D61336825C18A4F00CAE157 /* AlamofireNetworkActivityIndicator */, 2D5981B925E4D7F8000FB903 /* ThirdPartyMailer */, 2D939AC725EE14620076FA61 /* CropViewController */, - DB9A487D2603456B008B817C /* UITextView+Placeholder */, DBB525072611EAC0002F1F29 /* Tabman */, DBAC6482267D0B21007FE9FD /* DifferenceKit */, DBAC649D267DFE43007FE9FD /* DiffableDataSources */, DBAC64A0267E6D02007FE9FD /* Fuzi */, DBF7A0FB26830C33004176A2 /* FPSIndicator */, - DB01E23426A98F0900C3965B /* MetaTextKit */, DB552D4E26BBD10C00E481F6 /* OrderedCollections */, DBA5A52E26F07ED800CACBAA /* PanModal */, - DB02EA0C280D184B00E751C5 /* CommonOSLog */, - DB8D8E2E28192EED009FD90F /* Introspect */, + DB3EA911281BBEA800598866 /* AlamofireImage */, + DB3EA913281BBEA800598866 /* Alamofire */, ); productName = Mastodon; productReference = DB427DD225BAA00100D1B89D /* Mastodon.app */; @@ -3419,6 +3382,12 @@ name = AppShared; packageProductDependencies = ( DB02EA0A280D180D00E751C5 /* KeychainAccess */, + DB3EA8F4281BB65200598866 /* MastodonSDK */, + DB3EA8FB281BBAE100598866 /* AlamofireImage */, + DB3EA8FD281BBAF200598866 /* Alamofire */, + DB3EA8FF281BBB1D00598866 /* MetaTextKit */, + DB3EA901281BBD5D00598866 /* CommonOSLog */, + DB3EA903281BBD9400598866 /* Introspect */, ); productName = AppShared; productReference = DB68047F2637CD4C00430867 /* AppShared.framework */; @@ -3428,7 +3397,6 @@ isa = PBXNativeTarget; buildConfigurationList = DB8FABCF26AEC7B2008E5AF4 /* Build configuration list for PBXNativeTarget "MastodonIntent" */; buildPhases = ( - 625308CC94CCF528BD373740 /* [CP] Check Pods Manifest.lock */, DB8FABC226AEC7B2008E5AF4 /* Sources */, DB8FABC326AEC7B2008E5AF4 /* Frameworks */, DB8FABC426AEC7B2008E5AF4 /* Resources */, @@ -3439,9 +3407,6 @@ DB8FABDA26AEC873008E5AF4 /* PBXTargetDependency */, ); name = MastodonIntent; - packageProductDependencies = ( - DBB8AB4726AED09C00F6D281 /* MastodonSDK */, - ); productName = MastodonIntent; productReference = DB8FABC626AEC7B2008E5AF4 /* MastodonIntent.appex */; productType = "com.apple.product-type.app-extension"; @@ -3450,7 +3415,6 @@ isa = PBXNativeTarget; buildConfigurationList = DBC6462126A170AB00B0E31B /* Build configuration list for PBXNativeTarget "ShareActionExtension" */; buildPhases = ( - 641DEA63EE5B048C9A551302 /* [CP] Check Pods Manifest.lock */, DBC6460E26A170AB00B0E31B /* Sources */, DBC6460F26A170AB00B0E31B /* Frameworks */, DBC6461026A170AB00B0E31B /* Resources */, @@ -3462,10 +3426,9 @@ ); name = ShareActionExtension; packageProductDependencies = ( - DBBC24A926A5301B00398BB9 /* MastodonSDK */, - DBBC24B726A5421800398BB9 /* CommonOSLog */, - DBBC24D026A5484F00398BB9 /* UITextView+Placeholder */, - DB0C946426A6FD4D0088FB11 /* AlamofireImage */, + DB3EA90B281BBE9600598866 /* AlamofireImage */, + DB3EA90D281BBE9600598866 /* AlamofireNetworkActivityIndicator */, + DB3EA90F281BBE9600598866 /* Alamofire */, ); productName = ShareActionExtension; productReference = DBC6461226A170AB00B0E31B /* ShareActionExtension.appex */; @@ -3475,7 +3438,6 @@ isa = PBXNativeTarget; buildConfigurationList = DBF8AE1E263293E400C9C23C /* Build configuration list for PBXNativeTarget "NotificationService" */; buildPhases = ( - 0DC740704503CA6BED56F5C8 /* [CP] Check Pods Manifest.lock */, DBF8AE0F263293E400C9C23C /* Sources */, DBF8AE10263293E400C9C23C /* Frameworks */, DBF8AE11263293E400C9C23C /* Resources */, @@ -3487,9 +3449,9 @@ ); name = NotificationService; packageProductDependencies = ( - DB00CA962632DDB600A54956 /* CommonOSLog */, - DB6D9F41263527CE008423CD /* AlamofireImage */, - DB179266278D5A4A00B71DEB /* MastodonSDK */, + DB3EA905281BBE8200598866 /* AlamofireImage */, + DB3EA907281BBE8200598866 /* AlamofireNetworkActivityIndicator */, + DB3EA909281BBE8200598866 /* Alamofire */, ); productName = NotificationService; productReference = DBF8AE13263293E400C9C23C /* NotificationService.appex */; @@ -3564,7 +3526,6 @@ DB0140BB25C40D7500F9F3CF /* XCRemoteSwiftPackageReference "CommonOSLog" */, 2D5981B825E4D7F8000FB903 /* XCRemoteSwiftPackageReference "ThirdPartyMailer" */, 2D939AC625EE14620076FA61 /* XCRemoteSwiftPackageReference "TOCropViewController" */, - DB9A487C2603456B008B817C /* XCRemoteSwiftPackageReference "UITextView-Placeholder" */, DBB525062611EAC0002F1F29 /* XCRemoteSwiftPackageReference "Tabman" */, DB6804722637CC1200430867 /* XCRemoteSwiftPackageReference "KeychainAccess" */, DBAC6481267D0B21007FE9FD /* XCRemoteSwiftPackageReference "DifferenceKit" */, @@ -3576,6 +3537,7 @@ DB552D4D26BBD10C00E481F6 /* XCRemoteSwiftPackageReference "swift-collections" */, DBA5A52D26F07ED800CACBAA /* XCRemoteSwiftPackageReference "PanModal" */, DB8D8E2D28192EED009FD90F /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */, + DB3EA8F6281BBA4C00598866 /* XCRemoteSwiftPackageReference "Alamofire" */, ); productRefGroup = DB427DD325BAA00100D1B89D /* Products */; projectDirPath = ""; @@ -3658,28 +3620,6 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 0DC740704503CA6BED56F5C8 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-NotificationService-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; 5532CB85BBE168B25B20720B /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -3697,50 +3637,6 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Mastodon/Pods-Mastodon-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - 625308CC94CCF528BD373740 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-MastodonIntent-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - 641DEA63EE5B048C9A551302 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-ShareActionExtension-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; 6E033728B42BA1C0018B6131 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -4429,7 +4325,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - DB6804D12637CE4700430867 /* UserDefaults.swift in Sources */, DB73BF3B2711885500781945 /* UserDefaults+Notification.swift in Sources */, DB4932B726F30F0700EF46D4 /* Array.swift in Sources */, DB6804FD2637CFEC00430867 /* AppSecret.swift in Sources */, @@ -4779,6 +4674,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 117; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; @@ -4808,6 +4704,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 117; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; @@ -4973,7 +4870,6 @@ }; DB8FABD026AEC7B2008E5AF4 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 861BE60ED27430771CFD578D /* Pods-MastodonIntent.debug.xcconfig */; buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; @@ -4998,7 +4894,6 @@ }; DB8FABD326AEC7B2008E5AF4 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 159AC43EFE0A1F95FCB358A4 /* Pods-MastodonIntent.release.xcconfig */; buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; @@ -5023,7 +4918,6 @@ }; DBC6461D26A170AB00B0E31B /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 77EE917BC055E6621C0452B6 /* Pods-ShareActionExtension.debug.xcconfig */; buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; @@ -5048,7 +4942,6 @@ }; DBC6462026A170AB00B0E31B /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 95AD0663479892A2109EEFD0 /* Pods-ShareActionExtension.release.xcconfig */; buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; @@ -5137,6 +5030,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 117; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; @@ -5230,7 +5124,6 @@ }; DBEB19E627E4658E00B0E80E /* Release Snapshot */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 8ADD558BE5B8255E5764A54F /* Pods-NotificationService.release snapshot.xcconfig */; buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; @@ -5254,7 +5147,6 @@ }; DBEB19E727E4658E00B0E80E /* Release Snapshot */ = { isa = XCBuildConfiguration; - baseConfigurationReference = F43DF6E8AB8C87914A64FC48 /* Pods-ShareActionExtension.release snapshot.xcconfig */; buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; @@ -5279,7 +5171,6 @@ }; DBEB19E827E4658E00B0E80E /* Release Snapshot */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 2C12EB4B3699D5D597027962 /* Pods-MastodonIntent.release snapshot.xcconfig */; buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; @@ -5304,7 +5195,6 @@ }; DBF8AE1C263293E400C9C23C /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9553C689FFA9EBC880CAB78D /* Pods-NotificationService.debug.xcconfig */; buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; @@ -5328,7 +5218,6 @@ }; DBF8AE1D263293E400C9C23C /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9776D7C4B79101CF70181127 /* Pods-NotificationService.release.xcconfig */; buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; @@ -5492,6 +5381,14 @@ minimumVersion = 4.1.0; }; }; + DB3EA8F6281BBA4C00598866 /* XCRemoteSwiftPackageReference "Alamofire" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/Alamofire/Alamofire.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 5.4.0; + }; + }; DB552D4D26BBD10C00E481F6 /* XCRemoteSwiftPackageReference "swift-collections" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/apple/swift-collections.git"; @@ -5516,14 +5413,6 @@ minimumVersion = 0.1.4; }; }; - DB9A487C2603456B008B817C /* XCRemoteSwiftPackageReference "UITextView-Placeholder" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/MainasuK/UITextView-Placeholder"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 1.4.1; - }; - }; DBA5A52D26F07ED800CACBAA /* XCRemoteSwiftPackageReference "PanModal" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/slackhq/PanModal.git"; @@ -5590,64 +5479,85 @@ package = 2D939AC625EE14620076FA61 /* XCRemoteSwiftPackageReference "TOCropViewController" */; productName = CropViewController; }; - 5D526FE125BE9AC400460CB9 /* MastodonSDK */ = { - isa = XCSwiftPackageProductDependency; - productName = MastodonSDK; - }; - DB00CA962632DDB600A54956 /* CommonOSLog */ = { - isa = XCSwiftPackageProductDependency; - package = DB0140BB25C40D7500F9F3CF /* XCRemoteSwiftPackageReference "CommonOSLog" */; - productName = CommonOSLog; - }; - DB01E23426A98F0900C3965B /* MetaTextKit */ = { - isa = XCSwiftPackageProductDependency; - package = DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit" */; - productName = MetaTextKit; - }; DB02EA0A280D180D00E751C5 /* KeychainAccess */ = { isa = XCSwiftPackageProductDependency; package = DB6804722637CC1200430867 /* XCRemoteSwiftPackageReference "KeychainAccess" */; productName = KeychainAccess; }; - DB02EA0C280D184B00E751C5 /* CommonOSLog */ = { + DB3EA8F4281BB65200598866 /* MastodonSDK */ = { + isa = XCSwiftPackageProductDependency; + productName = MastodonSDK; + }; + DB3EA8FB281BBAE100598866 /* AlamofireImage */ = { + isa = XCSwiftPackageProductDependency; + package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */; + productName = AlamofireImage; + }; + DB3EA8FD281BBAF200598866 /* Alamofire */ = { + isa = XCSwiftPackageProductDependency; + package = DB3EA8F6281BBA4C00598866 /* XCRemoteSwiftPackageReference "Alamofire" */; + productName = Alamofire; + }; + DB3EA8FF281BBB1D00598866 /* MetaTextKit */ = { + isa = XCSwiftPackageProductDependency; + package = DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit" */; + productName = MetaTextKit; + }; + DB3EA901281BBD5D00598866 /* CommonOSLog */ = { isa = XCSwiftPackageProductDependency; package = DB0140BB25C40D7500F9F3CF /* XCRemoteSwiftPackageReference "CommonOSLog" */; productName = CommonOSLog; }; - DB0C946426A6FD4D0088FB11 /* AlamofireImage */ = { + DB3EA903281BBD9400598866 /* Introspect */ = { + isa = XCSwiftPackageProductDependency; + package = DB8D8E2D28192EED009FD90F /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */; + productName = Introspect; + }; + DB3EA905281BBE8200598866 /* AlamofireImage */ = { isa = XCSwiftPackageProductDependency; package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */; productName = AlamofireImage; }; - DB179266278D5A4A00B71DEB /* MastodonSDK */ = { + DB3EA907281BBE8200598866 /* AlamofireNetworkActivityIndicator */ = { isa = XCSwiftPackageProductDependency; - productName = MastodonSDK; + package = 2D61336725C18A4F00CAE157 /* XCRemoteSwiftPackageReference "AlamofireNetworkActivityIndicator" */; + productName = AlamofireNetworkActivityIndicator; }; - DB3D0FF225BAA61700EAA174 /* AlamofireImage */ = { + DB3EA909281BBE8200598866 /* Alamofire */ = { + isa = XCSwiftPackageProductDependency; + package = DB3EA8F6281BBA4C00598866 /* XCRemoteSwiftPackageReference "Alamofire" */; + productName = Alamofire; + }; + DB3EA90B281BBE9600598866 /* AlamofireImage */ = { isa = XCSwiftPackageProductDependency; package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */; productName = AlamofireImage; }; + DB3EA90D281BBE9600598866 /* AlamofireNetworkActivityIndicator */ = { + isa = XCSwiftPackageProductDependency; + package = 2D61336725C18A4F00CAE157 /* XCRemoteSwiftPackageReference "AlamofireNetworkActivityIndicator" */; + productName = AlamofireNetworkActivityIndicator; + }; + DB3EA90F281BBE9600598866 /* Alamofire */ = { + isa = XCSwiftPackageProductDependency; + package = DB3EA8F6281BBA4C00598866 /* XCRemoteSwiftPackageReference "Alamofire" */; + productName = Alamofire; + }; + DB3EA911281BBEA800598866 /* AlamofireImage */ = { + isa = XCSwiftPackageProductDependency; + package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */; + productName = AlamofireImage; + }; + DB3EA913281BBEA800598866 /* Alamofire */ = { + isa = XCSwiftPackageProductDependency; + package = DB3EA8F6281BBA4C00598866 /* XCRemoteSwiftPackageReference "Alamofire" */; + productName = Alamofire; + }; DB552D4E26BBD10C00E481F6 /* OrderedCollections */ = { isa = XCSwiftPackageProductDependency; package = DB552D4D26BBD10C00E481F6 /* XCRemoteSwiftPackageReference "swift-collections" */; productName = OrderedCollections; }; - DB6D9F41263527CE008423CD /* AlamofireImage */ = { - isa = XCSwiftPackageProductDependency; - package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */; - productName = AlamofireImage; - }; - DB8D8E2E28192EED009FD90F /* Introspect */ = { - isa = XCSwiftPackageProductDependency; - package = DB8D8E2D28192EED009FD90F /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */; - productName = Introspect; - }; - DB9A487D2603456B008B817C /* UITextView+Placeholder */ = { - isa = XCSwiftPackageProductDependency; - package = DB9A487C2603456B008B817C /* XCRemoteSwiftPackageReference "UITextView-Placeholder" */; - productName = "UITextView+Placeholder"; - }; DBA5A52E26F07ED800CACBAA /* PanModal */ = { isa = XCSwiftPackageProductDependency; package = DBA5A52D26F07ED800CACBAA /* XCRemoteSwiftPackageReference "PanModal" */; @@ -5673,24 +5583,6 @@ package = DBB525062611EAC0002F1F29 /* XCRemoteSwiftPackageReference "Tabman" */; productName = Tabman; }; - DBB8AB4726AED09C00F6D281 /* MastodonSDK */ = { - isa = XCSwiftPackageProductDependency; - productName = MastodonSDK; - }; - DBBC24A926A5301B00398BB9 /* MastodonSDK */ = { - isa = XCSwiftPackageProductDependency; - productName = MastodonSDK; - }; - DBBC24B726A5421800398BB9 /* CommonOSLog */ = { - isa = XCSwiftPackageProductDependency; - package = DB0140BB25C40D7500F9F3CF /* XCRemoteSwiftPackageReference "CommonOSLog" */; - productName = CommonOSLog; - }; - DBBC24D026A5484F00398BB9 /* UITextView+Placeholder */ = { - isa = XCSwiftPackageProductDependency; - package = DB9A487C2603456B008B817C /* XCRemoteSwiftPackageReference "UITextView-Placeholder" */; - productName = "UITextView+Placeholder"; - }; DBF7A0FB26830C33004176A2 /* FPSIndicator */ = { isa = XCSwiftPackageProductDependency; package = DBF7A0FA26830C33004176A2 /* XCRemoteSwiftPackageReference "FPSIndicator" */; diff --git a/Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon - Release.xcscheme b/Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon - Release.xcscheme index d5959cead..f88978596 100644 --- a/Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon - Release.xcscheme +++ b/Mastodon.xcodeproj/xcshareddata/xcschemes/Mastodon - Release.xcscheme @@ -1,6 +1,6 @@ Mastodon - RTL.xcscheme_^#shared#^_ orderHint - 19 + 6 Mastodon - Release.xcscheme_^#shared#^_ @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 24 + 21 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 22 + 19 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 23 + 20 SuppressBuildableAutocreation diff --git a/MastodonSDK/Package.swift b/MastodonSDK/Package.swift index 8b007c2a6..3b109cfa9 100644 --- a/MastodonSDK/Package.swift +++ b/MastodonSDK/Package.swift @@ -20,12 +20,7 @@ let package = Package( "MastodonLocalization", "MastodonSDK", "MastodonUI", - ]), - .library( - name: "MastodonCommon", - targets: [ - "MastodonCommon", - ]), + ]) ], dependencies: [ .package(url: "https://github.com/SwiftyJSON/SwiftyJSON.git", from: "5.0.0"), @@ -88,15 +83,15 @@ let package = Package( "MastodonExtension", "MastodonAsset", "MastodonLocalization", - "Nuke", - "NukeFLAnimatedImagePlugin", - "UITextView+Placeholder", - "Introspect", .product(name: "Alamofire", package: "Alamofire"), .product(name: "AlamofireImage", package: "AlamofireImage"), - .product(name: "MetaTextKit", package: "MetaTextKit"), .product(name: "FLAnimatedImage", package: "FLAnimatedImage"), .product(name: "FaviconFinder", package: "FaviconFinder"), + .product(name: "MetaTextKit", package: "MetaTextKit"), + .product(name: "Nuke", package: "Nuke"), + .product(name: "NukeFLAnimatedImagePlugin", package: "NukeFLAnimatedImagePlugin"), + .product(name: "Introspect", package: "Introspect"), + .product(name: "UITextView+Placeholder", package: "UITextView+Placeholder"), ] ), .testTarget( diff --git a/AppShared/UserDefaults.swift b/MastodonSDK/Sources/MastodonCommon/Extension/UserDefaults.swift similarity index 58% rename from AppShared/UserDefaults.swift rename to MastodonSDK/Sources/MastodonCommon/Extension/UserDefaults.swift index 31f8e27ef..53d298d0f 100644 --- a/AppShared/UserDefaults.swift +++ b/MastodonSDK/Sources/MastodonCommon/Extension/UserDefaults.swift @@ -1,14 +1,12 @@ // // UserDefaults.swift -// AppShared +// // -// Created by MainasuK Cirno on 2021-4-27. +// Created by MainasuK on 2022-4-29. // -import UIKit -import MastodonCommon +import Foundation extension UserDefaults { public static let shared = UserDefaults(suiteName: AppName.groupID)! } - diff --git a/Podfile b/Podfile index ad7715abd..30f90a05e 100644 --- a/Podfile +++ b/Podfile @@ -29,21 +29,6 @@ target 'Mastodon' do end -target 'NotificationService' do - # Comment the next line if you don't want to use dynamic frameworks - use_frameworks! -end - -target 'ShareActionExtension' do - # Comment the next line if you don't want to use dynamic frameworks - use_frameworks! -end - -target 'MastodonIntent' do - # Comment the next line if you don't want to use dynamic frameworks - use_frameworks! -end - target 'AppShared' do # Comment the next line if you don't want to use dynamic frameworks use_frameworks! diff --git a/Podfile.lock b/Podfile.lock index f8dde6937..0c156eadc 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -40,6 +40,6 @@ SPEC CHECKSUMS: SwiftGen: 67860cc7c3cfc2ed25b9b74cfd55495fc89f9108 "UITextField+Shake": 298ac5a0f239d731bdab999b19b628c956ca0ac3 -PODFILE CHECKSUM: c471d1f9c923dc63bf8684415c79b85adb2ac36b +PODFILE CHECKSUM: 335d0ca70493d4c280d0f8fd7f26fe9be6a4e289 COCOAPODS: 1.11.3 From c58315b8bdff3daa8232a86d58740944968e6d71 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 29 Apr 2022 15:05:22 +0800 Subject: [PATCH 046/101] chore: update i18n resources --- .../Generated/Strings.swift | 10 +- .../Resources/ar.lproj/Localizable.strings | 9 +- .../Resources/ca.lproj/Localizable.strings | 1 + .../Resources/de.lproj/Localizable.strings | 1 + .../Resources/en.lproj/Localizable.strings | 9 +- .../es-419.lproj/Localizable.strings | 1 + .../Resources/es.lproj/Localizable.strings | 1 + .../Resources/eu-ES.lproj/Localizable.strings | 1 + .../Resources/fr.lproj/Localizable.strings | 1 + .../Resources/gd-GB.lproj/Localizable.strings | 1 + .../Resources/ja.lproj/Localizable.strings | 1 + .../Resources/kab.lproj/Localizable.strings | 1 + .../Resources/ku.lproj/Localizable.strings | 1 + .../Resources/nl.lproj/Localizable.strings | 1 + .../Resources/ru.lproj/Localizable.strings | 3 +- .../Resources/sv_FI.lproj/Localizable.strings | 139 +++++++++--------- .../sv_FI.lproj/Localizable.stringsdict | 4 +- .../Resources/th.lproj/Localizable.strings | 1 + .../Resources/vi.lproj/Localizable.strings | 11 +- .../zh-Hans.lproj/Localizable.strings | 1 + 20 files changed, 109 insertions(+), 89 deletions(-) diff --git a/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift b/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift index 36ddc8ffe..de6b55cbd 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift +++ b/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift @@ -549,6 +549,8 @@ public enum L10n { /// These are the posts gaining traction in your corner of Mastodon. public static let intro = L10n.tr("Localizable", "Scene.Discovery.Intro") public enum Tabs { + /// Community + public static let community = L10n.tr("Localizable", "Scene.Discovery.Tabs.Community") /// For You public static let forYou = L10n.tr("Localizable", "Scene.Discovery.Tabs.ForYou") /// Hashtags @@ -892,11 +894,11 @@ public enum L10n { } } public enum ServerPicker { - /// Pick a community based on your interests, region, or a general purpose one. + /// Pick a server based on your interests, region, or a general purpose one. public static let subtitle = L10n.tr("Localizable", "Scene.ServerPicker.Subtitle") - /// Pick a community based on your interests, region, or a general purpose one. Each community is operated by an entirely independent organization or individual. + /// Pick a server based on your interests, region, or a general purpose one. Each server is operated by an entirely independent organization or individual. public static let subtitleExtend = L10n.tr("Localizable", "Scene.ServerPicker.SubtitleExtend") - /// Mastodon is made of users in different communities. + /// Mastodon is made of users in different servers. public static let title = L10n.tr("Localizable", "Scene.ServerPicker.Title") public enum Button { /// See Less @@ -943,7 +945,7 @@ public enum L10n { public static let noResults = L10n.tr("Localizable", "Scene.ServerPicker.EmptyState.NoResults") } public enum Input { - /// Search communities + /// Search servers public static let placeholder = L10n.tr("Localizable", "Scene.ServerPicker.Input.Placeholder") } public enum Label { diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings index 2cb63b209..2ed1a8ad3 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings @@ -126,7 +126,7 @@ "Common.Controls.Status.Visibility.Unlisted" = "يُمكِنُ لِلجَميعِ رُؤيَةُ هَذَا المَنشورِ وَلكِنَّهُ لَا يُعرَضُ فِي الخَطِّ الزَمنيّ العام."; "Common.Controls.Tabs.Home" = "الرَّئِيسَة"; "Common.Controls.Tabs.Notification" = "الإشعارات"; -"Common.Controls.Tabs.Profile" = "الملف التعريفي"; +"Common.Controls.Tabs.Profile" = "المِلَفُّ التَّعريفِيّ"; "Common.Controls.Tabs.Search" = "البَحث"; "Common.Controls.Timeline.Filtered" = "مُصفَّى"; "Common.Controls.Timeline.Header.BlockedWarning" = "لا يُمكِنُكَ عَرض الملف التَعريفي لهذا المُستخدِم @@ -203,10 +203,11 @@ انقر على الرابط لتأكيد حسابك."; "Scene.ConfirmEmail.Title" = "شيءٌ أخير."; "Scene.Discovery.Intro" = "هَذِهِ هِيَ المَنشُوراتُ الَّتي تَكْتَسِبُ شَعبِيَّةً فِي الرُّكنِ الخاصِّ بِكَ مِن مَاستُودون."; +"Scene.Discovery.Tabs.Community" = "المُجتَمَع"; "Scene.Discovery.Tabs.ForYou" = "لَك"; -"Scene.Discovery.Tabs.Hashtags" = "الوسوم"; -"Scene.Discovery.Tabs.News" = "الأخبار"; -"Scene.Discovery.Tabs.Posts" = "المنشورات"; +"Scene.Discovery.Tabs.Hashtags" = "وُسُوم"; +"Scene.Discovery.Tabs.News" = "أخبار"; +"Scene.Discovery.Tabs.Posts" = "مَنشُورات"; "Scene.Favorite.Title" = "مُفضَّلَتُك"; "Scene.Follower.Footer" = "لا يُمكِن عَرض المُتابِعين مِنَ الخوادم الأُخرى."; "Scene.Following.Footer" = "لا يُمكِن عَرض المُتابَعات مِنَ الخوادم الأُخرى."; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings index 62ddadfaf..f22a0ff74 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings @@ -202,6 +202,7 @@ carregat a Mastodon."; "Scene.ConfirmEmail.Subtitle" = "Toca l'enllaç del correu electrònic que t'hem enviat per a confirmar el teu compte."; "Scene.ConfirmEmail.Title" = "Una última cosa."; "Scene.Discovery.Intro" = "Aquestes son les publicacions que criden l'atenció en el teu racó de Mastodon."; +"Scene.Discovery.Tabs.Community" = "Comunitat"; "Scene.Discovery.Tabs.ForYou" = "Per a tu"; "Scene.Discovery.Tabs.Hashtags" = "Etiquetes"; "Scene.Discovery.Tabs.News" = "Notícies"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings index 71dd59d0f..29845981c 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings @@ -203,6 +203,7 @@ kann nicht auf Mastodon hochgeladen werden."; tippe darin auf den Link, um Dein Konto zu bestätigen."; "Scene.ConfirmEmail.Title" = "Noch eine letzte Sache."; "Scene.Discovery.Intro" = "These are the posts gaining traction in your corner of Mastodon."; +"Scene.Discovery.Tabs.Community" = "Community"; "Scene.Discovery.Tabs.ForYou" = "Für dich"; "Scene.Discovery.Tabs.Hashtags" = "Hashtags"; "Scene.Discovery.Tabs.News" = "Nachrichten"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings index eb1838e34..fe66593f4 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings @@ -202,6 +202,7 @@ uploaded to Mastodon."; "Scene.ConfirmEmail.Subtitle" = "Tap the link we emailed to you to verify your account."; "Scene.ConfirmEmail.Title" = "One last thing."; "Scene.Discovery.Intro" = "These are the posts gaining traction in your corner of Mastodon."; +"Scene.Discovery.Tabs.Community" = "Community"; "Scene.Discovery.Tabs.ForYou" = "For You"; "Scene.Discovery.Tabs.Hashtags" = "Hashtags"; "Scene.Discovery.Tabs.News" = "News"; @@ -330,13 +331,13 @@ uploaded to Mastodon."; "Scene.ServerPicker.EmptyState.BadNetwork" = "Something went wrong while loading the data. Check your internet connection."; "Scene.ServerPicker.EmptyState.FindingServers" = "Finding available servers..."; "Scene.ServerPicker.EmptyState.NoResults" = "No results"; -"Scene.ServerPicker.Input.Placeholder" = "Search communities"; +"Scene.ServerPicker.Input.Placeholder" = "Search servers"; "Scene.ServerPicker.Label.Category" = "CATEGORY"; "Scene.ServerPicker.Label.Language" = "LANGUAGE"; "Scene.ServerPicker.Label.Users" = "USERS"; -"Scene.ServerPicker.Subtitle" = "Pick a community based on your interests, region, or a general purpose one."; -"Scene.ServerPicker.SubtitleExtend" = "Pick a community based on your interests, region, or a general purpose one. Each community is operated by an entirely independent organization or individual."; -"Scene.ServerPicker.Title" = "Mastodon is made of users in different communities."; +"Scene.ServerPicker.Subtitle" = "Pick a server based on your interests, region, or a general purpose one."; +"Scene.ServerPicker.SubtitleExtend" = "Pick a server based on your interests, region, or a general purpose one. Each server is operated by an entirely independent organization or individual."; +"Scene.ServerPicker.Title" = "Mastodon is made of users in different servers."; "Scene.ServerRules.Button.Confirm" = "I Agree"; "Scene.ServerRules.PrivacyPolicy" = "privacy policy"; "Scene.ServerRules.Prompt" = "By continuing, you’re subject to the terms of service and privacy policy for %@."; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.strings index 0203cd195..db6cacc37 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.strings @@ -203,6 +203,7 @@ y no se puede subir a Mastodon."; pulsá en el enlace para confirmar tu cuenta."; "Scene.ConfirmEmail.Title" = "Una última cosa."; "Scene.Discovery.Intro" = "Estos son los mensajes que están ganando tracción en tu rincón de Mastodon."; +"Scene.Discovery.Tabs.Community" = "Community"; "Scene.Discovery.Tabs.ForYou" = "Para vos"; "Scene.Discovery.Tabs.Hashtags" = "Etiquetas"; "Scene.Discovery.Tabs.News" = "Novedades"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.strings index 9da54c16b..09fba0b42 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.strings @@ -203,6 +203,7 @@ subirse a Mastodon."; pulsa en el enlace para confirmar tu cuenta."; "Scene.ConfirmEmail.Title" = "Una última cosa."; "Scene.Discovery.Intro" = "These are the posts gaining traction in your corner of Mastodon."; +"Scene.Discovery.Tabs.Community" = "Community"; "Scene.Discovery.Tabs.ForYou" = "Para Ti"; "Scene.Discovery.Tabs.Hashtags" = "Etiquetas"; "Scene.Discovery.Tabs.News" = "Noticias"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.strings index 8be5744d5..e682977e9 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.strings @@ -203,6 +203,7 @@ Mastodonera igo."; sakatu kontua berresteko esteka."; "Scene.ConfirmEmail.Title" = "Eta azkenik..."; "Scene.Discovery.Intro" = "These are the posts gaining traction in your corner of Mastodon."; +"Scene.Discovery.Tabs.Community" = "Community"; "Scene.Discovery.Tabs.ForYou" = "Zuretzat"; "Scene.Discovery.Tabs.Hashtags" = "Traolak"; "Scene.Discovery.Tabs.News" = "Albisteak"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.strings index ebeba78ac..880612b29 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.strings @@ -203,6 +203,7 @@ téléversé sur Mastodon."; tapotez le lien pour confirmer votre compte."; "Scene.ConfirmEmail.Title" = "Une dernière chose."; "Scene.Discovery.Intro" = "These are the posts gaining traction in your corner of Mastodon."; +"Scene.Discovery.Tabs.Community" = "Community"; "Scene.Discovery.Tabs.ForYou" = "Pour vous"; "Scene.Discovery.Tabs.Hashtags" = "Hashtags"; "Scene.Discovery.Tabs.News" = "Actualité"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.strings index d6dddaf3a..586258e5a 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.strings @@ -203,6 +203,7 @@ a luchdadh suas gu Mastodon."; thoir gnogag air a’ chunntas a dhearbhadh a’ chunntais agad."; "Scene.ConfirmEmail.Title" = "Aon rud eile."; "Scene.Discovery.Intro" = "Seo na postaichean fèillmhor ’nad cheàrnaidh de Mhastodon."; +"Scene.Discovery.Tabs.Community" = "Community"; "Scene.Discovery.Tabs.ForYou" = "Dhut-sa"; "Scene.Discovery.Tabs.Hashtags" = "Tagaichean hais"; "Scene.Discovery.Tabs.News" = "Naidheachdan"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings index 184f53322..19056cf5a 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings @@ -197,6 +197,7 @@ "Scene.ConfirmEmail.Subtitle" = "先程 %@ にメールを送信しました。リンクをタップしてアカウントを確認してください。"; "Scene.ConfirmEmail.Title" = "さいごにもうひとつ。"; "Scene.Discovery.Intro" = "These are the posts gaining traction in your corner of Mastodon."; +"Scene.Discovery.Tabs.Community" = "Community"; "Scene.Discovery.Tabs.ForYou" = "For You"; "Scene.Discovery.Tabs.Hashtags" = "ハッシュタグ"; "Scene.Discovery.Tabs.News" = "ニュース"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.strings index aa95cfb69..3ea1700cd 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.strings @@ -202,6 +202,7 @@ Ad d-yettwasali ɣef Mastodon."; "Scene.ConfirmEmail.Subtitle" = "Sit ɣef useɣwen i ak-n-uznen i wakken ad tesneqdeḍ amiḍan-ik."; "Scene.ConfirmEmail.Title" = "Taɣawsa taneggarut."; "Scene.Discovery.Intro" = "Tigi d tisuffaɣ i d-ijebbden s waṭas deg tama-inek•inem n Mastodon."; +"Scene.Discovery.Tabs.Community" = "Community"; "Scene.Discovery.Tabs.ForYou" = "I kečč·kem"; "Scene.Discovery.Tabs.Hashtags" = "Ihacṭagen"; "Scene.Discovery.Tabs.News" = "Isallen"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings index 2444c70c4..7f2e7ef48 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings @@ -203,6 +203,7 @@ Profîla te ji wan ra wiha xuya dike."; girêdanê bitikne da ku ajimêra xwe bidî piştrastkirin."; "Scene.ConfirmEmail.Title" = "Tiştekî dawî."; "Scene.Discovery.Intro" = "Ev şandiyên ku di quncika Mastodon balê dikişîne."; +"Scene.Discovery.Tabs.Community" = "Civak"; "Scene.Discovery.Tabs.ForYou" = "Ji bo te"; "Scene.Discovery.Tabs.Hashtags" = "Hashtag"; "Scene.Discovery.Tabs.News" = "Nûçe"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.strings index 0a06b59d3..63586def9 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.strings @@ -197,6 +197,7 @@ Uw profiel ziet er zo uit voor hen."; klik op de link om uw account te bevestigen."; "Scene.ConfirmEmail.Title" = "Nog één ding."; "Scene.Discovery.Intro" = "Dit zijn de berichten die populair zijn in jouw Mastodon-kringen."; +"Scene.Discovery.Tabs.Community" = "Community"; "Scene.Discovery.Tabs.ForYou" = "Voor jou"; "Scene.Discovery.Tabs.Hashtags" = "Hashtags"; "Scene.Discovery.Tabs.News" = "Nieuws"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings index 051169824..0c0397731 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings @@ -213,6 +213,7 @@ подтвердить свою учётную запись."; "Scene.ConfirmEmail.Title" = "И ещё кое-что."; "Scene.Discovery.Intro" = "These are the posts gaining traction in your corner of Mastodon."; +"Scene.Discovery.Tabs.Community" = "Community"; "Scene.Discovery.Tabs.ForYou" = "For You"; "Scene.Discovery.Tabs.Hashtags" = "Hashtags"; "Scene.Discovery.Tabs.News" = "News"; @@ -346,7 +347,7 @@ "Scene.ServerPicker.Label.Language" = "ЯЗЫК"; "Scene.ServerPicker.Label.Users" = "ПОЛЬЗОВАТЕЛИ"; "Scene.ServerPicker.Subtitle" = "Выберите сообщество на основе своих интересов, региона или общей тематики."; -"Scene.ServerPicker.SubtitleExtend" = "Pick a community based on your interests, region, or a general purpose one. Each community is operated by an entirely independent organization or individual."; +"Scene.ServerPicker.SubtitleExtend" = "Pick a server based on your interests, region, or a general purpose one. Each server is operated by an entirely independent organization or individual."; "Scene.ServerPicker.Title" = "Выберите сервер, любой сервер."; "Scene.ServerRules.Button.Confirm" = "Принимаю"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/sv_FI.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/sv_FI.lproj/Localizable.strings index 342b05b23..135e34990 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/sv_FI.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/sv_FI.lproj/Localizable.strings @@ -1,21 +1,21 @@ "Common.Alerts.BlockDomain.BlockEntireDomain" = "Estä verkkotunnus"; -"Common.Alerts.BlockDomain.Title" = "Are you really, really sure you want to block the entire %@? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain and any of your followers from that domain will be removed."; +"Common.Alerts.BlockDomain.Title" = "Är du verkligen, verkligen säker på att du vill blockera hela %@? I de flesta fall är några riktade blockeringar eller nedtystade konton tillräckligt och att föredra. Du kommer inte se innehåll från den domänen och dina följare från den domänen kommer att tas bort."; "Common.Alerts.CleanCache.Message" = "%@ välimuisti tyhjennetty onnistuneesti."; "Common.Alerts.CleanCache.Title" = "Puhdista välimuisti"; "Common.Alerts.Common.PleaseTryAgain" = "Yritä uudelleen."; "Common.Alerts.Common.PleaseTryAgainLater" = "Yritä uudelleen myöhemmin."; -"Common.Alerts.DeletePost.Message" = "Are you sure you want to delete this post?"; +"Common.Alerts.DeletePost.Message" = "Är du säker på att du vill radera detta inlägg?"; "Common.Alerts.DeletePost.Title" = "Haluatko varmasti poistaa tämän julkaisun?"; -"Common.Alerts.DiscardPostContent.Message" = "Confirm to discard composed post content."; +"Common.Alerts.DiscardPostContent.Message" = "Bekräfta för att slänga inläggsutkast."; "Common.Alerts.DiscardPostContent.Title" = "Hylkää luonnos"; "Common.Alerts.EditProfileFailure.Message" = "Profiilia ei voida muoka. Yritä uudelleen."; "Common.Alerts.EditProfileFailure.Title" = "Virhe profiilin muokkauksessa"; "Common.Alerts.PublishPostFailure.AttachmentsMessage.MoreThanOneVideo" = "Ei voi liittä yhtä videota enempää."; -"Common.Alerts.PublishPostFailure.AttachmentsMessage.VideoAttachWithPhoto" = "Cannot attach a video to a post that already contains images."; +"Common.Alerts.PublishPostFailure.AttachmentsMessage.VideoAttachWithPhoto" = "Det går inte att bifoga en video till en status som redan innehåller bilder."; "Common.Alerts.PublishPostFailure.Message" = "Julkaisun julkaiseminen epäonnistui. Tarkista internet-yhteytesi."; "Common.Alerts.PublishPostFailure.Title" = "Julkaiseminen epäonnistui"; -"Common.Alerts.SavePhotoFailure.Message" = "Please enable the photo library access permission to save the photo."; +"Common.Alerts.SavePhotoFailure.Message" = "Aktivera åtkomst till Bilder för att spara bilden."; "Common.Alerts.SavePhotoFailure.Title" = "Kuvan tallentaminen epäonnistui"; "Common.Alerts.ServerError.Title" = "Palvelinvirhe"; "Common.Alerts.SignOut.Confirm" = "Kirjaudu ulos"; @@ -23,7 +23,7 @@ Tarkista internet-yhteytesi."; "Common.Alerts.SignOut.Title" = "Kirjaudu ulos"; "Common.Alerts.SignUpFailure.Title" = "Rekisteröinti epäonnistui"; "Common.Alerts.VoteFailure.PollEnded" = "Kysely on päättynyt"; -"Common.Alerts.VoteFailure.Title" = "Vote Failure"; +"Common.Alerts.VoteFailure.Title" = "Röstning misslyckades"; "Common.Controls.Actions.Add" = "Lisää"; "Common.Controls.Actions.Back" = "Takaisin"; "Common.Controls.Actions.BlockDomain" = "Estä %@"; @@ -37,11 +37,11 @@ Tarkista internet-yhteytesi."; "Common.Controls.Actions.Done" = "Valmis"; "Common.Controls.Actions.Edit" = "Muokkaa"; "Common.Controls.Actions.FindPeople" = "Löydä tilejä seurattavaksi"; -"Common.Controls.Actions.ManuallySearch" = "Manually search instead"; +"Common.Controls.Actions.ManuallySearch" = "Sök manuellt istället"; "Common.Controls.Actions.Next" = "Seuraava"; "Common.Controls.Actions.Ok" = "OK"; "Common.Controls.Actions.Open" = "Avaa"; -"Common.Controls.Actions.OpenInBrowser" = "Open in Browser"; +"Common.Controls.Actions.OpenInBrowser" = "Öppna i webbläsare"; "Common.Controls.Actions.OpenInSafari" = "Avaa Safarissa"; "Common.Controls.Actions.Preview" = "Esikatselu"; "Common.Controls.Actions.Previous" = "Edellinen"; @@ -74,7 +74,7 @@ Tarkista internet-yhteytesi."; "Common.Controls.Friendship.Pending" = "Pyydetty"; "Common.Controls.Friendship.Request" = "Pyydä"; "Common.Controls.Friendship.Unblock" = "Poista esto"; -"Common.Controls.Friendship.UnblockUser" = "Unblock %@"; +"Common.Controls.Friendship.UnblockUser" = "Avblockera %@"; "Common.Controls.Friendship.Unmute" = "Poista mykistys"; "Common.Controls.Friendship.UnmuteUser" = "Poista mykistys tililtä %@"; "Common.Controls.Keyboard.Common.ComposeNewPost" = "Koosta uusi julkaisu"; @@ -82,48 +82,48 @@ Tarkista internet-yhteytesi."; "Common.Controls.Keyboard.Common.ShowFavorites" = "Näytä suosikit"; "Common.Controls.Keyboard.Common.SwitchToTab" = "Vaihda %@"; "Common.Controls.Keyboard.SegmentedControl.NextSection" = "Seuraava lohko"; -"Common.Controls.Keyboard.SegmentedControl.PreviousSection" = "Previous Section"; +"Common.Controls.Keyboard.SegmentedControl.PreviousSection" = "Föregående avsnitt"; "Common.Controls.Keyboard.Timeline.NextStatus" = "Seuraava julkaisu"; "Common.Controls.Keyboard.Timeline.OpenAuthorProfile" = "Avaa tekijän profiili"; "Common.Controls.Keyboard.Timeline.OpenRebloggerProfile" = "Avaa edelleen jakajan profiili"; "Common.Controls.Keyboard.Timeline.OpenStatus" = "Avaa julkaisu"; -"Common.Controls.Keyboard.Timeline.PreviewImage" = "Preview Image"; +"Common.Controls.Keyboard.Timeline.PreviewImage" = "Förhandsgranska bild"; "Common.Controls.Keyboard.Timeline.PreviousStatus" = "Edellinen julkaisu"; "Common.Controls.Keyboard.Timeline.ReplyStatus" = "Vastaa julkaisuun"; "Common.Controls.Keyboard.Timeline.ToggleContentWarning" = "Vaihda sisältövaroitus"; -"Common.Controls.Keyboard.Timeline.ToggleFavorite" = "Toggle Favorite on Post"; -"Common.Controls.Keyboard.Timeline.ToggleReblog" = "Toggle Reblog on Post"; -"Common.Controls.Status.Actions.Favorite" = "Favorite"; +"Common.Controls.Keyboard.Timeline.ToggleFavorite" = "Växla favorit på inlägg"; +"Common.Controls.Keyboard.Timeline.ToggleReblog" = "Växla ompostning på inlägg"; +"Common.Controls.Status.Actions.Favorite" = "Favorit"; "Common.Controls.Status.Actions.Hide" = "Dölj"; "Common.Controls.Status.Actions.Menu" = "Valikko"; "Common.Controls.Status.Actions.Reblog" = "Jaa edelleen"; "Common.Controls.Status.Actions.Reply" = "Vastaa"; -"Common.Controls.Status.Actions.ShowGif" = "Show GIF"; -"Common.Controls.Status.Actions.ShowImage" = "Show image"; -"Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; -"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tap then hold to show menu"; -"Common.Controls.Status.Actions.Unfavorite" = "Unfavorite"; +"Common.Controls.Status.Actions.ShowGif" = "Visa GIF"; +"Common.Controls.Status.Actions.ShowImage" = "Visa bild"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Visa videospelare"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tryck och håll ned för att visa menyn"; +"Common.Controls.Status.Actions.Unfavorite" = "Ta bort favorit"; "Common.Controls.Status.Actions.Unreblog" = "Peru edelleen jako"; "Common.Controls.Status.ContentWarning" = "Sisältövaroitus"; "Common.Controls.Status.MediaContentWarning" = "Napauta mistä tahansa paljastaaksesi"; "Common.Controls.Status.Poll.Closed" = "Suljettu"; -"Common.Controls.Status.Poll.Vote" = "Vote"; -"Common.Controls.Status.SensitiveContent" = "Sensitive Content"; +"Common.Controls.Status.Poll.Vote" = "Rösta"; +"Common.Controls.Status.SensitiveContent" = "Känsligt innehåll"; "Common.Controls.Status.ShowPost" = "Näytä julkaisu"; "Common.Controls.Status.ShowUserProfile" = "Näytä tili"; "Common.Controls.Status.Tag.Email" = "Sähköposti"; "Common.Controls.Status.Tag.Emoji" = "Emoji"; "Common.Controls.Status.Tag.Hashtag" = "Hashtagi"; "Common.Controls.Status.Tag.Link" = "Linkki"; -"Common.Controls.Status.Tag.Mention" = "Mention"; +"Common.Controls.Status.Tag.Mention" = "Nämn"; "Common.Controls.Status.Tag.Url" = "URL"; -"Common.Controls.Status.TapToReveal" = "Tap to reveal"; +"Common.Controls.Status.TapToReveal" = "Tryck för att visa"; "Common.Controls.Status.UserReblogged" = "%@ jakoi edelleen"; "Common.Controls.Status.UserRepliedTo" = "Vastasi %@:lle"; -"Common.Controls.Status.Visibility.Direct" = "Only mentioned user can see this post."; -"Common.Controls.Status.Visibility.Private" = "Only their followers can see this post."; -"Common.Controls.Status.Visibility.PrivateFromMe" = "Only my followers can see this post."; -"Common.Controls.Status.Visibility.Unlisted" = "Everyone can see this post but not display in the public timeline."; +"Common.Controls.Status.Visibility.Direct" = "Endast nämnda användare kan se detta inlägg."; +"Common.Controls.Status.Visibility.Private" = "Endast deras följare kan se detta inlägg."; +"Common.Controls.Status.Visibility.PrivateFromMe" = "Bara mina följare kan se det här inlägget."; +"Common.Controls.Status.Visibility.Unlisted" = "Alla kan se detta inlägg men det visas inte i den offentliga tidslinjen."; "Common.Controls.Tabs.Home" = "Koti"; "Common.Controls.Tabs.Notification" = "Ilmoitus"; "Common.Controls.Tabs.Profile" = "Profiili"; @@ -156,13 +156,13 @@ Profiilisi näyttää tältä hänelle."; "Scene.Compose.Accessibility.EnableContentWarning" = "Ota sisältövaroitus käyttöön"; "Scene.Compose.Accessibility.PostVisibilityMenu" = "Julkaisun näkyvyysvalikko"; "Scene.Compose.Accessibility.RemovePoll" = "Poista kysely"; -"Scene.Compose.Attachment.AttachmentBroken" = "This %@ is broken and can’t be -uploaded to Mastodon."; +"Scene.Compose.Attachment.AttachmentBroken" = "Denna %@ är trasig och kan inte +laddas upp till Mastodon."; "Scene.Compose.Attachment.DescriptionPhoto" = "Kuvaile kuva näkövammaisille..."; "Scene.Compose.Attachment.DescriptionVideo" = "Kuvaile video näkövammaisille..."; "Scene.Compose.Attachment.Photo" = "kuva"; "Scene.Compose.Attachment.Video" = "video"; -"Scene.Compose.AutoComplete.SpaceToAdd" = "Space to add"; +"Scene.Compose.AutoComplete.SpaceToAdd" = "Mellanslag att lägga till"; "Scene.Compose.ComposeAction" = "Julkaise"; "Scene.Compose.ContentInputPlaceholder" = "Kirjoita tai liitä, siitä mitä ajattelet"; "Scene.Compose.ContentWarning.Placeholder" = "Kirjoita tarkka varoitus tähän..."; @@ -191,7 +191,7 @@ uploaded to Mastodon."; "Scene.Compose.Visibility.Public" = "Julkinen"; "Scene.Compose.Visibility.Unlisted" = "Listaamaton"; "Scene.ConfirmEmail.Button.OpenEmailApp" = "Avaa sähköpostisovellus"; -"Scene.ConfirmEmail.Button.Resend" = "Resend"; +"Scene.ConfirmEmail.Button.Resend" = "Skicka igen"; "Scene.ConfirmEmail.DontReceiveEmail.Description" = "Tarkista, että sähköpostiosoitteesi on oikea, sekä roskapostikansiosi, jos et vielä ole."; "Scene.ConfirmEmail.DontReceiveEmail.ResendEmail" = "Lähetä sähköposti uudelleen"; "Scene.ConfirmEmail.DontReceiveEmail.Title" = "Tarkista sähköpostisi"; @@ -201,11 +201,12 @@ uploaded to Mastodon."; "Scene.ConfirmEmail.OpenEmailApp.Title" = "Tarkasta postilaatikkosi."; "Scene.ConfirmEmail.Subtitle" = "Lähetimme juuri sähköpostin osoitteeseen %@, napauta siinä olevaa linkkiä vahvistaaksesi tilisi."; "Scene.ConfirmEmail.Title" = "Viimeinen asia."; -"Scene.Discovery.Intro" = "These are the posts gaining traction in your corner of Mastodon."; -"Scene.Discovery.Tabs.ForYou" = "For You"; -"Scene.Discovery.Tabs.Hashtags" = "Hashtags"; -"Scene.Discovery.Tabs.News" = "News"; -"Scene.Discovery.Tabs.Posts" = "Posts"; +"Scene.Discovery.Intro" = "Detta är de inlägg som engagerar i ditt hörn av Mastodon."; +"Scene.Discovery.Tabs.Community" = "Community"; +"Scene.Discovery.Tabs.ForYou" = "För dig"; +"Scene.Discovery.Tabs.Hashtags" = "Hashtaggar"; +"Scene.Discovery.Tabs.News" = "Nyheter"; +"Scene.Discovery.Tabs.Posts" = "Inlägg"; "Scene.Favorite.Title" = "Omat suosikit"; "Scene.Follower.Footer" = "Seuraajia muilta palvelimilta ei näytetä."; "Scene.Following.Footer" = "Seurauksia muilta palvelimilta ei näytetä."; @@ -216,43 +217,43 @@ uploaded to Mastodon."; "Scene.HomeTimeline.Title" = "Koti"; "Scene.Notification.Keyobard.ShowEverything" = "Näytä kaikki"; "Scene.Notification.Keyobard.ShowMentions" = "Näytä maininnat"; -"Scene.Notification.NotificationDescription.FavoritedYourPost" = "favorited your post"; -"Scene.Notification.NotificationDescription.FollowedYou" = "followed you"; +"Scene.Notification.NotificationDescription.FavoritedYourPost" = "favoriserade ditt inlägg"; +"Scene.Notification.NotificationDescription.FollowedYou" = "följde dig"; "Scene.Notification.NotificationDescription.MentionedYou" = "nämnde dig"; -"Scene.Notification.NotificationDescription.PollHasEnded" = "poll has ended"; -"Scene.Notification.NotificationDescription.RebloggedYourPost" = "reblogged your post"; -"Scene.Notification.NotificationDescription.RequestToFollowYou" = "request to follow you"; +"Scene.Notification.NotificationDescription.PollHasEnded" = "omröstningen har avslutats"; +"Scene.Notification.NotificationDescription.RebloggedYourPost" = "ompostade ditt inlägg"; +"Scene.Notification.NotificationDescription.RequestToFollowYou" = "begär att följa dig"; "Scene.Notification.Title.Everything" = "Kaikki"; "Scene.Notification.Title.Mentions" = "Maininnat"; "Scene.Preview.Keyboard.ClosePreview" = "Sulje esikatselu"; "Scene.Preview.Keyboard.ShowNext" = "Näytä seuraava"; "Scene.Preview.Keyboard.ShowPrevious" = "Näytä edellinen"; -"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Double tap to open the list"; -"Scene.Profile.Accessibility.EditAvatarImage" = "Edit avatar image"; -"Scene.Profile.Accessibility.ShowAvatarImage" = "Show avatar image"; -"Scene.Profile.Accessibility.ShowBannerImage" = "Show banner image"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Dubbeltryck för att öppna listan"; +"Scene.Profile.Accessibility.EditAvatarImage" = "Redigera profilbild"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "Visa profilbild"; +"Scene.Profile.Accessibility.ShowBannerImage" = "Visa banner"; "Scene.Profile.Dashboard.Followers" = "seuraajat"; "Scene.Profile.Dashboard.Following" = "seurataan"; "Scene.Profile.Dashboard.Posts" = "julkaisut"; "Scene.Profile.Fields.AddRow" = "Lisää rivi"; "Scene.Profile.Fields.Placeholder.Content" = "Sisältö"; "Scene.Profile.Fields.Placeholder.Label" = "Nimi"; -"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Message" = "Confirm to block %@"; -"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Title" = "Block Account"; -"Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Message" = "Confirm to mute %@"; -"Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Title" = "Mute Account"; -"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Message" = "Confirm to unblock %@"; -"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Title" = "Unblock Account"; +"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Message" = "Bekräfta för att blockera %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Title" = "Blockera konto"; +"Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Message" = "Bekräfta för att tysta %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Title" = "Tysta konto"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Message" = "Bekräfta för att avblockera %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Title" = "Avblockera konto"; "Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Message" = "Vahvista, että haluat poistaa mykistyksen tililtä %@"; "Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Title" = "Poista tilin mykistys"; "Scene.Profile.SegmentedControl.About" = "Om"; "Scene.Profile.SegmentedControl.Media" = "Media"; "Scene.Profile.SegmentedControl.Posts" = "Julkaisut"; -"Scene.Profile.SegmentedControl.PostsAndReplies" = "Posts and Replies"; +"Scene.Profile.SegmentedControl.PostsAndReplies" = "Inlägg och svar"; "Scene.Profile.SegmentedControl.Replies" = "Vastaukset"; "Scene.Register.Error.Item.Agreement" = "Hyväksy"; "Scene.Register.Error.Item.Email" = "Sähköposti"; -"Scene.Register.Error.Item.Locale" = "Locale"; +"Scene.Register.Error.Item.Locale" = "Språk"; "Scene.Register.Error.Item.Password" = "Salasana"; "Scene.Register.Error.Item.Reason" = "Syy"; "Scene.Register.Error.Item.Username" = "Käyttäjänimi"; @@ -261,7 +262,7 @@ uploaded to Mastodon."; "Scene.Register.Error.Reason.Blocked" = "%@ sisältää estetyn sähköpostipalveluntarjoajan"; "Scene.Register.Error.Reason.Inclusion" = "%@ ei ole tuettu arvo"; "Scene.Register.Error.Reason.Invalid" = "%@ on virheellinen"; -"Scene.Register.Error.Reason.Reserved" = "%@ is a reserved keyword"; +"Scene.Register.Error.Reason.Reserved" = "%@ är ett reserverat nyckelord"; "Scene.Register.Error.Reason.Taken" = "%@ on jo käytössä"; "Scene.Register.Error.Reason.TooLong" = "%@ on liian pitkä"; "Scene.Register.Error.Reason.TooShort" = "%@ on liian lyhyt"; @@ -274,26 +275,26 @@ uploaded to Mastodon."; "Scene.Register.Input.DisplayName.Placeholder" = "näyttönimi"; "Scene.Register.Input.Email.Placeholder" = "sähköposti"; "Scene.Register.Input.Invite.RegistrationUserInviteRequest" = "Miksi haluat liittyä?"; -"Scene.Register.Input.Password.Accessibility.Checked" = "checked"; -"Scene.Register.Input.Password.Accessibility.Unchecked" = "unchecked"; -"Scene.Register.Input.Password.CharacterLimit" = "8 characters"; +"Scene.Register.Input.Password.Accessibility.Checked" = "markerad"; +"Scene.Register.Input.Password.Accessibility.Unchecked" = "avmarkerad"; +"Scene.Register.Input.Password.CharacterLimit" = "8 tecken"; "Scene.Register.Input.Password.Hint" = "Salasanassasi on oltava vähintään kahdeksan merkkiä"; "Scene.Register.Input.Password.Placeholder" = "salasana"; -"Scene.Register.Input.Password.Require" = "Your password needs at least:"; +"Scene.Register.Input.Password.Require" = "Ditt lösenord behöver minst:"; "Scene.Register.Input.Username.DuplicatePrompt" = "Tämä käyttäjänimi on varattu."; "Scene.Register.Input.Username.Placeholder" = "käyttäjänimi"; "Scene.Register.Title" = "Kerro meille sinusta."; "Scene.Report.Content1" = "Onko julkaisuja, joita haluaisit lisätä ilmiantoon?"; "Scene.Report.Content2" = "Onko valvojien syytä tietää tästä ilmiannosta?"; -"Scene.Report.ReportSentTitle" = "Thanks for reporting, we’ll look into this."; -"Scene.Report.Reported" = "REPORTED"; +"Scene.Report.ReportSentTitle" = "Tack för din rapport, vi ska titta på det."; +"Scene.Report.Reported" = "RAPPORTERAD"; "Scene.Report.Send" = "Lähetä ilmianto"; "Scene.Report.SkipToSend" = "Lähetä ilman kommentteja"; "Scene.Report.Step1" = "Vaihe 1/2"; "Scene.Report.Step2" = "Vaihe 2/2"; "Scene.Report.TextPlaceholder" = "Kirjoita tai liitä lisäkommentteja"; "Scene.Report.Title" = "Ilmianna %@"; -"Scene.Report.TitleReport" = "Report"; +"Scene.Report.TitleReport" = "Rapportera"; "Scene.Search.Recommend.Accounts.Description" = "Haluta ehkä seurata näitä tilejä"; "Scene.Search.Recommend.Accounts.Follow" = "Seuraa"; "Scene.Search.Recommend.Accounts.Title" = "Saatat pitää näistä tileistä"; @@ -334,8 +335,8 @@ uploaded to Mastodon."; "Scene.ServerPicker.Label.Category" = "KATEGORIA"; "Scene.ServerPicker.Label.Language" = "KIELI"; "Scene.ServerPicker.Label.Users" = "TILIÄ"; -"Scene.ServerPicker.Subtitle" = "Pick a community based on your interests, region, or a general purpose one."; -"Scene.ServerPicker.SubtitleExtend" = "Pick a community based on your interests, region, or a general purpose one. Each community is operated by an entirely independent organization or individual."; +"Scene.ServerPicker.Subtitle" = "Välj en gemenskap baserad på dina intressen, region eller ett allmänt syfte."; +"Scene.ServerPicker.SubtitleExtend" = "Välj en gemenskap baserad på dina intressen, region eller ett allmänt syfte. Varje gemenskap drivs av en helt oberoende organisation eller individ."; "Scene.ServerPicker.Title" = "Valitse palvelin, mikä tahansa palvelin."; "Scene.ServerRules.Button.Confirm" = "Hyväksyn"; @@ -355,12 +356,12 @@ mikä tahansa palvelin."; "Scene.Settings.Section.BoringZone.Terms" = "Palveluehdot"; "Scene.Settings.Section.BoringZone.Title" = "Tylsä alue"; "Scene.Settings.Section.LookAndFeel.Light" = "Ljust"; -"Scene.Settings.Section.LookAndFeel.ReallyDark" = "Really Dark"; -"Scene.Settings.Section.LookAndFeel.SortaDark" = "Sorta Dark"; -"Scene.Settings.Section.LookAndFeel.Title" = "Look and Feel"; -"Scene.Settings.Section.LookAndFeel.UseSystem" = "Use System"; +"Scene.Settings.Section.LookAndFeel.ReallyDark" = "Verkligen mörk"; +"Scene.Settings.Section.LookAndFeel.SortaDark" = "Ganska mörk"; +"Scene.Settings.Section.LookAndFeel.Title" = "Utseende och känsla"; +"Scene.Settings.Section.LookAndFeel.UseSystem" = "Följ systeminställningarna"; "Scene.Settings.Section.Notifications.Boosts" = "Omien julkaisujen edelleen jaot"; -"Scene.Settings.Section.Notifications.Favorites" = "Favorites my post"; +"Scene.Settings.Section.Notifications.Favorites" = "Favoriserar mitt inlägg"; "Scene.Settings.Section.Notifications.Follows" = "Seuraa minua"; "Scene.Settings.Section.Notifications.Mentions" = "Mainitsee minut"; "Scene.Settings.Section.Notifications.Title" = "Ilmoitukset"; @@ -371,7 +372,7 @@ mikä tahansa palvelin."; "Scene.Settings.Section.Notifications.Trigger.Title" = "Ilmoita minulle, kun"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Poista käytöstä animoidut avatarit"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Poista käytöstä animoidut emojit"; -"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Open links in Mastodon"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Öppna länkar i Mastodon"; "Scene.Settings.Section.Preference.Title" = "Lisäasetukset"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "Todellinen mustan tumma tila"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Käytä oletusselainta linkkien avaamiseen"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/sv_FI.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/sv_FI.lproj/Localizable.stringsdict index 43231214a..091c8555e 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/sv_FI.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/sv_FI.lproj/Localizable.stringsdict @@ -125,9 +125,9 @@ NSStringFormatValueTypeKey ld one - 1 reply + 1 svar other - %ld replies + %ld svar plural.count.vote diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings index a9846e8e2..1ceff03a2 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings @@ -202,6 +202,7 @@ "Scene.ConfirmEmail.Subtitle" = "แตะลิงก์ที่เราส่งอีเมลถึงคุณเพื่อยืนยันบัญชีของคุณ"; "Scene.ConfirmEmail.Title" = "หนึ่งสิ่งสุดท้าย"; "Scene.Discovery.Intro" = "นี่คือโพสต์ที่กำลังได้รับความสนใจในมุมของ Mastodon ของคุณ"; +"Scene.Discovery.Tabs.Community" = "Community"; "Scene.Discovery.Tabs.ForYou" = "สำหรับคุณ"; "Scene.Discovery.Tabs.Hashtags" = "แฮชแท็ก"; "Scene.Discovery.Tabs.News" = "ข่าว"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.strings index 3b853cd6b..d7853fa79 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.strings @@ -119,7 +119,7 @@ Vui lòng kiểm tra kết nối mạng."; "Common.Controls.Status.Tag.Url" = "URL"; "Common.Controls.Status.TapToReveal" = "Nhấn để xem"; "Common.Controls.Status.UserReblogged" = "%@ đăng lại"; -"Common.Controls.Status.UserRepliedTo" = "Trả lời %@"; +"Common.Controls.Status.UserRepliedTo" = "Trả lời đến %@"; "Common.Controls.Status.Visibility.Direct" = "Chỉ người được nhắc đến có thể thấy tút."; "Common.Controls.Status.Visibility.Private" = "Chỉ người theo dõi của họ có thể thấy tút này."; "Common.Controls.Status.Visibility.PrivateFromMe" = "Chỉ người theo dõi tôi có thể thấy tút này."; @@ -202,6 +202,7 @@ tải lên Mastodon."; "Scene.ConfirmEmail.Subtitle" = "Nhấn vào liên kết chúng tôi gửi qua email để xác thực tài khoản."; "Scene.ConfirmEmail.Title" = "Còn điều này nữa."; "Scene.Discovery.Intro" = "Đây là những tút thu hút được sự chú ý trong góc Mastodon của bạn."; +"Scene.Discovery.Tabs.Community" = "Máy chủ"; "Scene.Discovery.Tabs.ForYou" = "Dành cho bạn"; "Scene.Discovery.Tabs.Hashtags" = "Hashtag"; "Scene.Discovery.Tabs.News" = "Tin tức"; @@ -330,13 +331,13 @@ tải lên Mastodon."; "Scene.ServerPicker.EmptyState.BadNetwork" = "Đã xảy ra lỗi. Hãy thử lại hoặc kiểm tra kết nối internet của bạn."; "Scene.ServerPicker.EmptyState.FindingServers" = "Đang tìm máy chủ hoạt động..."; "Scene.ServerPicker.EmptyState.NoResults" = "Không có kết quả"; -"Scene.ServerPicker.Input.Placeholder" = "Tìm cộng đồng"; +"Scene.ServerPicker.Input.Placeholder" = "Tìm máy chủ"; "Scene.ServerPicker.Label.Category" = "PHÂN LOẠI"; "Scene.ServerPicker.Label.Language" = "NGÔN NGỮ"; "Scene.ServerPicker.Label.Users" = "NGƯỜI DÙNG"; -"Scene.ServerPicker.Subtitle" = "Chọn một cộng đồng dựa theo sở thích, tôn giáo, hoặc ý muốn của bạn."; -"Scene.ServerPicker.SubtitleExtend" = "Chọn một cộng đồng dựa theo sở thích, tôn giáo, hoặc ý muốn của bạn. Mỗi cộng đồng có thể được vận hành bởi một tổ chức độc lập hoặc một cá nhân."; -"Scene.ServerPicker.Title" = "Mastodon gồm nhiều cộng đồng với nhiều thành viên khác nhau."; +"Scene.ServerPicker.Subtitle" = "Chọn một máy chủ dựa theo sở thích, tôn giáo, hoặc ý muốn của bạn."; +"Scene.ServerPicker.SubtitleExtend" = "Chọn một máy chủ dựa theo sở thích, tôn giáo, hoặc ý muốn của bạn. Mỗi máy chủ có thể được vận hành bởi một cá nhân hoặc một tổ chức."; +"Scene.ServerPicker.Title" = "Mastodon gồm nhiều máy chủ với thành viên riêng."; "Scene.ServerRules.Button.Confirm" = "Tôi đồng ý"; "Scene.ServerRules.PrivacyPolicy" = "chính sách bảo mật"; "Scene.ServerRules.Prompt" = "Tiếp tục nghĩa là bạn đồng ý điều khoản dịch vụ và chính sách bảo mật của %@."; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.strings index f0c67ec23..438747344 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.strings @@ -203,6 +203,7 @@ 点击链接确认你的帐户。"; "Scene.ConfirmEmail.Title" = "最后一件事。"; "Scene.Discovery.Intro" = "这些嘟文在你的长毛象小宇宙中备受关注。"; +"Scene.Discovery.Tabs.Community" = "社区"; "Scene.Discovery.Tabs.ForYou" = "为你推荐"; "Scene.Discovery.Tabs.Hashtags" = "话题标签"; "Scene.Discovery.Tabs.News" = "最新消息"; From 23eeaab465c8b369744c7641d615d53044c18f56 Mon Sep 17 00:00:00 2001 From: Marcus Kida Date: Fri, 29 Apr 2022 09:06:28 +0200 Subject: [PATCH 047/101] feat: use bundler to install Ruby Gems instead of installing them system-wide using root --- .github/scripts/setup.sh | 12 +++-- Documentation/Setup.md | 14 ++--- Gemfile | 6 +++ Gemfile.lock | 109 +++++++++++++++++++++++++++++++++++++++ update_localization.sh | 2 +- 5 files changed, 132 insertions(+), 11 deletions(-) create mode 100644 Gemfile create mode 100644 Gemfile.lock diff --git a/.github/scripts/setup.sh b/.github/scripts/setup.sh index 0c2612d51..f5934be0c 100755 --- a/.github/scripts/setup.sh +++ b/.github/scripts/setup.sh @@ -1,9 +1,13 @@ #!/bin/bash -sudo gem install cocoapods-keys +# Install Ruby Bundler +sudo gem install bundler:2.3.11 + +# Install Ruby Gems +bundle install # stub keys. DO NOT use in production -pod keys set notification_endpoint "" -pod keys set notification_endpoint_debug "" +bundle exec pod keys set notification_endpoint "" +bundle exec pod keys set notification_endpoint_debug "" -pod install +bundle exec pod install diff --git a/Documentation/Setup.md b/Documentation/Setup.md index ede9d4862..b17a9db8e 100644 --- a/Documentation/Setup.md +++ b/Documentation/Setup.md @@ -12,12 +12,13 @@ Intell the latest version of Xcode from the App Store or Apple Developer Downloa This guide may not suit your machine and actually setup procedure may change in the future. Please file the issue or Pull Request if there are any problems. ## CocoaPods -The app use [CocoaPods]() and [CocoaPods-Keys](https://github.com/orta/cocoapods-keys). The M1 Mac needs virtual ruby env to workaround compatibility issues. +The app use [CocoaPods]() and [CocoaPods-Keys](https://github.com/orta/cocoapods-keys). Ruby Gems are managed through Bundler. The M1 Mac needs virtual ruby env to workaround compatibility issues. #### Intel Mac ```zsh -sudo gem install cocoapods cocoapods-keys +sudo gem install bundler +bundle install ``` #### M1 Mac @@ -40,18 +41,19 @@ rbenv global 3.0.3 ruby --version # > ruby 3.0.3p157 (2021-11-24 revision 3fb7d2cadc) [arm64-darwin21] -sudo gem install cocoapods cocoapods-keys +sudo gem install bundler +bundle install ``` ## Bootstrap ```zsh # make a clean build -sudo gem install cocoapods-clean -pod clean +bundle install +bundle exec pod clean # make install -pod install --repo-update +bundle exec pod install --repo-update # open workspace open Mastodon.xcworkspace diff --git a/Gemfile b/Gemfile new file mode 100644 index 000000000..48aae3d82 --- /dev/null +++ b/Gemfile @@ -0,0 +1,6 @@ +source "https://rubygems.org" + +gem "cocoapods" +gem "cocoapods-clean" +gem "cocoapods-keys" + diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 000000000..b27a44a97 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,109 @@ +GEM + remote: https://rubygems.org/ + specs: + CFPropertyList (3.0.5) + rexml + RubyInline (3.12.5) + ZenTest (~> 4.3) + ZenTest (4.12.1) + activesupport (6.1.5.1) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + zeitwerk (~> 2.3) + addressable (2.8.0) + public_suffix (>= 2.0.2, < 5.0) + algoliasearch (1.27.5) + httpclient (~> 2.8, >= 2.8.3) + json (>= 1.5.1) + atomos (0.1.3) + claide (1.1.0) + cocoapods (1.11.3) + addressable (~> 2.8) + claide (>= 1.0.2, < 2.0) + cocoapods-core (= 1.11.3) + cocoapods-deintegrate (>= 1.0.3, < 2.0) + cocoapods-downloader (>= 1.4.0, < 2.0) + cocoapods-plugins (>= 1.0.0, < 2.0) + cocoapods-search (>= 1.0.0, < 2.0) + cocoapods-trunk (>= 1.4.0, < 2.0) + cocoapods-try (>= 1.1.0, < 2.0) + colored2 (~> 3.1) + escape (~> 0.0.4) + fourflusher (>= 2.3.0, < 3.0) + gh_inspector (~> 1.0) + molinillo (~> 0.8.0) + nap (~> 1.0) + ruby-macho (>= 1.0, < 3.0) + xcodeproj (>= 1.21.0, < 2.0) + cocoapods-clean (0.0.1) + cocoapods-core (1.11.3) + activesupport (>= 5.0, < 7) + addressable (~> 2.8) + algoliasearch (~> 1.0) + concurrent-ruby (~> 1.1) + fuzzy_match (~> 2.0.4) + nap (~> 1.0) + netrc (~> 0.11) + public_suffix (~> 4.0) + typhoeus (~> 1.0) + cocoapods-deintegrate (1.0.5) + cocoapods-downloader (1.6.3) + cocoapods-keys (2.2.1) + dotenv + osx_keychain + cocoapods-plugins (1.0.0) + nap + cocoapods-search (1.0.1) + cocoapods-trunk (1.6.0) + nap (>= 0.8, < 2.0) + netrc (~> 0.11) + cocoapods-try (1.2.0) + colored2 (3.1.2) + concurrent-ruby (1.1.10) + dotenv (2.7.6) + escape (0.0.4) + ethon (0.15.0) + ffi (>= 1.15.0) + ffi (1.15.5) + fourflusher (2.3.1) + fuzzy_match (2.0.4) + gh_inspector (1.1.3) + httpclient (2.8.3) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + json (2.6.1) + minitest (5.15.0) + molinillo (0.8.0) + nanaimo (0.3.0) + nap (1.1.0) + netrc (0.11.0) + osx_keychain (1.0.2) + RubyInline (~> 3) + public_suffix (4.0.7) + rexml (3.2.5) + ruby-macho (2.5.1) + typhoeus (1.4.0) + ethon (>= 0.9.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + xcodeproj (1.21.0) + CFPropertyList (>= 2.3.3, < 4.0) + atomos (~> 0.1.3) + claide (>= 1.0.2, < 2.0) + colored2 (~> 3.1) + nanaimo (~> 0.3.0) + rexml (~> 3.2.4) + zeitwerk (2.5.4) + +PLATFORMS + ruby + +DEPENDENCIES + cocoapods + cocoapods-clean + cocoapods-keys + +BUNDLED WITH + 2.3.11 diff --git a/update_localization.sh b/update_localization.sh index b234cd933..09cfc21d6 100755 --- a/update_localization.sh +++ b/update_localization.sh @@ -21,7 +21,7 @@ echo "${PODS_ROOT}/SwiftGen/bin/swiftgen" if [[ -f "${PODS_ROOT}/SwiftGen/bin/swiftgen" ]] then "${PODS_ROOT}/SwiftGen/bin/swiftgen" else - echo "Run 'pod install' or update your CocoaPods installation." + echo "Run 'bundle exec pod install' or update your CocoaPods installation." fi #task 4 clean temp file From 64a87a7aab2195df8ccbb0228c871d2a96205ab4 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 29 Apr 2022 15:25:39 +0800 Subject: [PATCH 048/101] feat: add Sorani (Kurdish) language --- .../Sources/StringsConvertor/main.swift | 1 + Mastodon.xcodeproj/project.pbxproj | 7 + .../xcschemes/xcschememanagement.plist | 4 +- .../Resources/ckb.lproj/InfoPlist.strings | 4 + MastodonIntent/ckb.lproj/Intents.strings | 51 +++ MastodonIntent/ckb.lproj/Intents.stringsdict | 54 +++ .../Resources/ckb.lproj/Localizable.strings | 391 +++++++++++++++++ .../ckb.lproj/Localizable.stringsdict | 406 ++++++++++++++++++ 8 files changed, 916 insertions(+), 2 deletions(-) create mode 100644 Mastodon/Resources/ckb.lproj/InfoPlist.strings create mode 100644 MastodonIntent/ckb.lproj/Intents.strings create mode 100644 MastodonIntent/ckb.lproj/Intents.stringsdict create mode 100644 MastodonSDK/Sources/MastodonLocalization/Resources/ckb.lproj/Localizable.strings create mode 100644 MastodonSDK/Sources/MastodonLocalization/Resources/ckb.lproj/Localizable.stringsdict diff --git a/Localization/StringsConvertor/Sources/StringsConvertor/main.swift b/Localization/StringsConvertor/Sources/StringsConvertor/main.swift index 92a858829..6604884a4 100644 --- a/Localization/StringsConvertor/Sources/StringsConvertor/main.swift +++ b/Localization/StringsConvertor/Sources/StringsConvertor/main.swift @@ -60,6 +60,7 @@ private func map(language: String) -> String? { case "kmr_TR": return "ku" // Kurmanji (Kurdish) case "ru_RU": return "ru" // Russian case "gd_GB": return "gd-GB" // Scottish Gaelic + case "ckb_IR": return "ckb" // Sorani (Kurdish) case "es_ES": return "es" // Spanish case "es_AR": return "es-419" // Spanish, Argentina case "sv-SE": return "sv" // Swedish diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 2795f6148..f2eeb9e37 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -1027,6 +1027,9 @@ DB4F097E26A03DA600D62E92 /* SearchHistoryFetchedResultController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchHistoryFetchedResultController.swift; sourceTree = ""; }; DB4FFC29269EC39600D62E92 /* SearchToSearchDetailViewControllerAnimatedTransitioning.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchToSearchDetailViewControllerAnimatedTransitioning.swift; sourceTree = ""; }; DB4FFC2A269EC39600D62E92 /* SearchTransitionController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchTransitionController.swift; sourceTree = ""; }; + DB519B09281BCA2E00F0C99D /* ckb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ckb; path = ckb.lproj/Intents.strings; sourceTree = ""; }; + DB519B0A281BCA2E00F0C99D /* ckb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ckb; path = ckb.lproj/InfoPlist.strings; sourceTree = ""; }; + DB519B0B281BCA4300F0C99D /* ckb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ckb; path = ckb.lproj/Intents.stringsdict; sourceTree = ""; }; DB51D170262832380062B7A1 /* BlurHashDecode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlurHashDecode.swift; sourceTree = ""; }; DB51D171262832380062B7A1 /* BlurHashEncode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlurHashEncode.swift; sourceTree = ""; }; DB564BD2269F3B35001E39A7 /* StatusFilterService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusFilterService.swift; sourceTree = ""; }; @@ -3518,6 +3521,7 @@ kab, vi, sv, + ckb, ); mainGroup = DB427DC925BAA00100D1B89D; packageReferences = ( @@ -4463,6 +4467,7 @@ DBF81C7427F68F5A00004A56 /* kab */, DBF81C7727F6913300004A56 /* vi */, DB8D8E3128196FA0009FD90F /* sv */, + DB519B09281BCA2E00F0C99D /* ckb */, ); name = Intents.intentdefinition; sourceTree = ""; @@ -4489,6 +4494,7 @@ DBF81C7527F68F5A00004A56 /* kab */, DBF81C7827F6913300004A56 /* vi */, DB8D8E3228196FA0009FD90F /* sv */, + DB519B0A281BCA2E00F0C99D /* ckb */, ); name = InfoPlist.strings; sourceTree = ""; @@ -4531,6 +4537,7 @@ DBF81C7627F68F5A00004A56 /* kab */, DBF81C7927F6913300004A56 /* vi */, DB8D8E3328196FA0009FD90F /* sv */, + DB519B0B281BCA4300F0C99D /* ckb */, ); name = Intents.stringsdict; sourceTree = ""; diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 640adb736..528a75b66 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 19 + 20 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 20 + 19 SuppressBuildableAutocreation diff --git a/Mastodon/Resources/ckb.lproj/InfoPlist.strings b/Mastodon/Resources/ckb.lproj/InfoPlist.strings new file mode 100644 index 000000000..710865573 --- /dev/null +++ b/Mastodon/Resources/ckb.lproj/InfoPlist.strings @@ -0,0 +1,4 @@ +"NSCameraUsageDescription" = "Used to take photo for post status"; +"NSPhotoLibraryAddUsageDescription" = "Used to save photo into the Photo Library"; +"NewPostShortcutItemTitle" = "New Post"; +"SearchShortcutItemTitle" = "Search"; \ No newline at end of file diff --git a/MastodonIntent/ckb.lproj/Intents.strings b/MastodonIntent/ckb.lproj/Intents.strings new file mode 100644 index 000000000..1d23253a3 --- /dev/null +++ b/MastodonIntent/ckb.lproj/Intents.strings @@ -0,0 +1,51 @@ +"16wxgf" = "پۆستێک بکە"; + +"751xkl" = "نووسین"; + +"CsR7G2" = "پۆستێک بکە"; + +"HZSGTr" = "چی پۆست بکرێت؟"; + +"HdGikU" = "پۆستکردنەکە سەرکەوتوو نەبوو"; + +"KDNTJ4" = "هۆکاری سەرنەکەوتن"; + +"RHxKOw" = "پۆست بە نووسینەوە بکە"; + +"RxSqsb" = "پۆست"; + +"WCIR3D" = "${content} لە ماستۆدۆن پۆست بکە"; + +"ZKJSNu" = "پۆست"; + +"ZS1XaK" = "${content}"; + +"ZbSjzC" = "دەرکەوتن"; + +"Zo4jgJ" = "دەرکەوتنی پۆست"; + +"apSxMG-dYQ5NN" = "${count} بژاردە بۆ 'گشتی' هەن."; + +"apSxMG-ehFLjY" = "${count} بژاردە بۆ 'تەنیا شوێنکەوتووەکان' هەن."; + +"ayoYEb-dYQ5NN" = "${content}، گشتی"; + +"ayoYEb-ehFLjY" = "${content}، تەنیا شوێنکەوتووەکان"; + +"dUyuGg" = "پۆستێک بکە"; + +"dYQ5NN" = "گشتی"; + +"ehFLjY" = "تەنیا شوێنکەوتووەکان"; + +"gfePDu" = "پۆستکردنەکە سەرکەوتوو نەبوو. ${failureReason}"; + +"k7dbKQ" = "پۆستەکە کرا."; + +"oGiqmY-dYQ5NN" = "دڵنیایت لە هەڵبژاردنی 'گشتی'؟"; + +"oGiqmY-ehFLjY" = "دڵنیایت لە هەڵبژاردنی 'تەنیا شوێنکەوتووەکان'؟"; + +"rM6dvp" = "بەستەر"; + +"ryJLwG" = "پۆستەکە کرا. "; diff --git a/MastodonIntent/ckb.lproj/Intents.stringsdict b/MastodonIntent/ckb.lproj/Intents.stringsdict new file mode 100644 index 000000000..5a39d5e64 --- /dev/null +++ b/MastodonIntent/ckb.lproj/Intents.stringsdict @@ -0,0 +1,54 @@ + + + + + There are ${count} options matching ‘${content}’. - 2 + + NSStringLocalizedFormatKey + There are %#@count_option@ matching ‘${content}’. + count_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + %ld + zero + 0 options + one + 1 option + two + 2 options + few + %ld options + many + %ld options + other + %ld options + + + There are ${count} options matching ‘${visibility}’. + + NSStringLocalizedFormatKey + There are %#@count_option@ matching ‘${visibility}’. + count_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + %ld + zero + 0 options + one + 1 option + two + 2 options + few + %ld options + many + %ld options + other + %ld options + + + + diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ckb.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ckb.lproj/Localizable.strings new file mode 100644 index 000000000..1db4f7936 --- /dev/null +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ckb.lproj/Localizable.strings @@ -0,0 +1,391 @@ +"Common.Alerts.BlockDomain.BlockEntireDomain" = "هەموو ڕاژەکارەکە ئاستەنگ بکە"; +"Common.Alerts.BlockDomain.Title" = "دڵنیایت دەتەوێت تەواوی %@ ئاستەنگ بکەیت؟ لە زۆر بارەکاندا ئاستەنگکردنی بچووک باشترە. ئەگەر وا بکەیت، لەو ڕاژەکارەوە هیچ شتێک نابینیت و هەموو شوێنکەوتووەکانت لەوێوە لادەبرێن."; +"Common.Alerts.CleanCache.Message" = "سەرکەوتووانە بیرگەی %@ پاک کرایەوە."; +"Common.Alerts.CleanCache.Title" = "بیرگە پاک بکەوە"; +"Common.Alerts.Common.PleaseTryAgain" = "تکایە دووبارە هەوڵ بدەوە."; +"Common.Alerts.Common.PleaseTryAgainLater" = "تکایە دواتر هەوڵ بدەوە."; +"Common.Alerts.DeletePost.Message" = "دڵنیایت دەتەوێت ئەم پۆستە بسڕیتەوە؟"; +"Common.Alerts.DeletePost.Title" = "بیسڕەوە"; +"Common.Alerts.DiscardPostContent.Message" = "دڵنیا ببەوە بۆ وازهێنان لە ناوەڕۆکەت."; +"Common.Alerts.DiscardPostContent.Title" = "ڕەشنووس هەڵمەگرە"; +"Common.Alerts.EditProfileFailure.Message" = "ناتوانرێت دەستکاریی پرۆفایل بکرێت. تکایە دووبارە هەوڵ بدەوە."; +"Common.Alerts.EditProfileFailure.Title" = "نەتوانرا دەستکاریی پرۆفایل بکرێت"; +"Common.Alerts.PublishPostFailure.AttachmentsMessage.MoreThanOneVideo" = "ناتوانیت زیاتر لە یەک ڤیدیۆی پێوە بلکێنیت."; +"Common.Alerts.PublishPostFailure.AttachmentsMessage.VideoAttachWithPhoto" = "ناتوانیت ڤیدیۆ بۆ پۆستێک زیاد بکەیت کە وێنەی تێدایە."; +"Common.Alerts.PublishPostFailure.Message" = "نەتوانرا پۆستەکە بکرێت. +تکایە لە بەردەستبوونی هێڵی ئینتەرنێت دڵنیا بە."; +"Common.Alerts.PublishPostFailure.Title" = "نەتوانرا پۆستەکە بکرێت"; +"Common.Alerts.SavePhotoFailure.Message" = "تکایە ڕێ بە ماستۆدۆن بدە تاوەکو بتوانێت وێنەکە هەڵبگرێت."; +"Common.Alerts.SavePhotoFailure.Title" = "نەتوانرا وێنەکە هەڵبگیرێت"; +"Common.Alerts.ServerError.Title" = "هەڵەی ڕاژەکار"; +"Common.Alerts.SignOut.Confirm" = "دەربچۆ"; +"Common.Alerts.SignOut.Message" = "دڵنیایت دەتەوێت دەربچیت؟"; +"Common.Alerts.SignOut.Title" = "دەربچۆ"; +"Common.Alerts.SignUpFailure.Title" = "تۆمارکردنەکە سەرکەوتوو نەبوو"; +"Common.Alerts.VoteFailure.PollEnded" = "دەنگدانەکە کۆتایی هاتووە"; +"Common.Alerts.VoteFailure.Title" = "نەتوانرا دەنگ بدرێت"; +"Common.Controls.Actions.Add" = "زیادی بکە"; +"Common.Controls.Actions.Back" = "بگەڕێوە"; +"Common.Controls.Actions.BlockDomain" = "%@ ئاستەنگ بکە"; +"Common.Controls.Actions.Cancel" = "هەڵوەشاندنەوه"; +"Common.Controls.Actions.Compose" = "پۆست بکە"; +"Common.Controls.Actions.Confirm" = "پشتڕاستی بکەوە"; +"Common.Controls.Actions.Continue" = "بەردەوام بە"; +"Common.Controls.Actions.CopyPhoto" = "لەبەری بگرەوە"; +"Common.Controls.Actions.Delete" = "بیسڕەوە"; +"Common.Controls.Actions.Discard" = "وازی لێ بێنە"; +"Common.Controls.Actions.Done" = "تەواو"; +"Common.Controls.Actions.Edit" = "دەستکاری"; +"Common.Controls.Actions.FindPeople" = "خەڵک بدۆزەوە"; +"Common.Controls.Actions.ManuallySearch" = "خۆت بگەڕێ"; +"Common.Controls.Actions.Next" = "دواتر"; +"Common.Controls.Actions.Ok" = "باشە"; +"Common.Controls.Actions.Open" = "بیکەوە"; +"Common.Controls.Actions.OpenInBrowser" = "لە وێبگەڕ بیکەوە"; +"Common.Controls.Actions.OpenInSafari" = "لە Safari بیکەوە"; +"Common.Controls.Actions.Preview" = "پێشبینین"; +"Common.Controls.Actions.Previous" = "پێشتر"; +"Common.Controls.Actions.Remove" = "لایبە"; +"Common.Controls.Actions.Reply" = "وەڵامی بدەوە"; +"Common.Controls.Actions.ReportUser" = "سکاڵا لە %@ بکە"; +"Common.Controls.Actions.Save" = "هەڵی بگرە"; +"Common.Controls.Actions.SavePhoto" = "هەڵی بگرە"; +"Common.Controls.Actions.SeeMore" = "زیاتر ببینە"; +"Common.Controls.Actions.Settings" = "رێکخستنەکان"; +"Common.Controls.Actions.Share" = "هاوبەشی بکە"; +"Common.Controls.Actions.SharePost" = "هاوبەشی بکە"; +"Common.Controls.Actions.ShareUser" = "%@ هاوبەش بکە"; +"Common.Controls.Actions.SignIn" = "بچۆ ژوورەوە"; +"Common.Controls.Actions.SignUp" = "خۆت تۆمار بکە"; +"Common.Controls.Actions.Skip" = "بیپەڕێنە"; +"Common.Controls.Actions.TakePhoto" = "وێنە بگرە"; +"Common.Controls.Actions.TryAgain" = "هەوڵ بدەوە"; +"Common.Controls.Actions.UnblockDomain" = "%@ ئاستەنگ مەکە"; +"Common.Controls.Friendship.Block" = "ئاستەنگی بکە"; +"Common.Controls.Friendship.BlockDomain" = "%@ ئاستەنگ بکە"; +"Common.Controls.Friendship.BlockUser" = "%@ ئاستەنگ بکە"; +"Common.Controls.Friendship.Blocked" = "ئاستەنگ کراوە"; +"Common.Controls.Friendship.EditInfo" = "دەستکاری"; +"Common.Controls.Friendship.Follow" = "شوێنی بکەوە"; +"Common.Controls.Friendship.Following" = "شوێنی دەکەویت"; +"Common.Controls.Friendship.Mute" = "بێدەنگی بکە"; +"Common.Controls.Friendship.MuteUser" = "%@ بێدەنگە"; +"Common.Controls.Friendship.Muted" = "بێدەنگ کراوە"; +"Common.Controls.Friendship.Pending" = "داوات کردووە"; +"Common.Controls.Friendship.Request" = "داوای لێ بکە"; +"Common.Controls.Friendship.Unblock" = "ئاستەنگی مەکە"; +"Common.Controls.Friendship.UnblockUser" = "%@ ئاستەنگ مەکە"; +"Common.Controls.Friendship.Unmute" = "بێدەنگی مەکە"; +"Common.Controls.Friendship.UnmuteUser" = "%@ بێدەنگ مەکە"; +"Common.Controls.Keyboard.Common.ComposeNewPost" = "پۆستێکی نوێ بکە"; +"Common.Controls.Keyboard.Common.OpenSettings" = "ڕێکخستنەکان بکەوە"; +"Common.Controls.Keyboard.Common.ShowFavorites" = "بەدڵبووەکان ببینە"; +"Common.Controls.Keyboard.Common.SwitchToTab" = "بڕۆ بۆ %@"; +"Common.Controls.Keyboard.SegmentedControl.NextSection" = "دەستنیشانکراوی دواتر"; +"Common.Controls.Keyboard.SegmentedControl.PreviousSection" = "بەشی پێشتر"; +"Common.Controls.Keyboard.Timeline.NextStatus" = "پۆستی دواتر"; +"Common.Controls.Keyboard.Timeline.OpenAuthorProfile" = "پرۆفایلەکەی بکەوە"; +"Common.Controls.Keyboard.Timeline.OpenRebloggerProfile" = "پرۆفایلەکەی بکەوە"; +"Common.Controls.Keyboard.Timeline.OpenStatus" = "بیکەوە"; +"Common.Controls.Keyboard.Timeline.PreviewImage" = "بیبینە"; +"Common.Controls.Keyboard.Timeline.PreviousStatus" = "پۆستی پێشتر"; +"Common.Controls.Keyboard.Timeline.ReplyStatus" = "وەڵامی بدەوە"; +"Common.Controls.Keyboard.Timeline.ToggleContentWarning" = "ئاگاداریی ناوەڕۆک نیشان بدە"; +"Common.Controls.Keyboard.Timeline.ToggleFavorite" = "بەدڵبوونی پۆست"; +"Common.Controls.Keyboard.Timeline.ToggleReblog" = "پۆستکردنەوەی پۆست"; +"Common.Controls.Status.Actions.Favorite" = "بەدڵمە"; +"Common.Controls.Status.Actions.Hide" = "بیشارەوە"; +"Common.Controls.Status.Actions.Menu" = "پێڕست"; +"Common.Controls.Status.Actions.Reblog" = "پۆستی بکەوە"; +"Common.Controls.Status.Actions.Reply" = "وەڵامی بدەوە"; +"Common.Controls.Status.Actions.ShowGif" = "گیفەکە نیشان بدە"; +"Common.Controls.Status.Actions.ShowImage" = "وێنەکە نیشان بدە"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "ڤیدیۆکە لێ بدە"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "دەستی پیا بنێ و بیگرە بۆ نیشاندانی پێڕستەکە"; +"Common.Controls.Status.Actions.Unfavorite" = "بەدڵبوونەکە بگەڕێنەوە"; +"Common.Controls.Status.Actions.Unreblog" = "پۆستکردنەکە بگەڕێنەوە"; +"Common.Controls.Status.ContentWarning" = "ئاگاداریی ناوەڕۆک"; +"Common.Controls.Status.MediaContentWarning" = "دەستی پیا بنێ بۆ نیشاندانی"; +"Common.Controls.Status.Poll.Closed" = "داخراوە"; +"Common.Controls.Status.Poll.Vote" = "دەنگ بدە"; +"Common.Controls.Status.SensitiveContent" = "ناوەڕۆکی هەستیار"; +"Common.Controls.Status.ShowPost" = "پۆستەکە نیشان بدە"; +"Common.Controls.Status.ShowUserProfile" = "پرۆفایلەکەی نیشان بدە"; +"Common.Controls.Status.Tag.Email" = "ئیمێڵ"; +"Common.Controls.Status.Tag.Emoji" = "ئیمۆجی"; +"Common.Controls.Status.Tag.Hashtag" = "هاشتاگ"; +"Common.Controls.Status.Tag.Link" = "بەستەر"; +"Common.Controls.Status.Tag.Mention" = "ئاماژە"; +"Common.Controls.Status.Tag.Url" = "بەستەر"; +"Common.Controls.Status.TapToReveal" = "دەستی پیا بنێ بۆ نیشاندانی"; +"Common.Controls.Status.UserReblogged" = "%@ پۆست کرایەوە"; +"Common.Controls.Status.UserRepliedTo" = "لە وەڵامدا بۆ %@"; +"Common.Controls.Status.Visibility.Direct" = "تەنیا بەکارهێنەرە ئاماژە پێکراوەکە دەتوانێت ئەم پۆستە ببینێت."; +"Common.Controls.Status.Visibility.Private" = "تەنیا شوێنکەوتووەکانی دەتوانن ئەم پۆستە ببینن."; +"Common.Controls.Status.Visibility.PrivateFromMe" = "تەنیا شوێنکەوتووەکانم دەتوانن ئەم پۆستە ببینن."; +"Common.Controls.Status.Visibility.Unlisted" = "هەرکەسێک دەتوانێت ئەم پۆستە ببینێت بەڵام ناچێتە بەردەمیان."; +"Common.Controls.Tabs.Home" = "ماڵەوە"; +"Common.Controls.Tabs.Notification" = "ئاگادارکردنەوەکان"; +"Common.Controls.Tabs.Profile" = "پرۆفایل"; +"Common.Controls.Tabs.Search" = "بگەڕێ"; +"Common.Controls.Timeline.Filtered" = "پاڵێوراو"; +"Common.Controls.Timeline.Header.BlockedWarning" = "ناتوانیت پرۆفایلی ئەم بەکارهێنەرە ببینیت +تا ئەو کاتەی ئاستەنگەکەت لادەبات."; +"Common.Controls.Timeline.Header.BlockingWarning" = "ناتوانیت پرۆفایلی ئەم بەکارهێنەرە ببینیت +هەتا ئاستەنگەکەیان لادەبەیت. +پرۆفایلەکەت ئاوها لایان دەردەکەوێت."; +"Common.Controls.Timeline.Header.NoStatusFound" = "هیچ پۆستێک نەدۆزرایەوە"; +"Common.Controls.Timeline.Header.SuspendedWarning" = "ئەم بەکارهێنەرە ڕاگیراوە."; +"Common.Controls.Timeline.Header.UserBlockedWarning" = "ناتوانیت پرۆفایلی %@ ببینیت +تا ئەو کاتەی ئاستەنگەکەت لادەبات."; +"Common.Controls.Timeline.Header.UserBlockingWarning" = "ناتوانیت پرۆفایلی %@ ببینیت +هەتا ئاستەنگەکەیان لادەبەیت. +پرۆفایلەکەت ئاوها لایان دەردەکەوێت."; +"Common.Controls.Timeline.Header.UserSuspendedWarning" = "هەژماری %@ ڕاگیراوە."; +"Common.Controls.Timeline.Loader.LoadMissingPosts" = "پۆستە ماوەکان بار بکە"; +"Common.Controls.Timeline.Loader.LoadingMissingPosts" = "پۆستە ماوەکان بار دەکرێن..."; +"Common.Controls.Timeline.Loader.ShowMoreReplies" = "وەڵامی زیاتر نیشان بدە"; +"Common.Controls.Timeline.Timestamp.Now" = "ئێستا"; +"Scene.AccountList.AddAccount" = "هەژمارێک زیاد بکە"; +"Scene.AccountList.DismissAccountSwitcher" = "پێڕستی هەژمارەکان دابخە"; +"Scene.AccountList.TabBarHint" = "هەژماری ئێستا: %@. دوو جا دەستی پیا بنێ بۆ کردنەوەی پێڕستی هەژمارەکان."; +"Scene.Compose.Accessibility.AppendAttachment" = "پێوەکراوی پێوە بکە"; +"Scene.Compose.Accessibility.AppendPoll" = "دەنگدان زیاد بکە"; +"Scene.Compose.Accessibility.CustomEmojiPicker" = "هەڵبژێری ئیمۆجی"; +"Scene.Compose.Accessibility.DisableContentWarning" = "ئاگاداریی ناوەڕۆک ناچالاک بکە"; +"Scene.Compose.Accessibility.EnableContentWarning" = "ئاگاداریی ناوەڕۆک چالاک بکە"; +"Scene.Compose.Accessibility.PostVisibilityMenu" = "پێڕستی شێوازی دەرکەوتنی پۆست"; +"Scene.Compose.Accessibility.RemovePoll" = "دانگدانەکە لابە"; +"Scene.Compose.Attachment.AttachmentBroken" = "ئەم %@ـە تێک چووە و ناتوانیت بەرزی بکەیتەوە."; +"Scene.Compose.Attachment.DescriptionPhoto" = "وێنەکەت بۆ نابیناکان باس بکە..."; +"Scene.Compose.Attachment.DescriptionVideo" = "ڤیدیۆکەت بۆ نابیناکان باس بکە..."; +"Scene.Compose.Attachment.Photo" = "وێنە"; +"Scene.Compose.Attachment.Video" = "ڤیدیۆ"; +"Scene.Compose.AutoComplete.SpaceToAdd" = "بۆشایی دابنێ بۆ زیادکردن"; +"Scene.Compose.ComposeAction" = "بڵاوی بکەوە"; +"Scene.Compose.ContentInputPlaceholder" = "دەتەوێت چی پۆست بکەیت؟"; +"Scene.Compose.ContentWarning.Placeholder" = "ئاگادارییەکەت لێرە بنووسە..."; +"Scene.Compose.Keyboard.AppendAttachmentEntry" = "پێوەکراوی پێوە بکە - %@"; +"Scene.Compose.Keyboard.DiscardPost" = "پۆستەکە هەڵوەشێنەوە"; +"Scene.Compose.Keyboard.PublishPost" = "پۆستە بڵاو بکەوە"; +"Scene.Compose.Keyboard.SelectVisibilityEntry" = "شێوازی دەرکەوتن هەڵبژێرە - %@"; +"Scene.Compose.Keyboard.ToggleContentWarning" = "ئاگاداریی ناوەڕۆک نیشان بدە"; +"Scene.Compose.Keyboard.TogglePoll" = "دەنگدانەکە نیشان بدە"; +"Scene.Compose.MediaSelection.Browse" = "بگەڕێ"; +"Scene.Compose.MediaSelection.Camera" = "وێنە بگرە"; +"Scene.Compose.MediaSelection.PhotoLibrary" = "وێنەکان"; +"Scene.Compose.Poll.DurationTime" = "کات:‌ %@"; +"Scene.Compose.Poll.OneDay" = "1 ڕۆژ"; +"Scene.Compose.Poll.OneHour" = "1 کاتژمێر"; +"Scene.Compose.Poll.OptionNumber" = "بژاردەی %ld"; +"Scene.Compose.Poll.SevenDays" = "7 ڕۆژ"; +"Scene.Compose.Poll.SixHours" = "6 کاتژمێر"; +"Scene.Compose.Poll.ThirtyMinutes" = "30 خولەک"; +"Scene.Compose.Poll.ThreeDays" = "3 ڕۆژ"; +"Scene.Compose.ReplyingToUser" = "لە وەڵامدا بۆ %@"; +"Scene.Compose.Title.NewPost" = "پۆستی نوێ"; +"Scene.Compose.Title.NewReply" = "وەڵامی نوێ"; +"Scene.Compose.Visibility.Direct" = "ئەوانەی ئاماژەیان پێ دەکەم"; +"Scene.Compose.Visibility.Private" = "تەنیا شوێنکەوتووان"; +"Scene.Compose.Visibility.Public" = "گشتی"; +"Scene.Compose.Visibility.Unlisted" = "پێشنیارنەکراو"; +"Scene.ConfirmEmail.Button.OpenEmailApp" = "بەرنامەی ئیمێڵەکەت بکەوە"; +"Scene.ConfirmEmail.Button.Resend" = "بینێرەوە"; +"Scene.ConfirmEmail.DontReceiveEmail.Description" = "دڵنیا بە لەوەی ئیمێڵەکەت دروستە و هەموو بوخچەکانت بگەڕێ."; +"Scene.ConfirmEmail.DontReceiveEmail.ResendEmail" = "ئیمێڵەکە بنێرەوە"; +"Scene.ConfirmEmail.DontReceiveEmail.Title" = "ئیمێڵەکەت ببینە"; +"Scene.ConfirmEmail.OpenEmailApp.Description" = "ئیمێڵێکمان بۆ ناردیت. هەموو بوخچەکانت ببینە."; +"Scene.ConfirmEmail.OpenEmailApp.Mail" = "Mail"; +"Scene.ConfirmEmail.OpenEmailApp.OpenEmailClient" = "بەرنامەی ئیمێڵەکەت بکەوە"; +"Scene.ConfirmEmail.OpenEmailApp.Title" = "ئیمێڵەکانت ببینە."; +"Scene.ConfirmEmail.Subtitle" = "بۆ پشتڕاستکردنەوەی هەژمارەکەت ئەو بەستەرە بکەوە کە بە ئیمێڵ بۆمان ناردوویت."; +"Scene.ConfirmEmail.Title" = "کۆتا شت."; +"Scene.Discovery.Intro" = "پۆست هەیە سەرنجیان لەسەرە لە گۆشەکەی تۆ."; +"Scene.Discovery.Tabs.Community" = "Community"; +"Scene.Discovery.Tabs.ForYou" = "بۆ تۆ"; +"Scene.Discovery.Tabs.Hashtags" = "هاشتاگەکان"; +"Scene.Discovery.Tabs.News" = "هەواڵەکان"; +"Scene.Discovery.Tabs.Posts" = "پۆستەکان"; +"Scene.Favorite.Title" = "بەدڵبووەکانت"; +"Scene.Follower.Footer" = "شوێنکەوتووەکانی لە ڕاژەکارەکانی ترەوە نیشان نادرێت."; +"Scene.Following.Footer" = "شوێنکەوتنەکانی بۆ هەژماری ڕاژەکارەکانی تر نیشان نادرێت."; +"Scene.HomeTimeline.NavigationBarState.NewPosts" = "پۆستە نوێکان ببینە"; +"Scene.HomeTimeline.NavigationBarState.Offline" = "دەرهێڵ"; +"Scene.HomeTimeline.NavigationBarState.Published" = "بڵاوکرایەوە!"; +"Scene.HomeTimeline.NavigationBarState.Publishing" = "پۆستەکە بڵاو دەکرێتەوە..."; +"Scene.HomeTimeline.Title" = "ماڵەوە"; +"Scene.Notification.Keyobard.ShowEverything" = "هەموو شتێک نیشان بدە"; +"Scene.Notification.Keyobard.ShowMentions" = "ئاماژەکان نیشان بدە"; +"Scene.Notification.NotificationDescription.FavoritedYourPost" = "پۆستەکەتی بەدڵ بوو"; +"Scene.Notification.NotificationDescription.FollowedYou" = "شوێنت کەوت"; +"Scene.Notification.NotificationDescription.MentionedYou" = "ئاماژەی پێت کرد"; +"Scene.Notification.NotificationDescription.PollHasEnded" = "دەنگدانەکە کۆتایی هات"; +"Scene.Notification.NotificationDescription.RebloggedYourPost" = "پۆستەکەتی پۆست کردەوە"; +"Scene.Notification.NotificationDescription.RequestToFollowYou" = "داواکاری بۆ شوێنکەوتنت"; +"Scene.Notification.Title.Everything" = "هەمووی"; +"Scene.Notification.Title.Mentions" = "ئاماژەکان"; +"Scene.Preview.Keyboard.ClosePreview" = "پێشبینینەکە دابخە"; +"Scene.Preview.Keyboard.ShowNext" = "هی دواتر نیشان بدە"; +"Scene.Preview.Keyboard.ShowPrevious" = "هی پێشتر نیشان بدە"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "دوو جار دەستی پیا بنێ بۆ کردنەوەی لیستەکە"; +"Scene.Profile.Accessibility.EditAvatarImage" = "دەستکاریی وێنەکە بکە"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "وێنەکە نیشان بدە"; +"Scene.Profile.Accessibility.ShowBannerImage" = "وێنەکەی پشتەوە نیشان بدە"; +"Scene.Profile.Dashboard.Followers" = "شوێنکەوتوو"; +"Scene.Profile.Dashboard.Following" = "شوێنکەوتن"; +"Scene.Profile.Dashboard.Posts" = "پۆستەکان"; +"Scene.Profile.Fields.AddRow" = "ڕیز زیاد بکە"; +"Scene.Profile.Fields.Placeholder.Content" = "ناوەڕۆک"; +"Scene.Profile.Fields.Placeholder.Label" = "ناونیشان"; +"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Message" = "دڵنیا ببەوە بۆ ئاستەنگکردنی %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Title" = "ئاستەنگی بکە"; +"Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Message" = "دڵیا ببەوە بۆ بێدەنگکردنی %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Title" = "بێدەنگی بکە"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Message" = "دڵنیا ببەوە بۆ لابردنی ئاستەنگی %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Title" = "ئاستەنگی مەکە"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Message" = "دڵنیا ببەوە بۆ بێدەنگنەکردنی %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Title" = "بێدەنگی مەکە"; +"Scene.Profile.SegmentedControl.About" = "دەربارە"; +"Scene.Profile.SegmentedControl.Media" = "میدیا"; +"Scene.Profile.SegmentedControl.Posts" = "پۆستەکان"; +"Scene.Profile.SegmentedControl.PostsAndReplies" = "پۆست و وەڵامەکان"; +"Scene.Profile.SegmentedControl.Replies" = "وەڵامەکان"; +"Scene.Register.Error.Item.Agreement" = "ڕێککەوتن"; +"Scene.Register.Error.Item.Email" = "ئیمێڵ"; +"Scene.Register.Error.Item.Locale" = "زمان"; +"Scene.Register.Error.Item.Password" = "تێپەڕوشە"; +"Scene.Register.Error.Item.Reason" = "هۆکار"; +"Scene.Register.Error.Item.Username" = "ناوی بەکارهێنەر"; +"Scene.Register.Error.Reason.Accepted" = "%@ دەبێت قبووڵ بکرێت"; +"Scene.Register.Error.Reason.Blank" = "%@ پێویستە"; +"Scene.Register.Error.Reason.Blocked" = "%@ خزمەتگوزارییەکی ئیمێڵی ڕێپێنەدراو بەکار دەهێنێت"; +"Scene.Register.Error.Reason.Inclusion" = "%@ پشتگیرینەکراوە"; +"Scene.Register.Error.Reason.Invalid" = "%@ نادروستە"; +"Scene.Register.Error.Reason.Reserved" = "%@ وشەیەکی گیراوە"; +"Scene.Register.Error.Reason.Taken" = "%@ بەکار هێنراوە لەلایەن یەکێکی تر"; +"Scene.Register.Error.Reason.TooLong" = "%@ زۆر درێژە"; +"Scene.Register.Error.Reason.TooShort" = "%@ زۆر کورتە"; +"Scene.Register.Error.Reason.Unreachable" = "%@ بوونی نییە"; +"Scene.Register.Error.Special.EmailInvalid" = "ئەم ئیمێڵە دروست نییە"; +"Scene.Register.Error.Special.PasswordTooShort" = "تێپەڕوشەکە زۆر کورتە (نابێت لە 8 نووسە کەمتر بێت)"; +"Scene.Register.Error.Special.UsernameInvalid" = "ناوی بەکارهێنەر دەبێت تەنیا پیت، ژمارە و هێڵی ژێرەوەی تێدا بێت"; +"Scene.Register.Error.Special.UsernameTooLong" = "ناوی بەکارهێنەرەکە زۆر درێژە (ناکرێت لە 30 نووسە زیاتر بێت)"; +"Scene.Register.Input.Avatar.Delete" = "بیسڕەوە"; +"Scene.Register.Input.DisplayName.Placeholder" = "ناوی نیشاندان"; +"Scene.Register.Input.Email.Placeholder" = "ئیمێڵ"; +"Scene.Register.Input.Invite.RegistrationUserInviteRequest" = "بۆچی دەتەوێت بەشدار بیت؟"; +"Scene.Register.Input.Password.Accessibility.Checked" = "هەڵبژێردراو"; +"Scene.Register.Input.Password.Accessibility.Unchecked" = "هەڵنەبژێردراو"; +"Scene.Register.Input.Password.CharacterLimit" = "8 پیت"; +"Scene.Register.Input.Password.Hint" = "دەبێت تێپەڕوشەکەت لایەنی کەم هەشت نووسە بێت"; +"Scene.Register.Input.Password.Placeholder" = "تێپەڕوشە"; +"Scene.Register.Input.Password.Require" = "تێپەڕوشەکەت لایەنی کەم پێویستیی هەیە بە:"; +"Scene.Register.Input.Username.DuplicatePrompt" = "ئەم ناوە گیراوە."; +"Scene.Register.Input.Username.Placeholder" = "ناوی بەکارهێنەر"; +"Scene.Register.Title" = "خۆت تۆمار بکە لە %@"; +"Scene.Report.Content1" = "پۆستی تر هەیە بتەوێت سکاڵایان لێ بکەیت؟"; +"Scene.Report.Content2" = "هیچ شتێکی هەیە بە چاودێرەکان بیزانن دەربارەی ئەم سکاڵایە؟"; +"Scene.Report.ReportSentTitle" = "سپاس بۆ سکاڵاکات، پێیدا دەچینەوە."; +"Scene.Report.Reported" = "سکاڵای لێ کرا"; +"Scene.Report.Send" = "سکاڵاکە بنێرە"; +"Scene.Report.SkipToSend" = "بەبێ لێدوان بینێرە"; +"Scene.Report.Step1" = "هەنگاوی 1 لە 2"; +"Scene.Report.Step2" = "هەنگاوی 2 لە 2"; +"Scene.Report.TextPlaceholder" = "ڕوونکردنەوەی زۆرتر بدە"; +"Scene.Report.Title" = "سکاڵا لە %@ بکە"; +"Scene.Report.TitleReport" = "سکاڵای لێ بکە"; +"Scene.Search.Recommend.Accounts.Description" = "لەوانەیە بتەوێت شوێنی ئەم هەژمارانە بکەویت"; +"Scene.Search.Recommend.Accounts.Follow" = "شوێنی بکەوە"; +"Scene.Search.Recommend.Accounts.Title" = "لەوانەیە حەزت لەمانە بێت"; +"Scene.Search.Recommend.ButtonText" = "هەمووی ببینە"; +"Scene.Search.Recommend.HashTag.Description" = "ئەو هاشتاگانەی سەرنجی زۆریان لەسەرە"; +"Scene.Search.Recommend.HashTag.PeopleTalking" = "%@ کەس باسی دەکەن"; +"Scene.Search.Recommend.HashTag.Title" = "ڕۆژەڤ"; +"Scene.Search.SearchBar.Cancel" = "بگەڕێوە"; +"Scene.Search.SearchBar.Placeholder" = "بۆ هاشتاگ و بەکارهێنەر بگەڕێ"; +"Scene.Search.Searching.Clear" = "بیانسڕەوە"; +"Scene.Search.Searching.EmptyState.NoResults" = "هیچ ئەنجامێک نەدۆزرایەوە"; +"Scene.Search.Searching.RecentSearch" = "گەڕانەکانی پێشترت"; +"Scene.Search.Searching.Segment.All" = "هەمووی"; +"Scene.Search.Searching.Segment.Hashtags" = "هاشتاگ"; +"Scene.Search.Searching.Segment.People" = "خەڵک"; +"Scene.Search.Searching.Segment.Posts" = "پۆست"; +"Scene.Search.Title" = "بگەڕێ"; +"Scene.ServerPicker.Button.Category.Academia" = "ئەکادیمیا"; +"Scene.ServerPicker.Button.Category.Activism" = "چالاکی"; +"Scene.ServerPicker.Button.Category.All" = "هەموو"; +"Scene.ServerPicker.Button.Category.AllAccessiblityDescription" = "بەش: هەموو"; +"Scene.ServerPicker.Button.Category.Art" = "هونەر"; +"Scene.ServerPicker.Button.Category.Food" = "خواردن"; +"Scene.ServerPicker.Button.Category.Furry" = "furry"; +"Scene.ServerPicker.Button.Category.Games" = "یاری"; +"Scene.ServerPicker.Button.Category.General" = "گشتی"; +"Scene.ServerPicker.Button.Category.Journalism" = "ڕۆژنامەوانی"; +"Scene.ServerPicker.Button.Category.Lgbt" = "lgbt"; +"Scene.ServerPicker.Button.Category.Music" = "موزیک"; +"Scene.ServerPicker.Button.Category.Regional" = "هەرێمی"; +"Scene.ServerPicker.Button.Category.Tech" = "تەکنۆلۆژیا"; +"Scene.ServerPicker.Button.SeeLess" = "کەمتر ببینە"; +"Scene.ServerPicker.Button.SeeMore" = "زیاتر ببینە"; +"Scene.ServerPicker.EmptyState.BadNetwork" = "هەڵەیەک ڕوویدا لە کاتی بارکردن. لە هەبوونی هێڵی ئینتەرنێت دڵنیا بە."; +"Scene.ServerPicker.EmptyState.FindingServers" = "ڕاژەکار دەدۆزرێتەوە..."; +"Scene.ServerPicker.EmptyState.NoResults" = "ئەنجام نییە"; +"Scene.ServerPicker.Input.Placeholder" = "بگەڕێ"; +"Scene.ServerPicker.Label.Category" = "بەش"; +"Scene.ServerPicker.Label.Language" = "زمان"; +"Scene.ServerPicker.Label.Users" = "بەکارهێنەر"; +"Scene.ServerPicker.Subtitle" = "ڕاژەکارێکێکی گشتی یان دانەیەک لەسەر بنەمای حەزەکانت و هەرێمەکەت هەڵبژێرە."; +"Scene.ServerPicker.SubtitleExtend" = "ڕاژەکارێکێکی گشتی یان دانەیەک لەسەر بنەمای حەزەکانت و هەرێمەکەت هەڵبژێرە. هەر ڕاژەکارێک لەلایەن ڕێکخراوێک یان تاکەکەسێک بەڕێوە دەبرێت."; +"Scene.ServerPicker.Title" = "ماستۆدۆن لە چەندان بەکارهێنەر پێک دێت کە لە ڕاژەکاری جیاواز دان."; +"Scene.ServerRules.Button.Confirm" = "ڕازیم"; +"Scene.ServerRules.PrivacyPolicy" = "سیاسەتی تایبەتێتی"; +"Scene.ServerRules.Prompt" = "بەردەوامبوونت واتای ڕازیبوونتە بە مەرجەکانی خزمەتگوزاری و سیاسەتی تایبەتێتیی %@."; +"Scene.ServerRules.Subtitle" = "ئەمانە لەلایەن چاودێرەکانی %@ دانراون و ناچار دەکرێن."; +"Scene.ServerRules.TermsOfService" = "مەرجەکانی بەکارهێنان"; +"Scene.ServerRules.Title" = "یاساکانی ڕاژەکار"; +"Scene.Settings.Footer.MastodonDescription" = "ماستۆدۆن پڕۆژەیەکی سەرچاوەکراوەیە. دەتوانیت لە گیتهەب لە کێشەکان ئاگادارمان بکەیتەوە: %@ (%@)"; +"Scene.Settings.Keyboard.CloseSettingsWindow" = "ڕێخستنەکان دابخە"; +"Scene.Settings.Section.Appearance.Automatic" = "خۆکار"; +"Scene.Settings.Section.Appearance.Dark" = "تاریک"; +"Scene.Settings.Section.Appearance.Light" = "ڕووناک"; +"Scene.Settings.Section.Appearance.Title" = "ڕووخسار"; +"Scene.Settings.Section.BoringZone.AccountSettings" = "ڕێکخستنەکانی هەژمار"; +"Scene.Settings.Section.BoringZone.Privacy" = "سیاسەتی تایبەتێتی"; +"Scene.Settings.Section.BoringZone.Terms" = "مەرجەکانی بەکارهێنان"; +"Scene.Settings.Section.BoringZone.Title" = "ناوچە بێنازەکە"; +"Scene.Settings.Section.LookAndFeel.Light" = "ڕووناک"; +"Scene.Settings.Section.LookAndFeel.ReallyDark" = "زۆر تاریک"; +"Scene.Settings.Section.LookAndFeel.SortaDark" = "کەم تاریک"; +"Scene.Settings.Section.LookAndFeel.Title" = "ڕووخسار و هەست"; +"Scene.Settings.Section.LookAndFeel.UseSystem" = "سیستەم"; +"Scene.Settings.Section.Notifications.Boosts" = "پۆستەکەم پۆست دەکاتەوە"; +"Scene.Settings.Section.Notifications.Favorites" = "پۆستەکەمی بەدڵ دەبێت"; +"Scene.Settings.Section.Notifications.Follows" = "شوێنم دەکەوێت"; +"Scene.Settings.Section.Notifications.Mentions" = "ئاماژەم پێ دەکات"; +"Scene.Settings.Section.Notifications.Title" = "ئاماژەکان نیشان بدە"; +"Scene.Settings.Section.Notifications.Trigger.Anyone" = "هەرکەسێک"; +"Scene.Settings.Section.Notifications.Trigger.Follow" = "هەرکەسێک شوێنی دەکەوم"; +"Scene.Settings.Section.Notifications.Trigger.Follower" = "شوێنکەوتووێکم"; +"Scene.Settings.Section.Notifications.Trigger.Noone" = "هیچکەس"; +"Scene.Settings.Section.Notifications.Trigger.Title" = "ئاگادارم بکەوە کاتێک"; +"Scene.Settings.Section.Preference.DisableAvatarAnimation" = "وێنە جووڵاوەکان ناچالاک بکە"; +"Scene.Settings.Section.Preference.DisableEmojiAnimation" = "ئیمۆجییە جووڵاوەکان ناچالاک بکە"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "بەستەرەکان لەناو ماستۆدۆن بکەوە"; +"Scene.Settings.Section.Preference.Title" = "پەسەندەکان"; +"Scene.Settings.Section.Preference.TrueBlackDarkMode" = "دۆخی ڕەش"; +"Scene.Settings.Section.Preference.UsingDefaultBrowser" = "وێبگەڕی بنەڕەت بەکار بهێنە بۆ کردنەوەی بەستەرەکان"; +"Scene.Settings.Section.SpicyZone.Clear" = "بیرگە پاک بکەوە"; +"Scene.Settings.Section.SpicyZone.Signout" = "دەربچۆ"; +"Scene.Settings.Section.SpicyZone.Title" = "ناوچەی گەرم"; +"Scene.Settings.Title" = "رێکخستنەکان"; +"Scene.SuggestionAccount.FollowExplain" = "کاتێک شوێنی یەکێک دەکەویت، پۆستەکانی دێتە بەردەمت."; +"Scene.SuggestionAccount.Title" = "خەڵک بدۆزەوە"; +"Scene.Thread.BackTitle" = "پۆستەکە"; +"Scene.Thread.Title" = "پۆستی %@"; +"Scene.Welcome.GetStarted" = "دەست پێ بکە"; +"Scene.Welcome.LogIn" = "بچۆ ژوورەوە"; +"Scene.Welcome.Slogan" = "تۆڕی کۆمەڵایەتی +لەژێر دەستەکانت."; +"Scene.Wizard.AccessibilityHint" = "دوو جار دەستی پیا بنێ بۆ داخستنی"; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "هەژمارەکەت بگۆڕە بە دەستڕاگرتن لەسەر دوگمەی پرۆفایلەکە."; +"Scene.Wizard.NewInMastodon" = "نوێ"; \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ckb.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/ckb.lproj/Localizable.stringsdict new file mode 100644 index 000000000..e744a4bd5 --- /dev/null +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ckb.lproj/Localizable.stringsdict @@ -0,0 +1,406 @@ + + + + + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + %ld ئاگاداریی نەبینراو + other + %ld ئاگاداریی نەبینراو + + + a11y.plural.count.input_limit_exceeds + + NSStringLocalizedFormatKey + سنووری نووسین %#@character_count@ دەرباز دەکات + character_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + %ld نووسە + other + %ld نووسە + + + a11y.plural.count.input_limit_remains + + NSStringLocalizedFormatKey + سنووری نووسین %#@character_count@ دەمێنێتەوە + character_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + %ld نووسە + other + %ld نووسە + + + plural.count.metric_formatted.post + + NSStringLocalizedFormatKey + %@%#@post_count@ + post_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + پۆست + other + پۆست + + + plural.count.post + + NSStringLocalizedFormatKey + %#@post_count@ + post_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + %ld پۆست + other + %ld پۆست + + + plural.count.favorite + + NSStringLocalizedFormatKey + %#@favorite_count@ + favorite_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + %ld بەدڵبوو + other + %ld بەدڵبوو + + + plural.count.reblog + + NSStringLocalizedFormatKey + %#@reblog_count@ + reblog_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + %ld پۆستکردنەوە + other + %ld پۆستکردنەوە + + + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + %ld وەڵام + other + %ld وەڵام + + + plural.count.vote + + NSStringLocalizedFormatKey + %#@vote_count@ + vote_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + %ld دەنگ + other + %ld دەنگ + + + plural.count.voter + + NSStringLocalizedFormatKey + %#@voter_count@ + voter_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + %ld دەنگدەر + other + %ld دەنگدەر + + + plural.people_talking + + NSStringLocalizedFormatKey + %#@count_people_talking@ + count_people_talking + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + %ld کەس باسی دەکات + other + %ld کەس باسی دەکەن + + + plural.count.following + + NSStringLocalizedFormatKey + %#@count_following@ + count_following + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + %ld شوێنکەوتن + other + %ld شوێنکەوتن + + + plural.count.follower + + NSStringLocalizedFormatKey + %#@count_follower@ + count_follower + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + %ld شوێنکەوتوو + other + %ld شوێنکەوتوو + + + date.year.left + + NSStringLocalizedFormatKey + %#@count_year_left@ + count_year_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + %ld ساڵی ماوە + other + %ld ساڵی ماوە + + + date.month.left + + NSStringLocalizedFormatKey + %#@count_month_left@ + count_month_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + %ld مانگی ماوە + other + %ld مانگی ماوە + + + date.day.left + + NSStringLocalizedFormatKey + %#@count_day_left@ + count_day_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + %ld ڕۆژی ماوە + other + %ld ڕۆژی ماوە + + + date.hour.left + + NSStringLocalizedFormatKey + %#@count_hour_left@ + count_hour_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + %ld کاتژمێری ماوە + other + %ld کاتژمێری ماوە + + + date.minute.left + + NSStringLocalizedFormatKey + %#@count_minute_left@ + count_minute_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + %ld خولەکی ماوە + other + %ld خولەکی ماوە + + + date.second.left + + NSStringLocalizedFormatKey + %#@count_second_left@ + count_second_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + %ld چرکەی ماوە + other + %ld چرکەی ماوە + + + date.year.ago.abbr + + NSStringLocalizedFormatKey + %#@count_year_ago_abbr@ + count_year_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + %ld ساڵ لەمەوبەر + other + %ld ساڵ لەمەوبەر + + + date.month.ago.abbr + + NSStringLocalizedFormatKey + %#@count_month_ago_abbr@ + count_month_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + %ld مانگ لەمەوبەر + other + %ld مانگ لەمەوبەر + + + date.day.ago.abbr + + NSStringLocalizedFormatKey + %#@count_day_ago_abbr@ + count_day_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + %ld ڕۆژ لەمەوبەر + other + %ld ڕۆژ لەمەوبەر + + + date.hour.ago.abbr + + NSStringLocalizedFormatKey + %#@count_hour_ago_abbr@ + count_hour_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + %ld کاتژمێر لەمەوبەر + other + %ld کاتژمێر لەمەوبەر + + + date.minute.ago.abbr + + NSStringLocalizedFormatKey + %#@count_minute_ago_abbr@ + count_minute_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + %ld خولەک لەمەوبەر + other + %ld خولەک لەمەوبەر + + + date.second.ago.abbr + + NSStringLocalizedFormatKey + %#@count_second_ago_abbr@ + count_second_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + %ld چرکە لەمەوبەر + other + %ld چرکە لەمەوبەر + + + + From b2b81e27e8296482cf7d0c81b2270c69b4432aa9 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 29 Apr 2022 15:34:23 +0800 Subject: [PATCH 049/101] feat: add Chinese Traditional, Galician, Italian, and Turkish languages --- .../Sources/StringsConvertor/main.swift | 4 + Mastodon.xcodeproj/project.pbxproj | 28 ++ Mastodon/Resources/gl.lproj/InfoPlist.strings | 4 + Mastodon/Resources/it.lproj/InfoPlist.strings | 4 + Mastodon/Resources/tr.lproj/InfoPlist.strings | 4 + .../Resources/zh-Hant.lproj/InfoPlist.strings | 4 + MastodonIntent/gl.lproj/Intents.strings | 51 +++ MastodonIntent/gl.lproj/Intents.stringsdict | 54 +++ MastodonIntent/it.lproj/Intents.strings | 51 +++ MastodonIntent/it.lproj/Intents.stringsdict | 54 +++ MastodonIntent/tr.lproj/Intents.strings | 51 +++ MastodonIntent/tr.lproj/Intents.stringsdict | 54 +++ MastodonIntent/zh-Hant.lproj/Intents.strings | 51 +++ .../zh-Hant.lproj/Intents.stringsdict | 54 +++ .../Resources/gl.lproj/Localizable.strings | 392 +++++++++++++++++ .../gl.lproj/Localizable.stringsdict | 406 ++++++++++++++++++ .../Resources/it.lproj/Localizable.strings | 391 +++++++++++++++++ .../it.lproj/Localizable.stringsdict | 406 ++++++++++++++++++ .../Resources/tr.lproj/Localizable.strings | 391 +++++++++++++++++ .../tr.lproj/Localizable.stringsdict | 406 ++++++++++++++++++ .../zh-Hant.lproj/Localizable.strings | 387 +++++++++++++++++ .../zh-Hant.lproj/Localizable.stringsdict | 356 +++++++++++++++ 22 files changed, 3603 insertions(+) create mode 100644 Mastodon/Resources/gl.lproj/InfoPlist.strings create mode 100644 Mastodon/Resources/it.lproj/InfoPlist.strings create mode 100644 Mastodon/Resources/tr.lproj/InfoPlist.strings create mode 100644 Mastodon/Resources/zh-Hant.lproj/InfoPlist.strings create mode 100644 MastodonIntent/gl.lproj/Intents.strings create mode 100644 MastodonIntent/gl.lproj/Intents.stringsdict create mode 100644 MastodonIntent/it.lproj/Intents.strings create mode 100644 MastodonIntent/it.lproj/Intents.stringsdict create mode 100644 MastodonIntent/tr.lproj/Intents.strings create mode 100644 MastodonIntent/tr.lproj/Intents.stringsdict create mode 100644 MastodonIntent/zh-Hant.lproj/Intents.strings create mode 100644 MastodonIntent/zh-Hant.lproj/Intents.stringsdict create mode 100644 MastodonSDK/Sources/MastodonLocalization/Resources/gl.lproj/Localizable.strings create mode 100644 MastodonSDK/Sources/MastodonLocalization/Resources/gl.lproj/Localizable.stringsdict create mode 100644 MastodonSDK/Sources/MastodonLocalization/Resources/it.lproj/Localizable.strings create mode 100644 MastodonSDK/Sources/MastodonLocalization/Resources/it.lproj/Localizable.stringsdict create mode 100644 MastodonSDK/Sources/MastodonLocalization/Resources/tr.lproj/Localizable.strings create mode 100644 MastodonSDK/Sources/MastodonLocalization/Resources/tr.lproj/Localizable.stringsdict create mode 100644 MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hant.lproj/Localizable.strings create mode 100644 MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hant.lproj/Localizable.stringsdict diff --git a/Localization/StringsConvertor/Sources/StringsConvertor/main.swift b/Localization/StringsConvertor/Sources/StringsConvertor/main.swift index 6604884a4..e30cf56a5 100644 --- a/Localization/StringsConvertor/Sources/StringsConvertor/main.swift +++ b/Localization/StringsConvertor/Sources/StringsConvertor/main.swift @@ -51,10 +51,13 @@ private func map(language: String) -> String? { case "eu_ES": return "eu-ES" // Basque case "ca_ES": return "ca" // Catalan case "zh_CN": return "zh-Hans" // Chinese Simplified + case "zh_TW": return "zh-Hant" // Chinese Traditional case "nl_NL": return "nl" // Dutch case "en_US": return "en" case "fr_FR": return "fr" // French + case "gl_ES": return "gl" // Galician case "de_DE": return "de" // German + case "it_IT": return "it" // Italian case "ja_JP": return "ja" // Japanese case "kab_KAB": return "kab" // Kabyle case "kmr_TR": return "ku" // Kurmanji (Kurdish) @@ -66,6 +69,7 @@ private func map(language: String) -> String? { case "sv-SE": return "sv" // Swedish case "sv_FI": return "sv_FI" // Swedish, Finland case "th_TH": return "th" // Thai + case "tr_TR": return "tr" // Turkish case "vi_VN": return "vi" // Vietnamese default: return nil } diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index f2eeb9e37..2255c3d46 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -1030,6 +1030,18 @@ DB519B09281BCA2E00F0C99D /* ckb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ckb; path = ckb.lproj/Intents.strings; sourceTree = ""; }; DB519B0A281BCA2E00F0C99D /* ckb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ckb; path = ckb.lproj/InfoPlist.strings; sourceTree = ""; }; DB519B0B281BCA4300F0C99D /* ckb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ckb; path = ckb.lproj/Intents.stringsdict; sourceTree = ""; }; + DB519B0C281BCAC300F0C99D /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Intents.strings"; sourceTree = ""; }; + DB519B0D281BCAC300F0C99D /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/InfoPlist.strings"; sourceTree = ""; }; + DB519B0E281BCAC300F0C99D /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "zh-Hant"; path = "zh-Hant.lproj/Intents.stringsdict"; sourceTree = ""; }; + DB519B0F281BCB3300F0C99D /* gl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = gl; path = gl.lproj/Intents.strings; sourceTree = ""; }; + DB519B10281BCB3300F0C99D /* gl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = gl; path = gl.lproj/InfoPlist.strings; sourceTree = ""; }; + DB519B11281BCB3400F0C99D /* gl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = gl; path = gl.lproj/Intents.stringsdict; sourceTree = ""; }; + DB519B12281BCBC400F0C99D /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Intents.strings; sourceTree = ""; }; + DB519B13281BCBC400F0C99D /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/InfoPlist.strings; sourceTree = ""; }; + DB519B14281BCBC400F0C99D /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = it; path = it.lproj/Intents.stringsdict; sourceTree = ""; }; + DB519B15281BCC2F00F0C99D /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Intents.strings; sourceTree = ""; }; + DB519B16281BCC2F00F0C99D /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/InfoPlist.strings; sourceTree = ""; }; + DB519B17281BCC2F00F0C99D /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = tr; path = tr.lproj/Intents.stringsdict; sourceTree = ""; }; DB51D170262832380062B7A1 /* BlurHashDecode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlurHashDecode.swift; sourceTree = ""; }; DB51D171262832380062B7A1 /* BlurHashEncode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlurHashEncode.swift; sourceTree = ""; }; DB564BD2269F3B35001E39A7 /* StatusFilterService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusFilterService.swift; sourceTree = ""; }; @@ -3522,6 +3534,10 @@ vi, sv, ckb, + "zh-Hant", + gl, + it, + tr, ); mainGroup = DB427DC925BAA00100D1B89D; packageReferences = ( @@ -4468,6 +4484,10 @@ DBF81C7727F6913300004A56 /* vi */, DB8D8E3128196FA0009FD90F /* sv */, DB519B09281BCA2E00F0C99D /* ckb */, + DB519B0C281BCAC300F0C99D /* zh-Hant */, + DB519B0F281BCB3300F0C99D /* gl */, + DB519B12281BCBC400F0C99D /* it */, + DB519B15281BCC2F00F0C99D /* tr */, ); name = Intents.intentdefinition; sourceTree = ""; @@ -4495,6 +4515,10 @@ DBF81C7827F6913300004A56 /* vi */, DB8D8E3228196FA0009FD90F /* sv */, DB519B0A281BCA2E00F0C99D /* ckb */, + DB519B0D281BCAC300F0C99D /* zh-Hant */, + DB519B10281BCB3300F0C99D /* gl */, + DB519B13281BCBC400F0C99D /* it */, + DB519B16281BCC2F00F0C99D /* tr */, ); name = InfoPlist.strings; sourceTree = ""; @@ -4538,6 +4562,10 @@ DBF81C7927F6913300004A56 /* vi */, DB8D8E3328196FA0009FD90F /* sv */, DB519B0B281BCA4300F0C99D /* ckb */, + DB519B0E281BCAC300F0C99D /* zh-Hant */, + DB519B11281BCB3400F0C99D /* gl */, + DB519B14281BCBC400F0C99D /* it */, + DB519B17281BCC2F00F0C99D /* tr */, ); name = Intents.stringsdict; sourceTree = ""; diff --git a/Mastodon/Resources/gl.lproj/InfoPlist.strings b/Mastodon/Resources/gl.lproj/InfoPlist.strings new file mode 100644 index 000000000..710865573 --- /dev/null +++ b/Mastodon/Resources/gl.lproj/InfoPlist.strings @@ -0,0 +1,4 @@ +"NSCameraUsageDescription" = "Used to take photo for post status"; +"NSPhotoLibraryAddUsageDescription" = "Used to save photo into the Photo Library"; +"NewPostShortcutItemTitle" = "New Post"; +"SearchShortcutItemTitle" = "Search"; \ No newline at end of file diff --git a/Mastodon/Resources/it.lproj/InfoPlist.strings b/Mastodon/Resources/it.lproj/InfoPlist.strings new file mode 100644 index 000000000..710865573 --- /dev/null +++ b/Mastodon/Resources/it.lproj/InfoPlist.strings @@ -0,0 +1,4 @@ +"NSCameraUsageDescription" = "Used to take photo for post status"; +"NSPhotoLibraryAddUsageDescription" = "Used to save photo into the Photo Library"; +"NewPostShortcutItemTitle" = "New Post"; +"SearchShortcutItemTitle" = "Search"; \ No newline at end of file diff --git a/Mastodon/Resources/tr.lproj/InfoPlist.strings b/Mastodon/Resources/tr.lproj/InfoPlist.strings new file mode 100644 index 000000000..710865573 --- /dev/null +++ b/Mastodon/Resources/tr.lproj/InfoPlist.strings @@ -0,0 +1,4 @@ +"NSCameraUsageDescription" = "Used to take photo for post status"; +"NSPhotoLibraryAddUsageDescription" = "Used to save photo into the Photo Library"; +"NewPostShortcutItemTitle" = "New Post"; +"SearchShortcutItemTitle" = "Search"; \ No newline at end of file diff --git a/Mastodon/Resources/zh-Hant.lproj/InfoPlist.strings b/Mastodon/Resources/zh-Hant.lproj/InfoPlist.strings new file mode 100644 index 000000000..710865573 --- /dev/null +++ b/Mastodon/Resources/zh-Hant.lproj/InfoPlist.strings @@ -0,0 +1,4 @@ +"NSCameraUsageDescription" = "Used to take photo for post status"; +"NSPhotoLibraryAddUsageDescription" = "Used to save photo into the Photo Library"; +"NewPostShortcutItemTitle" = "New Post"; +"SearchShortcutItemTitle" = "Search"; \ No newline at end of file diff --git a/MastodonIntent/gl.lproj/Intents.strings b/MastodonIntent/gl.lproj/Intents.strings new file mode 100644 index 000000000..6877490ba --- /dev/null +++ b/MastodonIntent/gl.lproj/Intents.strings @@ -0,0 +1,51 @@ +"16wxgf" = "Post on Mastodon"; + +"751xkl" = "Text Content"; + +"CsR7G2" = "Post on Mastodon"; + +"HZSGTr" = "What content to post?"; + +"HdGikU" = "Posting failed"; + +"KDNTJ4" = "Failure Reason"; + +"RHxKOw" = "Send Post with text content"; + +"RxSqsb" = "Post"; + +"WCIR3D" = "Post ${content} on Mastodon"; + +"ZKJSNu" = "Post"; + +"ZS1XaK" = "${content}"; + +"ZbSjzC" = "Visibility"; + +"Zo4jgJ" = "Post Visibility"; + +"apSxMG-dYQ5NN" = "There are ${count} options matching ‘Public’."; + +"apSxMG-ehFLjY" = "There are ${count} options matching ‘Followers Only’."; + +"ayoYEb-dYQ5NN" = "${content}, Public"; + +"ayoYEb-ehFLjY" = "${content}, Followers Only"; + +"dUyuGg" = "Post on Mastodon"; + +"dYQ5NN" = "Public"; + +"ehFLjY" = "Followers Only"; + +"gfePDu" = "Posting failed. ${failureReason}"; + +"k7dbKQ" = "Post was sent successfully."; + +"oGiqmY-dYQ5NN" = "Just to confirm, you wanted ‘Public’?"; + +"oGiqmY-ehFLjY" = "Just to confirm, you wanted ‘Followers Only’?"; + +"rM6dvp" = "URL"; + +"ryJLwG" = "Post was sent successfully. "; diff --git a/MastodonIntent/gl.lproj/Intents.stringsdict b/MastodonIntent/gl.lproj/Intents.stringsdict new file mode 100644 index 000000000..5a39d5e64 --- /dev/null +++ b/MastodonIntent/gl.lproj/Intents.stringsdict @@ -0,0 +1,54 @@ + + + + + There are ${count} options matching ‘${content}’. - 2 + + NSStringLocalizedFormatKey + There are %#@count_option@ matching ‘${content}’. + count_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + %ld + zero + 0 options + one + 1 option + two + 2 options + few + %ld options + many + %ld options + other + %ld options + + + There are ${count} options matching ‘${visibility}’. + + NSStringLocalizedFormatKey + There are %#@count_option@ matching ‘${visibility}’. + count_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + %ld + zero + 0 options + one + 1 option + two + 2 options + few + %ld options + many + %ld options + other + %ld options + + + + diff --git a/MastodonIntent/it.lproj/Intents.strings b/MastodonIntent/it.lproj/Intents.strings new file mode 100644 index 000000000..d26aef14b --- /dev/null +++ b/MastodonIntent/it.lproj/Intents.strings @@ -0,0 +1,51 @@ +"16wxgf" = "Pubblica su Mastodon"; + +"751xkl" = "Contenuto testuale"; + +"CsR7G2" = "Pubblica su Mastodon"; + +"HZSGTr" = "Quale contenuto postare?"; + +"HdGikU" = "Pubblicazione non riuscita"; + +"KDNTJ4" = "Motivo del fallimento"; + +"RHxKOw" = "Invia post con contenuto testuale"; + +"RxSqsb" = "Pubblica"; + +"WCIR3D" = "Pubblica ${content} su Mastodon"; + +"ZKJSNu" = "Pubblica"; + +"ZS1XaK" = "${content}"; + +"ZbSjzC" = "Visibilità"; + +"Zo4jgJ" = "Visibilità del post"; + +"apSxMG-dYQ5NN" = "Ci sono ${count} opzioni corrispondenti a 'Pubblico'."; + +"apSxMG-ehFLjY" = "Ci sono ${count} opzioni corrispondenti a ‘Solo Seguaci’."; + +"ayoYEb-dYQ5NN" = "${content}, Pubblico"; + +"ayoYEb-ehFLjY" = "${content}, Solo seguaci"; + +"dUyuGg" = "Pubblica su Mastodon"; + +"dYQ5NN" = "Pubblico"; + +"ehFLjY" = "Solo i seguaci"; + +"gfePDu" = "Pubblicazione fallita. ${failureReason}"; + +"k7dbKQ" = "Post inviato con successo."; + +"oGiqmY-dYQ5NN" = "Solo per confermare, volevi ‘Pubblico’?"; + +"oGiqmY-ehFLjY" = "Solo per confermare, volevi 'Solo seguaci'?"; + +"rM6dvp" = "URL"; + +"ryJLwG" = "Post inviato con successo. "; diff --git a/MastodonIntent/it.lproj/Intents.stringsdict b/MastodonIntent/it.lproj/Intents.stringsdict new file mode 100644 index 000000000..5a39d5e64 --- /dev/null +++ b/MastodonIntent/it.lproj/Intents.stringsdict @@ -0,0 +1,54 @@ + + + + + There are ${count} options matching ‘${content}’. - 2 + + NSStringLocalizedFormatKey + There are %#@count_option@ matching ‘${content}’. + count_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + %ld + zero + 0 options + one + 1 option + two + 2 options + few + %ld options + many + %ld options + other + %ld options + + + There are ${count} options matching ‘${visibility}’. + + NSStringLocalizedFormatKey + There are %#@count_option@ matching ‘${visibility}’. + count_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + %ld + zero + 0 options + one + 1 option + two + 2 options + few + %ld options + many + %ld options + other + %ld options + + + + diff --git a/MastodonIntent/tr.lproj/Intents.strings b/MastodonIntent/tr.lproj/Intents.strings new file mode 100644 index 000000000..dc60dee73 --- /dev/null +++ b/MastodonIntent/tr.lproj/Intents.strings @@ -0,0 +1,51 @@ +"16wxgf" = "Mastodon'da paylaş"; + +"751xkl" = "Metin içeriği"; + +"CsR7G2" = "Mastodon'da paylaş"; + +"HZSGTr" = "Ne içeriği paylaşılacak?"; + +"HdGikU" = "Gönderi paylaşılamadı"; + +"KDNTJ4" = "Hata Sebebi"; + +"RHxKOw" = "Metin içeriği ile gönderiyi paylaş"; + +"RxSqsb" = "Gönderi"; + +"WCIR3D" = "${content} içeriğini Mastodon'da paylaş"; + +"ZKJSNu" = "Gönderi"; + +"ZS1XaK" = "${content}"; + +"ZbSjzC" = "Gizlilik"; + +"Zo4jgJ" = "Gönderi Gizliliği"; + +"apSxMG-dYQ5NN" = "\"Herkese açık\" ile eşleşen ${count} seçenek var."; + +"apSxMG-ehFLjY" = "\"Sadece takipçiler\" ile eşleşen ${count} seçenek var."; + +"ayoYEb-dYQ5NN" = "${content}, Herkese açık"; + +"ayoYEb-ehFLjY" = "${content}, Sadece takipçiler"; + +"dUyuGg" = "Mastodon'da paylaş"; + +"dYQ5NN" = "Herkese açık"; + +"ehFLjY" = "Sadece takipçiler"; + +"gfePDu" = "Gönderi paylaşılamadı. ${failureReason}"; + +"k7dbKQ" = "Gönderi başarıyla paylaşıldı."; + +"oGiqmY-dYQ5NN" = "\"Herkese açık\" paylaşmak istediğinize emin misiniz?"; + +"oGiqmY-ehFLjY" = "\"Sadece takipçiler\" için paylaşmak istediğinize emin misiniz?"; + +"rM6dvp" = "Bağlantı"; + +"ryJLwG" = "Gönderi başarıyla paylaşıldı. "; diff --git a/MastodonIntent/tr.lproj/Intents.stringsdict b/MastodonIntent/tr.lproj/Intents.stringsdict new file mode 100644 index 000000000..5a39d5e64 --- /dev/null +++ b/MastodonIntent/tr.lproj/Intents.stringsdict @@ -0,0 +1,54 @@ + + + + + There are ${count} options matching ‘${content}’. - 2 + + NSStringLocalizedFormatKey + There are %#@count_option@ matching ‘${content}’. + count_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + %ld + zero + 0 options + one + 1 option + two + 2 options + few + %ld options + many + %ld options + other + %ld options + + + There are ${count} options matching ‘${visibility}’. + + NSStringLocalizedFormatKey + There are %#@count_option@ matching ‘${visibility}’. + count_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + %ld + zero + 0 options + one + 1 option + two + 2 options + few + %ld options + many + %ld options + other + %ld options + + + + diff --git a/MastodonIntent/zh-Hant.lproj/Intents.strings b/MastodonIntent/zh-Hant.lproj/Intents.strings new file mode 100644 index 000000000..a45a5f511 --- /dev/null +++ b/MastodonIntent/zh-Hant.lproj/Intents.strings @@ -0,0 +1,51 @@ +"16wxgf" = "於 Mastodon 上發嘟文"; + +"751xkl" = "文字內容"; + +"CsR7G2" = "於 Mastodon 上發嘟文"; + +"HZSGTr" = "要發什麼嘟呢?"; + +"HdGikU" = "嘟文失敗"; + +"KDNTJ4" = "失敗原因"; + +"RHxKOw" = "發送文字內容嘟文"; + +"RxSqsb" = "嘟文"; + +"WCIR3D" = "將 ${content} 於 Mastodon 上發嘟"; + +"ZKJSNu" = "嘟文"; + +"ZS1XaK" = "${content}"; + +"ZbSjzC" = "可見性"; + +"Zo4jgJ" = "嘟文可見性"; + +"apSxMG-dYQ5NN" = "有 ${count} 個選項符合「公開」。"; + +"apSxMG-ehFLjY" = "有 ${count} 個選項符合「僅限跟隨者」。"; + +"ayoYEb-dYQ5NN" = "${content},公開"; + +"ayoYEb-ehFLjY" = "${content},僅限跟隨者"; + +"dUyuGg" = "於 Mastodon 上發嘟文"; + +"dYQ5NN" = "公開"; + +"ehFLjY" = "僅限跟隨者"; + +"gfePDu" = "發嘟失敗。${failureReason}"; + +"k7dbKQ" = "成功發出嘟文。"; + +"oGiqmY-dYQ5NN" = "再確認一次,您想要「公開」?"; + +"oGiqmY-ehFLjY" = "再確認一次,您想要「僅限跟隨者」?"; + +"rM6dvp" = "網址"; + +"ryJLwG" = "成功發出嘟文。 "; diff --git a/MastodonIntent/zh-Hant.lproj/Intents.stringsdict b/MastodonIntent/zh-Hant.lproj/Intents.stringsdict new file mode 100644 index 000000000..5a39d5e64 --- /dev/null +++ b/MastodonIntent/zh-Hant.lproj/Intents.stringsdict @@ -0,0 +1,54 @@ + + + + + There are ${count} options matching ‘${content}’. - 2 + + NSStringLocalizedFormatKey + There are %#@count_option@ matching ‘${content}’. + count_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + %ld + zero + 0 options + one + 1 option + two + 2 options + few + %ld options + many + %ld options + other + %ld options + + + There are ${count} options matching ‘${visibility}’. + + NSStringLocalizedFormatKey + There are %#@count_option@ matching ‘${visibility}’. + count_option + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + %ld + zero + 0 options + one + 1 option + two + 2 options + few + %ld options + many + %ld options + other + %ld options + + + + diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/gl.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/gl.lproj/Localizable.strings new file mode 100644 index 000000000..a0a33a58f --- /dev/null +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/gl.lproj/Localizable.strings @@ -0,0 +1,392 @@ +"Common.Alerts.BlockDomain.BlockEntireDomain" = "Bloquear Dominio"; +"Common.Alerts.BlockDomain.Title" = "Tes a certeza de querer bloquear todo de %@? Na meirande parte dos casos uns bloqueos ou silenciados específicos son suficientes e preferibles. Non verás máis o contido deste dominio en ningunha cronoloxía pública e as túas seguidoras deste dominio serán eliminadas."; +"Common.Alerts.CleanCache.Message" = "Baleirouse %@ da caché correctamente."; +"Common.Alerts.CleanCache.Title" = "Limpar caché"; +"Common.Alerts.Common.PleaseTryAgain" = "Inténtao de novo."; +"Common.Alerts.Common.PleaseTryAgainLater" = "Inténtao de novo máis tarde."; +"Common.Alerts.DeletePost.Message" = "Tes a certeza de querer eliminar esta publicación?"; +"Common.Alerts.DeletePost.Title" = "Eliminar publicación"; +"Common.Alerts.DiscardPostContent.Message" = "Confirma que queres descartar o contido do borrador."; +"Common.Alerts.DiscardPostContent.Title" = "Descartar Borrador"; +"Common.Alerts.EditProfileFailure.Message" = "Non se editou o perfil. Inténtao máis tarde."; +"Common.Alerts.EditProfileFailure.Title" = "Erro ao editar o perfil"; +"Common.Alerts.PublishPostFailure.AttachmentsMessage.MoreThanOneVideo" = "Non podes anexar máis de un vídeo."; +"Common.Alerts.PublishPostFailure.AttachmentsMessage.VideoAttachWithPhoto" = "Non podes anexar un vídeo a unha publicación que xa contén imaxes."; +"Common.Alerts.PublishPostFailure.Message" = "Fallou a publicación. +Comproba a conexión a internet."; +"Common.Alerts.PublishPostFailure.Title" = "Fallou a publicación"; +"Common.Alerts.SavePhotoFailure.Message" = "Activa o permiso de acceso á galería de fotos para gardar a foto."; +"Common.Alerts.SavePhotoFailure.Title" = "Erro ao gardar a fotografía"; +"Common.Alerts.ServerError.Title" = "Erro do servidor"; +"Common.Alerts.SignOut.Confirm" = "Pechar sesión"; +"Common.Alerts.SignOut.Message" = "Tes a certeza de queres pechar a sesión?"; +"Common.Alerts.SignOut.Title" = "Pechar sesión"; +"Common.Alerts.SignUpFailure.Title" = "Fallou o rexistro"; +"Common.Alerts.VoteFailure.PollEnded" = "A enquisa rematou"; +"Common.Alerts.VoteFailure.Title" = "Fallou a votación"; +"Common.Controls.Actions.Add" = "Engadir"; +"Common.Controls.Actions.Back" = "Volver"; +"Common.Controls.Actions.BlockDomain" = "Bloquear a %@"; +"Common.Controls.Actions.Cancel" = "Cancelar"; +"Common.Controls.Actions.Compose" = "Escribir"; +"Common.Controls.Actions.Confirm" = "Confirmar"; +"Common.Controls.Actions.Continue" = "Continuar"; +"Common.Controls.Actions.CopyPhoto" = "Copiar foto"; +"Common.Controls.Actions.Delete" = "Eliminar"; +"Common.Controls.Actions.Discard" = "Descartar"; +"Common.Controls.Actions.Done" = "Feito"; +"Common.Controls.Actions.Edit" = "Editar"; +"Common.Controls.Actions.FindPeople" = "Atopar persoas para seguir"; +"Common.Controls.Actions.ManuallySearch" = "Buscar de xeito manual"; +"Common.Controls.Actions.Next" = "Seguinte"; +"Common.Controls.Actions.Ok" = "OK"; +"Common.Controls.Actions.Open" = "Abrir"; +"Common.Controls.Actions.OpenInBrowser" = "Abrir no navegador"; +"Common.Controls.Actions.OpenInSafari" = "Abrir en Safari"; +"Common.Controls.Actions.Preview" = "Vista previa"; +"Common.Controls.Actions.Previous" = "Anterior"; +"Common.Controls.Actions.Remove" = "Eliminar"; +"Common.Controls.Actions.Reply" = "Responder"; +"Common.Controls.Actions.ReportUser" = "Denunciar a %@"; +"Common.Controls.Actions.Save" = "Gardar"; +"Common.Controls.Actions.SavePhoto" = "Gardar foto"; +"Common.Controls.Actions.SeeMore" = "Ver máis"; +"Common.Controls.Actions.Settings" = "Axustes"; +"Common.Controls.Actions.Share" = "Compartir"; +"Common.Controls.Actions.SharePost" = "Compartir publicación"; +"Common.Controls.Actions.ShareUser" = "Compartir %@"; +"Common.Controls.Actions.SignIn" = "Acceder"; +"Common.Controls.Actions.SignUp" = "Inscribirse"; +"Common.Controls.Actions.Skip" = "Omitir"; +"Common.Controls.Actions.TakePhoto" = "Facer foto"; +"Common.Controls.Actions.TryAgain" = "Intentar de novo"; +"Common.Controls.Actions.UnblockDomain" = "Desbloquear a %@"; +"Common.Controls.Friendship.Block" = "Bloquear"; +"Common.Controls.Friendship.BlockDomain" = "Bloquear a %@"; +"Common.Controls.Friendship.BlockUser" = "Bloquear a %@"; +"Common.Controls.Friendship.Blocked" = "Bloqueada"; +"Common.Controls.Friendship.EditInfo" = "Editar info"; +"Common.Controls.Friendship.Follow" = "Seguir"; +"Common.Controls.Friendship.Following" = "Seguindo"; +"Common.Controls.Friendship.Mute" = "Acalar"; +"Common.Controls.Friendship.MuteUser" = "Acalar a %@"; +"Common.Controls.Friendship.Muted" = "Acalada"; +"Common.Controls.Friendship.Pending" = "Pendente"; +"Common.Controls.Friendship.Request" = "Solicitar"; +"Common.Controls.Friendship.Unblock" = "Desbloquear"; +"Common.Controls.Friendship.UnblockUser" = "Desbloquear a %@"; +"Common.Controls.Friendship.Unmute" = "Non Acalar"; +"Common.Controls.Friendship.UnmuteUser" = "Deixar de acalar a @%@"; +"Common.Controls.Keyboard.Common.ComposeNewPost" = "Escribir Nova publicación"; +"Common.Controls.Keyboard.Common.OpenSettings" = "Abrir axustes"; +"Common.Controls.Keyboard.Common.ShowFavorites" = "Mostrar Favoritos"; +"Common.Controls.Keyboard.Common.SwitchToTab" = "Cambiar a %@"; +"Common.Controls.Keyboard.SegmentedControl.NextSection" = "Sección seguinte"; +"Common.Controls.Keyboard.SegmentedControl.PreviousSection" = "Sección anterior"; +"Common.Controls.Keyboard.Timeline.NextStatus" = "Publicación seguinte"; +"Common.Controls.Keyboard.Timeline.OpenAuthorProfile" = "Ver Perfil da autora"; +"Common.Controls.Keyboard.Timeline.OpenRebloggerProfile" = "Ver perfil de quen promoveu"; +"Common.Controls.Keyboard.Timeline.OpenStatus" = "Abrir publicación"; +"Common.Controls.Keyboard.Timeline.PreviewImage" = "Previsualización da imaxe"; +"Common.Controls.Keyboard.Timeline.PreviousStatus" = "Publicación anterior"; +"Common.Controls.Keyboard.Timeline.ReplyStatus" = "Responder á publicación"; +"Common.Controls.Keyboard.Timeline.ToggleContentWarning" = "Marcar con Aviso sobre o contido"; +"Common.Controls.Keyboard.Timeline.ToggleFavorite" = "Engadir publicación a Favoritas"; +"Common.Controls.Keyboard.Timeline.ToggleReblog" = "Promover a publicación"; +"Common.Controls.Status.Actions.Favorite" = "Favorecer"; +"Common.Controls.Status.Actions.Hide" = "Agochar"; +"Common.Controls.Status.Actions.Menu" = "Menú"; +"Common.Controls.Status.Actions.Reblog" = "Promover"; +"Common.Controls.Status.Actions.Reply" = "Responder"; +"Common.Controls.Status.Actions.ShowGif" = "Mostrar GIF"; +"Common.Controls.Status.Actions.ShowImage" = "Mostrar a imaxe"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Mostrar reprodutor de vídeo"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Toca e mantén preso para menú"; +"Common.Controls.Status.Actions.Unfavorite" = "Eliminar dos favoritos"; +"Common.Controls.Status.Actions.Unreblog" = "Retirar promoción"; +"Common.Controls.Status.ContentWarning" = "Aviso sobre o contido"; +"Common.Controls.Status.MediaContentWarning" = "Toca nalgures para mostrar"; +"Common.Controls.Status.Poll.Closed" = "Pechada"; +"Common.Controls.Status.Poll.Vote" = "Votar"; +"Common.Controls.Status.SensitiveContent" = "Contido sensible"; +"Common.Controls.Status.ShowPost" = "Mostrar publicación"; +"Common.Controls.Status.ShowUserProfile" = "Mostrar perfil da usuaria"; +"Common.Controls.Status.Tag.Email" = "Email"; +"Common.Controls.Status.Tag.Emoji" = "Emoticona"; +"Common.Controls.Status.Tag.Hashtag" = "Cancelo"; +"Common.Controls.Status.Tag.Link" = "Ligazón"; +"Common.Controls.Status.Tag.Mention" = "Mención"; +"Common.Controls.Status.Tag.Url" = "URL"; +"Common.Controls.Status.TapToReveal" = "Toca para mostrar"; +"Common.Controls.Status.UserReblogged" = "%@ promoveu"; +"Common.Controls.Status.UserRepliedTo" = "Respondeu a %@"; +"Common.Controls.Status.Visibility.Direct" = "Só a usuaria mencionada pode ver a publicación."; +"Common.Controls.Status.Visibility.Private" = "Só as seguidoras poden ver a publicación."; +"Common.Controls.Status.Visibility.PrivateFromMe" = "Só as miñas seguidoras poden ver esta publicación."; +"Common.Controls.Status.Visibility.Unlisted" = "A publicación é visible para calquera pero non aparece na cronoloxía pública."; +"Common.Controls.Tabs.Home" = "Inicio"; +"Common.Controls.Tabs.Notification" = "Notificación"; +"Common.Controls.Tabs.Profile" = "Perfil"; +"Common.Controls.Tabs.Search" = "Busca"; +"Common.Controls.Timeline.Filtered" = "Filtrado"; +"Common.Controls.Timeline.Header.BlockedWarning" = "You can’t view this user’s profile +until they unblock you."; +"Common.Controls.Timeline.Header.BlockingWarning" = "Non podes ver o perfil da usuaria +ata que a desbloquees. +Así ven outras o teu perfil."; +"Common.Controls.Timeline.Header.NoStatusFound" = "Non se atopa a publicación"; +"Common.Controls.Timeline.Header.SuspendedWarning" = "This user has been suspended."; +"Common.Controls.Timeline.Header.UserBlockedWarning" = "You can’t view %@’s profile +until they unblock you."; +"Common.Controls.Timeline.Header.UserBlockingWarning" = "You can’t view %@’s profile +until you unblock them. +Your profile looks like this to them."; +"Common.Controls.Timeline.Header.UserSuspendedWarning" = "%@’s account has been suspended."; +"Common.Controls.Timeline.Loader.LoadMissingPosts" = "Cargar publicacións que faltan"; +"Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Cargando as publicacións que faltan..."; +"Common.Controls.Timeline.Loader.ShowMoreReplies" = "Mostrar máis respostas"; +"Common.Controls.Timeline.Timestamp.Now" = "Agora"; +"Scene.AccountList.AddAccount" = "Add Account"; +"Scene.AccountList.DismissAccountSwitcher" = "Dismiss Account Switcher"; +"Scene.AccountList.TabBarHint" = "Current selected profile: %@. Double tap then hold to show account switcher"; +"Scene.Compose.Accessibility.AppendAttachment" = "Engadir anexo"; +"Scene.Compose.Accessibility.AppendPoll" = "Engadir enquisa"; +"Scene.Compose.Accessibility.CustomEmojiPicker" = "Selector emoji personalizado"; +"Scene.Compose.Accessibility.DisableContentWarning" = "Retirar Aviso sobre o contido"; +"Scene.Compose.Accessibility.EnableContentWarning" = "Marcar con Aviso sobre o contido"; +"Scene.Compose.Accessibility.PostVisibilityMenu" = "Visibilidade da publicación"; +"Scene.Compose.Accessibility.RemovePoll" = "Eliminar enquisa"; +"Scene.Compose.Attachment.AttachmentBroken" = "This %@ is broken and can’t be +uploaded to Mastodon."; +"Scene.Compose.Attachment.DescriptionPhoto" = "Describe the photo for the visually-impaired..."; +"Scene.Compose.Attachment.DescriptionVideo" = "Describe the video for the visually-impaired..."; +"Scene.Compose.Attachment.Photo" = "photo"; +"Scene.Compose.Attachment.Video" = "video"; +"Scene.Compose.AutoComplete.SpaceToAdd" = "Barra de espazo engade"; +"Scene.Compose.ComposeAction" = "Publish"; +"Scene.Compose.ContentInputPlaceholder" = "Type or paste what’s on your mind"; +"Scene.Compose.ContentWarning.Placeholder" = "Escribe o teu aviso aquí..."; +"Scene.Compose.Keyboard.AppendAttachmentEntry" = "Engadir anexo - %@"; +"Scene.Compose.Keyboard.DiscardPost" = "Descartar publicación"; +"Scene.Compose.Keyboard.PublishPost" = "Publicar"; +"Scene.Compose.Keyboard.SelectVisibilityEntry" = "Elexir visibilidade - %@"; +"Scene.Compose.Keyboard.ToggleContentWarning" = "Marcar con Aviso sobre o contido"; +"Scene.Compose.Keyboard.TogglePoll" = "Activar enquisa"; +"Scene.Compose.MediaSelection.Browse" = "Browse"; +"Scene.Compose.MediaSelection.Camera" = "Take Photo"; +"Scene.Compose.MediaSelection.PhotoLibrary" = "Photo Library"; +"Scene.Compose.Poll.DurationTime" = "Duration: %@"; +"Scene.Compose.Poll.OneDay" = "1 Día"; +"Scene.Compose.Poll.OneHour" = "1 Hour"; +"Scene.Compose.Poll.OptionNumber" = "Opción %ld"; +"Scene.Compose.Poll.SevenDays" = "7 Días"; +"Scene.Compose.Poll.SixHours" = "6 Hours"; +"Scene.Compose.Poll.ThirtyMinutes" = "30 minutes"; +"Scene.Compose.Poll.ThreeDays" = "3 Días"; +"Scene.Compose.ReplyingToUser" = "replying to %@"; +"Scene.Compose.Title.NewPost" = "New Post"; +"Scene.Compose.Title.NewReply" = "New Reply"; +"Scene.Compose.Visibility.Direct" = "Só para persoas mencionadas"; +"Scene.Compose.Visibility.Private" = "Só para seguidoras"; +"Scene.Compose.Visibility.Public" = "Público"; +"Scene.Compose.Visibility.Unlisted" = "Non listado"; +"Scene.ConfirmEmail.Button.OpenEmailApp" = "Open Email App"; +"Scene.ConfirmEmail.Button.Resend" = "Resend"; +"Scene.ConfirmEmail.DontReceiveEmail.Description" = "Check if your email address is correct as well as your junk folder if you haven’t."; +"Scene.ConfirmEmail.DontReceiveEmail.ResendEmail" = "Resend Email"; +"Scene.ConfirmEmail.DontReceiveEmail.Title" = "Check your email"; +"Scene.ConfirmEmail.OpenEmailApp.Description" = "We just sent you an email. Check your junk folder if you haven’t."; +"Scene.ConfirmEmail.OpenEmailApp.Mail" = "Mail"; +"Scene.ConfirmEmail.OpenEmailApp.OpenEmailClient" = "Open Email Client"; +"Scene.ConfirmEmail.OpenEmailApp.Title" = "Check your inbox."; +"Scene.ConfirmEmail.Subtitle" = "Tap the link we emailed to you to verify your account."; +"Scene.ConfirmEmail.Title" = "One last thing."; +"Scene.Discovery.Intro" = "These are the posts gaining traction in your corner of Mastodon."; +"Scene.Discovery.Tabs.Community" = "Comunidade"; +"Scene.Discovery.Tabs.ForYou" = "For You"; +"Scene.Discovery.Tabs.Hashtags" = "Cancelos"; +"Scene.Discovery.Tabs.News" = "Novas"; +"Scene.Discovery.Tabs.Posts" = "Publicacións"; +"Scene.Favorite.Title" = "Your Favorites"; +"Scene.Follower.Footer" = "Non se mostran seguidoras desde outros servidores."; +"Scene.Following.Footer" = "Non se mostran os seguimentos desde outros servidores."; +"Scene.HomeTimeline.NavigationBarState.NewPosts" = "See new posts"; +"Scene.HomeTimeline.NavigationBarState.Offline" = "Offline"; +"Scene.HomeTimeline.NavigationBarState.Published" = "Published!"; +"Scene.HomeTimeline.NavigationBarState.Publishing" = "Publishing post..."; +"Scene.HomeTimeline.Title" = "Home"; +"Scene.Notification.Keyobard.ShowEverything" = "Show Everything"; +"Scene.Notification.Keyobard.ShowMentions" = "Show Mentions"; +"Scene.Notification.NotificationDescription.FavoritedYourPost" = "favorited your post"; +"Scene.Notification.NotificationDescription.FollowedYou" = "followed you"; +"Scene.Notification.NotificationDescription.MentionedYou" = "mentioned you"; +"Scene.Notification.NotificationDescription.PollHasEnded" = "poll has ended"; +"Scene.Notification.NotificationDescription.RebloggedYourPost" = "reblogged your post"; +"Scene.Notification.NotificationDescription.RequestToFollowYou" = "request to follow you"; +"Scene.Notification.Title.Everything" = "Everything"; +"Scene.Notification.Title.Mentions" = "Mentions"; +"Scene.Preview.Keyboard.ClosePreview" = "Pechar vista previa"; +"Scene.Preview.Keyboard.ShowNext" = "Mostrar Seguinte"; +"Scene.Preview.Keyboard.ShowPrevious" = "Mostar Anterior"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Dous toques para abrir a lista"; +"Scene.Profile.Accessibility.EditAvatarImage" = "Editar imaxe de avatar"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "Mostrar imaxe de avatar"; +"Scene.Profile.Accessibility.ShowBannerImage" = "Mostrar imaxe de cabeceira"; +"Scene.Profile.Dashboard.Followers" = "seguidoras"; +"Scene.Profile.Dashboard.Following" = "seguindo"; +"Scene.Profile.Dashboard.Posts" = "publicacións"; +"Scene.Profile.Fields.AddRow" = "Engadir fila"; +"Scene.Profile.Fields.Placeholder.Content" = "Contido"; +"Scene.Profile.Fields.Placeholder.Label" = "Etiqueta"; +"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Message" = "Confirma o bloqueo de %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Title" = "Bloquear Conta"; +"Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Message" = "Confirma Acalar a %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Title" = "Acalar conta"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Message" = "Confirma o desbloqueo de %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Title" = "Desbloquear Conta"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Message" = "Confirma restablecer a %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Title" = "Retirar acalado da Conta"; +"Scene.Profile.SegmentedControl.About" = "Acerca de"; +"Scene.Profile.SegmentedControl.Media" = "Multimedia"; +"Scene.Profile.SegmentedControl.Posts" = "Publicacións"; +"Scene.Profile.SegmentedControl.PostsAndReplies" = "Publicacións e respostas"; +"Scene.Profile.SegmentedControl.Replies" = "Respostas"; +"Scene.Register.Error.Item.Agreement" = "Acordo"; +"Scene.Register.Error.Item.Email" = "Email"; +"Scene.Register.Error.Item.Locale" = "Locale"; +"Scene.Register.Error.Item.Password" = "Contrasinal"; +"Scene.Register.Error.Item.Reason" = "Razón"; +"Scene.Register.Error.Item.Username" = "Identificador"; +"Scene.Register.Error.Reason.Accepted" = "%@ debe ser aceptado"; +"Scene.Register.Error.Reason.Blank" = "%@ é requerido"; +"Scene.Register.Error.Reason.Blocked" = "%@ é un provedor de email non autorizado"; +"Scene.Register.Error.Reason.Inclusion" = "%@ non é un valor soportado"; +"Scene.Register.Error.Reason.Invalid" = "%@ non é válido"; +"Scene.Register.Error.Reason.Reserved" = "%@ é unha palabra reservada"; +"Scene.Register.Error.Reason.Taken" = "%@ xa está en uso"; +"Scene.Register.Error.Reason.TooLong" = "%@ é demasiado longo"; +"Scene.Register.Error.Reason.TooShort" = "%@ é demasiado curto"; +"Scene.Register.Error.Reason.Unreachable" = "%@ semella que non existe"; +"Scene.Register.Error.Special.EmailInvalid" = "This is not a valid email address"; +"Scene.Register.Error.Special.PasswordTooShort" = "Password is too short (must be at least 8 characters)"; +"Scene.Register.Error.Special.UsernameInvalid" = "O nome de usuaria só pode ter caracteres alfanuméricos e trazos baixos"; +"Scene.Register.Error.Special.UsernameTooLong" = "Username is too long (can’t be longer than 30 characters)"; +"Scene.Register.Input.Avatar.Delete" = "Eliminar"; +"Scene.Register.Input.DisplayName.Placeholder" = "nome público"; +"Scene.Register.Input.Email.Placeholder" = "email"; +"Scene.Register.Input.Invite.RegistrationUserInviteRequest" = "Por que queres unirte?"; +"Scene.Register.Input.Password.Accessibility.Checked" = "validado"; +"Scene.Register.Input.Password.Accessibility.Unchecked" = "non validado"; +"Scene.Register.Input.Password.CharacterLimit" = "8 caracteres"; +"Scene.Register.Input.Password.Hint" = "O teu contrasinal debe ter cando menos oito caracteres"; +"Scene.Register.Input.Password.Placeholder" = "contrasinal"; +"Scene.Register.Input.Password.Require" = "O contrasinal debe ter polo menos:"; +"Scene.Register.Input.Username.DuplicatePrompt" = "Este nome de usuaria xa está en uso."; +"Scene.Register.Input.Username.Placeholder" = "identificador"; +"Scene.Register.Title" = "Imos crear a túa conta en %@"; +"Scene.Report.Content1" = "Hai outras publicacións que desexes engadir á denuncia?"; +"Scene.Report.Content2" = "Hai algo que a moderación deba saber acerca desta denuncia?"; +"Scene.Report.ReportSentTitle" = "Grazas pola denuncia, investigarémola."; +"Scene.Report.Reported" = "DENUNCIADO"; +"Scene.Report.Send" = "Enviar Denuncia"; +"Scene.Report.SkipToSend" = "Enviar sen comentarios"; +"Scene.Report.Step1" = "Paso 1 de 2"; +"Scene.Report.Step2" = "Paso 2 de 2"; +"Scene.Report.TextPlaceholder" = "Escribe ou pega comentarios adicionais"; +"Scene.Report.Title" = "Denunciar a %@"; +"Scene.Report.TitleReport" = "Denunciar"; +"Scene.Search.Recommend.Accounts.Description" = "Mira se che interesan estas contas"; +"Scene.Search.Recommend.Accounts.Follow" = "Seguir"; +"Scene.Search.Recommend.Accounts.Title" = "Contas que poderían gustarche"; +"Scene.Search.Recommend.ButtonText" = "Ver todo"; +"Scene.Search.Recommend.HashTag.Description" = "Cancelos que están recibindo moita atención"; +"Scene.Search.Recommend.HashTag.PeopleTalking" = "%@ persoas están comentando"; +"Scene.Search.Recommend.HashTag.Title" = "En voga en Mastodon"; +"Scene.Search.SearchBar.Cancel" = "Cancelar"; +"Scene.Search.SearchBar.Placeholder" = "Buscar cancelos e usuarias"; +"Scene.Search.Searching.Clear" = "Limpar"; +"Scene.Search.Searching.EmptyState.NoResults" = "Sen resultados"; +"Scene.Search.Searching.RecentSearch" = "Buscas recentes"; +"Scene.Search.Searching.Segment.All" = "Todo"; +"Scene.Search.Searching.Segment.Hashtags" = "Cancelos"; +"Scene.Search.Searching.Segment.People" = "Persoas"; +"Scene.Search.Searching.Segment.Posts" = "Publicacións"; +"Scene.Search.Title" = "Procurar"; +"Scene.ServerPicker.Button.Category.Academia" = "academia"; +"Scene.ServerPicker.Button.Category.Activism" = "activismo"; +"Scene.ServerPicker.Button.Category.All" = "Todo"; +"Scene.ServerPicker.Button.Category.AllAccessiblityDescription" = "Categoría: Todo"; +"Scene.ServerPicker.Button.Category.Art" = "arte"; +"Scene.ServerPicker.Button.Category.Food" = "comida"; +"Scene.ServerPicker.Button.Category.Furry" = "peluxos"; +"Scene.ServerPicker.Button.Category.Games" = "xogos"; +"Scene.ServerPicker.Button.Category.General" = "xeral"; +"Scene.ServerPicker.Button.Category.Journalism" = "xornalismo"; +"Scene.ServerPicker.Button.Category.Lgbt" = "lgbt"; +"Scene.ServerPicker.Button.Category.Music" = "música"; +"Scene.ServerPicker.Button.Category.Regional" = "rexional"; +"Scene.ServerPicker.Button.Category.Tech" = "tecnoloxía"; +"Scene.ServerPicker.Button.SeeLess" = "Ver menos"; +"Scene.ServerPicker.Button.SeeMore" = "Ver máis"; +"Scene.ServerPicker.EmptyState.BadNetwork" = "Algo fallou ao cargar os datos. Comproba a conexión a internet."; +"Scene.ServerPicker.EmptyState.FindingServers" = "Buscando servidores dispoñibles..."; +"Scene.ServerPicker.EmptyState.NoResults" = "Sen resultados"; +"Scene.ServerPicker.Input.Placeholder" = "Buscar comunidades"; +"Scene.ServerPicker.Label.Category" = "CATEGORÍA"; +"Scene.ServerPicker.Label.Language" = "IDIOMA"; +"Scene.ServerPicker.Label.Users" = "USUARIAS"; +"Scene.ServerPicker.Subtitle" = "Elixe unha comunidade en función dos teus intereses, rexión ou unha de propósito xeral."; +"Scene.ServerPicker.SubtitleExtend" = "Elixe unha comunidade en función dos teus intereses, rexión ou unha de propósito xeral. Cada comunidade está xestionada por unha organización totalmente independente ou unha única persoa."; +"Scene.ServerPicker.Title" = "Mastodon fórmano as persoas das diferentes comunidades."; +"Scene.ServerRules.Button.Confirm" = "I Agree"; +"Scene.ServerRules.PrivacyPolicy" = "privacy policy"; +"Scene.ServerRules.Prompt" = "By continuing, you’re subject to the terms of service and privacy policy for %@."; +"Scene.ServerRules.Subtitle" = "These are set and enforced by the %@ moderators."; +"Scene.ServerRules.TermsOfService" = "terms of service"; +"Scene.ServerRules.Title" = "Some ground rules."; +"Scene.Settings.Footer.MastodonDescription" = "Mastodon is open source software. You can report issues on GitHub at %@ (%@)"; +"Scene.Settings.Keyboard.CloseSettingsWindow" = "Close Settings Window"; +"Scene.Settings.Section.Appearance.Automatic" = "Automatic"; +"Scene.Settings.Section.Appearance.Dark" = "Always Dark"; +"Scene.Settings.Section.Appearance.Light" = "Always Light"; +"Scene.Settings.Section.Appearance.Title" = "Appearance"; +"Scene.Settings.Section.BoringZone.AccountSettings" = "Account Settings"; +"Scene.Settings.Section.BoringZone.Privacy" = "Privacy Policy"; +"Scene.Settings.Section.BoringZone.Terms" = "Terms of Service"; +"Scene.Settings.Section.BoringZone.Title" = "The Boring Zone"; +"Scene.Settings.Section.LookAndFeel.Light" = "Light"; +"Scene.Settings.Section.LookAndFeel.ReallyDark" = "Really Dark"; +"Scene.Settings.Section.LookAndFeel.SortaDark" = "Sorta Dark"; +"Scene.Settings.Section.LookAndFeel.Title" = "Look and Feel"; +"Scene.Settings.Section.LookAndFeel.UseSystem" = "Use System"; +"Scene.Settings.Section.Notifications.Boosts" = "Reblogs my post"; +"Scene.Settings.Section.Notifications.Favorites" = "Favorites my post"; +"Scene.Settings.Section.Notifications.Follows" = "Follows me"; +"Scene.Settings.Section.Notifications.Mentions" = "Mentions me"; +"Scene.Settings.Section.Notifications.Title" = "Notifications"; +"Scene.Settings.Section.Notifications.Trigger.Anyone" = "anyone"; +"Scene.Settings.Section.Notifications.Trigger.Follow" = "anyone I follow"; +"Scene.Settings.Section.Notifications.Trigger.Follower" = "a follower"; +"Scene.Settings.Section.Notifications.Trigger.Noone" = "no one"; +"Scene.Settings.Section.Notifications.Trigger.Title" = "Notify me when"; +"Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Disable animated avatars"; +"Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Disable animated emojis"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Open links in Mastodon"; +"Scene.Settings.Section.Preference.Title" = "Preferences"; +"Scene.Settings.Section.Preference.TrueBlackDarkMode" = "True black dark mode"; +"Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Use default browser to open links"; +"Scene.Settings.Section.SpicyZone.Clear" = "Clear Media Cache"; +"Scene.Settings.Section.SpicyZone.Signout" = "Sign Out"; +"Scene.Settings.Section.SpicyZone.Title" = "The Spicy Zone"; +"Scene.Settings.Title" = "Settings"; +"Scene.SuggestionAccount.FollowExplain" = "When you follow someone, you’ll see their posts in your home feed."; +"Scene.SuggestionAccount.Title" = "Find People to Follow"; +"Scene.Thread.BackTitle" = "Post"; +"Scene.Thread.Title" = "Post from %@"; +"Scene.Welcome.GetStarted" = "Comezar"; +"Scene.Welcome.LogIn" = "Acceder"; +"Scene.Welcome.Slogan" = "Social networking +back in your hands."; +"Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard"; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button."; +"Scene.Wizard.NewInMastodon" = "New in Mastodon"; \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/gl.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/gl.lproj/Localizable.stringsdict new file mode 100644 index 000000000..503ff9dbd --- /dev/null +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/gl.lproj/Localizable.stringsdict @@ -0,0 +1,406 @@ + + + + + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 unread notification + other + %ld unread notification + + + a11y.plural.count.input_limit_exceeds + + NSStringLocalizedFormatKey + Input limit exceeds %#@character_count@ + character_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 character + other + %ld characters + + + a11y.plural.count.input_limit_remains + + NSStringLocalizedFormatKey + Input limit remains %#@character_count@ + character_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 character + other + %ld characters + + + plural.count.metric_formatted.post + + NSStringLocalizedFormatKey + %@ %#@post_count@ + post_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + post + other + posts + + + plural.count.post + + NSStringLocalizedFormatKey + %#@post_count@ + post_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 post + other + %ld posts + + + plural.count.favorite + + NSStringLocalizedFormatKey + %#@favorite_count@ + favorite_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 favorite + other + %ld favorites + + + plural.count.reblog + + NSStringLocalizedFormatKey + %#@reblog_count@ + reblog_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reblog + other + %ld reblogs + + + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 reply + other + %ld replies + + + plural.count.vote + + NSStringLocalizedFormatKey + %#@vote_count@ + vote_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 vote + other + %ld votes + + + plural.count.voter + + NSStringLocalizedFormatKey + %#@voter_count@ + voter_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 voter + other + %ld voters + + + plural.people_talking + + NSStringLocalizedFormatKey + %#@count_people_talking@ + count_people_talking + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 people talking + other + %ld people talking + + + plural.count.following + + NSStringLocalizedFormatKey + %#@count_following@ + count_following + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 following + other + %ld following + + + plural.count.follower + + NSStringLocalizedFormatKey + %#@count_follower@ + count_follower + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 follower + other + %ld followers + + + date.year.left + + NSStringLocalizedFormatKey + %#@count_year_left@ + count_year_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 year left + other + %ld years left + + + date.month.left + + NSStringLocalizedFormatKey + %#@count_month_left@ + count_month_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 months left + other + %ld months left + + + date.day.left + + NSStringLocalizedFormatKey + %#@count_day_left@ + count_day_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 day left + other + %ld days left + + + date.hour.left + + NSStringLocalizedFormatKey + %#@count_hour_left@ + count_hour_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 hour left + other + %ld hours left + + + date.minute.left + + NSStringLocalizedFormatKey + %#@count_minute_left@ + count_minute_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 minute left + other + %ld minutes left + + + date.second.left + + NSStringLocalizedFormatKey + %#@count_second_left@ + count_second_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 second left + other + %ld seconds left + + + date.year.ago.abbr + + NSStringLocalizedFormatKey + %#@count_year_ago_abbr@ + count_year_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1y ago + other + %ldy ago + + + date.month.ago.abbr + + NSStringLocalizedFormatKey + %#@count_month_ago_abbr@ + count_month_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1M ago + other + %ldM ago + + + date.day.ago.abbr + + NSStringLocalizedFormatKey + %#@count_day_ago_abbr@ + count_day_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1d ago + other + %ldd ago + + + date.hour.ago.abbr + + NSStringLocalizedFormatKey + %#@count_hour_ago_abbr@ + count_hour_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1h ago + other + %ldh ago + + + date.minute.ago.abbr + + NSStringLocalizedFormatKey + %#@count_minute_ago_abbr@ + count_minute_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1m ago + other + %ldm ago + + + date.second.ago.abbr + + NSStringLocalizedFormatKey + %#@count_second_ago_abbr@ + count_second_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1s ago + other + %lds ago + + + + diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/it.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/it.lproj/Localizable.strings new file mode 100644 index 000000000..0c10d8d60 --- /dev/null +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/it.lproj/Localizable.strings @@ -0,0 +1,391 @@ +"Common.Alerts.BlockDomain.BlockEntireDomain" = "Blocca il dominio"; +"Common.Alerts.BlockDomain.Title" = "Vuoi davvero bloccare %@ completamente? Nella maggioranza dei casi, è preferibile e sufficiente bloccare o silenziare pochi account in modo mirato. Non vedrai i contenuti di quel dominio e tutti i tuoi follower da quel dominio verranno rimossi."; +"Common.Alerts.CleanCache.Message" = "Cache %@ pulita con successo."; +"Common.Alerts.CleanCache.Title" = "Pulisci la cache"; +"Common.Alerts.Common.PleaseTryAgain" = "Per favore riprova."; +"Common.Alerts.Common.PleaseTryAgainLater" = "Per favore, riprova più tardi."; +"Common.Alerts.DeletePost.Message" = "Vuoi veramente eliminare questo post?"; +"Common.Alerts.DeletePost.Title" = "Cancella il post"; +"Common.Alerts.DiscardPostContent.Message" = "Confermare di scartare il contenuto del post composto."; +"Common.Alerts.DiscardPostContent.Title" = "Elimina bozza"; +"Common.Alerts.EditProfileFailure.Message" = "Impossibile modificare il profilo. Per favore, riprova."; +"Common.Alerts.EditProfileFailure.Title" = "Errore nella modifica del profilo"; +"Common.Alerts.PublishPostFailure.AttachmentsMessage.MoreThanOneVideo" = "Impossibile allegare più di un filmato."; +"Common.Alerts.PublishPostFailure.AttachmentsMessage.VideoAttachWithPhoto" = "Impossibile allegare un filmato a un post che contiene già immagini."; +"Common.Alerts.PublishPostFailure.Message" = "Pubblicazione del post fallita. +Per favore verifica la tua connessione internet."; +"Common.Alerts.PublishPostFailure.Title" = "Pubblicazione fallita"; +"Common.Alerts.SavePhotoFailure.Message" = "Si prega di abilitare l'autorizzazione di accesso alla galleria immagini per salvare la foto."; +"Common.Alerts.SavePhotoFailure.Title" = "Salvataggio foto fallito"; +"Common.Alerts.ServerError.Title" = "Errore del server"; +"Common.Alerts.SignOut.Confirm" = "Esci"; +"Common.Alerts.SignOut.Message" = "Vuoi davvero scollegarti?"; +"Common.Alerts.SignOut.Title" = "Esci"; +"Common.Alerts.SignUpFailure.Title" = "Iscrizione fallita"; +"Common.Alerts.VoteFailure.PollEnded" = "Il sondaggio è terminato"; +"Common.Alerts.VoteFailure.Title" = "Voto fallito"; +"Common.Controls.Actions.Add" = "Aggiungi"; +"Common.Controls.Actions.Back" = "Indietro"; +"Common.Controls.Actions.BlockDomain" = "Blocca %@"; +"Common.Controls.Actions.Cancel" = "Annulla"; +"Common.Controls.Actions.Compose" = "Scrivi"; +"Common.Controls.Actions.Confirm" = "Conferma"; +"Common.Controls.Actions.Continue" = "Continua"; +"Common.Controls.Actions.CopyPhoto" = "Copia foto"; +"Common.Controls.Actions.Delete" = "Elimina"; +"Common.Controls.Actions.Discard" = "Abbandona"; +"Common.Controls.Actions.Done" = "Fatto"; +"Common.Controls.Actions.Edit" = "Modifica"; +"Common.Controls.Actions.FindPeople" = "Trova persone da seguire"; +"Common.Controls.Actions.ManuallySearch" = "Cerca manualmente invece"; +"Common.Controls.Actions.Next" = "Avanti"; +"Common.Controls.Actions.Ok" = "OK"; +"Common.Controls.Actions.Open" = "Apri"; +"Common.Controls.Actions.OpenInBrowser" = "Apri nel browser"; +"Common.Controls.Actions.OpenInSafari" = "Apri su Safari"; +"Common.Controls.Actions.Preview" = "Anteprima"; +"Common.Controls.Actions.Previous" = "Precedente"; +"Common.Controls.Actions.Remove" = "Rimuovi"; +"Common.Controls.Actions.Reply" = "Rispondi"; +"Common.Controls.Actions.ReportUser" = "Segnala %@"; +"Common.Controls.Actions.Save" = "Salva"; +"Common.Controls.Actions.SavePhoto" = "Salva foto"; +"Common.Controls.Actions.SeeMore" = "Visualizza altro"; +"Common.Controls.Actions.Settings" = "Impostazioni"; +"Common.Controls.Actions.Share" = "Condividi"; +"Common.Controls.Actions.SharePost" = "Condividi il post"; +"Common.Controls.Actions.ShareUser" = "Condividi %@"; +"Common.Controls.Actions.SignIn" = "Accedi"; +"Common.Controls.Actions.SignUp" = "Registrati"; +"Common.Controls.Actions.Skip" = "Salta"; +"Common.Controls.Actions.TakePhoto" = "Scatta foto"; +"Common.Controls.Actions.TryAgain" = "Riprova"; +"Common.Controls.Actions.UnblockDomain" = "Sblocca %@"; +"Common.Controls.Friendship.Block" = "Blocca"; +"Common.Controls.Friendship.BlockDomain" = "Blocca %@"; +"Common.Controls.Friendship.BlockUser" = "Blocca %@"; +"Common.Controls.Friendship.Blocked" = "Bloccato"; +"Common.Controls.Friendship.EditInfo" = "Modifica info"; +"Common.Controls.Friendship.Follow" = "Segui"; +"Common.Controls.Friendship.Following" = "Stai seguendo"; +"Common.Controls.Friendship.Mute" = "Silenzia"; +"Common.Controls.Friendship.MuteUser" = "Silenzia %@"; +"Common.Controls.Friendship.Muted" = "Silenziato"; +"Common.Controls.Friendship.Pending" = "In attesa"; +"Common.Controls.Friendship.Request" = "Richiesta"; +"Common.Controls.Friendship.Unblock" = "Sblocca"; +"Common.Controls.Friendship.UnblockUser" = "Sblocca %@"; +"Common.Controls.Friendship.Unmute" = "Riattiva"; +"Common.Controls.Friendship.UnmuteUser" = "Riattiva %@"; +"Common.Controls.Keyboard.Common.ComposeNewPost" = "Componi un nuovo post"; +"Common.Controls.Keyboard.Common.OpenSettings" = "Apri Impostazioni"; +"Common.Controls.Keyboard.Common.ShowFavorites" = "Mostra preferiti"; +"Common.Controls.Keyboard.Common.SwitchToTab" = "Passa a %@"; +"Common.Controls.Keyboard.SegmentedControl.NextSection" = "Sezione successiva"; +"Common.Controls.Keyboard.SegmentedControl.PreviousSection" = "Sezione precedente"; +"Common.Controls.Keyboard.Timeline.NextStatus" = "Post successivo"; +"Common.Controls.Keyboard.Timeline.OpenAuthorProfile" = "Apri il profilo dell'autore"; +"Common.Controls.Keyboard.Timeline.OpenRebloggerProfile" = "Apri il profilo di chi ha condiviso"; +"Common.Controls.Keyboard.Timeline.OpenStatus" = "Apri il post"; +"Common.Controls.Keyboard.Timeline.PreviewImage" = "Anteprima immagine"; +"Common.Controls.Keyboard.Timeline.PreviousStatus" = "Post precedente"; +"Common.Controls.Keyboard.Timeline.ReplyStatus" = "Rispondi al post"; +"Common.Controls.Keyboard.Timeline.ToggleContentWarning" = "Attiva/Disattiva avvertimento contenuti"; +"Common.Controls.Keyboard.Timeline.ToggleFavorite" = "Attiva/Disattiva preferito nel post"; +"Common.Controls.Keyboard.Timeline.ToggleReblog" = "Attiva/Disattiva condivisione sul post"; +"Common.Controls.Status.Actions.Favorite" = "Preferito"; +"Common.Controls.Status.Actions.Hide" = "Nascondi"; +"Common.Controls.Status.Actions.Menu" = "Menù"; +"Common.Controls.Status.Actions.Reblog" = "Condivisione"; +"Common.Controls.Status.Actions.Reply" = "Rispondi"; +"Common.Controls.Status.Actions.ShowGif" = "Mostra GIF"; +"Common.Controls.Status.Actions.ShowImage" = "Mostra immagine"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Mostra lettore video"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tocca quindi tieni premuto per mostrare il menu"; +"Common.Controls.Status.Actions.Unfavorite" = "Non preferito"; +"Common.Controls.Status.Actions.Unreblog" = "Annulla condivisione"; +"Common.Controls.Status.ContentWarning" = "Avviso sul contenuto"; +"Common.Controls.Status.MediaContentWarning" = "Tocca ovunque per rivelare"; +"Common.Controls.Status.Poll.Closed" = "Chiuso"; +"Common.Controls.Status.Poll.Vote" = "Vota"; +"Common.Controls.Status.SensitiveContent" = "Contenuto sensibile"; +"Common.Controls.Status.ShowPost" = "Mostra il post"; +"Common.Controls.Status.ShowUserProfile" = "Mostra il profilo dell'utente"; +"Common.Controls.Status.Tag.Email" = "Email"; +"Common.Controls.Status.Tag.Emoji" = "Emoji"; +"Common.Controls.Status.Tag.Hashtag" = "Etichetta"; +"Common.Controls.Status.Tag.Link" = "Collegamento"; +"Common.Controls.Status.Tag.Mention" = "Menzione"; +"Common.Controls.Status.Tag.Url" = "URL"; +"Common.Controls.Status.TapToReveal" = "Tocca per rivelare"; +"Common.Controls.Status.UserReblogged" = "%@ hanno condiviso"; +"Common.Controls.Status.UserRepliedTo" = "Rispondi a %@"; +"Common.Controls.Status.Visibility.Direct" = "Solo l'utente menzionato può vedere questo post."; +"Common.Controls.Status.Visibility.Private" = "Solo i loro seguaci possono vedere questo post."; +"Common.Controls.Status.Visibility.PrivateFromMe" = "Solo i miei seguaci possono vedere questo post."; +"Common.Controls.Status.Visibility.Unlisted" = "Tutti possono vedere questo post ma non mostrare nella cronologia pubblica."; +"Common.Controls.Tabs.Home" = "Inizio"; +"Common.Controls.Tabs.Notification" = "Notifiche"; +"Common.Controls.Tabs.Profile" = "Profilo"; +"Common.Controls.Tabs.Search" = "Cerca"; +"Common.Controls.Timeline.Filtered" = "Filtrato"; +"Common.Controls.Timeline.Header.BlockedWarning" = "Non puoi visualizzare il profilo di questo utente +fino a quando non ti sbloccano."; +"Common.Controls.Timeline.Header.BlockingWarning" = "Non puoi visualizzare il profilo di questo utente +finché non li sblocchi. +Il tuo profilo sembra questo per loro."; +"Common.Controls.Timeline.Header.NoStatusFound" = "Nessun post trovato"; +"Common.Controls.Timeline.Header.SuspendedWarning" = "Questo utente è stato sospeso."; +"Common.Controls.Timeline.Header.UserBlockedWarning" = "Non puoi visualizzare il profilo di %@ +fino a quando non ti sbloccano."; +"Common.Controls.Timeline.Header.UserBlockingWarning" = "Non puoi visualizzare il profilo di %@ +finché non li sblocchi. +Il tuo profilo sembra questo per loro."; +"Common.Controls.Timeline.Header.UserSuspendedWarning" = "L'account di %@ è stato sospeso."; +"Common.Controls.Timeline.Loader.LoadMissingPosts" = "Carica i post mancanti"; +"Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Caricamento post mancanti..."; +"Common.Controls.Timeline.Loader.ShowMoreReplies" = "Mostra più risposte"; +"Common.Controls.Timeline.Timestamp.Now" = "Ora"; +"Scene.AccountList.AddAccount" = "Aggiungi account"; +"Scene.AccountList.DismissAccountSwitcher" = "Ignora il cambio account"; +"Scene.AccountList.TabBarHint" = "Profilo corrente selezionato: %@. Doppio tocco e tieni premuto per mostrare il cambio account"; +"Scene.Compose.Accessibility.AppendAttachment" = "Aggiungi allegato"; +"Scene.Compose.Accessibility.AppendPoll" = "Aggiungi sondaggio"; +"Scene.Compose.Accessibility.CustomEmojiPicker" = "Selettore Emoji personalizzato"; +"Scene.Compose.Accessibility.DisableContentWarning" = "Disabilita avviso di contenuti"; +"Scene.Compose.Accessibility.EnableContentWarning" = "Abilita avvertimento contenuti"; +"Scene.Compose.Accessibility.PostVisibilityMenu" = "Menu di visibilità del post"; +"Scene.Compose.Accessibility.RemovePoll" = "Elimina sondaggio"; +"Scene.Compose.Attachment.AttachmentBroken" = "Questo %@ è rotto e non può essere +caricato su Mastodon."; +"Scene.Compose.Attachment.DescriptionPhoto" = "Descrivi la foto per gli utenti ipovedenti..."; +"Scene.Compose.Attachment.DescriptionVideo" = "Descrivi il filmato per gli utenti ipovedenti..."; +"Scene.Compose.Attachment.Photo" = "foto"; +"Scene.Compose.Attachment.Video" = "filmato"; +"Scene.Compose.AutoComplete.SpaceToAdd" = "Spazio da aggiungere"; +"Scene.Compose.ComposeAction" = "Pubblica"; +"Scene.Compose.ContentInputPlaceholder" = "Digita o incolla quello che hai in mente"; +"Scene.Compose.ContentWarning.Placeholder" = "Scrivi un avviso accurato qui..."; +"Scene.Compose.Keyboard.AppendAttachmentEntry" = "Aggiungi allegato - %@"; +"Scene.Compose.Keyboard.DiscardPost" = "Scarta post"; +"Scene.Compose.Keyboard.PublishPost" = "Pubblica il post"; +"Scene.Compose.Keyboard.SelectVisibilityEntry" = "Seleziona visibilità - %@"; +"Scene.Compose.Keyboard.ToggleContentWarning" = "Attiva/Disattiva avviso contenuti"; +"Scene.Compose.Keyboard.TogglePoll" = "Attiva/Disattiva Sondaggio"; +"Scene.Compose.MediaSelection.Browse" = "Sfoglia"; +"Scene.Compose.MediaSelection.Camera" = "Scatta foto"; +"Scene.Compose.MediaSelection.PhotoLibrary" = "Libreria foto"; +"Scene.Compose.Poll.DurationTime" = "Durata: %@"; +"Scene.Compose.Poll.OneDay" = "1 giorno"; +"Scene.Compose.Poll.OneHour" = "1 ora"; +"Scene.Compose.Poll.OptionNumber" = "Opzione %ld"; +"Scene.Compose.Poll.SevenDays" = "7 giorni"; +"Scene.Compose.Poll.SixHours" = "6 ore"; +"Scene.Compose.Poll.ThirtyMinutes" = "30 minuti"; +"Scene.Compose.Poll.ThreeDays" = "3 giorni"; +"Scene.Compose.ReplyingToUser" = "rispondendo a %@"; +"Scene.Compose.Title.NewPost" = "Nuovo post"; +"Scene.Compose.Title.NewReply" = "Nuova risposta"; +"Scene.Compose.Visibility.Direct" = "Solo le persone che menziono"; +"Scene.Compose.Visibility.Private" = "Solo i seguaci"; +"Scene.Compose.Visibility.Public" = "Pubblico"; +"Scene.Compose.Visibility.Unlisted" = "Non elencato"; +"Scene.ConfirmEmail.Button.OpenEmailApp" = "Apri l'app Email"; +"Scene.ConfirmEmail.Button.Resend" = "Invia di nuovo"; +"Scene.ConfirmEmail.DontReceiveEmail.Description" = "Controlla se il tuo indirizzo email sia corretto, così come la tua cartella spazzatura se non ce l'hai."; +"Scene.ConfirmEmail.DontReceiveEmail.ResendEmail" = "Invia e-mail di nuovo"; +"Scene.ConfirmEmail.DontReceiveEmail.Title" = "Controlla la tua e-mail"; +"Scene.ConfirmEmail.OpenEmailApp.Description" = "Ti abbiamo appena inviato un'email. Controlla la tua cartella spazzatura se non ce l'hai."; +"Scene.ConfirmEmail.OpenEmailApp.Mail" = "Posta"; +"Scene.ConfirmEmail.OpenEmailApp.OpenEmailClient" = "Apri client Email"; +"Scene.ConfirmEmail.OpenEmailApp.Title" = "Controlla la tua posta in arrivo."; +"Scene.ConfirmEmail.Subtitle" = "Tocca il link che ti abbiamo inviato per verificare il tuo account."; +"Scene.ConfirmEmail.Title" = "Un'ultima cosa."; +"Scene.Discovery.Intro" = "Questi sono i post che stanno guadagnando popolarità nel tuo angolo di Mastodon."; +"Scene.Discovery.Tabs.Community" = "Community"; +"Scene.Discovery.Tabs.ForYou" = "Per Te"; +"Scene.Discovery.Tabs.Hashtags" = "Hashtag"; +"Scene.Discovery.Tabs.News" = "Notizie"; +"Scene.Discovery.Tabs.Posts" = "Post"; +"Scene.Favorite.Title" = "I tuoi preferiti"; +"Scene.Follower.Footer" = "I seguaci da altri server non vengono visualizzati."; +"Scene.Following.Footer" = "I follow da altri server non vengono visualizzati."; +"Scene.HomeTimeline.NavigationBarState.NewPosts" = "Vedi nuovi post"; +"Scene.HomeTimeline.NavigationBarState.Offline" = "Non in linea"; +"Scene.HomeTimeline.NavigationBarState.Published" = "Pubblicato!"; +"Scene.HomeTimeline.NavigationBarState.Publishing" = "Pubblicazione post..."; +"Scene.HomeTimeline.Title" = "Inizio"; +"Scene.Notification.Keyobard.ShowEverything" = "Mostra Tutto"; +"Scene.Notification.Keyobard.ShowMentions" = "Mostra Menzioni"; +"Scene.Notification.NotificationDescription.FavoritedYourPost" = "ha apprezzato il tuo post"; +"Scene.Notification.NotificationDescription.FollowedYou" = "ti ha seguito"; +"Scene.Notification.NotificationDescription.MentionedYou" = "ti ha menzionato"; +"Scene.Notification.NotificationDescription.PollHasEnded" = "sondaggio terminato"; +"Scene.Notification.NotificationDescription.RebloggedYourPost" = "ha ripostato il tuo post"; +"Scene.Notification.NotificationDescription.RequestToFollowYou" = "richiesta di seguirti"; +"Scene.Notification.Title.Everything" = "Tutto"; +"Scene.Notification.Title.Mentions" = "Menzioni"; +"Scene.Preview.Keyboard.ClosePreview" = "Chiudi anteprima"; +"Scene.Preview.Keyboard.ShowNext" = "Mostra successivo"; +"Scene.Preview.Keyboard.ShowPrevious" = "Mostra precedente"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Doppio tocco per aprire la lista"; +"Scene.Profile.Accessibility.EditAvatarImage" = "Modifica immagine avatar"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "Mostra immagine avatar"; +"Scene.Profile.Accessibility.ShowBannerImage" = "Mostra immagine banner"; +"Scene.Profile.Dashboard.Followers" = "seguaci"; +"Scene.Profile.Dashboard.Following" = "seguendo"; +"Scene.Profile.Dashboard.Posts" = "post"; +"Scene.Profile.Fields.AddRow" = "Aggiungi riga"; +"Scene.Profile.Fields.Placeholder.Content" = "Contenuto"; +"Scene.Profile.Fields.Placeholder.Label" = "Etichetta"; +"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Message" = "Confermi di bloccare %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Title" = "Blocca account"; +"Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Message" = "Confermi di silenziare %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Title" = "Silenzia account"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Message" = "Conferma per sbloccare %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Title" = "Sblocca account"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Message" = "Confermi di riattivare %@"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Title" = "Riattiva account"; +"Scene.Profile.SegmentedControl.About" = "Info su"; +"Scene.Profile.SegmentedControl.Media" = "Media"; +"Scene.Profile.SegmentedControl.Posts" = "Post"; +"Scene.Profile.SegmentedControl.PostsAndReplies" = "Post e risposte"; +"Scene.Profile.SegmentedControl.Replies" = "Risposte"; +"Scene.Register.Error.Item.Agreement" = "Accordo"; +"Scene.Register.Error.Item.Email" = "Email"; +"Scene.Register.Error.Item.Locale" = "Locale"; +"Scene.Register.Error.Item.Password" = "Password"; +"Scene.Register.Error.Item.Reason" = "Motivo"; +"Scene.Register.Error.Item.Username" = "Nome utente"; +"Scene.Register.Error.Reason.Accepted" = "%@ deve essere accettato"; +"Scene.Register.Error.Reason.Blank" = "%@ è richiesto"; +"Scene.Register.Error.Reason.Blocked" = "%@ contiene un provider email non consentito"; +"Scene.Register.Error.Reason.Inclusion" = "%@ non è un valore supportato"; +"Scene.Register.Error.Reason.Invalid" = "%@ non è valido"; +"Scene.Register.Error.Reason.Reserved" = "%@ è una parola chiave riservata"; +"Scene.Register.Error.Reason.Taken" = "%@ è già in uso"; +"Scene.Register.Error.Reason.TooLong" = "%@ è troppo lungo"; +"Scene.Register.Error.Reason.TooShort" = "%@ è troppo corto"; +"Scene.Register.Error.Reason.Unreachable" = "%@ non sembra esistere"; +"Scene.Register.Error.Special.EmailInvalid" = "Questo non è un indirizzo email valido"; +"Scene.Register.Error.Special.PasswordTooShort" = "La password è troppo corta (deve contenere almeno 8 caratteri)"; +"Scene.Register.Error.Special.UsernameInvalid" = "Il nome utente deve contenere solo caratteri alfanumerici e trattini bassi"; +"Scene.Register.Error.Special.UsernameTooLong" = "Il nome utente è troppo lungo (non può essere più lungo di 30 caratteri)"; +"Scene.Register.Input.Avatar.Delete" = "Elimina"; +"Scene.Register.Input.DisplayName.Placeholder" = "visualizza nome"; +"Scene.Register.Input.Email.Placeholder" = "email"; +"Scene.Register.Input.Invite.RegistrationUserInviteRequest" = "Perché vuoi unirti?"; +"Scene.Register.Input.Password.Accessibility.Checked" = "verificato"; +"Scene.Register.Input.Password.Accessibility.Unchecked" = "non verificato"; +"Scene.Register.Input.Password.CharacterLimit" = "8 caratteri"; +"Scene.Register.Input.Password.Hint" = "La tua password deve essere di almeno 8 caratteri"; +"Scene.Register.Input.Password.Placeholder" = "password"; +"Scene.Register.Input.Password.Require" = "La tua password ha bisogno di almeno:"; +"Scene.Register.Input.Username.DuplicatePrompt" = "Questo nome utente è già stato preso."; +"Scene.Register.Input.Username.Placeholder" = "nome utente"; +"Scene.Register.Title" = "Facciamo in modo che sia configurato il %@"; +"Scene.Report.Content1" = "Ci sono altri post che vorresti aggiungere alla segnalazione?"; +"Scene.Report.Content2" = "C'è qualcosa che i moderatori dovrebbero sapere su questa segnalazione?"; +"Scene.Report.ReportSentTitle" = "Grazie per la segnalazione, esamineremo questo aspetto."; +"Scene.Report.Reported" = "SEGNALATO"; +"Scene.Report.Send" = "Invia segnalazione"; +"Scene.Report.SkipToSend" = "Invia senza commento"; +"Scene.Report.Step1" = "Fase 1 di 2"; +"Scene.Report.Step2" = "Fase 2 di 2"; +"Scene.Report.TextPlaceholder" = "Digita o incolla commenti aggiuntivi"; +"Scene.Report.Title" = "Segnala %@"; +"Scene.Report.TitleReport" = "Segnala"; +"Scene.Search.Recommend.Accounts.Description" = "Potresti voler seguire questi account"; +"Scene.Search.Recommend.Accounts.Follow" = "Segui"; +"Scene.Search.Recommend.Accounts.Title" = "Account che potrebbero piacerti"; +"Scene.Search.Recommend.ButtonText" = "Vedi tutto"; +"Scene.Search.Recommend.HashTag.Description" = "Hashtag che stanno ottenendo un bel po' di attenzione"; +"Scene.Search.Recommend.HashTag.PeopleTalking" = "%@ persone ne parlano"; +"Scene.Search.Recommend.HashTag.Title" = "Di tendenza su Mastodon"; +"Scene.Search.SearchBar.Cancel" = "Annulla"; +"Scene.Search.SearchBar.Placeholder" = "Cerca hashtag e utenti"; +"Scene.Search.Searching.Clear" = "Cancella"; +"Scene.Search.Searching.EmptyState.NoResults" = "Nessun risultato"; +"Scene.Search.Searching.RecentSearch" = "Ricerche recenti"; +"Scene.Search.Searching.Segment.All" = "Tutto"; +"Scene.Search.Searching.Segment.Hashtags" = "Hashtags"; +"Scene.Search.Searching.Segment.People" = "Persone"; +"Scene.Search.Searching.Segment.Posts" = "Post"; +"Scene.Search.Title" = "Cerca"; +"Scene.ServerPicker.Button.Category.Academia" = "accademia"; +"Scene.ServerPicker.Button.Category.Activism" = "attivismo"; +"Scene.ServerPicker.Button.Category.All" = "Tutti"; +"Scene.ServerPicker.Button.Category.AllAccessiblityDescription" = "Categoria: Tutti"; +"Scene.ServerPicker.Button.Category.Art" = "arte"; +"Scene.ServerPicker.Button.Category.Food" = "cibo"; +"Scene.ServerPicker.Button.Category.Furry" = "peloso"; +"Scene.ServerPicker.Button.Category.Games" = "giochi"; +"Scene.ServerPicker.Button.Category.General" = "generale"; +"Scene.ServerPicker.Button.Category.Journalism" = "giornalismo"; +"Scene.ServerPicker.Button.Category.Lgbt" = "lgbt"; +"Scene.ServerPicker.Button.Category.Music" = "musica"; +"Scene.ServerPicker.Button.Category.Regional" = "locale"; +"Scene.ServerPicker.Button.Category.Tech" = "tecnologia"; +"Scene.ServerPicker.Button.SeeLess" = "Vedi meno"; +"Scene.ServerPicker.Button.SeeMore" = "Vedi di più"; +"Scene.ServerPicker.EmptyState.BadNetwork" = "Qualcosa è andato storto durante il caricamento dei dati. Controlla la tua connessione internet."; +"Scene.ServerPicker.EmptyState.FindingServers" = "Ricerca server disponibili..."; +"Scene.ServerPicker.EmptyState.NoResults" = "Nessun risultato"; +"Scene.ServerPicker.Input.Placeholder" = "Cerca comunità"; +"Scene.ServerPicker.Label.Category" = "CATEGORIA"; +"Scene.ServerPicker.Label.Language" = "LINGUA"; +"Scene.ServerPicker.Label.Users" = "UTENTI"; +"Scene.ServerPicker.Subtitle" = "Scegli una comunità basata sui tuoi interessi, regione o uno scopo generale."; +"Scene.ServerPicker.SubtitleExtend" = "Scegli una comunità basata sui tuoi interessi, regione o uno scopo generale. Ogni comunità è gestita da un'organizzazione completamente indipendente o individuale."; +"Scene.ServerPicker.Title" = "Mastodon è fatto di utenti in diverse comunità."; +"Scene.ServerRules.Button.Confirm" = "Accetto"; +"Scene.ServerRules.PrivacyPolicy" = "privacy policy"; +"Scene.ServerRules.Prompt" = "Continuando, sei soggetto alle condizioni di servizio e all'informativa sulla privacy per %@."; +"Scene.ServerRules.Subtitle" = "Questi sono impostati e applicati dai moderatori %@."; +"Scene.ServerRules.TermsOfService" = "condizioni del servizio"; +"Scene.ServerRules.Title" = "Alcune regole di base."; +"Scene.Settings.Footer.MastodonDescription" = "Mastodon è un software open source. Puoi segnalare problemi su GitHub a %@ (%@)"; +"Scene.Settings.Keyboard.CloseSettingsWindow" = "Chiudi la finestra Impostazioni"; +"Scene.Settings.Section.Appearance.Automatic" = "Automatico"; +"Scene.Settings.Section.Appearance.Dark" = "Sempre scuro"; +"Scene.Settings.Section.Appearance.Light" = "Sempre chiaro"; +"Scene.Settings.Section.Appearance.Title" = "Aspetto"; +"Scene.Settings.Section.BoringZone.AccountSettings" = "Impostazioni account"; +"Scene.Settings.Section.BoringZone.Privacy" = "Politica sulla Privacy"; +"Scene.Settings.Section.BoringZone.Terms" = "Termini di servizio"; +"Scene.Settings.Section.BoringZone.Title" = "La zona boring"; +"Scene.Settings.Section.LookAndFeel.Light" = "Chiaro"; +"Scene.Settings.Section.LookAndFeel.ReallyDark" = "Davvero scuro"; +"Scene.Settings.Section.LookAndFeel.SortaDark" = "Un po' scuro"; +"Scene.Settings.Section.LookAndFeel.Title" = "Look and Feel"; +"Scene.Settings.Section.LookAndFeel.UseSystem" = "Predefinito di sistema"; +"Scene.Settings.Section.Notifications.Boosts" = "Condivide i miei post"; +"Scene.Settings.Section.Notifications.Favorites" = "Apprezza i miei post"; +"Scene.Settings.Section.Notifications.Follows" = "Mi segue"; +"Scene.Settings.Section.Notifications.Mentions" = "Mi menziona"; +"Scene.Settings.Section.Notifications.Title" = "Notifiche"; +"Scene.Settings.Section.Notifications.Trigger.Anyone" = "chiunque"; +"Scene.Settings.Section.Notifications.Trigger.Follow" = "chiunque io segua"; +"Scene.Settings.Section.Notifications.Trigger.Follower" = "un seguace"; +"Scene.Settings.Section.Notifications.Trigger.Noone" = "nessuno"; +"Scene.Settings.Section.Notifications.Trigger.Title" = "Avvisami quando"; +"Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Disabilita avatar animati"; +"Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Disabilita emoji animate"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Apri i link in Mastodon"; +"Scene.Settings.Section.Preference.Title" = "Preferenze"; +"Scene.Settings.Section.Preference.TrueBlackDarkMode" = "Modalità molto scura"; +"Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Usa browser predefinito per aprire i collegamenti"; +"Scene.Settings.Section.SpicyZone.Clear" = "Cancella la cache multimediale"; +"Scene.Settings.Section.SpicyZone.Signout" = "Esci"; +"Scene.Settings.Section.SpicyZone.Title" = "La zona piccante"; +"Scene.Settings.Title" = "Impostazioni"; +"Scene.SuggestionAccount.FollowExplain" = "Quando segui qualcuno, vedrai i loro post nella tua home feed."; +"Scene.SuggestionAccount.Title" = "Trova alcune persone da seguire"; +"Scene.Thread.BackTitle" = "Post"; +"Scene.Thread.Title" = "Post da %@"; +"Scene.Welcome.GetStarted" = "Inizia"; +"Scene.Welcome.LogIn" = "Accedi"; +"Scene.Welcome.Slogan" = "Il social network, di nuovo nelle tue mani."; +"Scene.Wizard.AccessibilityHint" = "Doppio tocco per eliminare questa procedura guidata"; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Passa tra più account tenendo premuto il pulsante del profilo."; +"Scene.Wizard.NewInMastodon" = "Nuovo su Mastodon"; \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/it.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/it.lproj/Localizable.stringsdict new file mode 100644 index 000000000..710980608 --- /dev/null +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/it.lproj/Localizable.stringsdict @@ -0,0 +1,406 @@ + + + + + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 notifica non letta + other + %ld notifiche non lette + + + a11y.plural.count.input_limit_exceeds + + NSStringLocalizedFormatKey + Il limite di input supera %#@character_count@ + character_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 carattere + other + %ld caratteri + + + a11y.plural.count.input_limit_remains + + NSStringLocalizedFormatKey + Il limite di input rimane %#@character_count@ + character_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 carattere + other + %ld caratteri + + + plural.count.metric_formatted.post + + NSStringLocalizedFormatKey + %@ %#@post_count@ + post_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + post + other + post + + + plural.count.post + + NSStringLocalizedFormatKey + %#@post_count@ + post_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 post + other + %ld post + + + plural.count.favorite + + NSStringLocalizedFormatKey + %#@favorite_count@ + favorite_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 preferito + other + %ld preferiti + + + plural.count.reblog + + NSStringLocalizedFormatKey + %#@reblog_count@ + reblog_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 condivisione + other + %ld condivisioni + + + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 risposta + other + %ld risposte + + + plural.count.vote + + NSStringLocalizedFormatKey + %#@vote_count@ + vote_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 voto + other + %ld voti + + + plural.count.voter + + NSStringLocalizedFormatKey + %#@voter_count@ + voter_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 votante + other + %ld votanti + + + plural.people_talking + + NSStringLocalizedFormatKey + %#@count_people_talking@ + count_people_talking + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 persona ne parla + other + %ld persone ne parlano + + + plural.count.following + + NSStringLocalizedFormatKey + %#@count_following@ + count_following + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 following + other + %ld stanno seguendo + + + plural.count.follower + + NSStringLocalizedFormatKey + %#@count_follower@ + count_follower + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 seguace + other + %ld seguaci + + + date.year.left + + NSStringLocalizedFormatKey + %#@count_year_left@ + count_year_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 anno rimasto + other + %ld anni rimasti + + + date.month.left + + NSStringLocalizedFormatKey + %#@count_month_left@ + count_month_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 mese rimasto + other + %ld mesi rimasti + + + date.day.left + + NSStringLocalizedFormatKey + %#@count_day_left@ + count_day_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 giorno rimasto + other + %ld giorni rimasti + + + date.hour.left + + NSStringLocalizedFormatKey + %#@count_hour_left@ + count_hour_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 ora rimasta + other + %ld ore rimaste + + + date.minute.left + + NSStringLocalizedFormatKey + %#@count_minute_left@ + count_minute_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 minuto rimasto + other + %ld minuti rimasti + + + date.second.left + + NSStringLocalizedFormatKey + %#@count_second_left@ + count_second_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 secondo rimasto + other + %ld secondi rimasti + + + date.year.ago.abbr + + NSStringLocalizedFormatKey + %#@count_year_ago_abbr@ + count_year_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 anno fa + other + %ld anni fa + + + date.month.ago.abbr + + NSStringLocalizedFormatKey + %#@count_month_ago_abbr@ + count_month_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 mese fa + other + %ld mesi fa + + + date.day.ago.abbr + + NSStringLocalizedFormatKey + %#@count_day_ago_abbr@ + count_day_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 giorno fa + other + %ld giorni fa + + + date.hour.ago.abbr + + NSStringLocalizedFormatKey + %#@count_hour_ago_abbr@ + count_hour_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 ora fa + other + %ld ore fa + + + date.minute.ago.abbr + + NSStringLocalizedFormatKey + %#@count_minute_ago_abbr@ + count_minute_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 minuto fa + other + %ld minuti fa + + + date.second.ago.abbr + + NSStringLocalizedFormatKey + %#@count_second_ago_abbr@ + count_second_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 secondo fa + other + %ld secondi fa + + + + diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/tr.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/tr.lproj/Localizable.strings new file mode 100644 index 000000000..9bee4db1a --- /dev/null +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/tr.lproj/Localizable.strings @@ -0,0 +1,391 @@ +"Common.Alerts.BlockDomain.BlockEntireDomain" = "Alan Adını Engelle"; +"Common.Alerts.BlockDomain.Title" = "%@ alan adını tamamen engellemek istediğine gerçekten emin misiniz? Pek çok durumda o alan adından birkaç kişiyi engellemek ve sessize almak yeterlidir ve tercih edilir. Engellediğinizde bu alan adından herhangi bir içerik görmeyeceksiniz ve o alan adından olan takipçileriniz silinecek."; +"Common.Alerts.CleanCache.Message" = "%@ boyutunda önbellek temizlendi."; +"Common.Alerts.CleanCache.Title" = "Önbelleği Temizle"; +"Common.Alerts.Common.PleaseTryAgain" = "Lütfen tekrar deneyin."; +"Common.Alerts.Common.PleaseTryAgainLater" = "Lütfen daha sonra tekrar deneyin."; +"Common.Alerts.DeletePost.Message" = "Bu gönderiyi silmek istediğinize emin misiniz?"; +"Common.Alerts.DeletePost.Title" = "Gönderiyi Sil"; +"Common.Alerts.DiscardPostContent.Message" = "Yazdığın gönderiyi paylaşmadan silmek istiyor musun?"; +"Common.Alerts.DiscardPostContent.Title" = "Taslağı Sil"; +"Common.Alerts.EditProfileFailure.Message" = "Profil düzenlenemedi. Lütfen tekrar deneyin."; +"Common.Alerts.EditProfileFailure.Title" = "Profil Düzenleme Hatası"; +"Common.Alerts.PublishPostFailure.AttachmentsMessage.MoreThanOneVideo" = "Gönderiye birden fazla video eklenemez."; +"Common.Alerts.PublishPostFailure.AttachmentsMessage.VideoAttachWithPhoto" = "İçeriğinde görseller olan bir gönderiye video eklenemez."; +"Common.Alerts.PublishPostFailure.Message" = "Gönderi paylaşılamadı. Lütfen internet bağlantını kontrol et."; +"Common.Alerts.PublishPostFailure.Title" = "Paylaşılamadı"; +"Common.Alerts.SavePhotoFailure.Message" = "Görseli kaydetmek için lütfen galeri erişim iznini aktifleştirin."; +"Common.Alerts.SavePhotoFailure.Title" = "Görsel Kaydetme Hatası"; +"Common.Alerts.ServerError.Title" = "Sunucu Hatası"; +"Common.Alerts.SignOut.Confirm" = "Oturumu Kapat"; +"Common.Alerts.SignOut.Message" = "Oturumu kapatmak istediğinize emin misiniz?"; +"Common.Alerts.SignOut.Title" = "Oturumu Kapat"; +"Common.Alerts.SignUpFailure.Title" = "Kaydolma Başarısız"; +"Common.Alerts.VoteFailure.PollEnded" = "Anket bitti"; +"Common.Alerts.VoteFailure.Title" = "Oy Verme Başarısız"; +"Common.Controls.Actions.Add" = "Ekle"; +"Common.Controls.Actions.Back" = "Geri"; +"Common.Controls.Actions.BlockDomain" = "%@ kişisini engelle"; +"Common.Controls.Actions.Cancel" = "İptal et"; +"Common.Controls.Actions.Compose" = "Yaz"; +"Common.Controls.Actions.Confirm" = "Onayla"; +"Common.Controls.Actions.Continue" = "Devam et"; +"Common.Controls.Actions.CopyPhoto" = "Fotoğrafı Kopyala"; +"Common.Controls.Actions.Delete" = "Sil"; +"Common.Controls.Actions.Discard" = "Vazgeç"; +"Common.Controls.Actions.Done" = "Kapat"; +"Common.Controls.Actions.Edit" = "Düzenle"; +"Common.Controls.Actions.FindPeople" = "Takip etmek için birkaç kişi bul"; +"Common.Controls.Actions.ManuallySearch" = "Onun yerine manuel olarak ara"; +"Common.Controls.Actions.Next" = "İleri"; +"Common.Controls.Actions.Ok" = "Tamam"; +"Common.Controls.Actions.Open" = "Aç"; +"Common.Controls.Actions.OpenInBrowser" = "Tarayıcıda Aç"; +"Common.Controls.Actions.OpenInSafari" = "Safari'de Aç"; +"Common.Controls.Actions.Preview" = "Önizleme"; +"Common.Controls.Actions.Previous" = "Önceki"; +"Common.Controls.Actions.Remove" = "Kaldır"; +"Common.Controls.Actions.Reply" = "Yanıtla"; +"Common.Controls.Actions.ReportUser" = "%@ kişisini bildir"; +"Common.Controls.Actions.Save" = "Kaydet"; +"Common.Controls.Actions.SavePhoto" = "Fotoğrafı Kaydet"; +"Common.Controls.Actions.SeeMore" = "Daha Fazla Gör"; +"Common.Controls.Actions.Settings" = "Ayarlar"; +"Common.Controls.Actions.Share" = "Paylaş"; +"Common.Controls.Actions.SharePost" = "Gönderiyi Paylaş"; +"Common.Controls.Actions.ShareUser" = "%@ ile paylaş"; +"Common.Controls.Actions.SignIn" = "Giriş Yap"; +"Common.Controls.Actions.SignUp" = "Kaydol"; +"Common.Controls.Actions.Skip" = "Atla"; +"Common.Controls.Actions.TakePhoto" = "Fotoğraf Çek"; +"Common.Controls.Actions.TryAgain" = "Tekrar Deneyin"; +"Common.Controls.Actions.UnblockDomain" = "%@ kişisinin engelini kaldır"; +"Common.Controls.Friendship.Block" = "Engelle"; +"Common.Controls.Friendship.BlockDomain" = "%@ kişisini engelle"; +"Common.Controls.Friendship.BlockUser" = "%@ kişisini engelle"; +"Common.Controls.Friendship.Blocked" = "Engellendi"; +"Common.Controls.Friendship.EditInfo" = "Bilgiyi Düzenle"; +"Common.Controls.Friendship.Follow" = "Takip et"; +"Common.Controls.Friendship.Following" = "Takip ediliyor"; +"Common.Controls.Friendship.Mute" = "Sessize al"; +"Common.Controls.Friendship.MuteUser" = "Sustur %@"; +"Common.Controls.Friendship.Muted" = "Susturuldu"; +"Common.Controls.Friendship.Pending" = "Bekliyor"; +"Common.Controls.Friendship.Request" = "İstek"; +"Common.Controls.Friendship.Unblock" = "Engeli kaldır"; +"Common.Controls.Friendship.UnblockUser" = "%@ kişisinin engelini kaldır"; +"Common.Controls.Friendship.Unmute" = "Susturmayı kaldır"; +"Common.Controls.Friendship.UnmuteUser" = "Sesini aç %@"; +"Common.Controls.Keyboard.Common.ComposeNewPost" = "Yeni Gönderi Yaz"; +"Common.Controls.Keyboard.Common.OpenSettings" = "Ayarları Aç"; +"Common.Controls.Keyboard.Common.ShowFavorites" = "Favorilerimi Göster"; +"Common.Controls.Keyboard.Common.SwitchToTab" = "Geç: %@"; +"Common.Controls.Keyboard.SegmentedControl.NextSection" = "Sonraki Bölüm"; +"Common.Controls.Keyboard.SegmentedControl.PreviousSection" = "Önceki Seçim"; +"Common.Controls.Keyboard.Timeline.NextStatus" = "Sonraki Gönderi"; +"Common.Controls.Keyboard.Timeline.OpenAuthorProfile" = "Yazarın Profilini Aç"; +"Common.Controls.Keyboard.Timeline.OpenRebloggerProfile" = "Yeniden Paylaşanın Profilini Aç"; +"Common.Controls.Keyboard.Timeline.OpenStatus" = "Gönderiyi Aç"; +"Common.Controls.Keyboard.Timeline.PreviewImage" = "Görseli Önizle"; +"Common.Controls.Keyboard.Timeline.PreviousStatus" = "Önceki Gönderi"; +"Common.Controls.Keyboard.Timeline.ReplyStatus" = "Gönderiyi Yanıtla"; +"Common.Controls.Keyboard.Timeline.ToggleContentWarning" = "İçerik Uyarısı durumunu değiştir"; +"Common.Controls.Keyboard.Timeline.ToggleFavorite" = "Gönderiyi favorileme durumunu değiştir"; +"Common.Controls.Keyboard.Timeline.ToggleReblog" = "Gönderiyi yeniden paylaşma durumunu değiştir"; +"Common.Controls.Status.Actions.Favorite" = "Favorile"; +"Common.Controls.Status.Actions.Hide" = "Gizle"; +"Common.Controls.Status.Actions.Menu" = "Menü"; +"Common.Controls.Status.Actions.Reblog" = "Yeniden paylaş"; +"Common.Controls.Status.Actions.Reply" = "Yanıtla"; +"Common.Controls.Status.Actions.ShowGif" = "GIF'i göster"; +"Common.Controls.Status.Actions.ShowImage" = "Görüntüyü göster"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "Video oynatıcıyı göster"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Menüyü göstermek için dokunun ve basılı tutun"; +"Common.Controls.Status.Actions.Unfavorite" = "Favorilerden Çıkar"; +"Common.Controls.Status.Actions.Unreblog" = "Yeniden paylaşımı geri al"; +"Common.Controls.Status.ContentWarning" = "İçerik Uyarısı"; +"Common.Controls.Status.MediaContentWarning" = "Göstermek için herhangi bir yere basın"; +"Common.Controls.Status.Poll.Closed" = "Kapandı"; +"Common.Controls.Status.Poll.Vote" = "Oy ver"; +"Common.Controls.Status.SensitiveContent" = "Hassas İçerik"; +"Common.Controls.Status.ShowPost" = "Gönderiyi Göster"; +"Common.Controls.Status.ShowUserProfile" = "Kullanıcı profilini göster"; +"Common.Controls.Status.Tag.Email" = "E-posta"; +"Common.Controls.Status.Tag.Emoji" = "Emoji"; +"Common.Controls.Status.Tag.Hashtag" = "Etiket"; +"Common.Controls.Status.Tag.Link" = "Bağlantı"; +"Common.Controls.Status.Tag.Mention" = "Bahset"; +"Common.Controls.Status.Tag.Url" = "Bağlantı"; +"Common.Controls.Status.TapToReveal" = "Göstermek için basın"; +"Common.Controls.Status.UserReblogged" = "%@ yeniden paylaştı"; +"Common.Controls.Status.UserRepliedTo" = "%@ kullanıcısına yanıt verdi"; +"Common.Controls.Status.Visibility.Direct" = "Sadece bahsedilen kullanıcı bu gönderiyi görebilir."; +"Common.Controls.Status.Visibility.Private" = "Sadece gönderi sahibinin takipçileri bu gönderiyi görebilir."; +"Common.Controls.Status.Visibility.PrivateFromMe" = "Sadece benim takipçilerim bu gönderiyi görebilir."; +"Common.Controls.Status.Visibility.Unlisted" = "Bu gönderiyi herkes görebilir, fakat herkese açık zaman tünelinde gösterilmez."; +"Common.Controls.Tabs.Home" = "Ana Sayfa"; +"Common.Controls.Tabs.Notification" = "Bildirimler"; +"Common.Controls.Tabs.Profile" = "Profil"; +"Common.Controls.Tabs.Search" = "Arama"; +"Common.Controls.Timeline.Filtered" = "Filtrelenmiş"; +"Common.Controls.Timeline.Header.BlockedWarning" = "Bu kişi sizin engelinizi kaldırana +kadar onun profilini göremezsiniz."; +"Common.Controls.Timeline.Header.BlockingWarning" = "Bu kişinin engelini kaldırana kadar +onun profilini göremezsiniz. +Bu kişiye göre profiliniz böyle gözüküyor."; +"Common.Controls.Timeline.Header.NoStatusFound" = "Hiçbir Gönderi Bulunamadı"; +"Common.Controls.Timeline.Header.SuspendedWarning" = "Bu kullanıcı askıya alındı."; +"Common.Controls.Timeline.Header.UserBlockedWarning" = "%@ kişisi sizin engelinizi kaldırana +kadar onun profilini göremezsiniz."; +"Common.Controls.Timeline.Header.UserBlockingWarning" = "%@ kişisinin engelini kaldırana kadar +onun profilini göremezsiniz. +Bu kişiye göre profiliniz böyle gözüküyor."; +"Common.Controls.Timeline.Header.UserSuspendedWarning" = "%@ kişisinin hesabı askıya alındı."; +"Common.Controls.Timeline.Loader.LoadMissingPosts" = "Daha fazla gönderi yükle"; +"Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Daha fazla gönderi yükleniyor..."; +"Common.Controls.Timeline.Loader.ShowMoreReplies" = "Daha fazla yanıt görüntüe"; +"Common.Controls.Timeline.Timestamp.Now" = "Şimdi"; +"Scene.AccountList.AddAccount" = "Hesap Ekle"; +"Scene.AccountList.DismissAccountSwitcher" = "Hesap Değiştiriciyi Kapat"; +"Scene.AccountList.TabBarHint" = "Şu anki seçili profil: %@. Hesap değiştiriciyi göstermek için iki kez dokunun ve basılı tutun"; +"Scene.Compose.Accessibility.AppendAttachment" = "Dosya Ekle"; +"Scene.Compose.Accessibility.AppendPoll" = "Anket Ekle"; +"Scene.Compose.Accessibility.CustomEmojiPicker" = "Özel Emoji Seçici"; +"Scene.Compose.Accessibility.DisableContentWarning" = "İçerik Uyarısını Kapat"; +"Scene.Compose.Accessibility.EnableContentWarning" = "İçerik Uyarısını Etkinleştir"; +"Scene.Compose.Accessibility.PostVisibilityMenu" = "Gönderi Görünürlüğü Menüsü"; +"Scene.Compose.Accessibility.RemovePoll" = "Anketi Kaldır"; +"Scene.Compose.Attachment.AttachmentBroken" = "Bu %@ bozuk ve Mastodon'a +yüklenemiyor."; +"Scene.Compose.Attachment.DescriptionPhoto" = "Görme engelliler için fotoğrafı tarif edin..."; +"Scene.Compose.Attachment.DescriptionVideo" = "Görme engelliler için videoyu tarif edin..."; +"Scene.Compose.Attachment.Photo" = "fotoğraf"; +"Scene.Compose.Attachment.Video" = "video"; +"Scene.Compose.AutoComplete.SpaceToAdd" = "Eklemek için boşluk tuşuna basın"; +"Scene.Compose.ComposeAction" = "Yayınla"; +"Scene.Compose.ContentInputPlaceholder" = "Aklınızdan geçenleri yazın veya yapıştırın"; +"Scene.Compose.ContentWarning.Placeholder" = "Buraya kesin bir uyarı yazın..."; +"Scene.Compose.Keyboard.AppendAttachmentEntry" = "Dosya Ekle - %@"; +"Scene.Compose.Keyboard.DiscardPost" = "Gönderiyi İptal Et"; +"Scene.Compose.Keyboard.PublishPost" = "Gönderiyi Yayınla"; +"Scene.Compose.Keyboard.SelectVisibilityEntry" = "Görünürlüğü Seç - %@"; +"Scene.Compose.Keyboard.ToggleContentWarning" = "İçerik Uyarısı durumunu değiştir"; +"Scene.Compose.Keyboard.TogglePoll" = "Anketi Aç/Kapat"; +"Scene.Compose.MediaSelection.Browse" = "Göz at"; +"Scene.Compose.MediaSelection.Camera" = "Fotoğraf Çek"; +"Scene.Compose.MediaSelection.PhotoLibrary" = "Fotoğraf Albümü"; +"Scene.Compose.Poll.DurationTime" = "Süre: %@"; +"Scene.Compose.Poll.OneDay" = "1 Gün"; +"Scene.Compose.Poll.OneHour" = "1 Saat"; +"Scene.Compose.Poll.OptionNumber" = "Seçenek %ld"; +"Scene.Compose.Poll.SevenDays" = "7 Gün"; +"Scene.Compose.Poll.SixHours" = "6 Saat"; +"Scene.Compose.Poll.ThirtyMinutes" = "30 dakika"; +"Scene.Compose.Poll.ThreeDays" = "3 Gün"; +"Scene.Compose.ReplyingToUser" = "yanıtlanıyor: %@"; +"Scene.Compose.Title.NewPost" = "Yeni Gönderi"; +"Scene.Compose.Title.NewReply" = "Yeni Yanıt"; +"Scene.Compose.Visibility.Direct" = "Sadece bahsettiğim insanlar"; +"Scene.Compose.Visibility.Private" = "Yalnızca takipçiler"; +"Scene.Compose.Visibility.Public" = "Herkese açık"; +"Scene.Compose.Visibility.Unlisted" = "Listelenmemiş"; +"Scene.ConfirmEmail.Button.OpenEmailApp" = "E-posta Uygulamasını Aç"; +"Scene.ConfirmEmail.Button.Resend" = "Yeniden gönder"; +"Scene.ConfirmEmail.DontReceiveEmail.Description" = "E-posta adresinizin doğru olup olmadığını ve doğru ise gereksiz klasörünüzü kontrol edin."; +"Scene.ConfirmEmail.DontReceiveEmail.ResendEmail" = "E-postayı Yeniden Gönder"; +"Scene.ConfirmEmail.DontReceiveEmail.Title" = "Posta kutunuzu kontrol edin"; +"Scene.ConfirmEmail.OpenEmailApp.Description" = "Size bir e-posta gönderdik. Eğer e-postayı almadıysanız, gereksiz klasörünü kontrol edin."; +"Scene.ConfirmEmail.OpenEmailApp.Mail" = "Posta"; +"Scene.ConfirmEmail.OpenEmailApp.OpenEmailClient" = "E-posta İstemcisini Aç"; +"Scene.ConfirmEmail.OpenEmailApp.Title" = "Gelen kutunuzu kontrol edin."; +"Scene.ConfirmEmail.Subtitle" = "Hesabınızı doğrulamak için size e-postayla gönderdiğimiz bağlantıya dokunun."; +"Scene.ConfirmEmail.Title" = "Son bir şey."; +"Scene.Discovery.Intro" = "Bunlar, Mastodon'un köşesinde ilgi çeken gönderilerdir."; +"Scene.Discovery.Tabs.Community" = "Community"; +"Scene.Discovery.Tabs.ForYou" = "Senin İçin"; +"Scene.Discovery.Tabs.Hashtags" = "Etiketler"; +"Scene.Discovery.Tabs.News" = "Haberler"; +"Scene.Discovery.Tabs.Posts" = "Gönderiler"; +"Scene.Favorite.Title" = "Favorilerin"; +"Scene.Follower.Footer" = "Diğer sunucudaki takipçiler gösterilemiyor."; +"Scene.Following.Footer" = "Diğer sunucudaki takip edilenler gösterilemiyor."; +"Scene.HomeTimeline.NavigationBarState.NewPosts" = "Yeni gönderiler gör"; +"Scene.HomeTimeline.NavigationBarState.Offline" = "Çevrimdışı"; +"Scene.HomeTimeline.NavigationBarState.Published" = "Yayınlandı!"; +"Scene.HomeTimeline.NavigationBarState.Publishing" = "Gönderi yayınlanıyor..."; +"Scene.HomeTimeline.Title" = "Ana Sayfa"; +"Scene.Notification.Keyobard.ShowEverything" = "Her Şeyi Göster"; +"Scene.Notification.Keyobard.ShowMentions" = "Bahsetmeleri Göster"; +"Scene.Notification.NotificationDescription.FavoritedYourPost" = "gönderini favoriledi"; +"Scene.Notification.NotificationDescription.FollowedYou" = "seni takip etti"; +"Scene.Notification.NotificationDescription.MentionedYou" = "senden bahsetti"; +"Scene.Notification.NotificationDescription.PollHasEnded" = "anket sona erdi"; +"Scene.Notification.NotificationDescription.RebloggedYourPost" = "gönderini yeniden paylaştı"; +"Scene.Notification.NotificationDescription.RequestToFollowYou" = "size takip isteği gönderdi"; +"Scene.Notification.Title.Everything" = "Her şey"; +"Scene.Notification.Title.Mentions" = "Bahsetmeler"; +"Scene.Preview.Keyboard.ClosePreview" = "Önizlemeyi Kapat"; +"Scene.Preview.Keyboard.ShowNext" = "Sonrakini Göster"; +"Scene.Preview.Keyboard.ShowPrevious" = "Öncekini Göster"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "Listeyi açmak için çift tıklayın"; +"Scene.Profile.Accessibility.EditAvatarImage" = "Profil fotoğrafını düzenle"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "Profil resmini göster"; +"Scene.Profile.Accessibility.ShowBannerImage" = "Kapak fotoğrafını göster"; +"Scene.Profile.Dashboard.Followers" = "takipçi"; +"Scene.Profile.Dashboard.Following" = "takip ediliyor"; +"Scene.Profile.Dashboard.Posts" = "gönderiler"; +"Scene.Profile.Fields.AddRow" = "Satır Ekle"; +"Scene.Profile.Fields.Placeholder.Content" = "İçerik"; +"Scene.Profile.Fields.Placeholder.Label" = "Etiket"; +"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Message" = "%@ engellemeyi onayla"; +"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Title" = "Hesabı Engelle"; +"Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Message" = "%@ susturmak için onaylayın"; +"Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Title" = "Hesabı sustur"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Message" = "%@ engellemeyi kaldırmayı onaylayın"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Title" = "Hesabın Engelini Kaldır"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Message" = "%@ susturmasını kaldırmak için onaylayın"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Title" = "Susturmayı kaldır"; +"Scene.Profile.SegmentedControl.About" = "Hakkında"; +"Scene.Profile.SegmentedControl.Media" = "Medya"; +"Scene.Profile.SegmentedControl.Posts" = "Gönderiler"; +"Scene.Profile.SegmentedControl.PostsAndReplies" = "Gönderiler ve Yanıtlar"; +"Scene.Profile.SegmentedControl.Replies" = "Yanıtlar"; +"Scene.Register.Error.Item.Agreement" = "Anlaşma"; +"Scene.Register.Error.Item.Email" = "E-posta"; +"Scene.Register.Error.Item.Locale" = "Locale"; +"Scene.Register.Error.Item.Password" = "Parola"; +"Scene.Register.Error.Item.Reason" = "Sebep"; +"Scene.Register.Error.Item.Username" = "Kullanıcı adı"; +"Scene.Register.Error.Reason.Accepted" = "%@ kabul edilmelidir"; +"Scene.Register.Error.Reason.Blank" = "%@ gerekli"; +"Scene.Register.Error.Reason.Blocked" = "%@ izin verilmeyen bir e-posta sağlayıcı içeriyor"; +"Scene.Register.Error.Reason.Inclusion" = "%@ desteklenen bir değer değil"; +"Scene.Register.Error.Reason.Invalid" = "%@ geçersiz"; +"Scene.Register.Error.Reason.Reserved" = "%@ rezerve edilen bir kelime"; +"Scene.Register.Error.Reason.Taken" = "%@ zaten kullanımda"; +"Scene.Register.Error.Reason.TooLong" = "%@ çok uzun"; +"Scene.Register.Error.Reason.TooShort" = "%@ çok kısa"; +"Scene.Register.Error.Reason.Unreachable" = "%@ mevcut değil"; +"Scene.Register.Error.Special.EmailInvalid" = "Bu geçerli bir e-posta adresi değil"; +"Scene.Register.Error.Special.PasswordTooShort" = "Şifre çok kısa (en az 8 karakter olmalı)"; +"Scene.Register.Error.Special.UsernameInvalid" = "Kullanıcı adı yalnızca alfasayısal karakterler ve alt çizgiler içerebilir"; +"Scene.Register.Error.Special.UsernameTooLong" = "Kullanıcı adı çok uzun (30 karakterden uzun olamaz)"; +"Scene.Register.Input.Avatar.Delete" = "Sil"; +"Scene.Register.Input.DisplayName.Placeholder" = "görünen ad"; +"Scene.Register.Input.Email.Placeholder" = "e-posta"; +"Scene.Register.Input.Invite.RegistrationUserInviteRequest" = "Neden katılmak istiyorsun?"; +"Scene.Register.Input.Password.Accessibility.Checked" = "işaretli"; +"Scene.Register.Input.Password.Accessibility.Unchecked" = "işaretsiz"; +"Scene.Register.Input.Password.CharacterLimit" = "8 karakter"; +"Scene.Register.Input.Password.Hint" = "Parolanız en az sekiz karakter içermelidir"; +"Scene.Register.Input.Password.Placeholder" = "parola"; +"Scene.Register.Input.Password.Require" = "Parolanızda en azından şunlar olmalı:"; +"Scene.Register.Input.Username.DuplicatePrompt" = "Bu kullanıcı adı alınmış."; +"Scene.Register.Input.Username.Placeholder" = "kullanıcı adı"; +"Scene.Register.Title" = "%@ için kurulumunuzu yapalım"; +"Scene.Report.Content1" = "Bu rapora eklemek istediğiniz başka gönderiler var mı?"; +"Scene.Report.Content2" = "Bu rapor hakkında moderatörlerin bilmesi gerektiği bir şey var mı?"; +"Scene.Report.ReportSentTitle" = "Rapor için teşekkürler, bununla ilgileneceğiz."; +"Scene.Report.Reported" = "RAPORLANDI"; +"Scene.Report.Send" = "Raporu Gönder"; +"Scene.Report.SkipToSend" = "Yorum yapmadan gönder"; +"Scene.Report.Step1" = "Adım 1/2"; +"Scene.Report.Step2" = "Adım 2/2"; +"Scene.Report.TextPlaceholder" = "Ek yorum yazın veya yapıştırın"; +"Scene.Report.Title" = "%@ kişisini bildir"; +"Scene.Report.TitleReport" = "Raporla"; +"Scene.Search.Recommend.Accounts.Description" = "Bu hesapları takip etmek isteyebilirsiniz"; +"Scene.Search.Recommend.Accounts.Follow" = "Takip et"; +"Scene.Search.Recommend.Accounts.Title" = "Hoşunuza gidebilecek hesaplar"; +"Scene.Search.Recommend.ButtonText" = "Tümünü Gör"; +"Scene.Search.Recommend.HashTag.Description" = "Oldukça ilgi gören etiketler"; +"Scene.Search.Recommend.HashTag.PeopleTalking" = "%@ kişi konuşuyor"; +"Scene.Search.Recommend.HashTag.Title" = "Mastodon'da Popüler"; +"Scene.Search.SearchBar.Cancel" = "İptal"; +"Scene.Search.SearchBar.Placeholder" = "Etiketleri ve kullanıcıları ara"; +"Scene.Search.Searching.Clear" = "Temizle"; +"Scene.Search.Searching.EmptyState.NoResults" = "Sonuç yok"; +"Scene.Search.Searching.RecentSearch" = "Son aramalar"; +"Scene.Search.Searching.Segment.All" = "Tümü"; +"Scene.Search.Searching.Segment.Hashtags" = "Etiketler"; +"Scene.Search.Searching.Segment.People" = "İnsanlar"; +"Scene.Search.Searching.Segment.Posts" = "Gönderiler"; +"Scene.Search.Title" = "Arama"; +"Scene.ServerPicker.Button.Category.Academia" = "akademi"; +"Scene.ServerPicker.Button.Category.Activism" = "aktivizm"; +"Scene.ServerPicker.Button.Category.All" = "Tümü"; +"Scene.ServerPicker.Button.Category.AllAccessiblityDescription" = "Kategori: Tümü"; +"Scene.ServerPicker.Button.Category.Art" = "sanat"; +"Scene.ServerPicker.Button.Category.Food" = "yiyecek"; +"Scene.ServerPicker.Button.Category.Furry" = "furry"; +"Scene.ServerPicker.Button.Category.Games" = "oyunlar"; +"Scene.ServerPicker.Button.Category.General" = "genel"; +"Scene.ServerPicker.Button.Category.Journalism" = "gazetecilik"; +"Scene.ServerPicker.Button.Category.Lgbt" = "lgbt"; +"Scene.ServerPicker.Button.Category.Music" = "müzik"; +"Scene.ServerPicker.Button.Category.Regional" = "bölgesel"; +"Scene.ServerPicker.Button.Category.Tech" = "teknoloji"; +"Scene.ServerPicker.Button.SeeLess" = "Daha Az Göster"; +"Scene.ServerPicker.Button.SeeMore" = "Daha Fazla Gör"; +"Scene.ServerPicker.EmptyState.BadNetwork" = "Veriyi yüklerken bir hata oluştu. Lütfen internet bağlantınızı kontrol edin."; +"Scene.ServerPicker.EmptyState.FindingServers" = "Mevcut sunucular aranıyor..."; +"Scene.ServerPicker.EmptyState.NoResults" = "Sonuç yok"; +"Scene.ServerPicker.Input.Placeholder" = "Toplulukları ara"; +"Scene.ServerPicker.Label.Category" = "KATEGORİ"; +"Scene.ServerPicker.Label.Language" = "DİL"; +"Scene.ServerPicker.Label.Users" = "KULLANICILAR"; +"Scene.ServerPicker.Subtitle" = "İlgi alanlarınıza, bölgenize veya genel amaçlı bir topluluk seçin."; +"Scene.ServerPicker.SubtitleExtend" = "İlgi alanlarınıza, bölgenize veya genel amaçlı bir topluluk seçin. Her topluluk tamamen bağımsız bir kuruluş veya kişi tarafından işletilmektedir."; +"Scene.ServerPicker.Title" = "Mastodon, farklı topluluklardaki kullanıcılardan oluşur."; +"Scene.ServerRules.Button.Confirm" = "Kabul Ediyorum"; +"Scene.ServerRules.PrivacyPolicy" = "gizlilik politikası"; +"Scene.ServerRules.Prompt" = "Devam ederek, %@ için kullanım şartlarını ve gizlilik politikasını kabul etmiş olursunuz."; +"Scene.ServerRules.Subtitle" = "Bunlar, %@ moderatörleri tarafından ayarlanmış ve uygulanmıştır."; +"Scene.ServerRules.TermsOfService" = "kullanım şartları"; +"Scene.ServerRules.Title" = "Bazı temel kurallar."; +"Scene.Settings.Footer.MastodonDescription" = "Mastodon açık kaynaklı bir yazılımdır. GitHub'dan %@ (%@) üzerinden katkıda bulunabilir veya sorunları bildirebilirsiniz"; +"Scene.Settings.Keyboard.CloseSettingsWindow" = "Ayarlar Penceresini Kapat"; +"Scene.Settings.Section.Appearance.Automatic" = "Otomatik"; +"Scene.Settings.Section.Appearance.Dark" = "Daima Koyu"; +"Scene.Settings.Section.Appearance.Light" = "Daima Açık"; +"Scene.Settings.Section.Appearance.Title" = "Görünüm"; +"Scene.Settings.Section.BoringZone.AccountSettings" = "Hesap Ayarları"; +"Scene.Settings.Section.BoringZone.Privacy" = "Gizlilik Politikası"; +"Scene.Settings.Section.BoringZone.Terms" = "Hizmet Şartları"; +"Scene.Settings.Section.BoringZone.Title" = "Sıkıcı Bölge"; +"Scene.Settings.Section.LookAndFeel.Light" = "Açık"; +"Scene.Settings.Section.LookAndFeel.ReallyDark" = "Gerçek Koyu"; +"Scene.Settings.Section.LookAndFeel.SortaDark" = "Hafif Koyu"; +"Scene.Settings.Section.LookAndFeel.Title" = "Look and Feel"; +"Scene.Settings.Section.LookAndFeel.UseSystem" = "Sistem İle Aynı"; +"Scene.Settings.Section.Notifications.Boosts" = "Gönderimi yeniden paylaştığında"; +"Scene.Settings.Section.Notifications.Favorites" = "Gönderimi favorilerine eklediğinde"; +"Scene.Settings.Section.Notifications.Follows" = "Beni takip ettiğinde"; +"Scene.Settings.Section.Notifications.Mentions" = "Benden bahsettiğinde"; +"Scene.Settings.Section.Notifications.Title" = "Bildirimler"; +"Scene.Settings.Section.Notifications.Trigger.Anyone" = "herhangi biri"; +"Scene.Settings.Section.Notifications.Trigger.Follow" = "takip ettiğim biri"; +"Scene.Settings.Section.Notifications.Trigger.Follower" = "bir takipçim"; +"Scene.Settings.Section.Notifications.Trigger.Noone" = "bilgilendirme"; +"Scene.Settings.Section.Notifications.Trigger.Title" = "Beni şu durumda bilgilendir: "; +"Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Hareketli avatarları devre dışı bırak"; +"Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Hareketli emojileri devre dışı bırak"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Bağlantıları Mastodon içinden aç"; +"Scene.Settings.Section.Preference.Title" = "Tercihler"; +"Scene.Settings.Section.Preference.TrueBlackDarkMode" = "Tam siyah koyu modu"; +"Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Bağlantıları varsayılan tarayıcıda aç"; +"Scene.Settings.Section.SpicyZone.Clear" = "Medya Önbelleğini Temizle"; +"Scene.Settings.Section.SpicyZone.Signout" = "Oturumu Kapat"; +"Scene.Settings.Section.SpicyZone.Title" = "Tehlikeli bölge"; +"Scene.Settings.Title" = "Ayarlar"; +"Scene.SuggestionAccount.FollowExplain" = "Birisini takip ettiğinizde, ana sayfanızda o kişinin gönderilerini görürsünüz."; +"Scene.SuggestionAccount.Title" = "Takip Edecek İnsanlar Bul"; +"Scene.Thread.BackTitle" = "Gönderi"; +"Scene.Thread.Title" = "%@ kullanıcının gönderisi"; +"Scene.Welcome.GetStarted" = "Başlayın"; +"Scene.Welcome.LogIn" = "Oturum Aç"; +"Scene.Welcome.Slogan" = "Sosyal ağ, +tekrardan ellerinizde."; +"Scene.Wizard.AccessibilityHint" = "Bu yardımı kapatmak için çift tıklayın"; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Profil butonuna basılı tutarak birden fazla hesap arasında geçiş yapın."; +"Scene.Wizard.NewInMastodon" = "Mastodon'da Yeni"; \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/tr.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/tr.lproj/Localizable.stringsdict new file mode 100644 index 000000000..d6817c1f6 --- /dev/null +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/tr.lproj/Localizable.stringsdict @@ -0,0 +1,406 @@ + + + + + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + Okunmamış 1 bildirim + other + Okunmamış %ld bildirim + + + a11y.plural.count.input_limit_exceeds + + NSStringLocalizedFormatKey + %#@character_count@ karakter limiti aşıyor + character_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 karakter + other + %ld karakter + + + a11y.plural.count.input_limit_remains + + NSStringLocalizedFormatKey + %#@character_count@ karakter limiti var + character_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 karakter + other + %ld karakter + + + plural.count.metric_formatted.post + + NSStringLocalizedFormatKey + %@ %#@post_count@ + post_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + gönderi + other + gönderi + + + plural.count.post + + NSStringLocalizedFormatKey + %#@post_count@ + post_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 gönderi + other + %ld gönderi + + + plural.count.favorite + + NSStringLocalizedFormatKey + %#@favorite_count@ + favorite_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 favori + other + %ld favori + + + plural.count.reblog + + NSStringLocalizedFormatKey + %#@reblog_count@ + reblog_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 yeniden paylaşım + other + %ld yeniden paylaşım + + + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + %ld yanıt + other + %ld yanıt + + + plural.count.vote + + NSStringLocalizedFormatKey + %#@vote_count@ + vote_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 oy + other + %ld oy + + + plural.count.voter + + NSStringLocalizedFormatKey + %#@voter_count@ + voter_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 oy veren + other + %ld oy veren + + + plural.people_talking + + NSStringLocalizedFormatKey + %#@count_people_talking@ + count_people_talking + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 kişi konuşuyor + other + %ld kişi konuşuyor + + + plural.count.following + + NSStringLocalizedFormatKey + %#@count_following@ + count_following + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 takip edilen + other + %ld takip edilen + + + plural.count.follower + + NSStringLocalizedFormatKey + %#@count_follower@ + count_follower + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 takipçi + other + %ld takipçi + + + date.year.left + + NSStringLocalizedFormatKey + %#@count_year_left@ + count_year_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 yıl kaldı + other + %ld yıl kaldı + + + date.month.left + + NSStringLocalizedFormatKey + %#@count_month_left@ + count_month_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 ay kaldı + other + %ld ay kaldı + + + date.day.left + + NSStringLocalizedFormatKey + %#@count_day_left@ + count_day_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 gün kaldı + other + %ld gün kaldı + + + date.hour.left + + NSStringLocalizedFormatKey + %#@count_hour_left@ + count_hour_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 saat kaldı + other + %ld saat kaldı + + + date.minute.left + + NSStringLocalizedFormatKey + %#@count_minute_left@ + count_minute_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 dakika kaldı + other + %ld dakika kaldı + + + date.second.left + + NSStringLocalizedFormatKey + %#@count_second_left@ + count_second_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 saniye kaldı + other + %ld saniye kaldı + + + date.year.ago.abbr + + NSStringLocalizedFormatKey + %#@count_year_ago_abbr@ + count_year_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 yıl önce + other + %ld yıl önce + + + date.month.ago.abbr + + NSStringLocalizedFormatKey + %#@count_month_ago_abbr@ + count_month_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 ay önce + other + %ld ay önce + + + date.day.ago.abbr + + NSStringLocalizedFormatKey + %#@count_day_ago_abbr@ + count_day_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 gün önce + other + %ld gün önce + + + date.hour.ago.abbr + + NSStringLocalizedFormatKey + %#@count_hour_ago_abbr@ + count_hour_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 saat önce + other + %ld saat önce + + + date.minute.ago.abbr + + NSStringLocalizedFormatKey + %#@count_minute_ago_abbr@ + count_minute_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 dakika önce + other + %ld dakika önce + + + date.second.ago.abbr + + NSStringLocalizedFormatKey + %#@count_second_ago_abbr@ + count_second_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + one + 1 saniye önce + other + %ld saniye önce + + + + diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hant.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hant.lproj/Localizable.strings new file mode 100644 index 000000000..e76396f15 --- /dev/null +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hant.lproj/Localizable.strings @@ -0,0 +1,387 @@ +"Common.Alerts.BlockDomain.BlockEntireDomain" = "封鎖網域"; +"Common.Alerts.BlockDomain.Title" = "真的非常確定封鎖整個 %@ 網域嗎?大部分情況下,您只需要封鎖或靜音少數特定的帳帳戶能滿足需求了。您將不能看到來自此網域的內容。您來自該網域的跟隨者也將被移除。"; +"Common.Alerts.CleanCache.Message" = "成功清除 %@ 快取。"; +"Common.Alerts.CleanCache.Title" = "清除快取"; +"Common.Alerts.Common.PleaseTryAgain" = "請再試一次。"; +"Common.Alerts.Common.PleaseTryAgainLater" = "請稍候再試。"; +"Common.Alerts.DeletePost.Message" = "是否確定要刪除此嘟文?"; +"Common.Alerts.DeletePost.Title" = "刪除嘟文"; +"Common.Alerts.DiscardPostContent.Message" = "確認放棄編寫中的嘟文內容。"; +"Common.Alerts.DiscardPostContent.Title" = "捨棄草稿"; +"Common.Alerts.EditProfileFailure.Message" = "無法編輯個人檔案。請重試。"; +"Common.Alerts.EditProfileFailure.Title" = "編輯個人檔案錯誤"; +"Common.Alerts.PublishPostFailure.AttachmentsMessage.MoreThanOneVideo" = "無法附加一個以上影片。"; +"Common.Alerts.PublishPostFailure.AttachmentsMessage.VideoAttachWithPhoto" = "無法在已有圖片的嘟文上附加影片。"; +"Common.Alerts.PublishPostFailure.Message" = "發表嘟文失敗。 +請檢查您的網路連線。"; +"Common.Alerts.PublishPostFailure.Title" = "發表嘟文失敗"; +"Common.Alerts.SavePhotoFailure.Message" = "請開啟圖片庫存取權限以儲存照片。"; +"Common.Alerts.SavePhotoFailure.Title" = "儲存照片失敗"; +"Common.Alerts.ServerError.Title" = "伺服器錯誤"; +"Common.Alerts.SignOut.Confirm" = "登出"; +"Common.Alerts.SignOut.Message" = "您確定要登出嗎?"; +"Common.Alerts.SignOut.Title" = "登出"; +"Common.Alerts.SignUpFailure.Title" = "註冊失敗"; +"Common.Alerts.VoteFailure.PollEnded" = "投票已結束"; +"Common.Alerts.VoteFailure.Title" = "投票失敗"; +"Common.Controls.Actions.Add" = "新增"; +"Common.Controls.Actions.Back" = "上一頁"; +"Common.Controls.Actions.BlockDomain" = "封鎖 %@"; +"Common.Controls.Actions.Cancel" = "取消"; +"Common.Controls.Actions.Compose" = "撰寫"; +"Common.Controls.Actions.Confirm" = "確認"; +"Common.Controls.Actions.Continue" = "繼續"; +"Common.Controls.Actions.CopyPhoto" = "複製照片"; +"Common.Controls.Actions.Delete" = "刪除"; +"Common.Controls.Actions.Discard" = "捨棄"; +"Common.Controls.Actions.Done" = "完成"; +"Common.Controls.Actions.Edit" = "編輯"; +"Common.Controls.Actions.FindPeople" = "尋找一些人來跟隨"; +"Common.Controls.Actions.ManuallySearch" = "手動搜尋"; +"Common.Controls.Actions.Next" = "下一頁"; +"Common.Controls.Actions.Ok" = "OK"; +"Common.Controls.Actions.Open" = "開啟"; +"Common.Controls.Actions.OpenInBrowser" = "在瀏覽器中開啟"; +"Common.Controls.Actions.OpenInSafari" = "在 Safari 中開啟"; +"Common.Controls.Actions.Preview" = "預覽"; +"Common.Controls.Actions.Previous" = "上一步"; +"Common.Controls.Actions.Remove" = "刪除"; +"Common.Controls.Actions.Reply" = "回覆"; +"Common.Controls.Actions.ReportUser" = "檢舉 %@"; +"Common.Controls.Actions.Save" = "儲存"; +"Common.Controls.Actions.SavePhoto" = "儲存照片"; +"Common.Controls.Actions.SeeMore" = "檢視更多"; +"Common.Controls.Actions.Settings" = "設定"; +"Common.Controls.Actions.Share" = "分享"; +"Common.Controls.Actions.SharePost" = "分享嘟文"; +"Common.Controls.Actions.ShareUser" = "分享 %@"; +"Common.Controls.Actions.SignIn" = "登入"; +"Common.Controls.Actions.SignUp" = "註冊"; +"Common.Controls.Actions.Skip" = "跳過"; +"Common.Controls.Actions.TakePhoto" = "拍攝照片"; +"Common.Controls.Actions.TryAgain" = "再試一次"; +"Common.Controls.Actions.UnblockDomain" = "解除封鎖 %@"; +"Common.Controls.Friendship.Block" = "封鎖"; +"Common.Controls.Friendship.BlockDomain" = "封鎖 %@"; +"Common.Controls.Friendship.BlockUser" = "封鎖 %@"; +"Common.Controls.Friendship.Blocked" = "已封鎖"; +"Common.Controls.Friendship.EditInfo" = "編輯"; +"Common.Controls.Friendship.Follow" = "跟隨"; +"Common.Controls.Friendship.Following" = "跟隨中"; +"Common.Controls.Friendship.Mute" = "靜音"; +"Common.Controls.Friendship.MuteUser" = "靜音 %@"; +"Common.Controls.Friendship.Muted" = "已靜音"; +"Common.Controls.Friendship.Pending" = "等待中"; +"Common.Controls.Friendship.Request" = "請求"; +"Common.Controls.Friendship.Unblock" = "解除封鎖"; +"Common.Controls.Friendship.UnblockUser" = "解除封鎖 %@"; +"Common.Controls.Friendship.Unmute" = "取消靜音"; +"Common.Controls.Friendship.UnmuteUser" = "取消靜音 %@"; +"Common.Controls.Keyboard.Common.ComposeNewPost" = "撰寫新嘟文"; +"Common.Controls.Keyboard.Common.OpenSettings" = "開啟設定"; +"Common.Controls.Keyboard.Common.ShowFavorites" = "顯示最愛"; +"Common.Controls.Keyboard.Common.SwitchToTab" = "切換至 %@"; +"Common.Controls.Keyboard.SegmentedControl.NextSection" = "下一個區塊"; +"Common.Controls.Keyboard.SegmentedControl.PreviousSection" = "上一個區塊"; +"Common.Controls.Keyboard.Timeline.NextStatus" = "下一則嘟文"; +"Common.Controls.Keyboard.Timeline.OpenAuthorProfile" = "開啟作者的個人檔案頁面"; +"Common.Controls.Keyboard.Timeline.OpenRebloggerProfile" = "開啟轉嘟者的個人檔案頁面"; +"Common.Controls.Keyboard.Timeline.OpenStatus" = "開啟嘟文"; +"Common.Controls.Keyboard.Timeline.PreviewImage" = "預覽圖片"; +"Common.Controls.Keyboard.Timeline.PreviousStatus" = "先前的嘟文"; +"Common.Controls.Keyboard.Timeline.ReplyStatus" = "回覆嘟文"; +"Common.Controls.Keyboard.Timeline.ToggleContentWarning" = "切換內容警告"; +"Common.Controls.Keyboard.Timeline.ToggleFavorite" = "切換最愛嘟文"; +"Common.Controls.Keyboard.Timeline.ToggleReblog" = "切換轉發嘟文"; +"Common.Controls.Status.Actions.Favorite" = "最愛"; +"Common.Controls.Status.Actions.Hide" = "隱藏"; +"Common.Controls.Status.Actions.Menu" = "選單"; +"Common.Controls.Status.Actions.Reblog" = "轉嘟"; +"Common.Controls.Status.Actions.Reply" = "回覆"; +"Common.Controls.Status.Actions.ShowGif" = "顯示 GIF"; +"Common.Controls.Status.Actions.ShowImage" = "顯示圖片"; +"Common.Controls.Status.Actions.ShowVideoPlayer" = "顯示影片播放器"; +"Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "輕觸然後按住以顯示選單"; +"Common.Controls.Status.Actions.Unfavorite" = "取消最愛"; +"Common.Controls.Status.Actions.Unreblog" = "取消轉嘟"; +"Common.Controls.Status.ContentWarning" = "內容警告"; +"Common.Controls.Status.MediaContentWarning" = "輕觸任何地方以顯示"; +"Common.Controls.Status.Poll.Closed" = "已關閉"; +"Common.Controls.Status.Poll.Vote" = "投票"; +"Common.Controls.Status.SensitiveContent" = "敏感內容"; +"Common.Controls.Status.ShowPost" = "顯示嘟文"; +"Common.Controls.Status.ShowUserProfile" = "顯示使用者個人檔案頁面"; +"Common.Controls.Status.Tag.Email" = "電子郵件"; +"Common.Controls.Status.Tag.Emoji" = "emoji"; +"Common.Controls.Status.Tag.Hashtag" = "主題標籤"; +"Common.Controls.Status.Tag.Link" = "連結"; +"Common.Controls.Status.Tag.Mention" = "提及"; +"Common.Controls.Status.Tag.Url" = "網址"; +"Common.Controls.Status.TapToReveal" = "輕觸以顯示"; +"Common.Controls.Status.UserReblogged" = "%@ 已轉嘟"; +"Common.Controls.Status.UserRepliedTo" = "回覆給 %@"; +"Common.Controls.Status.Visibility.Direct" = "只有被提及的使用者能看到此嘟文。"; +"Common.Controls.Status.Visibility.Private" = "只有他們的跟隨者能看到此嘟文。"; +"Common.Controls.Status.Visibility.PrivateFromMe" = "只有我的跟隨者能看到此嘟文。"; +"Common.Controls.Status.Visibility.Unlisted" = "任何人都能看到此嘟文,但是不會顯示於公開時間軸上。"; +"Common.Controls.Tabs.Home" = "首頁"; +"Common.Controls.Tabs.Notification" = "通知"; +"Common.Controls.Tabs.Profile" = "個人檔案"; +"Common.Controls.Tabs.Search" = "搜尋"; +"Common.Controls.Timeline.Filtered" = "已過濾"; +"Common.Controls.Timeline.Header.BlockedWarning" = "您無法瀏覽該使用者的個人檔案,除非他們取消封鎖您。"; +"Common.Controls.Timeline.Header.BlockingWarning" = "您無法瀏覽該使用者的個人檔案,除非您取消封鎖。 +您的個人檔案看起來像是這樣。"; +"Common.Controls.Timeline.Header.NoStatusFound" = "沒有任何嘟文"; +"Common.Controls.Timeline.Header.SuspendedWarning" = "此使用者已被停權。"; +"Common.Controls.Timeline.Header.UserBlockedWarning" = "您無法瀏覽 %@ 的個人檔案,除非他們取消封鎖您。"; +"Common.Controls.Timeline.Header.UserBlockingWarning" = "您無法瀏覽 %@ 的個人檔案,除非您取消封鎖。 +您的個人檔案看起來像是這樣。"; +"Common.Controls.Timeline.Header.UserSuspendedWarning" = "%@ 的帳號已經被停權。"; +"Common.Controls.Timeline.Loader.LoadMissingPosts" = "讀取錯過的嘟文"; +"Common.Controls.Timeline.Loader.LoadingMissingPosts" = "正在讀取錯過的嘟文..."; +"Common.Controls.Timeline.Loader.ShowMoreReplies" = "顯示更多回覆"; +"Common.Controls.Timeline.Timestamp.Now" = "剛剛"; +"Scene.AccountList.AddAccount" = "新增帳號"; +"Scene.AccountList.DismissAccountSwitcher" = "關閉帳號切換器"; +"Scene.AccountList.TabBarHint" = "目前已選擇的個人檔案:%@。點兩下然後按住以顯示帳號切換器"; +"Scene.Compose.Accessibility.AppendAttachment" = "新增附件"; +"Scene.Compose.Accessibility.AppendPoll" = "新增投票"; +"Scene.Compose.Accessibility.CustomEmojiPicker" = "自訂 emoji 選擇器"; +"Scene.Compose.Accessibility.DisableContentWarning" = "停用內容警告"; +"Scene.Compose.Accessibility.EnableContentWarning" = "啟用內容警告"; +"Scene.Compose.Accessibility.PostVisibilityMenu" = "嘟文可見性選單"; +"Scene.Compose.Accessibility.RemovePoll" = "移除投票"; +"Scene.Compose.Attachment.AttachmentBroken" = "此 %@ 已損毀,並無法被上傳至 Mastodon。"; +"Scene.Compose.Attachment.DescriptionPhoto" = "為視障人士提供圖片說明..."; +"Scene.Compose.Attachment.DescriptionVideo" = "為視障人士提供影片說明..."; +"Scene.Compose.Attachment.Photo" = "照片"; +"Scene.Compose.Attachment.Video" = "影片"; +"Scene.Compose.AutoComplete.SpaceToAdd" = "添加的空白"; +"Scene.Compose.ComposeAction" = "嘟出去"; +"Scene.Compose.ContentInputPlaceholder" = "正在想些什麼嗎?"; +"Scene.Compose.ContentWarning.Placeholder" = "請於此處寫下精準的警告..."; +"Scene.Compose.Keyboard.AppendAttachmentEntry" = "新增附件 - %@"; +"Scene.Compose.Keyboard.DiscardPost" = "捨棄嘟文"; +"Scene.Compose.Keyboard.PublishPost" = "發表嘟文"; +"Scene.Compose.Keyboard.SelectVisibilityEntry" = "選擇可見性 - %@"; +"Scene.Compose.Keyboard.ToggleContentWarning" = "切換內容警告"; +"Scene.Compose.Keyboard.TogglePoll" = "切換投票"; +"Scene.Compose.MediaSelection.Browse" = "瀏覽"; +"Scene.Compose.MediaSelection.Camera" = "拍攝照片"; +"Scene.Compose.MediaSelection.PhotoLibrary" = "圖片庫"; +"Scene.Compose.Poll.DurationTime" = "持續時間:%@"; +"Scene.Compose.Poll.OneDay" = "一天"; +"Scene.Compose.Poll.OneHour" = "一小時"; +"Scene.Compose.Poll.OptionNumber" = "選項 %ld"; +"Scene.Compose.Poll.SevenDays" = "七天"; +"Scene.Compose.Poll.SixHours" = "六小時"; +"Scene.Compose.Poll.ThirtyMinutes" = "30 分鐘"; +"Scene.Compose.Poll.ThreeDays" = "三天"; +"Scene.Compose.ReplyingToUser" = "正在回覆 %@"; +"Scene.Compose.Title.NewPost" = "新增嘟文"; +"Scene.Compose.Title.NewReply" = "新增回覆"; +"Scene.Compose.Visibility.Direct" = "僅限於我提及的人"; +"Scene.Compose.Visibility.Private" = "僅限跟隨者"; +"Scene.Compose.Visibility.Public" = "公開"; +"Scene.Compose.Visibility.Unlisted" = "不公開"; +"Scene.ConfirmEmail.Button.OpenEmailApp" = "開啟電子郵件 App"; +"Scene.ConfirmEmail.Button.Resend" = "重新發送"; +"Scene.ConfirmEmail.DontReceiveEmail.Description" = "請檢查您的電子郵件地址是否正確,以及您的垃圾信件夾。"; +"Scene.ConfirmEmail.DontReceiveEmail.ResendEmail" = "重新發送電子郵件"; +"Scene.ConfirmEmail.DontReceiveEmail.Title" = "請檢查您的電子郵件"; +"Scene.ConfirmEmail.OpenEmailApp.Description" = "我們剛寄送您一封電子郵件。請檢查您的垃圾信件夾。"; +"Scene.ConfirmEmail.OpenEmailApp.Mail" = "電子郵件"; +"Scene.ConfirmEmail.OpenEmailApp.OpenEmailClient" = "請開啟電子郵件程式"; +"Scene.ConfirmEmail.OpenEmailApp.Title" = "請檢查您的收件夾。"; +"Scene.ConfirmEmail.Subtitle" = "點擊我們寄送給您的帳號驗證連結。"; +"Scene.ConfirmEmail.Title" = "最後一步。"; +"Scene.Discovery.Intro" = "這些嘟文正在您 Mastodon 的角落受到注目。"; +"Scene.Discovery.Tabs.Community" = "社群"; +"Scene.Discovery.Tabs.ForYou" = "為您推薦"; +"Scene.Discovery.Tabs.Hashtags" = "主題標籤"; +"Scene.Discovery.Tabs.News" = "最新消息"; +"Scene.Discovery.Tabs.Posts" = "嘟文"; +"Scene.Favorite.Title" = "您的最愛"; +"Scene.Follower.Footer" = "來自其他伺服器的跟隨者不會被顯示。"; +"Scene.Following.Footer" = "來自其他伺服器的跟隨中不會被顯示。"; +"Scene.HomeTimeline.NavigationBarState.NewPosts" = "檢視最新嘟文"; +"Scene.HomeTimeline.NavigationBarState.Offline" = "離線"; +"Scene.HomeTimeline.NavigationBarState.Published" = "嘟出去!"; +"Scene.HomeTimeline.NavigationBarState.Publishing" = "發表嘟文..."; +"Scene.HomeTimeline.Title" = "首頁"; +"Scene.Notification.Keyobard.ShowEverything" = "顯示全部"; +"Scene.Notification.Keyobard.ShowMentions" = "顯示提及"; +"Scene.Notification.NotificationDescription.FavoritedYourPost" = "最愛了您的嘟文"; +"Scene.Notification.NotificationDescription.FollowedYou" = "跟隨了您"; +"Scene.Notification.NotificationDescription.MentionedYou" = "提到了您"; +"Scene.Notification.NotificationDescription.PollHasEnded" = "投票已結束"; +"Scene.Notification.NotificationDescription.RebloggedYourPost" = "轉嘟了您的嘟文"; +"Scene.Notification.NotificationDescription.RequestToFollowYou" = "要求跟隨您"; +"Scene.Notification.Title.Everything" = "全部"; +"Scene.Notification.Title.Mentions" = "提及"; +"Scene.Preview.Keyboard.ClosePreview" = "關閉預覽"; +"Scene.Preview.Keyboard.ShowNext" = "顯示下一筆"; +"Scene.Preview.Keyboard.ShowPrevious" = "顯示上一筆"; +"Scene.Profile.Accessibility.DoubleTapToOpenTheList" = "點兩下以開啟列表"; +"Scene.Profile.Accessibility.EditAvatarImage" = "編輯大頭貼"; +"Scene.Profile.Accessibility.ShowAvatarImage" = "顯示大頭貼"; +"Scene.Profile.Accessibility.ShowBannerImage" = "顯示橫幅圖片"; +"Scene.Profile.Dashboard.Followers" = "跟隨者"; +"Scene.Profile.Dashboard.Following" = "跟隨中"; +"Scene.Profile.Dashboard.Posts" = "嘟文"; +"Scene.Profile.Fields.AddRow" = "新增列"; +"Scene.Profile.Fields.Placeholder.Content" = "內容"; +"Scene.Profile.Fields.Placeholder.Label" = "標籤"; +"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Message" = "確認將 %@ 封鎖"; +"Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.Title" = "封鎖"; +"Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Message" = "確認將 %@ 靜音"; +"Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.Title" = "靜音"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Message" = "確認將 %@ 取消封鎖"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.Title" = "取消封鎖"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Message" = "確認將 %@ 取消靜音"; +"Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.Title" = "取消靜音"; +"Scene.Profile.SegmentedControl.About" = "關於"; +"Scene.Profile.SegmentedControl.Media" = "媒體"; +"Scene.Profile.SegmentedControl.Posts" = "嘟文"; +"Scene.Profile.SegmentedControl.PostsAndReplies" = "嘟文及回覆"; +"Scene.Profile.SegmentedControl.Replies" = "回覆"; +"Scene.Register.Error.Item.Agreement" = "條款"; +"Scene.Register.Error.Item.Email" = "電子郵件"; +"Scene.Register.Error.Item.Locale" = "地區"; +"Scene.Register.Error.Item.Password" = "密碼"; +"Scene.Register.Error.Item.Reason" = "原因"; +"Scene.Register.Error.Item.Username" = "使用者名稱"; +"Scene.Register.Error.Reason.Accepted" = "請先閱讀並同意 %@"; +"Scene.Register.Error.Reason.Blank" = "%@ 為必填選項"; +"Scene.Register.Error.Reason.Blocked" = "%@ 包含不被允許的電子郵件供應商"; +"Scene.Register.Error.Reason.Inclusion" = "%@ 是不被支援的值"; +"Scene.Register.Error.Reason.Invalid" = "%@ 是無效的"; +"Scene.Register.Error.Reason.Reserved" = "%@ 是一個保留的關鍵字"; +"Scene.Register.Error.Reason.Taken" = "%@ 已被使用"; +"Scene.Register.Error.Reason.TooLong" = "%@ 太長了"; +"Scene.Register.Error.Reason.TooShort" = "%@ 太短了"; +"Scene.Register.Error.Reason.Unreachable" = "%@ 似乎並不存在"; +"Scene.Register.Error.Special.EmailInvalid" = "這不是一個有效的電子郵件地址"; +"Scene.Register.Error.Special.PasswordTooShort" = "密碼太短了(至少需要八個字元)"; +"Scene.Register.Error.Special.UsernameInvalid" = "使用者名稱僅能包含英文字母數字以及底線"; +"Scene.Register.Error.Special.UsernameTooLong" = "使用者名稱太長了(不能超過 30 個字元)"; +"Scene.Register.Input.Avatar.Delete" = "刪除"; +"Scene.Register.Input.DisplayName.Placeholder" = "顯示名稱"; +"Scene.Register.Input.Email.Placeholder" = "電子郵件"; +"Scene.Register.Input.Invite.RegistrationUserInviteRequest" = "為什麼想要加入呢?"; +"Scene.Register.Input.Password.Accessibility.Checked" = "已選擇"; +"Scene.Register.Input.Password.Accessibility.Unchecked" = "取消勾選"; +"Scene.Register.Input.Password.CharacterLimit" = "8 個字元"; +"Scene.Register.Input.Password.Hint" = "您的密碼必須至少為八個字元"; +"Scene.Register.Input.Password.Placeholder" = "密碼"; +"Scene.Register.Input.Password.Require" = "您的密碼必須是至少:"; +"Scene.Register.Input.Username.DuplicatePrompt" = "此使用者名稱已被佔用。"; +"Scene.Register.Input.Username.Placeholder" = "使用者名稱"; +"Scene.Register.Title" = "讓我們一起設定 %@ 吧!"; +"Scene.Report.Content1" = "還有其他您想加入這份檢舉報告的嘟文嗎?"; +"Scene.Report.Content2" = "有其他管管們需要知道關於這份檢舉報告的嗎?"; +"Scene.Report.ReportSentTitle" = "感謝您的檢舉,我們將著手處理。"; +"Scene.Report.Reported" = "已檢舉"; +"Scene.Report.Send" = "傳送檢舉報告"; +"Scene.Report.SkipToSend" = "不加入備註並傳送"; +"Scene.Report.Step1" = "兩個步驟中的第一步"; +"Scene.Report.Step2" = "兩個步驟中的第二步"; +"Scene.Report.TextPlaceholder" = "請輸入或貼上額外的備註"; +"Scene.Report.Title" = "檢舉 %@"; +"Scene.Report.TitleReport" = "檢舉"; +"Scene.Search.Recommend.Accounts.Description" = "您也許想跟隨這些帳號"; +"Scene.Search.Recommend.Accounts.Follow" = "跟隨"; +"Scene.Search.Recommend.Accounts.Title" = "您可能會喜歡的帳號"; +"Scene.Search.Recommend.ButtonText" = "檢視全部"; +"Scene.Search.Recommend.HashTag.Description" = "發燒中的主題標籤"; +"Scene.Search.Recommend.HashTag.PeopleTalking" = "%@ 人正在討論"; +"Scene.Search.Recommend.HashTag.Title" = "Mastodon 上的熱門討論"; +"Scene.Search.SearchBar.Cancel" = "取消"; +"Scene.Search.SearchBar.Placeholder" = "搜尋主題標籤及使用者"; +"Scene.Search.Searching.Clear" = "清除"; +"Scene.Search.Searching.EmptyState.NoResults" = "沒有任何結果"; +"Scene.Search.Searching.RecentSearch" = "最近的搜尋"; +"Scene.Search.Searching.Segment.All" = "全部"; +"Scene.Search.Searching.Segment.Hashtags" = "主題標籤"; +"Scene.Search.Searching.Segment.People" = "使用者"; +"Scene.Search.Searching.Segment.Posts" = "嘟文"; +"Scene.Search.Title" = "搜尋"; +"Scene.ServerPicker.Button.Category.Academia" = "學術"; +"Scene.ServerPicker.Button.Category.Activism" = "社會運動"; +"Scene.ServerPicker.Button.Category.All" = "全部"; +"Scene.ServerPicker.Button.Category.AllAccessiblityDescription" = "分類:全部"; +"Scene.ServerPicker.Button.Category.Art" = "藝術"; +"Scene.ServerPicker.Button.Category.Food" = "食物"; +"Scene.ServerPicker.Button.Category.Furry" = "毛茸茸"; +"Scene.ServerPicker.Button.Category.Games" = "遊戲"; +"Scene.ServerPicker.Button.Category.General" = "一般"; +"Scene.ServerPicker.Button.Category.Journalism" = "新聞記者"; +"Scene.ServerPicker.Button.Category.Lgbt" = "LGBT"; +"Scene.ServerPicker.Button.Category.Music" = "音樂"; +"Scene.ServerPicker.Button.Category.Regional" = "區域性"; +"Scene.ServerPicker.Button.Category.Tech" = "科技"; +"Scene.ServerPicker.Button.SeeLess" = "顯示較少"; +"Scene.ServerPicker.Button.SeeMore" = "檢視更多"; +"Scene.ServerPicker.EmptyState.BadNetwork" = "讀取資料時發生錯誤。請檢查您的網路連線。"; +"Scene.ServerPicker.EmptyState.FindingServers" = "尋找可用的伺服器..."; +"Scene.ServerPicker.EmptyState.NoResults" = "沒有結果"; +"Scene.ServerPicker.Input.Placeholder" = "搜尋伺服器"; +"Scene.ServerPicker.Label.Category" = "分類"; +"Scene.ServerPicker.Label.Language" = "語言"; +"Scene.ServerPicker.Label.Users" = "使用者"; +"Scene.ServerPicker.Subtitle" = "基於您的興趣、地區、或一般用途選定一個伺服器。"; +"Scene.ServerPicker.SubtitleExtend" = "基於您的興趣、地區、或一般用途選定一個伺服器。每個伺服器是由完全獨立的組織或個人營運。"; +"Scene.ServerPicker.Title" = "Mastodon 由不同伺服器的使用者組成。"; +"Scene.ServerRules.Button.Confirm" = "我已閱讀並同意"; +"Scene.ServerRules.PrivacyPolicy" = "隱私權政策"; +"Scene.ServerRules.Prompt" = "繼續的話,代表您將遵守 %@ 的服務條款和隱私權政策。"; +"Scene.ServerRules.Subtitle" = "這些被 %@ 的管管們制定以及實施。"; +"Scene.ServerRules.TermsOfService" = "服務條款"; +"Scene.ServerRules.Title" = "一些基本守則。"; +"Scene.Settings.Footer.MastodonDescription" = "Mastodon 是開源軟體。您可以在 GitHub %@ (%@) 上回報問題。"; +"Scene.Settings.Keyboard.CloseSettingsWindow" = "關閉設定視窗"; +"Scene.Settings.Section.Appearance.Automatic" = "自動"; +"Scene.Settings.Section.Appearance.Dark" = "深色佈景主題"; +"Scene.Settings.Section.Appearance.Light" = "亮色佈景主題"; +"Scene.Settings.Section.Appearance.Title" = "外觀設定"; +"Scene.Settings.Section.BoringZone.AccountSettings" = "帳號設定"; +"Scene.Settings.Section.BoringZone.Privacy" = "隱私權政策"; +"Scene.Settings.Section.BoringZone.Terms" = "服務條款"; +"Scene.Settings.Section.BoringZone.Title" = "無聊的這些"; +"Scene.Settings.Section.LookAndFeel.Light" = "淺色"; +"Scene.Settings.Section.LookAndFeel.ReallyDark" = "闇黑風格"; +"Scene.Settings.Section.LookAndFeel.SortaDark" = "有點黑又不會太黑"; +"Scene.Settings.Section.LookAndFeel.Title" = "外觀與風格"; +"Scene.Settings.Section.LookAndFeel.UseSystem" = "與系統一致"; +"Scene.Settings.Section.Notifications.Boosts" = "將我的嘟文轉嘟"; +"Scene.Settings.Section.Notifications.Favorites" = "將我的嘟文加到最愛"; +"Scene.Settings.Section.Notifications.Follows" = "跟隨著我"; +"Scene.Settings.Section.Notifications.Mentions" = "提到了我"; +"Scene.Settings.Section.Notifications.Title" = "通知"; +"Scene.Settings.Section.Notifications.Trigger.Anyone" = "任何人"; +"Scene.Settings.Section.Notifications.Trigger.Follow" = "任何我跟隨的人"; +"Scene.Settings.Section.Notifications.Trigger.Follower" = "跟隨者"; +"Scene.Settings.Section.Notifications.Trigger.Noone" = "沒有人"; +"Scene.Settings.Section.Notifications.Trigger.Title" = "以下狀況請通知我"; +"Scene.Settings.Section.Preference.DisableAvatarAnimation" = "停用動畫大頭貼"; +"Scene.Settings.Section.Preference.DisableEmojiAnimation" = "停用動畫 emoji"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "在 Mastodon 中開啟連結"; +"Scene.Settings.Section.Preference.Title" = "偏好設定"; +"Scene.Settings.Section.Preference.TrueBlackDarkMode" = "真☆闇黑模式"; +"Scene.Settings.Section.Preference.UsingDefaultBrowser" = "使用預設瀏覽器開啟連結"; +"Scene.Settings.Section.SpicyZone.Clear" = "清除媒體快取"; +"Scene.Settings.Section.SpicyZone.Signout" = "登出"; +"Scene.Settings.Section.SpicyZone.Title" = "危險地帶"; +"Scene.Settings.Title" = "設定"; +"Scene.SuggestionAccount.FollowExplain" = "當您跟隨這些人時,將會看到他們的嘟文出現在您的首頁時間軸上。"; +"Scene.SuggestionAccount.Title" = "尋找一些人來跟隨"; +"Scene.Thread.BackTitle" = "嘟文"; +"Scene.Thread.Title" = "來自 %@ 的嘟文"; +"Scene.Welcome.GetStarted" = "新手上路"; +"Scene.Welcome.LogIn" = "登入"; +"Scene.Welcome.Slogan" = "社群網路 +還權於您。"; +"Scene.Wizard.AccessibilityHint" = "點兩下以關閉此設定精靈"; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "按住個人檔案按鈕以於多個帳號間切換。"; +"Scene.Wizard.NewInMastodon" = "Mastodon 新功能"; \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hant.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hant.lproj/Localizable.stringsdict new file mode 100644 index 000000000..0f28a8f6e --- /dev/null +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hant.lproj/Localizable.stringsdict @@ -0,0 +1,356 @@ + + + + + a11y.plural.count.unread.notification + + NSStringLocalizedFormatKey + %#@notification_count_unread_notification@ + notification_count_unread_notification + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld 則未讀通知 + + + a11y.plural.count.input_limit_exceeds + + NSStringLocalizedFormatKey + 輸入字數限制超過 %#@character_count@ 字 + character_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld 個字元 + + + a11y.plural.count.input_limit_remains + + NSStringLocalizedFormatKey + 輸入字數限制剩餘 %#@character_count@ 字 + character_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld 個字 + + + plural.count.metric_formatted.post + + NSStringLocalizedFormatKey + %@ %#@post_count@ + post_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + 嘟文 + + + plural.count.post + + NSStringLocalizedFormatKey + %#@post_count@ + post_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld 則嘟文 + + + plural.count.favorite + + NSStringLocalizedFormatKey + %#@favorite_count@ + favorite_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld 個最愛 + + + plural.count.reblog + + NSStringLocalizedFormatKey + %#@reblog_count@ + reblog_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld 個轉嘟 + + + plural.count.reply + + NSStringLocalizedFormatKey + %#@reply_count@ + reply_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld 個回覆 + + + plural.count.vote + + NSStringLocalizedFormatKey + %#@vote_count@ + vote_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld 票 + + + plural.count.voter + + NSStringLocalizedFormatKey + %#@voter_count@ + voter_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld 位投票者 + + + plural.people_talking + + NSStringLocalizedFormatKey + %#@count_people_talking@ + count_people_talking + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld 個人正在討論 + + + plural.count.following + + NSStringLocalizedFormatKey + %#@count_following@ + count_following + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld 個跟隨中 + + + plural.count.follower + + NSStringLocalizedFormatKey + %#@count_follower@ + count_follower + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld 個跟隨者 + + + date.year.left + + NSStringLocalizedFormatKey + %#@count_year_left@ + count_year_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + 還有 %ld 年 + + + date.month.left + + NSStringLocalizedFormatKey + %#@count_month_left@ + count_month_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + 還有 %ld 個月 + + + date.day.left + + NSStringLocalizedFormatKey + %#@count_day_left@ + count_day_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + 還有 %ld 天 + + + date.hour.left + + NSStringLocalizedFormatKey + %#@count_hour_left@ + count_hour_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + 還有 %ld 小時 + + + date.minute.left + + NSStringLocalizedFormatKey + %#@count_minute_left@ + count_minute_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + 還有 %ld 分鐘 + + + date.second.left + + NSStringLocalizedFormatKey + %#@count_second_left@ + count_second_left + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + 還有 %ld 秒 + + + date.year.ago.abbr + + NSStringLocalizedFormatKey + %#@count_year_ago_abbr@ + count_year_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld 年前 + + + date.month.ago.abbr + + NSStringLocalizedFormatKey + %#@count_month_ago_abbr@ + count_month_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld 個月前 + + + date.day.ago.abbr + + NSStringLocalizedFormatKey + %#@count_day_ago_abbr@ + count_day_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld 天前 + + + date.hour.ago.abbr + + NSStringLocalizedFormatKey + %#@count_hour_ago_abbr@ + count_hour_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld 小時前 + + + date.minute.ago.abbr + + NSStringLocalizedFormatKey + %#@count_minute_ago_abbr@ + count_minute_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld 分鐘前 + + + date.second.ago.abbr + + NSStringLocalizedFormatKey + %#@count_second_ago_abbr@ + count_second_ago_abbr + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + other + %ld 秒前 + + + + From d90b61e732f197c18336a05a8fbbeebd71dd9ad7 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 29 Apr 2022 15:45:32 +0800 Subject: [PATCH 050/101] fix: tab bar avatar button not update issue. resolve #383 --- .../Root/MainTab/MainTabBarController.swift | 33 +++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift index 1b08722d5..7ea748a60 100644 --- a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift +++ b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift @@ -106,6 +106,10 @@ class MainTabBarController: UITabBarController { var _viewControllers: [UIViewController] = [] private(set) var isReadyForWizardAvatarButton = false + + // output + var avatarURLObserver: AnyCancellable? + @Published var avatarURL: URL? init(context: AppContext, coordinator: SceneCoordinator) { self.context = context @@ -226,17 +230,34 @@ extension MainTabBarController { .store(in: &disposeBag) layoutAvatarButton() + + $avatarURL + .receive(on: DispatchQueue.main) + .sink { [weak self] avatarURL in + guard let self = self else { return } + self.avatarButton.avatarImageView.setImage( + url: avatarURL, + placeholder: .placeholder(color: .systemFill), + scaleToSize: MainTabBarController.avatarButtonSize + ) + } + .store(in: &disposeBag) context.authenticationService.activeMastodonAuthentication .receive(on: DispatchQueue.main) .sink { [weak self] activeMastodonAuthentication in guard let self = self else { return } - let avatarImageURL = activeMastodonAuthentication?.user.avatarImageURL() - self.avatarButton.avatarImageView.setImage( - url: avatarImageURL, - placeholder: .placeholder(color: .systemFill), - scaleToSize: MainTabBarController.avatarButtonSize - ) + if let user = activeMastodonAuthentication?.user { + self.avatarURLObserver = user.publisher(for: \.avatar) + .sink { [weak self, weak user] _ in + guard let self = self else { return } + guard let user = user else { return } + guard user.managedObjectContext != nil else { return } + self.avatarURL = user.avatarImageURL() + } + } else { + self.avatarURLObserver = nil + } // a11y let _profileTabItem = self.tabBar.items?.first { item in item.tag == Tab.me.tag } From a96f0e51853f474a31cdee8d7126971290a21d79 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 29 Apr 2022 15:55:31 +0800 Subject: [PATCH 051/101] fix: a11y label missing for home timeline navigation bar title button issue --- Localization/app.json | 7 +++++-- .../View/HomeTimelineNavigationBarTitleView.swift | 6 ++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Localization/app.json b/Localization/app.json index 50512250d..63ccdff65 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -342,8 +342,11 @@ "offline": "Offline", "new_posts": "See new posts", "published": "Published!", - "Publishing": "Publishing post..." - } + "Publishing": "Publishing post...", + "accessibility": { + "logo_description": "Tap to scroll to top and tap again to previous location" + } + }, }, "suggestion_account": { "title": "Find People to Follow", diff --git a/Mastodon/Scene/HomeTimeline/View/HomeTimelineNavigationBarTitleView.swift b/Mastodon/Scene/HomeTimeline/View/HomeTimelineNavigationBarTitleView.swift index e67ee0106..016884f72 100644 --- a/Mastodon/Scene/HomeTimeline/View/HomeTimelineNavigationBarTitleView.swift +++ b/Mastodon/Scene/HomeTimeline/View/HomeTimelineNavigationBarTitleView.swift @@ -108,6 +108,8 @@ extension HomeTimelineNavigationBarTitleView { logoButton.setImage(Asset.Asset.mastodonTextLogo.image.withRenderingMode(.alwaysTemplate), for: .normal) logoButton.contentMode = .center logoButton.isHidden = false + logoButton.accessibilityLabel = "Logo Button" // TODO :i18n + logoButton.accessibilityHint = "Tap to scroll to top and tap again to previous location" case .newPostButton: configureButton( title: L10n.Scene.HomeTimeline.NavigationBarState.newPosts, @@ -115,6 +117,7 @@ extension HomeTimelineNavigationBarTitleView { backgroundColor: Asset.Colors.brandBlue.color ) button.isHidden = false + button.accessibilityLabel = L10n.Scene.HomeTimeline.NavigationBarState.newPosts case .offlineButton: configureButton( title: L10n.Scene.HomeTimeline.NavigationBarState.offline, @@ -122,12 +125,14 @@ extension HomeTimelineNavigationBarTitleView { backgroundColor: Asset.Colors.danger.color ) button.isHidden = false + button.accessibilityLabel = L10n.Scene.HomeTimeline.NavigationBarState.offline case .publishingPostLabel: label.font = .systemFont(ofSize: 17, weight: .semibold) label.textColor = Asset.Colors.Label.primary.color label.text = L10n.Scene.HomeTimeline.NavigationBarState.publishing label.textAlignment = .center label.isHidden = false + button.accessibilityLabel = L10n.Scene.HomeTimeline.NavigationBarState.publishing case .publishedButton: blockingState = state configureButton( @@ -136,6 +141,7 @@ extension HomeTimelineNavigationBarTitleView { backgroundColor: Asset.Colors.successGreen.color ) button.isHidden = false + button.accessibilityLabel = L10n.Scene.HomeTimeline.NavigationBarState.published let presentDuration: TimeInterval = 0.33 let scaleAnimator = UIViewPropertyAnimator(duration: presentDuration, timingParameters: UISpringTimingParameters()) From d49fa0cced3ffe45636df330e043d07908a2ceb6 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 29 Apr 2022 15:56:06 +0800 Subject: [PATCH 052/101] chore: update version to 1.4.0 (118) --- AppShared/Info.plist | 4 +-- Mastodon.xcodeproj/project.pbxproj | 36 +++++++++---------- .../xcschemes/xcschememanagement.plist | 6 ++-- Mastodon/Info.plist | 4 +-- MastodonIntent/Info.plist | 4 +-- MastodonTests/Info.plist | 4 +-- MastodonUITests/Info.plist | 4 +-- NotificationService/Info.plist | 4 +-- ShareActionExtension/Info.plist | 4 +-- 9 files changed, 35 insertions(+), 35 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index da1201b7f..7465ea609 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.3 + 1.4.0 CFBundleVersion - 117 + 118 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 2255c3d46..f9efc0b56 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4711,7 +4711,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 117; + CURRENT_PROJECT_VERSION = 118; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4741,7 +4741,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 117; + CURRENT_PROJECT_VERSION = 118; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4849,11 +4849,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 117; + CURRENT_PROJECT_VERSION = 118; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 117; + DYLIB_CURRENT_VERSION = 118; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4880,11 +4880,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 117; + CURRENT_PROJECT_VERSION = 118; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 117; + DYLIB_CURRENT_VERSION = 118; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4908,7 +4908,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 117; + CURRENT_PROJECT_VERSION = 118; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4932,7 +4932,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 117; + CURRENT_PROJECT_VERSION = 118; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4956,7 +4956,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 117; + CURRENT_PROJECT_VERSION = 118; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4980,7 +4980,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 117; + CURRENT_PROJECT_VERSION = 118; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5067,7 +5067,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 117; + CURRENT_PROJECT_VERSION = 118; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5134,11 +5134,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 117; + CURRENT_PROJECT_VERSION = 118; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 117; + DYLIB_CURRENT_VERSION = 118; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5162,7 +5162,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 117; + CURRENT_PROJECT_VERSION = 118; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5185,7 +5185,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 117; + CURRENT_PROJECT_VERSION = 118; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5209,7 +5209,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 117; + CURRENT_PROJECT_VERSION = 118; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5233,7 +5233,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 117; + CURRENT_PROJECT_VERSION = 118; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5256,7 +5256,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 117; + CURRENT_PROJECT_VERSION = 118; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 528a75b66..59c178422 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 21 + 29 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 20 + 31 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 19 + 30 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 22e36efbb..2e5024bbb 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -30,7 +30,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.3 + 1.4.0 CFBundleURLTypes @@ -43,7 +43,7 @@ CFBundleVersion - 117 + 118 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index c43b12529..c902ad648 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.3 + 1.4.0 CFBundleVersion - 117 + 118 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index da1201b7f..7465ea609 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.3 + 1.4.0 CFBundleVersion - 117 + 118 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index da1201b7f..7465ea609 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.3 + 1.4.0 CFBundleVersion - 117 + 118 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index d3b7fdfe5..bfb91294d 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.3 + 1.4.0 CFBundleVersion - 117 + 118 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 565cd561b..01167b24f 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.3.3 + 1.4.0 CFBundleVersion - 117 + 118 NSExtension NSExtensionAttributes From ad5b6575c7d17f1a0f2bd1c608c9fb32e2296c0b Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 29 Apr 2022 16:00:02 +0800 Subject: [PATCH 053/101] chore: add a11y words for navigation bar button --- Localization/app.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Localization/app.json b/Localization/app.json index 63ccdff65..90b9b0fd8 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -344,7 +344,8 @@ "published": "Published!", "Publishing": "Publishing post...", "accessibility": { - "logo_description": "Tap to scroll to top and tap again to previous location" + "logo_label": "Logo Button", + "logo_hint": "Tap to scroll to top and tap again to previous location" } }, }, From b6c944da26e4ebe7da7ceaec20486273b43d53b4 Mon Sep 17 00:00:00 2001 From: Marcus Kida Date: Fri, 29 Apr 2022 10:49:24 +0200 Subject: [PATCH 054/101] chore: install bundler without sudo --- .github/scripts/setup.sh | 2 +- Documentation/Setup.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/scripts/setup.sh b/.github/scripts/setup.sh index f5934be0c..9b52d5b9e 100755 --- a/.github/scripts/setup.sh +++ b/.github/scripts/setup.sh @@ -1,7 +1,7 @@ #!/bin/bash # Install Ruby Bundler -sudo gem install bundler:2.3.11 +gem install bundler:2.3.11 # Install Ruby Gems bundle install diff --git a/Documentation/Setup.md b/Documentation/Setup.md index b17a9db8e..1c2f0a6c5 100644 --- a/Documentation/Setup.md +++ b/Documentation/Setup.md @@ -17,7 +17,7 @@ The app use [CocoaPods]() and [CocoaPods-Keys](https://github.com/orta/cocoapods #### Intel Mac ```zsh -sudo gem install bundler +gem install bundler bundle install ``` @@ -41,7 +41,7 @@ rbenv global 3.0.3 ruby --version # > ruby 3.0.3p157 (2021-11-24 revision 3fb7d2cadc) [arm64-darwin21] -sudo gem install bundler +gem install bundler bundle install ``` From 2a8305a6a0848d023c7e056212350f0fa39b8511 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 29 Apr 2022 18:45:08 +0800 Subject: [PATCH 055/101] fix: workaround post render crash issue #404 --- Mastodon.xcodeproj/project.pbxproj | 2 +- .../xcschemes/xcschememanagement.plist | 8 ++++---- .../xcshareddata/swiftpm/Package.resolved | 8 ++++---- MastodonSDK/Package.swift | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index f9efc0b56..4646dab87 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -5397,7 +5397,7 @@ repositoryURL = "https://github.com/TwidereProject/MetaTextKit.git"; requirement = { kind = exactVersion; - version = 2.2.2; + version = 2.2.3; }; }; DB0E2D2C26833FF600865C3C /* XCRemoteSwiftPackageReference "Nuke-FLAnimatedImage-Plugin" */ = { diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 59c178422..f31d71c9d 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -19,7 +19,7 @@ Mastodon - RTL.xcscheme_^#shared#^_ orderHint - 6 + 7 Mastodon - Release.xcscheme_^#shared#^_ @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 29 + 24 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 31 + 23 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 30 + 22 SuppressBuildableAutocreation diff --git a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved index 53f6a3a4c..cca51e911 100644 --- a/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Mastodon.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -105,8 +105,8 @@ "repositoryURL": "https://github.com/TwidereProject/MetaTextKit.git", "state": { "branch": null, - "revision": "8074400b3819ef0395550082e6e8e960ef22e1f3", - "version": "2.2.2" + "revision": "2b9556a78b2986b8c0b04adc6da8ec206b448a0c", + "version": "2.2.3" } }, { @@ -114,8 +114,8 @@ "repositoryURL": "https://github.com/kean/Nuke.git", "state": { "branch": null, - "revision": "78fa963b8491fc520791d8c2a509f1b8593d8aae", - "version": "10.7.1" + "revision": "0ea7545b5c918285aacc044dc75048625c8257cc", + "version": "10.8.0" } }, { diff --git a/MastodonSDK/Package.swift b/MastodonSDK/Package.swift index 3b109cfa9..c963be72d 100644 --- a/MastodonSDK/Package.swift +++ b/MastodonSDK/Package.swift @@ -27,7 +27,7 @@ let package = Package( .package(url: "https://github.com/apple/swift-nio.git", from: "1.0.0"), .package(url: "https://github.com/kean/Nuke.git", from: "10.3.1"), .package(url: "https://github.com/Flipboard/FLAnimatedImage.git", from: "1.0.0"), - .package(url: "https://github.com/TwidereProject/MetaTextKit.git", .exact("2.2.2")), + .package(url: "https://github.com/TwidereProject/MetaTextKit.git", .exact("2.2.3")), .package(url: "https://github.com/Alamofire/Alamofire.git", from: "5.4.0"), .package(url: "https://github.com/Alamofire/AlamofireImage.git", from: "4.1.0"), .package(name: "NukeFLAnimatedImagePlugin", url: "https://github.com/kean/Nuke-FLAnimatedImage-Plugin.git", from: "8.0.0"), From 589c3e83076c363796ba970cf5f1688e7c96296a Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 29 Apr 2022 18:46:24 +0800 Subject: [PATCH 056/101] chore: update i18n resources --- Mastodon/Scene/Discovery/DiscoveryViewModel.swift | 2 +- .../MastodonLocalization/Resources/it.lproj/Localizable.strings | 2 +- .../MastodonLocalization/Resources/ru.lproj/Localizable.strings | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Mastodon/Scene/Discovery/DiscoveryViewModel.swift b/Mastodon/Scene/Discovery/DiscoveryViewModel.swift index ca4773fe1..dfeb16e2b 100644 --- a/Mastodon/Scene/Discovery/DiscoveryViewModel.swift +++ b/Mastodon/Scene/Discovery/DiscoveryViewModel.swift @@ -158,7 +158,7 @@ extension DiscoveryNewsViewController: PageViewController { // MARK: - PageViewController extension DiscoveryCommunityViewController: PageViewController { - var tabItemTitle: String { "Community" } + var tabItemTitle: String { L10n.Scene.Discovery.Tabs.community } var tabItem: TMBarItemable { return TMBarItem(title: tabItemTitle) } diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/it.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/it.lproj/Localizable.strings index 0c10d8d60..8a80b11da 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/it.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/it.lproj/Localizable.strings @@ -202,7 +202,7 @@ caricato su Mastodon."; "Scene.ConfirmEmail.Subtitle" = "Tocca il link che ti abbiamo inviato per verificare il tuo account."; "Scene.ConfirmEmail.Title" = "Un'ultima cosa."; "Scene.Discovery.Intro" = "Questi sono i post che stanno guadagnando popolarità nel tuo angolo di Mastodon."; -"Scene.Discovery.Tabs.Community" = "Community"; +"Scene.Discovery.Tabs.Community" = "Comunità"; "Scene.Discovery.Tabs.ForYou" = "Per Te"; "Scene.Discovery.Tabs.Hashtags" = "Hashtag"; "Scene.Discovery.Tabs.News" = "Notizie"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings index 0c0397731..7353b6209 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings @@ -213,7 +213,7 @@ подтвердить свою учётную запись."; "Scene.ConfirmEmail.Title" = "И ещё кое-что."; "Scene.Discovery.Intro" = "These are the posts gaining traction in your corner of Mastodon."; -"Scene.Discovery.Tabs.Community" = "Community"; +"Scene.Discovery.Tabs.Community" = "Сообщество"; "Scene.Discovery.Tabs.ForYou" = "For You"; "Scene.Discovery.Tabs.Hashtags" = "Hashtags"; "Scene.Discovery.Tabs.News" = "News"; From 0b7ff6e54d8966d8219cbcdfcb1bb16b275888a8 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 29 Apr 2022 18:46:56 +0800 Subject: [PATCH 057/101] chore: update version to 1.4.0 (119) --- AppShared/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 36 +++++++++---------- .../xcschemes/xcschememanagement.plist | 6 ++-- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 9 files changed, 28 insertions(+), 28 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 7465ea609..148d09e80 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.4.0 CFBundleVersion - 118 + 119 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 4646dab87..87c95cb08 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4711,7 +4711,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 118; + CURRENT_PROJECT_VERSION = 119; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4741,7 +4741,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 118; + CURRENT_PROJECT_VERSION = 119; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4849,11 +4849,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 118; + CURRENT_PROJECT_VERSION = 119; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 118; + DYLIB_CURRENT_VERSION = 119; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4880,11 +4880,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 118; + CURRENT_PROJECT_VERSION = 119; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 118; + DYLIB_CURRENT_VERSION = 119; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4908,7 +4908,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 118; + CURRENT_PROJECT_VERSION = 119; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4932,7 +4932,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 118; + CURRENT_PROJECT_VERSION = 119; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4956,7 +4956,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 118; + CURRENT_PROJECT_VERSION = 119; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4980,7 +4980,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 118; + CURRENT_PROJECT_VERSION = 119; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5067,7 +5067,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 118; + CURRENT_PROJECT_VERSION = 119; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5134,11 +5134,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 118; + CURRENT_PROJECT_VERSION = 119; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 118; + DYLIB_CURRENT_VERSION = 119; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5162,7 +5162,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 118; + CURRENT_PROJECT_VERSION = 119; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5185,7 +5185,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 118; + CURRENT_PROJECT_VERSION = 119; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5209,7 +5209,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 118; + CURRENT_PROJECT_VERSION = 119; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5233,7 +5233,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 118; + CURRENT_PROJECT_VERSION = 119; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5256,7 +5256,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 118; + CURRENT_PROJECT_VERSION = 119; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index f31d71c9d..528fffac1 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 24 + 29 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 23 + 30 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 22 + 31 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 2e5024bbb..6209c4d90 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -43,7 +43,7 @@ CFBundleVersion - 118 + 119 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index c902ad648..6ccdceaf4 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.4.0 CFBundleVersion - 118 + 119 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 7465ea609..148d09e80 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.4.0 CFBundleVersion - 118 + 119 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 7465ea609..148d09e80 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.4.0 CFBundleVersion - 118 + 119 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index bfb91294d..5cc309ef0 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.4.0 CFBundleVersion - 118 + 119 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 01167b24f..ba3650337 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.4.0 CFBundleVersion - 118 + 119 NSExtension NSExtensionAttributes From 484f8536ba47aab4082ddbe4ad44203c4b65f005 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 29 Apr 2022 19:11:47 +0800 Subject: [PATCH 058/101] feat: use new sort logic for pick server list --- .../PickServer/MastodonPickServerViewModel.swift | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift index 59008c530..2e4994815 100644 --- a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift +++ b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift @@ -126,14 +126,22 @@ extension MastodonPickServerViewModel { // append to dict languageToServersMapping[languageCode] = indexedServers .filter { $0.language.lowercased() == languageCode.lowercased() } - .sorted(by: { $0.totalUsers > $1.totalUsers }) + .sorted(by: { lh, rh in + let lhValue = abs(log2(800.0) - log2(Double(lh.lastWeekUsers))) + let rhValue = abs(log2(800.0) - log2(Double(rh.lastWeekUsers))) + return lhValue > rhValue + }) } // sort remains servers by `totalUsers` let remainsServers = indexedServers .filter { server in return !languageToServersMapping.contains { _, servers in servers.contains(server) } } - .sorted(by: { $0.totalUsers > $1.totalUsers }) + .sorted(by: { lh, rh in + let lhValue = abs(log2(800.0) - log2(Double(lh.lastWeekUsers))) + let rhValue = abs(log2(800.0) - log2(Double(rh.lastWeekUsers))) + return lhValue > rhValue + }) var _indexedServers: [Mastodon.Entity.Server] = [] for key in languageToServersMapping.keys { From f78da3791505c44dd2fee4e96ac5a74b14691243 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 29 Apr 2022 19:12:09 +0800 Subject: [PATCH 059/101] chore: update version to 1.4.0 (120) --- AppShared/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 36 +++++++++---------- .../xcschemes/xcschememanagement.plist | 8 ++--- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 9 files changed, 29 insertions(+), 29 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 148d09e80..2cacc3762 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.4.0 CFBundleVersion - 119 + 120 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 87c95cb08..c1c6b5472 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4711,7 +4711,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 119; + CURRENT_PROJECT_VERSION = 120; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4741,7 +4741,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 119; + CURRENT_PROJECT_VERSION = 120; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4849,11 +4849,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 119; + CURRENT_PROJECT_VERSION = 120; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 119; + DYLIB_CURRENT_VERSION = 120; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4880,11 +4880,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 119; + CURRENT_PROJECT_VERSION = 120; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 119; + DYLIB_CURRENT_VERSION = 120; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4908,7 +4908,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 119; + CURRENT_PROJECT_VERSION = 120; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4932,7 +4932,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 119; + CURRENT_PROJECT_VERSION = 120; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4956,7 +4956,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 119; + CURRENT_PROJECT_VERSION = 120; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4980,7 +4980,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 119; + CURRENT_PROJECT_VERSION = 120; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5067,7 +5067,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 119; + CURRENT_PROJECT_VERSION = 120; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5134,11 +5134,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 119; + CURRENT_PROJECT_VERSION = 120; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 119; + DYLIB_CURRENT_VERSION = 120; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5162,7 +5162,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 119; + CURRENT_PROJECT_VERSION = 120; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5185,7 +5185,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 119; + CURRENT_PROJECT_VERSION = 120; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5209,7 +5209,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 119; + CURRENT_PROJECT_VERSION = 120; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5233,7 +5233,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 119; + CURRENT_PROJECT_VERSION = 120; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5256,7 +5256,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 119; + CURRENT_PROJECT_VERSION = 120; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 528fffac1..c71d962de 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -19,7 +19,7 @@ Mastodon - RTL.xcscheme_^#shared#^_ orderHint - 7 + 6 Mastodon - Release.xcscheme_^#shared#^_ @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 29 + 26 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 30 + 27 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 31 + 28 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 6209c4d90..0d95b8647 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -43,7 +43,7 @@ CFBundleVersion - 119 + 120 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 6ccdceaf4..2895a0994 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.4.0 CFBundleVersion - 119 + 120 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 148d09e80..2cacc3762 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.4.0 CFBundleVersion - 119 + 120 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 148d09e80..2cacc3762 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.4.0 CFBundleVersion - 119 + 120 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index 5cc309ef0..d07eb4b2d 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.4.0 CFBundleVersion - 119 + 120 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index ba3650337..9c268021b 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.4.0 CFBundleVersion - 119 + 120 NSExtension NSExtensionAttributes From b64b88883eafaca242abe694338e21b9d474c4ac Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 29 Apr 2022 20:41:23 +0800 Subject: [PATCH 060/101] chore: update sort direction and add comments --- .../xcschemes/xcschememanagement.plist | 6 +++--- .../PickServer/MastodonPickServerViewModel.swift | 11 +++++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index c71d962de..640adb736 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 26 + 21 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 27 + 19 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 28 + 20 SuppressBuildableAutocreation diff --git a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift index 2e4994815..749843880 100644 --- a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift +++ b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift @@ -115,8 +115,11 @@ extension MastodonPickServerViewModel { if self.mode == .signUp { indexedServers = indexedServers.filter { !$0.approvalRequired } } + // Note: + // sort by calculate last week users count + // and make medium size (~800) server to top - // group by language user preferred language first. Then sort by `totalUsers` + // group by language user preferred language first var languageToServersMapping = OrderedDictionary() for language in Locale.preferredLanguages { let local = Locale(identifier: language) @@ -129,10 +132,10 @@ extension MastodonPickServerViewModel { .sorted(by: { lh, rh in let lhValue = abs(log2(800.0) - log2(Double(lh.lastWeekUsers))) let rhValue = abs(log2(800.0) - log2(Double(rh.lastWeekUsers))) - return lhValue > rhValue + return lhValue < rhValue }) } - // sort remains servers by `totalUsers` + // sort remains servers let remainsServers = indexedServers .filter { server in return !languageToServersMapping.contains { _, servers in servers.contains(server) } @@ -140,7 +143,7 @@ extension MastodonPickServerViewModel { .sorted(by: { lh, rh in let lhValue = abs(log2(800.0) - log2(Double(lh.lastWeekUsers))) let rhValue = abs(log2(800.0) - log2(Double(rh.lastWeekUsers))) - return lhValue > rhValue + return lhValue < rhValue }) var _indexedServers: [Mastodon.Entity.Server] = [] From 8e4f382a8f592c673709a2fbb1d99632364c38ad Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 29 Apr 2022 20:42:11 +0800 Subject: [PATCH 061/101] chore: update version to 1.4.0 (121) --- AppShared/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 36 +++++++++---------- .../xcschemes/xcschememanagement.plist | 6 ++-- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 9 files changed, 28 insertions(+), 28 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 2cacc3762..a1528e2c5 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.4.0 CFBundleVersion - 120 + 121 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index c1c6b5472..fcba16b23 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4711,7 +4711,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 120; + CURRENT_PROJECT_VERSION = 121; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4741,7 +4741,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 120; + CURRENT_PROJECT_VERSION = 121; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4849,11 +4849,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 120; + CURRENT_PROJECT_VERSION = 121; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 120; + DYLIB_CURRENT_VERSION = 121; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4880,11 +4880,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 120; + CURRENT_PROJECT_VERSION = 121; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 120; + DYLIB_CURRENT_VERSION = 121; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4908,7 +4908,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 120; + CURRENT_PROJECT_VERSION = 121; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4932,7 +4932,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 120; + CURRENT_PROJECT_VERSION = 121; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4956,7 +4956,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 120; + CURRENT_PROJECT_VERSION = 121; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4980,7 +4980,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 120; + CURRENT_PROJECT_VERSION = 121; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5067,7 +5067,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 120; + CURRENT_PROJECT_VERSION = 121; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5134,11 +5134,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 120; + CURRENT_PROJECT_VERSION = 121; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 120; + DYLIB_CURRENT_VERSION = 121; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5162,7 +5162,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 120; + CURRENT_PROJECT_VERSION = 121; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5185,7 +5185,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 120; + CURRENT_PROJECT_VERSION = 121; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5209,7 +5209,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 120; + CURRENT_PROJECT_VERSION = 121; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5233,7 +5233,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 120; + CURRENT_PROJECT_VERSION = 121; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5256,7 +5256,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 120; + CURRENT_PROJECT_VERSION = 121; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 640adb736..979898bbd 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 21 + 28 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 19 + 27 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 20 + 22 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 0d95b8647..6dec562da 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -43,7 +43,7 @@ CFBundleVersion - 120 + 121 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 2895a0994..d08d9c217 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.4.0 CFBundleVersion - 120 + 121 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 2cacc3762..a1528e2c5 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.4.0 CFBundleVersion - 120 + 121 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 2cacc3762..a1528e2c5 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.4.0 CFBundleVersion - 120 + 121 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index d07eb4b2d..0029eea56 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.4.0 CFBundleVersion - 120 + 121 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 9c268021b..25fc34294 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.4.0 CFBundleVersion - 120 + 121 NSExtension NSExtensionAttributes From 170d514126706353295d8722ed4911e7a456921c Mon Sep 17 00:00:00 2001 From: vollkorntomate Date: Wed, 4 May 2022 20:05:03 +0200 Subject: [PATCH 062/101] Improve tab bar icon vertical alignment --- .../Scene/Root/MainTab/MainTabBarController.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift index 7ea748a60..f9bdf9f0f 100644 --- a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift +++ b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift @@ -147,10 +147,10 @@ extension MainTabBarController { let viewControllers: [UIViewController] = tabs.map { tab in let viewController = tab.viewController(context: context, coordinator: coordinator) viewController.tabBarItem.tag = tab.tag - viewController.tabBarItem.title = tab.title - viewController.tabBarItem.image = tab.image + viewController.tabBarItem.title = nil + viewController.tabBarItem.image = tab.image.imageWithoutBaseline() viewController.tabBarItem.accessibilityLabel = tab.title - viewController.tabBarItem.largeContentSizeImage = tab.largeImage + viewController.tabBarItem.largeContentSizeImage = tab.largeImage.imageWithoutBaseline() viewController.tabBarItem.imageInsets = UIEdgeInsets(top: 6, left: 0, bottom: -6, right: 0) return viewController } @@ -224,8 +224,8 @@ extension MainTabBarController { } ?? false let image = hasUnreadPushNotification ? UIImage(systemName: "bell.badge.fill")! : UIImage(systemName: "bell.fill")! - notificationViewController.tabBarItem.image = image - notificationViewController.navigationController?.tabBarItem.image = image + notificationViewController.tabBarItem.image = image.imageWithoutBaseline() + notificationViewController.navigationController?.tabBarItem.image = image.imageWithoutBaseline() } .store(in: &disposeBag) @@ -371,7 +371,7 @@ extension MainTabBarController { view.addSubview(self.avatarButton) NSLayoutConstraint.activate([ self.avatarButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), - self.avatarButton.centerYAnchor.constraint(equalTo: anchorImageView.centerYAnchor, constant: 1.5), // 1.5pt offset + self.avatarButton.centerYAnchor.constraint(equalTo: view.centerYAnchor), self.avatarButton.widthAnchor.constraint(equalToConstant: MainTabBarController.avatarButtonSize.width).priority(.required - 1), self.avatarButton.heightAnchor.constraint(equalToConstant: MainTabBarController.avatarButtonSize.height).priority(.required - 1), ]) From f385658d7022eb8e216edebc9911ad876272aabd Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 6 May 2022 14:29:34 +0800 Subject: [PATCH 063/101] feat: update tabBar UI --- .../xcschemes/xcschememanagement.plist | 6 +- Mastodon/Coordinator/SceneCoordinator.swift | 4 +- .../Root/ContentSplitViewController.swift | 3 +- .../Root/MainTab/MainTabBarController.swift | 198 ++++++++++++++---- .../Scene/Root/RootSplitViewController.swift | 6 +- .../Scene/Root/Sidebar/SidebarViewModel.swift | 55 +++-- .../Sidebar/View/SidebarListContentView.swift | 13 +- .../bell.badge.fill.imageset/Contents.json | 15 ++ .../bell.badge.fill.pdf | 94 +++++++++ .../bell.badge.imageset/Contents.json | 15 ++ .../bell.badge.imageset/bell.badge.pdf | 112 ++++++++++ .../bell.fill.imageset/Contents.json | 15 ++ .../bell.fill.imageset/bell.fill.pdf | 88 ++++++++ .../bell.imageset/Contents.json | 15 ++ .../ObjectsAndTools/bell.imageset/bell.pdf | 106 ++++++++++ .../gear.imageset/Contents.json | 15 ++ .../ObjectsAndTools/gear.imageset/gear.pdf | 155 ++++++++++++++ .../house.fill.imageset/Contents.json | 15 ++ .../house.fill.imageset/Home-fill.pdf | 85 ++++++++ .../house.imageset/Contents.json | 15 ++ .../ObjectsAndTools/house.imageset/Home.pdf | 105 ++++++++++ .../Contents.json | 15 ++ .../Search-Fill.pdf | 83 ++++++++ .../magnifyingglass.imageset/Contents.json | 15 ++ .../magnifyingglass.imageset/Search.pdf | 83 ++++++++ .../square.and.pencil.imageset/Contents.json | 15 ++ .../square.and.pencil.pdf | 93 ++++++++ .../MastodonAsset/Generated/Assets.swift | 10 + .../MastodonUI/Extension/UIImage.swift | 17 ++ 29 files changed, 1399 insertions(+), 67 deletions(-) create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.fill.imageset/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.fill.imageset/bell.badge.fill.pdf create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.imageset/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.imageset/bell.badge.pdf create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.fill.imageset/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.fill.imageset/bell.fill.pdf create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.imageset/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.imageset/bell.pdf create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/gear.imageset/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/gear.imageset/gear.pdf create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.fill.imageset/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.fill.imageset/Home-fill.pdf create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.imageset/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.imageset/Home.pdf create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.fill.imageset/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.fill.imageset/Search-Fill.pdf create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.imageset/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.imageset/Search.pdf create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/square.and.pencil.imageset/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/square.and.pencil.imageset/square.and.pencil.pdf create mode 100644 MastodonSDK/Sources/MastodonUI/Extension/UIImage.swift diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 979898bbd..1ac4532e7 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 28 + 19 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 27 + 21 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 22 + 20 SuppressBuildableAutocreation diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index 1f8030014..819872c70 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -368,10 +368,10 @@ extension SceneCoordinator { splitViewController?.contentSplitViewController.currentSupplementaryTab = tab splitViewController?.compactMainTabBarViewController.selectedIndex = tab.rawValue - splitViewController?.compactMainTabBarViewController.currentTab.value = tab + splitViewController?.compactMainTabBarViewController.currentTab = tab tabBarController.selectedIndex = tab.rawValue - tabBarController.currentTab.value = tab + tabBarController.currentTab = tab } } diff --git a/Mastodon/Scene/Root/ContentSplitViewController.swift b/Mastodon/Scene/Root/ContentSplitViewController.swift index 5a34e1ed8..e3a6952f8 100644 --- a/Mastodon/Scene/Root/ContentSplitViewController.swift +++ b/Mastodon/Scene/Root/ContentSplitViewController.swift @@ -83,7 +83,8 @@ extension ContentSplitViewController { .sink(receiveValue: { [weak self] tab in guard let self = self else { return } self.mainTabBarController.selectedIndex = tab.rawValue - self.mainTabBarController.currentTab.value = tab + self.mainTabBarController.currentTab = tab + self.sidebarViewController.viewModel.currentTab = tab }) .store(in: &disposeBag) } diff --git a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift index f9bdf9f0f..d6eea39da 100644 --- a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift +++ b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift @@ -22,14 +22,29 @@ class MainTabBarController: UITabBarController { weak var context: AppContext! weak var coordinator: SceneCoordinator! + let composeButttonShadowBackgroundContainer = ShadowBackgroundContainer() + let composeButton: UIButton = { + let button = UIButton() + button.setImage(Asset.ObjectsAndTools.squareAndPencil.image.withRenderingMode(.alwaysTemplate), for: .normal) + button.setBackgroundImage(UIImage.placeholder(color: Asset.Colors.Label.primary.color), for: .normal) + button.setBackgroundImage(UIImage.placeholder(color: Asset.Colors.Label.primary.color.withAlphaComponent(0.8)), for: .highlighted) + button.tintColor = Asset.Colors.Label.primaryReverse.color + button.contentEdgeInsets = UIEdgeInsets(top: 6, left: 12, bottom: 6, right: 12) + button.layer.masksToBounds = true + button.layer.cornerCurve = .continuous + button.layer.cornerRadius = 8 + return button + }() + static let avatarButtonSize = CGSize(width: 25, height: 25) let avatarButton = CircleAvatarButton() - var currentTab = CurrentValueSubject(.home) + @Published var currentTab: Tab = .home enum Tab: Int, CaseIterable { case home case search + case compose case notification case me @@ -41,6 +56,7 @@ class MainTabBarController: UITabBarController { switch self { case .home: return L10n.Common.Controls.Tabs.home case .search: return L10n.Common.Controls.Tabs.search + case .compose: return L10n.Common.Controls.Actions.compose case .notification: return L10n.Common.Controls.Tabs.notification case .me: return L10n.Common.Controls.Tabs.profile } @@ -48,28 +64,41 @@ class MainTabBarController: UITabBarController { var image: UIImage { switch self { - case .home: return UIImage(systemName: "house.fill")! - case .search: return UIImage(systemName: "magnifyingglass")! - case .notification: return UIImage(systemName: "bell.fill")! + case .home: return Asset.ObjectsAndTools.house.image.withRenderingMode(.alwaysTemplate) + case .search: return Asset.ObjectsAndTools.magnifyingglass.image.withRenderingMode(.alwaysTemplate) + case .compose: return Asset.ObjectsAndTools.squareAndPencil.image.withRenderingMode(.alwaysTemplate) + case .notification: return Asset.ObjectsAndTools.bell.image.withRenderingMode(.alwaysTemplate) + case .me: return UIImage(systemName: "person")! + } + } + + var selectedImage: UIImage { + switch self { + case .home: return Asset.ObjectsAndTools.houseFill.image.withRenderingMode(.alwaysTemplate) + case .search: return Asset.ObjectsAndTools.magnifyingglassFill.image.withRenderingMode(.alwaysTemplate) + case .compose: return Asset.ObjectsAndTools.squareAndPencil.image.withRenderingMode(.alwaysTemplate) + case .notification: return Asset.ObjectsAndTools.bellFill.image.withRenderingMode(.alwaysTemplate) case .me: return UIImage(systemName: "person.fill")! } } var largeImage: UIImage { switch self { - case .home: return UIImage(systemName: "house.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 80))! - case .search: return UIImage(systemName: "magnifyingglass", withConfiguration: UIImage.SymbolConfiguration(pointSize: 80))! - case .notification: return UIImage(systemName: "bell.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 80))! - case .me: return UIImage(systemName: "person.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 80))! + case .home: return Asset.ObjectsAndTools.house.image.withRenderingMode(.alwaysTemplate).resized(size: CGSize(width: 80, height: 80)) + case .search: return Asset.ObjectsAndTools.magnifyingglass.image.withRenderingMode(.alwaysTemplate).resized(size: CGSize(width: 80, height: 80)) + case .compose: return Asset.ObjectsAndTools.squareAndPencil.image.withRenderingMode(.alwaysTemplate).resized(size: CGSize(width: 80, height: 80)) + case .notification: return Asset.ObjectsAndTools.bell.image.withRenderingMode(.alwaysTemplate).resized(size: CGSize(width: 80, height: 80)) + case .me: return UIImage(systemName: "person", withConfiguration: UIImage.SymbolConfiguration(pointSize: 80))! } } var sidebarImage: UIImage { switch self { - case .home: return UIImage(systemName: "house")! - case .search: return UIImage(systemName: "magnifyingglass")! - case .notification: return UIImage(systemName: "bell")! - case .me: return UIImage(systemName: "person.fill")! + case .home: return Asset.ObjectsAndTools.house.image.withRenderingMode(.alwaysTemplate) + case .search: return Asset.ObjectsAndTools.magnifyingglass.image.withRenderingMode(.alwaysTemplate) + case .compose: return Asset.ObjectsAndTools.squareAndPencil.image.withRenderingMode(.alwaysTemplate) + case .notification: return Asset.ObjectsAndTools.bell.image.withRenderingMode(.alwaysTemplate) + case .me: return UIImage(systemName: "person")! } } @@ -86,6 +115,8 @@ class MainTabBarController: UITabBarController { _viewController.context = context _viewController.coordinator = coordinator viewController = _viewController + case .compose: + viewController = UIViewController() case .notification: let _viewController = NotificationViewController() _viewController.context = context @@ -149,18 +180,31 @@ extension MainTabBarController { viewController.tabBarItem.tag = tab.tag viewController.tabBarItem.title = nil viewController.tabBarItem.image = tab.image.imageWithoutBaseline() - viewController.tabBarItem.accessibilityLabel = tab.title + viewController.tabBarItem.selectedImage = tab.selectedImage.imageWithoutBaseline() viewController.tabBarItem.largeContentSizeImage = tab.largeImage.imageWithoutBaseline() + viewController.tabBarItem.accessibilityLabel = tab.title viewController.tabBarItem.imageInsets = UIEdgeInsets(top: 6, left: 0, bottom: -6, right: 0) + + switch tab { + case .compose: + viewController.tabBarItem.isEnabled = false + default: + break + } + return viewController } _viewControllers = viewControllers setViewControllers(viewControllers, animated: false) selectedIndex = 0 - - UITabBarItem.appearance().setTitleTextAttributes([.foregroundColor : UIColor.clear], for: .normal) - UITabBarItem.appearance().setTitleTextAttributes([.foregroundColor : UIColor.clear], for: .highlighted) - UITabBarItem.appearance().setTitleTextAttributes([.foregroundColor : UIColor.clear], for: .selected) + + let tabBarItemAppearance = UITabBarItemAppearance() + tabBarItemAppearance.configureWithDefault(for: .stacked) + tabBarItemAppearance.normal.iconColor = Asset.Colors.Label.primary.color + tabBar.standardAppearance.stackedItemPositioning = .centered + tabBar.standardAppearance.stackedLayoutAppearance = tabBarItemAppearance + tabBar.standardAppearance.inlineLayoutAppearance = tabBarItemAppearance + tabBar.standardAppearance.compactInlineLayoutAppearance = tabBarItemAppearance context.apiService.error .receive(on: DispatchQueue.main) @@ -208,13 +252,15 @@ extension MainTabBarController { } .store(in: &disposeBag) - // handle push notification. toggle entry when finish fetch latest notification - Publishers.CombineLatest( + // handle push notification. + // toggle entry when finish fetch latest notification + Publishers.CombineLatest3( context.authenticationService.activeMastodonAuthentication, - context.notificationService.unreadNotificationCountDidUpdate + context.notificationService.unreadNotificationCountDidUpdate, + $currentTab ) .receive(on: DispatchQueue.main) - .sink { [weak self] authentication, _ in + .sink { [weak self] authentication, _, currentTab in guard let self = self else { return } guard let notificationViewController = self.notificationViewController else { return } @@ -223,12 +269,19 @@ extension MainTabBarController { return count > 0 } ?? false - let image = hasUnreadPushNotification ? UIImage(systemName: "bell.badge.fill")! : UIImage(systemName: "bell.fill")! + let image: UIImage = { + if currentTab == .notification { + return hasUnreadPushNotification ? Asset.ObjectsAndTools.bellBadgeFill.image.withRenderingMode(.alwaysTemplate) : Asset.ObjectsAndTools.bellFill.image.withRenderingMode(.alwaysTemplate) + } else { + return hasUnreadPushNotification ? Asset.ObjectsAndTools.bellBadge.image.withRenderingMode(.alwaysTemplate) : Asset.ObjectsAndTools.bell.image.withRenderingMode(.alwaysTemplate) + } + }() notificationViewController.tabBarItem.image = image.imageWithoutBaseline() notificationViewController.navigationController?.tabBarItem.image = image.imageWithoutBaseline() } .store(in: &disposeBag) + layoutComposeButton() layoutAvatarButton() $avatarURL @@ -280,7 +333,7 @@ extension MainTabBarController { } .store(in: &disposeBag) - currentTab + $currentTab .receive(on: DispatchQueue.main) .sink { [weak self] tab in guard let self = self else { return } @@ -290,6 +343,8 @@ extension MainTabBarController { updateTabBarDisplay() + composeButton.addTarget(self, action: #selector(MainTabBarController.composeButtonDidPressed(_:)), for: .touchUpInside) + #if DEBUG // Debug Register viewController // Task { @MainActor in @@ -307,23 +362,25 @@ extension MainTabBarController { super.traitCollectionDidChange(previousTraitCollection) updateTabBarDisplay() + updateComposeButtonAppearance() updateAvatarButtonAppearance() } } extension MainTabBarController { - private func updateTabBarDisplay() { - switch traitCollection.horizontalSizeClass { - case .compact: - tabBar.isHidden = false - default: - tabBar.isHidden = true - } + + @objc private func composeButtonDidPressed(_ sender: UIButton) { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)") + guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return } + let composeViewModel = ComposeViewModel( + context: context, + composeKind: .post, + authenticationBox: authenticationBox + ) + coordinator.present(scene: .compose(viewModel: composeViewModel), from: nil, transition: .modal(animated: true, completion: nil)) } -} - -extension MainTabBarController { + @objc private func tabBarLongPressGestureRecognizerHandler(_ sender: UILongPressGestureRecognizer) { guard sender.state == .began else { return } @@ -351,6 +408,57 @@ extension MainTabBarController { } extension MainTabBarController { + + private func updateTabBarDisplay() { + switch traitCollection.horizontalSizeClass { + case .compact: + tabBar.isHidden = false + default: + tabBar.isHidden = true + } + } + + private func layoutComposeButton() { + guard composeButton.superview == nil else { return } + + let _composeTabItem = self.tabBar.items?.first { item in item.tag == Tab.compose.tag } + guard let composeTabItem = _composeTabItem else { return } + guard let view = composeTabItem.value(forKey: "view") as? UIView else { + return + } + + let _anchorImageView = view.subviews.first { subview in subview is UIImageView } as? UIImageView + guard let anchorImageView = _anchorImageView else { + assertionFailure() + return + } + anchorImageView.alpha = 0 + + composeButttonShadowBackgroundContainer.translatesAutoresizingMaskIntoConstraints = false + tabBar.addSubview(composeButttonShadowBackgroundContainer) + NSLayoutConstraint.activate([ + composeButttonShadowBackgroundContainer.centerXAnchor.constraint(equalTo: anchorImageView.centerXAnchor), + composeButttonShadowBackgroundContainer.centerYAnchor.constraint(equalTo: anchorImageView.centerYAnchor), + ]) + composeButttonShadowBackgroundContainer.cornerRadius = composeButton.layer.cornerRadius + + composeButton.translatesAutoresizingMaskIntoConstraints = false + composeButttonShadowBackgroundContainer.addSubview(composeButton) + NSLayoutConstraint.activate([ + composeButton.topAnchor.constraint(equalTo: composeButttonShadowBackgroundContainer.topAnchor), + composeButton.leadingAnchor.constraint(equalTo: composeButttonShadowBackgroundContainer.leadingAnchor), + composeButton.trailingAnchor.constraint(equalTo: composeButttonShadowBackgroundContainer.trailingAnchor), + composeButton.bottomAnchor.constraint(equalTo: composeButttonShadowBackgroundContainer.bottomAnchor), + ]) + composeButton.setContentHuggingPriority(.required - 1, for: .horizontal) + composeButton.setContentHuggingPriority(.required - 1, for: .vertical) + } + + private func updateComposeButtonAppearance() { + composeButton.setBackgroundImage(UIImage.placeholder(color: Asset.Colors.Label.primary.color), for: .normal) + composeButton.setBackgroundImage(UIImage.placeholder(color: Asset.Colors.Label.primary.color.withAlphaComponent(0.8)), for: .highlighted) + } + private func layoutAvatarButton() { guard avatarButton.superview == nil else { return } @@ -370,8 +478,8 @@ extension MainTabBarController { self.avatarButton.translatesAutoresizingMaskIntoConstraints = false view.addSubview(self.avatarButton) NSLayoutConstraint.activate([ - self.avatarButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), - self.avatarButton.centerYAnchor.constraint(equalTo: view.centerYAnchor), + self.avatarButton.centerXAnchor.constraint(equalTo: anchorImageView.centerXAnchor), + self.avatarButton.centerYAnchor.constraint(equalTo: anchorImageView.centerYAnchor), self.avatarButton.widthAnchor.constraint(equalToConstant: MainTabBarController.avatarButtonSize.width).priority(.required - 1), self.avatarButton.heightAnchor.constraint(equalToConstant: MainTabBarController.avatarButtonSize.height).priority(.required - 1), ]) @@ -381,9 +489,10 @@ extension MainTabBarController { } private func updateAvatarButtonAppearance() { - avatarButton.borderColor = currentTab.value == .me ? .label : .systemFill + avatarButton.borderColor = currentTab == .me ? .label : .systemFill avatarButton.setNeedsLayout() } + } extension MainTabBarController { @@ -403,11 +512,12 @@ extension MainTabBarController: UITabBarControllerDelegate { func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: select %s", ((#file as NSString).lastPathComponent), #line, #function, viewController.debugDescription) defer { - if let tab = Tab(rawValue: tabBarController.selectedIndex) { - currentTab.value = tab + if let tab = Tab(rawValue: viewController.tabBarItem.tag) { + currentTab = tab } } - guard currentTab.value.rawValue == tabBarController.selectedIndex, + // assert index is as same as the tab rawValue + guard currentTab.rawValue == tabBarController.selectedIndex, let navigationController = viewController as? UINavigationController, navigationController.viewControllers.count == 1, let scrollViewContainer = navigationController.topViewController as? ScrollViewContainer else { @@ -478,7 +588,13 @@ extension MainTabBarController { var switchToTabKeyCommands: [UIKeyCommand] { var commands: [UIKeyCommand] = [] - for (i, tab) in Tab.allCases.enumerated() { + let tabs: [Tab] = [ + .home, + .search, + .notification, + .me + ] + for (i, tab) in tabs.enumerated() { let title = L10n.Common.Controls.Keyboard.Common.switchToTab(tab.title) let input = String(i + 1) let command = UIKeyCommand( @@ -584,7 +700,7 @@ extension MainTabBarController { let previousTab = Tab(rawValue: selectedIndex) selectedIndex = index if let tab = Tab(rawValue: index) { - currentTab.value = tab + currentTab = tab } if let previousTab = previousTab { diff --git a/Mastodon/Scene/Root/RootSplitViewController.swift b/Mastodon/Scene/Root/RootSplitViewController.swift index d9b18b0b4..f19282936 100644 --- a/Mastodon/Scene/Root/RootSplitViewController.swift +++ b/Mastodon/Scene/Root/RootSplitViewController.swift @@ -208,7 +208,7 @@ extension RootSplitViewController: UISplitViewControllerDelegate { switch proposedTopColumn { case .compact: RootSplitViewController.transform(from: contentSplitViewController.mainTabBarController, to: compactMainTabBarViewController) - compactMainTabBarViewController.currentTab.value = contentSplitViewController.currentSupplementaryTab + compactMainTabBarViewController.currentTab = contentSplitViewController.currentSupplementaryTab default: assertionFailure() @@ -231,11 +231,11 @@ extension RootSplitViewController: UISplitViewControllerDelegate { RootSplitViewController.transform(from: compactMainTabBarViewController, to: contentSplitViewController.mainTabBarController) - let tab = compactMainTabBarViewController.currentTab.value + let tab = compactMainTabBarViewController.currentTab if tab == .search { contentSplitViewController.currentSupplementaryTab = .home } else { - contentSplitViewController.currentSupplementaryTab = compactMainTabBarViewController.currentTab.value + contentSplitViewController.currentSupplementaryTab = compactMainTabBarViewController.currentTab } return proposedDisplayMode diff --git a/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift index 3cc277dc6..a6698d6c2 100644 --- a/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift +++ b/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift @@ -22,7 +22,8 @@ final class SidebarViewModel { let context: AppContext @Published private var isSidebarDataSourceReady = false @Published private var isAvatarButtonDataReady = false - + @Published var currentTab: MainTabBarController.Tab = .home + // output var diffableDataSource: UICollectionViewDiffableDataSource? var secondaryDiffableDataSource: UICollectionViewDiffableDataSource? @@ -86,35 +87,55 @@ extension SidebarViewModel { } }() cell.item = SidebarListContentView.Item( + isActive: false, title: item.title, - image: item.sidebarImage, + image: item.image, + activeImage: item.selectedImage, imageURL: imageURL ) cell.setNeedsUpdateConfiguration() cell.isAccessibilityElement = true cell.accessibilityLabel = item.title + self.$currentTab + .receive(on: DispatchQueue.main) + .sink { [weak cell] currentTab in + guard let cell = cell else { return } + cell.item?.isActive = currentTab == item + cell.setNeedsUpdateConfiguration() + } + .store(in: &cell.disposeBag) + switch item { case .notification: - Publishers.CombineLatest( + Publishers.CombineLatest3( self.context.authenticationService.activeMastodonAuthentication, - self.context.notificationService.unreadNotificationCountDidUpdate + self.context.notificationService.unreadNotificationCountDidUpdate, + self.$currentTab ) .receive(on: DispatchQueue.main) - .sink { [weak cell] authentication, _ in + .sink { [weak cell] authentication, _, currentTab in guard let cell = cell else { return } let hasUnreadPushNotification: Bool = authentication.flatMap { authentication in let count = UserDefaults.shared.getNotificationCountWithAccessToken(accessToken: authentication.userAccessToken) return count > 0 } ?? false - let image = hasUnreadPushNotification ? UIImage(systemName: "bell.badge")! : UIImage(systemName: "bell")! - cell._contentView?.imageView.image = image + let image: UIImage = { + if currentTab == .notification { + return hasUnreadPushNotification ? Asset.ObjectsAndTools.bellBadgeFill.image.withRenderingMode(.alwaysTemplate) : Asset.ObjectsAndTools.bellFill.image.withRenderingMode(.alwaysTemplate) + } else { + return hasUnreadPushNotification ? Asset.ObjectsAndTools.bellBadge.image.withRenderingMode(.alwaysTemplate) : Asset.ObjectsAndTools.bell.image.withRenderingMode(.alwaysTemplate) + } + }() + cell.item?.image = image + cell.item?.activeImage = image + cell.setNeedsUpdateConfiguration() } .store(in: &cell.disposeBag) case .me: guard let authentication = self.context.authenticationService.activeMastodonAuthentication.value else { break } - let currentUserDisplayName = authentication.user.displayNameWithFallback ?? "no user" + let currentUserDisplayName = authentication.user.displayNameWithFallback cell.accessibilityHint = L10n.Scene.AccountList.tabBarHint(currentUserDisplayName) default: break @@ -122,7 +143,7 @@ extension SidebarViewModel { } let cellRegistration = UICollectionView.CellRegistration { [weak self] cell, indexPath, item in - guard let self = self else { return } + guard let _ = self else { return } cell.item = item cell.setNeedsUpdateConfiguration() cell.isAccessibilityElement = true @@ -140,15 +161,19 @@ extension SidebarViewModel { return collectionView.dequeueConfiguredReusableCell(using: tabCellRegistration, for: indexPath, item: tab) case .setting: let item = SidebarListContentView.Item( + isActive: false, title: L10n.Common.Controls.Actions.settings, - image: UIImage(systemName: "gear")!, + image: Asset.ObjectsAndTools.gear.image.withRenderingMode(.alwaysTemplate), + activeImage: Asset.ObjectsAndTools.gear.image.withRenderingMode(.alwaysTemplate), imageURL: nil ) return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: item) case .compose: let item = SidebarListContentView.Item( + isActive: false, title: L10n.Common.Controls.Actions.compose, - image: UIImage(systemName: "square.and.pencil")!, + image: Asset.ObjectsAndTools.squareAndPencil.image.withRenderingMode(.alwaysTemplate), + activeImage: Asset.ObjectsAndTools.squareAndPencil.image.withRenderingMode(.alwaysTemplate), imageURL: nil ) return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: item) @@ -192,15 +217,15 @@ extension SidebarViewModel { } let item = SidebarListContentView.Item( + isActive: false, title: L10n.Common.Controls.Actions.compose, - image: UIImage(systemName: "square.and.pencil")!, + image: Asset.ObjectsAndTools.squareAndPencil.image.withRenderingMode(.alwaysTemplate), + activeImage: Asset.ObjectsAndTools.squareAndPencil.image.withRenderingMode(.alwaysTemplate), imageURL: nil ) return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: item) } -// _secondaryDiffableDataSource.supplementaryViewProvider = { collectionView, elementKind, indexPath in -// return nil -// } + secondaryDiffableDataSource = _secondaryDiffableDataSource var secondarySnapshot = NSDiffableDataSourceSnapshot() diff --git a/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift b/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift index d6ae40e17..794563eaf 100644 --- a/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift +++ b/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift @@ -93,12 +93,14 @@ extension SidebarListContentView { // configure model imageView.isHidden = item.imageURL != nil avatarButton.isHidden = item.imageURL == nil - imageView.image = item.image.withRenderingMode(.alwaysTemplate) + imageView.image = item.isActive ? item.activeImage.withRenderingMode(.alwaysTemplate) : item.image.withRenderingMode(.alwaysTemplate) avatarButton.avatarImageView.setImage( url: item.imageURL, placeholder: avatarButton.avatarImageView.image ?? .placeholder(color: .systemFill), // reuse to avoid blink scaleToSize: nil ) + avatarButton.borderWidth = item.isActive ? 2 : 0 + avatarButton.setNeedsLayout() } } @@ -107,25 +109,32 @@ extension SidebarListContentView { // state var isSelected: Bool = false var isHighlighted: Bool = false + var isActive: Bool // model let title: String - let image: UIImage + var image: UIImage + var activeImage: UIImage let imageURL: URL? + static func == (lhs: SidebarListContentView.Item, rhs: SidebarListContentView.Item) -> Bool { return lhs.isSelected == rhs.isSelected && lhs.isHighlighted == rhs.isHighlighted + && lhs.isActive == rhs.isActive && lhs.title == rhs.title && lhs.image == rhs.image + && lhs.activeImage == rhs.activeImage && lhs.imageURL == rhs.imageURL } func hash(into hasher: inout Hasher) { hasher.combine(isSelected) hasher.combine(isHighlighted) + hasher.combine(isActive) hasher.combine(title) hasher.combine(image) + hasher.combine(activeImage) imageURL.flatMap { hasher.combine($0) } } } diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.fill.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.fill.imageset/Contents.json new file mode 100644 index 000000000..956d7c99c --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.fill.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "bell.badge.fill.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.fill.imageset/bell.badge.fill.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.fill.imageset/bell.badge.fill.pdf new file mode 100644 index 000000000..10b05f319 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.fill.imageset/bell.badge.fill.pdf @@ -0,0 +1,94 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 4.000000 3.251190 cm +0.000000 0.000000 0.000000 scn +17.228973 14.106000 m +17.604315 14.106000 17.967243 14.159944 18.310644 14.260609 c +18.330521 14.022223 18.340664 13.781026 18.340664 13.537420 c +18.340664 9.025727 l +19.917404 5.460056 l +19.978443 5.322020 20.010000 5.172432 20.010000 5.021130 c +20.010000 4.429121 19.537165 3.949203 18.953897 3.949203 c +1.056364 3.949203 l +0.907638 3.949203 0.760588 3.981087 0.624843 4.042767 c +0.092485 4.284660 -0.145878 4.918783 0.092444 5.459118 c +1.665367 9.025314 l +1.665486 13.551995 l +1.670396 13.833986 l +1.824999 18.382032 5.507209 22.000000 10.003014 22.000000 c +11.607554 22.000000 13.106230 21.539965 14.378001 20.742750 c +13.732699 20.037863 13.338069 19.093309 13.338069 18.055204 c +13.338069 15.874119 15.080086 14.106000 17.228973 14.106000 c +h +13.291688 2.819208 m +13.026393 1.219061 11.654965 0.000000 10.003014 0.000000 c +8.351062 0.000000 6.979633 1.219061 6.714338 2.819208 c +13.291688 2.819208 l +h +17.228973 15.234344 m +18.763893 15.234344 20.008190 16.497286 20.008190 18.055204 c +20.008190 19.613121 18.763893 20.876064 17.228973 20.876064 c +15.694054 20.876064 14.449756 19.613121 14.449756 18.055204 c +14.449756 16.497286 15.694054 15.234344 17.228973 15.234344 c +h +f +n +Q + +endstream +endobj + +3 0 obj + 1305 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 28.000000 28.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000001395 00000 n +0000001418 00000 n +0000001591 00000 n +0000001665 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +1724 +%%EOF \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.imageset/Contents.json new file mode 100644 index 000000000..7e5adf71d --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "bell.badge.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.imageset/bell.badge.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.imageset/bell.badge.pdf new file mode 100644 index 000000000..0aa1ebbd9 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.imageset/bell.badge.pdf @@ -0,0 +1,112 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 4.000000 3.000000 cm +0.000000 0.000000 0.000000 scn +9.991263 22.000000 m +11.600367 22.000000 13.104079 21.540958 14.379686 20.742632 c +13.999659 20.330532 13.705750 19.835861 13.527027 19.288073 c +12.501425 19.935305 11.289410 20.308149 9.991263 20.308149 c +6.295337 20.308149 3.312736 17.291861 3.312205 13.540749 c +3.312205 8.567127 l +1.816118 5.077236 l +18.175934 5.077236 l +16.670322 8.566052 l +16.670446 13.526248 l +16.666271 13.780252 l +16.662128 13.902481 16.654818 14.023849 16.644423 14.144276 c +16.834492 14.115398 17.029049 14.100430 17.227058 14.100430 c +17.602913 14.100430 17.966335 14.154360 18.310204 14.254990 c +18.322084 14.112284 18.330519 13.968523 18.335421 13.823792 c +18.340088 13.540749 l +18.340088 8.919773 l +19.876272 5.360107 l +19.953144 5.181980 19.992825 4.989672 19.992825 4.795261 c +19.992825 4.016609 19.369843 3.385387 18.601355 3.385387 c +13.330793 3.383699 l +13.330793 1.514933 11.835634 -0.000002 9.991263 -0.000002 c +8.212763 -0.000002 6.758977 1.408655 6.657403 3.184881 c +6.651230 3.386263 l +1.391824 3.385387 l +1.201094 3.385387 1.012400 3.425116 0.837460 3.502110 c +0.132594 3.812326 -0.190615 4.642769 0.115552 5.356956 c +1.642440 8.918699 l +1.642440 13.540869 l +1.643104 18.227058 5.373904 22.000000 9.991263 22.000000 c +h +11.660524 3.386263 m +8.321499 3.383699 l +8.321499 2.449318 9.069077 1.691849 9.991263 1.691849 c +10.859203 1.691849 11.572474 2.362822 11.653385 3.220762 c +11.660524 3.386263 l +h +14.488358 18.551571 m +14.594155 19.146286 14.884010 19.676186 15.296021 20.078548 c +15.796463 20.567268 16.477119 20.867832 17.227058 20.867832 c +18.764036 20.867832 20.010000 19.605387 20.010000 18.048080 c +20.010000 16.815081 19.228939 15.766922 18.140787 15.383841 c +17.854582 15.283082 17.547131 15.228331 17.227058 15.228331 c +16.950932 15.228331 16.684196 15.269077 16.432392 15.344961 c +15.282606 15.691461 14.444118 16.770555 14.444118 18.048080 c +14.444118 18.219936 14.459294 18.388199 14.488358 18.551571 c +h +f +n +Q + +endstream +endobj + +3 0 obj + 2038 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 28.000000 28.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000002128 00000 n +0000002151 00000 n +0000002324 00000 n +0000002398 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +2457 +%%EOF \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.fill.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.fill.imageset/Contents.json new file mode 100644 index 000000000..eea5ce48f --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.fill.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "bell.fill.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.fill.imageset/bell.fill.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.fill.imageset/bell.fill.pdf new file mode 100644 index 000000000..b738813f8 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.fill.imageset/bell.fill.pdf @@ -0,0 +1,88 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 3.994385 2.997498 cm +0.000000 0.000000 0.000000 scn +13.471207 3.000130 m +13.228097 1.303843 11.769090 0.000013 10.005556 0.000013 c +8.242023 0.000013 6.783014 1.303843 6.539904 3.000130 c +13.471207 3.000130 l +h +10.005556 22.002502 m +14.615297 22.002502 18.368101 18.333513 18.503042 13.756456 c +18.503042 13.501259 l +18.506800 13.501259 l +18.506556 9.389503 l +19.920570 5.745182 l +19.958755 5.646759 19.984545 5.544180 19.997494 5.439810 c +20.007233 5.282207 l +20.007233 4.619465 19.503553 4.074364 18.858105 4.008816 c +18.727232 4.002207 l +1.280344 4.002207 l +1.121637 4.002207 0.964313 4.031721 0.816398 4.089247 c +0.198722 4.329462 -0.126749 4.996468 0.046107 5.621784 c +0.087384 5.746153 l +1.503556 9.390502 l +1.504312 13.501259 l +1.504312 18.196365 5.310449 22.002502 10.005556 22.002502 c +h +f +n +Q + +endstream +endobj + +3 0 obj + 870 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 28.000000 28.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000000960 00000 n +0000000982 00000 n +0000001155 00000 n +0000001229 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +1288 +%%EOF \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.imageset/Contents.json new file mode 100644 index 000000000..da621b2a4 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "bell.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.imageset/bell.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.imageset/bell.pdf new file mode 100644 index 000000000..52a4bea08 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.imageset/bell.pdf @@ -0,0 +1,106 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 3.994385 2.997498 cm +0.000000 0.000000 0.000000 scn +10.005556 22.002502 m +14.615297 22.002502 18.368101 18.333513 18.503042 13.756456 c +18.506800 13.501259 l +18.506556 8.889502 l +19.920570 5.245478 l +19.958755 5.147055 19.984545 5.044476 19.997494 4.940105 c +20.007233 4.782503 l +20.007233 4.119761 19.503553 3.574659 18.858105 3.509111 c +18.727232 3.502502 l +13.506981 3.501438 l +13.506981 1.567654 11.939340 0.000013 10.005556 0.000013 c +8.136232 0.000013 6.609047 1.464890 6.509312 3.309326 c +6.504000 3.503502 l +1.280344 3.502502 l +1.121637 3.502502 0.964313 3.532017 0.816398 3.589542 c +0.198722 3.829758 -0.126749 4.496763 0.046107 5.122080 c +0.087384 5.246449 l +1.503556 8.890503 l +1.504312 13.501259 l +1.504312 18.196365 5.310449 22.002502 10.005556 22.002502 c +h +12.001492 3.352070 m +12.006001 3.503502 l +8.004131 3.501438 l +8.004131 2.396082 8.900200 1.500013 10.005556 1.500013 c +11.060669 1.500013 11.925088 2.316473 12.001492 3.352070 c +h +10.005556 20.502502 m +6.219432 20.502502 3.135237 17.497185 3.008372 13.741951 c +3.004312 13.501259 l +3.004312 8.749136 l +3.004312 8.687140 2.996625 8.625507 2.981514 8.565626 c +2.953312 8.477293 l +1.601556 5.003502 l +18.405556 5.003502 l +17.057579 8.477861 l +17.035206 8.535532 17.020094 8.595635 17.012506 8.656790 c +17.006800 8.749136 l +17.006800 13.501259 l +17.006800 17.367939 13.872236 20.502502 10.005556 20.502502 c +h +f +n +Q + +endstream +endobj + +3 0 obj + 1451 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 28.000000 28.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000001541 00000 n +0000001564 00000 n +0000001737 00000 n +0000001811 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +1870 +%%EOF \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/gear.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/gear.imageset/Contents.json new file mode 100644 index 000000000..8dfa77c79 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/gear.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "gear.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/gear.imageset/gear.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/gear.imageset/gear.pdf new file mode 100644 index 000000000..d0e5607b9 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/gear.imageset/gear.pdf @@ -0,0 +1,155 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 4.639893 4.163849 cm +0.000000 0.000000 0.000000 scn +9.372525 19.586090 m +10.106503 19.577631 10.837610 19.492828 11.554037 19.333052 c +11.866778 19.263306 12.100667 19.002579 12.136167 18.684128 c +12.306372 17.157282 l +12.383412 16.456230 12.975316 15.925249 13.680974 15.924509 c +13.870646 15.924213 14.058271 15.963713 14.233541 16.041258 c +15.634164 16.656530 l +15.925470 16.784498 16.265816 16.714733 16.483282 16.482475 c +17.495462 15.401449 18.249289 14.104940 18.688040 12.690507 c +18.782648 12.385511 18.673761 12.054057 18.416712 11.864587 c +17.175230 10.949497 l +16.821091 10.689301 16.611935 10.276085 16.611935 9.836634 c +16.611935 9.397182 16.821091 8.983968 17.176010 8.723198 c +18.418562 7.807791 l +18.675699 7.618353 18.784660 7.286852 18.690054 6.981801 c +18.251465 5.567602 17.498068 4.271195 16.486473 3.189995 c +16.269207 2.957779 15.929114 2.887827 15.637836 3.015442 c +14.231503 3.631588 l +13.829185 3.807648 13.367112 3.781857 12.986887 3.562117 c +12.606662 3.342377 12.353621 2.954891 12.305302 2.518358 c +12.136227 0.991678 l +12.101363 0.676876 11.872503 0.417910 11.564378 0.344601 c +10.115929 -0.000013 8.606833 -0.000013 7.158383 0.344601 c +6.850258 0.417910 6.621398 0.676876 6.586535 0.991678 c +6.417712 2.516102 l +6.368124 2.951803 6.114693 3.338112 5.734776 3.557108 c +5.354860 3.776103 4.893555 3.801792 4.492552 3.626715 c +3.085926 3.010441 l +2.794572 2.882792 2.454386 2.952816 2.237134 3.185158 c +1.224976 4.267610 0.471545 5.565555 0.033552 6.981297 c +-0.060786 7.286231 0.048213 7.617466 0.305198 7.806790 c +1.548530 8.722771 l +1.902669 8.982967 2.111826 9.396182 2.111826 9.835633 c +2.111826 10.275084 1.902669 10.688300 1.548066 10.948837 c +0.305513 11.863244 l +0.048147 12.052642 -0.060952 12.384308 0.033719 12.689507 c +0.472470 14.103941 1.226297 15.400448 2.238477 16.481474 c +2.455943 16.713732 2.796290 16.783497 3.087596 16.655531 c +4.487972 16.040365 l +4.890913 15.863533 5.354152 15.890244 5.736122 16.113400 c +6.116442 16.334003 6.369638 16.721867 6.418519 17.158447 c +6.588595 18.684128 l +6.624113 19.002741 6.858214 19.263550 7.171155 19.333147 c +7.888429 19.492670 8.620303 19.577436 9.372525 19.586090 c +h +9.372712 18.086191 m +8.918673 18.080845 8.465910 18.041662 8.018175 17.969074 c +7.909245 16.991905 l +7.807416 16.082413 7.280385 15.275068 6.490771 14.817059 c +5.696323 14.352917 4.727715 14.297064 3.884934 14.666923 c +2.986644 15.061529 l +2.414711 14.367364 1.959492 13.584736 1.638873 12.744408 c +2.436671 12.157299 l +3.175481 11.614474 3.611826 10.752420 3.611826 9.835633 c +3.611826 8.918846 3.175481 8.056792 2.437450 7.514541 c +1.638397 6.925866 l +1.958737 6.084057 2.414029 5.299965 2.986352 4.604462 c +3.891485 5.001020 l +4.729578 5.366932 5.691594 5.313361 6.483880 4.856663 c +7.276166 4.399964 7.804679 3.594347 7.908344 2.683468 c +8.017305 1.699598 l +8.906950 1.548321 9.815811 1.548321 10.705456 1.699598 c +10.814412 2.683426 l +10.915205 3.594033 11.443104 4.402411 12.236333 4.860834 c +13.029562 5.319258 13.993543 5.373064 14.833156 5.005638 c +15.737573 4.609392 l +16.309378 5.303812 16.764484 6.086632 17.085032 6.927112 c +16.287088 7.514968 l +15.548278 8.057793 15.111936 8.919847 15.111936 9.836634 c +15.111936 10.753421 15.548280 11.615475 16.286161 12.157617 c +17.083044 12.744996 l +16.762415 13.585482 16.307142 14.368252 15.735116 15.062530 c +14.838643 14.668724 l +14.473309 14.507083 14.078127 14.423886 13.679017 14.424510 c +12.209332 14.426050 10.975889 15.532539 10.815476 16.992264 c +10.706551 17.969393 l +10.261019 18.041893 9.812987 18.080971 9.372712 18.086191 c +h +9.360047 13.586140 m +11.431115 13.586140 13.110047 11.907207 13.110047 9.836140 c +13.110047 7.765072 11.431115 6.086140 9.360047 6.086140 c +7.288980 6.086140 5.610047 7.765072 5.610047 9.836140 c +5.610047 11.907207 7.288980 13.586140 9.360047 13.586140 c +h +9.360047 12.086140 m +8.117407 12.086140 7.110047 11.078780 7.110047 9.836140 c +7.110047 8.593499 8.117407 7.586140 9.360047 7.586140 c +10.602688 7.586140 11.610047 8.593499 11.610047 9.836140 c +11.610047 11.078780 10.602688 12.086140 9.360047 12.086140 c +h +f +n +Q + +endstream +endobj + +3 0 obj + 4141 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 28.000000 28.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000004231 00000 n +0000004254 00000 n +0000004427 00000 n +0000004501 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +4560 +%%EOF \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.fill.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.fill.imageset/Contents.json new file mode 100644 index 000000000..b12998cbd --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.fill.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "Home-fill.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.fill.imageset/Home-fill.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.fill.imageset/Home-fill.pdf new file mode 100644 index 000000000..e8e156e31 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.fill.imageset/Home-fill.pdf @@ -0,0 +1,85 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 4.000000 2.835022 cm +0.000000 0.000000 0.000000 scn +8.592125 21.667089 m +9.414732 22.326954 10.585270 22.326952 11.407875 21.667089 c +19.157869 15.450343 l +19.690231 15.023304 19.999994 14.377716 19.999994 13.695241 c +19.999994 2.414970 l +19.999994 1.172331 18.992638 0.164970 17.749996 0.164970 c +15.250000 0.164970 l +14.007360 0.164970 13.000000 1.172327 13.000000 2.414968 c +13.000000 8.914963 l +13.000000 9.329177 12.664214 9.664963 12.250000 9.664963 c +7.750000 9.664963 l +7.335785 9.664963 7.000000 9.329177 7.000000 8.914964 c +7.000000 2.414970 l +7.000000 1.172331 5.992641 0.164970 4.750000 0.164970 c +2.250000 0.164970 l +1.007360 0.164970 0.000000 1.172327 0.000000 2.414968 c +0.000000 13.695240 l +0.000000 14.377715 0.309763 15.023304 0.842125 15.450343 c +8.592125 21.667089 l +h +f +n +Q + +endstream +endobj + +3 0 obj + 862 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 28.000000 28.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000000952 00000 n +0000000974 00000 n +0000001147 00000 n +0000001221 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +1280 +%%EOF \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.imageset/Contents.json new file mode 100644 index 000000000..968281c21 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "Home.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.imageset/Home.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.imageset/Home.pdf new file mode 100644 index 000000000..1b5772ddd --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.imageset/Home.pdf @@ -0,0 +1,105 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 4.000000 2.834961 cm +0.000000 0.000000 0.000000 scn +8.591907 21.668686 m +9.414594 22.328781 10.585405 22.328781 11.408092 21.668686 c +19.158089 15.450356 l +19.690319 15.023312 19.999994 14.377806 19.999994 13.695429 c +19.999994 2.415045 l +19.999994 1.172405 18.992638 0.165045 17.749996 0.165045 c +14.750000 0.165045 l +13.507360 0.165045 12.500000 1.172403 12.500000 2.415045 c +12.500000 8.415037 l +12.500000 8.829250 12.164213 9.165037 11.750000 9.165037 c +8.250000 9.165037 l +7.835786 9.165037 7.500000 8.829250 7.500000 8.415037 c +7.500000 2.415045 l +7.500000 1.172403 6.492640 0.165045 5.250000 0.165045 c +2.250000 0.165045 l +1.007360 0.165045 0.000000 1.172401 0.000000 2.415043 c +0.000000 13.695428 l +0.000000 14.377805 0.309674 15.023312 0.841907 15.450356 c +8.591907 21.668686 l +h +10.469363 20.498734 m +10.195135 20.718765 9.804865 20.718765 9.530635 20.498734 c +1.780635 14.280403 l +1.603225 14.138056 1.500000 13.922887 1.500000 13.695428 c +1.500000 2.415043 l +1.500000 2.000832 1.835786 1.665045 2.250000 1.665045 c +5.250000 1.665045 l +5.664214 1.665045 6.000000 2.000832 6.000000 2.415045 c +6.000000 8.415037 l +6.000000 9.657678 7.007360 10.665037 8.250000 10.665037 c +11.750000 10.665037 l +12.992640 10.665037 14.000000 9.657678 14.000000 8.415037 c +14.000000 2.415045 l +14.000000 2.000832 14.335787 1.665045 14.750000 1.665045 c +17.749996 1.665045 l +18.164207 1.665045 18.499994 2.000830 18.499994 2.415045 c +18.499994 13.695429 l +18.499994 13.922888 18.396770 14.138056 18.219358 14.280403 c +10.469363 20.498734 l +h +f +n +Q + +endstream +endobj + +3 0 obj + 1604 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 28.000000 28.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000001694 00000 n +0000001717 00000 n +0000001890 00000 n +0000001964 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +2023 +%%EOF \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.fill.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.fill.imageset/Contents.json new file mode 100644 index 000000000..6986c762a --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.fill.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "Search-Fill.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.fill.imageset/Search-Fill.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.fill.imageset/Search-Fill.pdf new file mode 100644 index 000000000..26e5a4576 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.fill.imageset/Search-Fill.pdf @@ -0,0 +1,83 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 2.000000 1.855835 cm +0.000000 0.000000 0.000000 scn +9.500000 24.144165 m +14.746705 24.144165 19.000000 19.890869 19.000000 14.644165 c +19.000000 12.562231 18.330292 10.636717 17.194551 9.071299 c +23.560659 2.704824 l +24.146446 2.119038 24.146446 1.169292 23.560659 0.583506 c +23.011484 0.034330 22.142424 0.000008 21.553263 0.480536 c +21.439341 0.583506 l +15.072866 6.949614 l +13.507448 5.813873 11.581934 5.144165 9.500000 5.144165 c +4.253295 5.144165 0.000000 9.397460 0.000000 14.644165 c +0.000000 19.890869 4.253295 24.144165 9.500000 24.144165 c +h +9.500000 21.144165 m +5.910149 21.144165 3.000000 18.234016 3.000000 14.644165 c +3.000000 11.054314 5.910149 8.144165 9.500000 8.144165 c +13.089851 8.144165 16.000000 11.054314 16.000000 14.644165 c +16.000000 18.234016 13.089851 21.144165 9.500000 21.144165 c +h +f +n +Q + +endstream +endobj + +3 0 obj + 887 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 28.000000 28.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000000977 00000 n +0000000999 00000 n +0000001172 00000 n +0000001246 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +1305 +%%EOF \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.imageset/Contents.json new file mode 100644 index 000000000..e4ab2267b --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "Search.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.imageset/Search.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.imageset/Search.pdf new file mode 100644 index 000000000..7bd1758c7 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.imageset/Search.pdf @@ -0,0 +1,83 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 2.750000 2.679199 cm +0.000000 0.000000 0.000000 scn +8.750000 22.570801 m +13.582491 22.570801 17.500000 18.653292 17.500000 13.820801 c +17.500000 11.674633 16.727327 9.708933 15.444990 8.186705 c +22.280331 1.351131 l +22.573223 1.058239 22.573223 0.583363 22.280331 0.290470 c +22.014065 0.024204 21.597401 -0.000004 21.303789 0.217852 c +21.219669 0.290470 l +14.384096 7.125811 l +12.861868 5.843473 10.896168 5.070801 8.750000 5.070801 c +3.917509 5.070801 0.000000 8.988310 0.000000 13.820801 c +0.000000 18.653292 3.917509 22.570801 8.750000 22.570801 c +h +8.750000 21.070801 m +4.745935 21.070801 1.500000 17.824865 1.500000 13.820801 c +1.500000 9.816736 4.745935 6.570801 8.750000 6.570801 c +12.754065 6.570801 16.000000 9.816736 16.000000 13.820801 c +16.000000 17.824865 12.754065 21.070801 8.750000 21.070801 c +h +f +n +Q + +endstream +endobj + +3 0 obj + 885 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 28.000000 28.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000000975 00000 n +0000000997 00000 n +0000001170 00000 n +0000001244 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +1303 +%%EOF \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/square.and.pencil.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/square.and.pencil.imageset/Contents.json new file mode 100644 index 000000000..18bb2201a --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/square.and.pencil.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "square.and.pencil.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/square.and.pencil.imageset/square.and.pencil.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/square.and.pencil.imageset/square.and.pencil.pdf new file mode 100644 index 000000000..8cb4a15c9 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/square.and.pencil.imageset/square.and.pencil.pdf @@ -0,0 +1,93 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 3.000000 2.926788 cm +0.000000 0.000000 0.000000 scn +18.780287 17.792883 m +19.073179 18.085777 19.073177 18.560650 18.780285 18.853542 c +18.487391 19.146435 18.012516 19.146435 17.719624 18.853540 c +7.719669 8.853540 l +7.250000 7.323212 l +8.780332 7.792883 l +18.780287 17.792883 l +h +3.249999 18.073212 m +1.455072 18.073212 0.000000 16.618137 0.000000 14.823212 c +0.000000 3.323212 l +0.000000 1.528286 1.455075 0.073212 3.250000 0.073212 c +14.750000 0.073212 l +16.544926 0.073212 18.000000 1.528286 18.000000 3.323212 c +18.000000 11.323212 l +18.000000 11.737425 17.664213 12.073212 17.250000 12.073212 c +16.835787 12.073212 16.500000 11.737425 16.500000 11.323212 c +16.500000 3.323212 l +16.500000 2.356712 15.716498 1.573212 14.750000 1.573212 c +3.250000 1.573212 l +2.283502 1.573212 1.500000 2.356712 1.500000 3.323212 c +1.500000 14.823212 l +1.500000 15.789711 2.283501 16.573212 3.249999 16.573212 c +11.249994 16.573212 l +11.664207 16.573212 11.999994 16.908998 11.999994 17.323212 c +11.999994 17.737425 11.664207 18.073212 11.249994 18.073212 c +3.249999 18.073212 l +h +f +n +Q + +endstream +endobj + +3 0 obj + 1142 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 24.000000 24.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000001232 00000 n +0000001255 00000 n +0000001428 00000 n +0000001502 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +1561 +%%EOF \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift b/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift index 3e7fa5c11..cf103a2f8 100644 --- a/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift +++ b/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift @@ -99,6 +99,16 @@ public enum Asset { public static let faceSmilingAdaptive = ImageAsset(name: "Human/face.smiling.adaptive") } public enum ObjectsAndTools { + public static let bellBadgeFill = ImageAsset(name: "ObjectsAndTools/bell.badge.fill") + public static let bellBadge = ImageAsset(name: "ObjectsAndTools/bell.badge") + public static let bellFill = ImageAsset(name: "ObjectsAndTools/bell.fill") + public static let bell = ImageAsset(name: "ObjectsAndTools/bell") + public static let gear = ImageAsset(name: "ObjectsAndTools/gear") + public static let houseFill = ImageAsset(name: "ObjectsAndTools/house.fill") + public static let house = ImageAsset(name: "ObjectsAndTools/house") + public static let magnifyingglassFill = ImageAsset(name: "ObjectsAndTools/magnifyingglass.fill") + public static let magnifyingglass = ImageAsset(name: "ObjectsAndTools/magnifyingglass") + public static let squareAndPencil = ImageAsset(name: "ObjectsAndTools/square.and.pencil") public static let starFill = ImageAsset(name: "ObjectsAndTools/star.fill") public static let star = ImageAsset(name: "ObjectsAndTools/star") } diff --git a/MastodonSDK/Sources/MastodonUI/Extension/UIImage.swift b/MastodonSDK/Sources/MastodonUI/Extension/UIImage.swift new file mode 100644 index 000000000..105b4c27d --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/Extension/UIImage.swift @@ -0,0 +1,17 @@ +// +// UIImage.swift +// +// +// Created by MainasuK on 2022-5-6. +// + +import UIKit + +extension UIImage { + + public func resized(size: CGSize) -> UIImage { + return UIGraphicsImageRenderer(size: size).image { context in + self.draw(in: CGRect(origin: .zero, size: size)) + } + } +} From 096ae1ad19b5d050364edcaf96075437ba6a1e5c Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 6 May 2022 14:30:28 +0800 Subject: [PATCH 064/101] chore: update version to 1.4.1 (122) --- AppShared/Info.plist | 4 +-- Mastodon.xcodeproj/project.pbxproj | 36 +++++++++---------- .../xcschemes/xcschememanagement.plist | 6 ++-- Mastodon/Info.plist | 4 +-- MastodonIntent/Info.plist | 4 +-- MastodonTests/Info.plist | 4 +-- MastodonUITests/Info.plist | 4 +-- NotificationService/Info.plist | 4 +-- ShareActionExtension/Info.plist | 4 +-- 9 files changed, 35 insertions(+), 35 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index a1528e2c5..4078f08d8 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.4.0 + 1.4.1 CFBundleVersion - 121 + 122 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index fcba16b23..1da8f4d4e 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4711,7 +4711,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 121; + CURRENT_PROJECT_VERSION = 122; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4741,7 +4741,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 121; + CURRENT_PROJECT_VERSION = 122; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4849,11 +4849,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 121; + CURRENT_PROJECT_VERSION = 122; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 121; + DYLIB_CURRENT_VERSION = 122; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4880,11 +4880,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 121; + CURRENT_PROJECT_VERSION = 122; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 121; + DYLIB_CURRENT_VERSION = 122; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4908,7 +4908,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 121; + CURRENT_PROJECT_VERSION = 122; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4932,7 +4932,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 121; + CURRENT_PROJECT_VERSION = 122; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4956,7 +4956,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 121; + CURRENT_PROJECT_VERSION = 122; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4980,7 +4980,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 121; + CURRENT_PROJECT_VERSION = 122; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5067,7 +5067,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 121; + CURRENT_PROJECT_VERSION = 122; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5134,11 +5134,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 121; + CURRENT_PROJECT_VERSION = 122; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 121; + DYLIB_CURRENT_VERSION = 122; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5162,7 +5162,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 121; + CURRENT_PROJECT_VERSION = 122; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5185,7 +5185,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 121; + CURRENT_PROJECT_VERSION = 122; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5209,7 +5209,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 121; + CURRENT_PROJECT_VERSION = 122; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5233,7 +5233,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 121; + CURRENT_PROJECT_VERSION = 122; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5256,7 +5256,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 121; + CURRENT_PROJECT_VERSION = 122; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 1ac4532e7..8e1d661f5 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 19 + 31 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 21 + 29 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 20 + 30 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 6dec562da..1c08032c5 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -30,7 +30,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.4.0 + 1.4.1 CFBundleURLTypes @@ -43,7 +43,7 @@ CFBundleVersion - 121 + 122 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index d08d9c217..caf9a9e8c 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.4.0 + 1.4.1 CFBundleVersion - 121 + 122 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index a1528e2c5..4078f08d8 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.4.0 + 1.4.1 CFBundleVersion - 121 + 122 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index a1528e2c5..4078f08d8 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.4.0 + 1.4.1 CFBundleVersion - 121 + 122 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index 0029eea56..c030e8650 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.4.0 + 1.4.1 CFBundleVersion - 121 + 122 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 25fc34294..be4eded9a 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.4.0 + 1.4.1 CFBundleVersion - 121 + 122 NSExtension NSExtensionAttributes From 8d78f6586d0972249a3ab6d28d462070d017bbf8 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 6 May 2022 14:47:15 +0800 Subject: [PATCH 065/101] chore: fix accessibility large content label text missing issue --- .../Scene/Root/MainTab/MainTabBarController.swift | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift index d6eea39da..b91435a56 100644 --- a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift +++ b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift @@ -174,11 +174,12 @@ extension MainTabBarController { } .store(in: &disposeBag) + // seealso: `ThemeService.apply(theme:)` let tabs = Tab.allCases let viewControllers: [UIViewController] = tabs.map { tab in let viewController = tab.viewController(context: context, coordinator: coordinator) viewController.tabBarItem.tag = tab.tag - viewController.tabBarItem.title = nil + viewController.tabBarItem.title = tab.title // needs for acessiblity large content label viewController.tabBarItem.image = tab.image.imageWithoutBaseline() viewController.tabBarItem.selectedImage = tab.selectedImage.imageWithoutBaseline() viewController.tabBarItem.largeContentSizeImage = tab.largeImage.imageWithoutBaseline() @@ -197,14 +198,6 @@ extension MainTabBarController { _viewControllers = viewControllers setViewControllers(viewControllers, animated: false) selectedIndex = 0 - - let tabBarItemAppearance = UITabBarItemAppearance() - tabBarItemAppearance.configureWithDefault(for: .stacked) - tabBarItemAppearance.normal.iconColor = Asset.Colors.Label.primary.color - tabBar.standardAppearance.stackedItemPositioning = .centered - tabBar.standardAppearance.stackedLayoutAppearance = tabBarItemAppearance - tabBar.standardAppearance.inlineLayoutAppearance = tabBarItemAppearance - tabBar.standardAppearance.compactInlineLayoutAppearance = tabBarItemAppearance context.apiService.error .receive(on: DispatchQueue.main) From c8e80139015b3cd56d1b9625e6d5d8cfe37c9823 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 6 May 2022 14:47:49 +0800 Subject: [PATCH 066/101] chore: update version to 1.4.1 (123) --- AppShared/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 36 +++++++++---------- .../xcschemes/xcschememanagement.plist | 6 ++-- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 9 files changed, 28 insertions(+), 28 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 4078f08d8..0b876b035 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.4.1 CFBundleVersion - 122 + 123 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 1da8f4d4e..ca9400a6f 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4711,7 +4711,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 122; + CURRENT_PROJECT_VERSION = 123; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4741,7 +4741,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 122; + CURRENT_PROJECT_VERSION = 123; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4849,11 +4849,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 122; + CURRENT_PROJECT_VERSION = 123; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 122; + DYLIB_CURRENT_VERSION = 123; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4880,11 +4880,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 122; + CURRENT_PROJECT_VERSION = 123; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 122; + DYLIB_CURRENT_VERSION = 123; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4908,7 +4908,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 122; + CURRENT_PROJECT_VERSION = 123; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4932,7 +4932,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 122; + CURRENT_PROJECT_VERSION = 123; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4956,7 +4956,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 122; + CURRENT_PROJECT_VERSION = 123; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4980,7 +4980,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 122; + CURRENT_PROJECT_VERSION = 123; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5067,7 +5067,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 122; + CURRENT_PROJECT_VERSION = 123; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5134,11 +5134,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 122; + CURRENT_PROJECT_VERSION = 123; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 122; + DYLIB_CURRENT_VERSION = 123; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5162,7 +5162,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 122; + CURRENT_PROJECT_VERSION = 123; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5185,7 +5185,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 122; + CURRENT_PROJECT_VERSION = 123; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5209,7 +5209,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 122; + CURRENT_PROJECT_VERSION = 123; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5233,7 +5233,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 122; + CURRENT_PROJECT_VERSION = 123; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5256,7 +5256,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 122; + CURRENT_PROJECT_VERSION = 123; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 8e1d661f5..b4eb63998 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 31 + 33 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 29 + 32 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 30 + 34 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 1c08032c5..2eac130fd 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -43,7 +43,7 @@ CFBundleVersion - 122 + 123 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index caf9a9e8c..79b876e51 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.4.1 CFBundleVersion - 122 + 123 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 4078f08d8..0b876b035 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.4.1 CFBundleVersion - 122 + 123 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 4078f08d8..0b876b035 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.4.1 CFBundleVersion - 122 + 123 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index c030e8650..43a11fa79 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.4.1 CFBundleVersion - 122 + 123 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index be4eded9a..e8dc0cb3a 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.4.1 CFBundleVersion - 122 + 123 NSExtension NSExtensionAttributes From ca0a697cd085e5e280d1a0e137d85c496d0f1443 Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 6 May 2022 15:17:26 +0800 Subject: [PATCH 067/101] chore: update navigation bar button item assets --- .../HashtagTimelineViewController.swift | 2 +- .../HomeTimelineViewController.swift | 37 +----- .../HomeTimeline/HomeTimelineViewModel.swift | 1 - .../Scene/Profile/ProfileViewController.swift | 21 +++- .../Root/ContentSplitViewController.swift | 1 - .../Contents.json | 15 +++ .../Share iOS.pdf | 110 ++++++++++++++++++ .../MastodonAsset/Generated/Assets.swift | 1 + 8 files changed, 149 insertions(+), 39 deletions(-) create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Arrow/square.and.arrow.up.imageset/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Arrow/square.and.arrow.up.imageset/Share iOS.pdf diff --git a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift index b3a8ca040..3b8db5d56 100644 --- a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift +++ b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift @@ -28,7 +28,7 @@ final class HashtagTimelineViewController: UIViewController, NeedsDependency, Me let composeBarButtonItem: UIBarButtonItem = { let barButtonItem = UIBarButtonItem() - barButtonItem.image = UIImage(systemName: "square.and.pencil")?.withRenderingMode(.alwaysTemplate) + barButtonItem.image = Asset.ObjectsAndTools.squareAndPencil.image.withRenderingMode(.alwaysTemplate) return barButtonItem }() diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift index 549552725..64d3d5941 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift @@ -51,19 +51,11 @@ final class HomeTimelineViewController: UIViewController, NeedsDependency, Media let settingBarButtonItem: UIBarButtonItem = { let barButtonItem = UIBarButtonItem() barButtonItem.tintColor = ThemeService.tintColor - barButtonItem.image = UIImage(systemName: "gear")?.withRenderingMode(.alwaysTemplate) + barButtonItem.image = Asset.ObjectsAndTools.gear.image.withRenderingMode(.alwaysTemplate) barButtonItem.accessibilityLabel = L10n.Common.Controls.Actions.settings return barButtonItem }() - let composeBarButtonItem: UIBarButtonItem = { - let barButtonItem = UIBarButtonItem() - barButtonItem.tintColor = ThemeService.tintColor - barButtonItem.image = UIImage(systemName: "square.and.pencil")?.withRenderingMode(.alwaysTemplate) - barButtonItem.accessibilityLabel = L10n.Common.Controls.Actions.compose - return barButtonItem - }() - let tableView: UITableView = { let tableView = ControlContainableTableView() tableView.register(StatusTableViewCell.self, forCellReuseIdentifier: String(describing: StatusTableViewCell.self)) @@ -109,14 +101,14 @@ extension HomeTimelineViewController { guard let self = self else { return } #if DEBUG // display debug menu - self.navigationItem.leftBarButtonItem = { + self.navigationItem.rightBarButtonItem = { let barButtonItem = UIBarButtonItem() barButtonItem.image = UIImage(systemName: "ellipsis.circle") barButtonItem.menu = self.debugMenu return barButtonItem }() #else - self.navigationItem.leftBarButtonItem = displaySettingBarButtonItem ? self.settingBarButtonItem : nil + self.navigationItem.rightBarButtonItem = displaySettingBarButtonItem ? self.settingBarButtonItem : nil #endif } .store(in: &disposeBag) @@ -133,16 +125,6 @@ extension HomeTimelineViewController { titleView.button.menu = self.debugMenu #endif - viewModel.$displayComposeBarButtonItem - .receive(on: DispatchQueue.main) - .sink { [weak self] displayComposeBarButtonItem in - guard let self = self else { return } - self.navigationItem.rightBarButtonItem = displayComposeBarButtonItem ? self.composeBarButtonItem : nil - } - .store(in: &disposeBag) - composeBarButtonItem.target = self - composeBarButtonItem.action = #selector(HomeTimelineViewController.composeBarButtonItemPressed(_:)) - navigationItem.titleView = titleView titleView.delegate = self @@ -411,18 +393,7 @@ extension HomeTimelineViewController { let settingsViewModel = SettingsViewModel(context: context, setting: setting) coordinator.present(scene: .settings(viewModel: settingsViewModel), from: self, transition: .modal(animated: true, completion: nil)) } - - @objc private func composeBarButtonItemPressed(_ sender: UIBarButtonItem) { - os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) - guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return } - let composeViewModel = ComposeViewModel( - context: context, - composeKind: .post, - authenticationBox: authenticationBox - ) - coordinator.present(scene: .compose(viewModel: composeViewModel), from: self, transition: .modal(animated: true, completion: nil)) - } - + @objc private func refreshControlValueChanged(_ sender: UIRefreshControl) { guard viewModel.loadLatestStateMachine.enter(HomeTimelineViewModel.LoadLatestState.Loading.self) else { sender.endRefreshing() diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift index b2c280fb5..be7de3a5a 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift @@ -33,7 +33,6 @@ final class HomeTimelineViewModel: NSObject { @Published var lastAutomaticFetchTimestamp: Date? = nil @Published var scrollPositionRecord: ScrollPositionRecord? = nil @Published var displaySettingBarButtonItem = true - @Published var displayComposeBarButtonItem = true weak var tableView: UITableView? weak var timelineMiddleLoaderTableViewCellDelegate: TimelineMiddleLoaderTableViewCellDelegate? diff --git a/Mastodon/Scene/Profile/ProfileViewController.swift b/Mastodon/Scene/Profile/ProfileViewController.swift index 55a952b0e..d3de07cff 100644 --- a/Mastodon/Scene/Profile/ProfileViewController.swift +++ b/Mastodon/Scene/Profile/ProfileViewController.swift @@ -42,19 +42,34 @@ final class ProfileViewController: UIViewController, NeedsDependency, MediaPrevi }() private(set) lazy var settingBarButtonItem: UIBarButtonItem = { - let barButtonItem = UIBarButtonItem(image: UIImage(systemName: "gear"), style: .plain, target: self, action: #selector(ProfileViewController.settingBarButtonItemPressed(_:))) + let barButtonItem = UIBarButtonItem( + image: Asset.ObjectsAndTools.gear.image.withRenderingMode(.alwaysTemplate), + style: .plain, + target: self, + action: #selector(ProfileViewController.settingBarButtonItemPressed(_:)) + ) barButtonItem.tintColor = .white return barButtonItem }() private(set) lazy var shareBarButtonItem: UIBarButtonItem = { - let barButtonItem = UIBarButtonItem(image: UIImage(systemName: "square.and.arrow.up"), style: .plain, target: self, action: #selector(ProfileViewController.shareBarButtonItemPressed(_:))) + let barButtonItem = UIBarButtonItem( + image: Asset.Arrow.squareAndArrowUp.image.withRenderingMode(.alwaysTemplate), + style: .plain, + target: self, + action: #selector(ProfileViewController.shareBarButtonItemPressed(_:)) + ) barButtonItem.tintColor = .white return barButtonItem }() private(set) lazy var favoriteBarButtonItem: UIBarButtonItem = { - let barButtonItem = UIBarButtonItem(image: UIImage(systemName: "star"), style: .plain, target: self, action: #selector(ProfileViewController.favoriteBarButtonItemPressed(_:))) + let barButtonItem = UIBarButtonItem( + image: Asset.ObjectsAndTools.star.image.withRenderingMode(.alwaysTemplate), + style: .plain, + target: self, + action: #selector(ProfileViewController.favoriteBarButtonItemPressed(_:)) + ) barButtonItem.tintColor = .white return barButtonItem }() diff --git a/Mastodon/Scene/Root/ContentSplitViewController.swift b/Mastodon/Scene/Root/ContentSplitViewController.swift index e3a6952f8..03e203107 100644 --- a/Mastodon/Scene/Root/ContentSplitViewController.swift +++ b/Mastodon/Scene/Root/ContentSplitViewController.swift @@ -38,7 +38,6 @@ final class ContentSplitViewController: UIViewController, NeedsDependency { private(set) lazy var mainTabBarController: MainTabBarController = { let mainTabBarController = MainTabBarController(context: context, coordinator: coordinator) if let homeTimelineViewController = mainTabBarController.viewController(of: HomeTimelineViewController.self) { - homeTimelineViewController.viewModel.displayComposeBarButtonItem = false homeTimelineViewController.viewModel.displaySettingBarButtonItem = false } return mainTabBarController diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Arrow/square.and.arrow.up.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Arrow/square.and.arrow.up.imageset/Contents.json new file mode 100644 index 000000000..33c521feb --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Arrow/square.and.arrow.up.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "Share iOS.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Arrow/square.and.arrow.up.imageset/Share iOS.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Arrow/square.and.arrow.up.imageset/Share iOS.pdf new file mode 100644 index 000000000..99e7c6724 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Arrow/square.and.arrow.up.imageset/Share iOS.pdf @@ -0,0 +1,110 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 5.004150 3.928345 cm +0.000000 0.000000 0.000000 scn +16.750000 11.071655 m +17.129696 11.071655 17.443491 10.789501 17.493153 10.423426 c +17.500000 10.321655 l +17.500000 3.320786 l +17.500000 1.587753 16.143545 0.171539 14.434423 0.075930 c +14.250000 0.070786 l +3.250000 0.070786 l +1.516969 0.070786 0.100754 1.427240 0.005145 3.136362 c +0.000000 3.320786 l +0.000000 10.321655 l +0.000000 10.735868 0.335786 11.071655 0.750000 11.071655 c +1.129696 11.071655 1.443491 10.789501 1.493153 10.423426 c +1.500000 10.321655 l +1.500000 3.320786 l +1.500000 2.402613 2.207110 1.649591 3.106473 1.576586 c +3.250000 1.570786 l +14.250000 1.570786 l +15.168174 1.570786 15.921191 2.277895 15.994198 3.177258 c +16.000000 3.320786 l +16.000000 10.321655 l +16.000000 10.735868 16.335787 11.071655 16.750000 11.071655 c +h +3.215397 14.855352 m +8.211636 19.851965 l +8.477744 20.118093 8.894129 20.142456 9.187749 19.924934 c +9.271878 19.852423 l +14.276731 14.855809 l +14.569866 14.563158 14.570257 14.088284 14.277605 13.795150 c +14.011558 13.528664 13.594913 13.504115 13.301123 13.721727 c +13.216944 13.794276 l +9.493999 17.510654 l +9.494885 5.816710 l +9.494885 5.437014 9.212732 5.123218 8.846657 5.073555 c +8.744885 5.066710 l +8.365190 5.066710 8.051395 5.348864 8.001733 5.714939 c +7.994885 5.816710 l +7.993999 17.513655 l +4.276096 13.794732 l +4.009840 13.528456 3.593178 13.504234 3.299558 13.722077 c +3.215437 13.794693 l +2.949160 14.060949 2.924938 14.477612 3.142782 14.771232 c +3.215397 14.855352 l +8.211636 19.851965 l +3.215397 14.855352 l +h +f +n +Q + +endstream +endobj + +3 0 obj + 1600 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 28.000000 28.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000001690 00000 n +0000001713 00000 n +0000001886 00000 n +0000001960 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +2019 +%%EOF \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift b/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift index cf103a2f8..b594f9209 100644 --- a/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift +++ b/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift @@ -24,6 +24,7 @@ public enum Asset { public enum Arrow { public static let `repeat` = ImageAsset(name: "Arrow/repeat") public static let repeatSmall = ImageAsset(name: "Arrow/repeat.small") + public static let squareAndArrowUp = ImageAsset(name: "Arrow/square.and.arrow.up") } public enum Asset { public static let email = ImageAsset(name: "Asset/email") From bbb46e62fda1c6d60706d3b8f45d1944f4a2f6fa Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 6 May 2022 15:17:46 +0800 Subject: [PATCH 068/101] fix: compose tabBar button layout raise crash on iPad issue --- Mastodon/Scene/Root/MainTab/MainTabBarController.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift index b91435a56..8970e2f29 100644 --- a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift +++ b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift @@ -406,8 +406,10 @@ extension MainTabBarController { switch traitCollection.horizontalSizeClass { case .compact: tabBar.isHidden = false + composeButttonShadowBackgroundContainer.isHidden = false default: tabBar.isHidden = true + composeButttonShadowBackgroundContainer.isHidden = true } } @@ -428,7 +430,7 @@ extension MainTabBarController { anchorImageView.alpha = 0 composeButttonShadowBackgroundContainer.translatesAutoresizingMaskIntoConstraints = false - tabBar.addSubview(composeButttonShadowBackgroundContainer) + self.view.addSubview(composeButttonShadowBackgroundContainer) // add to tabBar will crash on iPad when size class changing NSLayoutConstraint.activate([ composeButttonShadowBackgroundContainer.centerXAnchor.constraint(equalTo: anchorImageView.centerXAnchor), composeButttonShadowBackgroundContainer.centerYAnchor.constraint(equalTo: anchorImageView.centerYAnchor), From 9054b4eae3cd010c81d44b57323a143e065646bf Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 6 May 2022 15:18:16 +0800 Subject: [PATCH 069/101] chore: update version to 1.4.1 (124) --- AppShared/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 36 +++++++++---------- .../xcschemes/xcschememanagement.plist | 6 ++-- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 9 files changed, 28 insertions(+), 28 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 0b876b035..1abe4cbf3 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.4.1 CFBundleVersion - 123 + 124 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index ca9400a6f..7ddc27ac5 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4711,7 +4711,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 123; + CURRENT_PROJECT_VERSION = 124; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4741,7 +4741,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 123; + CURRENT_PROJECT_VERSION = 124; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4849,11 +4849,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 123; + CURRENT_PROJECT_VERSION = 124; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 123; + DYLIB_CURRENT_VERSION = 124; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4880,11 +4880,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 123; + CURRENT_PROJECT_VERSION = 124; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 123; + DYLIB_CURRENT_VERSION = 124; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4908,7 +4908,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 123; + CURRENT_PROJECT_VERSION = 124; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4932,7 +4932,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 123; + CURRENT_PROJECT_VERSION = 124; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4956,7 +4956,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 123; + CURRENT_PROJECT_VERSION = 124; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4980,7 +4980,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 123; + CURRENT_PROJECT_VERSION = 124; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5067,7 +5067,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 123; + CURRENT_PROJECT_VERSION = 124; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5134,11 +5134,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 123; + CURRENT_PROJECT_VERSION = 124; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 123; + DYLIB_CURRENT_VERSION = 124; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5162,7 +5162,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 123; + CURRENT_PROJECT_VERSION = 124; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5185,7 +5185,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 123; + CURRENT_PROJECT_VERSION = 124; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5209,7 +5209,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 123; + CURRENT_PROJECT_VERSION = 124; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5233,7 +5233,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 123; + CURRENT_PROJECT_VERSION = 124; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5256,7 +5256,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 123; + CURRENT_PROJECT_VERSION = 124; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index b4eb63998..8853baadf 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 33 + 35 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 32 + 36 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 34 + 37 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 2eac130fd..07308a8ee 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -43,7 +43,7 @@ CFBundleVersion - 123 + 124 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 79b876e51..a1adcf83b 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.4.1 CFBundleVersion - 123 + 124 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 0b876b035..1abe4cbf3 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.4.1 CFBundleVersion - 123 + 124 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 0b876b035..1abe4cbf3 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.4.1 CFBundleVersion - 123 + 124 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index 43a11fa79..bb670f1db 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.4.1 CFBundleVersion - 123 + 124 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index e8dc0cb3a..57436f4d9 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.4.1 CFBundleVersion - 123 + 124 NSExtension NSExtensionAttributes From 8aa8825269993fdca4eef5a05bdebbbcd08fb85c Mon Sep 17 00:00:00 2001 From: CMK Date: Sat, 7 May 2022 11:42:10 +0800 Subject: [PATCH 070/101] chore: suppress warnings --- Mastodon.xcodeproj/project.pbxproj | 4 ---- .../xcschemes/xcschememanagement.plist | 6 +++--- Mastodon/Coordinator/SceneCoordinator.swift | 2 +- .../Onboarding/PickServerSection.swift | 2 +- .../Diffiable/Settings/SettingsSection.swift | 2 +- .../MastodonSDK/Mastodon+Entity+Tag.swift | 19 +++++++++---------- .../Extension/UINavigationController.swift | 16 ---------------- .../DataSourceFacade+SearchHistory.swift | 2 +- ...er+NotificationTableViewCellDelegate.swift | 2 +- ...Provider+StatusTableViewCellDelegate.swift | 2 +- ...ider+TableViewControllerNavigateable.swift | 2 +- ...taSourceProvider+UITableViewDelegate.swift | 2 +- .../Scene/Account/AccountViewController.swift | 2 +- .../AutoCompleteViewModel+State.swift | 2 +- .../News/DiscoveryNewsViewModel+State.swift | 2 +- ...meTimelineViewController+DebugAction.swift | 2 +- .../Scene/Profile/ProfileViewController.swift | 4 ++-- .../Root/Sidebar/SidebarViewController.swift | 5 ++--- .../Settings/SettingsViewController.swift | 2 +- ...wViewControllerAnimatedTransitioning.swift | 2 ++ .../APIService/APIService+Thread.swift | 2 +- Mastodon/Service/InstanceService.swift | 2 +- .../MastodonUI/Extension/UIImage.swift | 1 + 23 files changed, 34 insertions(+), 53 deletions(-) delete mode 100644 Mastodon/Extension/UINavigationController.swift diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 7ddc27ac5..0f49a3f4e 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -537,7 +537,6 @@ DBCBED1726132DB500B49291 /* UserTimelineViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBCBED1626132DB500B49291 /* UserTimelineViewModel+Diffable.swift */; }; DBCBED1D26132E1A00B49291 /* StatusFetchedResultsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBCBED1C26132E1A00B49291 /* StatusFetchedResultsController.swift */; }; DBCC3B30261440A50045B23D /* UITabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBCC3B2F261440A50045B23D /* UITabBarController.swift */; }; - DBCC3B36261440BA0045B23D /* UINavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBCC3B35261440BA0045B23D /* UINavigationController.swift */; }; DBCC3B8F26148F7B0045B23D /* CachedProfileViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBCC3B8E26148F7B0045B23D /* CachedProfileViewModel.swift */; }; DBCC3B9526157E6E0045B23D /* APIService+Relationship.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBCC3B9426157E6E0045B23D /* APIService+Relationship.swift */; }; DBCCC71E25F73297007E1AB6 /* APIService+Reblog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBCCC71D25F73297007E1AB6 /* APIService+Reblog.swift */; }; @@ -1302,7 +1301,6 @@ DBCBED1626132DB500B49291 /* UserTimelineViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserTimelineViewModel+Diffable.swift"; sourceTree = ""; }; DBCBED1C26132E1A00B49291 /* StatusFetchedResultsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusFetchedResultsController.swift; sourceTree = ""; }; DBCC3B2F261440A50045B23D /* UITabBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITabBarController.swift; sourceTree = ""; }; - DBCC3B35261440BA0045B23D /* UINavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UINavigationController.swift; sourceTree = ""; }; DBCC3B8E26148F7B0045B23D /* CachedProfileViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CachedProfileViewModel.swift; sourceTree = ""; }; DBCC3B9426157E6E0045B23D /* APIService+Relationship.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Relationship.swift"; sourceTree = ""; }; DBCCC71D25F73297007E1AB6 /* APIService+Reblog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Reblog.swift"; sourceTree = ""; }; @@ -2792,7 +2790,6 @@ 2D84350425FF858100EECE90 /* UIScrollView.swift */, DB9E0D6E25EE008500CFDD76 /* UIInterpolatingMotionEffect.swift */, DBCC3B2F261440A50045B23D /* UITabBarController.swift */, - DBCC3B35261440BA0045B23D /* UINavigationController.swift */, DB73BF4827140BA300781945 /* UICollectionViewDiffableDataSource.swift */, DB73BF4A27140C0800781945 /* UITableViewDiffableDataSource.swift */, ); @@ -4029,7 +4026,6 @@ DB9D7C21269824B80054B3DF /* APIService+Filter.swift in Sources */, 2D38F1E525CD46C100561493 /* HomeTimelineViewModel.swift in Sources */, DB0FCB842796B2A2006C02E2 /* FavoriteViewController+DataSourceProvider.swift in Sources */, - DBCC3B36261440BA0045B23D /* UINavigationController.swift in Sources */, DB0FCB68279507EF006C02E2 /* DataSourceFacade+Meta.swift in Sources */, DB63F75C279956D000455B82 /* Persistence+Tag.swift in Sources */, 2D84350525FF858100EECE90 /* UIScrollView.swift in Sources */, diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 8853baadf..7f54b9011 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 35 + 20 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 36 + 19 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 37 + 21 SuppressBuildableAutocreation diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index 819872c70..5e7fbf472 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -309,7 +309,7 @@ extension SceneCoordinator { if scene.isOnboarding { return OnboardingNavigationController(rootViewController: viewController) } else { - return UINavigationController(rootViewController: viewController) + return AdaptiveStatusBarStyleNavigationController(rootViewController: viewController) } }() modalNavigationController.modalPresentationCapturesStatusBarAppearance = true diff --git a/Mastodon/Diffiable/Onboarding/PickServerSection.swift b/Mastodon/Diffiable/Onboarding/PickServerSection.swift index 5faaefbcc..01a31f6f6 100644 --- a/Mastodon/Diffiable/Onboarding/PickServerSection.swift +++ b/Mastodon/Diffiable/Onboarding/PickServerSection.swift @@ -29,7 +29,7 @@ extension PickServerSection { weak dependency, weak pickServerCellDelegate ] tableView, indexPath, item -> UITableViewCell? in - guard let dependency = dependency else { return nil } + guard let _ = dependency else { return nil } switch item { case .header: let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: OnboardingHeadlineTableViewCell.self), for: indexPath) as! OnboardingHeadlineTableViewCell diff --git a/Mastodon/Diffiable/Settings/SettingsSection.swift b/Mastodon/Diffiable/Settings/SettingsSection.swift index adc7140be..6925303d8 100644 --- a/Mastodon/Diffiable/Settings/SettingsSection.swift +++ b/Mastodon/Diffiable/Settings/SettingsSection.swift @@ -51,7 +51,7 @@ extension SettingsSection { } cell.delegate = settingsAppearanceTableViewCellDelegate return cell - case .appearancePreference(let record, let appearanceType): + case .appearancePreference(let record, _): let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SettingsToggleTableViewCell.self), for: indexPath) as! SettingsToggleTableViewCell cell.delegate = settingsToggleCellDelegate managedObjectContext.performAndWait { diff --git a/Mastodon/Extension/MastodonSDK/Mastodon+Entity+Tag.swift b/Mastodon/Extension/MastodonSDK/Mastodon+Entity+Tag.swift index e217d3a82..6251d1814 100644 --- a/Mastodon/Extension/MastodonSDK/Mastodon+Entity+Tag.swift +++ b/Mastodon/Extension/MastodonSDK/Mastodon+Entity+Tag.swift @@ -7,13 +7,12 @@ import MastodonSDK -extension Mastodon.Entity.Tag: Hashable { - public func hash(into hasher: inout Hasher) { - hasher.combine(name) - } - - public static func == (lhs: Mastodon.Entity.Tag, rhs: Mastodon.Entity.Tag) -> Bool { - return lhs.name == rhs.name - } -} - +//extension Mastodon.Entity.Tag: Hashable { +// public func hash(into hasher: inout Hasher) { +// hasher.combine(name) +// } +// +// public static func == (lhs: Mastodon.Entity.Tag, rhs: Mastodon.Entity.Tag) -> Bool { +// return lhs.name == rhs.name +// } +//} diff --git a/Mastodon/Extension/UINavigationController.swift b/Mastodon/Extension/UINavigationController.swift deleted file mode 100644 index 9a9c44ab3..000000000 --- a/Mastodon/Extension/UINavigationController.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// UINavigationController.swift -// Mastodon -// -// Created by MainasuK Cirno on 2021-3-31. -// - -import UIKit - -// This not works! -// SeeAlso: `AdaptiveStatusBarStyleNavigationController` -extension UINavigationController { - open override var childForStatusBarStyle: UIViewController? { - return visibleViewController - } -} diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+SearchHistory.swift b/Mastodon/Protocol/Provider/DataSourceFacade+SearchHistory.swift index cbc6bf348..8beaabbae 100644 --- a/Mastodon/Protocol/Provider/DataSourceFacade+SearchHistory.swift +++ b/Mastodon/Protocol/Provider/DataSourceFacade+SearchHistory.swift @@ -99,7 +99,7 @@ extension DataSourceFacade { try await managedObjectContext.performChanges { guard let authenticationBox = _authenticationBox else { return } - guard let me = authenticationBox.authenticationRecord.object(in: managedObjectContext)?.user else { return } + guard let _ = authenticationBox.authenticationRecord.object(in: managedObjectContext)?.user else { return } let request = SearchHistory.sortedFetchRequest request.predicate = SearchHistory.predicate( domain: authenticationBox.domain, diff --git a/Mastodon/Protocol/Provider/DataSourceProvider+NotificationTableViewCellDelegate.swift b/Mastodon/Protocol/Provider/DataSourceProvider+NotificationTableViewCellDelegate.swift index f6e58673b..ca7fdeb18 100644 --- a/Mastodon/Protocol/Provider/DataSourceProvider+NotificationTableViewCellDelegate.swift +++ b/Mastodon/Protocol/Provider/DataSourceProvider+NotificationTableViewCellDelegate.swift @@ -486,7 +486,7 @@ extension NotificationTableViewCellDelegate where Self: DataSourceProvider { provider: self, user: user ) - case .notification(let notification): + case .notification: assertionFailure("TODO") default: assertionFailure("TODO") diff --git a/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift b/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift index 9e5838e77..f00e14840 100644 --- a/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift +++ b/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift @@ -494,7 +494,7 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider { provider: self, user: user ) - case .notification(let notification): + case .notification: assertionFailure("TODO") default: assertionFailure("TODO") diff --git a/Mastodon/Protocol/Provider/DataSourceProvider+TableViewControllerNavigateable.swift b/Mastodon/Protocol/Provider/DataSourceProvider+TableViewControllerNavigateable.swift index f7e50cff8..50fa17866 100644 --- a/Mastodon/Protocol/Provider/DataSourceProvider+TableViewControllerNavigateable.swift +++ b/Mastodon/Protocol/Provider/DataSourceProvider+TableViewControllerNavigateable.swift @@ -138,7 +138,7 @@ extension TableViewControllerNavigateableCore where Self: DataSourceProvider { target: .status, status: record ) - case .notification(let record): + case .notification: assertionFailure() default: assertionFailure() diff --git a/Mastodon/Protocol/Provider/DataSourceProvider+UITableViewDelegate.swift b/Mastodon/Protocol/Provider/DataSourceProvider+UITableViewDelegate.swift index 3968df110..c00c36971 100644 --- a/Mastodon/Protocol/Provider/DataSourceProvider+UITableViewDelegate.swift +++ b/Mastodon/Protocol/Provider/DataSourceProvider+UITableViewDelegate.swift @@ -93,7 +93,7 @@ extension UITableViewDelegate where Self: DataSourceProvider & MediaPreviewableV guard let image = mediaView.thumbnail(), let assetURLString = mediaView.configuration?.assetURL, let assetURL = URL(string: assetURLString), - let resourceType = mediaView.configuration?.resourceType + let _ = mediaView.configuration?.resourceType else { // not provide preview unless thumbnail ready return nil diff --git a/Mastodon/Scene/Account/AccountViewController.swift b/Mastodon/Scene/Account/AccountViewController.swift index 42c9e1d62..20d7b26a1 100644 --- a/Mastodon/Scene/Account/AccountViewController.swift +++ b/Mastodon/Scene/Account/AccountViewController.swift @@ -118,7 +118,7 @@ extension AccountListViewController { // the presentingViewController may deinit. // Hold it and check the window to prevent PanModel crash - guard let presentingViewController = presentingViewController else { return } + guard let _ = presentingViewController else { return } guard self.view.window != nil else { return } self.hasLoaded = true diff --git a/Mastodon/Scene/Compose/AutoComplete/AutoCompleteViewModel+State.swift b/Mastodon/Scene/Compose/AutoComplete/AutoCompleteViewModel+State.swift index ebda78a1e..632b57b66 100644 --- a/Mastodon/Scene/Compose/AutoComplete/AutoCompleteViewModel+State.swift +++ b/Mastodon/Scene/Compose/AutoComplete/AutoCompleteViewModel+State.swift @@ -77,7 +77,7 @@ extension AutoCompleteViewModel.State { override func didEnter(from previousState: GKState?) { super.didEnter(from: previousState) - guard let viewModel = viewModel, let stateMachine = stateMachine else { return } + guard let viewModel = viewModel, let _ = stateMachine else { return } let searchText = viewModel.inputText.value let searchType = AutoCompleteViewModel.SearchType(inputText: searchText) ?? .default diff --git a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift index 8da975de2..92b84d176 100644 --- a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift +++ b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift @@ -68,7 +68,7 @@ extension DiscoveryNewsViewModel.State { override func didEnter(from previousState: GKState?) { super.didEnter(from: previousState) - guard let viewModel = viewModel, let stateMachine = stateMachine else { return } + guard let _ = viewModel, let stateMachine = stateMachine else { return } stateMachine.enter(Loading.self) } diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift index 8b6eb9f42..4fae66d33 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift @@ -186,7 +186,7 @@ extension HomeTimelineViewController { } func match(item: StatusItem) -> Bool { - let authenticationBox = AppContext.shared.authenticationService.activeMastodonAuthenticationBox.value + // let authenticationBox = AppContext.shared.authenticationService.activeMastodonAuthenticationBox.value switch item { case .feed(let record): guard let feed = record.object(in: AppContext.shared.managedObjectContext) else { return false } diff --git a/Mastodon/Scene/Profile/ProfileViewController.swift b/Mastodon/Scene/Profile/ProfileViewController.swift index d3de07cff..021f62ede 100644 --- a/Mastodon/Scene/Profile/ProfileViewController.swift +++ b/Mastodon/Scene/Profile/ProfileViewController.swift @@ -634,7 +634,7 @@ extension ProfileViewController { return nil } let name = user.displayNameWithFallback - let record = ManagedObjectRecord(objectID: user.objectID) + let _ = ManagedObjectRecord(objectID: user.objectID) let menu = MastodonMenu.setupMenu( actions: [ .muteUser(.init(name: name, isMuting: self.viewModel.isMuting.value)), @@ -649,7 +649,7 @@ extension ProfileViewController { .sink { [weak self] completion in guard let self = self else { return } switch completion { - case .failure(let error): + case .failure: self.moreMenuBarButtonItem.menu = nil case .finished: break diff --git a/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift index 7ac0f6e54..c7cf3d49d 100644 --- a/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift +++ b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift @@ -154,10 +154,9 @@ extension SidebarViewController { coordinator.animate { context in self.collectionView.collectionViewLayout.invalidateLayout() - } completion: { [weak self] context in -// guard let self = self else { return } + } completion: { context in + // do nothing } - } } diff --git a/Mastodon/Scene/Settings/SettingsViewController.swift b/Mastodon/Scene/Settings/SettingsViewController.swift index 4cf20cd09..8455ac7d9 100644 --- a/Mastodon/Scene/Settings/SettingsViewController.swift +++ b/Mastodon/Scene/Settings/SettingsViewController.swift @@ -448,7 +448,7 @@ extension SettingsViewController: SettingsAppearanceTableViewCellDelegate { guard let dataSource = viewModel.dataSource else { return } guard let indexPath = tableView.indexPath(for: cell) else { return } let item = dataSource.itemIdentifier(for: indexPath) - guard case let .appearance(record) = item else { return } + guard case .appearance = item else { return } Task { @MainActor in switch appearanceMode { diff --git a/Mastodon/Scene/Transition/MediaPreview/MediaHostToMediaPreviewViewControllerAnimatedTransitioning.swift b/Mastodon/Scene/Transition/MediaPreview/MediaHostToMediaPreviewViewControllerAnimatedTransitioning.swift index f730e0b8b..1b2d62211 100644 --- a/Mastodon/Scene/Transition/MediaPreview/MediaHostToMediaPreviewViewControllerAnimatedTransitioning.swift +++ b/Mastodon/Scene/Transition/MediaPreview/MediaHostToMediaPreviewViewControllerAnimatedTransitioning.swift @@ -255,6 +255,8 @@ extension MediaHostToMediaPreviewViewControllerAnimatedTransitioning { rect.size.height -= offset return rect }() + + // FIXME: let maskLayerToFinalPath = maskLayerToFinalRect.flatMap { UIBezierPath(rect: $0) }?.cgPath if let maskLayerToPath = maskLayerToPath { diff --git a/Mastodon/Service/APIService/APIService+Thread.swift b/Mastodon/Service/APIService/APIService+Thread.swift index 782da5886..f6c36e5b6 100644 --- a/Mastodon/Service/APIService/APIService+Thread.swift +++ b/Mastodon/Service/APIService/APIService+Thread.swift @@ -34,7 +34,7 @@ extension APIService { let value = response.value.ancestors + response.value.descendants for entity in value { - Persistence.Status.createOrMerge( + _ = Persistence.Status.createOrMerge( in: managedObjectContext, context: Persistence.Status.PersistContext( domain: domain, diff --git a/Mastodon/Service/InstanceService.swift b/Mastodon/Service/InstanceService.swift index 4fb6309fd..03b8dfd4e 100644 --- a/Mastodon/Service/InstanceService.swift +++ b/Mastodon/Service/InstanceService.swift @@ -95,7 +95,7 @@ extension InstanceService { self.logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [Instance] update instance for domain: \(domain)") } } receiveValue: { [weak self] response in - guard let self = self else { return } + guard let _ = self else { return } // do nothing } .store(in: &disposeBag) diff --git a/MastodonSDK/Sources/MastodonUI/Extension/UIImage.swift b/MastodonSDK/Sources/MastodonUI/Extension/UIImage.swift index 105b4c27d..141b723bc 100644 --- a/MastodonSDK/Sources/MastodonUI/Extension/UIImage.swift +++ b/MastodonSDK/Sources/MastodonUI/Extension/UIImage.swift @@ -14,4 +14,5 @@ extension UIImage { self.draw(in: CGRect(origin: .zero, size: size)) } } + } From f0658f77f8289fe68bdba49fa71586d21ece09f7 Mon Sep 17 00:00:00 2001 From: CMK Date: Sat, 7 May 2022 11:43:37 +0800 Subject: [PATCH 071/101] feat: add navigation pan pop gesture. resolve #407 #419 --- ...veStatusBarStyleNavigationController.swift | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/Mastodon/Scene/Share/NavigationController/AdaptiveStatusBarStyleNavigationController.swift b/Mastodon/Scene/Share/NavigationController/AdaptiveStatusBarStyleNavigationController.swift index aac23285b..f4ad467da 100644 --- a/Mastodon/Scene/Share/NavigationController/AdaptiveStatusBarStyleNavigationController.swift +++ b/Mastodon/Scene/Share/NavigationController/AdaptiveStatusBarStyleNavigationController.swift @@ -10,7 +10,41 @@ import UIKit // Make status bar style adaptive for child view controller // SeeAlso: `modalPresentationCapturesStatusBarAppearance` class AdaptiveStatusBarStyleNavigationController: UINavigationController { + + private lazy var fullWidthBackGestureRecognizer = UIPanGestureRecognizer() + override var childForStatusBarStyle: UIViewController? { visibleViewController } } + +// ref: https://stackoverflow.com/a/60598558/3797903 +extension AdaptiveStatusBarStyleNavigationController { + + override func viewDidLoad() { + super.viewDidLoad() + setupFullWidthBackGesture() + } + + private func setupFullWidthBackGesture() { + // The trick here is to wire up our full-width `fullWidthBackGestureRecognizer` to execute the same handler as + // the system `interactivePopGestureRecognizer`. That's done by assigning the same "targets" (effectively + // object and selector) of the system one to our gesture recognizer. + guard let interactivePopGestureRecognizer = interactivePopGestureRecognizer, + let targets = interactivePopGestureRecognizer.value(forKey: "targets") + else { return } + + fullWidthBackGestureRecognizer.setValue(targets, forKey: "targets") + fullWidthBackGestureRecognizer.delegate = self + view.addGestureRecognizer(fullWidthBackGestureRecognizer) + } +} + +// MARK: - UIGestureRecognizerDelegate +extension AdaptiveStatusBarStyleNavigationController: UIGestureRecognizerDelegate { + func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { + let isSystemSwipeToBackEnabled = interactivePopGestureRecognizer?.isEnabled == true + let isThereStackedViewControllers = viewControllers.count > 1 + return isSystemSwipeToBackEnabled && isThereStackedViewControllers + } +} From 716e8bf121d20ce56e3a1aae5d1c5237b32aa9ee Mon Sep 17 00:00:00 2001 From: CMK Date: Sat, 7 May 2022 11:45:44 +0800 Subject: [PATCH 072/101] chore: update version to 1.4.1 (125) --- AppShared/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 36 +++++++++---------- .../xcschemes/xcschememanagement.plist | 6 ++-- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 9 files changed, 28 insertions(+), 28 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 1abe4cbf3..973b24056 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.4.1 CFBundleVersion - 124 + 125 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 0f49a3f4e..c8a0a2bca 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4707,7 +4707,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 124; + CURRENT_PROJECT_VERSION = 125; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4737,7 +4737,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 124; + CURRENT_PROJECT_VERSION = 125; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4845,11 +4845,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 124; + CURRENT_PROJECT_VERSION = 125; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 124; + DYLIB_CURRENT_VERSION = 125; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4876,11 +4876,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 124; + CURRENT_PROJECT_VERSION = 125; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 124; + DYLIB_CURRENT_VERSION = 125; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4904,7 +4904,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 124; + CURRENT_PROJECT_VERSION = 125; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4928,7 +4928,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 124; + CURRENT_PROJECT_VERSION = 125; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4952,7 +4952,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 124; + CURRENT_PROJECT_VERSION = 125; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4976,7 +4976,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 124; + CURRENT_PROJECT_VERSION = 125; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5063,7 +5063,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 124; + CURRENT_PROJECT_VERSION = 125; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5130,11 +5130,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 124; + CURRENT_PROJECT_VERSION = 125; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 124; + DYLIB_CURRENT_VERSION = 125; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5158,7 +5158,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 124; + CURRENT_PROJECT_VERSION = 125; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5181,7 +5181,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 124; + CURRENT_PROJECT_VERSION = 125; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5205,7 +5205,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 124; + CURRENT_PROJECT_VERSION = 125; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5229,7 +5229,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 124; + CURRENT_PROJECT_VERSION = 125; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5252,7 +5252,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 124; + CURRENT_PROJECT_VERSION = 125; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 7f54b9011..75b20985b 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 20 + 26 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 19 + 28 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 21 + 27 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 07308a8ee..14588c758 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -43,7 +43,7 @@ CFBundleVersion - 124 + 125 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index a1adcf83b..58d21c7bb 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.4.1 CFBundleVersion - 124 + 125 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 1abe4cbf3..973b24056 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.4.1 CFBundleVersion - 124 + 125 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 1abe4cbf3..973b24056 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.4.1 CFBundleVersion - 124 + 125 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index bb670f1db..c65337a3d 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.4.1 CFBundleVersion - 124 + 125 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 57436f4d9..e1d9a940e 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.4.1 CFBundleVersion - 124 + 125 NSExtension NSExtensionAttributes From 7380d28d745ae16bb083c088ff41a551c625b362 Mon Sep 17 00:00:00 2001 From: CMK Date: Sat, 7 May 2022 15:12:00 +0800 Subject: [PATCH 073/101] fix: profile bio line break get trimmed issue. resolve #311 --- Mastodon/Scene/Profile/Header/ProfileHeaderViewModel.swift | 5 ++++- Mastodon/Scene/Profile/ProfileViewController.swift | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Mastodon/Scene/Profile/Header/ProfileHeaderViewModel.swift b/Mastodon/Scene/Profile/Header/ProfileHeaderViewModel.swift index 7f7b0dd00..8bdce2a6d 100644 --- a/Mastodon/Scene/Profile/Header/ProfileHeaderViewModel.swift +++ b/Mastodon/Scene/Profile/Header/ProfileHeaderViewModel.swift @@ -90,7 +90,10 @@ extension ProfileHeaderViewModel { extension ProfileHeaderViewModel { static func normalize(note: String?) -> String? { - guard let note = note?.trimmingCharacters(in: .whitespacesAndNewlines),!note.isEmpty else { + let _note = note?.replacingOccurrences(of: "
|
", with: "\u{2028}", options: .regularExpression, range: nil) + .replacingOccurrences(of: "

", with: "

\u{2029}", range: nil) + .trimmingCharacters(in: .whitespacesAndNewlines) + guard let note = _note, !note.isEmpty else { return nil } diff --git a/Mastodon/Scene/Profile/ProfileViewController.swift b/Mastodon/Scene/Profile/ProfileViewController.swift index 021f62ede..b376ebcf9 100644 --- a/Mastodon/Scene/Profile/ProfileViewController.swift +++ b/Mastodon/Scene/Profile/ProfileViewController.swift @@ -953,6 +953,7 @@ extension ProfileViewController: ProfileHeaderViewDelegate { viewModel.isUpdating.value = true Task { do { + // TODO: handle error _ = try await viewModel.updateProfileInfo( headerProfileInfo: profileHeaderViewModel.editProfileInfo, aboutProfileInfo: profileAboutViewModel.editProfileInfo From 238945d9b11fe8e8f675627c9cfdaa34f5a5837e Mon Sep 17 00:00:00 2001 From: CMK Date: Sat, 7 May 2022 15:13:07 +0800 Subject: [PATCH 074/101] chore: update version to 1.4.1 (126) --- AppShared/Info.plist | 2 +- Mastodon.xcodeproj/project.pbxproj | 36 +++++++++---------- .../xcschemes/xcschememanagement.plist | 6 ++-- Mastodon/Info.plist | 2 +- MastodonIntent/Info.plist | 2 +- MastodonTests/Info.plist | 2 +- MastodonUITests/Info.plist | 2 +- NotificationService/Info.plist | 2 +- ShareActionExtension/Info.plist | 2 +- 9 files changed, 28 insertions(+), 28 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 973b24056..92f442892 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.4.1 CFBundleVersion - 125 + 126
diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index c8a0a2bca..d5f5cbd79 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4707,7 +4707,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 125; + CURRENT_PROJECT_VERSION = 126; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4737,7 +4737,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 125; + CURRENT_PROJECT_VERSION = 126; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4845,11 +4845,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 125; + CURRENT_PROJECT_VERSION = 126; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 125; + DYLIB_CURRENT_VERSION = 126; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4876,11 +4876,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 125; + CURRENT_PROJECT_VERSION = 126; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 125; + DYLIB_CURRENT_VERSION = 126; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4904,7 +4904,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 125; + CURRENT_PROJECT_VERSION = 126; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4928,7 +4928,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 125; + CURRENT_PROJECT_VERSION = 126; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4952,7 +4952,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 125; + CURRENT_PROJECT_VERSION = 126; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4976,7 +4976,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 125; + CURRENT_PROJECT_VERSION = 126; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5063,7 +5063,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 125; + CURRENT_PROJECT_VERSION = 126; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5130,11 +5130,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 125; + CURRENT_PROJECT_VERSION = 126; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 125; + DYLIB_CURRENT_VERSION = 126; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5158,7 +5158,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 125; + CURRENT_PROJECT_VERSION = 126; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5181,7 +5181,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 125; + CURRENT_PROJECT_VERSION = 126; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5205,7 +5205,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 125; + CURRENT_PROJECT_VERSION = 126; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5229,7 +5229,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 125; + CURRENT_PROJECT_VERSION = 126; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5252,7 +5252,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 125; + CURRENT_PROJECT_VERSION = 126; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 75b20985b..07a847a0c 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 26 + 28 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 28 + 27 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 27 + 26 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 14588c758..c93fd9a65 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -43,7 +43,7 @@
CFBundleVersion - 125 + 126 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 58d21c7bb..3f1630945 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.4.1 CFBundleVersion - 125 + 126 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 973b24056..92f442892 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.4.1 CFBundleVersion - 125 + 126 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 973b24056..92f442892 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString 1.4.1 CFBundleVersion - 125 + 126 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index c65337a3d..f074db82b 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.4.1 CFBundleVersion - 125 + 126 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index e1d9a940e..31c7447fe 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 1.4.1 CFBundleVersion - 125 + 126 NSExtension NSExtensionAttributes From e4c38c70e29ea873b77312436845ddd7fc0ca7dd Mon Sep 17 00:00:00 2001 From: CMK Date: Mon, 9 May 2022 11:28:35 +0800 Subject: [PATCH 075/101] Release v1.4.1 (#427) * feat: use bundler to install Ruby Gems instead of installing them system-wide using root * chore: install bundler without sudo * Improve tab bar icon vertical alignment * feat: update tabBar UI * chore: update version to 1.4.1 (122) * chore: fix accessibility large content label text missing issue * chore: update version to 1.4.1 (123) * chore: update navigation bar button item assets * fix: compose tabBar button layout raise crash on iPad issue * chore: update version to 1.4.1 (124) * chore: suppress warnings * feat: add navigation pan pop gesture. resolve #407 #419 * chore: update version to 1.4.1 (125) * fix: profile bio line break get trimmed issue. resolve #311 * chore: update version to 1.4.1 (126) Co-authored-by: Marcus Kida Co-authored-by: vollkorntomate --- .github/scripts/setup.sh | 12 +- AppShared/Info.plist | 4 +- Documentation/Setup.md | 14 +- Gemfile | 6 + Gemfile.lock | 109 ++++++++++ Mastodon.xcodeproj/project.pbxproj | 40 ++-- .../xcschemes/xcschememanagement.plist | 2 +- Mastodon/Coordinator/SceneCoordinator.swift | 6 +- .../Onboarding/PickServerSection.swift | 2 +- .../Diffiable/Settings/SettingsSection.swift | 2 +- .../MastodonSDK/Mastodon+Entity+Tag.swift | 19 +- .../Extension/UINavigationController.swift | 16 -- Mastodon/Info.plist | 4 +- .../DataSourceFacade+SearchHistory.swift | 2 +- ...er+NotificationTableViewCellDelegate.swift | 2 +- ...Provider+StatusTableViewCellDelegate.swift | 2 +- ...ider+TableViewControllerNavigateable.swift | 2 +- ...taSourceProvider+UITableViewDelegate.swift | 2 +- .../Scene/Account/AccountViewController.swift | 2 +- .../AutoCompleteViewModel+State.swift | 2 +- .../News/DiscoveryNewsViewModel+State.swift | 2 +- .../HashtagTimelineViewController.swift | 2 +- ...meTimelineViewController+DebugAction.swift | 2 +- .../HomeTimelineViewController.swift | 37 +--- .../HomeTimeline/HomeTimelineViewModel.swift | 1 - .../Header/ProfileHeaderViewModel.swift | 5 +- .../Scene/Profile/ProfileViewController.swift | 26 ++- .../Root/ContentSplitViewController.swift | 4 +- .../Root/MainTab/MainTabBarController.swift | 201 ++++++++++++++---- .../Scene/Root/RootSplitViewController.swift | 6 +- .../Root/Sidebar/SidebarViewController.swift | 5 +- .../Scene/Root/Sidebar/SidebarViewModel.swift | 55 +++-- .../Sidebar/View/SidebarListContentView.swift | 13 +- .../Settings/SettingsViewController.swift | 2 +- ...veStatusBarStyleNavigationController.swift | 34 +++ ...wViewControllerAnimatedTransitioning.swift | 2 + .../APIService/APIService+Thread.swift | 2 +- Mastodon/Service/InstanceService.swift | 2 +- MastodonIntent/Info.plist | 4 +- .../Contents.json | 15 ++ .../Share iOS.pdf | 110 ++++++++++ .../bell.badge.fill.imageset/Contents.json | 15 ++ .../bell.badge.fill.pdf | 94 ++++++++ .../bell.badge.imageset/Contents.json | 15 ++ .../bell.badge.imageset/bell.badge.pdf | 112 ++++++++++ .../bell.fill.imageset/Contents.json | 15 ++ .../bell.fill.imageset/bell.fill.pdf | 88 ++++++++ .../bell.imageset/Contents.json | 15 ++ .../ObjectsAndTools/bell.imageset/bell.pdf | 106 +++++++++ .../gear.imageset/Contents.json | 15 ++ .../ObjectsAndTools/gear.imageset/gear.pdf | 155 ++++++++++++++ .../house.fill.imageset/Contents.json | 15 ++ .../house.fill.imageset/Home-fill.pdf | 85 ++++++++ .../house.imageset/Contents.json | 15 ++ .../ObjectsAndTools/house.imageset/Home.pdf | 105 +++++++++ .../Contents.json | 15 ++ .../Search-Fill.pdf | 83 ++++++++ .../magnifyingglass.imageset/Contents.json | 15 ++ .../magnifyingglass.imageset/Search.pdf | 83 ++++++++ .../square.and.pencil.imageset/Contents.json | 15 ++ .../square.and.pencil.pdf | 93 ++++++++ .../MastodonAsset/Generated/Assets.swift | 11 + .../MastodonUI/Extension/UIImage.swift | 18 ++ MastodonTests/Info.plist | 4 +- MastodonUITests/Info.plist | 4 +- NotificationService/Info.plist | 4 +- ShareActionExtension/Info.plist | 4 +- update_localization.sh | 2 +- 68 files changed, 1779 insertions(+), 202 deletions(-) create mode 100644 Gemfile create mode 100644 Gemfile.lock delete mode 100644 Mastodon/Extension/UINavigationController.swift create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Arrow/square.and.arrow.up.imageset/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Arrow/square.and.arrow.up.imageset/Share iOS.pdf create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.fill.imageset/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.fill.imageset/bell.badge.fill.pdf create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.imageset/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.imageset/bell.badge.pdf create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.fill.imageset/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.fill.imageset/bell.fill.pdf create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.imageset/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.imageset/bell.pdf create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/gear.imageset/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/gear.imageset/gear.pdf create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.fill.imageset/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.fill.imageset/Home-fill.pdf create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.imageset/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.imageset/Home.pdf create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.fill.imageset/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.fill.imageset/Search-Fill.pdf create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.imageset/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.imageset/Search.pdf create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/square.and.pencil.imageset/Contents.json create mode 100644 MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/square.and.pencil.imageset/square.and.pencil.pdf create mode 100644 MastodonSDK/Sources/MastodonUI/Extension/UIImage.swift diff --git a/.github/scripts/setup.sh b/.github/scripts/setup.sh index 0c2612d51..9b52d5b9e 100755 --- a/.github/scripts/setup.sh +++ b/.github/scripts/setup.sh @@ -1,9 +1,13 @@ #!/bin/bash -sudo gem install cocoapods-keys +# Install Ruby Bundler +gem install bundler:2.3.11 + +# Install Ruby Gems +bundle install # stub keys. DO NOT use in production -pod keys set notification_endpoint "" -pod keys set notification_endpoint_debug "" +bundle exec pod keys set notification_endpoint "" +bundle exec pod keys set notification_endpoint_debug "" -pod install +bundle exec pod install diff --git a/AppShared/Info.plist b/AppShared/Info.plist index a1528e2c5..92f442892 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.4.0 + 1.4.1 CFBundleVersion - 121 + 126 diff --git a/Documentation/Setup.md b/Documentation/Setup.md index ede9d4862..1c2f0a6c5 100644 --- a/Documentation/Setup.md +++ b/Documentation/Setup.md @@ -12,12 +12,13 @@ Intell the latest version of Xcode from the App Store or Apple Developer Downloa This guide may not suit your machine and actually setup procedure may change in the future. Please file the issue or Pull Request if there are any problems. ## CocoaPods -The app use [CocoaPods]() and [CocoaPods-Keys](https://github.com/orta/cocoapods-keys). The M1 Mac needs virtual ruby env to workaround compatibility issues. +The app use [CocoaPods]() and [CocoaPods-Keys](https://github.com/orta/cocoapods-keys). Ruby Gems are managed through Bundler. The M1 Mac needs virtual ruby env to workaround compatibility issues. #### Intel Mac ```zsh -sudo gem install cocoapods cocoapods-keys +gem install bundler +bundle install ``` #### M1 Mac @@ -40,18 +41,19 @@ rbenv global 3.0.3 ruby --version # > ruby 3.0.3p157 (2021-11-24 revision 3fb7d2cadc) [arm64-darwin21] -sudo gem install cocoapods cocoapods-keys +gem install bundler +bundle install ``` ## Bootstrap ```zsh # make a clean build -sudo gem install cocoapods-clean -pod clean +bundle install +bundle exec pod clean # make install -pod install --repo-update +bundle exec pod install --repo-update # open workspace open Mastodon.xcworkspace diff --git a/Gemfile b/Gemfile new file mode 100644 index 000000000..48aae3d82 --- /dev/null +++ b/Gemfile @@ -0,0 +1,6 @@ +source "https://rubygems.org" + +gem "cocoapods" +gem "cocoapods-clean" +gem "cocoapods-keys" + diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 000000000..b27a44a97 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,109 @@ +GEM + remote: https://rubygems.org/ + specs: + CFPropertyList (3.0.5) + rexml + RubyInline (3.12.5) + ZenTest (~> 4.3) + ZenTest (4.12.1) + activesupport (6.1.5.1) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + zeitwerk (~> 2.3) + addressable (2.8.0) + public_suffix (>= 2.0.2, < 5.0) + algoliasearch (1.27.5) + httpclient (~> 2.8, >= 2.8.3) + json (>= 1.5.1) + atomos (0.1.3) + claide (1.1.0) + cocoapods (1.11.3) + addressable (~> 2.8) + claide (>= 1.0.2, < 2.0) + cocoapods-core (= 1.11.3) + cocoapods-deintegrate (>= 1.0.3, < 2.0) + cocoapods-downloader (>= 1.4.0, < 2.0) + cocoapods-plugins (>= 1.0.0, < 2.0) + cocoapods-search (>= 1.0.0, < 2.0) + cocoapods-trunk (>= 1.4.0, < 2.0) + cocoapods-try (>= 1.1.0, < 2.0) + colored2 (~> 3.1) + escape (~> 0.0.4) + fourflusher (>= 2.3.0, < 3.0) + gh_inspector (~> 1.0) + molinillo (~> 0.8.0) + nap (~> 1.0) + ruby-macho (>= 1.0, < 3.0) + xcodeproj (>= 1.21.0, < 2.0) + cocoapods-clean (0.0.1) + cocoapods-core (1.11.3) + activesupport (>= 5.0, < 7) + addressable (~> 2.8) + algoliasearch (~> 1.0) + concurrent-ruby (~> 1.1) + fuzzy_match (~> 2.0.4) + nap (~> 1.0) + netrc (~> 0.11) + public_suffix (~> 4.0) + typhoeus (~> 1.0) + cocoapods-deintegrate (1.0.5) + cocoapods-downloader (1.6.3) + cocoapods-keys (2.2.1) + dotenv + osx_keychain + cocoapods-plugins (1.0.0) + nap + cocoapods-search (1.0.1) + cocoapods-trunk (1.6.0) + nap (>= 0.8, < 2.0) + netrc (~> 0.11) + cocoapods-try (1.2.0) + colored2 (3.1.2) + concurrent-ruby (1.1.10) + dotenv (2.7.6) + escape (0.0.4) + ethon (0.15.0) + ffi (>= 1.15.0) + ffi (1.15.5) + fourflusher (2.3.1) + fuzzy_match (2.0.4) + gh_inspector (1.1.3) + httpclient (2.8.3) + i18n (1.10.0) + concurrent-ruby (~> 1.0) + json (2.6.1) + minitest (5.15.0) + molinillo (0.8.0) + nanaimo (0.3.0) + nap (1.1.0) + netrc (0.11.0) + osx_keychain (1.0.2) + RubyInline (~> 3) + public_suffix (4.0.7) + rexml (3.2.5) + ruby-macho (2.5.1) + typhoeus (1.4.0) + ethon (>= 0.9.0) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + xcodeproj (1.21.0) + CFPropertyList (>= 2.3.3, < 4.0) + atomos (~> 0.1.3) + claide (>= 1.0.2, < 2.0) + colored2 (~> 3.1) + nanaimo (~> 0.3.0) + rexml (~> 3.2.4) + zeitwerk (2.5.4) + +PLATFORMS + ruby + +DEPENDENCIES + cocoapods + cocoapods-clean + cocoapods-keys + +BUNDLED WITH + 2.3.11 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index fcba16b23..d5f5cbd79 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -537,7 +537,6 @@ DBCBED1726132DB500B49291 /* UserTimelineViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBCBED1626132DB500B49291 /* UserTimelineViewModel+Diffable.swift */; }; DBCBED1D26132E1A00B49291 /* StatusFetchedResultsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBCBED1C26132E1A00B49291 /* StatusFetchedResultsController.swift */; }; DBCC3B30261440A50045B23D /* UITabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBCC3B2F261440A50045B23D /* UITabBarController.swift */; }; - DBCC3B36261440BA0045B23D /* UINavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBCC3B35261440BA0045B23D /* UINavigationController.swift */; }; DBCC3B8F26148F7B0045B23D /* CachedProfileViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBCC3B8E26148F7B0045B23D /* CachedProfileViewModel.swift */; }; DBCC3B9526157E6E0045B23D /* APIService+Relationship.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBCC3B9426157E6E0045B23D /* APIService+Relationship.swift */; }; DBCCC71E25F73297007E1AB6 /* APIService+Reblog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBCCC71D25F73297007E1AB6 /* APIService+Reblog.swift */; }; @@ -1302,7 +1301,6 @@ DBCBED1626132DB500B49291 /* UserTimelineViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserTimelineViewModel+Diffable.swift"; sourceTree = ""; }; DBCBED1C26132E1A00B49291 /* StatusFetchedResultsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusFetchedResultsController.swift; sourceTree = ""; }; DBCC3B2F261440A50045B23D /* UITabBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITabBarController.swift; sourceTree = ""; }; - DBCC3B35261440BA0045B23D /* UINavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UINavigationController.swift; sourceTree = ""; }; DBCC3B8E26148F7B0045B23D /* CachedProfileViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CachedProfileViewModel.swift; sourceTree = ""; }; DBCC3B9426157E6E0045B23D /* APIService+Relationship.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Relationship.swift"; sourceTree = ""; }; DBCCC71D25F73297007E1AB6 /* APIService+Reblog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Reblog.swift"; sourceTree = ""; }; @@ -2792,7 +2790,6 @@ 2D84350425FF858100EECE90 /* UIScrollView.swift */, DB9E0D6E25EE008500CFDD76 /* UIInterpolatingMotionEffect.swift */, DBCC3B2F261440A50045B23D /* UITabBarController.swift */, - DBCC3B35261440BA0045B23D /* UINavigationController.swift */, DB73BF4827140BA300781945 /* UICollectionViewDiffableDataSource.swift */, DB73BF4A27140C0800781945 /* UITableViewDiffableDataSource.swift */, ); @@ -4029,7 +4026,6 @@ DB9D7C21269824B80054B3DF /* APIService+Filter.swift in Sources */, 2D38F1E525CD46C100561493 /* HomeTimelineViewModel.swift in Sources */, DB0FCB842796B2A2006C02E2 /* FavoriteViewController+DataSourceProvider.swift in Sources */, - DBCC3B36261440BA0045B23D /* UINavigationController.swift in Sources */, DB0FCB68279507EF006C02E2 /* DataSourceFacade+Meta.swift in Sources */, DB63F75C279956D000455B82 /* Persistence+Tag.swift in Sources */, 2D84350525FF858100EECE90 /* UIScrollView.swift in Sources */, @@ -4711,7 +4707,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 121; + CURRENT_PROJECT_VERSION = 126; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4741,7 +4737,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 121; + CURRENT_PROJECT_VERSION = 126; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4849,11 +4845,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 121; + CURRENT_PROJECT_VERSION = 126; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 121; + DYLIB_CURRENT_VERSION = 126; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4880,11 +4876,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 121; + CURRENT_PROJECT_VERSION = 126; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 121; + DYLIB_CURRENT_VERSION = 126; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4908,7 +4904,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 121; + CURRENT_PROJECT_VERSION = 126; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4932,7 +4928,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 121; + CURRENT_PROJECT_VERSION = 126; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4956,7 +4952,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 121; + CURRENT_PROJECT_VERSION = 126; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4980,7 +4976,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 121; + CURRENT_PROJECT_VERSION = 126; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5067,7 +5063,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 121; + CURRENT_PROJECT_VERSION = 126; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5134,11 +5130,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 121; + CURRENT_PROJECT_VERSION = 126; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 121; + DYLIB_CURRENT_VERSION = 126; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5162,7 +5158,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 121; + CURRENT_PROJECT_VERSION = 126; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5185,7 +5181,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 121; + CURRENT_PROJECT_VERSION = 126; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5209,7 +5205,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 121; + CURRENT_PROJECT_VERSION = 126; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5233,7 +5229,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 121; + CURRENT_PROJECT_VERSION = 126; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5256,7 +5252,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 121; + CURRENT_PROJECT_VERSION = 126; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 979898bbd..07a847a0c 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -129,7 +129,7 @@ ShareActionExtension.xcscheme_^#shared#^_ orderHint - 22 + 26 SuppressBuildableAutocreation diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index 1f8030014..5e7fbf472 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -309,7 +309,7 @@ extension SceneCoordinator { if scene.isOnboarding { return OnboardingNavigationController(rootViewController: viewController) } else { - return UINavigationController(rootViewController: viewController) + return AdaptiveStatusBarStyleNavigationController(rootViewController: viewController) } }() modalNavigationController.modalPresentationCapturesStatusBarAppearance = true @@ -368,10 +368,10 @@ extension SceneCoordinator { splitViewController?.contentSplitViewController.currentSupplementaryTab = tab splitViewController?.compactMainTabBarViewController.selectedIndex = tab.rawValue - splitViewController?.compactMainTabBarViewController.currentTab.value = tab + splitViewController?.compactMainTabBarViewController.currentTab = tab tabBarController.selectedIndex = tab.rawValue - tabBarController.currentTab.value = tab + tabBarController.currentTab = tab } } diff --git a/Mastodon/Diffiable/Onboarding/PickServerSection.swift b/Mastodon/Diffiable/Onboarding/PickServerSection.swift index 5faaefbcc..01a31f6f6 100644 --- a/Mastodon/Diffiable/Onboarding/PickServerSection.swift +++ b/Mastodon/Diffiable/Onboarding/PickServerSection.swift @@ -29,7 +29,7 @@ extension PickServerSection { weak dependency, weak pickServerCellDelegate ] tableView, indexPath, item -> UITableViewCell? in - guard let dependency = dependency else { return nil } + guard let _ = dependency else { return nil } switch item { case .header: let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: OnboardingHeadlineTableViewCell.self), for: indexPath) as! OnboardingHeadlineTableViewCell diff --git a/Mastodon/Diffiable/Settings/SettingsSection.swift b/Mastodon/Diffiable/Settings/SettingsSection.swift index adc7140be..6925303d8 100644 --- a/Mastodon/Diffiable/Settings/SettingsSection.swift +++ b/Mastodon/Diffiable/Settings/SettingsSection.swift @@ -51,7 +51,7 @@ extension SettingsSection { } cell.delegate = settingsAppearanceTableViewCellDelegate return cell - case .appearancePreference(let record, let appearanceType): + case .appearancePreference(let record, _): let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SettingsToggleTableViewCell.self), for: indexPath) as! SettingsToggleTableViewCell cell.delegate = settingsToggleCellDelegate managedObjectContext.performAndWait { diff --git a/Mastodon/Extension/MastodonSDK/Mastodon+Entity+Tag.swift b/Mastodon/Extension/MastodonSDK/Mastodon+Entity+Tag.swift index e217d3a82..6251d1814 100644 --- a/Mastodon/Extension/MastodonSDK/Mastodon+Entity+Tag.swift +++ b/Mastodon/Extension/MastodonSDK/Mastodon+Entity+Tag.swift @@ -7,13 +7,12 @@ import MastodonSDK -extension Mastodon.Entity.Tag: Hashable { - public func hash(into hasher: inout Hasher) { - hasher.combine(name) - } - - public static func == (lhs: Mastodon.Entity.Tag, rhs: Mastodon.Entity.Tag) -> Bool { - return lhs.name == rhs.name - } -} - +//extension Mastodon.Entity.Tag: Hashable { +// public func hash(into hasher: inout Hasher) { +// hasher.combine(name) +// } +// +// public static func == (lhs: Mastodon.Entity.Tag, rhs: Mastodon.Entity.Tag) -> Bool { +// return lhs.name == rhs.name +// } +//} diff --git a/Mastodon/Extension/UINavigationController.swift b/Mastodon/Extension/UINavigationController.swift deleted file mode 100644 index 9a9c44ab3..000000000 --- a/Mastodon/Extension/UINavigationController.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// UINavigationController.swift -// Mastodon -// -// Created by MainasuK Cirno on 2021-3-31. -// - -import UIKit - -// This not works! -// SeeAlso: `AdaptiveStatusBarStyleNavigationController` -extension UINavigationController { - open override var childForStatusBarStyle: UIViewController? { - return visibleViewController - } -} diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 6dec562da..c93fd9a65 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -30,7 +30,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.4.0 + 1.4.1 CFBundleURLTypes @@ -43,7 +43,7 @@ CFBundleVersion - 121 + 126 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+SearchHistory.swift b/Mastodon/Protocol/Provider/DataSourceFacade+SearchHistory.swift index cbc6bf348..8beaabbae 100644 --- a/Mastodon/Protocol/Provider/DataSourceFacade+SearchHistory.swift +++ b/Mastodon/Protocol/Provider/DataSourceFacade+SearchHistory.swift @@ -99,7 +99,7 @@ extension DataSourceFacade { try await managedObjectContext.performChanges { guard let authenticationBox = _authenticationBox else { return } - guard let me = authenticationBox.authenticationRecord.object(in: managedObjectContext)?.user else { return } + guard let _ = authenticationBox.authenticationRecord.object(in: managedObjectContext)?.user else { return } let request = SearchHistory.sortedFetchRequest request.predicate = SearchHistory.predicate( domain: authenticationBox.domain, diff --git a/Mastodon/Protocol/Provider/DataSourceProvider+NotificationTableViewCellDelegate.swift b/Mastodon/Protocol/Provider/DataSourceProvider+NotificationTableViewCellDelegate.swift index f6e58673b..ca7fdeb18 100644 --- a/Mastodon/Protocol/Provider/DataSourceProvider+NotificationTableViewCellDelegate.swift +++ b/Mastodon/Protocol/Provider/DataSourceProvider+NotificationTableViewCellDelegate.swift @@ -486,7 +486,7 @@ extension NotificationTableViewCellDelegate where Self: DataSourceProvider { provider: self, user: user ) - case .notification(let notification): + case .notification: assertionFailure("TODO") default: assertionFailure("TODO") diff --git a/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift b/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift index 9e5838e77..f00e14840 100644 --- a/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift +++ b/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift @@ -494,7 +494,7 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider { provider: self, user: user ) - case .notification(let notification): + case .notification: assertionFailure("TODO") default: assertionFailure("TODO") diff --git a/Mastodon/Protocol/Provider/DataSourceProvider+TableViewControllerNavigateable.swift b/Mastodon/Protocol/Provider/DataSourceProvider+TableViewControllerNavigateable.swift index f7e50cff8..50fa17866 100644 --- a/Mastodon/Protocol/Provider/DataSourceProvider+TableViewControllerNavigateable.swift +++ b/Mastodon/Protocol/Provider/DataSourceProvider+TableViewControllerNavigateable.swift @@ -138,7 +138,7 @@ extension TableViewControllerNavigateableCore where Self: DataSourceProvider { target: .status, status: record ) - case .notification(let record): + case .notification: assertionFailure() default: assertionFailure() diff --git a/Mastodon/Protocol/Provider/DataSourceProvider+UITableViewDelegate.swift b/Mastodon/Protocol/Provider/DataSourceProvider+UITableViewDelegate.swift index 3968df110..c00c36971 100644 --- a/Mastodon/Protocol/Provider/DataSourceProvider+UITableViewDelegate.swift +++ b/Mastodon/Protocol/Provider/DataSourceProvider+UITableViewDelegate.swift @@ -93,7 +93,7 @@ extension UITableViewDelegate where Self: DataSourceProvider & MediaPreviewableV guard let image = mediaView.thumbnail(), let assetURLString = mediaView.configuration?.assetURL, let assetURL = URL(string: assetURLString), - let resourceType = mediaView.configuration?.resourceType + let _ = mediaView.configuration?.resourceType else { // not provide preview unless thumbnail ready return nil diff --git a/Mastodon/Scene/Account/AccountViewController.swift b/Mastodon/Scene/Account/AccountViewController.swift index 42c9e1d62..20d7b26a1 100644 --- a/Mastodon/Scene/Account/AccountViewController.swift +++ b/Mastodon/Scene/Account/AccountViewController.swift @@ -118,7 +118,7 @@ extension AccountListViewController { // the presentingViewController may deinit. // Hold it and check the window to prevent PanModel crash - guard let presentingViewController = presentingViewController else { return } + guard let _ = presentingViewController else { return } guard self.view.window != nil else { return } self.hasLoaded = true diff --git a/Mastodon/Scene/Compose/AutoComplete/AutoCompleteViewModel+State.swift b/Mastodon/Scene/Compose/AutoComplete/AutoCompleteViewModel+State.swift index ebda78a1e..632b57b66 100644 --- a/Mastodon/Scene/Compose/AutoComplete/AutoCompleteViewModel+State.swift +++ b/Mastodon/Scene/Compose/AutoComplete/AutoCompleteViewModel+State.swift @@ -77,7 +77,7 @@ extension AutoCompleteViewModel.State { override func didEnter(from previousState: GKState?) { super.didEnter(from: previousState) - guard let viewModel = viewModel, let stateMachine = stateMachine else { return } + guard let viewModel = viewModel, let _ = stateMachine else { return } let searchText = viewModel.inputText.value let searchType = AutoCompleteViewModel.SearchType(inputText: searchText) ?? .default diff --git a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift index 8da975de2..92b84d176 100644 --- a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift +++ b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewModel+State.swift @@ -68,7 +68,7 @@ extension DiscoveryNewsViewModel.State { override func didEnter(from previousState: GKState?) { super.didEnter(from: previousState) - guard let viewModel = viewModel, let stateMachine = stateMachine else { return } + guard let _ = viewModel, let stateMachine = stateMachine else { return } stateMachine.enter(Loading.self) } diff --git a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift index b3a8ca040..3b8db5d56 100644 --- a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift +++ b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift @@ -28,7 +28,7 @@ final class HashtagTimelineViewController: UIViewController, NeedsDependency, Me let composeBarButtonItem: UIBarButtonItem = { let barButtonItem = UIBarButtonItem() - barButtonItem.image = UIImage(systemName: "square.and.pencil")?.withRenderingMode(.alwaysTemplate) + barButtonItem.image = Asset.ObjectsAndTools.squareAndPencil.image.withRenderingMode(.alwaysTemplate) return barButtonItem }() diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift index 8b6eb9f42..4fae66d33 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+DebugAction.swift @@ -186,7 +186,7 @@ extension HomeTimelineViewController { } func match(item: StatusItem) -> Bool { - let authenticationBox = AppContext.shared.authenticationService.activeMastodonAuthenticationBox.value + // let authenticationBox = AppContext.shared.authenticationService.activeMastodonAuthenticationBox.value switch item { case .feed(let record): guard let feed = record.object(in: AppContext.shared.managedObjectContext) else { return false } diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift index 549552725..64d3d5941 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift @@ -51,19 +51,11 @@ final class HomeTimelineViewController: UIViewController, NeedsDependency, Media let settingBarButtonItem: UIBarButtonItem = { let barButtonItem = UIBarButtonItem() barButtonItem.tintColor = ThemeService.tintColor - barButtonItem.image = UIImage(systemName: "gear")?.withRenderingMode(.alwaysTemplate) + barButtonItem.image = Asset.ObjectsAndTools.gear.image.withRenderingMode(.alwaysTemplate) barButtonItem.accessibilityLabel = L10n.Common.Controls.Actions.settings return barButtonItem }() - let composeBarButtonItem: UIBarButtonItem = { - let barButtonItem = UIBarButtonItem() - barButtonItem.tintColor = ThemeService.tintColor - barButtonItem.image = UIImage(systemName: "square.and.pencil")?.withRenderingMode(.alwaysTemplate) - barButtonItem.accessibilityLabel = L10n.Common.Controls.Actions.compose - return barButtonItem - }() - let tableView: UITableView = { let tableView = ControlContainableTableView() tableView.register(StatusTableViewCell.self, forCellReuseIdentifier: String(describing: StatusTableViewCell.self)) @@ -109,14 +101,14 @@ extension HomeTimelineViewController { guard let self = self else { return } #if DEBUG // display debug menu - self.navigationItem.leftBarButtonItem = { + self.navigationItem.rightBarButtonItem = { let barButtonItem = UIBarButtonItem() barButtonItem.image = UIImage(systemName: "ellipsis.circle") barButtonItem.menu = self.debugMenu return barButtonItem }() #else - self.navigationItem.leftBarButtonItem = displaySettingBarButtonItem ? self.settingBarButtonItem : nil + self.navigationItem.rightBarButtonItem = displaySettingBarButtonItem ? self.settingBarButtonItem : nil #endif } .store(in: &disposeBag) @@ -133,16 +125,6 @@ extension HomeTimelineViewController { titleView.button.menu = self.debugMenu #endif - viewModel.$displayComposeBarButtonItem - .receive(on: DispatchQueue.main) - .sink { [weak self] displayComposeBarButtonItem in - guard let self = self else { return } - self.navigationItem.rightBarButtonItem = displayComposeBarButtonItem ? self.composeBarButtonItem : nil - } - .store(in: &disposeBag) - composeBarButtonItem.target = self - composeBarButtonItem.action = #selector(HomeTimelineViewController.composeBarButtonItemPressed(_:)) - navigationItem.titleView = titleView titleView.delegate = self @@ -411,18 +393,7 @@ extension HomeTimelineViewController { let settingsViewModel = SettingsViewModel(context: context, setting: setting) coordinator.present(scene: .settings(viewModel: settingsViewModel), from: self, transition: .modal(animated: true, completion: nil)) } - - @objc private func composeBarButtonItemPressed(_ sender: UIBarButtonItem) { - os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) - guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return } - let composeViewModel = ComposeViewModel( - context: context, - composeKind: .post, - authenticationBox: authenticationBox - ) - coordinator.present(scene: .compose(viewModel: composeViewModel), from: self, transition: .modal(animated: true, completion: nil)) - } - + @objc private func refreshControlValueChanged(_ sender: UIRefreshControl) { guard viewModel.loadLatestStateMachine.enter(HomeTimelineViewModel.LoadLatestState.Loading.self) else { sender.endRefreshing() diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift index b2c280fb5..be7de3a5a 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift @@ -33,7 +33,6 @@ final class HomeTimelineViewModel: NSObject { @Published var lastAutomaticFetchTimestamp: Date? = nil @Published var scrollPositionRecord: ScrollPositionRecord? = nil @Published var displaySettingBarButtonItem = true - @Published var displayComposeBarButtonItem = true weak var tableView: UITableView? weak var timelineMiddleLoaderTableViewCellDelegate: TimelineMiddleLoaderTableViewCellDelegate? diff --git a/Mastodon/Scene/Profile/Header/ProfileHeaderViewModel.swift b/Mastodon/Scene/Profile/Header/ProfileHeaderViewModel.swift index 7f7b0dd00..8bdce2a6d 100644 --- a/Mastodon/Scene/Profile/Header/ProfileHeaderViewModel.swift +++ b/Mastodon/Scene/Profile/Header/ProfileHeaderViewModel.swift @@ -90,7 +90,10 @@ extension ProfileHeaderViewModel { extension ProfileHeaderViewModel { static func normalize(note: String?) -> String? { - guard let note = note?.trimmingCharacters(in: .whitespacesAndNewlines),!note.isEmpty else { + let _note = note?.replacingOccurrences(of: "
|
", with: "\u{2028}", options: .regularExpression, range: nil) + .replacingOccurrences(of: "

", with: "

\u{2029}", range: nil) + .trimmingCharacters(in: .whitespacesAndNewlines) + guard let note = _note, !note.isEmpty else { return nil } diff --git a/Mastodon/Scene/Profile/ProfileViewController.swift b/Mastodon/Scene/Profile/ProfileViewController.swift index 55a952b0e..b376ebcf9 100644 --- a/Mastodon/Scene/Profile/ProfileViewController.swift +++ b/Mastodon/Scene/Profile/ProfileViewController.swift @@ -42,19 +42,34 @@ final class ProfileViewController: UIViewController, NeedsDependency, MediaPrevi }() private(set) lazy var settingBarButtonItem: UIBarButtonItem = { - let barButtonItem = UIBarButtonItem(image: UIImage(systemName: "gear"), style: .plain, target: self, action: #selector(ProfileViewController.settingBarButtonItemPressed(_:))) + let barButtonItem = UIBarButtonItem( + image: Asset.ObjectsAndTools.gear.image.withRenderingMode(.alwaysTemplate), + style: .plain, + target: self, + action: #selector(ProfileViewController.settingBarButtonItemPressed(_:)) + ) barButtonItem.tintColor = .white return barButtonItem }() private(set) lazy var shareBarButtonItem: UIBarButtonItem = { - let barButtonItem = UIBarButtonItem(image: UIImage(systemName: "square.and.arrow.up"), style: .plain, target: self, action: #selector(ProfileViewController.shareBarButtonItemPressed(_:))) + let barButtonItem = UIBarButtonItem( + image: Asset.Arrow.squareAndArrowUp.image.withRenderingMode(.alwaysTemplate), + style: .plain, + target: self, + action: #selector(ProfileViewController.shareBarButtonItemPressed(_:)) + ) barButtonItem.tintColor = .white return barButtonItem }() private(set) lazy var favoriteBarButtonItem: UIBarButtonItem = { - let barButtonItem = UIBarButtonItem(image: UIImage(systemName: "star"), style: .plain, target: self, action: #selector(ProfileViewController.favoriteBarButtonItemPressed(_:))) + let barButtonItem = UIBarButtonItem( + image: Asset.ObjectsAndTools.star.image.withRenderingMode(.alwaysTemplate), + style: .plain, + target: self, + action: #selector(ProfileViewController.favoriteBarButtonItemPressed(_:)) + ) barButtonItem.tintColor = .white return barButtonItem }() @@ -619,7 +634,7 @@ extension ProfileViewController { return nil } let name = user.displayNameWithFallback - let record = ManagedObjectRecord(objectID: user.objectID) + let _ = ManagedObjectRecord(objectID: user.objectID) let menu = MastodonMenu.setupMenu( actions: [ .muteUser(.init(name: name, isMuting: self.viewModel.isMuting.value)), @@ -634,7 +649,7 @@ extension ProfileViewController { .sink { [weak self] completion in guard let self = self else { return } switch completion { - case .failure(let error): + case .failure: self.moreMenuBarButtonItem.menu = nil case .finished: break @@ -938,6 +953,7 @@ extension ProfileViewController: ProfileHeaderViewDelegate { viewModel.isUpdating.value = true Task { do { + // TODO: handle error _ = try await viewModel.updateProfileInfo( headerProfileInfo: profileHeaderViewModel.editProfileInfo, aboutProfileInfo: profileAboutViewModel.editProfileInfo diff --git a/Mastodon/Scene/Root/ContentSplitViewController.swift b/Mastodon/Scene/Root/ContentSplitViewController.swift index 5a34e1ed8..03e203107 100644 --- a/Mastodon/Scene/Root/ContentSplitViewController.swift +++ b/Mastodon/Scene/Root/ContentSplitViewController.swift @@ -38,7 +38,6 @@ final class ContentSplitViewController: UIViewController, NeedsDependency { private(set) lazy var mainTabBarController: MainTabBarController = { let mainTabBarController = MainTabBarController(context: context, coordinator: coordinator) if let homeTimelineViewController = mainTabBarController.viewController(of: HomeTimelineViewController.self) { - homeTimelineViewController.viewModel.displayComposeBarButtonItem = false homeTimelineViewController.viewModel.displaySettingBarButtonItem = false } return mainTabBarController @@ -83,7 +82,8 @@ extension ContentSplitViewController { .sink(receiveValue: { [weak self] tab in guard let self = self else { return } self.mainTabBarController.selectedIndex = tab.rawValue - self.mainTabBarController.currentTab.value = tab + self.mainTabBarController.currentTab = tab + self.sidebarViewController.viewModel.currentTab = tab }) .store(in: &disposeBag) } diff --git a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift index 7ea748a60..8970e2f29 100644 --- a/Mastodon/Scene/Root/MainTab/MainTabBarController.swift +++ b/Mastodon/Scene/Root/MainTab/MainTabBarController.swift @@ -22,14 +22,29 @@ class MainTabBarController: UITabBarController { weak var context: AppContext! weak var coordinator: SceneCoordinator! + let composeButttonShadowBackgroundContainer = ShadowBackgroundContainer() + let composeButton: UIButton = { + let button = UIButton() + button.setImage(Asset.ObjectsAndTools.squareAndPencil.image.withRenderingMode(.alwaysTemplate), for: .normal) + button.setBackgroundImage(UIImage.placeholder(color: Asset.Colors.Label.primary.color), for: .normal) + button.setBackgroundImage(UIImage.placeholder(color: Asset.Colors.Label.primary.color.withAlphaComponent(0.8)), for: .highlighted) + button.tintColor = Asset.Colors.Label.primaryReverse.color + button.contentEdgeInsets = UIEdgeInsets(top: 6, left: 12, bottom: 6, right: 12) + button.layer.masksToBounds = true + button.layer.cornerCurve = .continuous + button.layer.cornerRadius = 8 + return button + }() + static let avatarButtonSize = CGSize(width: 25, height: 25) let avatarButton = CircleAvatarButton() - var currentTab = CurrentValueSubject(.home) + @Published var currentTab: Tab = .home enum Tab: Int, CaseIterable { case home case search + case compose case notification case me @@ -41,6 +56,7 @@ class MainTabBarController: UITabBarController { switch self { case .home: return L10n.Common.Controls.Tabs.home case .search: return L10n.Common.Controls.Tabs.search + case .compose: return L10n.Common.Controls.Actions.compose case .notification: return L10n.Common.Controls.Tabs.notification case .me: return L10n.Common.Controls.Tabs.profile } @@ -48,28 +64,41 @@ class MainTabBarController: UITabBarController { var image: UIImage { switch self { - case .home: return UIImage(systemName: "house.fill")! - case .search: return UIImage(systemName: "magnifyingglass")! - case .notification: return UIImage(systemName: "bell.fill")! + case .home: return Asset.ObjectsAndTools.house.image.withRenderingMode(.alwaysTemplate) + case .search: return Asset.ObjectsAndTools.magnifyingglass.image.withRenderingMode(.alwaysTemplate) + case .compose: return Asset.ObjectsAndTools.squareAndPencil.image.withRenderingMode(.alwaysTemplate) + case .notification: return Asset.ObjectsAndTools.bell.image.withRenderingMode(.alwaysTemplate) + case .me: return UIImage(systemName: "person")! + } + } + + var selectedImage: UIImage { + switch self { + case .home: return Asset.ObjectsAndTools.houseFill.image.withRenderingMode(.alwaysTemplate) + case .search: return Asset.ObjectsAndTools.magnifyingglassFill.image.withRenderingMode(.alwaysTemplate) + case .compose: return Asset.ObjectsAndTools.squareAndPencil.image.withRenderingMode(.alwaysTemplate) + case .notification: return Asset.ObjectsAndTools.bellFill.image.withRenderingMode(.alwaysTemplate) case .me: return UIImage(systemName: "person.fill")! } } var largeImage: UIImage { switch self { - case .home: return UIImage(systemName: "house.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 80))! - case .search: return UIImage(systemName: "magnifyingglass", withConfiguration: UIImage.SymbolConfiguration(pointSize: 80))! - case .notification: return UIImage(systemName: "bell.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 80))! - case .me: return UIImage(systemName: "person.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 80))! + case .home: return Asset.ObjectsAndTools.house.image.withRenderingMode(.alwaysTemplate).resized(size: CGSize(width: 80, height: 80)) + case .search: return Asset.ObjectsAndTools.magnifyingglass.image.withRenderingMode(.alwaysTemplate).resized(size: CGSize(width: 80, height: 80)) + case .compose: return Asset.ObjectsAndTools.squareAndPencil.image.withRenderingMode(.alwaysTemplate).resized(size: CGSize(width: 80, height: 80)) + case .notification: return Asset.ObjectsAndTools.bell.image.withRenderingMode(.alwaysTemplate).resized(size: CGSize(width: 80, height: 80)) + case .me: return UIImage(systemName: "person", withConfiguration: UIImage.SymbolConfiguration(pointSize: 80))! } } var sidebarImage: UIImage { switch self { - case .home: return UIImage(systemName: "house")! - case .search: return UIImage(systemName: "magnifyingglass")! - case .notification: return UIImage(systemName: "bell")! - case .me: return UIImage(systemName: "person.fill")! + case .home: return Asset.ObjectsAndTools.house.image.withRenderingMode(.alwaysTemplate) + case .search: return Asset.ObjectsAndTools.magnifyingglass.image.withRenderingMode(.alwaysTemplate) + case .compose: return Asset.ObjectsAndTools.squareAndPencil.image.withRenderingMode(.alwaysTemplate) + case .notification: return Asset.ObjectsAndTools.bell.image.withRenderingMode(.alwaysTemplate) + case .me: return UIImage(systemName: "person")! } } @@ -86,6 +115,8 @@ class MainTabBarController: UITabBarController { _viewController.context = context _viewController.coordinator = coordinator viewController = _viewController + case .compose: + viewController = UIViewController() case .notification: let _viewController = NotificationViewController() _viewController.context = context @@ -143,24 +174,30 @@ extension MainTabBarController { } .store(in: &disposeBag) + // seealso: `ThemeService.apply(theme:)` let tabs = Tab.allCases let viewControllers: [UIViewController] = tabs.map { tab in let viewController = tab.viewController(context: context, coordinator: coordinator) viewController.tabBarItem.tag = tab.tag - viewController.tabBarItem.title = tab.title - viewController.tabBarItem.image = tab.image + viewController.tabBarItem.title = tab.title // needs for acessiblity large content label + viewController.tabBarItem.image = tab.image.imageWithoutBaseline() + viewController.tabBarItem.selectedImage = tab.selectedImage.imageWithoutBaseline() + viewController.tabBarItem.largeContentSizeImage = tab.largeImage.imageWithoutBaseline() viewController.tabBarItem.accessibilityLabel = tab.title - viewController.tabBarItem.largeContentSizeImage = tab.largeImage viewController.tabBarItem.imageInsets = UIEdgeInsets(top: 6, left: 0, bottom: -6, right: 0) + + switch tab { + case .compose: + viewController.tabBarItem.isEnabled = false + default: + break + } + return viewController } _viewControllers = viewControllers setViewControllers(viewControllers, animated: false) selectedIndex = 0 - - UITabBarItem.appearance().setTitleTextAttributes([.foregroundColor : UIColor.clear], for: .normal) - UITabBarItem.appearance().setTitleTextAttributes([.foregroundColor : UIColor.clear], for: .highlighted) - UITabBarItem.appearance().setTitleTextAttributes([.foregroundColor : UIColor.clear], for: .selected) context.apiService.error .receive(on: DispatchQueue.main) @@ -208,13 +245,15 @@ extension MainTabBarController { } .store(in: &disposeBag) - // handle push notification. toggle entry when finish fetch latest notification - Publishers.CombineLatest( + // handle push notification. + // toggle entry when finish fetch latest notification + Publishers.CombineLatest3( context.authenticationService.activeMastodonAuthentication, - context.notificationService.unreadNotificationCountDidUpdate + context.notificationService.unreadNotificationCountDidUpdate, + $currentTab ) .receive(on: DispatchQueue.main) - .sink { [weak self] authentication, _ in + .sink { [weak self] authentication, _, currentTab in guard let self = self else { return } guard let notificationViewController = self.notificationViewController else { return } @@ -223,12 +262,19 @@ extension MainTabBarController { return count > 0 } ?? false - let image = hasUnreadPushNotification ? UIImage(systemName: "bell.badge.fill")! : UIImage(systemName: "bell.fill")! - notificationViewController.tabBarItem.image = image - notificationViewController.navigationController?.tabBarItem.image = image + let image: UIImage = { + if currentTab == .notification { + return hasUnreadPushNotification ? Asset.ObjectsAndTools.bellBadgeFill.image.withRenderingMode(.alwaysTemplate) : Asset.ObjectsAndTools.bellFill.image.withRenderingMode(.alwaysTemplate) + } else { + return hasUnreadPushNotification ? Asset.ObjectsAndTools.bellBadge.image.withRenderingMode(.alwaysTemplate) : Asset.ObjectsAndTools.bell.image.withRenderingMode(.alwaysTemplate) + } + }() + notificationViewController.tabBarItem.image = image.imageWithoutBaseline() + notificationViewController.navigationController?.tabBarItem.image = image.imageWithoutBaseline() } .store(in: &disposeBag) + layoutComposeButton() layoutAvatarButton() $avatarURL @@ -280,7 +326,7 @@ extension MainTabBarController { } .store(in: &disposeBag) - currentTab + $currentTab .receive(on: DispatchQueue.main) .sink { [weak self] tab in guard let self = self else { return } @@ -290,6 +336,8 @@ extension MainTabBarController { updateTabBarDisplay() + composeButton.addTarget(self, action: #selector(MainTabBarController.composeButtonDidPressed(_:)), for: .touchUpInside) + #if DEBUG // Debug Register viewController // Task { @MainActor in @@ -307,23 +355,25 @@ extension MainTabBarController { super.traitCollectionDidChange(previousTraitCollection) updateTabBarDisplay() + updateComposeButtonAppearance() updateAvatarButtonAppearance() } } extension MainTabBarController { - private func updateTabBarDisplay() { - switch traitCollection.horizontalSizeClass { - case .compact: - tabBar.isHidden = false - default: - tabBar.isHidden = true - } + + @objc private func composeButtonDidPressed(_ sender: UIButton) { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)") + guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return } + let composeViewModel = ComposeViewModel( + context: context, + composeKind: .post, + authenticationBox: authenticationBox + ) + coordinator.present(scene: .compose(viewModel: composeViewModel), from: nil, transition: .modal(animated: true, completion: nil)) } -} - -extension MainTabBarController { + @objc private func tabBarLongPressGestureRecognizerHandler(_ sender: UILongPressGestureRecognizer) { guard sender.state == .began else { return } @@ -351,6 +401,59 @@ extension MainTabBarController { } extension MainTabBarController { + + private func updateTabBarDisplay() { + switch traitCollection.horizontalSizeClass { + case .compact: + tabBar.isHidden = false + composeButttonShadowBackgroundContainer.isHidden = false + default: + tabBar.isHidden = true + composeButttonShadowBackgroundContainer.isHidden = true + } + } + + private func layoutComposeButton() { + guard composeButton.superview == nil else { return } + + let _composeTabItem = self.tabBar.items?.first { item in item.tag == Tab.compose.tag } + guard let composeTabItem = _composeTabItem else { return } + guard let view = composeTabItem.value(forKey: "view") as? UIView else { + return + } + + let _anchorImageView = view.subviews.first { subview in subview is UIImageView } as? UIImageView + guard let anchorImageView = _anchorImageView else { + assertionFailure() + return + } + anchorImageView.alpha = 0 + + composeButttonShadowBackgroundContainer.translatesAutoresizingMaskIntoConstraints = false + self.view.addSubview(composeButttonShadowBackgroundContainer) // add to tabBar will crash on iPad when size class changing + NSLayoutConstraint.activate([ + composeButttonShadowBackgroundContainer.centerXAnchor.constraint(equalTo: anchorImageView.centerXAnchor), + composeButttonShadowBackgroundContainer.centerYAnchor.constraint(equalTo: anchorImageView.centerYAnchor), + ]) + composeButttonShadowBackgroundContainer.cornerRadius = composeButton.layer.cornerRadius + + composeButton.translatesAutoresizingMaskIntoConstraints = false + composeButttonShadowBackgroundContainer.addSubview(composeButton) + NSLayoutConstraint.activate([ + composeButton.topAnchor.constraint(equalTo: composeButttonShadowBackgroundContainer.topAnchor), + composeButton.leadingAnchor.constraint(equalTo: composeButttonShadowBackgroundContainer.leadingAnchor), + composeButton.trailingAnchor.constraint(equalTo: composeButttonShadowBackgroundContainer.trailingAnchor), + composeButton.bottomAnchor.constraint(equalTo: composeButttonShadowBackgroundContainer.bottomAnchor), + ]) + composeButton.setContentHuggingPriority(.required - 1, for: .horizontal) + composeButton.setContentHuggingPriority(.required - 1, for: .vertical) + } + + private func updateComposeButtonAppearance() { + composeButton.setBackgroundImage(UIImage.placeholder(color: Asset.Colors.Label.primary.color), for: .normal) + composeButton.setBackgroundImage(UIImage.placeholder(color: Asset.Colors.Label.primary.color.withAlphaComponent(0.8)), for: .highlighted) + } + private func layoutAvatarButton() { guard avatarButton.superview == nil else { return } @@ -370,8 +473,8 @@ extension MainTabBarController { self.avatarButton.translatesAutoresizingMaskIntoConstraints = false view.addSubview(self.avatarButton) NSLayoutConstraint.activate([ - self.avatarButton.centerXAnchor.constraint(equalTo: view.centerXAnchor), - self.avatarButton.centerYAnchor.constraint(equalTo: anchorImageView.centerYAnchor, constant: 1.5), // 1.5pt offset + self.avatarButton.centerXAnchor.constraint(equalTo: anchorImageView.centerXAnchor), + self.avatarButton.centerYAnchor.constraint(equalTo: anchorImageView.centerYAnchor), self.avatarButton.widthAnchor.constraint(equalToConstant: MainTabBarController.avatarButtonSize.width).priority(.required - 1), self.avatarButton.heightAnchor.constraint(equalToConstant: MainTabBarController.avatarButtonSize.height).priority(.required - 1), ]) @@ -381,9 +484,10 @@ extension MainTabBarController { } private func updateAvatarButtonAppearance() { - avatarButton.borderColor = currentTab.value == .me ? .label : .systemFill + avatarButton.borderColor = currentTab == .me ? .label : .systemFill avatarButton.setNeedsLayout() } + } extension MainTabBarController { @@ -403,11 +507,12 @@ extension MainTabBarController: UITabBarControllerDelegate { func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: select %s", ((#file as NSString).lastPathComponent), #line, #function, viewController.debugDescription) defer { - if let tab = Tab(rawValue: tabBarController.selectedIndex) { - currentTab.value = tab + if let tab = Tab(rawValue: viewController.tabBarItem.tag) { + currentTab = tab } } - guard currentTab.value.rawValue == tabBarController.selectedIndex, + // assert index is as same as the tab rawValue + guard currentTab.rawValue == tabBarController.selectedIndex, let navigationController = viewController as? UINavigationController, navigationController.viewControllers.count == 1, let scrollViewContainer = navigationController.topViewController as? ScrollViewContainer else { @@ -478,7 +583,13 @@ extension MainTabBarController { var switchToTabKeyCommands: [UIKeyCommand] { var commands: [UIKeyCommand] = [] - for (i, tab) in Tab.allCases.enumerated() { + let tabs: [Tab] = [ + .home, + .search, + .notification, + .me + ] + for (i, tab) in tabs.enumerated() { let title = L10n.Common.Controls.Keyboard.Common.switchToTab(tab.title) let input = String(i + 1) let command = UIKeyCommand( @@ -584,7 +695,7 @@ extension MainTabBarController { let previousTab = Tab(rawValue: selectedIndex) selectedIndex = index if let tab = Tab(rawValue: index) { - currentTab.value = tab + currentTab = tab } if let previousTab = previousTab { diff --git a/Mastodon/Scene/Root/RootSplitViewController.swift b/Mastodon/Scene/Root/RootSplitViewController.swift index d9b18b0b4..f19282936 100644 --- a/Mastodon/Scene/Root/RootSplitViewController.swift +++ b/Mastodon/Scene/Root/RootSplitViewController.swift @@ -208,7 +208,7 @@ extension RootSplitViewController: UISplitViewControllerDelegate { switch proposedTopColumn { case .compact: RootSplitViewController.transform(from: contentSplitViewController.mainTabBarController, to: compactMainTabBarViewController) - compactMainTabBarViewController.currentTab.value = contentSplitViewController.currentSupplementaryTab + compactMainTabBarViewController.currentTab = contentSplitViewController.currentSupplementaryTab default: assertionFailure() @@ -231,11 +231,11 @@ extension RootSplitViewController: UISplitViewControllerDelegate { RootSplitViewController.transform(from: compactMainTabBarViewController, to: contentSplitViewController.mainTabBarController) - let tab = compactMainTabBarViewController.currentTab.value + let tab = compactMainTabBarViewController.currentTab if tab == .search { contentSplitViewController.currentSupplementaryTab = .home } else { - contentSplitViewController.currentSupplementaryTab = compactMainTabBarViewController.currentTab.value + contentSplitViewController.currentSupplementaryTab = compactMainTabBarViewController.currentTab } return proposedDisplayMode diff --git a/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift index 7ac0f6e54..c7cf3d49d 100644 --- a/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift +++ b/Mastodon/Scene/Root/Sidebar/SidebarViewController.swift @@ -154,10 +154,9 @@ extension SidebarViewController { coordinator.animate { context in self.collectionView.collectionViewLayout.invalidateLayout() - } completion: { [weak self] context in -// guard let self = self else { return } + } completion: { context in + // do nothing } - } } diff --git a/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift b/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift index 3cc277dc6..a6698d6c2 100644 --- a/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift +++ b/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift @@ -22,7 +22,8 @@ final class SidebarViewModel { let context: AppContext @Published private var isSidebarDataSourceReady = false @Published private var isAvatarButtonDataReady = false - + @Published var currentTab: MainTabBarController.Tab = .home + // output var diffableDataSource: UICollectionViewDiffableDataSource? var secondaryDiffableDataSource: UICollectionViewDiffableDataSource? @@ -86,35 +87,55 @@ extension SidebarViewModel { } }() cell.item = SidebarListContentView.Item( + isActive: false, title: item.title, - image: item.sidebarImage, + image: item.image, + activeImage: item.selectedImage, imageURL: imageURL ) cell.setNeedsUpdateConfiguration() cell.isAccessibilityElement = true cell.accessibilityLabel = item.title + self.$currentTab + .receive(on: DispatchQueue.main) + .sink { [weak cell] currentTab in + guard let cell = cell else { return } + cell.item?.isActive = currentTab == item + cell.setNeedsUpdateConfiguration() + } + .store(in: &cell.disposeBag) + switch item { case .notification: - Publishers.CombineLatest( + Publishers.CombineLatest3( self.context.authenticationService.activeMastodonAuthentication, - self.context.notificationService.unreadNotificationCountDidUpdate + self.context.notificationService.unreadNotificationCountDidUpdate, + self.$currentTab ) .receive(on: DispatchQueue.main) - .sink { [weak cell] authentication, _ in + .sink { [weak cell] authentication, _, currentTab in guard let cell = cell else { return } let hasUnreadPushNotification: Bool = authentication.flatMap { authentication in let count = UserDefaults.shared.getNotificationCountWithAccessToken(accessToken: authentication.userAccessToken) return count > 0 } ?? false - let image = hasUnreadPushNotification ? UIImage(systemName: "bell.badge")! : UIImage(systemName: "bell")! - cell._contentView?.imageView.image = image + let image: UIImage = { + if currentTab == .notification { + return hasUnreadPushNotification ? Asset.ObjectsAndTools.bellBadgeFill.image.withRenderingMode(.alwaysTemplate) : Asset.ObjectsAndTools.bellFill.image.withRenderingMode(.alwaysTemplate) + } else { + return hasUnreadPushNotification ? Asset.ObjectsAndTools.bellBadge.image.withRenderingMode(.alwaysTemplate) : Asset.ObjectsAndTools.bell.image.withRenderingMode(.alwaysTemplate) + } + }() + cell.item?.image = image + cell.item?.activeImage = image + cell.setNeedsUpdateConfiguration() } .store(in: &cell.disposeBag) case .me: guard let authentication = self.context.authenticationService.activeMastodonAuthentication.value else { break } - let currentUserDisplayName = authentication.user.displayNameWithFallback ?? "no user" + let currentUserDisplayName = authentication.user.displayNameWithFallback cell.accessibilityHint = L10n.Scene.AccountList.tabBarHint(currentUserDisplayName) default: break @@ -122,7 +143,7 @@ extension SidebarViewModel { } let cellRegistration = UICollectionView.CellRegistration { [weak self] cell, indexPath, item in - guard let self = self else { return } + guard let _ = self else { return } cell.item = item cell.setNeedsUpdateConfiguration() cell.isAccessibilityElement = true @@ -140,15 +161,19 @@ extension SidebarViewModel { return collectionView.dequeueConfiguredReusableCell(using: tabCellRegistration, for: indexPath, item: tab) case .setting: let item = SidebarListContentView.Item( + isActive: false, title: L10n.Common.Controls.Actions.settings, - image: UIImage(systemName: "gear")!, + image: Asset.ObjectsAndTools.gear.image.withRenderingMode(.alwaysTemplate), + activeImage: Asset.ObjectsAndTools.gear.image.withRenderingMode(.alwaysTemplate), imageURL: nil ) return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: item) case .compose: let item = SidebarListContentView.Item( + isActive: false, title: L10n.Common.Controls.Actions.compose, - image: UIImage(systemName: "square.and.pencil")!, + image: Asset.ObjectsAndTools.squareAndPencil.image.withRenderingMode(.alwaysTemplate), + activeImage: Asset.ObjectsAndTools.squareAndPencil.image.withRenderingMode(.alwaysTemplate), imageURL: nil ) return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: item) @@ -192,15 +217,15 @@ extension SidebarViewModel { } let item = SidebarListContentView.Item( + isActive: false, title: L10n.Common.Controls.Actions.compose, - image: UIImage(systemName: "square.and.pencil")!, + image: Asset.ObjectsAndTools.squareAndPencil.image.withRenderingMode(.alwaysTemplate), + activeImage: Asset.ObjectsAndTools.squareAndPencil.image.withRenderingMode(.alwaysTemplate), imageURL: nil ) return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: item) } -// _secondaryDiffableDataSource.supplementaryViewProvider = { collectionView, elementKind, indexPath in -// return nil -// } + secondaryDiffableDataSource = _secondaryDiffableDataSource var secondarySnapshot = NSDiffableDataSourceSnapshot() diff --git a/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift b/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift index d6ae40e17..794563eaf 100644 --- a/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift +++ b/Mastodon/Scene/Root/Sidebar/View/SidebarListContentView.swift @@ -93,12 +93,14 @@ extension SidebarListContentView { // configure model imageView.isHidden = item.imageURL != nil avatarButton.isHidden = item.imageURL == nil - imageView.image = item.image.withRenderingMode(.alwaysTemplate) + imageView.image = item.isActive ? item.activeImage.withRenderingMode(.alwaysTemplate) : item.image.withRenderingMode(.alwaysTemplate) avatarButton.avatarImageView.setImage( url: item.imageURL, placeholder: avatarButton.avatarImageView.image ?? .placeholder(color: .systemFill), // reuse to avoid blink scaleToSize: nil ) + avatarButton.borderWidth = item.isActive ? 2 : 0 + avatarButton.setNeedsLayout() } } @@ -107,25 +109,32 @@ extension SidebarListContentView { // state var isSelected: Bool = false var isHighlighted: Bool = false + var isActive: Bool // model let title: String - let image: UIImage + var image: UIImage + var activeImage: UIImage let imageURL: URL? + static func == (lhs: SidebarListContentView.Item, rhs: SidebarListContentView.Item) -> Bool { return lhs.isSelected == rhs.isSelected && lhs.isHighlighted == rhs.isHighlighted + && lhs.isActive == rhs.isActive && lhs.title == rhs.title && lhs.image == rhs.image + && lhs.activeImage == rhs.activeImage && lhs.imageURL == rhs.imageURL } func hash(into hasher: inout Hasher) { hasher.combine(isSelected) hasher.combine(isHighlighted) + hasher.combine(isActive) hasher.combine(title) hasher.combine(image) + hasher.combine(activeImage) imageURL.flatMap { hasher.combine($0) } } } diff --git a/Mastodon/Scene/Settings/SettingsViewController.swift b/Mastodon/Scene/Settings/SettingsViewController.swift index 4cf20cd09..8455ac7d9 100644 --- a/Mastodon/Scene/Settings/SettingsViewController.swift +++ b/Mastodon/Scene/Settings/SettingsViewController.swift @@ -448,7 +448,7 @@ extension SettingsViewController: SettingsAppearanceTableViewCellDelegate { guard let dataSource = viewModel.dataSource else { return } guard let indexPath = tableView.indexPath(for: cell) else { return } let item = dataSource.itemIdentifier(for: indexPath) - guard case let .appearance(record) = item else { return } + guard case .appearance = item else { return } Task { @MainActor in switch appearanceMode { diff --git a/Mastodon/Scene/Share/NavigationController/AdaptiveStatusBarStyleNavigationController.swift b/Mastodon/Scene/Share/NavigationController/AdaptiveStatusBarStyleNavigationController.swift index aac23285b..f4ad467da 100644 --- a/Mastodon/Scene/Share/NavigationController/AdaptiveStatusBarStyleNavigationController.swift +++ b/Mastodon/Scene/Share/NavigationController/AdaptiveStatusBarStyleNavigationController.swift @@ -10,7 +10,41 @@ import UIKit // Make status bar style adaptive for child view controller // SeeAlso: `modalPresentationCapturesStatusBarAppearance` class AdaptiveStatusBarStyleNavigationController: UINavigationController { + + private lazy var fullWidthBackGestureRecognizer = UIPanGestureRecognizer() + override var childForStatusBarStyle: UIViewController? { visibleViewController } } + +// ref: https://stackoverflow.com/a/60598558/3797903 +extension AdaptiveStatusBarStyleNavigationController { + + override func viewDidLoad() { + super.viewDidLoad() + setupFullWidthBackGesture() + } + + private func setupFullWidthBackGesture() { + // The trick here is to wire up our full-width `fullWidthBackGestureRecognizer` to execute the same handler as + // the system `interactivePopGestureRecognizer`. That's done by assigning the same "targets" (effectively + // object and selector) of the system one to our gesture recognizer. + guard let interactivePopGestureRecognizer = interactivePopGestureRecognizer, + let targets = interactivePopGestureRecognizer.value(forKey: "targets") + else { return } + + fullWidthBackGestureRecognizer.setValue(targets, forKey: "targets") + fullWidthBackGestureRecognizer.delegate = self + view.addGestureRecognizer(fullWidthBackGestureRecognizer) + } +} + +// MARK: - UIGestureRecognizerDelegate +extension AdaptiveStatusBarStyleNavigationController: UIGestureRecognizerDelegate { + func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { + let isSystemSwipeToBackEnabled = interactivePopGestureRecognizer?.isEnabled == true + let isThereStackedViewControllers = viewControllers.count > 1 + return isSystemSwipeToBackEnabled && isThereStackedViewControllers + } +} diff --git a/Mastodon/Scene/Transition/MediaPreview/MediaHostToMediaPreviewViewControllerAnimatedTransitioning.swift b/Mastodon/Scene/Transition/MediaPreview/MediaHostToMediaPreviewViewControllerAnimatedTransitioning.swift index f730e0b8b..1b2d62211 100644 --- a/Mastodon/Scene/Transition/MediaPreview/MediaHostToMediaPreviewViewControllerAnimatedTransitioning.swift +++ b/Mastodon/Scene/Transition/MediaPreview/MediaHostToMediaPreviewViewControllerAnimatedTransitioning.swift @@ -255,6 +255,8 @@ extension MediaHostToMediaPreviewViewControllerAnimatedTransitioning { rect.size.height -= offset return rect }() + + // FIXME: let maskLayerToFinalPath = maskLayerToFinalRect.flatMap { UIBezierPath(rect: $0) }?.cgPath if let maskLayerToPath = maskLayerToPath { diff --git a/Mastodon/Service/APIService/APIService+Thread.swift b/Mastodon/Service/APIService/APIService+Thread.swift index 782da5886..f6c36e5b6 100644 --- a/Mastodon/Service/APIService/APIService+Thread.swift +++ b/Mastodon/Service/APIService/APIService+Thread.swift @@ -34,7 +34,7 @@ extension APIService { let value = response.value.ancestors + response.value.descendants for entity in value { - Persistence.Status.createOrMerge( + _ = Persistence.Status.createOrMerge( in: managedObjectContext, context: Persistence.Status.PersistContext( domain: domain, diff --git a/Mastodon/Service/InstanceService.swift b/Mastodon/Service/InstanceService.swift index 4fb6309fd..03b8dfd4e 100644 --- a/Mastodon/Service/InstanceService.swift +++ b/Mastodon/Service/InstanceService.swift @@ -95,7 +95,7 @@ extension InstanceService { self.logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [Instance] update instance for domain: \(domain)") } } receiveValue: { [weak self] response in - guard let self = self else { return } + guard let _ = self else { return } // do nothing } .store(in: &disposeBag) diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index d08d9c217..3f1630945 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.4.0 + 1.4.1 CFBundleVersion - 121 + 126 NSExtension NSExtensionAttributes diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Arrow/square.and.arrow.up.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Arrow/square.and.arrow.up.imageset/Contents.json new file mode 100644 index 000000000..33c521feb --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Arrow/square.and.arrow.up.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "Share iOS.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Arrow/square.and.arrow.up.imageset/Share iOS.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Arrow/square.and.arrow.up.imageset/Share iOS.pdf new file mode 100644 index 000000000..99e7c6724 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/Arrow/square.and.arrow.up.imageset/Share iOS.pdf @@ -0,0 +1,110 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 5.004150 3.928345 cm +0.000000 0.000000 0.000000 scn +16.750000 11.071655 m +17.129696 11.071655 17.443491 10.789501 17.493153 10.423426 c +17.500000 10.321655 l +17.500000 3.320786 l +17.500000 1.587753 16.143545 0.171539 14.434423 0.075930 c +14.250000 0.070786 l +3.250000 0.070786 l +1.516969 0.070786 0.100754 1.427240 0.005145 3.136362 c +0.000000 3.320786 l +0.000000 10.321655 l +0.000000 10.735868 0.335786 11.071655 0.750000 11.071655 c +1.129696 11.071655 1.443491 10.789501 1.493153 10.423426 c +1.500000 10.321655 l +1.500000 3.320786 l +1.500000 2.402613 2.207110 1.649591 3.106473 1.576586 c +3.250000 1.570786 l +14.250000 1.570786 l +15.168174 1.570786 15.921191 2.277895 15.994198 3.177258 c +16.000000 3.320786 l +16.000000 10.321655 l +16.000000 10.735868 16.335787 11.071655 16.750000 11.071655 c +h +3.215397 14.855352 m +8.211636 19.851965 l +8.477744 20.118093 8.894129 20.142456 9.187749 19.924934 c +9.271878 19.852423 l +14.276731 14.855809 l +14.569866 14.563158 14.570257 14.088284 14.277605 13.795150 c +14.011558 13.528664 13.594913 13.504115 13.301123 13.721727 c +13.216944 13.794276 l +9.493999 17.510654 l +9.494885 5.816710 l +9.494885 5.437014 9.212732 5.123218 8.846657 5.073555 c +8.744885 5.066710 l +8.365190 5.066710 8.051395 5.348864 8.001733 5.714939 c +7.994885 5.816710 l +7.993999 17.513655 l +4.276096 13.794732 l +4.009840 13.528456 3.593178 13.504234 3.299558 13.722077 c +3.215437 13.794693 l +2.949160 14.060949 2.924938 14.477612 3.142782 14.771232 c +3.215397 14.855352 l +8.211636 19.851965 l +3.215397 14.855352 l +h +f +n +Q + +endstream +endobj + +3 0 obj + 1600 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 28.000000 28.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000001690 00000 n +0000001713 00000 n +0000001886 00000 n +0000001960 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +2019 +%%EOF \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.fill.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.fill.imageset/Contents.json new file mode 100644 index 000000000..956d7c99c --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.fill.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "bell.badge.fill.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.fill.imageset/bell.badge.fill.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.fill.imageset/bell.badge.fill.pdf new file mode 100644 index 000000000..10b05f319 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.fill.imageset/bell.badge.fill.pdf @@ -0,0 +1,94 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 4.000000 3.251190 cm +0.000000 0.000000 0.000000 scn +17.228973 14.106000 m +17.604315 14.106000 17.967243 14.159944 18.310644 14.260609 c +18.330521 14.022223 18.340664 13.781026 18.340664 13.537420 c +18.340664 9.025727 l +19.917404 5.460056 l +19.978443 5.322020 20.010000 5.172432 20.010000 5.021130 c +20.010000 4.429121 19.537165 3.949203 18.953897 3.949203 c +1.056364 3.949203 l +0.907638 3.949203 0.760588 3.981087 0.624843 4.042767 c +0.092485 4.284660 -0.145878 4.918783 0.092444 5.459118 c +1.665367 9.025314 l +1.665486 13.551995 l +1.670396 13.833986 l +1.824999 18.382032 5.507209 22.000000 10.003014 22.000000 c +11.607554 22.000000 13.106230 21.539965 14.378001 20.742750 c +13.732699 20.037863 13.338069 19.093309 13.338069 18.055204 c +13.338069 15.874119 15.080086 14.106000 17.228973 14.106000 c +h +13.291688 2.819208 m +13.026393 1.219061 11.654965 0.000000 10.003014 0.000000 c +8.351062 0.000000 6.979633 1.219061 6.714338 2.819208 c +13.291688 2.819208 l +h +17.228973 15.234344 m +18.763893 15.234344 20.008190 16.497286 20.008190 18.055204 c +20.008190 19.613121 18.763893 20.876064 17.228973 20.876064 c +15.694054 20.876064 14.449756 19.613121 14.449756 18.055204 c +14.449756 16.497286 15.694054 15.234344 17.228973 15.234344 c +h +f +n +Q + +endstream +endobj + +3 0 obj + 1305 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 28.000000 28.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000001395 00000 n +0000001418 00000 n +0000001591 00000 n +0000001665 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +1724 +%%EOF \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.imageset/Contents.json new file mode 100644 index 000000000..7e5adf71d --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "bell.badge.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.imageset/bell.badge.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.imageset/bell.badge.pdf new file mode 100644 index 000000000..0aa1ebbd9 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.badge.imageset/bell.badge.pdf @@ -0,0 +1,112 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 4.000000 3.000000 cm +0.000000 0.000000 0.000000 scn +9.991263 22.000000 m +11.600367 22.000000 13.104079 21.540958 14.379686 20.742632 c +13.999659 20.330532 13.705750 19.835861 13.527027 19.288073 c +12.501425 19.935305 11.289410 20.308149 9.991263 20.308149 c +6.295337 20.308149 3.312736 17.291861 3.312205 13.540749 c +3.312205 8.567127 l +1.816118 5.077236 l +18.175934 5.077236 l +16.670322 8.566052 l +16.670446 13.526248 l +16.666271 13.780252 l +16.662128 13.902481 16.654818 14.023849 16.644423 14.144276 c +16.834492 14.115398 17.029049 14.100430 17.227058 14.100430 c +17.602913 14.100430 17.966335 14.154360 18.310204 14.254990 c +18.322084 14.112284 18.330519 13.968523 18.335421 13.823792 c +18.340088 13.540749 l +18.340088 8.919773 l +19.876272 5.360107 l +19.953144 5.181980 19.992825 4.989672 19.992825 4.795261 c +19.992825 4.016609 19.369843 3.385387 18.601355 3.385387 c +13.330793 3.383699 l +13.330793 1.514933 11.835634 -0.000002 9.991263 -0.000002 c +8.212763 -0.000002 6.758977 1.408655 6.657403 3.184881 c +6.651230 3.386263 l +1.391824 3.385387 l +1.201094 3.385387 1.012400 3.425116 0.837460 3.502110 c +0.132594 3.812326 -0.190615 4.642769 0.115552 5.356956 c +1.642440 8.918699 l +1.642440 13.540869 l +1.643104 18.227058 5.373904 22.000000 9.991263 22.000000 c +h +11.660524 3.386263 m +8.321499 3.383699 l +8.321499 2.449318 9.069077 1.691849 9.991263 1.691849 c +10.859203 1.691849 11.572474 2.362822 11.653385 3.220762 c +11.660524 3.386263 l +h +14.488358 18.551571 m +14.594155 19.146286 14.884010 19.676186 15.296021 20.078548 c +15.796463 20.567268 16.477119 20.867832 17.227058 20.867832 c +18.764036 20.867832 20.010000 19.605387 20.010000 18.048080 c +20.010000 16.815081 19.228939 15.766922 18.140787 15.383841 c +17.854582 15.283082 17.547131 15.228331 17.227058 15.228331 c +16.950932 15.228331 16.684196 15.269077 16.432392 15.344961 c +15.282606 15.691461 14.444118 16.770555 14.444118 18.048080 c +14.444118 18.219936 14.459294 18.388199 14.488358 18.551571 c +h +f +n +Q + +endstream +endobj + +3 0 obj + 2038 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 28.000000 28.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000002128 00000 n +0000002151 00000 n +0000002324 00000 n +0000002398 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +2457 +%%EOF \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.fill.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.fill.imageset/Contents.json new file mode 100644 index 000000000..eea5ce48f --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.fill.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "bell.fill.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.fill.imageset/bell.fill.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.fill.imageset/bell.fill.pdf new file mode 100644 index 000000000..b738813f8 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.fill.imageset/bell.fill.pdf @@ -0,0 +1,88 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 3.994385 2.997498 cm +0.000000 0.000000 0.000000 scn +13.471207 3.000130 m +13.228097 1.303843 11.769090 0.000013 10.005556 0.000013 c +8.242023 0.000013 6.783014 1.303843 6.539904 3.000130 c +13.471207 3.000130 l +h +10.005556 22.002502 m +14.615297 22.002502 18.368101 18.333513 18.503042 13.756456 c +18.503042 13.501259 l +18.506800 13.501259 l +18.506556 9.389503 l +19.920570 5.745182 l +19.958755 5.646759 19.984545 5.544180 19.997494 5.439810 c +20.007233 5.282207 l +20.007233 4.619465 19.503553 4.074364 18.858105 4.008816 c +18.727232 4.002207 l +1.280344 4.002207 l +1.121637 4.002207 0.964313 4.031721 0.816398 4.089247 c +0.198722 4.329462 -0.126749 4.996468 0.046107 5.621784 c +0.087384 5.746153 l +1.503556 9.390502 l +1.504312 13.501259 l +1.504312 18.196365 5.310449 22.002502 10.005556 22.002502 c +h +f +n +Q + +endstream +endobj + +3 0 obj + 870 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 28.000000 28.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000000960 00000 n +0000000982 00000 n +0000001155 00000 n +0000001229 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +1288 +%%EOF \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.imageset/Contents.json new file mode 100644 index 000000000..da621b2a4 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "bell.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.imageset/bell.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.imageset/bell.pdf new file mode 100644 index 000000000..52a4bea08 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/bell.imageset/bell.pdf @@ -0,0 +1,106 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 3.994385 2.997498 cm +0.000000 0.000000 0.000000 scn +10.005556 22.002502 m +14.615297 22.002502 18.368101 18.333513 18.503042 13.756456 c +18.506800 13.501259 l +18.506556 8.889502 l +19.920570 5.245478 l +19.958755 5.147055 19.984545 5.044476 19.997494 4.940105 c +20.007233 4.782503 l +20.007233 4.119761 19.503553 3.574659 18.858105 3.509111 c +18.727232 3.502502 l +13.506981 3.501438 l +13.506981 1.567654 11.939340 0.000013 10.005556 0.000013 c +8.136232 0.000013 6.609047 1.464890 6.509312 3.309326 c +6.504000 3.503502 l +1.280344 3.502502 l +1.121637 3.502502 0.964313 3.532017 0.816398 3.589542 c +0.198722 3.829758 -0.126749 4.496763 0.046107 5.122080 c +0.087384 5.246449 l +1.503556 8.890503 l +1.504312 13.501259 l +1.504312 18.196365 5.310449 22.002502 10.005556 22.002502 c +h +12.001492 3.352070 m +12.006001 3.503502 l +8.004131 3.501438 l +8.004131 2.396082 8.900200 1.500013 10.005556 1.500013 c +11.060669 1.500013 11.925088 2.316473 12.001492 3.352070 c +h +10.005556 20.502502 m +6.219432 20.502502 3.135237 17.497185 3.008372 13.741951 c +3.004312 13.501259 l +3.004312 8.749136 l +3.004312 8.687140 2.996625 8.625507 2.981514 8.565626 c +2.953312 8.477293 l +1.601556 5.003502 l +18.405556 5.003502 l +17.057579 8.477861 l +17.035206 8.535532 17.020094 8.595635 17.012506 8.656790 c +17.006800 8.749136 l +17.006800 13.501259 l +17.006800 17.367939 13.872236 20.502502 10.005556 20.502502 c +h +f +n +Q + +endstream +endobj + +3 0 obj + 1451 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 28.000000 28.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000001541 00000 n +0000001564 00000 n +0000001737 00000 n +0000001811 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +1870 +%%EOF \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/gear.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/gear.imageset/Contents.json new file mode 100644 index 000000000..8dfa77c79 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/gear.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "gear.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/gear.imageset/gear.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/gear.imageset/gear.pdf new file mode 100644 index 000000000..d0e5607b9 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/gear.imageset/gear.pdf @@ -0,0 +1,155 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 4.639893 4.163849 cm +0.000000 0.000000 0.000000 scn +9.372525 19.586090 m +10.106503 19.577631 10.837610 19.492828 11.554037 19.333052 c +11.866778 19.263306 12.100667 19.002579 12.136167 18.684128 c +12.306372 17.157282 l +12.383412 16.456230 12.975316 15.925249 13.680974 15.924509 c +13.870646 15.924213 14.058271 15.963713 14.233541 16.041258 c +15.634164 16.656530 l +15.925470 16.784498 16.265816 16.714733 16.483282 16.482475 c +17.495462 15.401449 18.249289 14.104940 18.688040 12.690507 c +18.782648 12.385511 18.673761 12.054057 18.416712 11.864587 c +17.175230 10.949497 l +16.821091 10.689301 16.611935 10.276085 16.611935 9.836634 c +16.611935 9.397182 16.821091 8.983968 17.176010 8.723198 c +18.418562 7.807791 l +18.675699 7.618353 18.784660 7.286852 18.690054 6.981801 c +18.251465 5.567602 17.498068 4.271195 16.486473 3.189995 c +16.269207 2.957779 15.929114 2.887827 15.637836 3.015442 c +14.231503 3.631588 l +13.829185 3.807648 13.367112 3.781857 12.986887 3.562117 c +12.606662 3.342377 12.353621 2.954891 12.305302 2.518358 c +12.136227 0.991678 l +12.101363 0.676876 11.872503 0.417910 11.564378 0.344601 c +10.115929 -0.000013 8.606833 -0.000013 7.158383 0.344601 c +6.850258 0.417910 6.621398 0.676876 6.586535 0.991678 c +6.417712 2.516102 l +6.368124 2.951803 6.114693 3.338112 5.734776 3.557108 c +5.354860 3.776103 4.893555 3.801792 4.492552 3.626715 c +3.085926 3.010441 l +2.794572 2.882792 2.454386 2.952816 2.237134 3.185158 c +1.224976 4.267610 0.471545 5.565555 0.033552 6.981297 c +-0.060786 7.286231 0.048213 7.617466 0.305198 7.806790 c +1.548530 8.722771 l +1.902669 8.982967 2.111826 9.396182 2.111826 9.835633 c +2.111826 10.275084 1.902669 10.688300 1.548066 10.948837 c +0.305513 11.863244 l +0.048147 12.052642 -0.060952 12.384308 0.033719 12.689507 c +0.472470 14.103941 1.226297 15.400448 2.238477 16.481474 c +2.455943 16.713732 2.796290 16.783497 3.087596 16.655531 c +4.487972 16.040365 l +4.890913 15.863533 5.354152 15.890244 5.736122 16.113400 c +6.116442 16.334003 6.369638 16.721867 6.418519 17.158447 c +6.588595 18.684128 l +6.624113 19.002741 6.858214 19.263550 7.171155 19.333147 c +7.888429 19.492670 8.620303 19.577436 9.372525 19.586090 c +h +9.372712 18.086191 m +8.918673 18.080845 8.465910 18.041662 8.018175 17.969074 c +7.909245 16.991905 l +7.807416 16.082413 7.280385 15.275068 6.490771 14.817059 c +5.696323 14.352917 4.727715 14.297064 3.884934 14.666923 c +2.986644 15.061529 l +2.414711 14.367364 1.959492 13.584736 1.638873 12.744408 c +2.436671 12.157299 l +3.175481 11.614474 3.611826 10.752420 3.611826 9.835633 c +3.611826 8.918846 3.175481 8.056792 2.437450 7.514541 c +1.638397 6.925866 l +1.958737 6.084057 2.414029 5.299965 2.986352 4.604462 c +3.891485 5.001020 l +4.729578 5.366932 5.691594 5.313361 6.483880 4.856663 c +7.276166 4.399964 7.804679 3.594347 7.908344 2.683468 c +8.017305 1.699598 l +8.906950 1.548321 9.815811 1.548321 10.705456 1.699598 c +10.814412 2.683426 l +10.915205 3.594033 11.443104 4.402411 12.236333 4.860834 c +13.029562 5.319258 13.993543 5.373064 14.833156 5.005638 c +15.737573 4.609392 l +16.309378 5.303812 16.764484 6.086632 17.085032 6.927112 c +16.287088 7.514968 l +15.548278 8.057793 15.111936 8.919847 15.111936 9.836634 c +15.111936 10.753421 15.548280 11.615475 16.286161 12.157617 c +17.083044 12.744996 l +16.762415 13.585482 16.307142 14.368252 15.735116 15.062530 c +14.838643 14.668724 l +14.473309 14.507083 14.078127 14.423886 13.679017 14.424510 c +12.209332 14.426050 10.975889 15.532539 10.815476 16.992264 c +10.706551 17.969393 l +10.261019 18.041893 9.812987 18.080971 9.372712 18.086191 c +h +9.360047 13.586140 m +11.431115 13.586140 13.110047 11.907207 13.110047 9.836140 c +13.110047 7.765072 11.431115 6.086140 9.360047 6.086140 c +7.288980 6.086140 5.610047 7.765072 5.610047 9.836140 c +5.610047 11.907207 7.288980 13.586140 9.360047 13.586140 c +h +9.360047 12.086140 m +8.117407 12.086140 7.110047 11.078780 7.110047 9.836140 c +7.110047 8.593499 8.117407 7.586140 9.360047 7.586140 c +10.602688 7.586140 11.610047 8.593499 11.610047 9.836140 c +11.610047 11.078780 10.602688 12.086140 9.360047 12.086140 c +h +f +n +Q + +endstream +endobj + +3 0 obj + 4141 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 28.000000 28.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000004231 00000 n +0000004254 00000 n +0000004427 00000 n +0000004501 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +4560 +%%EOF \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.fill.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.fill.imageset/Contents.json new file mode 100644 index 000000000..b12998cbd --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.fill.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "Home-fill.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.fill.imageset/Home-fill.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.fill.imageset/Home-fill.pdf new file mode 100644 index 000000000..e8e156e31 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.fill.imageset/Home-fill.pdf @@ -0,0 +1,85 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 4.000000 2.835022 cm +0.000000 0.000000 0.000000 scn +8.592125 21.667089 m +9.414732 22.326954 10.585270 22.326952 11.407875 21.667089 c +19.157869 15.450343 l +19.690231 15.023304 19.999994 14.377716 19.999994 13.695241 c +19.999994 2.414970 l +19.999994 1.172331 18.992638 0.164970 17.749996 0.164970 c +15.250000 0.164970 l +14.007360 0.164970 13.000000 1.172327 13.000000 2.414968 c +13.000000 8.914963 l +13.000000 9.329177 12.664214 9.664963 12.250000 9.664963 c +7.750000 9.664963 l +7.335785 9.664963 7.000000 9.329177 7.000000 8.914964 c +7.000000 2.414970 l +7.000000 1.172331 5.992641 0.164970 4.750000 0.164970 c +2.250000 0.164970 l +1.007360 0.164970 0.000000 1.172327 0.000000 2.414968 c +0.000000 13.695240 l +0.000000 14.377715 0.309763 15.023304 0.842125 15.450343 c +8.592125 21.667089 l +h +f +n +Q + +endstream +endobj + +3 0 obj + 862 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 28.000000 28.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000000952 00000 n +0000000974 00000 n +0000001147 00000 n +0000001221 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +1280 +%%EOF \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.imageset/Contents.json new file mode 100644 index 000000000..968281c21 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "Home.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.imageset/Home.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.imageset/Home.pdf new file mode 100644 index 000000000..1b5772ddd --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/house.imageset/Home.pdf @@ -0,0 +1,105 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 4.000000 2.834961 cm +0.000000 0.000000 0.000000 scn +8.591907 21.668686 m +9.414594 22.328781 10.585405 22.328781 11.408092 21.668686 c +19.158089 15.450356 l +19.690319 15.023312 19.999994 14.377806 19.999994 13.695429 c +19.999994 2.415045 l +19.999994 1.172405 18.992638 0.165045 17.749996 0.165045 c +14.750000 0.165045 l +13.507360 0.165045 12.500000 1.172403 12.500000 2.415045 c +12.500000 8.415037 l +12.500000 8.829250 12.164213 9.165037 11.750000 9.165037 c +8.250000 9.165037 l +7.835786 9.165037 7.500000 8.829250 7.500000 8.415037 c +7.500000 2.415045 l +7.500000 1.172403 6.492640 0.165045 5.250000 0.165045 c +2.250000 0.165045 l +1.007360 0.165045 0.000000 1.172401 0.000000 2.415043 c +0.000000 13.695428 l +0.000000 14.377805 0.309674 15.023312 0.841907 15.450356 c +8.591907 21.668686 l +h +10.469363 20.498734 m +10.195135 20.718765 9.804865 20.718765 9.530635 20.498734 c +1.780635 14.280403 l +1.603225 14.138056 1.500000 13.922887 1.500000 13.695428 c +1.500000 2.415043 l +1.500000 2.000832 1.835786 1.665045 2.250000 1.665045 c +5.250000 1.665045 l +5.664214 1.665045 6.000000 2.000832 6.000000 2.415045 c +6.000000 8.415037 l +6.000000 9.657678 7.007360 10.665037 8.250000 10.665037 c +11.750000 10.665037 l +12.992640 10.665037 14.000000 9.657678 14.000000 8.415037 c +14.000000 2.415045 l +14.000000 2.000832 14.335787 1.665045 14.750000 1.665045 c +17.749996 1.665045 l +18.164207 1.665045 18.499994 2.000830 18.499994 2.415045 c +18.499994 13.695429 l +18.499994 13.922888 18.396770 14.138056 18.219358 14.280403 c +10.469363 20.498734 l +h +f +n +Q + +endstream +endobj + +3 0 obj + 1604 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 28.000000 28.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000001694 00000 n +0000001717 00000 n +0000001890 00000 n +0000001964 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +2023 +%%EOF \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.fill.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.fill.imageset/Contents.json new file mode 100644 index 000000000..6986c762a --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.fill.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "Search-Fill.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.fill.imageset/Search-Fill.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.fill.imageset/Search-Fill.pdf new file mode 100644 index 000000000..26e5a4576 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.fill.imageset/Search-Fill.pdf @@ -0,0 +1,83 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 2.000000 1.855835 cm +0.000000 0.000000 0.000000 scn +9.500000 24.144165 m +14.746705 24.144165 19.000000 19.890869 19.000000 14.644165 c +19.000000 12.562231 18.330292 10.636717 17.194551 9.071299 c +23.560659 2.704824 l +24.146446 2.119038 24.146446 1.169292 23.560659 0.583506 c +23.011484 0.034330 22.142424 0.000008 21.553263 0.480536 c +21.439341 0.583506 l +15.072866 6.949614 l +13.507448 5.813873 11.581934 5.144165 9.500000 5.144165 c +4.253295 5.144165 0.000000 9.397460 0.000000 14.644165 c +0.000000 19.890869 4.253295 24.144165 9.500000 24.144165 c +h +9.500000 21.144165 m +5.910149 21.144165 3.000000 18.234016 3.000000 14.644165 c +3.000000 11.054314 5.910149 8.144165 9.500000 8.144165 c +13.089851 8.144165 16.000000 11.054314 16.000000 14.644165 c +16.000000 18.234016 13.089851 21.144165 9.500000 21.144165 c +h +f +n +Q + +endstream +endobj + +3 0 obj + 887 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 28.000000 28.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000000977 00000 n +0000000999 00000 n +0000001172 00000 n +0000001246 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +1305 +%%EOF \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.imageset/Contents.json new file mode 100644 index 000000000..e4ab2267b --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "Search.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.imageset/Search.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.imageset/Search.pdf new file mode 100644 index 000000000..7bd1758c7 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/magnifyingglass.imageset/Search.pdf @@ -0,0 +1,83 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 2.750000 2.679199 cm +0.000000 0.000000 0.000000 scn +8.750000 22.570801 m +13.582491 22.570801 17.500000 18.653292 17.500000 13.820801 c +17.500000 11.674633 16.727327 9.708933 15.444990 8.186705 c +22.280331 1.351131 l +22.573223 1.058239 22.573223 0.583363 22.280331 0.290470 c +22.014065 0.024204 21.597401 -0.000004 21.303789 0.217852 c +21.219669 0.290470 l +14.384096 7.125811 l +12.861868 5.843473 10.896168 5.070801 8.750000 5.070801 c +3.917509 5.070801 0.000000 8.988310 0.000000 13.820801 c +0.000000 18.653292 3.917509 22.570801 8.750000 22.570801 c +h +8.750000 21.070801 m +4.745935 21.070801 1.500000 17.824865 1.500000 13.820801 c +1.500000 9.816736 4.745935 6.570801 8.750000 6.570801 c +12.754065 6.570801 16.000000 9.816736 16.000000 13.820801 c +16.000000 17.824865 12.754065 21.070801 8.750000 21.070801 c +h +f +n +Q + +endstream +endobj + +3 0 obj + 885 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 28.000000 28.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000000975 00000 n +0000000997 00000 n +0000001170 00000 n +0000001244 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +1303 +%%EOF \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/square.and.pencil.imageset/Contents.json b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/square.and.pencil.imageset/Contents.json new file mode 100644 index 000000000..18bb2201a --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/square.and.pencil.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "square.and.pencil.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/square.and.pencil.imageset/square.and.pencil.pdf b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/square.and.pencil.imageset/square.and.pencil.pdf new file mode 100644 index 000000000..8cb4a15c9 --- /dev/null +++ b/MastodonSDK/Sources/MastodonAsset/Assets.xcassets/ObjectsAndTools/square.and.pencil.imageset/square.and.pencil.pdf @@ -0,0 +1,93 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 3.000000 2.926788 cm +0.000000 0.000000 0.000000 scn +18.780287 17.792883 m +19.073179 18.085777 19.073177 18.560650 18.780285 18.853542 c +18.487391 19.146435 18.012516 19.146435 17.719624 18.853540 c +7.719669 8.853540 l +7.250000 7.323212 l +8.780332 7.792883 l +18.780287 17.792883 l +h +3.249999 18.073212 m +1.455072 18.073212 0.000000 16.618137 0.000000 14.823212 c +0.000000 3.323212 l +0.000000 1.528286 1.455075 0.073212 3.250000 0.073212 c +14.750000 0.073212 l +16.544926 0.073212 18.000000 1.528286 18.000000 3.323212 c +18.000000 11.323212 l +18.000000 11.737425 17.664213 12.073212 17.250000 12.073212 c +16.835787 12.073212 16.500000 11.737425 16.500000 11.323212 c +16.500000 3.323212 l +16.500000 2.356712 15.716498 1.573212 14.750000 1.573212 c +3.250000 1.573212 l +2.283502 1.573212 1.500000 2.356712 1.500000 3.323212 c +1.500000 14.823212 l +1.500000 15.789711 2.283501 16.573212 3.249999 16.573212 c +11.249994 16.573212 l +11.664207 16.573212 11.999994 16.908998 11.999994 17.323212 c +11.999994 17.737425 11.664207 18.073212 11.249994 18.073212 c +3.249999 18.073212 l +h +f +n +Q + +endstream +endobj + +3 0 obj + 1142 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 24.000000 24.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000001232 00000 n +0000001255 00000 n +0000001428 00000 n +0000001502 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +1561 +%%EOF \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift b/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift index 3e7fa5c11..b594f9209 100644 --- a/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift +++ b/MastodonSDK/Sources/MastodonAsset/Generated/Assets.swift @@ -24,6 +24,7 @@ public enum Asset { public enum Arrow { public static let `repeat` = ImageAsset(name: "Arrow/repeat") public static let repeatSmall = ImageAsset(name: "Arrow/repeat.small") + public static let squareAndArrowUp = ImageAsset(name: "Arrow/square.and.arrow.up") } public enum Asset { public static let email = ImageAsset(name: "Asset/email") @@ -99,6 +100,16 @@ public enum Asset { public static let faceSmilingAdaptive = ImageAsset(name: "Human/face.smiling.adaptive") } public enum ObjectsAndTools { + public static let bellBadgeFill = ImageAsset(name: "ObjectsAndTools/bell.badge.fill") + public static let bellBadge = ImageAsset(name: "ObjectsAndTools/bell.badge") + public static let bellFill = ImageAsset(name: "ObjectsAndTools/bell.fill") + public static let bell = ImageAsset(name: "ObjectsAndTools/bell") + public static let gear = ImageAsset(name: "ObjectsAndTools/gear") + public static let houseFill = ImageAsset(name: "ObjectsAndTools/house.fill") + public static let house = ImageAsset(name: "ObjectsAndTools/house") + public static let magnifyingglassFill = ImageAsset(name: "ObjectsAndTools/magnifyingglass.fill") + public static let magnifyingglass = ImageAsset(name: "ObjectsAndTools/magnifyingglass") + public static let squareAndPencil = ImageAsset(name: "ObjectsAndTools/square.and.pencil") public static let starFill = ImageAsset(name: "ObjectsAndTools/star.fill") public static let star = ImageAsset(name: "ObjectsAndTools/star") } diff --git a/MastodonSDK/Sources/MastodonUI/Extension/UIImage.swift b/MastodonSDK/Sources/MastodonUI/Extension/UIImage.swift new file mode 100644 index 000000000..141b723bc --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/Extension/UIImage.swift @@ -0,0 +1,18 @@ +// +// UIImage.swift +// +// +// Created by MainasuK on 2022-5-6. +// + +import UIKit + +extension UIImage { + + public func resized(size: CGSize) -> UIImage { + return UIGraphicsImageRenderer(size: size).image { context in + self.draw(in: CGRect(origin: .zero, size: size)) + } + } + +} diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index a1528e2c5..92f442892 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.4.0 + 1.4.1 CFBundleVersion - 121 + 126 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index a1528e2c5..92f442892 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.4.0 + 1.4.1 CFBundleVersion - 121 + 126 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index 0029eea56..f074db82b 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.4.0 + 1.4.1 CFBundleVersion - 121 + 126 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 25fc34294..31c7447fe 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.4.0 + 1.4.1 CFBundleVersion - 121 + 126 NSExtension NSExtensionAttributes diff --git a/update_localization.sh b/update_localization.sh index b234cd933..09cfc21d6 100755 --- a/update_localization.sh +++ b/update_localization.sh @@ -21,7 +21,7 @@ echo "${PODS_ROOT}/SwiftGen/bin/swiftgen" if [[ -f "${PODS_ROOT}/SwiftGen/bin/swiftgen" ]] then "${PODS_ROOT}/SwiftGen/bin/swiftgen" else - echo "Run 'pod install' or update your CocoaPods installation." + echo "Run 'bundle exec pod install' or update your CocoaPods installation." fi #task 4 clean temp file From e0f6940e28bc1b48c95f2da008c615b91e742f24 Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 10 May 2022 18:02:23 +0800 Subject: [PATCH 076/101] feat: add i18n strings for report flow --- Localization/app.json | 44 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/Localization/app.json b/Localization/app.json index 90b9b0fd8..44ff04de4 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -240,7 +240,8 @@ "category": "CATEGORY" }, "input": { - "placeholder": "Search servers" + "placeholder": "Search servers", + "search_servers_or_enter_url": "Search communities or enter URL" }, "empty_state": { "finding_servers": "Finding available servers...", @@ -600,7 +601,46 @@ "send": "Send Report", "skip_to_send": "Send without comment", "text_placeholder": "Type or paste additional comments", - "reported": "REPORTED" + "reported": "REPORTED", + "step_one": { + "step_1_of_4": "Step 1 of 4", + "whats_wrong_with_this_post": "What's wrong with this post?", + "whats_wrong_with_this_account": "What's wrong with this account?", + "whats_wrong_with_this_username": "What's wrong with %s?", + "select_the_best_match": "Select the best match", + "i_dont_like_it": "I don’t like it", + "it_is_not_something_you_want_to_see": "It is not something you want to see", + "its_spam": "It’s spam", + "malicious_links_fake_engagement_or_repetetive_replies": "Malicious links, fake engagement, or repetetive replies", + "it_violates_server_rules": "It violates server rules", + "you_are_aware_that_it_breaks_specific_rules": "You are aware that it breaks specific rules", + "its_something_else": "It’s something else", + "the_issue_does_not_fit_into_other_categories": "The issue does not fit into other categories" + }, + "step_two": { + "step_2_of_4": "Step 2 of 4", + "which_rules_are_being_violated": "Which rules are being violated?", + "select_all_that_apply": "Select all that apply", + "i_just_don’t_like_it": "I just don’t like it" + }, + "step_three": { + "step_3_of_4": "Step 3 of 4", + "are_there_any_posts_that_back_up_this_report": "Are there any posts that back up this report?", + "select_all_that_apply": "Select all that apply" + }, + "step_four": { + "step_4_of_4": "Step 4 of 4", + "is_there_anything_else_we_should_know": "Is there anything else we should know?" + }, + "step_final": { + "dont_want_to_see_this": "Don’t want to see this?", + "when_you_see_something_you_dont_like_on_mastodon_you_can_remove_the_person_from_your_experience.": "When you see something you don’t like on Mastodon, you can remove the person from your experience.", + "unfollow_user": "Unfollow %s", + "mute_user": "Mute %s", + "you_wont_see_their_posts_or_reblogs_in_your_home_feed_they_wont_know_they_ve_been_muted": "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted.", + "Block_domain": "Block %s", + "they_will_no_longer_be_able_to_follow_or_see_your_posts_but_they_can_see_if_theyve_been_blocked": "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked." + } }, "preview": { "keyboard": { From 2ef6345d836c7d86d8485df3f521299a822a327f Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 10 May 2022 18:34:39 +0800 Subject: [PATCH 077/101] feat: add violates server rules report path --- Mastodon.xcodeproj/project.pbxproj | 78 ++++++-- .../xcschemes/xcschememanagement.plist | 6 +- Mastodon/Coordinator/SceneCoordinator.swift | 12 +- .../MastodonConfirmEmailViewController.swift | 5 + .../Register/MastodonRegisterView.swift | 3 - .../Report/Report/ReportViewController.swift | 165 ++++++++++++++++ .../Scene/Report/Report/ReportViewModel.swift | 176 ++++++++++++++++++ .../ReportReason/ReportReasonView.swift | 113 +++++++++++ .../ReportReasonViewController.swift | 116 ++++++++++++ .../ReportReason/ReportReasonViewModel.swift | 83 +++++++++ .../ReportResultViewController.swift | 16 ++ .../ReportServerRulesView.swift | 116 ++++++++++++ .../ReportServerRulesViewController.swift | 117 ++++++++++++ .../ReportServerRulesViewModel.swift | 35 ++++ ...swift => ReportStatusViewController.swift} | 76 ++++---- ...t => ReportStatusViewModel+Diffable.swift} | 6 +- ...wift => ReportStatusViewModel+State.swift} | 20 +- ...odel.swift => ReportStatusViewModel.swift} | 9 +- .../ReportSupplementaryViewController.swift | 65 +++---- ...eportSupplementaryViewModel+Diffable.swift | 4 +- .../ReportSupplementaryViewModel.swift | 50 +---- .../Cell/ReportCommentTableViewCell.swift | 17 +- .../ReportViewControllerAppearance.swift | 2 +- ...veStatusBarStyleNavigationController.swift | 8 +- 24 files changed, 1129 insertions(+), 169 deletions(-) create mode 100644 Mastodon/Scene/Report/Report/ReportViewController.swift create mode 100644 Mastodon/Scene/Report/Report/ReportViewModel.swift create mode 100644 Mastodon/Scene/Report/ReportReason/ReportReasonView.swift create mode 100644 Mastodon/Scene/Report/ReportReason/ReportReasonViewController.swift create mode 100644 Mastodon/Scene/Report/ReportReason/ReportReasonViewModel.swift create mode 100644 Mastodon/Scene/Report/ReportServerRules/ReportServerRulesView.swift create mode 100644 Mastodon/Scene/Report/ReportServerRules/ReportServerRulesViewController.swift create mode 100644 Mastodon/Scene/Report/ReportServerRules/ReportServerRulesViewModel.swift rename Mastodon/Scene/Report/ReportStatus/{ReportViewController.swift => ReportStatusViewController.swift} (75%) rename Mastodon/Scene/Report/ReportStatus/{ReportViewModel+Diffable.swift => ReportStatusViewModel+Diffable.swift} (93%) rename Mastodon/Scene/Report/ReportStatus/{ReportViewModel+State.swift => ReportStatusViewModel+State.swift} (92%) rename Mastodon/Scene/Report/ReportStatus/{ReportViewModel.swift => ReportStatusViewModel.swift} (91%) diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index d5f5cbd79..400e4d73f 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -87,7 +87,7 @@ 2DF123A725C3B0210020F248 /* ActiveLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DF123A625C3B0210020F248 /* ActiveLabel.swift */; }; 2DF75BA725D10E1000694EC8 /* APIService+Favorite.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DF75BA625D10E1000694EC8 /* APIService+Favorite.swift */; }; 5B24BBDA262DB14800A9381B /* ReportViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B24BBD7262DB14800A9381B /* ReportViewModel.swift */; }; - 5B24BBDB262DB14800A9381B /* ReportViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B24BBD8262DB14800A9381B /* ReportViewModel+Diffable.swift */; }; + 5B24BBDB262DB14800A9381B /* ReportStatusViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B24BBD8262DB14800A9381B /* ReportStatusViewModel+Diffable.swift */; }; 5B24BBE2262DB19100A9381B /* APIService+Report.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B24BBE1262DB19100A9381B /* APIService+Report.swift */; }; 5B90C45E262599800002E742 /* SettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B90C456262599800002E742 /* SettingsViewModel.swift */; }; 5B90C45F262599800002E742 /* SettingsToggleTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B90C459262599800002E742 /* SettingsToggleTableViewCell.swift */; }; @@ -440,7 +440,7 @@ DB98337125C9443200AD9700 /* APIService+Authentication.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98337025C9443200AD9700 /* APIService+Authentication.swift */; }; DB98337F25C9452D00AD9700 /* APIService+APIError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98337E25C9452D00AD9700 /* APIService+APIError.swift */; }; DB98339C25C96DE600AD9700 /* APIService+Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98339B25C96DE600AD9700 /* APIService+Account.swift */; }; - DB98EB4727B0DFAA0082E365 /* ReportViewModel+State.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98EB4627B0DFAA0082E365 /* ReportViewModel+State.swift */; }; + DB98EB4727B0DFAA0082E365 /* ReportStatusViewModel+State.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98EB4627B0DFAA0082E365 /* ReportStatusViewModel+State.swift */; }; DB98EB4927B0F0CD0082E365 /* ReportStatusTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98EB4827B0F0CD0082E365 /* ReportStatusTableViewCell.swift */; }; DB98EB4C27B0F2BC0082E365 /* ReportStatusTableViewCell+ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98EB4B27B0F2BC0082E365 /* ReportStatusTableViewCell+ViewModel.swift */; }; DB98EB5327B0F9890082E365 /* ReportHeadlineTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98EB5227B0F9890082E365 /* ReportHeadlineTableViewCell.swift */; }; @@ -566,6 +566,14 @@ DBE3CE07261D6A0E00430CC6 /* FavoriteViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE3CE06261D6A0E00430CC6 /* FavoriteViewModel+Diffable.swift */; }; DBE54AC62636C89F004E7C0B /* NotificationPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE54AC52636C89F004E7C0B /* NotificationPreference.swift */; }; DBE54ACC2636C8FD004E7C0B /* NotificationPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE54AC52636C89F004E7C0B /* NotificationPreference.swift */; }; + DBEFCD71282A12B200C0ABEA /* ReportReasonViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBEFCD70282A12B200C0ABEA /* ReportReasonViewController.swift */; }; + DBEFCD74282A130400C0ABEA /* ReportReasonViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBEFCD73282A130400C0ABEA /* ReportReasonViewModel.swift */; }; + DBEFCD76282A143F00C0ABEA /* ReportStatusViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBEFCD75282A143F00C0ABEA /* ReportStatusViewController.swift */; }; + DBEFCD79282A147000C0ABEA /* ReportStatusViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBEFCD78282A147000C0ABEA /* ReportStatusViewModel.swift */; }; + DBEFCD7B282A162400C0ABEA /* ReportReasonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBEFCD7A282A162400C0ABEA /* ReportReasonView.swift */; }; + DBEFCD7D282A2A3B00C0ABEA /* ReportServerRulesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBEFCD7C282A2A3B00C0ABEA /* ReportServerRulesViewController.swift */; }; + DBEFCD80282A2AA900C0ABEA /* ReportServerRulesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBEFCD7F282A2AA900C0ABEA /* ReportServerRulesViewModel.swift */; }; + DBEFCD82282A2AB100C0ABEA /* ReportServerRulesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBEFCD81282A2AB100C0ABEA /* ReportServerRulesView.swift */; }; DBF156DF2701B17600EC00B7 /* SidebarAddAccountCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBF156DE2701B17600EC00B7 /* SidebarAddAccountCollectionViewCell.swift */; }; DBF156E22702DA6900EC00B7 /* UIStatusBarManager+HandleTapAction.m in Sources */ = {isa = PBXBuildFile; fileRef = DBF156E12702DA6900EC00B7 /* UIStatusBarManager+HandleTapAction.m */; }; DBF156E42702DB3F00EC00B7 /* HandleTapAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBF156E32702DB3F00EC00B7 /* HandleTapAction.swift */; }; @@ -789,7 +797,7 @@ 459EA4F43058CAB47719E963 /* Pods-Mastodon-MastodonUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-MastodonUITests.debug.xcconfig"; path = "Target Support Files/Pods-Mastodon-MastodonUITests/Pods-Mastodon-MastodonUITests.debug.xcconfig"; sourceTree = ""; }; 46DAB0EBDDFB678347CD96FF /* Pods-MastodonTests.asdk - release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonTests.asdk - release.xcconfig"; path = "Target Support Files/Pods-MastodonTests/Pods-MastodonTests.asdk - release.xcconfig"; sourceTree = ""; }; 5B24BBD7262DB14800A9381B /* ReportViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReportViewModel.swift; sourceTree = ""; }; - 5B24BBD8262DB14800A9381B /* ReportViewModel+Diffable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ReportViewModel+Diffable.swift"; sourceTree = ""; }; + 5B24BBD8262DB14800A9381B /* ReportStatusViewModel+Diffable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ReportStatusViewModel+Diffable.swift"; sourceTree = ""; }; 5B24BBE1262DB19100A9381B /* APIService+Report.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "APIService+Report.swift"; sourceTree = ""; }; 5B90C456262599800002E742 /* SettingsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewModel.swift; sourceTree = ""; }; 5B90C459262599800002E742 /* SettingsToggleTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsToggleTableViewCell.swift; sourceTree = ""; }; @@ -1199,7 +1207,7 @@ DB98337025C9443200AD9700 /* APIService+Authentication.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Authentication.swift"; sourceTree = ""; }; DB98337E25C9452D00AD9700 /* APIService+APIError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "APIService+APIError.swift"; sourceTree = ""; }; DB98339B25C96DE600AD9700 /* APIService+Account.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Account.swift"; sourceTree = ""; }; - DB98EB4627B0DFAA0082E365 /* ReportViewModel+State.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ReportViewModel+State.swift"; sourceTree = ""; }; + DB98EB4627B0DFAA0082E365 /* ReportStatusViewModel+State.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ReportStatusViewModel+State.swift"; sourceTree = ""; }; DB98EB4827B0F0CD0082E365 /* ReportStatusTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportStatusTableViewCell.swift; sourceTree = ""; }; DB98EB4B27B0F2BC0082E365 /* ReportStatusTableViewCell+ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ReportStatusTableViewCell+ViewModel.swift"; sourceTree = ""; }; DB98EB5227B0F9890082E365 /* ReportHeadlineTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportHeadlineTableViewCell.swift; sourceTree = ""; }; @@ -1329,6 +1337,14 @@ DBEB19E927E4F37B00B0E80E /* ku */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ku; path = ku.lproj/Intents.strings; sourceTree = ""; }; DBEB19EA27E4F37B00B0E80E /* ku */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ku; path = ku.lproj/InfoPlist.strings; sourceTree = ""; }; DBEB19EB27E4F37B00B0E80E /* ku */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ku; path = ku.lproj/Intents.stringsdict; sourceTree = ""; }; + DBEFCD70282A12B200C0ABEA /* ReportReasonViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportReasonViewController.swift; sourceTree = ""; }; + DBEFCD73282A130400C0ABEA /* ReportReasonViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportReasonViewModel.swift; sourceTree = ""; }; + DBEFCD75282A143F00C0ABEA /* ReportStatusViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportStatusViewController.swift; sourceTree = ""; }; + DBEFCD78282A147000C0ABEA /* ReportStatusViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportStatusViewModel.swift; sourceTree = ""; }; + DBEFCD7A282A162400C0ABEA /* ReportReasonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportReasonView.swift; sourceTree = ""; }; + DBEFCD7C282A2A3B00C0ABEA /* ReportServerRulesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportServerRulesViewController.swift; sourceTree = ""; }; + DBEFCD7F282A2AA900C0ABEA /* ReportServerRulesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportServerRulesViewModel.swift; sourceTree = ""; }; + DBEFCD81282A2AB100C0ABEA /* ReportServerRulesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportServerRulesView.swift; sourceTree = ""; }; DBF156DE2701B17600EC00B7 /* SidebarAddAccountCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarAddAccountCollectionViewCell.swift; sourceTree = ""; }; DBF156E02702DA6800EC00B7 /* Mastodon-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Mastodon-Bridging-Header.h"; sourceTree = ""; }; DBF156E12702DA6900EC00B7 /* UIStatusBarManager+HandleTapAction.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIStatusBarManager+HandleTapAction.m"; sourceTree = ""; }; @@ -1842,6 +1858,9 @@ isa = PBXGroup; children = ( DB98EB5727B0FF1F0082E365 /* Share */, + DBEFCD77282A144D00C0ABEA /* Report */, + DBEFCD72282A12B900C0ABEA /* ReportReason */, + DBEFCD7E282A2A3D00C0ABEA /* ReportServerRules */, DB98EB4F27B0F9300082E365 /* ReportStatus */, DB98EB5A27B109900082E365 /* ReportSupplementary */, DB98EB6327B216490082E365 /* ReportResult */, @@ -2208,8 +2227,8 @@ DB427DD425BAA00100D1B89D /* Mastodon */ = { isa = PBXGroup; children = ( - DB427DE325BAA00100D1B89D /* Info.plist */, DB89BA1025C10FF5008580ED /* Mastodon.entitlements */, + DB427DE325BAA00100D1B89D /* Info.plist */, 2D76319C25C151DE00929FB9 /* Diffiable */, DB8AF52A25C13561002E6C99 /* State */, 2D61335525C1886800CAE157 /* Service */, @@ -2850,10 +2869,10 @@ DB98EB4F27B0F9300082E365 /* ReportStatus */ = { isa = PBXGroup; children = ( - 5BB04FD4262E7AFF0043BFF6 /* ReportViewController.swift */, - 5B24BBD7262DB14800A9381B /* ReportViewModel.swift */, - 5B24BBD8262DB14800A9381B /* ReportViewModel+Diffable.swift */, - DB98EB4627B0DFAA0082E365 /* ReportViewModel+State.swift */, + DBEFCD75282A143F00C0ABEA /* ReportStatusViewController.swift */, + DBEFCD78282A147000C0ABEA /* ReportStatusViewModel.swift */, + 5B24BBD8262DB14800A9381B /* ReportStatusViewModel+Diffable.swift */, + DB98EB4627B0DFAA0082E365 /* ReportStatusViewModel+State.swift */, ); path = ReportStatus; sourceTree = ""; @@ -3177,6 +3196,35 @@ path = Favorite; sourceTree = ""; }; + DBEFCD72282A12B900C0ABEA /* ReportReason */ = { + isa = PBXGroup; + children = ( + DBEFCD70282A12B200C0ABEA /* ReportReasonViewController.swift */, + DBEFCD73282A130400C0ABEA /* ReportReasonViewModel.swift */, + DBEFCD7A282A162400C0ABEA /* ReportReasonView.swift */, + ); + path = ReportReason; + sourceTree = ""; + }; + DBEFCD77282A144D00C0ABEA /* Report */ = { + isa = PBXGroup; + children = ( + 5BB04FD4262E7AFF0043BFF6 /* ReportViewController.swift */, + 5B24BBD7262DB14800A9381B /* ReportViewModel.swift */, + ); + path = Report; + sourceTree = ""; + }; + DBEFCD7E282A2A3D00C0ABEA /* ReportServerRules */ = { + isa = PBXGroup; + children = ( + DBEFCD7C282A2A3B00C0ABEA /* ReportServerRulesViewController.swift */, + DBEFCD7F282A2AA900C0ABEA /* ReportServerRulesViewModel.swift */, + DBEFCD81282A2AB100C0ABEA /* ReportServerRulesView.swift */, + ); + path = ReportServerRules; + sourceTree = ""; + }; DBF1D24F269DAF6100C1C08A /* SearchDetail */ = { isa = PBXGroup; children = ( @@ -3873,6 +3921,7 @@ 2D364F7225E66D7500204FDC /* MastodonResendEmailViewController.swift in Sources */, DB68A06325E905E000CFDF14 /* UIApplication.swift in Sources */, DB02CDAB26256A9500D0A2AF /* ThreadReplyLoaderTableViewCell.swift in Sources */, + DBEFCD80282A2AA900C0ABEA /* ReportServerRulesViewModel.swift in Sources */, DB0617FF27855D6C0030EE79 /* MastodonServerRulesViewModel+Diffable.swift in Sources */, DBB5255E2611F07A002F1F29 /* ProfileViewModel.swift in Sources */, DB0FCB982797F6BF006C02E2 /* UserTableViewCell+ViewModel.swift in Sources */, @@ -3900,6 +3949,7 @@ DB63F76F279A7D1100455B82 /* NotificationTableViewCell.swift in Sources */, DB297B1B2679FAE200704C90 /* PlaceholderImageCacheService.swift in Sources */, DB0FCB8C2796BF8D006C02E2 /* SearchViewModel+Diffable.swift in Sources */, + DBEFCD76282A143F00C0ABEA /* ReportStatusViewController.swift in Sources */, 2D8FCA082637EABB00137F46 /* APIService+FollowRequest.swift in Sources */, DBDFF1952805561700557A48 /* DiscoveryPostsViewModel+Diffable.swift in Sources */, DB03A795272A981400EE37C5 /* ContentSplitViewController.swift in Sources */, @@ -4030,7 +4080,7 @@ DB63F75C279956D000455B82 /* Persistence+Tag.swift in Sources */, 2D84350525FF858100EECE90 /* UIScrollView.swift in Sources */, DB49A61F25FF32AA00B98345 /* EmojiService+CustomEmojiViewModel.swift in Sources */, - 5B24BBDB262DB14800A9381B /* ReportViewModel+Diffable.swift in Sources */, + 5B24BBDB262DB14800A9381B /* ReportStatusViewModel+Diffable.swift in Sources */, DB4F0968269ED8AD00D62E92 /* SearchHistoryTableHeaderView.swift in Sources */, 0FB3D2FE25E4CB6400AAD544 /* OnboardingHeadlineTableViewCell.swift in Sources */, 5DA732CC2629CEF500A92342 /* UIView+Remove.swift in Sources */, @@ -4042,6 +4092,7 @@ DBBF1DC92652538500E5B703 /* AutoCompleteSection.swift in Sources */, DB3E6FE72806A7A200B035AE /* DiscoveryItem.swift in Sources */, DB8AF55D25C138B7002E6C99 /* UIViewController.swift in Sources */, + DBEFCD79282A147000C0ABEA /* ReportStatusViewModel.swift in Sources */, DB7F48452620241000796008 /* ProfileHeaderViewModel.swift in Sources */, DB647C5926F1EA2700F7F82C /* WizardPreference.swift in Sources */, DB0A322E280EE9FD001729D2 /* DiscoveryIntroBannerView.swift in Sources */, @@ -4092,7 +4143,7 @@ DBA94434265CBB5300C537E1 /* ProfileFieldSection.swift in Sources */, DB336F28278D6EC70031E64B /* MastodonFieldContainer.swift in Sources */, DBF156E42702DB3F00EC00B7 /* HandleTapAction.swift in Sources */, - DB98EB4727B0DFAA0082E365 /* ReportViewModel+State.swift in Sources */, + DB98EB4727B0DFAA0082E365 /* ReportStatusViewModel+State.swift in Sources */, 2D5981A125E4A593000FB903 /* MastodonConfirmEmailViewModel.swift in Sources */, DB6B74F6272FBCDB00C70B6E /* FollowerListViewModel+State.swift in Sources */, DB87D4452609BE0500D12C0D /* ComposeStatusPollOptionCollectionViewCell.swift in Sources */, @@ -4150,6 +4201,7 @@ DB6D9F8426358EEC008423CD /* SettingsItem.swift in Sources */, 2D364F7825E66D8300204FDC /* MastodonResendEmailViewModel.swift in Sources */, DBA465932696B495002B41DB /* APIService+WebFinger.swift in Sources */, + DBEFCD7B282A162400C0ABEA /* ReportReasonView.swift in Sources */, DB8AF54525C13647002E6C99 /* NeedsDependency.swift in Sources */, DB63F77B279ACAE500455B82 /* DataSourceFacade+Favorite.swift in Sources */, DB9D6BF825E4F5690051B173 /* NotificationViewController.swift in Sources */, @@ -4164,6 +4216,7 @@ DB4F097526A037F500D62E92 /* SearchHistoryViewModel.swift in Sources */, DB3EA8E9281B7A3700598866 /* DiscoveryCommunityViewModel.swift in Sources */, DB6180F826391D660018D199 /* MediaPreviewingViewController.swift in Sources */, + DBEFCD71282A12B200C0ABEA /* ReportReasonViewController.swift in Sources */, DB0140CF25C42AEE00F9F3CF /* OSLog.swift in Sources */, DB98EB5627B0FF1B0082E365 /* ReportViewControllerAppearance.swift in Sources */, DB938F1526241FDF00E5B6C1 /* APIService+Thread.swift in Sources */, @@ -4200,6 +4253,7 @@ 2D7867192625B77500211898 /* NotificationItem.swift in Sources */, DB45FAB625CA5485005A8AC7 /* UIAlertController.swift in Sources */, DBE0821525CD382600FD6BBD /* MastodonRegisterViewController.swift in Sources */, + DBEFCD74282A130400C0ABEA /* ReportReasonViewModel.swift in Sources */, 2D5A3D0325CF8742002347D6 /* ControlContainableScrollViews.swift in Sources */, DB36679D268AB91B0027D07F /* ComposeStatusAttachmentTableViewCell.swift in Sources */, DB98336B25C9420100AD9700 /* APIService+App.swift in Sources */, @@ -4287,6 +4341,7 @@ DB0617EB277EF3820030EE79 /* GradientBorderView.swift in Sources */, DB789A1225F9F2CC0071ACA0 /* ComposeViewModel.swift in Sources */, DB63F74B279914A000455B82 /* FollowingListViewController+DataSourceProvider.swift in Sources */, + DBEFCD7D282A2A3B00C0ABEA /* ReportServerRulesViewController.swift in Sources */, DBB525362611ECEB002F1F29 /* UserTimelineViewController.swift in Sources */, DB938F3326243D6200E5B6C1 /* TimelineTopLoaderTableViewCell.swift in Sources */, DB98EB4927B0F0CD0082E365 /* ReportStatusTableViewCell.swift in Sources */, @@ -4297,6 +4352,7 @@ DB98EB6527B216500082E365 /* ReportResultViewModel.swift in Sources */, DB4F096A269EDAD200D62E92 /* SearchResultViewModel+State.swift in Sources */, 5BB04FF5262F0E6D0043BFF6 /* ReportSection.swift in Sources */, + DBEFCD82282A2AB100C0ABEA /* ReportServerRulesView.swift in Sources */, DBA94436265CBB7400C537E1 /* ProfileFieldItem.swift in Sources */, DB023D2A27A0FE5C005AC798 /* DataSourceProvider+NotificationTableViewCellDelegate.swift in Sources */, DB98EB6027B10E150082E365 /* ReportCommentTableViewCell.swift in Sources */, diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 07a847a0c..7f54b9011 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -109,7 +109,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 28 + 20 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +124,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 27 + 19 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 26 + 21 SuppressBuildableAutocreation diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index 5e7fbf472..d149e63a2 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -158,7 +158,7 @@ extension SceneCoordinator { case mastodonServerRules(viewModel: MastodonServerRulesViewModel) case mastodonConfirmEmail(viewModel: MastodonConfirmEmailViewModel) case mastodonResendEmail(viewModel: MastodonResendEmailViewModel) - case mastodonWebView(viewModel:WebViewModel) + case mastodonWebView(viewModel: WebViewModel) // search case searchDetail(viewModel: SearchDetailViewModel) @@ -184,6 +184,8 @@ extension SceneCoordinator { // report case report(viewModel: ReportViewModel) + case reportServerRules(viewModel: ReportServerRulesViewModel) + case reportStatus(viewModel: ReportStatusViewModel) case reportSupplementary(viewModel: ReportSupplementaryViewModel) case reportResult(viewModel: ReportResultViewModel) @@ -447,6 +449,14 @@ private extension SceneCoordinator { let _viewController = ReportViewController() _viewController.viewModel = viewModel viewController = _viewController + case .reportServerRules(let viewModel): + let _viewController = ReportServerRulesViewController() + _viewController.viewModel = viewModel + viewController = _viewController + case .reportStatus(let viewModel): + let _viewController = ReportStatusViewController() + _viewController.viewModel = viewModel + viewController = _viewController case .reportSupplementary(let viewModel): let _viewController = ReportSupplementaryViewController() _viewController.viewModel = viewModel diff --git a/Mastodon/Scene/Onboarding/ConfirmEmail/MastodonConfirmEmailViewController.swift b/Mastodon/Scene/Onboarding/ConfirmEmail/MastodonConfirmEmailViewController.swift index b1b2280d8..cb7a96f85 100644 --- a/Mastodon/Scene/Onboarding/ConfirmEmail/MastodonConfirmEmailViewController.swift +++ b/Mastodon/Scene/Onboarding/ConfirmEmail/MastodonConfirmEmailViewController.swift @@ -229,6 +229,11 @@ extension MastodonConfirmEmailViewController { } } +// MARK: - PanPopableViewController +extension MastodonConfirmEmailViewController: PanPopableViewController { + var isPanPopable: Bool { false } +} + // MARK: - OnboardingViewControllerAppearance extension MastodonConfirmEmailViewController: OnboardingViewControllerAppearance { } diff --git a/Mastodon/Scene/Onboarding/Register/MastodonRegisterView.swift b/Mastodon/Scene/Onboarding/Register/MastodonRegisterView.swift index 1a47de22f..2be7c61d7 100644 --- a/Mastodon/Scene/Onboarding/Register/MastodonRegisterView.swift +++ b/Mastodon/Scene/Onboarding/Register/MastodonRegisterView.swift @@ -197,9 +197,6 @@ struct MastodonRegisterView: View { } } - - - } struct WidthKey: PreferenceKey { diff --git a/Mastodon/Scene/Report/Report/ReportViewController.swift b/Mastodon/Scene/Report/Report/ReportViewController.swift new file mode 100644 index 000000000..6d3f6da06 --- /dev/null +++ b/Mastodon/Scene/Report/Report/ReportViewController.swift @@ -0,0 +1,165 @@ +// +// ReportViewController.swift +// Mastodon +// +// Created by ihugo on 2021/4/20. +// + +import os.log +import UIKit +import Combine +import CoreDataStack +import MastodonAsset +import MastodonLocalization + +class ReportViewController: UIViewController, NeedsDependency, ReportViewControllerAppearance { + + let logger = Logger(subsystem: "ReportViewController", category: "ViewController") + + var disposeBag = Set() + private var observations = Set() + + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } + weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + + var viewModel: ReportViewModel! + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } + +} + +extension ReportViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + setupAppearance() + defer { setupNavigationBarBackgroundView() } + + viewModel.reportReasonViewModel.delegate = self + viewModel.reportServerRulesViewModel.delegate = self + viewModel.reportStatusViewModel.delegate = self + viewModel.reportSupplementaryViewModel.delegate = self + + let reportReasonViewController = ReportReasonViewController() + reportReasonViewController.context = context + reportReasonViewController.coordinator = coordinator + reportReasonViewController.viewModel = viewModel.reportReasonViewModel + + addChild(reportReasonViewController) + reportReasonViewController.view.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(reportReasonViewController.view) + reportReasonViewController.didMove(toParent: self) + NSLayoutConstraint.activate([ + reportReasonViewController.view.topAnchor.constraint(equalTo: view.topAnchor), + reportReasonViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), + reportReasonViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), + reportReasonViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor), + ]) + } + +} + +// MARK: - UIAdaptivePresentationControllerDelegate +extension ReportViewController: UIAdaptivePresentationControllerDelegate { + func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool { + return viewModel.isReportSuccess + } +} + +// MARK: - ReportReasonViewControllerDelegate +extension ReportViewController: ReportReasonViewControllerDelegate { + func reportReasonViewController(_ viewController: ReportReasonViewController, nextButtonPressed button: UIButton) { + guard let reason = viewController.viewModel.selectReason else { return } + switch reason { + case .violateRule: + coordinator.present( + scene: .reportServerRules(viewModel: viewModel.reportServerRulesViewModel), + from: self, + transition: .show + ) + default: + break + } + } +} + +// MARK: - ReportServerRulesViewControllerDelegate +extension ReportViewController: ReportServerRulesViewControllerDelegate { + func reportServerRulesViewController(_ viewController: ReportServerRulesViewController, nextButtonPressed button: UIButton) { + if viewController.viewModel.isDislike { + + } else if viewController.viewModel.selectRule != nil { + coordinator.present( + scene: .reportStatus(viewModel: viewModel.reportStatusViewModel), + from: self, + transition: .show + ) + } else { + assertionFailure() + } + } +} + +// MARK: - ReportStatusViewControllerDelegate +extension ReportViewController: ReportStatusViewControllerDelegate { + func reportStatusViewController(_ viewController: ReportStatusViewController, skipButtonDidPressed button: UIButton) { + coordinateToReportSupplementary() + } + + func reportStatusViewController(_ viewController: ReportStatusViewController, nextButtonDidPressed button: UIButton) { + coordinateToReportSupplementary() + } + + private func coordinateToReportSupplementary() { + coordinator.present( + scene: .reportSupplementary(viewModel: viewModel.reportSupplementaryViewModel), + from: self, + transition: .show + ) + } +} + +// MARK: - ReportSupplementaryViewControllerDelegate +extension ReportViewController: ReportSupplementaryViewControllerDelegate { + func reportSupplementaryViewController(_ viewController: ReportSupplementaryViewController, skipButtonDidPressed button: UIButton) { + report() + } + + func reportSupplementaryViewController(_ viewController: ReportSupplementaryViewController, nextButtonDidPressed button: UIButton) { + report() + } + + private func report() { + Task { @MainActor in + do { + let _ = try await viewModel.report() + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): report success") + + let reportResultViewModel = ReportResultViewModel( + context: context, + user: viewModel.user + ) + + coordinator.present( + scene: .reportResult(viewModel: reportResultViewModel), + from: self, + transition: .show + ) + + } catch { + let alertController = UIAlertController(for: error, title: nil, preferredStyle: .alert) + let okAction = UIAlertAction(title: L10n.Common.Controls.Actions.ok, style: .default, handler: nil) + alertController.addAction(okAction) + self.coordinator.present( + scene: .alertController(alertController: alertController), + from: nil, + transition: .alertController(animated: true, completion: nil) + ) + } + } // end Task + } + +} diff --git a/Mastodon/Scene/Report/Report/ReportViewModel.swift b/Mastodon/Scene/Report/Report/ReportViewModel.swift new file mode 100644 index 000000000..73bac19b0 --- /dev/null +++ b/Mastodon/Scene/Report/Report/ReportViewModel.swift @@ -0,0 +1,176 @@ +// +// ReportViewModel.swift +// Mastodon +// +// Created by ihugo on 2021/4/19. +// + +import Combine +import CoreData +import CoreDataStack +import Foundation +import GameplayKit +import MastodonSDK +import OrderedCollections +import os.log +import UIKit + +class ReportViewModel { + + var disposeBag = Set() + + let reportReasonViewModel: ReportReasonViewModel + let reportServerRulesViewModel: ReportServerRulesViewModel + let reportStatusViewModel: ReportStatusViewModel + let reportSupplementaryViewModel: ReportSupplementaryViewModel + + // input + let context: AppContext + let user: ManagedObjectRecord + let status: ManagedObjectRecord? + + // output + @Published var isReporting = false + @Published var isReportSuccess = false + + init( + context: AppContext, + user: ManagedObjectRecord, + status: ManagedObjectRecord? + ) { + self.context = context + self.user = user + self.status = status + self.reportReasonViewModel = ReportReasonViewModel(context: context) + self.reportServerRulesViewModel = ReportServerRulesViewModel(context: context) + self.reportStatusViewModel = ReportStatusViewModel(context: context, user: user, status: status) + self.reportSupplementaryViewModel = ReportSupplementaryViewModel(context: context, user: user) + // end init + + guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { + return + } + + // setup reason viewModel + if status != nil { + // TODO: i18n + reportReasonViewModel.headline = "What’s wrong with post?" + } else { + Task { @MainActor in + let managedObjectContext = context.managedObjectContext + let _username: String? = try? await managedObjectContext.perform { + let user = user.object(in: managedObjectContext) + return user?.acctWithDomain + } + if let username = _username { + reportReasonViewModel.headline = "What’s wrong with @\(username)?" + } else { + reportReasonViewModel.headline = "What’s wrong with this account?" + } + } // end Task + } + + // bind server rules + Task { @MainActor in + do { + let response = try await context.apiService.instance(domain: authenticationBox.domain) + .timeout(3, scheduler: DispatchQueue.main) + .singleOutput() + let rules = response.value.rules ?? [] + reportReasonViewModel.serverRules = rules + reportServerRulesViewModel.serverRules = rules + } catch { + reportReasonViewModel.serverRules = [] + reportServerRulesViewModel.serverRules = [] + } + } // end Task + + $isReporting + .assign(to: &reportSupplementaryViewModel.$isBusy) + } + +} + +extension ReportViewModel { + @MainActor + func report() async throws { + guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value, + !isReporting + else { + assertionFailure() + return + } + + let managedObjectContext = context.managedObjectContext + let _query: Mastodon.API.Reports.FileReportQuery? = try await managedObjectContext.perform { + guard let user = self.user.object(in: managedObjectContext) else { return nil } + let statusIDs: [Status.ID]? = { + if self.reportStatusViewModel.isSkip { + let _id: Status.ID? = self.reportStatusViewModel.status.flatMap { record -> Status.ID? in + guard let status = record.object(in: managedObjectContext) else { return nil } + return status.id + } + return _id.flatMap { [$0] } + } else { + return self.reportStatusViewModel.selectStatuses.compactMap { record -> Status.ID? in + guard let status = record.object(in: managedObjectContext) else { return nil } + return status.id + } + } + }() + let comment: String? = { + var suffixes: [String] = [] + let content: String? + + if let reason = self.reportReasonViewModel.selectReason { + switch reason { + case .spam: + suffixes.append(reason.rawValue) + case .violateRule: + suffixes.append(reason.rawValue) + if let rule = self.reportServerRulesViewModel.selectRule { + suffixes.append(rule.text) + } + + case .dislike, .other: + break + } + } + + content = self.reportSupplementaryViewModel.isSkip ? nil : self.reportSupplementaryViewModel.commentContext.comment + + let suffix: String? = { + let text = suffixes.joined(separator: ". ") + guard !text.isEmpty else { return nil } + return "<" + text + ">" + }() + + let comment = [content, suffix] + .compactMap { $0 } + .joined(separator: " ") + return comment.isEmpty ? nil : comment + }() + return Mastodon.API.Reports.FileReportQuery( + accountID: user.id, + statusIDs: statusIDs, + comment: comment, + forward: true + ) + } + + guard let query = _query else { return } + + do { + isReporting = true + try await Task.sleep(nanoseconds: .second * 3) +// let _ = try await context.apiService.report( +// query: query, +// authenticationBox: authenticationBox +// ) + isReportSuccess = true + } catch { + isReporting = false + throw error + } + } +} diff --git a/Mastodon/Scene/Report/ReportReason/ReportReasonView.swift b/Mastodon/Scene/Report/ReportReason/ReportReasonView.swift new file mode 100644 index 000000000..3a8b4579f --- /dev/null +++ b/Mastodon/Scene/Report/ReportReason/ReportReasonView.swift @@ -0,0 +1,113 @@ +// +// ReportReasonView.swift +// Mastodon +// +// Created by MainasuK on 2022-5-10. +// + +import UIKit +import SwiftUI +import MastodonLocalization +import MastodonSDK +import MastodonAsset + +struct ReportReasonView: View { + + @ObservedObject var viewModel: ReportReasonViewModel + + // TODO: i18n + var body: some View { + ScrollView(.vertical) { + HStack { + VStack(alignment: .leading, spacing: 8) { + Text("Step 1 of 4") + .foregroundColor(Color(Asset.Colors.Label.secondary.color)) + .font(Font(UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)) as CTFont)) + Text(viewModel.headline) + .foregroundColor(Color(Asset.Colors.Label.primary.color)) + .font(Font(UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: .systemFont(ofSize: 28, weight: .bold)) as CTFont)) + Text("Select the best match") + .foregroundColor(Color(Asset.Colors.Label.secondary.color)) + .font(Font(UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)) as CTFont)) + } + Spacer() + } + .padding() + + VStack(spacing: 16) { + if let serverRules = viewModel.serverRules { + ForEach(ReportReasonViewModel.Reason.allCases, id: \.self) { reason in + switch reason { + case .violateRule where serverRules.isEmpty: + EmptyView() + default: + ReportReasonRowView(reason: reason, isSelect: reason == viewModel.selectReason) + .background( + Color(viewModel.backgroundColor) + ) + .onTapGesture { + viewModel.selectReason = reason + } + } + } + } else { + ProgressView() + } + } + .padding() + .transition(.opacity) + .animation(.easeInOut) + + Spacer() + .frame(minHeight: viewModel.bottomPaddingHeight) + } + .background( + Color(viewModel.backgroundColor) + ) + } + +} + +struct ReportReasonRowView: View { + + var reason: ReportReasonViewModel.Reason + var isSelect: Bool + + var body: some View { + HStack(spacing: 14) { + Image(systemName: isSelect ? "checkmark.circle.fill" : "circle") + .resizable() + .frame(width: 28, height: 28, alignment: .center) + VStack(alignment: .leading, spacing: 4) { + Text(reason.title) + .foregroundColor(Color(Asset.Colors.Label.primary.color)) + .font(.headline) + Text(reason.subtitle) + .font(.subheadline) + .foregroundColor(Color(Asset.Colors.Label.secondary.color)) + } + Spacer() + } + } + +} + +#if DEBUG +struct ReportReasonView_Previews: PreviewProvider { + static var previews: some View { + Group { + NavigationView { + ReportReasonView(viewModel: ReportReasonViewModel(context: .shared)) + .navigationBarTitle(Text("")) + .navigationBarTitleDisplayMode(.inline) + } + NavigationView { + ReportReasonView(viewModel: ReportReasonViewModel(context: .shared)) + .navigationBarTitle(Text("")) + .navigationBarTitleDisplayMode(.inline) + } + .preferredColorScheme(.dark) + } + } +} +#endif diff --git a/Mastodon/Scene/Report/ReportReason/ReportReasonViewController.swift b/Mastodon/Scene/Report/ReportReason/ReportReasonViewController.swift new file mode 100644 index 000000000..b0651e42d --- /dev/null +++ b/Mastodon/Scene/Report/ReportReason/ReportReasonViewController.swift @@ -0,0 +1,116 @@ +// +// ReportReasonViewController.swift +// Mastodon +// +// Created by MainasuK on 2022-5-10. +// + +import os.log +import UIKit +import SwiftUI +import Combine +import MastodonUI +import MastodonAsset +import MastodonLocalization + +protocol ReportReasonViewControllerDelegate: AnyObject { + func reportReasonViewController(_ viewController: ReportReasonViewController, nextButtonPressed button: UIButton) +} + +final class ReportReasonViewController: UIViewController, NeedsDependency, ReportViewControllerAppearance { + + let logger = Logger(subsystem: "ReportReasonViewController", category: "ViewController") + + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } + weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + + var disposeBag = Set() + private var observations = Set() + + var viewModel: ReportReasonViewModel! + private(set) lazy var reportReasonView = ReportReasonView(viewModel: viewModel) + + lazy var cancelBarButtonItem = UIBarButtonItem( + barButtonSystemItem: .cancel, + target: self, + action: #selector(ReportReasonViewController.cancelBarButtonItemDidPressed(_:)) + ) + + let navigationActionView: NavigationActionView = { + let navigationActionView = NavigationActionView() + navigationActionView.backgroundColor = Asset.Scene.Onboarding.background.color + navigationActionView.hidesBackButton = true + return navigationActionView + }() + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } + +} + +extension ReportReasonViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + setupAppearance() + defer { setupNavigationBarBackgroundView() } + + navigationItem.rightBarButtonItem = cancelBarButtonItem + + let hostingViewController = UIHostingController(rootView: reportReasonView) + hostingViewController.view.preservesSuperviewLayoutMargins = true + addChild(hostingViewController) + hostingViewController.view.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(hostingViewController.view) + NSLayoutConstraint.activate([ + hostingViewController.view.topAnchor.constraint(equalTo: view.topAnchor), + hostingViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), + hostingViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), + hostingViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor), + ]) + + navigationActionView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(navigationActionView) + defer { + view.bringSubviewToFront(navigationActionView) + } + NSLayoutConstraint.activate([ + navigationActionView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + navigationActionView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + view.bottomAnchor.constraint(equalTo: navigationActionView.bottomAnchor), + ]) + + navigationActionView + .observe(\.bounds, options: [.initial, .new]) { [weak self] navigationActionView, _ in + guard let self = self else { return } + let inset = navigationActionView.frame.height + self.viewModel.bottomPaddingHeight = inset + } + .store(in: &observations) + + viewModel.$selectReason + .map { $0 != nil } + .assign(to: \.isEnabled, on: navigationActionView.nextButton) + .store(in: &disposeBag) + + navigationActionView.nextButton.addTarget(self, action: #selector(ReportReasonViewController.nextButtonPressed(_:)), for: .touchUpInside) + } + +} + +extension ReportReasonViewController { + + @objc private func cancelBarButtonItemDidPressed(_ sender: UIBarButtonItem) { + dismiss(animated: true, completion: nil) + } + + @objc private func nextButtonPressed(_ sender: UIButton) { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)") + + assert(viewModel.delegate != nil) + viewModel.delegate?.reportReasonViewController(self, nextButtonPressed: sender) + } + +} diff --git a/Mastodon/Scene/Report/ReportReason/ReportReasonViewModel.swift b/Mastodon/Scene/Report/ReportReason/ReportReasonViewModel.swift new file mode 100644 index 000000000..b156ea311 --- /dev/null +++ b/Mastodon/Scene/Report/ReportReason/ReportReasonViewModel.swift @@ -0,0 +1,83 @@ +// +// ReportReasonViewModel.swift +// Mastodon +// +// Created by MainasuK on 2022-5-10. +// + +import UIKit +import SwiftUI +import MastodonAsset +import MastodonSDK + +final class ReportReasonViewModel: ObservableObject { + + weak var delegate: ReportReasonViewControllerDelegate? + + // input + let context: AppContext + + @Published var headline = "What's wrong with this account?" + @Published var serverRules: [Mastodon.Entity.Instance.Rule]? + + @Published var bottomPaddingHeight: CGFloat = .zero + @Published var backgroundColor: UIColor = Asset.Scene.Report.background.color + + // output + @Published var selectReason: Reason? + + init(context: AppContext) { + self.context = context + // end init + } + +} + +extension ReportReasonViewModel { + enum Reason: Hashable, CaseIterable { + case dislike + case spam + case violateRule + case other + + var title: String { + switch self { + case .dislike: + return "I don’t like it" + case .spam: + return "It’s spam" + case .violateRule: + return "It violates server rules" + case .other: + return "It’s something else" + } + } + + var subtitle: String { + switch self { + case .dislike: + return "It is not something you want to see" + case .spam: + return "Malicious links, fake engagement, or repetetive replies" + case .violateRule: + return "You are aware that it breaks specific rules" + case .other: + return "The issue does not fit into other categories" + } + } + + // do not i18n this + var rawValue: String { + switch self { + case .dislike: + return "I don’t like it" + case .spam: + return "It’s spam" + case .violateRule: + return "It violates server rules" + case .other: + return "It’s something else" + } + } + } +} diff --git a/Mastodon/Scene/Report/ReportResult/ReportResultViewController.swift b/Mastodon/Scene/Report/ReportResult/ReportResultViewController.swift index 26f56b98d..1073c21a2 100644 --- a/Mastodon/Scene/Report/ReportResult/ReportResultViewController.swift +++ b/Mastodon/Scene/Report/ReportResult/ReportResultViewController.swift @@ -21,6 +21,12 @@ final class ReportResultViewController: UIViewController, NeedsDependency, Repor var viewModel: ReportResultViewModel! + lazy var doneBarButtonItem = UIBarButtonItem( + barButtonSystemItem: .done, + target: self, + action: #selector(ReportResultViewController.doneBarButtonItemDidPressed(_:)) + ) + let tableView: UITableView = { let tableView = ControlContainableTableView() tableView.backgroundColor = Asset.Scene.Report.background.color @@ -60,6 +66,7 @@ extension ReportResultViewController { defer { setupNavigationBarBackgroundView() } navigationItem.hidesBackButton = true + navigationItem.rightBarButtonItem = doneBarButtonItem tableView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(tableView) @@ -102,6 +109,10 @@ extension ReportResultViewController { } extension ReportResultViewController { + + @objc func doneBarButtonItemDidPressed(_ sender: UIButton) { + dismiss(animated: true, completion: nil) + } @objc func nextButtonDidPressed(_ sender: UIButton) { dismiss(animated: true, completion: nil) @@ -111,3 +122,8 @@ extension ReportResultViewController { // MARK: - UITableViewDelegate extension ReportResultViewController: UITableViewDelegate { } + +// MARK: - PanPopableViewController +extension ReportResultViewController: PanPopableViewController { + var isPanPopable: Bool { false } +} diff --git a/Mastodon/Scene/Report/ReportServerRules/ReportServerRulesView.swift b/Mastodon/Scene/Report/ReportServerRules/ReportServerRulesView.swift new file mode 100644 index 000000000..e8dcfa886 --- /dev/null +++ b/Mastodon/Scene/Report/ReportServerRules/ReportServerRulesView.swift @@ -0,0 +1,116 @@ +// +// ReportServerRulesView.swift +// Mastodon +// +// Created by MainasuK on 2022-5-10. +// + +import UIKit +import SwiftUI +import MastodonLocalization +import MastodonSDK +import MastodonAsset + +struct ReportServerRulesView: View { + + @ObservedObject var viewModel: ReportServerRulesViewModel + + // TODO: i18n + var body: some View { + ScrollView(.vertical) { + HStack { + VStack(alignment: .leading, spacing: 8) { + Text("Step 2 of 4") + .foregroundColor(Color(Asset.Colors.Label.secondary.color)) + .font(Font(UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)) as CTFont)) + Text(viewModel.headline) + .foregroundColor(Color(Asset.Colors.Label.primary.color)) + .font(Font(UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: .systemFont(ofSize: 28, weight: .bold)) as CTFont)) + Text("Select all that apply") + .foregroundColor(Color(Asset.Colors.Label.secondary.color)) + .font(Font(UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)) as CTFont)) + } + Spacer() + } + .padding() + + VStack(spacing: 32) { + ForEach(viewModel.serverRules, id: \.self) { rule in + ReportServerRulesRowView( + title: rule.text, + isSelect: rule == viewModel.selectRule + ) + .background( + Color(viewModel.backgroundColor) + ) + .onTapGesture { + viewModel.selectRule = rule + viewModel.isDislike = false + } + } + ReportServerRulesRowView( + title: "I just don’t like it", + isSelect: viewModel.isDislike + ) + .background( + Color(viewModel.backgroundColor) + ) + .onTapGesture { + viewModel.selectRule = nil + viewModel.isDislike = true + } + } + .padding() + .transition(.opacity) + .animation(.easeInOut) + + Spacer() + .frame(minHeight: viewModel.bottomPaddingHeight) + } + .background( + Color(viewModel.backgroundColor) + ) + } + +} + +struct ReportServerRulesRowView: View { + + var title: String + var isSelect: Bool + + var body: some View { + HStack(spacing: 14) { + Image(systemName: isSelect ? "checkmark.circle.fill" : "circle") + .resizable() + .frame(width: 28, height: 28, alignment: .center) + VStack(alignment: .leading, spacing: 4) { + Text(title) + .foregroundColor(Color(Asset.Colors.Label.primary.color)) + .font(.headline) + } + Spacer() + } + } + +} + +#if DEBUG +struct ReportServerRulesView_Previews: PreviewProvider { + static var previews: some View { + Group { + NavigationView { + ReportServerRulesView(viewModel: ReportServerRulesViewModel(context: .shared)) + .navigationBarTitle(Text("")) + .navigationBarTitleDisplayMode(.inline) + } + NavigationView { + ReportServerRulesView(viewModel: ReportServerRulesViewModel(context: .shared)) + .navigationBarTitle(Text("")) + .navigationBarTitleDisplayMode(.inline) + } + .preferredColorScheme(.dark) + } + } +} +#endif diff --git a/Mastodon/Scene/Report/ReportServerRules/ReportServerRulesViewController.swift b/Mastodon/Scene/Report/ReportServerRules/ReportServerRulesViewController.swift new file mode 100644 index 000000000..330debbb8 --- /dev/null +++ b/Mastodon/Scene/Report/ReportServerRules/ReportServerRulesViewController.swift @@ -0,0 +1,117 @@ +// +// ReportServerRulesViewController.swift +// Mastodon +// +// Created by MainasuK on 2022-5-10. +// + +import os.log +import UIKit +import SwiftUI +import Combine +import MastodonUI +import MastodonAsset +import MastodonLocalization + +protocol ReportServerRulesViewControllerDelegate: AnyObject { + func reportServerRulesViewController(_ viewController: ReportServerRulesViewController, nextButtonPressed button: UIButton) +} + +final class ReportServerRulesViewController: UIViewController, NeedsDependency, ReportViewControllerAppearance { + + let logger = Logger(subsystem: "ReportReasonViewController", category: "ViewController") + + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } + weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + + var disposeBag = Set() + private var observations = Set() + + var viewModel: ReportServerRulesViewModel! + private(set) lazy var reportServerRulesView = ReportServerRulesView(viewModel: viewModel) + + lazy var cancelBarButtonItem = UIBarButtonItem( + barButtonSystemItem: .cancel, + target: self, + action: #selector(ReportServerRulesViewController.cancelBarButtonItemDidPressed(_:)) + ) + + let navigationActionView: NavigationActionView = { + let navigationActionView = NavigationActionView() + navigationActionView.backgroundColor = Asset.Scene.Onboarding.background.color + navigationActionView.hidesBackButton = true + return navigationActionView + }() + + deinit { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } + +} + +extension ReportServerRulesViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + setupAppearance() + defer { setupNavigationBarBackgroundView() } + + let hostingViewController = UIHostingController(rootView: reportServerRulesView) + hostingViewController.view.preservesSuperviewLayoutMargins = true + addChild(hostingViewController) + hostingViewController.view.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(hostingViewController.view) + NSLayoutConstraint.activate([ + hostingViewController.view.topAnchor.constraint(equalTo: view.topAnchor), + hostingViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), + hostingViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), + hostingViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor), + ]) + + navigationActionView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(navigationActionView) + defer { + view.bringSubviewToFront(navigationActionView) + } + NSLayoutConstraint.activate([ + navigationActionView.leadingAnchor.constraint(equalTo: view.leadingAnchor), + navigationActionView.trailingAnchor.constraint(equalTo: view.trailingAnchor), + view.bottomAnchor.constraint(equalTo: navigationActionView.bottomAnchor), + ]) + + navigationActionView + .observe(\.bounds, options: [.initial, .new]) { [weak self] navigationActionView, _ in + guard let self = self else { return } + let inset = navigationActionView.frame.height + self.viewModel.bottomPaddingHeight = inset + } + .store(in: &observations) + + Publishers.CombineLatest( + viewModel.$selectRule, + viewModel.$isDislike + ) + .map { $0 != nil || $1 } + .assign(to: \.isEnabled, on: navigationActionView.nextButton) + .store(in: &disposeBag) + + navigationActionView.nextButton.addTarget(self, action: #selector(ReportServerRulesViewController.nextButtonPressed(_:)), for: .touchUpInside) + } + +} + +extension ReportServerRulesViewController { + + @objc private func cancelBarButtonItemDidPressed(_ sender: UIBarButtonItem) { + dismiss(animated: true, completion: nil) + } + + @objc private func nextButtonPressed(_ sender: UIButton) { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)") + + assert(viewModel.delegate != nil) + viewModel.delegate?.reportServerRulesViewController(self, nextButtonPressed: sender) + } + +} diff --git a/Mastodon/Scene/Report/ReportServerRules/ReportServerRulesViewModel.swift b/Mastodon/Scene/Report/ReportServerRules/ReportServerRulesViewModel.swift new file mode 100644 index 000000000..1960899a9 --- /dev/null +++ b/Mastodon/Scene/Report/ReportServerRules/ReportServerRulesViewModel.swift @@ -0,0 +1,35 @@ +// +// ReportServerRulesViewModel.swift +// Mastodon +// +// Created by MainasuK on 2022-5-10. +// + +import UIKit +import SwiftUI +import MastodonAsset +import MastodonSDK + +final class ReportServerRulesViewModel: ObservableObject { + + weak var delegate: ReportServerRulesViewControllerDelegate? + + // input + let context: AppContext + + @Published var headline = "Which rules are being violated?" + @Published var serverRules: [Mastodon.Entity.Instance.Rule] = [] + + @Published var bottomPaddingHeight: CGFloat = .zero + @Published var backgroundColor: UIColor = Asset.Scene.Report.background.color + + // output + @Published var selectRule: Mastodon.Entity.Instance.Rule? + @Published var isDislike: Bool = false + + init(context: AppContext) { + self.context = context + // end init + } + +} diff --git a/Mastodon/Scene/Report/ReportStatus/ReportViewController.swift b/Mastodon/Scene/Report/ReportStatus/ReportStatusViewController.swift similarity index 75% rename from Mastodon/Scene/Report/ReportStatus/ReportViewController.swift rename to Mastodon/Scene/Report/ReportStatus/ReportStatusViewController.swift index 12291a964..d3844a3be 100644 --- a/Mastodon/Scene/Report/ReportStatus/ReportViewController.swift +++ b/Mastodon/Scene/Report/ReportStatus/ReportStatusViewController.swift @@ -1,8 +1,8 @@ // -// ReportViewController.swift +// ReportStatusViewController.swift // Mastodon // -// Created by ihugo on 2021/4/20. +// Created by MainasuK on 2022-5-10. // import os.log @@ -12,21 +12,29 @@ import CoreDataStack import MastodonAsset import MastodonLocalization -class ReportViewController: UIViewController, NeedsDependency, ReportViewControllerAppearance { +protocol ReportStatusViewControllerDelegate: AnyObject { + func reportStatusViewController(_ viewController: ReportStatusViewController, skipButtonDidPressed button: UIButton) + func reportStatusViewController(_ viewController: ReportStatusViewController, nextButtonDidPressed button: UIButton) +} + +class ReportStatusViewController: UIViewController, NeedsDependency, ReportViewControllerAppearance { + + let logger = Logger(subsystem: "ReportStatusViewController", category: "ViewController") var disposeBag = Set() private var observations = Set() weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } - - var viewModel: ReportViewModel! + + var viewModel: ReportStatusViewModel! // MAKK: - UI + lazy var cancelBarButtonItem = UIBarButtonItem( barButtonSystemItem: .cancel, target: self, - action: #selector(ReportViewController.cancelBarButtonItemDidPressed(_:)) + action: #selector(ReportStatusViewController.cancelBarButtonItemDidPressed(_:)) ) let tableView: UITableView = { @@ -58,7 +66,7 @@ class ReportViewController: UIViewController, NeedsDependency, ReportViewControl } -extension ReportViewController { +extension ReportStatusViewController { override func viewDidLoad() { super.viewDidLoad() @@ -67,7 +75,7 @@ extension ReportViewController { defer { setupNavigationBarBackgroundView() } navigationItem.rightBarButtonItem = cancelBarButtonItem - + tableView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(tableView) NSLayoutConstraint.activate([ @@ -109,7 +117,7 @@ extension ReportViewController { .sink { [weak self] _ in guard let self = self else { return } guard self.view.window != nil else { return } - self.viewModel.stateMachine.enter(ReportViewModel.State.Loading.self) + self.viewModel.stateMachine.enter(ReportStatusViewModel.State.Loading.self) } .store(in: &disposeBag) @@ -118,56 +126,38 @@ extension ReportViewController { .assign(to: \.isEnabled, on: navigationActionView.nextButton) .store(in: &disposeBag) - navigationActionView.backButton.addTarget(self, action: #selector(ReportViewController.skipButtonDidPressed(_:)), for: .touchUpInside) - navigationActionView.nextButton.addTarget(self, action: #selector(ReportViewController.nextButtonDidPressed(_:)), for: .touchUpInside) + navigationActionView.backButton.addTarget(self, action: #selector(ReportStatusViewController.skipButtonDidPressed(_:)), for: .touchUpInside) + navigationActionView.nextButton.addTarget(self, action: #selector(ReportStatusViewController.nextButtonDidPressed(_:)), for: .touchUpInside) } } -extension ReportViewController { - +extension ReportStatusViewController { + @objc private func cancelBarButtonItemDidPressed(_ sender: UIBarButtonItem) { dismiss(animated: true, completion: nil) } - @objc func skipButtonDidPressed(_ sender: UIButton) { - var selectStatuses: [ManagedObjectRecord] = [] - if let selectStatus = viewModel.status { - selectStatuses.append(selectStatus) - } + @objc private func skipButtonDidPressed(_ sender: UIButton) { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)") - let reportSupplementaryViewModel = ReportSupplementaryViewModel( - context: context, - user: viewModel.user, - selectStatuses: selectStatuses - ) - coordinator.present( - scene: .reportSupplementary(viewModel: reportSupplementaryViewModel), - from: self, - transition: .show - ) + assert(viewModel.delegate != nil) + viewModel.isSkip = true + viewModel.delegate?.reportStatusViewController(self, skipButtonDidPressed: sender) } - @objc func nextButtonDidPressed(_ sender: UIButton) { - let selectStatuses = Array(viewModel.selectStatuses) - guard !selectStatuses.isEmpty else { return } + @objc private func nextButtonDidPressed(_ sender: UIButton) { + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)") - let reportSupplementaryViewModel = ReportSupplementaryViewModel( - context: context, - user: viewModel.user, - selectStatuses: selectStatuses - ) - coordinator.present( - scene: .reportSupplementary(viewModel: reportSupplementaryViewModel), - from: self, - transition: .show - ) + assert(viewModel.delegate != nil) + viewModel.isSkip = false + viewModel.delegate?.reportStatusViewController(self, nextButtonDidPressed: sender) } } // MARK: - UITableViewDelegate -extension ReportViewController: UITableViewDelegate { +extension ReportStatusViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? { guard let item = viewModel.diffableDataSource?.itemIdentifier(for: indexPath), case .status = item @@ -214,7 +204,7 @@ extension ReportViewController: UITableViewDelegate { } // MARK: - UIAdaptivePresentationControllerDelegate -extension ReportViewController: UIAdaptivePresentationControllerDelegate { +extension ReportStatusViewController: UIAdaptivePresentationControllerDelegate { func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool { return false } diff --git a/Mastodon/Scene/Report/ReportStatus/ReportViewModel+Diffable.swift b/Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel+Diffable.swift similarity index 93% rename from Mastodon/Scene/Report/ReportStatus/ReportViewModel+Diffable.swift rename to Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel+Diffable.swift index 30ec5d872..5bcc2f3d6 100644 --- a/Mastodon/Scene/Report/ReportStatus/ReportViewModel+Diffable.swift +++ b/Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel+Diffable.swift @@ -12,11 +12,11 @@ import CoreDataStack import MastodonAsset import MastodonLocalization -extension ReportViewModel { +extension ReportStatusViewModel { static let reportItemHeaderContext = ReportItem.HeaderContext( primaryLabelText: L10n.Scene.Report.content1, - secondaryLabelText: L10n.Scene.Report.step1 + secondaryLabelText: "Step 3 of 4" ) func setupDiffableDataSource( @@ -41,7 +41,7 @@ extension ReportViewModel { var snapshot = NSDiffableDataSourceSnapshot() snapshot.appendSections([.main]) - snapshot.appendItems([.header(context: ReportViewModel.reportItemHeaderContext)], toSection: .main) + snapshot.appendItems([.header(context: ReportStatusViewModel.reportItemHeaderContext)], toSection: .main) let items = records.map { ReportItem.status(record: $0) } snapshot.appendItems(items, toSection: .main) diff --git a/Mastodon/Scene/Report/ReportStatus/ReportViewModel+State.swift b/Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel+State.swift similarity index 92% rename from Mastodon/Scene/Report/ReportStatus/ReportViewModel+State.swift rename to Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel+State.swift index 1bc43830f..c653fc4ad 100644 --- a/Mastodon/Scene/Report/ReportStatus/ReportViewModel+State.swift +++ b/Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel+State.swift @@ -12,7 +12,7 @@ import CoreData import CoreDataStack import GameplayKit -extension ReportViewModel { +extension ReportStatusViewModel { class State: GKState { let logger = Logger(subsystem: "ReportViewModel.State", category: "StateMachine") @@ -23,15 +23,15 @@ extension ReportViewModel { String(describing: Self.self) } - weak var viewModel: ReportViewModel? + weak var viewModel: ReportStatusViewModel? - init(viewModel: ReportViewModel) { + init(viewModel: ReportStatusViewModel) { self.viewModel = viewModel } override func didEnter(from previousState: GKState?) { super.didEnter(from: previousState) - let previousState = previousState as? ReportViewModel.State + let previousState = previousState as? ReportStatusViewModel.State logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): [\(self.id.uuidString)] enter \(self.name), previous: \(previousState?.name ?? "")") } @@ -46,8 +46,8 @@ extension ReportViewModel { } } -extension ReportViewModel.State { - class Initial: ReportViewModel.State { +extension ReportStatusViewModel.State { + class Initial: ReportStatusViewModel.State { override func isValidNextState(_ stateClass: AnyClass) -> Bool { guard let _ = viewModel else { return false } switch stateClass { @@ -59,7 +59,7 @@ extension ReportViewModel.State { } } - class Loading: ReportViewModel.State { + class Loading: ReportStatusViewModel.State { override func isValidNextState(_ stateClass: AnyClass) -> Bool { switch stateClass { case is Fail.Type: @@ -128,7 +128,7 @@ extension ReportViewModel.State { } } - class Fail: ReportViewModel.State { + class Fail: ReportStatusViewModel.State { override func isValidNextState(_ stateClass: AnyClass) -> Bool { switch stateClass { case is Loading.Type: @@ -139,7 +139,7 @@ extension ReportViewModel.State { } } - class Idle: ReportViewModel.State { + class Idle: ReportStatusViewModel.State { override func isValidNextState(_ stateClass: AnyClass) -> Bool { switch stateClass { case is Loading.Type: @@ -150,7 +150,7 @@ extension ReportViewModel.State { } } - class NoMore: ReportViewModel.State { + class NoMore: ReportStatusViewModel.State { override func isValidNextState(_ stateClass: AnyClass) -> Bool { return false } diff --git a/Mastodon/Scene/Report/ReportStatus/ReportViewModel.swift b/Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel.swift similarity index 91% rename from Mastodon/Scene/Report/ReportStatus/ReportViewModel.swift rename to Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel.swift index 46a475262..239960637 100644 --- a/Mastodon/Scene/Report/ReportStatus/ReportViewModel.swift +++ b/Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel.swift @@ -1,8 +1,8 @@ // -// ReportViewModel.swift +// ReportStatusViewModel.swift // Mastodon // -// Created by ihugo on 2021/4/19. +// Created by MainasuK on 2022-5-10. // import Combine @@ -15,10 +15,12 @@ import OrderedCollections import os.log import UIKit -class ReportViewModel { +class ReportStatusViewModel { var disposeBag = Set() + weak var delegate: ReportStatusViewControllerDelegate? + // input let context: AppContext let user: ManagedObjectRecord @@ -26,6 +28,7 @@ class ReportViewModel { let statusFetchedResultsController: StatusFetchedResultsController let listBatchFetchViewModel = ListBatchFetchViewModel() + @Published var isSkip = false @Published var selectStatuses = OrderedSet>() // output diff --git a/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewController.swift b/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewController.swift index 4f6e102b2..10191f6ed 100644 --- a/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewController.swift +++ b/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewController.swift @@ -11,20 +11,25 @@ import Combine import MastodonAsset import MastodonLocalization +protocol ReportSupplementaryViewControllerDelegate: AnyObject { + func reportSupplementaryViewController(_ viewController: ReportSupplementaryViewController, skipButtonDidPressed button: UIButton) + func reportSupplementaryViewController(_ viewController: ReportSupplementaryViewController, nextButtonDidPressed button: UIButton) +} + final class ReportSupplementaryViewController: UIViewController, NeedsDependency, ReportViewControllerAppearance { let logger = Logger(subsystem: "ReportSupplementaryViewController", category: "ViewController") var disposeBag = Set() private var observations = Set() - + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } var viewModel: ReportSupplementaryViewModel! { willSet { precondition(!isViewLoaded) } } - // MAKK: - UI + lazy var cancelBarButtonItem = UIBarButtonItem( barButtonSystemItem: .cancel, target: self, @@ -74,16 +79,14 @@ extension ReportSupplementaryViewController { setupAppearance() defer { setupNavigationBarBackgroundView() } - navigationItem.rightBarButtonItem = cancelBarButtonItem - - viewModel.$isReporting + viewModel.$isBusy .receive(on: DispatchQueue.main) - .sink { [weak self] isReporting in + .sink { [weak self] isBusy in guard let self = self else { return } - self.navigationActionView.isUserInteractionEnabled = !isReporting + self.navigationItem.rightBarButtonItem = isBusy ? self.activityIndicatorBarButtonItem : self.cancelBarButtonItem } .store(in: &disposeBag) - + tableView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(tableView) NSLayoutConstraint.activate([ @@ -130,49 +133,25 @@ extension ReportSupplementaryViewController { } extension ReportSupplementaryViewController { - private func report(withComment: Bool) { - Task { - do { - let _ = try await viewModel.report(withComment: withComment) - logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): report success") - - let reportResultViewModel = ReportResultViewModel( - context: context, - user: viewModel.user - ) - - coordinator.present( - scene: .reportResult(viewModel: reportResultViewModel), - from: self, - transition: .show - ) - - } catch { - let alertController = UIAlertController(for: error, title: nil, preferredStyle: .alert) - let okAction = UIAlertAction(title: L10n.Common.Controls.Actions.ok, style: .default, handler: nil) - alertController.addAction(okAction) - self.coordinator.present( - scene: .alertController(alertController: alertController), - from: nil, - transition: .alertController(animated: true, completion: nil) - ) - } - } // end Task - } -} - -extension ReportSupplementaryViewController { - + @objc private func cancelBarButtonItemDidPressed(_ sender: UIBarButtonItem) { dismiss(animated: true, completion: nil) } @objc func skipButtonDidPressed(_ sender: UIButton) { - report(withComment: false) + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)") + + assert(viewModel.delegate != nil) + viewModel.isSkip = true + viewModel.delegate?.reportSupplementaryViewController(self, skipButtonDidPressed: sender) } @objc func nextButtonDidPressed(_ sender: UIButton) { - report(withComment: true) + logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)") + + assert(viewModel.delegate != nil) + viewModel.isSkip = false + viewModel.delegate?.reportSupplementaryViewController(self, nextButtonDidPressed: sender) } } diff --git a/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewModel+Diffable.swift b/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewModel+Diffable.swift index 5fb9e7421..e59617c35 100644 --- a/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewModel+Diffable.swift +++ b/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewModel+Diffable.swift @@ -15,8 +15,8 @@ import MastodonLocalization extension ReportSupplementaryViewModel { static let reportItemHeaderContext = ReportItem.HeaderContext( - primaryLabelText: L10n.Scene.Report.content2, - secondaryLabelText: L10n.Scene.Report.step2 + primaryLabelText: "Is there anything else we should know?", + secondaryLabelText: "Step 4 of 4" ) func setupDiffableDataSource( diff --git a/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewModel.swift b/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewModel.swift index e73e82dd6..4147d07d7 100644 --- a/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewModel.swift +++ b/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewModel.swift @@ -12,26 +12,26 @@ import MastodonSDK class ReportSupplementaryViewModel { + weak var delegate: ReportSupplementaryViewControllerDelegate? + // Input var context: AppContext let user: ManagedObjectRecord - let selectStatuses: [ManagedObjectRecord] let commentContext = ReportItem.CommentContext() + @Published var isSkip = false + @Published var isBusy = false + // output var diffableDataSource: UITableViewDiffableDataSource? @Published var isNextButtonEnabled = false - @Published var isReporting = false - @Published var isReportSuccess = false init( context: AppContext, - user: ManagedObjectRecord, - selectStatuses: [ManagedObjectRecord] + user: ManagedObjectRecord ) { self.context = context self.user = user - self.selectStatuses = selectStatuses // end init commentContext.$comment @@ -42,41 +42,3 @@ class ReportSupplementaryViewModel { } } - -extension ReportSupplementaryViewModel { - func report(withComment: Bool) async throws { - guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { - assertionFailure() - return - } - - let managedObjectContext = context.managedObjectContext - let _query: Mastodon.API.Reports.FileReportQuery? = try await managedObjectContext.perform { - guard let user = self.user.object(in: managedObjectContext) else { return nil } - let statusIDs = self.selectStatuses.compactMap { record -> Status.ID? in - guard let status = record.object(in: managedObjectContext) else { return nil } - return status.id - } - return Mastodon.API.Reports.FileReportQuery( - accountID: user.id, - statusIDs: statusIDs, - comment: withComment ? self.commentContext.comment : nil, - forward: nil - ) - } - - guard let query = _query else { return } - - do { - isReporting = true - let _ = try await context.apiService.report( - query: query, - authenticationBox: authenticationBox - ) - isReportSuccess = true - } catch { - isReporting = false - throw error - } - } -} diff --git a/Mastodon/Scene/Report/Share/Cell/ReportCommentTableViewCell.swift b/Mastodon/Scene/Report/Share/Cell/ReportCommentTableViewCell.swift index b982ee5ac..d735a094c 100644 --- a/Mastodon/Scene/Report/Share/Cell/ReportCommentTableViewCell.swift +++ b/Mastodon/Scene/Report/Share/Cell/ReportCommentTableViewCell.swift @@ -8,6 +8,7 @@ import UIKit import Combine import MastodonUI +import MastodonAsset import MastodonLocalization import UITextView_Placeholder @@ -27,7 +28,8 @@ final class ReportCommentTableViewCell: UITableViewCell { textView.attributedPlaceholder = NSAttributedString( string: L10n.Scene.Report.textPlaceholder, attributes: [ - .font: font + .font: font, + .foregroundColor: Asset.Colors.Label.secondary.color ] ) textView.textContainerInset = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16) @@ -80,4 +82,17 @@ extension ReportCommentTableViewCell { commentTextView.heightAnchor.constraint(greaterThanOrEqualToConstant: 100).priority(.defaultHigh), ]) } + + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + + commentTextView.attributedPlaceholder = NSAttributedString( + string: L10n.Scene.Report.textPlaceholder, + attributes: [ + .font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)), + .foregroundColor: Asset.Colors.Label.secondary.color + ] + ) + } + } diff --git a/Mastodon/Scene/Report/Share/ReportViewControllerAppearance.swift b/Mastodon/Scene/Report/Share/ReportViewControllerAppearance.swift index 6b35f3d89..fb9bcd63f 100644 --- a/Mastodon/Scene/Report/Share/ReportViewControllerAppearance.swift +++ b/Mastodon/Scene/Report/Share/ReportViewControllerAppearance.swift @@ -19,7 +19,7 @@ extension ReportViewControllerAppearance { func setupAppearance() { - title = L10n.Scene.Report.titleReport + // title = L10n.Scene.Report.titleReport view.backgroundColor = Asset.Scene.Report.background.color setupNavigationBarAppearance() diff --git a/Mastodon/Scene/Share/NavigationController/AdaptiveStatusBarStyleNavigationController.swift b/Mastodon/Scene/Share/NavigationController/AdaptiveStatusBarStyleNavigationController.swift index f4ad467da..ec145f86d 100644 --- a/Mastodon/Scene/Share/NavigationController/AdaptiveStatusBarStyleNavigationController.swift +++ b/Mastodon/Scene/Share/NavigationController/AdaptiveStatusBarStyleNavigationController.swift @@ -23,6 +23,7 @@ extension AdaptiveStatusBarStyleNavigationController { override func viewDidLoad() { super.viewDidLoad() + setupFullWidthBackGesture() } @@ -45,6 +46,11 @@ extension AdaptiveStatusBarStyleNavigationController: UIGestureRecognizerDelegat func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { let isSystemSwipeToBackEnabled = interactivePopGestureRecognizer?.isEnabled == true let isThereStackedViewControllers = viewControllers.count > 1 - return isSystemSwipeToBackEnabled && isThereStackedViewControllers + let isPanPopable = (topViewController as? PanPopableViewController)?.isPanPopable ?? true + return isSystemSwipeToBackEnabled && isThereStackedViewControllers && isPanPopable } } + +protocol PanPopableViewController: UIViewController { + var isPanPopable: Bool { get } +} From a88bb763fbbaf5f26715cbae4fd50a97be034db1 Mon Sep 17 00:00:00 2001 From: CMK Date: Tue, 10 May 2022 18:53:02 +0800 Subject: [PATCH 078/101] feat: add spam and other reason report flow path --- .../Report/Report/ReportViewController.swift | 29 +++++++++++++++++-- .../Scene/Report/Report/ReportViewModel.swift | 26 +++++++++++++---- .../ReportReasonViewController.swift | 12 -------- .../ReportSupplementaryViewController.swift | 2 ++ .../ReportSupplementaryViewModel.swift | 14 +++++---- 5 files changed, 57 insertions(+), 26 deletions(-) diff --git a/Mastodon/Scene/Report/Report/ReportViewController.swift b/Mastodon/Scene/Report/Report/ReportViewController.swift index 6d3f6da06..1fa8428e6 100644 --- a/Mastodon/Scene/Report/Report/ReportViewController.swift +++ b/Mastodon/Scene/Report/Report/ReportViewController.swift @@ -24,6 +24,12 @@ class ReportViewController: UIViewController, NeedsDependency, ReportViewControl var viewModel: ReportViewModel! + lazy var cancelBarButtonItem = UIBarButtonItem( + barButtonSystemItem: .cancel, + target: self, + action: #selector(ReportViewController.cancelBarButtonItemDidPressed(_:)) + ) + deinit { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) } @@ -38,6 +44,8 @@ extension ReportViewController { setupAppearance() defer { setupNavigationBarBackgroundView() } + navigationItem.rightBarButtonItem = cancelBarButtonItem + viewModel.reportReasonViewModel.delegate = self viewModel.reportServerRulesViewModel.delegate = self viewModel.reportStatusViewModel.delegate = self @@ -62,6 +70,14 @@ extension ReportViewController { } +extension ReportViewController { + + @objc private func cancelBarButtonItemDidPressed(_ sender: UIBarButtonItem) { + dismiss(animated: true, completion: nil) + } + +} + // MARK: - UIAdaptivePresentationControllerDelegate extension ReportViewController: UIAdaptivePresentationControllerDelegate { func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool { @@ -74,14 +90,21 @@ extension ReportViewController: ReportReasonViewControllerDelegate { func reportReasonViewController(_ viewController: ReportReasonViewController, nextButtonPressed button: UIButton) { guard let reason = viewController.viewModel.selectReason else { return } switch reason { + case .dislike: + // TODO: + break case .violateRule: coordinator.present( scene: .reportServerRules(viewModel: viewModel.reportServerRulesViewModel), from: self, transition: .show ) - default: - break + case .spam, .other: + coordinator.present( + scene: .reportStatus(viewModel: viewModel.reportStatusViewModel), + from: self, + transition: .show + ) } } } @@ -90,7 +113,7 @@ extension ReportViewController: ReportReasonViewControllerDelegate { extension ReportViewController: ReportServerRulesViewControllerDelegate { func reportServerRulesViewController(_ viewController: ReportServerRulesViewController, nextButtonPressed button: UIButton) { if viewController.viewModel.isDislike { - + // TODO: } else if viewController.viewModel.selectRule != nil { coordinator.present( scene: .reportStatus(viewModel: viewModel.reportStatusViewModel), diff --git a/Mastodon/Scene/Report/Report/ReportViewModel.swift b/Mastodon/Scene/Report/Report/ReportViewModel.swift index 73bac19b0..590aed87d 100644 --- a/Mastodon/Scene/Report/Report/ReportViewModel.swift +++ b/Mastodon/Scene/Report/Report/ReportViewModel.swift @@ -104,6 +104,9 @@ extension ReportViewModel { let managedObjectContext = context.managedObjectContext let _query: Mastodon.API.Reports.FileReportQuery? = try await managedObjectContext.perform { guard let user = self.user.object(in: managedObjectContext) else { return nil } + + // the status picker is essential step in report flow + // only check isSkip or not let statusIDs: [Status.ID]? = { if self.reportStatusViewModel.isSkip { let _id: Status.ID? = self.reportStatusViewModel.status.flatMap { record -> Status.ID? in @@ -118,10 +121,15 @@ extension ReportViewModel { } } }() + + // the user comment is essential step in report flow + // only check isSkip or not let comment: String? = { var suffixes: [String] = [] let content: String? + // the server rules is NOT essential step in report flow + // append suffix depends which reason if let reason = self.reportReasonViewModel.selectReason { switch reason { case .spam: @@ -130,9 +138,12 @@ extension ReportViewModel { suffixes.append(reason.rawValue) if let rule = self.reportServerRulesViewModel.selectRule { suffixes.append(rule.text) + } else { + assertionFailure("should select valid rule") } - - case .dislike, .other: + case .dislike: + assertionFailure("should not enter the report flow") + case .other: break } } @@ -162,11 +173,14 @@ extension ReportViewModel { do { isReporting = true + #if DEBUG try await Task.sleep(nanoseconds: .second * 3) -// let _ = try await context.apiService.report( -// query: query, -// authenticationBox: authenticationBox -// ) + #else + let _ = try await context.apiService.report( + query: query, + authenticationBox: authenticationBox + ) + #endif isReportSuccess = true } catch { isReporting = false diff --git a/Mastodon/Scene/Report/ReportReason/ReportReasonViewController.swift b/Mastodon/Scene/Report/ReportReason/ReportReasonViewController.swift index b0651e42d..ac5d9e797 100644 --- a/Mastodon/Scene/Report/ReportReason/ReportReasonViewController.swift +++ b/Mastodon/Scene/Report/ReportReason/ReportReasonViewController.swift @@ -30,12 +30,6 @@ final class ReportReasonViewController: UIViewController, NeedsDependency, Repor var viewModel: ReportReasonViewModel! private(set) lazy var reportReasonView = ReportReasonView(viewModel: viewModel) - lazy var cancelBarButtonItem = UIBarButtonItem( - barButtonSystemItem: .cancel, - target: self, - action: #selector(ReportReasonViewController.cancelBarButtonItemDidPressed(_:)) - ) - let navigationActionView: NavigationActionView = { let navigationActionView = NavigationActionView() navigationActionView.backgroundColor = Asset.Scene.Onboarding.background.color @@ -57,8 +51,6 @@ extension ReportReasonViewController { setupAppearance() defer { setupNavigationBarBackgroundView() } - navigationItem.rightBarButtonItem = cancelBarButtonItem - let hostingViewController = UIHostingController(rootView: reportReasonView) hostingViewController.view.preservesSuperviewLayoutMargins = true addChild(hostingViewController) @@ -102,10 +94,6 @@ extension ReportReasonViewController { extension ReportReasonViewController { - @objc private func cancelBarButtonItemDidPressed(_ sender: UIBarButtonItem) { - dismiss(animated: true, completion: nil) - } - @objc private func nextButtonPressed(_ sender: UIButton) { logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)") diff --git a/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewController.swift b/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewController.swift index 10191f6ed..fd7783170 100644 --- a/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewController.swift +++ b/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewController.swift @@ -84,6 +84,8 @@ extension ReportSupplementaryViewController { .sink { [weak self] isBusy in guard let self = self else { return } self.navigationItem.rightBarButtonItem = isBusy ? self.activityIndicatorBarButtonItem : self.cancelBarButtonItem + self.navigationItem.hidesBackButton = isBusy + self.navigationActionView.backButton.isUserInteractionEnabled = !isBusy } .store(in: &disposeBag) diff --git a/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewModel.swift b/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewModel.swift index 4147d07d7..c07ee1f54 100644 --- a/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewModel.swift +++ b/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewModel.swift @@ -34,11 +34,15 @@ class ReportSupplementaryViewModel { self.user = user // end init - commentContext.$comment - .map { comment -> Bool in - return !comment.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty - } - .assign(to: &$isNextButtonEnabled) + Publishers.CombineLatest( + commentContext.$comment, + $isBusy + ) + .map { comment, isBusy -> Bool in + guard !isBusy else { return false } + return !comment.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty + } + .assign(to: &$isNextButtonEnabled) } } From 18bd5d66d2181d46d6b66cb939490c2f2ef05184 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 11 May 2022 11:04:48 +0800 Subject: [PATCH 079/101] chore: add profile scheme and build configuration --- Mastodon.xcodeproj/project.pbxproj | 347 +++++++++++++++--- .../xcschemes/xcschememanagement.plist | 29 +- Mastodon/Supporting Files/SceneDelegate.swift | 8 +- 3 files changed, 320 insertions(+), 64 deletions(-) diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 400e4d73f..b9105dcda 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -818,7 +818,10 @@ 5DDDF1A82617489F00311060 /* Mastodon+Entity+History.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Mastodon+Entity+History.swift"; sourceTree = ""; }; 5DF1056325F887CB00D6C0D4 /* AVPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AVPlayer.swift; sourceTree = ""; }; 6130CBE4B26E3C976ACC1688 /* Pods-ShareActionExtension.asdk - debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShareActionExtension.asdk - debug.xcconfig"; path = "Target Support Files/Pods-ShareActionExtension/Pods-ShareActionExtension.asdk - debug.xcconfig"; sourceTree = ""; }; + 63EF9E6E5B575CD2A8B0475D /* Pods-AppShared.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppShared.profile.xcconfig"; path = "Target Support Files/Pods-AppShared/Pods-AppShared.profile.xcconfig"; sourceTree = ""; }; + 728DE51ADA27C395C6E1BAB5 /* Pods-Mastodon-MastodonUITests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-MastodonUITests.profile.xcconfig"; path = "Target Support Files/Pods-Mastodon-MastodonUITests/Pods-Mastodon-MastodonUITests.profile.xcconfig"; sourceTree = ""; }; 75E3471C898DDD9631729B6E /* Pods-Mastodon.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon.release.xcconfig"; path = "Target Support Files/Pods-Mastodon/Pods-Mastodon.release.xcconfig"; sourceTree = ""; }; + 7CB58D292DA7ACEF179A9050 /* Pods-Mastodon.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon.profile.xcconfig"; path = "Target Support Files/Pods-Mastodon/Pods-Mastodon.profile.xcconfig"; sourceTree = ""; }; 7CEFFAE9AF9284B13C0A758D /* Pods-MastodonTests.asdk - debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonTests.asdk - debug.xcconfig"; path = "Target Support Files/Pods-MastodonTests/Pods-MastodonTests.asdk - debug.xcconfig"; sourceTree = ""; }; 819CEC9DCAD8E8E7BD85A7BB /* Pods-Mastodon.asdk.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon.asdk.xcconfig"; path = "Target Support Files/Pods-Mastodon/Pods-Mastodon.asdk.xcconfig"; sourceTree = ""; }; 8850E70A1D5FF51432E43653 /* Pods-Mastodon-MastodonUITests.asdk - release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-MastodonUITests.asdk - release.xcconfig"; path = "Target Support Files/Pods-Mastodon-MastodonUITests/Pods-Mastodon-MastodonUITests.asdk - release.xcconfig"; sourceTree = ""; }; @@ -1385,6 +1388,7 @@ DBFEF07226A6913D006D7ED1 /* APIService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIService.swift; sourceTree = ""; }; DBFEF07A26A6BCE8006D7ED1 /* APIService+Status+Publish.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Status+Publish.swift"; sourceTree = ""; }; DDB1B139FA8EA26F510D58B6 /* Pods-AppShared.asdk - release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppShared.asdk - release.xcconfig"; path = "Target Support Files/Pods-AppShared/Pods-AppShared.asdk - release.xcconfig"; sourceTree = ""; }; + DF65937EC1FF64462BC002EE /* Pods-MastodonTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonTests.profile.xcconfig"; path = "Target Support Files/Pods-MastodonTests/Pods-MastodonTests.profile.xcconfig"; sourceTree = ""; }; E5C7236E58D14A0322FE00F2 /* Pods-Mastodon-MastodonUITests.asdk - debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-MastodonUITests.asdk - debug.xcconfig"; path = "Target Support Files/Pods-Mastodon-MastodonUITests/Pods-Mastodon-MastodonUITests.asdk - debug.xcconfig"; sourceTree = ""; }; E9AABD3D26B64B8C00E237DA /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Intents.strings; sourceTree = ""; }; E9AABD4026B64B8D00E237DA /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/InfoPlist.strings; sourceTree = ""; }; @@ -1587,6 +1591,10 @@ 0655B257371274BEB7EB1C19 /* Pods-Mastodon.release snapshot.xcconfig */, 0827D1674B2523503E8605F6 /* Pods-Mastodon-MastodonUITests.release snapshot.xcconfig */, 8E79CCBE51FBC3F7FE8CF49F /* Pods-MastodonTests.release snapshot.xcconfig */, + 63EF9E6E5B575CD2A8B0475D /* Pods-AppShared.profile.xcconfig */, + 7CB58D292DA7ACEF179A9050 /* Pods-Mastodon.profile.xcconfig */, + 728DE51ADA27C395C6E1BAB5 /* Pods-Mastodon-MastodonUITests.profile.xcconfig */, + DF65937EC1FF64462BC002EE /* Pods-MastodonTests.profile.xcconfig */, ); path = Pods; sourceTree = ""; @@ -3586,23 +3594,23 @@ ); mainGroup = DB427DC925BAA00100D1B89D; packageReferences = ( - DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */, + DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage.git" */, 2D61336725C18A4F00CAE157 /* XCRemoteSwiftPackageReference "AlamofireNetworkActivityIndicator" */, DB0140BB25C40D7500F9F3CF /* XCRemoteSwiftPackageReference "CommonOSLog" */, - 2D5981B825E4D7F8000FB903 /* XCRemoteSwiftPackageReference "ThirdPartyMailer" */, - 2D939AC625EE14620076FA61 /* XCRemoteSwiftPackageReference "TOCropViewController" */, + 2D5981B825E4D7F8000FB903 /* XCRemoteSwiftPackageReference "ThirdPartyMailer.git" */, + 2D939AC625EE14620076FA61 /* XCRemoteSwiftPackageReference "TOCropViewController.git" */, DBB525062611EAC0002F1F29 /* XCRemoteSwiftPackageReference "Tabman" */, - DB6804722637CC1200430867 /* XCRemoteSwiftPackageReference "KeychainAccess" */, - DBAC6481267D0B21007FE9FD /* XCRemoteSwiftPackageReference "DifferenceKit" */, - DBAC649C267DFE43007FE9FD /* XCRemoteSwiftPackageReference "DiffableDataSources" */, - DBAC649F267E6D01007FE9FD /* XCRemoteSwiftPackageReference "Fuzi" */, - DBF7A0FA26830C33004176A2 /* XCRemoteSwiftPackageReference "FPSIndicator" */, - DB0E2D2C26833FF600865C3C /* XCRemoteSwiftPackageReference "Nuke-FLAnimatedImage-Plugin" */, - DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit" */, - DB552D4D26BBD10C00E481F6 /* XCRemoteSwiftPackageReference "swift-collections" */, - DBA5A52D26F07ED800CACBAA /* XCRemoteSwiftPackageReference "PanModal" */, - DB8D8E2D28192EED009FD90F /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */, - DB3EA8F6281BBA4C00598866 /* XCRemoteSwiftPackageReference "Alamofire" */, + DB6804722637CC1200430867 /* XCRemoteSwiftPackageReference "KeychainAccess.git" */, + DBAC6481267D0B21007FE9FD /* XCRemoteSwiftPackageReference "DifferenceKit.git" */, + DBAC649C267DFE43007FE9FD /* XCRemoteSwiftPackageReference "DiffableDataSources.git" */, + DBAC649F267E6D01007FE9FD /* XCRemoteSwiftPackageReference "Fuzi.git" */, + DBF7A0FA26830C33004176A2 /* XCRemoteSwiftPackageReference "FPSIndicator.git" */, + DB0E2D2C26833FF600865C3C /* XCRemoteSwiftPackageReference "Nuke-FLAnimatedImage-Plugin.git" */, + DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit.git" */, + DB552D4D26BBD10C00E481F6 /* XCRemoteSwiftPackageReference "swift-collections.git" */, + DBA5A52D26F07ED800CACBAA /* XCRemoteSwiftPackageReference "PanModal.git" */, + DB8D8E2D28192EED009FD90F /* XCRemoteSwiftPackageReference "SwiftUI-Introspect.git" */, + DB3EA8F6281BBA4C00598866 /* XCRemoteSwiftPackageReference "Alamofire.git" */, ); productRefGroup = DB427DD325BAA00100D1B89D /* Products */; projectDirPath = ""; @@ -4668,7 +4676,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -4955,6 +4963,241 @@ }; name = Release; }; + DB848E2A282B5E6300A302CC /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "PROFILE=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INTENTS_CODEGEN_LANGUAGE = Swift; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = PROFILE; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + DB848E2B282B5E6300A302CC /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7CB58D292DA7ACEF179A9050 /* Pods-Mastodon.profile.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 126; + DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; + DEVELOPMENT_TEAM = 5Z4GVSS33P; + INFOPLIST_FILE = Mastodon/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0.7; + PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OBJC_BRIDGING_HEADER = "Mastodon/Vender/Mastodon-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + DB848E2C282B5E6300A302CC /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = DF65937EC1FF64462BC002EE /* Pods-MastodonTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 5Z4GVSS33P; + INFOPLIST_FILE = MastodonTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.MastodonTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Mastodon.app/Mastodon"; + }; + name = Profile; + }; + DB848E2D282B5E6300A302CC /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 728DE51ADA27C395C6E1BAB5 /* Pods-Mastodon-MastodonUITests.profile.xcconfig */; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 5Z4GVSS33P; + INFOPLIST_FILE = MastodonUITests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.MastodonUITests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_TARGET_NAME = Mastodon; + }; + name = Profile; + }; + DB848E2E282B5E6300A302CC /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 63EF9E6E5B575CD2A8B0475D /* Pods-AppShared.profile.xcconfig */; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 126; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = 5Z4GVSS33P; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 126; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = AppShared/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.AppShared; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Profile; + }; + DB848E2F282B5E6300A302CC /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 126; + DEVELOPMENT_TEAM = 5Z4GVSS33P; + INFOPLIST_FILE = NotificationService/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + MARKETING_VERSION = 1.0.7; + PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.NotificationService; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + DB848E30282B5E6300A302CC /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 126; + DEVELOPMENT_TEAM = 5Z4GVSS33P; + INFOPLIST_FILE = ShareActionExtension/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + MARKETING_VERSION = 1.0.7; + PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.ShareActionExtension; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + DB848E31282B5E6300A302CC /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 126; + DEVELOPMENT_TEAM = 5Z4GVSS33P; + INFOPLIST_FILE = MastodonIntent/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + MARKETING_VERSION = 1.0.7; + PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.MastodonIntent; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; DB8FABD026AEC7B2008E5AF4 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -5333,6 +5576,7 @@ isa = XCConfigurationList; buildConfigurations = ( DB427DFA25BAA00100D1B89D /* Debug */, + DB848E2A282B5E6300A302CC /* Profile */, DB427DFB25BAA00100D1B89D /* Release */, DBEB19E127E4658E00B0E80E /* Release Snapshot */, ); @@ -5343,6 +5587,7 @@ isa = XCConfigurationList; buildConfigurations = ( DB427DFD25BAA00100D1B89D /* Debug */, + DB848E2B282B5E6300A302CC /* Profile */, DB427DFE25BAA00100D1B89D /* Release */, DBEB19E227E4658E00B0E80E /* Release Snapshot */, ); @@ -5353,6 +5598,7 @@ isa = XCConfigurationList; buildConfigurations = ( DB427E0025BAA00100D1B89D /* Debug */, + DB848E2C282B5E6300A302CC /* Profile */, DB427E0125BAA00100D1B89D /* Release */, DBEB19E327E4658E00B0E80E /* Release Snapshot */, ); @@ -5363,6 +5609,7 @@ isa = XCConfigurationList; buildConfigurations = ( DB427E0325BAA00100D1B89D /* Debug */, + DB848E2D282B5E6300A302CC /* Profile */, DB427E0425BAA00100D1B89D /* Release */, DBEB19E427E4658E00B0E80E /* Release Snapshot */, ); @@ -5373,6 +5620,7 @@ isa = XCConfigurationList; buildConfigurations = ( DB6804892637CD4C00430867 /* Debug */, + DB848E2E282B5E6300A302CC /* Profile */, DB68048A2637CD4C00430867 /* Release */, DBEB19E527E4658E00B0E80E /* Release Snapshot */, ); @@ -5383,6 +5631,7 @@ isa = XCConfigurationList; buildConfigurations = ( DB8FABD026AEC7B2008E5AF4 /* Debug */, + DB848E31282B5E6300A302CC /* Profile */, DB8FABD326AEC7B2008E5AF4 /* Release */, DBEB19E827E4658E00B0E80E /* Release Snapshot */, ); @@ -5393,6 +5642,7 @@ isa = XCConfigurationList; buildConfigurations = ( DBC6461D26A170AB00B0E31B /* Debug */, + DB848E30282B5E6300A302CC /* Profile */, DBC6462026A170AB00B0E31B /* Release */, DBEB19E727E4658E00B0E80E /* Release Snapshot */, ); @@ -5403,6 +5653,7 @@ isa = XCConfigurationList; buildConfigurations = ( DBF8AE1C263293E400C9C23C /* Debug */, + DB848E2F282B5E6300A302CC /* Profile */, DBF8AE1D263293E400C9C23C /* Release */, DBEB19E627E4658E00B0E80E /* Release Snapshot */, ); @@ -5412,7 +5663,7 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ - 2D5981B825E4D7F8000FB903 /* XCRemoteSwiftPackageReference "ThirdPartyMailer" */ = { + 2D5981B825E4D7F8000FB903 /* XCRemoteSwiftPackageReference "ThirdPartyMailer.git" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/vtourraine/ThirdPartyMailer.git"; requirement = { @@ -5428,7 +5679,7 @@ minimumVersion = 3.1.0; }; }; - 2D939AC625EE14620076FA61 /* XCRemoteSwiftPackageReference "TOCropViewController" */ = { + 2D939AC625EE14620076FA61 /* XCRemoteSwiftPackageReference "TOCropViewController.git" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/TimOliver/TOCropViewController.git"; requirement = { @@ -5444,7 +5695,7 @@ minimumVersion = 0.1.1; }; }; - DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit" */ = { + DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit.git" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/TwidereProject/MetaTextKit.git"; requirement = { @@ -5452,7 +5703,7 @@ version = 2.2.3; }; }; - DB0E2D2C26833FF600865C3C /* XCRemoteSwiftPackageReference "Nuke-FLAnimatedImage-Plugin" */ = { + DB0E2D2C26833FF600865C3C /* XCRemoteSwiftPackageReference "Nuke-FLAnimatedImage-Plugin.git" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/kean/Nuke-FLAnimatedImage-Plugin.git"; requirement = { @@ -5460,7 +5711,7 @@ minimumVersion = 8.0.0; }; }; - DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */ = { + DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage.git" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/Alamofire/AlamofireImage.git"; requirement = { @@ -5468,7 +5719,7 @@ minimumVersion = 4.1.0; }; }; - DB3EA8F6281BBA4C00598866 /* XCRemoteSwiftPackageReference "Alamofire" */ = { + DB3EA8F6281BBA4C00598866 /* XCRemoteSwiftPackageReference "Alamofire.git" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/Alamofire/Alamofire.git"; requirement = { @@ -5476,7 +5727,7 @@ minimumVersion = 5.4.0; }; }; - DB552D4D26BBD10C00E481F6 /* XCRemoteSwiftPackageReference "swift-collections" */ = { + DB552D4D26BBD10C00E481F6 /* XCRemoteSwiftPackageReference "swift-collections.git" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/apple/swift-collections.git"; requirement = { @@ -5484,7 +5735,7 @@ minimumVersion = 0.0.5; }; }; - DB6804722637CC1200430867 /* XCRemoteSwiftPackageReference "KeychainAccess" */ = { + DB6804722637CC1200430867 /* XCRemoteSwiftPackageReference "KeychainAccess.git" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/kishikawakatsumi/KeychainAccess.git"; requirement = { @@ -5492,7 +5743,7 @@ minimumVersion = 4.2.2; }; }; - DB8D8E2D28192EED009FD90F /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */ = { + DB8D8E2D28192EED009FD90F /* XCRemoteSwiftPackageReference "SwiftUI-Introspect.git" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/siteline/SwiftUI-Introspect.git"; requirement = { @@ -5500,7 +5751,7 @@ minimumVersion = 0.1.4; }; }; - DBA5A52D26F07ED800CACBAA /* XCRemoteSwiftPackageReference "PanModal" */ = { + DBA5A52D26F07ED800CACBAA /* XCRemoteSwiftPackageReference "PanModal.git" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/slackhq/PanModal.git"; requirement = { @@ -5508,7 +5759,7 @@ minimumVersion = 1.2.7; }; }; - DBAC6481267D0B21007FE9FD /* XCRemoteSwiftPackageReference "DifferenceKit" */ = { + DBAC6481267D0B21007FE9FD /* XCRemoteSwiftPackageReference "DifferenceKit.git" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/ra1028/DifferenceKit.git"; requirement = { @@ -5516,7 +5767,7 @@ version = 1.2.0; }; }; - DBAC649C267DFE43007FE9FD /* XCRemoteSwiftPackageReference "DiffableDataSources" */ = { + DBAC649C267DFE43007FE9FD /* XCRemoteSwiftPackageReference "DiffableDataSources.git" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/MainasuK/DiffableDataSources.git"; requirement = { @@ -5524,7 +5775,7 @@ kind = branch; }; }; - DBAC649F267E6D01007FE9FD /* XCRemoteSwiftPackageReference "Fuzi" */ = { + DBAC649F267E6D01007FE9FD /* XCRemoteSwiftPackageReference "Fuzi.git" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/cezheng/Fuzi.git"; requirement = { @@ -5540,7 +5791,7 @@ minimumVersion = 2.11.0; }; }; - DBF7A0FA26830C33004176A2 /* XCRemoteSwiftPackageReference "FPSIndicator" */ = { + DBF7A0FA26830C33004176A2 /* XCRemoteSwiftPackageReference "FPSIndicator.git" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/MainasuK/FPSIndicator.git"; requirement = { @@ -5553,7 +5804,7 @@ /* Begin XCSwiftPackageProductDependency section */ 2D5981B925E4D7F8000FB903 /* ThirdPartyMailer */ = { isa = XCSwiftPackageProductDependency; - package = 2D5981B825E4D7F8000FB903 /* XCRemoteSwiftPackageReference "ThirdPartyMailer" */; + package = 2D5981B825E4D7F8000FB903 /* XCRemoteSwiftPackageReference "ThirdPartyMailer.git" */; productName = ThirdPartyMailer; }; 2D61336825C18A4F00CAE157 /* AlamofireNetworkActivityIndicator */ = { @@ -5563,12 +5814,12 @@ }; 2D939AC725EE14620076FA61 /* CropViewController */ = { isa = XCSwiftPackageProductDependency; - package = 2D939AC625EE14620076FA61 /* XCRemoteSwiftPackageReference "TOCropViewController" */; + package = 2D939AC625EE14620076FA61 /* XCRemoteSwiftPackageReference "TOCropViewController.git" */; productName = CropViewController; }; DB02EA0A280D180D00E751C5 /* KeychainAccess */ = { isa = XCSwiftPackageProductDependency; - package = DB6804722637CC1200430867 /* XCRemoteSwiftPackageReference "KeychainAccess" */; + package = DB6804722637CC1200430867 /* XCRemoteSwiftPackageReference "KeychainAccess.git" */; productName = KeychainAccess; }; DB3EA8F4281BB65200598866 /* MastodonSDK */ = { @@ -5577,17 +5828,17 @@ }; DB3EA8FB281BBAE100598866 /* AlamofireImage */ = { isa = XCSwiftPackageProductDependency; - package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */; + package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage.git" */; productName = AlamofireImage; }; DB3EA8FD281BBAF200598866 /* Alamofire */ = { isa = XCSwiftPackageProductDependency; - package = DB3EA8F6281BBA4C00598866 /* XCRemoteSwiftPackageReference "Alamofire" */; + package = DB3EA8F6281BBA4C00598866 /* XCRemoteSwiftPackageReference "Alamofire.git" */; productName = Alamofire; }; DB3EA8FF281BBB1D00598866 /* MetaTextKit */ = { isa = XCSwiftPackageProductDependency; - package = DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit" */; + package = DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit.git" */; productName = MetaTextKit; }; DB3EA901281BBD5D00598866 /* CommonOSLog */ = { @@ -5597,12 +5848,12 @@ }; DB3EA903281BBD9400598866 /* Introspect */ = { isa = XCSwiftPackageProductDependency; - package = DB8D8E2D28192EED009FD90F /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */; + package = DB8D8E2D28192EED009FD90F /* XCRemoteSwiftPackageReference "SwiftUI-Introspect.git" */; productName = Introspect; }; DB3EA905281BBE8200598866 /* AlamofireImage */ = { isa = XCSwiftPackageProductDependency; - package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */; + package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage.git" */; productName = AlamofireImage; }; DB3EA907281BBE8200598866 /* AlamofireNetworkActivityIndicator */ = { @@ -5612,12 +5863,12 @@ }; DB3EA909281BBE8200598866 /* Alamofire */ = { isa = XCSwiftPackageProductDependency; - package = DB3EA8F6281BBA4C00598866 /* XCRemoteSwiftPackageReference "Alamofire" */; + package = DB3EA8F6281BBA4C00598866 /* XCRemoteSwiftPackageReference "Alamofire.git" */; productName = Alamofire; }; DB3EA90B281BBE9600598866 /* AlamofireImage */ = { isa = XCSwiftPackageProductDependency; - package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */; + package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage.git" */; productName = AlamofireImage; }; DB3EA90D281BBE9600598866 /* AlamofireNetworkActivityIndicator */ = { @@ -5627,42 +5878,42 @@ }; DB3EA90F281BBE9600598866 /* Alamofire */ = { isa = XCSwiftPackageProductDependency; - package = DB3EA8F6281BBA4C00598866 /* XCRemoteSwiftPackageReference "Alamofire" */; + package = DB3EA8F6281BBA4C00598866 /* XCRemoteSwiftPackageReference "Alamofire.git" */; productName = Alamofire; }; DB3EA911281BBEA800598866 /* AlamofireImage */ = { isa = XCSwiftPackageProductDependency; - package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */; + package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage.git" */; productName = AlamofireImage; }; DB3EA913281BBEA800598866 /* Alamofire */ = { isa = XCSwiftPackageProductDependency; - package = DB3EA8F6281BBA4C00598866 /* XCRemoteSwiftPackageReference "Alamofire" */; + package = DB3EA8F6281BBA4C00598866 /* XCRemoteSwiftPackageReference "Alamofire.git" */; productName = Alamofire; }; DB552D4E26BBD10C00E481F6 /* OrderedCollections */ = { isa = XCSwiftPackageProductDependency; - package = DB552D4D26BBD10C00E481F6 /* XCRemoteSwiftPackageReference "swift-collections" */; + package = DB552D4D26BBD10C00E481F6 /* XCRemoteSwiftPackageReference "swift-collections.git" */; productName = OrderedCollections; }; DBA5A52E26F07ED800CACBAA /* PanModal */ = { isa = XCSwiftPackageProductDependency; - package = DBA5A52D26F07ED800CACBAA /* XCRemoteSwiftPackageReference "PanModal" */; + package = DBA5A52D26F07ED800CACBAA /* XCRemoteSwiftPackageReference "PanModal.git" */; productName = PanModal; }; DBAC6482267D0B21007FE9FD /* DifferenceKit */ = { isa = XCSwiftPackageProductDependency; - package = DBAC6481267D0B21007FE9FD /* XCRemoteSwiftPackageReference "DifferenceKit" */; + package = DBAC6481267D0B21007FE9FD /* XCRemoteSwiftPackageReference "DifferenceKit.git" */; productName = DifferenceKit; }; DBAC649D267DFE43007FE9FD /* DiffableDataSources */ = { isa = XCSwiftPackageProductDependency; - package = DBAC649C267DFE43007FE9FD /* XCRemoteSwiftPackageReference "DiffableDataSources" */; + package = DBAC649C267DFE43007FE9FD /* XCRemoteSwiftPackageReference "DiffableDataSources.git" */; productName = DiffableDataSources; }; DBAC64A0267E6D02007FE9FD /* Fuzi */ = { isa = XCSwiftPackageProductDependency; - package = DBAC649F267E6D01007FE9FD /* XCRemoteSwiftPackageReference "Fuzi" */; + package = DBAC649F267E6D01007FE9FD /* XCRemoteSwiftPackageReference "Fuzi.git" */; productName = Fuzi; }; DBB525072611EAC0002F1F29 /* Tabman */ = { @@ -5672,7 +5923,7 @@ }; DBF7A0FB26830C33004176A2 /* FPSIndicator */ = { isa = XCSwiftPackageProductDependency; - package = DBF7A0FA26830C33004176A2 /* XCRemoteSwiftPackageReference "FPSIndicator" */; + package = DBF7A0FA26830C33004176A2 /* XCRemoteSwiftPackageReference "FPSIndicator.git" */; productName = FPSIndicator; }; /* End XCSwiftPackageProductDependency section */ diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 7f54b9011..3d2d4b728 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -9,33 +9,38 @@ isShown orderHint - 4 + 5 CoreDataStack.xcscheme_^#shared#^_ orderHint 27 - Mastodon - RTL.xcscheme_^#shared#^_ - - orderHint - 6 - - Mastodon - Release.xcscheme_^#shared#^_ + Mastodon - Profile.xcscheme_^#shared#^_ orderHint 1 - Mastodon - Snapshot.xcscheme_^#shared#^_ + Mastodon - RTL.xcscheme_^#shared#^_ + + orderHint + 7 + + Mastodon - Release.xcscheme_^#shared#^_ orderHint 2 - Mastodon - ar.xcscheme + Mastodon - Snapshot.xcscheme_^#shared#^_ orderHint 3 + Mastodon - ar.xcscheme + + orderHint + 4 + Mastodon - ar.xcscheme_^#shared#^_ orderHint @@ -109,7 +114,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 20 + 27 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +129,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 19 + 29 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 21 + 28 SuppressBuildableAutocreation diff --git a/Mastodon/Supporting Files/SceneDelegate.swift b/Mastodon/Supporting Files/SceneDelegate.swift index d178cd0d3..54b1fd57e 100644 --- a/Mastodon/Supporting Files/SceneDelegate.swift +++ b/Mastodon/Supporting Files/SceneDelegate.swift @@ -10,7 +10,7 @@ import UIKit import Combine import CoreDataStack -#if DEBUG +#if PROFILE import FPSIndicator #endif @@ -22,7 +22,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? var coordinator: SceneCoordinator? - #if DEBUG + #if PROFILE var fpsIndicator: FPSIndicator? #endif @@ -87,8 +87,8 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { } .store(in: &observations) - #if DEBUG - // fpsIndicator = FPSIndicator(windowScene: windowScene) + #if PROFILE + fpsIndicator = FPSIndicator(windowScene: windowScene) #endif } From 590aa1336e381782bdb94dc42c7ff64007380aaf Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 11 May 2022 15:02:47 +0800 Subject: [PATCH 080/101] chore: update i18n resources --- MastodonIntent/gl.lproj/Intents.strings | 48 ++-- .../Resources/ar.lproj/Localizable.strings | 10 +- .../ar.lproj/Localizable.stringsdict | 8 +- .../Resources/ca.lproj/Localizable.strings | 10 +- .../Resources/de.lproj/Localizable.strings | 6 +- .../es-419.lproj/Localizable.strings | 2 +- .../Resources/gd-GB.lproj/Localizable.strings | 2 +- .../Resources/gl.lproj/Localizable.strings | 224 +++++++++--------- .../gl.lproj/Localizable.stringsdict | 104 ++++---- .../Resources/ja.lproj/Localizable.strings | 48 ++-- .../ja.lproj/Localizable.stringsdict | 2 +- .../Resources/ku.lproj/Localizable.strings | 5 +- .../Resources/th.lproj/Localizable.strings | 22 +- .../Resources/tr.lproj/Localizable.strings | 4 +- 14 files changed, 247 insertions(+), 248 deletions(-) diff --git a/MastodonIntent/gl.lproj/Intents.strings b/MastodonIntent/gl.lproj/Intents.strings index 6877490ba..2083cc701 100644 --- a/MastodonIntent/gl.lproj/Intents.strings +++ b/MastodonIntent/gl.lproj/Intents.strings @@ -1,51 +1,51 @@ -"16wxgf" = "Post on Mastodon"; +"16wxgf" = "Publicar en Mastodon"; -"751xkl" = "Text Content"; +"751xkl" = "Texto a incluír"; -"CsR7G2" = "Post on Mastodon"; +"CsR7G2" = "Publicar en Mastodon"; -"HZSGTr" = "What content to post?"; +"HZSGTr" = "Cal é o contido a publicar?"; -"HdGikU" = "Posting failed"; +"HdGikU" = "Fallou a publicación"; -"KDNTJ4" = "Failure Reason"; +"KDNTJ4" = "Razón do fallo"; -"RHxKOw" = "Send Post with text content"; +"RHxKOw" = "Enviar Publicación con texto"; -"RxSqsb" = "Post"; +"RxSqsb" = "Publicación"; -"WCIR3D" = "Post ${content} on Mastodon"; +"WCIR3D" = "Publicar ${content} en Mastodon"; -"ZKJSNu" = "Post"; +"ZKJSNu" = "Publicación"; "ZS1XaK" = "${content}"; -"ZbSjzC" = "Visibility"; +"ZbSjzC" = "Visibilidade"; -"Zo4jgJ" = "Post Visibility"; +"Zo4jgJ" = "Visibilidade da publicación"; -"apSxMG-dYQ5NN" = "There are ${count} options matching ‘Public’."; +"apSxMG-dYQ5NN" = "Hai ${count} opcións que coinciden con ‘Público’."; -"apSxMG-ehFLjY" = "There are ${count} options matching ‘Followers Only’."; +"apSxMG-ehFLjY" = "Hai ${count} opcións que coinciden con 'Só seguidoras’."; -"ayoYEb-dYQ5NN" = "${content}, Public"; +"ayoYEb-dYQ5NN" = "${content}, Público"; -"ayoYEb-ehFLjY" = "${content}, Followers Only"; +"ayoYEb-ehFLjY" = "${content}, Só seguidoras"; -"dUyuGg" = "Post on Mastodon"; +"dUyuGg" = "Publicar en Mastodon"; -"dYQ5NN" = "Public"; +"dYQ5NN" = "Público"; -"ehFLjY" = "Followers Only"; +"ehFLjY" = "Só seguidoras"; -"gfePDu" = "Posting failed. ${failureReason}"; +"gfePDu" = "Fallou a publicación. ${failureReason}"; -"k7dbKQ" = "Post was sent successfully."; +"k7dbKQ" = "Publicación correcta."; -"oGiqmY-dYQ5NN" = "Just to confirm, you wanted ‘Public’?"; +"oGiqmY-dYQ5NN" = "Só para confirmar, querías ’Público'?"; -"oGiqmY-ehFLjY" = "Just to confirm, you wanted ‘Followers Only’?"; +"oGiqmY-ehFLjY" = "Só para confirmar, querías ’Só para seguidoras'?"; "rM6dvp" = "URL"; -"ryJLwG" = "Post was sent successfully. "; +"ryJLwG" = "Publicación correcta. "; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings index 2ed1a8ad3..09ab59f78 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings @@ -58,7 +58,7 @@ "Common.Controls.Actions.SignIn" = "تسجيل الدخول"; "Common.Controls.Actions.SignUp" = "إنشاء حِساب"; "Common.Controls.Actions.Skip" = "تخطي"; -"Common.Controls.Actions.TakePhoto" = "التقاط صورة"; +"Common.Controls.Actions.TakePhoto" = "اِلتِقاطُ صُورَة"; "Common.Controls.Actions.TryAgain" = "المُحاولة مرة أُخرى"; "Common.Controls.Actions.UnblockDomain" = "رفع الحظر عن %@"; "Common.Controls.Friendship.Block" = "حظر"; @@ -164,7 +164,7 @@ "Scene.Compose.Attachment.Video" = "مقطع مرئي"; "Scene.Compose.AutoComplete.SpaceToAdd" = "انقر على مساحة لإضافتِها"; "Scene.Compose.ComposeAction" = "نَشر"; -"Scene.Compose.ContentInputPlaceholder" = "أخبِرنا بِما يَجُولُ فِي ذِهنَك"; +"Scene.Compose.ContentInputPlaceholder" = "عَبِّر عَمَّ يَجُولُ فِي ذِهنِك"; "Scene.Compose.ContentWarning.Placeholder" = "اكتب تَحذيرًا دَقيقًا هُنا..."; "Scene.Compose.Keyboard.AppendAttachmentEntry" = "إضافة مُرفَق - %@"; "Scene.Compose.Keyboard.DiscardPost" = "تجاهُل المنشور"; @@ -172,9 +172,9 @@ "Scene.Compose.Keyboard.SelectVisibilityEntry" = "اختر مدى الظهور - %@"; "Scene.Compose.Keyboard.ToggleContentWarning" = "تبديل تحذير المُحتَوى"; "Scene.Compose.Keyboard.TogglePoll" = "تبديل الاستطلاع"; -"Scene.Compose.MediaSelection.Browse" = "تصفح"; -"Scene.Compose.MediaSelection.Camera" = "إلتقاط صورة"; -"Scene.Compose.MediaSelection.PhotoLibrary" = "مكتبة الصور"; +"Scene.Compose.MediaSelection.Browse" = "تَصَفَّح"; +"Scene.Compose.MediaSelection.Camera" = "اِلتِقاطُ صُورَة"; +"Scene.Compose.MediaSelection.PhotoLibrary" = "مَكتَبَةُ الصُّوَر"; "Scene.Compose.Poll.DurationTime" = "المُدَّة: %@"; "Scene.Compose.Poll.OneDay" = "يومٌ واحِد"; "Scene.Compose.Poll.OneHour" = "ساعةٌ واحدة"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.stringsdict index c2f641720..dddba5132 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.stringsdict @@ -109,7 +109,7 @@ NSStringFormatValueTypeKey ld zero - لا منشور + لا مَنشورات one منشورٌ واحِد two @@ -447,13 +447,13 @@ zero تتبقى لَحظة one - تتبقى ثانية + تتبقى ثانية واحِدة two - تتبقى ثانيتين + تتبقى ثانيتان few تتبقى %ld ثوان many - تتبقى %ld ثانيةً + تتبقى %ld ثانية other تتبقى %ld ثانية diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings index f22a0ff74..3c02a5010 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings @@ -283,7 +283,7 @@ carregat a Mastodon."; "Scene.Register.Input.Password.Require" = "La teva contrasenya com a mínim necessita:"; "Scene.Register.Input.Username.DuplicatePrompt" = "Aquest nom d'usuari ja està en ús."; "Scene.Register.Input.Username.Placeholder" = "nom d'usuari"; -"Scene.Register.Title" = "Parla'ns de tu."; +"Scene.Register.Title" = "Anem a configurar-te a %@"; "Scene.Report.Content1" = "Hi ha alguna altre publicació que vulguis afegir a l'informe?"; "Scene.Report.Content2" = "Hi ha alguna cosa que els moderadors hagin de saber sobre aquest informe?"; "Scene.Report.ReportSentTitle" = "Gràcies per informar, ho investigarem."; @@ -328,10 +328,10 @@ carregat a Mastodon."; "Scene.ServerPicker.Button.Category.Tech" = "tecnologia"; "Scene.ServerPicker.Button.SeeLess" = "Veure Menys"; "Scene.ServerPicker.Button.SeeMore" = "Veure Més"; -"Scene.ServerPicker.EmptyState.BadNetwork" = "S'ha produït un error en carregar les dades. Comprova la teva connexió a Internet."; +"Scene.ServerPicker.EmptyState.BadNetwork" = "Alguna cosa no ha anat bé en carregar les dades. Comprova la teva connexió a Internet."; "Scene.ServerPicker.EmptyState.FindingServers" = "Cercant els servidors disponibles..."; "Scene.ServerPicker.EmptyState.NoResults" = "No hi ha resultats"; -"Scene.ServerPicker.Input.Placeholder" = "Troba un servidor o uneix-te al teu..."; +"Scene.ServerPicker.Input.Placeholder" = "Cerca servidors"; "Scene.ServerPicker.Label.Category" = "CATEGORIA"; "Scene.ServerPicker.Label.Language" = "LLENGUATGE"; "Scene.ServerPicker.Label.Users" = "USUARIS"; @@ -341,7 +341,7 @@ carregat a Mastodon."; "Scene.ServerRules.Button.Confirm" = "Hi estic d'acord"; "Scene.ServerRules.PrivacyPolicy" = "política de privadesa"; "Scene.ServerRules.Prompt" = "Al continuar, estàs subjecte als termes de servei i a la política de privacitat de %@."; -"Scene.ServerRules.Subtitle" = "Aquestes regles estan establertes per els administradors de %@."; +"Scene.ServerRules.Subtitle" = "Aquestes regles estan establertes i aplicades per els moderadors de %@."; "Scene.ServerRules.TermsOfService" = "termes del servei"; "Scene.ServerRules.Title" = "Algunes regles bàsiques."; "Scene.Settings.Footer.MastodonDescription" = "Mastodon és un programari de codi obert. Pots informar de problemes a GitHub a %@ (%@)"; @@ -380,7 +380,7 @@ carregat a Mastodon."; "Scene.Settings.Section.SpicyZone.Title" = "La Zona Picant"; "Scene.Settings.Title" = "Configuració"; "Scene.SuggestionAccount.FollowExplain" = "Quan segueixes algú, veuràs les seves publicacions a Inici."; -"Scene.SuggestionAccount.Title" = "Cerca Persones per Seguir"; +"Scene.SuggestionAccount.Title" = "Cerca Persones a Seguir"; "Scene.Thread.BackTitle" = "Publicació"; "Scene.Thread.Title" = "Publicació de %@"; "Scene.Welcome.GetStarted" = "Comença"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings index 29845981c..7c3e16ec5 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings @@ -108,7 +108,7 @@ Bitte überprüfe deine Internetverbindung."; "Common.Controls.Status.MediaContentWarning" = "Tippe irgendwo zum Anzeigen"; "Common.Controls.Status.Poll.Closed" = "Beendet"; "Common.Controls.Status.Poll.Vote" = "Abstimmen"; -"Common.Controls.Status.SensitiveContent" = "Sensitive Content"; +"Common.Controls.Status.SensitiveContent" = "NSFW-Inhalt"; "Common.Controls.Status.ShowPost" = "Beitrag anzeigen"; "Common.Controls.Status.ShowUserProfile" = "Benutzerprofil anzeigen"; "Common.Controls.Status.Tag.Email" = "E-Mail"; @@ -202,7 +202,7 @@ kann nicht auf Mastodon hochgeladen werden."; "Scene.ConfirmEmail.Subtitle" = "Wir haben gerade eine E-Mail an %@ gesendet, tippe darin auf den Link, um Dein Konto zu bestätigen."; "Scene.ConfirmEmail.Title" = "Noch eine letzte Sache."; -"Scene.Discovery.Intro" = "These are the posts gaining traction in your corner of Mastodon."; +"Scene.Discovery.Intro" = "Dies sind die Beiträge, die in deiner Umgebung auf Mastodon beliebter werden."; "Scene.Discovery.Tabs.Community" = "Community"; "Scene.Discovery.Tabs.ForYou" = "Für dich"; "Scene.Discovery.Tabs.Hashtags" = "Hashtags"; @@ -389,5 +389,5 @@ beliebigen Server."; "Scene.Welcome.LogIn" = "Anmelden"; "Scene.Welcome.Slogan" = "Soziale Netzwerke wieder in deinen Händen."; "Scene.Wizard.AccessibilityHint" = "Doppeltippen, um diesen Assistenten zu schließen"; -"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Wechsel zwischen mehreren Konten durch drücken der Profil-Schaltfläche."; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Wechsel zwischen mehreren Konten durch Drücken der Profil-Schaltfläche."; "Scene.Wizard.NewInMastodon" = "Neu in Mastodon"; \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.strings index db6cacc37..af5d453b7 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.strings @@ -203,7 +203,7 @@ y no se puede subir a Mastodon."; pulsá en el enlace para confirmar tu cuenta."; "Scene.ConfirmEmail.Title" = "Una última cosa."; "Scene.Discovery.Intro" = "Estos son los mensajes que están ganando tracción en tu rincón de Mastodon."; -"Scene.Discovery.Tabs.Community" = "Community"; +"Scene.Discovery.Tabs.Community" = "Comunidad"; "Scene.Discovery.Tabs.ForYou" = "Para vos"; "Scene.Discovery.Tabs.Hashtags" = "Etiquetas"; "Scene.Discovery.Tabs.News" = "Novedades"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.strings index 586258e5a..d14d7acd3 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.strings @@ -203,7 +203,7 @@ a luchdadh suas gu Mastodon."; thoir gnogag air a’ chunntas a dhearbhadh a’ chunntais agad."; "Scene.ConfirmEmail.Title" = "Aon rud eile."; "Scene.Discovery.Intro" = "Seo na postaichean fèillmhor ’nad cheàrnaidh de Mhastodon."; -"Scene.Discovery.Tabs.Community" = "Community"; +"Scene.Discovery.Tabs.Community" = "Coimhearsnachd"; "Scene.Discovery.Tabs.ForYou" = "Dhut-sa"; "Scene.Discovery.Tabs.Hashtags" = "Tagaichean hais"; "Scene.Discovery.Tabs.News" = "Naidheachdan"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/gl.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/gl.lproj/Localizable.strings index a0a33a58f..35fe4066d 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/gl.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/gl.lproj/Localizable.strings @@ -129,26 +129,26 @@ Comproba a conexión a internet."; "Common.Controls.Tabs.Profile" = "Perfil"; "Common.Controls.Tabs.Search" = "Busca"; "Common.Controls.Timeline.Filtered" = "Filtrado"; -"Common.Controls.Timeline.Header.BlockedWarning" = "You can’t view this user’s profile -until they unblock you."; +"Common.Controls.Timeline.Header.BlockedWarning" = "Non podes ver o perfil desta usuaria +ata que te desbloquee."; "Common.Controls.Timeline.Header.BlockingWarning" = "Non podes ver o perfil da usuaria ata que a desbloquees. Así ven outras o teu perfil."; "Common.Controls.Timeline.Header.NoStatusFound" = "Non se atopa a publicación"; -"Common.Controls.Timeline.Header.SuspendedWarning" = "This user has been suspended."; -"Common.Controls.Timeline.Header.UserBlockedWarning" = "You can’t view %@’s profile -until they unblock you."; -"Common.Controls.Timeline.Header.UserBlockingWarning" = "You can’t view %@’s profile -until you unblock them. -Your profile looks like this to them."; -"Common.Controls.Timeline.Header.UserSuspendedWarning" = "%@’s account has been suspended."; +"Common.Controls.Timeline.Header.SuspendedWarning" = "Esta usuaria foi suspendida."; +"Common.Controls.Timeline.Header.UserBlockedWarning" = "Non podes ver o perfil de %@ +ata que te desbloquee."; +"Common.Controls.Timeline.Header.UserBlockingWarning" = "Non podes ver o perfil de %@ +ata que o desbloquees. +Así se ve o teu perfil."; +"Common.Controls.Timeline.Header.UserSuspendedWarning" = "A conta de %@ foi suspendida."; "Common.Controls.Timeline.Loader.LoadMissingPosts" = "Cargar publicacións que faltan"; "Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Cargando as publicacións que faltan..."; "Common.Controls.Timeline.Loader.ShowMoreReplies" = "Mostrar máis respostas"; "Common.Controls.Timeline.Timestamp.Now" = "Agora"; -"Scene.AccountList.AddAccount" = "Add Account"; -"Scene.AccountList.DismissAccountSwitcher" = "Dismiss Account Switcher"; -"Scene.AccountList.TabBarHint" = "Current selected profile: %@. Double tap then hold to show account switcher"; +"Scene.AccountList.AddAccount" = "Engadir conta"; +"Scene.AccountList.DismissAccountSwitcher" = "Desbotar intercambiador de contas"; +"Scene.AccountList.TabBarHint" = "Perfil seleccionado: %@. Dobre toque e manter para mostrar o intercambiador de contas"; "Scene.Compose.Accessibility.AppendAttachment" = "Engadir anexo"; "Scene.Compose.Accessibility.AppendPoll" = "Engadir enquisa"; "Scene.Compose.Accessibility.CustomEmojiPicker" = "Selector emoji personalizado"; @@ -156,15 +156,15 @@ Your profile looks like this to them."; "Scene.Compose.Accessibility.EnableContentWarning" = "Marcar con Aviso sobre o contido"; "Scene.Compose.Accessibility.PostVisibilityMenu" = "Visibilidade da publicación"; "Scene.Compose.Accessibility.RemovePoll" = "Eliminar enquisa"; -"Scene.Compose.Attachment.AttachmentBroken" = "This %@ is broken and can’t be -uploaded to Mastodon."; -"Scene.Compose.Attachment.DescriptionPhoto" = "Describe the photo for the visually-impaired..."; -"Scene.Compose.Attachment.DescriptionVideo" = "Describe the video for the visually-impaired..."; -"Scene.Compose.Attachment.Photo" = "photo"; -"Scene.Compose.Attachment.Video" = "video"; +"Scene.Compose.Attachment.AttachmentBroken" = "Este %@ está estragado e non pode +ser subido a Mastodon."; +"Scene.Compose.Attachment.DescriptionPhoto" = "Describe a foto para persoas con problemas visuais..."; +"Scene.Compose.Attachment.DescriptionVideo" = "Describe o vídeo para persoas con problemas visuais..."; +"Scene.Compose.Attachment.Photo" = "foto"; +"Scene.Compose.Attachment.Video" = "vídeo"; "Scene.Compose.AutoComplete.SpaceToAdd" = "Barra de espazo engade"; -"Scene.Compose.ComposeAction" = "Publish"; -"Scene.Compose.ContentInputPlaceholder" = "Type or paste what’s on your mind"; +"Scene.Compose.ComposeAction" = "Publicar"; +"Scene.Compose.ContentInputPlaceholder" = "Escribe o que che apeteza"; "Scene.Compose.ContentWarning.Placeholder" = "Escribe o teu aviso aquí..."; "Scene.Compose.Keyboard.AppendAttachmentEntry" = "Engadir anexo - %@"; "Scene.Compose.Keyboard.DiscardPost" = "Descartar publicación"; @@ -172,59 +172,59 @@ uploaded to Mastodon."; "Scene.Compose.Keyboard.SelectVisibilityEntry" = "Elexir visibilidade - %@"; "Scene.Compose.Keyboard.ToggleContentWarning" = "Marcar con Aviso sobre o contido"; "Scene.Compose.Keyboard.TogglePoll" = "Activar enquisa"; -"Scene.Compose.MediaSelection.Browse" = "Browse"; -"Scene.Compose.MediaSelection.Camera" = "Take Photo"; -"Scene.Compose.MediaSelection.PhotoLibrary" = "Photo Library"; -"Scene.Compose.Poll.DurationTime" = "Duration: %@"; +"Scene.Compose.MediaSelection.Browse" = "Explorar"; +"Scene.Compose.MediaSelection.Camera" = "Facer foto"; +"Scene.Compose.MediaSelection.PhotoLibrary" = "Biblioteca de fotos"; +"Scene.Compose.Poll.DurationTime" = "Duración: %@"; "Scene.Compose.Poll.OneDay" = "1 Día"; -"Scene.Compose.Poll.OneHour" = "1 Hour"; +"Scene.Compose.Poll.OneHour" = "1 Hora"; "Scene.Compose.Poll.OptionNumber" = "Opción %ld"; "Scene.Compose.Poll.SevenDays" = "7 Días"; -"Scene.Compose.Poll.SixHours" = "6 Hours"; -"Scene.Compose.Poll.ThirtyMinutes" = "30 minutes"; +"Scene.Compose.Poll.SixHours" = "6 Horas"; +"Scene.Compose.Poll.ThirtyMinutes" = "30 minutos"; "Scene.Compose.Poll.ThreeDays" = "3 Días"; -"Scene.Compose.ReplyingToUser" = "replying to %@"; -"Scene.Compose.Title.NewPost" = "New Post"; -"Scene.Compose.Title.NewReply" = "New Reply"; +"Scene.Compose.ReplyingToUser" = "en resposta a %@"; +"Scene.Compose.Title.NewPost" = "Nova publicación"; +"Scene.Compose.Title.NewReply" = "Nova resposta"; "Scene.Compose.Visibility.Direct" = "Só para persoas mencionadas"; "Scene.Compose.Visibility.Private" = "Só para seguidoras"; "Scene.Compose.Visibility.Public" = "Público"; "Scene.Compose.Visibility.Unlisted" = "Non listado"; -"Scene.ConfirmEmail.Button.OpenEmailApp" = "Open Email App"; -"Scene.ConfirmEmail.Button.Resend" = "Resend"; -"Scene.ConfirmEmail.DontReceiveEmail.Description" = "Check if your email address is correct as well as your junk folder if you haven’t."; -"Scene.ConfirmEmail.DontReceiveEmail.ResendEmail" = "Resend Email"; -"Scene.ConfirmEmail.DontReceiveEmail.Title" = "Check your email"; -"Scene.ConfirmEmail.OpenEmailApp.Description" = "We just sent you an email. Check your junk folder if you haven’t."; -"Scene.ConfirmEmail.OpenEmailApp.Mail" = "Mail"; -"Scene.ConfirmEmail.OpenEmailApp.OpenEmailClient" = "Open Email Client"; -"Scene.ConfirmEmail.OpenEmailApp.Title" = "Check your inbox."; -"Scene.ConfirmEmail.Subtitle" = "Tap the link we emailed to you to verify your account."; -"Scene.ConfirmEmail.Title" = "One last thing."; -"Scene.Discovery.Intro" = "These are the posts gaining traction in your corner of Mastodon."; +"Scene.ConfirmEmail.Button.OpenEmailApp" = "Abrir app de email"; +"Scene.ConfirmEmail.Button.Resend" = "Reenviar"; +"Scene.ConfirmEmail.DontReceiveEmail.Description" = "Comproba que o enderezo de email é correcto e que non vaia directo ao cartafol de spam."; +"Scene.ConfirmEmail.DontReceiveEmail.ResendEmail" = "Volver enviar o correo"; +"Scene.ConfirmEmail.DontReceiveEmail.Title" = "Revisa o teu correo"; +"Scene.ConfirmEmail.OpenEmailApp.Description" = "Enviámosche un email. Se non aparece, mira no cartafol do lixo."; +"Scene.ConfirmEmail.OpenEmailApp.Mail" = "Correo"; +"Scene.ConfirmEmail.OpenEmailApp.OpenEmailClient" = "Abrir cliente de email"; +"Scene.ConfirmEmail.OpenEmailApp.Title" = "Mira na caixa de correo."; +"Scene.ConfirmEmail.Subtitle" = "Preme na ligazón que che enviamos ao email para verificar a conta."; +"Scene.ConfirmEmail.Title" = "O último detalle."; +"Scene.Discovery.Intro" = "Estas son as publicacións en voga no teu recuncho de Mastodon."; "Scene.Discovery.Tabs.Community" = "Comunidade"; -"Scene.Discovery.Tabs.ForYou" = "For You"; +"Scene.Discovery.Tabs.ForYou" = "Para ti"; "Scene.Discovery.Tabs.Hashtags" = "Cancelos"; "Scene.Discovery.Tabs.News" = "Novas"; "Scene.Discovery.Tabs.Posts" = "Publicacións"; -"Scene.Favorite.Title" = "Your Favorites"; +"Scene.Favorite.Title" = "Publicacións Favoritas"; "Scene.Follower.Footer" = "Non se mostran seguidoras desde outros servidores."; "Scene.Following.Footer" = "Non se mostran os seguimentos desde outros servidores."; -"Scene.HomeTimeline.NavigationBarState.NewPosts" = "See new posts"; -"Scene.HomeTimeline.NavigationBarState.Offline" = "Offline"; -"Scene.HomeTimeline.NavigationBarState.Published" = "Published!"; -"Scene.HomeTimeline.NavigationBarState.Publishing" = "Publishing post..."; -"Scene.HomeTimeline.Title" = "Home"; -"Scene.Notification.Keyobard.ShowEverything" = "Show Everything"; -"Scene.Notification.Keyobard.ShowMentions" = "Show Mentions"; -"Scene.Notification.NotificationDescription.FavoritedYourPost" = "favorited your post"; -"Scene.Notification.NotificationDescription.FollowedYou" = "followed you"; -"Scene.Notification.NotificationDescription.MentionedYou" = "mentioned you"; -"Scene.Notification.NotificationDescription.PollHasEnded" = "poll has ended"; -"Scene.Notification.NotificationDescription.RebloggedYourPost" = "reblogged your post"; -"Scene.Notification.NotificationDescription.RequestToFollowYou" = "request to follow you"; -"Scene.Notification.Title.Everything" = "Everything"; -"Scene.Notification.Title.Mentions" = "Mentions"; +"Scene.HomeTimeline.NavigationBarState.NewPosts" = "Novas publicacións"; +"Scene.HomeTimeline.NavigationBarState.Offline" = "Sen conexión"; +"Scene.HomeTimeline.NavigationBarState.Published" = "Publicado!"; +"Scene.HomeTimeline.NavigationBarState.Publishing" = "Publicando..."; +"Scene.HomeTimeline.Title" = "Inicio"; +"Scene.Notification.Keyobard.ShowEverything" = "Mostrar Todo"; +"Scene.Notification.Keyobard.ShowMentions" = "Mostrar mencións"; +"Scene.Notification.NotificationDescription.FavoritedYourPost" = "marcou a túa publicación como favorita"; +"Scene.Notification.NotificationDescription.FollowedYou" = "séguete"; +"Scene.Notification.NotificationDescription.MentionedYou" = "mencionoute"; +"Scene.Notification.NotificationDescription.PollHasEnded" = "a enquisa rematou"; +"Scene.Notification.NotificationDescription.RebloggedYourPost" = "compartiu a túa publicación"; +"Scene.Notification.NotificationDescription.RequestToFollowYou" = "solicitou seguirte"; +"Scene.Notification.Title.Everything" = "Todo"; +"Scene.Notification.Title.Mentions" = "Mencións"; "Scene.Preview.Keyboard.ClosePreview" = "Pechar vista previa"; "Scene.Preview.Keyboard.ShowNext" = "Mostrar Seguinte"; "Scene.Preview.Keyboard.ShowPrevious" = "Mostar Anterior"; @@ -267,10 +267,10 @@ uploaded to Mastodon."; "Scene.Register.Error.Reason.TooLong" = "%@ é demasiado longo"; "Scene.Register.Error.Reason.TooShort" = "%@ é demasiado curto"; "Scene.Register.Error.Reason.Unreachable" = "%@ semella que non existe"; -"Scene.Register.Error.Special.EmailInvalid" = "This is not a valid email address"; -"Scene.Register.Error.Special.PasswordTooShort" = "Password is too short (must be at least 8 characters)"; +"Scene.Register.Error.Special.EmailInvalid" = "Este non é un enderezo válido de email"; +"Scene.Register.Error.Special.PasswordTooShort" = "O contrasinal é demasiado curto (debe ter 8 caracteres como mínimo)"; "Scene.Register.Error.Special.UsernameInvalid" = "O nome de usuaria só pode ter caracteres alfanuméricos e trazos baixos"; -"Scene.Register.Error.Special.UsernameTooLong" = "Username is too long (can’t be longer than 30 characters)"; +"Scene.Register.Error.Special.UsernameTooLong" = "O nome de usuaria é demasiado longo (maior de 30 caracteres)"; "Scene.Register.Input.Avatar.Delete" = "Eliminar"; "Scene.Register.Input.DisplayName.Placeholder" = "nome público"; "Scene.Register.Input.Email.Placeholder" = "email"; @@ -338,55 +338,55 @@ uploaded to Mastodon."; "Scene.ServerPicker.Subtitle" = "Elixe unha comunidade en función dos teus intereses, rexión ou unha de propósito xeral."; "Scene.ServerPicker.SubtitleExtend" = "Elixe unha comunidade en función dos teus intereses, rexión ou unha de propósito xeral. Cada comunidade está xestionada por unha organización totalmente independente ou unha única persoa."; "Scene.ServerPicker.Title" = "Mastodon fórmano as persoas das diferentes comunidades."; -"Scene.ServerRules.Button.Confirm" = "I Agree"; -"Scene.ServerRules.PrivacyPolicy" = "privacy policy"; -"Scene.ServerRules.Prompt" = "By continuing, you’re subject to the terms of service and privacy policy for %@."; -"Scene.ServerRules.Subtitle" = "These are set and enforced by the %@ moderators."; -"Scene.ServerRules.TermsOfService" = "terms of service"; -"Scene.ServerRules.Title" = "Some ground rules."; -"Scene.Settings.Footer.MastodonDescription" = "Mastodon is open source software. You can report issues on GitHub at %@ (%@)"; -"Scene.Settings.Keyboard.CloseSettingsWindow" = "Close Settings Window"; -"Scene.Settings.Section.Appearance.Automatic" = "Automatic"; -"Scene.Settings.Section.Appearance.Dark" = "Always Dark"; -"Scene.Settings.Section.Appearance.Light" = "Always Light"; -"Scene.Settings.Section.Appearance.Title" = "Appearance"; -"Scene.Settings.Section.BoringZone.AccountSettings" = "Account Settings"; -"Scene.Settings.Section.BoringZone.Privacy" = "Privacy Policy"; -"Scene.Settings.Section.BoringZone.Terms" = "Terms of Service"; -"Scene.Settings.Section.BoringZone.Title" = "The Boring Zone"; -"Scene.Settings.Section.LookAndFeel.Light" = "Light"; -"Scene.Settings.Section.LookAndFeel.ReallyDark" = "Really Dark"; -"Scene.Settings.Section.LookAndFeel.SortaDark" = "Sorta Dark"; -"Scene.Settings.Section.LookAndFeel.Title" = "Look and Feel"; -"Scene.Settings.Section.LookAndFeel.UseSystem" = "Use System"; -"Scene.Settings.Section.Notifications.Boosts" = "Reblogs my post"; -"Scene.Settings.Section.Notifications.Favorites" = "Favorites my post"; -"Scene.Settings.Section.Notifications.Follows" = "Follows me"; -"Scene.Settings.Section.Notifications.Mentions" = "Mentions me"; -"Scene.Settings.Section.Notifications.Title" = "Notifications"; -"Scene.Settings.Section.Notifications.Trigger.Anyone" = "anyone"; -"Scene.Settings.Section.Notifications.Trigger.Follow" = "anyone I follow"; -"Scene.Settings.Section.Notifications.Trigger.Follower" = "a follower"; -"Scene.Settings.Section.Notifications.Trigger.Noone" = "no one"; -"Scene.Settings.Section.Notifications.Trigger.Title" = "Notify me when"; -"Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Disable animated avatars"; -"Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Disable animated emojis"; -"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Open links in Mastodon"; -"Scene.Settings.Section.Preference.Title" = "Preferences"; -"Scene.Settings.Section.Preference.TrueBlackDarkMode" = "True black dark mode"; -"Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Use default browser to open links"; -"Scene.Settings.Section.SpicyZone.Clear" = "Clear Media Cache"; -"Scene.Settings.Section.SpicyZone.Signout" = "Sign Out"; -"Scene.Settings.Section.SpicyZone.Title" = "The Spicy Zone"; -"Scene.Settings.Title" = "Settings"; -"Scene.SuggestionAccount.FollowExplain" = "When you follow someone, you’ll see their posts in your home feed."; -"Scene.SuggestionAccount.Title" = "Find People to Follow"; -"Scene.Thread.BackTitle" = "Post"; -"Scene.Thread.Title" = "Post from %@"; +"Scene.ServerRules.Button.Confirm" = "Acepto"; +"Scene.ServerRules.PrivacyPolicy" = "polícica de privacidade"; +"Scene.ServerRules.Prompt" = "Ao continuar, acatas os termos do servizo e a política de privacidade para %@."; +"Scene.ServerRules.Subtitle" = "Son establecidas e aplicadas pola moderación de %@."; +"Scene.ServerRules.TermsOfService" = "termos do servizo"; +"Scene.ServerRules.Title" = "Algunhas regras básicas."; +"Scene.Settings.Footer.MastodonDescription" = "Mastodon é software de código aberto. Podes informar de fallos en GitHub en %@ (%@)"; +"Scene.Settings.Keyboard.CloseSettingsWindow" = "Pechar ventá de axustes"; +"Scene.Settings.Section.Appearance.Automatic" = "Automático"; +"Scene.Settings.Section.Appearance.Dark" = "Sempre escuro"; +"Scene.Settings.Section.Appearance.Light" = "Sempre claro"; +"Scene.Settings.Section.Appearance.Title" = "Aparencia"; +"Scene.Settings.Section.BoringZone.AccountSettings" = "Axustes da conta"; +"Scene.Settings.Section.BoringZone.Privacy" = "Política de Privacidade"; +"Scene.Settings.Section.BoringZone.Terms" = "Termos do Servizo"; +"Scene.Settings.Section.BoringZone.Title" = "A zona aburrida"; +"Scene.Settings.Section.LookAndFeel.Light" = "Claro"; +"Scene.Settings.Section.LookAndFeel.ReallyDark" = "Realmente escuro"; +"Scene.Settings.Section.LookAndFeel.SortaDark" = "Algo escuro"; +"Scene.Settings.Section.LookAndFeel.Title" = "Aparencia"; +"Scene.Settings.Section.LookAndFeel.UseSystem" = "Seguir o sistema"; +"Scene.Settings.Section.Notifications.Boosts" = "Promove a miña publicación"; +"Scene.Settings.Section.Notifications.Favorites" = "Favorece a miña publicación"; +"Scene.Settings.Section.Notifications.Follows" = "Me segue"; +"Scene.Settings.Section.Notifications.Mentions" = "Me menciona"; +"Scene.Settings.Section.Notifications.Title" = "Notificacións"; +"Scene.Settings.Section.Notifications.Trigger.Anyone" = "calquera"; +"Scene.Settings.Section.Notifications.Trigger.Follow" = "alguén a quen sigo"; +"Scene.Settings.Section.Notifications.Trigger.Follower" = "unha seguidora"; +"Scene.Settings.Section.Notifications.Trigger.Noone" = "ninguén"; +"Scene.Settings.Section.Notifications.Trigger.Title" = "Avisarme cando"; +"Scene.Settings.Section.Preference.DisableAvatarAnimation" = "Desactivar avatares animados"; +"Scene.Settings.Section.Preference.DisableEmojiAnimation" = "Desactivar emojis animados"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Abrir ligazóns en Mastodon"; +"Scene.Settings.Section.Preference.Title" = "Preferencias"; +"Scene.Settings.Section.Preference.TrueBlackDarkMode" = "Modo negro verdadeiro"; +"Scene.Settings.Section.Preference.UsingDefaultBrowser" = "Usar navegador por defecto para as ligazóns"; +"Scene.Settings.Section.SpicyZone.Clear" = "Limpar caché multimedia"; +"Scene.Settings.Section.SpicyZone.Signout" = "Pechar sesión"; +"Scene.Settings.Section.SpicyZone.Title" = "A zona picante"; +"Scene.Settings.Title" = "Axustes"; +"Scene.SuggestionAccount.FollowExplain" = "Cando sigas a alguén verás as súas publicacións na cronoloxía de inicio."; +"Scene.SuggestionAccount.Title" = "Atopar persoas para seguir"; +"Scene.Thread.BackTitle" = "Publicación"; +"Scene.Thread.Title" = "Publicación de %@"; "Scene.Welcome.GetStarted" = "Comezar"; "Scene.Welcome.LogIn" = "Acceder"; -"Scene.Welcome.Slogan" = "Social networking -back in your hands."; -"Scene.Wizard.AccessibilityHint" = "Double tap to dismiss this wizard"; -"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Switch between multiple accounts by holding the profile button."; -"Scene.Wizard.NewInMastodon" = "New in Mastodon"; \ No newline at end of file +"Scene.Welcome.Slogan" = "Comunicación social +de volta ás túas mans."; +"Scene.Wizard.AccessibilityHint" = "Dobre toque para desbotar este asistente"; +"Scene.Wizard.MultipleAccountSwitchIntroDescription" = "Cambia dunha conta a outra mantendo preso o botón do perfil."; +"Scene.Wizard.NewInMastodon" = "Novidade en Mastodon"; \ No newline at end of file diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/gl.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/gl.lproj/Localizable.stringsdict index 503ff9dbd..a67c938ab 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/gl.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/gl.lproj/Localizable.stringsdict @@ -13,15 +13,15 @@ NSStringFormatValueTypeKey ld one - 1 unread notification + 1 notificación non lida other - %ld unread notification + %ld notificacións non lidas a11y.plural.count.input_limit_exceeds NSStringLocalizedFormatKey - Input limit exceeds %#@character_count@ + O límite supera %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -29,15 +29,15 @@ NSStringFormatValueTypeKey ld one - 1 character + 1 caracter other - %ld characters + %ld caracteres a11y.plural.count.input_limit_remains NSStringLocalizedFormatKey - Input limit remains %#@character_count@ + O límite de entrada mantense en %#@character_count@ character_count NSStringFormatSpecTypeKey @@ -45,9 +45,9 @@ NSStringFormatValueTypeKey ld one - 1 character + 1 caracter other - %ld characters + %ld caracteres plural.count.metric_formatted.post @@ -61,9 +61,9 @@ NSStringFormatValueTypeKey ld one - post + publicación other - posts + publicacións plural.count.post @@ -77,9 +77,9 @@ NSStringFormatValueTypeKey ld one - 1 post + 1 publicación other - %ld posts + %ld publicacións plural.count.favorite @@ -93,9 +93,9 @@ NSStringFormatValueTypeKey ld one - 1 favorite + 1 favorito other - %ld favorites + %ld favoritos plural.count.reblog @@ -109,9 +109,9 @@ NSStringFormatValueTypeKey ld one - 1 reblog + 1 promoción other - %ld reblogs + %ld promocións plural.count.reply @@ -125,9 +125,9 @@ NSStringFormatValueTypeKey ld one - 1 reply + 1 resposta other - %ld replies + %ld respostas plural.count.vote @@ -141,9 +141,9 @@ NSStringFormatValueTypeKey ld one - 1 vote + 1 voto other - %ld votes + %ld votos plural.count.voter @@ -157,9 +157,9 @@ NSStringFormatValueTypeKey ld one - 1 voter + 1 votante other - %ld voters + %ld votantes plural.people_talking @@ -173,9 +173,9 @@ NSStringFormatValueTypeKey ld one - 1 people talking + 1 persoa comentando other - %ld people talking + %ld persoas comentando plural.count.following @@ -189,9 +189,9 @@ NSStringFormatValueTypeKey ld one - 1 following + 1 seguimento other - %ld following + %ld seguimentos plural.count.follower @@ -205,9 +205,9 @@ NSStringFormatValueTypeKey ld one - 1 follower + 1 seguidora other - %ld followers + %ld seguidoras date.year.left @@ -221,9 +221,9 @@ NSStringFormatValueTypeKey ld one - 1 year left + Queda 1 ano other - %ld years left + Quedan %ld anos date.month.left @@ -237,9 +237,9 @@ NSStringFormatValueTypeKey ld one - 1 months left + Queda 1 mes other - %ld months left + Quedan %ld meses date.day.left @@ -253,9 +253,9 @@ NSStringFormatValueTypeKey ld one - 1 day left + Queda 1 día other - %ld days left + Quedan %ld días date.hour.left @@ -269,9 +269,9 @@ NSStringFormatValueTypeKey ld one - 1 hour left + Queda 1 hora other - %ld hours left + Quedan %ld horas date.minute.left @@ -285,9 +285,9 @@ NSStringFormatValueTypeKey ld one - 1 minute left + Queda 1 minuto other - %ld minutes left + Quedan %ld minutos date.second.left @@ -301,9 +301,9 @@ NSStringFormatValueTypeKey ld one - 1 second left + Queda 1 segundo other - %ld seconds left + Quedan %ld segundos date.year.ago.abbr @@ -317,9 +317,9 @@ NSStringFormatValueTypeKey ld one - 1y ago + hai 1 ano other - %ldy ago + hai %ld anos date.month.ago.abbr @@ -333,9 +333,9 @@ NSStringFormatValueTypeKey ld one - 1M ago + hai 1 mes other - %ldM ago + hai %ld meses date.day.ago.abbr @@ -349,9 +349,9 @@ NSStringFormatValueTypeKey ld one - 1d ago + hai 1 día other - %ldd ago + hai %ld días date.hour.ago.abbr @@ -365,9 +365,9 @@ NSStringFormatValueTypeKey ld one - 1h ago + fai 1 hora other - %ldh ago + fai %ld horas date.minute.ago.abbr @@ -381,9 +381,9 @@ NSStringFormatValueTypeKey ld one - 1m ago + fai 1 minuto other - %ldm ago + fai %ld minutos date.second.ago.abbr @@ -397,9 +397,9 @@ NSStringFormatValueTypeKey ld one - 1s ago + fai 1 seg. other - %lds ago + fai %ld seg. diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings index 19056cf5a..015a88551 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings @@ -4,8 +4,8 @@ "Common.Alerts.CleanCache.Title" = "キャッシュを消去"; "Common.Alerts.Common.PleaseTryAgain" = "もう一度お試しください。"; "Common.Alerts.Common.PleaseTryAgainLater" = "後でもう一度お試しください。"; -"Common.Alerts.DeletePost.Message" = "本当に削除しますか?"; -"Common.Alerts.DeletePost.Title" = "この投稿を消去しますか?"; +"Common.Alerts.DeletePost.Message" = "本当にこの投稿を削除しますか?"; +"Common.Alerts.DeletePost.Title" = "投稿を削除"; "Common.Alerts.DiscardPostContent.Message" = "この操作は取り消しできません。下書きは失われます。"; "Common.Alerts.DiscardPostContent.Title" = "投稿を破棄しますか?"; "Common.Alerts.EditProfileFailure.Message" = "プロフィールを編集できません。もう一度お試しください。"; @@ -32,13 +32,13 @@ "Common.Controls.Actions.Confirm" = "確認"; "Common.Controls.Actions.Continue" = "続ける"; "Common.Controls.Actions.CopyPhoto" = "写真をコピー"; -"Common.Controls.Actions.Delete" = "消去"; +"Common.Controls.Actions.Delete" = "削除"; "Common.Controls.Actions.Discard" = "破棄"; "Common.Controls.Actions.Done" = "完了"; "Common.Controls.Actions.Edit" = "編集"; "Common.Controls.Actions.FindPeople" = "フォローする人を見つける"; "Common.Controls.Actions.ManuallySearch" = "手動で検索する"; -"Common.Controls.Actions.Next" = "次"; +"Common.Controls.Actions.Next" = "次へ"; "Common.Controls.Actions.Ok" = "OK"; "Common.Controls.Actions.Open" = "開く"; "Common.Controls.Actions.OpenInBrowser" = "ブラウザで開く"; @@ -98,8 +98,8 @@ "Common.Controls.Status.Actions.Menu" = "メニュー"; "Common.Controls.Status.Actions.Reblog" = "ブースト"; "Common.Controls.Status.Actions.Reply" = "返信"; -"Common.Controls.Status.Actions.ShowGif" = "Show GIF"; -"Common.Controls.Status.Actions.ShowImage" = "Show image"; +"Common.Controls.Status.Actions.ShowGif" = "GIFを表示"; +"Common.Controls.Status.Actions.ShowImage" = "画像を表示"; "Common.Controls.Status.Actions.ShowVideoPlayer" = "Show video player"; "Common.Controls.Status.Actions.TapThenHoldToShowMenu" = "Tap then hold to show menu"; "Common.Controls.Status.Actions.Unfavorite" = "お気に入り登録を取り消す"; @@ -117,7 +117,7 @@ "Common.Controls.Status.Tag.Link" = "リンク"; "Common.Controls.Status.Tag.Mention" = "メンション"; "Common.Controls.Status.Tag.Url" = "URL"; -"Common.Controls.Status.TapToReveal" = "Tap to reveal"; +"Common.Controls.Status.TapToReveal" = "タップして表示"; "Common.Controls.Status.UserReblogged" = "%@がブースト"; "Common.Controls.Status.UserRepliedTo" = "%@に返信"; "Common.Controls.Status.Visibility.Direct" = "この投稿はメンションされたユーザーに限り見ることができます。"; @@ -196,9 +196,9 @@ "Scene.ConfirmEmail.OpenEmailApp.Title" = "メールを確認"; "Scene.ConfirmEmail.Subtitle" = "先程 %@ にメールを送信しました。リンクをタップしてアカウントを確認してください。"; "Scene.ConfirmEmail.Title" = "さいごにもうひとつ。"; -"Scene.Discovery.Intro" = "These are the posts gaining traction in your corner of Mastodon."; -"Scene.Discovery.Tabs.Community" = "Community"; -"Scene.Discovery.Tabs.ForYou" = "For You"; +"Scene.Discovery.Intro" = "あなたのMastodonサーバーで注目を集めている投稿がここに表示されます。"; +"Scene.Discovery.Tabs.Community" = "コミュニティ"; +"Scene.Discovery.Tabs.ForYou" = "おすすめ"; "Scene.Discovery.Tabs.Hashtags" = "ハッシュタグ"; "Scene.Discovery.Tabs.News" = "ニュース"; "Scene.Discovery.Tabs.Posts" = "投稿"; @@ -212,12 +212,12 @@ "Scene.HomeTimeline.Title" = "ホーム"; "Scene.Notification.Keyobard.ShowEverything" = "すべて見る"; "Scene.Notification.Keyobard.ShowMentions" = "メンションを見る"; -"Scene.Notification.NotificationDescription.FavoritedYourPost" = "favorited your post"; -"Scene.Notification.NotificationDescription.FollowedYou" = "followed you"; -"Scene.Notification.NotificationDescription.MentionedYou" = "mentioned you"; -"Scene.Notification.NotificationDescription.PollHasEnded" = "poll has ended"; -"Scene.Notification.NotificationDescription.RebloggedYourPost" = "reblogged your post"; -"Scene.Notification.NotificationDescription.RequestToFollowYou" = "request to follow you"; +"Scene.Notification.NotificationDescription.FavoritedYourPost" = "さんがあなたの投稿をお気に入りに登録しました"; +"Scene.Notification.NotificationDescription.FollowedYou" = "さんにフォローされました"; +"Scene.Notification.NotificationDescription.MentionedYou" = "さんがあなたに返信しました"; +"Scene.Notification.NotificationDescription.PollHasEnded" = "アンケートが終了しました"; +"Scene.Notification.NotificationDescription.RebloggedYourPost" = "さんがあなたの投稿をブーストしました"; +"Scene.Notification.NotificationDescription.RequestToFollowYou" = "さんがあなたにフォローリクエストしました"; "Scene.Notification.Title.Everything" = "すべて"; "Scene.Notification.Title.Mentions" = "メンション"; "Scene.Preview.Keyboard.ClosePreview" = "プレビューを閉じる"; @@ -266,7 +266,7 @@ "Scene.Register.Error.Special.PasswordTooShort" = "パスワードが短すぎます(8文字以上)"; "Scene.Register.Error.Special.UsernameInvalid" = "ユーザーネームには、英数字とアンダースコアのみを使用してください。"; "Scene.Register.Error.Special.UsernameTooLong" = "ユーザー名が長すぎます(30文字以内)"; -"Scene.Register.Input.Avatar.Delete" = "消去"; +"Scene.Register.Input.Avatar.Delete" = "削除"; "Scene.Register.Input.DisplayName.Placeholder" = "表示名"; "Scene.Register.Input.Email.Placeholder" = "メール"; "Scene.Register.Input.Invite.RegistrationUserInviteRequest" = "なぜ参加したいと思ったのですか?"; @@ -349,11 +349,11 @@ "Scene.Settings.Section.BoringZone.Privacy" = "プライバシーポリシー"; "Scene.Settings.Section.BoringZone.Terms" = "利用規約"; "Scene.Settings.Section.BoringZone.Title" = "アプリについて"; -"Scene.Settings.Section.LookAndFeel.Light" = "Light"; -"Scene.Settings.Section.LookAndFeel.ReallyDark" = "Really Dark"; -"Scene.Settings.Section.LookAndFeel.SortaDark" = "Sorta Dark"; -"Scene.Settings.Section.LookAndFeel.Title" = "Look and Feel"; -"Scene.Settings.Section.LookAndFeel.UseSystem" = "Use System"; +"Scene.Settings.Section.LookAndFeel.Light" = "ライト"; +"Scene.Settings.Section.LookAndFeel.ReallyDark" = "ブラック"; +"Scene.Settings.Section.LookAndFeel.SortaDark" = "ダーク"; +"Scene.Settings.Section.LookAndFeel.Title" = "テーマ"; +"Scene.Settings.Section.LookAndFeel.UseSystem" = "端末の設定を使う"; "Scene.Settings.Section.Notifications.Boosts" = "ブースト"; "Scene.Settings.Section.Notifications.Favorites" = "お気に入り登録"; "Scene.Settings.Section.Notifications.Follows" = "フォロー"; @@ -366,7 +366,7 @@ "Scene.Settings.Section.Notifications.Trigger.Title" = "通知を受け取る"; "Scene.Settings.Section.Preference.DisableAvatarAnimation" = "アバターのアニメーションを無効化する"; "Scene.Settings.Section.Preference.DisableEmojiAnimation" = "絵文字のアニメーションを無効化する"; -"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Open links in Mastodon"; +"Scene.Settings.Section.Preference.OpenLinksInMastodon" = "Mastodonでリンクを開く"; "Scene.Settings.Section.Preference.Title" = "環境設定"; "Scene.Settings.Section.Preference.TrueBlackDarkMode" = "真っ黒なダークテーマを使用する"; "Scene.Settings.Section.Preference.UsingDefaultBrowser" = "既定のブラウザでリンクを開く"; @@ -378,7 +378,7 @@ "Scene.SuggestionAccount.Title" = "フォローする人を探す"; "Scene.Thread.BackTitle" = "投稿"; "Scene.Thread.Title" = "%@の投稿"; -"Scene.Welcome.GetStarted" = "Get Started"; +"Scene.Welcome.GetStarted" = "はじめる"; "Scene.Welcome.LogIn" = "ログイン"; "Scene.Welcome.Slogan" = "ソーシャルネットワーキングを、あなたの手の中に."; "Scene.Wizard.AccessibilityHint" = "チュートリアルを閉じるには、ダブルタップしてください"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.stringsdict b/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.stringsdict index 8dfc95079..95c35172e 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.stringsdict +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.stringsdict @@ -153,7 +153,7 @@ NSStringFormatValueTypeKey ld other - %ld people talking + %ld人が投稿 plural.count.following diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings index 7f2e7ef48..f9c237770 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings @@ -332,14 +332,13 @@ girêdanê bitikne da ku ajimêra xwe bidî piştrastkirin."; "Scene.ServerPicker.EmptyState.BadNetwork" = "Di dema barkirina daneyan da çewtî derket. Girêdana xwe ya înternetê kontrol bike."; "Scene.ServerPicker.EmptyState.FindingServers" = "Peydakirina rajekarên berdest..."; "Scene.ServerPicker.EmptyState.NoResults" = "Encam tune"; -"Scene.ServerPicker.Input.Placeholder" = "Rajekarekî bibîne an jî beşdarî ya xwe bibe..."; +"Scene.ServerPicker.Input.Placeholder" = "Li rajekaran bigere"; "Scene.ServerPicker.Label.Category" = "BEŞ"; "Scene.ServerPicker.Label.Language" = "ZIMAN"; "Scene.ServerPicker.Label.Users" = "BIKARHÊNER"; "Scene.ServerPicker.Subtitle" = "Li gorî berjewendî, herêm, an jî armancek gelemperî civakekê hilbijêre."; "Scene.ServerPicker.SubtitleExtend" = "Li gorî berjewendî, herêm, an jî armancek gelemperî civakekê hilbijêre. Her civakek ji hêla rêxistinek an kesek bi tevahî serbixwe ve tê xebitandin."; -"Scene.ServerPicker.Title" = "Rajekarekê hilbijêre, -Her kîjan rajekar be."; +"Scene.ServerPicker.Title" = "Mastodon ji bikarhênerên di civakên cuda de pêk tê."; "Scene.ServerRules.Button.Confirm" = "Ez dipejirînim"; "Scene.ServerRules.PrivacyPolicy" = "polîtikaya nihêniyê"; "Scene.ServerRules.Prompt" = "Bi domandinê, tu ji bo %@ di bin mercên bikaranînê û polîtîkaya nepenîtiyê dipejirînî."; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings index 1ceff03a2..ef723027d 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings @@ -202,7 +202,7 @@ "Scene.ConfirmEmail.Subtitle" = "แตะลิงก์ที่เราส่งอีเมลถึงคุณเพื่อยืนยันบัญชีของคุณ"; "Scene.ConfirmEmail.Title" = "หนึ่งสิ่งสุดท้าย"; "Scene.Discovery.Intro" = "นี่คือโพสต์ที่กำลังได้รับความสนใจในมุมของ Mastodon ของคุณ"; -"Scene.Discovery.Tabs.Community" = "Community"; +"Scene.Discovery.Tabs.Community" = "ชุมชน"; "Scene.Discovery.Tabs.ForYou" = "สำหรับคุณ"; "Scene.Discovery.Tabs.Hashtags" = "แฮชแท็ก"; "Scene.Discovery.Tabs.News" = "ข่าว"; @@ -258,7 +258,7 @@ "Scene.Register.Error.Item.Reason" = "เหตุผล"; "Scene.Register.Error.Item.Username" = "ชื่อผู้ใช้"; "Scene.Register.Error.Reason.Accepted" = "ต้องยอมรับ %@"; -"Scene.Register.Error.Reason.Blank" = "ต้องมี %@"; +"Scene.Register.Error.Reason.Blank" = "ต้องการ %@"; "Scene.Register.Error.Reason.Blocked" = "%@ มีผู้ให้บริการอีเมลที่ไม่ได้รับอนุญาต"; "Scene.Register.Error.Reason.Inclusion" = "%@ ไม่ใช่ค่าที่รองรับ"; "Scene.Register.Error.Reason.Invalid" = "%@ ไม่ถูกต้อง"; @@ -278,9 +278,9 @@ "Scene.Register.Input.Password.Accessibility.Checked" = "กาเครื่องหมายแล้ว"; "Scene.Register.Input.Password.Accessibility.Unchecked" = "ไม่ได้กาเครื่องหมาย"; "Scene.Register.Input.Password.CharacterLimit" = "8 ตัวอักษร"; -"Scene.Register.Input.Password.Hint" = "รหัสผ่านของคุณต้องมีอย่างน้อยแปดตัวอักษร"; +"Scene.Register.Input.Password.Hint" = "รหัสผ่านของคุณจำเป็นต้องมีอย่างน้อยแปดตัวอักษร"; "Scene.Register.Input.Password.Placeholder" = "รหัสผ่าน"; -"Scene.Register.Input.Password.Require" = "รหัสผ่านของคุณต้องมีอย่างน้อย:"; +"Scene.Register.Input.Password.Require" = "รหัสผ่านของคุณจำเป็นต้องมีอย่างน้อย:"; "Scene.Register.Input.Username.DuplicatePrompt" = "ชื่อผู้ใช้นี้ถูกใช้ไปแล้ว"; "Scene.Register.Input.Username.Placeholder" = "ชื่อผู้ใช้"; "Scene.Register.Title" = "มาตั้งค่าของคุณใน %@ กันเลย"; @@ -312,16 +312,16 @@ "Scene.Search.Searching.Segment.People" = "ผู้คน"; "Scene.Search.Searching.Segment.Posts" = "โพสต์"; "Scene.Search.Title" = "ค้นหา"; -"Scene.ServerPicker.Button.Category.Academia" = "วิชาการ"; +"Scene.ServerPicker.Button.Category.Academia" = "สถาบันการศึกษา"; "Scene.ServerPicker.Button.Category.Activism" = "กิจกรรมเพื่อการเปลี่ยนแปลง"; "Scene.ServerPicker.Button.Category.All" = "ทั้งหมด"; "Scene.ServerPicker.Button.Category.AllAccessiblityDescription" = "หมวดหมู่: ทั้งหมด"; "Scene.ServerPicker.Button.Category.Art" = "ศิลปะ"; "Scene.ServerPicker.Button.Category.Food" = "อาหาร"; -"Scene.ServerPicker.Button.Category.Furry" = "furry"; +"Scene.ServerPicker.Button.Category.Furry" = "สัตว์ขนยาว"; "Scene.ServerPicker.Button.Category.Games" = "เกม"; "Scene.ServerPicker.Button.Category.General" = "ทั่วไป"; -"Scene.ServerPicker.Button.Category.Journalism" = "การเขียนข่าว"; +"Scene.ServerPicker.Button.Category.Journalism" = "วารสารศาสตร์"; "Scene.ServerPicker.Button.Category.Lgbt" = "lgbt"; "Scene.ServerPicker.Button.Category.Music" = "ดนตรี"; "Scene.ServerPicker.Button.Category.Regional" = "ภูมิภาค"; @@ -331,13 +331,13 @@ "Scene.ServerPicker.EmptyState.BadNetwork" = "มีบางอย่างผิดพลาดขณะโหลดข้อมูล ตรวจสอบการเชื่อมต่ออินเทอร์เน็ตของคุณ"; "Scene.ServerPicker.EmptyState.FindingServers" = "กำลังค้นหาเซิร์ฟเวอร์ที่พร้อมใช้งาน..."; "Scene.ServerPicker.EmptyState.NoResults" = "ไม่มีผลลัพธ์"; -"Scene.ServerPicker.Input.Placeholder" = "ค้นหาชุมชน"; +"Scene.ServerPicker.Input.Placeholder" = "ค้นหาเซิร์ฟเวอร์"; "Scene.ServerPicker.Label.Category" = "หมวดหมู่"; "Scene.ServerPicker.Label.Language" = "ภาษา"; "Scene.ServerPicker.Label.Users" = "ผู้ใช้"; -"Scene.ServerPicker.Subtitle" = "เลือกชุมชนตามความสนใจ, ภูมิภาค หรือวัตถุประสงค์ทั่วไปของคุณ"; -"Scene.ServerPicker.SubtitleExtend" = "เลือกชุมชนตามความสนใจ, ภูมิภาค หรือวัตถุประสงค์ทั่วไปของคุณ แต่ละชุมชนดำเนินการโดยองค์กรหรือบุคคลที่เป็นอิสระโดยสิ้นเชิง"; -"Scene.ServerPicker.Title" = "Mastodon ประกอบด้วยผู้ใช้ในชุมชนต่าง ๆ"; +"Scene.ServerPicker.Subtitle" = "เลือกเซิร์ฟเวอร์ตามความสนใจ, ภูมิภาค หรือวัตถุประสงค์ทั่วไปของคุณ"; +"Scene.ServerPicker.SubtitleExtend" = "เลือกเซิร์ฟเวอร์ตามความสนใจ, ภูมิภาค หรือวัตถุประสงค์ทั่วไปของคุณ แต่ละเซิร์ฟเวอร์ดำเนินการโดยองค์กรหรือบุคคลที่เป็นอิสระโดยสิ้นเชิง"; +"Scene.ServerPicker.Title" = "Mastodon ประกอบด้วยผู้ใช้ในเซิร์ฟเวอร์ต่าง ๆ"; "Scene.ServerRules.Button.Confirm" = "ฉันเห็นด้วย"; "Scene.ServerRules.PrivacyPolicy" = "นโยบายความเป็นส่วนตัว"; "Scene.ServerRules.Prompt" = "เมื่อคุณดำเนินการต่อ คุณอยู่ภายใต้เงื่อนไขการให้บริการและนโยบายความเป็นส่วนตัวสำหรับ %@"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/tr.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/tr.lproj/Localizable.strings index 9bee4db1a..887fa0641 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/tr.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/tr.lproj/Localizable.strings @@ -201,7 +201,7 @@ yüklenemiyor."; "Scene.ConfirmEmail.Subtitle" = "Hesabınızı doğrulamak için size e-postayla gönderdiğimiz bağlantıya dokunun."; "Scene.ConfirmEmail.Title" = "Son bir şey."; "Scene.Discovery.Intro" = "Bunlar, Mastodon'un köşesinde ilgi çeken gönderilerdir."; -"Scene.Discovery.Tabs.Community" = "Community"; +"Scene.Discovery.Tabs.Community" = "Topluluk"; "Scene.Discovery.Tabs.ForYou" = "Senin İçin"; "Scene.Discovery.Tabs.Hashtags" = "Etiketler"; "Scene.Discovery.Tabs.News" = "Haberler"; @@ -356,7 +356,7 @@ yüklenemiyor."; "Scene.Settings.Section.LookAndFeel.Light" = "Açık"; "Scene.Settings.Section.LookAndFeel.ReallyDark" = "Gerçek Koyu"; "Scene.Settings.Section.LookAndFeel.SortaDark" = "Hafif Koyu"; -"Scene.Settings.Section.LookAndFeel.Title" = "Look and Feel"; +"Scene.Settings.Section.LookAndFeel.Title" = "Görünüm"; "Scene.Settings.Section.LookAndFeel.UseSystem" = "Sistem İle Aynı"; "Scene.Settings.Section.Notifications.Boosts" = "Gönderimi yeniden paylaştığında"; "Scene.Settings.Section.Notifications.Favorites" = "Gönderimi favorilerine eklediğinde"; From 7f1b3188de8e3d4b9165ea4fea290185da8a1178 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 11 May 2022 16:09:52 +0800 Subject: [PATCH 081/101] feat: add report actions --- Mastodon.xcodeproj/project.pbxproj | 102 ++++----- .../xcschemes/xcschememanagement.plist | 6 +- .../ReportResult/ReportResultView.swift | 206 ++++++++++++++++++ .../ReportResultViewController.swift | 118 +++++++--- .../ReportResultViewModel+Diffable.swift | 37 ---- .../ReportResult/ReportResultViewModel.swift | 33 ++- 6 files changed, 376 insertions(+), 126 deletions(-) create mode 100644 Mastodon/Scene/Report/ReportResult/ReportResultView.swift delete mode 100644 Mastodon/Scene/Report/ReportResult/ReportResultViewModel+Diffable.swift diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index b9105dcda..59b29381e 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -410,6 +410,7 @@ DB7A9F932818F33C0016AF98 /* MastodonServerRulesViewController+Debug.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB7A9F922818F33C0016AF98 /* MastodonServerRulesViewController+Debug.swift */; }; DB7F48452620241000796008 /* ProfileHeaderViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB7F48442620241000796008 /* ProfileHeaderViewModel.swift */; }; DB8190C62601FF0400020C08 /* AttachmentContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB8190C52601FF0400020C08 /* AttachmentContainerView.swift */; }; + DB848E33282B62A800A302CC /* ReportResultView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB848E32282B62A800A302CC /* ReportResultView.swift */; }; DB852D1926FAEB6B00FC9D81 /* SidebarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB852D1826FAEB6B00FC9D81 /* SidebarViewController.swift */; }; DB852D1C26FB021500FC9D81 /* RootSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB852D1B26FB021500FC9D81 /* RootSplitViewController.swift */; }; DB852D1F26FB037800FC9D81 /* SidebarViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB852D1E26FB037800FC9D81 /* SidebarViewModel.swift */; }; @@ -451,7 +452,6 @@ DB98EB6027B10E150082E365 /* ReportCommentTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98EB5F27B10E150082E365 /* ReportCommentTableViewCell.swift */; }; DB98EB6227B215EB0082E365 /* ReportResultViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98EB6127B215EB0082E365 /* ReportResultViewController.swift */; }; DB98EB6527B216500082E365 /* ReportResultViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98EB6427B216500082E365 /* ReportResultViewModel.swift */; }; - DB98EB6727B216560082E365 /* ReportResultViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98EB6627B216560082E365 /* ReportResultViewModel+Diffable.swift */; }; DB98EB6927B21A7C0082E365 /* ReportResultActionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98EB6827B21A7C0082E365 /* ReportResultActionTableViewCell.swift */; }; DB98EB6B27B243470082E365 /* SettingsAppearanceTableViewCell+ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98EB6A27B243470082E365 /* SettingsAppearanceTableViewCell+ViewModel.swift */; }; DB9A486C26032AC1008B817C /* AttachmentContainerView+EmptyStateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9A486B26032AC1008B817C /* AttachmentContainerView+EmptyStateView.swift */; }; @@ -1173,6 +1173,7 @@ DB8190C52601FF0400020C08 /* AttachmentContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentContainerView.swift; sourceTree = ""; }; DB8481142788121200BBEABA /* MastodonRegisterTextFieldTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonRegisterTextFieldTableViewCell.swift; sourceTree = ""; }; DB84811627883C2600BBEABA /* MastodonRegisterPasswordHintTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonRegisterPasswordHintTableViewCell.swift; sourceTree = ""; }; + DB848E32282B62A800A302CC /* ReportResultView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportResultView.swift; sourceTree = ""; }; DB852D1826FAEB6B00FC9D81 /* SidebarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarViewController.swift; sourceTree = ""; }; DB852D1B26FB021500FC9D81 /* RootSplitViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootSplitViewController.swift; sourceTree = ""; }; DB852D1E26FB037800FC9D81 /* SidebarViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarViewModel.swift; sourceTree = ""; }; @@ -1221,7 +1222,6 @@ DB98EB5F27B10E150082E365 /* ReportCommentTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportCommentTableViewCell.swift; sourceTree = ""; }; DB98EB6127B215EB0082E365 /* ReportResultViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportResultViewController.swift; sourceTree = ""; }; DB98EB6427B216500082E365 /* ReportResultViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportResultViewModel.swift; sourceTree = ""; }; - DB98EB6627B216560082E365 /* ReportResultViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ReportResultViewModel+Diffable.swift"; sourceTree = ""; }; DB98EB6827B21A7C0082E365 /* ReportResultActionTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportResultActionTableViewCell.swift; sourceTree = ""; }; DB98EB6A27B243470082E365 /* SettingsAppearanceTableViewCell+ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SettingsAppearanceTableViewCell+ViewModel.swift"; sourceTree = ""; }; DB9A486B26032AC1008B817C /* AttachmentContainerView+EmptyStateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AttachmentContainerView+EmptyStateView.swift"; sourceTree = ""; }; @@ -2909,7 +2909,7 @@ children = ( DB98EB6127B215EB0082E365 /* ReportResultViewController.swift */, DB98EB6427B216500082E365 /* ReportResultViewModel.swift */, - DB98EB6627B216560082E365 /* ReportResultViewModel+Diffable.swift */, + DB848E32282B62A800A302CC /* ReportResultView.swift */, ); path = ReportResult; sourceTree = ""; @@ -3594,23 +3594,23 @@ ); mainGroup = DB427DC925BAA00100D1B89D; packageReferences = ( - DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage.git" */, + DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */, 2D61336725C18A4F00CAE157 /* XCRemoteSwiftPackageReference "AlamofireNetworkActivityIndicator" */, DB0140BB25C40D7500F9F3CF /* XCRemoteSwiftPackageReference "CommonOSLog" */, - 2D5981B825E4D7F8000FB903 /* XCRemoteSwiftPackageReference "ThirdPartyMailer.git" */, - 2D939AC625EE14620076FA61 /* XCRemoteSwiftPackageReference "TOCropViewController.git" */, + 2D5981B825E4D7F8000FB903 /* XCRemoteSwiftPackageReference "ThirdPartyMailer" */, + 2D939AC625EE14620076FA61 /* XCRemoteSwiftPackageReference "TOCropViewController" */, DBB525062611EAC0002F1F29 /* XCRemoteSwiftPackageReference "Tabman" */, - DB6804722637CC1200430867 /* XCRemoteSwiftPackageReference "KeychainAccess.git" */, - DBAC6481267D0B21007FE9FD /* XCRemoteSwiftPackageReference "DifferenceKit.git" */, - DBAC649C267DFE43007FE9FD /* XCRemoteSwiftPackageReference "DiffableDataSources.git" */, - DBAC649F267E6D01007FE9FD /* XCRemoteSwiftPackageReference "Fuzi.git" */, - DBF7A0FA26830C33004176A2 /* XCRemoteSwiftPackageReference "FPSIndicator.git" */, - DB0E2D2C26833FF600865C3C /* XCRemoteSwiftPackageReference "Nuke-FLAnimatedImage-Plugin.git" */, - DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit.git" */, - DB552D4D26BBD10C00E481F6 /* XCRemoteSwiftPackageReference "swift-collections.git" */, - DBA5A52D26F07ED800CACBAA /* XCRemoteSwiftPackageReference "PanModal.git" */, - DB8D8E2D28192EED009FD90F /* XCRemoteSwiftPackageReference "SwiftUI-Introspect.git" */, - DB3EA8F6281BBA4C00598866 /* XCRemoteSwiftPackageReference "Alamofire.git" */, + DB6804722637CC1200430867 /* XCRemoteSwiftPackageReference "KeychainAccess" */, + DBAC6481267D0B21007FE9FD /* XCRemoteSwiftPackageReference "DifferenceKit" */, + DBAC649C267DFE43007FE9FD /* XCRemoteSwiftPackageReference "DiffableDataSources" */, + DBAC649F267E6D01007FE9FD /* XCRemoteSwiftPackageReference "Fuzi" */, + DBF7A0FA26830C33004176A2 /* XCRemoteSwiftPackageReference "FPSIndicator" */, + DB0E2D2C26833FF600865C3C /* XCRemoteSwiftPackageReference "Nuke-FLAnimatedImage-Plugin" */, + DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit" */, + DB552D4D26BBD10C00E481F6 /* XCRemoteSwiftPackageReference "swift-collections" */, + DBA5A52D26F07ED800CACBAA /* XCRemoteSwiftPackageReference "PanModal" */, + DB8D8E2D28192EED009FD90F /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */, + DB3EA8F6281BBA4C00598866 /* XCRemoteSwiftPackageReference "Alamofire" */, ); productRefGroup = DB427DD325BAA00100D1B89D /* Products */; projectDirPath = ""; @@ -3951,6 +3951,7 @@ 5DDDF1932617442700311060 /* Mastodon+Entity+Account.swift in Sources */, DB63F767279A5EB300455B82 /* NotificationTimelineViewModel.swift in Sources */, 2D607AD826242FC500B70763 /* NotificationViewModel.swift in Sources */, + DB848E33282B62A800A302CC /* ReportResultView.swift in Sources */, DBABE3EC25ECAC4B00879EE5 /* WelcomeIllustrationView.swift in Sources */, DB564BD3269F3B35001E39A7 /* StatusFilterService.swift in Sources */, DB0FCB9C27980AB6006C02E2 /* HashtagTimelineViewController+DataSourceProvider.swift in Sources */, @@ -4126,7 +4127,6 @@ DB3E6FEF2806D82600B035AE /* DiscoveryNewsViewModel.swift in Sources */, DBBF1DCB2652539E00E5B703 /* AutoCompleteItem.swift in Sources */, 2DA6054725F716A2006356F9 /* PlaybackState.swift in Sources */, - DB98EB6727B216560082E365 /* ReportResultViewModel+Diffable.swift in Sources */, DBC7A672260C897100E57475 /* StatusContentWarningEditorView.swift in Sources */, DB025B95278D6530002F581E /* Persistence+MastodonUser.swift in Sources */, DB3667A6268AE2620027D07F /* ComposeStatusPollSection.swift in Sources */, @@ -5663,7 +5663,7 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ - 2D5981B825E4D7F8000FB903 /* XCRemoteSwiftPackageReference "ThirdPartyMailer.git" */ = { + 2D5981B825E4D7F8000FB903 /* XCRemoteSwiftPackageReference "ThirdPartyMailer" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/vtourraine/ThirdPartyMailer.git"; requirement = { @@ -5679,7 +5679,7 @@ minimumVersion = 3.1.0; }; }; - 2D939AC625EE14620076FA61 /* XCRemoteSwiftPackageReference "TOCropViewController.git" */ = { + 2D939AC625EE14620076FA61 /* XCRemoteSwiftPackageReference "TOCropViewController" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/TimOliver/TOCropViewController.git"; requirement = { @@ -5695,7 +5695,7 @@ minimumVersion = 0.1.1; }; }; - DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit.git" */ = { + DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/TwidereProject/MetaTextKit.git"; requirement = { @@ -5703,7 +5703,7 @@ version = 2.2.3; }; }; - DB0E2D2C26833FF600865C3C /* XCRemoteSwiftPackageReference "Nuke-FLAnimatedImage-Plugin.git" */ = { + DB0E2D2C26833FF600865C3C /* XCRemoteSwiftPackageReference "Nuke-FLAnimatedImage-Plugin" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/kean/Nuke-FLAnimatedImage-Plugin.git"; requirement = { @@ -5711,7 +5711,7 @@ minimumVersion = 8.0.0; }; }; - DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage.git" */ = { + DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/Alamofire/AlamofireImage.git"; requirement = { @@ -5719,7 +5719,7 @@ minimumVersion = 4.1.0; }; }; - DB3EA8F6281BBA4C00598866 /* XCRemoteSwiftPackageReference "Alamofire.git" */ = { + DB3EA8F6281BBA4C00598866 /* XCRemoteSwiftPackageReference "Alamofire" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/Alamofire/Alamofire.git"; requirement = { @@ -5727,7 +5727,7 @@ minimumVersion = 5.4.0; }; }; - DB552D4D26BBD10C00E481F6 /* XCRemoteSwiftPackageReference "swift-collections.git" */ = { + DB552D4D26BBD10C00E481F6 /* XCRemoteSwiftPackageReference "swift-collections" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/apple/swift-collections.git"; requirement = { @@ -5735,7 +5735,7 @@ minimumVersion = 0.0.5; }; }; - DB6804722637CC1200430867 /* XCRemoteSwiftPackageReference "KeychainAccess.git" */ = { + DB6804722637CC1200430867 /* XCRemoteSwiftPackageReference "KeychainAccess" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/kishikawakatsumi/KeychainAccess.git"; requirement = { @@ -5743,7 +5743,7 @@ minimumVersion = 4.2.2; }; }; - DB8D8E2D28192EED009FD90F /* XCRemoteSwiftPackageReference "SwiftUI-Introspect.git" */ = { + DB8D8E2D28192EED009FD90F /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/siteline/SwiftUI-Introspect.git"; requirement = { @@ -5751,7 +5751,7 @@ minimumVersion = 0.1.4; }; }; - DBA5A52D26F07ED800CACBAA /* XCRemoteSwiftPackageReference "PanModal.git" */ = { + DBA5A52D26F07ED800CACBAA /* XCRemoteSwiftPackageReference "PanModal" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/slackhq/PanModal.git"; requirement = { @@ -5759,7 +5759,7 @@ minimumVersion = 1.2.7; }; }; - DBAC6481267D0B21007FE9FD /* XCRemoteSwiftPackageReference "DifferenceKit.git" */ = { + DBAC6481267D0B21007FE9FD /* XCRemoteSwiftPackageReference "DifferenceKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/ra1028/DifferenceKit.git"; requirement = { @@ -5767,7 +5767,7 @@ version = 1.2.0; }; }; - DBAC649C267DFE43007FE9FD /* XCRemoteSwiftPackageReference "DiffableDataSources.git" */ = { + DBAC649C267DFE43007FE9FD /* XCRemoteSwiftPackageReference "DiffableDataSources" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/MainasuK/DiffableDataSources.git"; requirement = { @@ -5775,7 +5775,7 @@ kind = branch; }; }; - DBAC649F267E6D01007FE9FD /* XCRemoteSwiftPackageReference "Fuzi.git" */ = { + DBAC649F267E6D01007FE9FD /* XCRemoteSwiftPackageReference "Fuzi" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/cezheng/Fuzi.git"; requirement = { @@ -5791,7 +5791,7 @@ minimumVersion = 2.11.0; }; }; - DBF7A0FA26830C33004176A2 /* XCRemoteSwiftPackageReference "FPSIndicator.git" */ = { + DBF7A0FA26830C33004176A2 /* XCRemoteSwiftPackageReference "FPSIndicator" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/MainasuK/FPSIndicator.git"; requirement = { @@ -5804,7 +5804,7 @@ /* Begin XCSwiftPackageProductDependency section */ 2D5981B925E4D7F8000FB903 /* ThirdPartyMailer */ = { isa = XCSwiftPackageProductDependency; - package = 2D5981B825E4D7F8000FB903 /* XCRemoteSwiftPackageReference "ThirdPartyMailer.git" */; + package = 2D5981B825E4D7F8000FB903 /* XCRemoteSwiftPackageReference "ThirdPartyMailer" */; productName = ThirdPartyMailer; }; 2D61336825C18A4F00CAE157 /* AlamofireNetworkActivityIndicator */ = { @@ -5814,12 +5814,12 @@ }; 2D939AC725EE14620076FA61 /* CropViewController */ = { isa = XCSwiftPackageProductDependency; - package = 2D939AC625EE14620076FA61 /* XCRemoteSwiftPackageReference "TOCropViewController.git" */; + package = 2D939AC625EE14620076FA61 /* XCRemoteSwiftPackageReference "TOCropViewController" */; productName = CropViewController; }; DB02EA0A280D180D00E751C5 /* KeychainAccess */ = { isa = XCSwiftPackageProductDependency; - package = DB6804722637CC1200430867 /* XCRemoteSwiftPackageReference "KeychainAccess.git" */; + package = DB6804722637CC1200430867 /* XCRemoteSwiftPackageReference "KeychainAccess" */; productName = KeychainAccess; }; DB3EA8F4281BB65200598866 /* MastodonSDK */ = { @@ -5828,17 +5828,17 @@ }; DB3EA8FB281BBAE100598866 /* AlamofireImage */ = { isa = XCSwiftPackageProductDependency; - package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage.git" */; + package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */; productName = AlamofireImage; }; DB3EA8FD281BBAF200598866 /* Alamofire */ = { isa = XCSwiftPackageProductDependency; - package = DB3EA8F6281BBA4C00598866 /* XCRemoteSwiftPackageReference "Alamofire.git" */; + package = DB3EA8F6281BBA4C00598866 /* XCRemoteSwiftPackageReference "Alamofire" */; productName = Alamofire; }; DB3EA8FF281BBB1D00598866 /* MetaTextKit */ = { isa = XCSwiftPackageProductDependency; - package = DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit.git" */; + package = DB01E23126A98F0900C3965B /* XCRemoteSwiftPackageReference "MetaTextKit" */; productName = MetaTextKit; }; DB3EA901281BBD5D00598866 /* CommonOSLog */ = { @@ -5848,12 +5848,12 @@ }; DB3EA903281BBD9400598866 /* Introspect */ = { isa = XCSwiftPackageProductDependency; - package = DB8D8E2D28192EED009FD90F /* XCRemoteSwiftPackageReference "SwiftUI-Introspect.git" */; + package = DB8D8E2D28192EED009FD90F /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */; productName = Introspect; }; DB3EA905281BBE8200598866 /* AlamofireImage */ = { isa = XCSwiftPackageProductDependency; - package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage.git" */; + package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */; productName = AlamofireImage; }; DB3EA907281BBE8200598866 /* AlamofireNetworkActivityIndicator */ = { @@ -5863,12 +5863,12 @@ }; DB3EA909281BBE8200598866 /* Alamofire */ = { isa = XCSwiftPackageProductDependency; - package = DB3EA8F6281BBA4C00598866 /* XCRemoteSwiftPackageReference "Alamofire.git" */; + package = DB3EA8F6281BBA4C00598866 /* XCRemoteSwiftPackageReference "Alamofire" */; productName = Alamofire; }; DB3EA90B281BBE9600598866 /* AlamofireImage */ = { isa = XCSwiftPackageProductDependency; - package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage.git" */; + package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */; productName = AlamofireImage; }; DB3EA90D281BBE9600598866 /* AlamofireNetworkActivityIndicator */ = { @@ -5878,42 +5878,42 @@ }; DB3EA90F281BBE9600598866 /* Alamofire */ = { isa = XCSwiftPackageProductDependency; - package = DB3EA8F6281BBA4C00598866 /* XCRemoteSwiftPackageReference "Alamofire.git" */; + package = DB3EA8F6281BBA4C00598866 /* XCRemoteSwiftPackageReference "Alamofire" */; productName = Alamofire; }; DB3EA911281BBEA800598866 /* AlamofireImage */ = { isa = XCSwiftPackageProductDependency; - package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage.git" */; + package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */; productName = AlamofireImage; }; DB3EA913281BBEA800598866 /* Alamofire */ = { isa = XCSwiftPackageProductDependency; - package = DB3EA8F6281BBA4C00598866 /* XCRemoteSwiftPackageReference "Alamofire.git" */; + package = DB3EA8F6281BBA4C00598866 /* XCRemoteSwiftPackageReference "Alamofire" */; productName = Alamofire; }; DB552D4E26BBD10C00E481F6 /* OrderedCollections */ = { isa = XCSwiftPackageProductDependency; - package = DB552D4D26BBD10C00E481F6 /* XCRemoteSwiftPackageReference "swift-collections.git" */; + package = DB552D4D26BBD10C00E481F6 /* XCRemoteSwiftPackageReference "swift-collections" */; productName = OrderedCollections; }; DBA5A52E26F07ED800CACBAA /* PanModal */ = { isa = XCSwiftPackageProductDependency; - package = DBA5A52D26F07ED800CACBAA /* XCRemoteSwiftPackageReference "PanModal.git" */; + package = DBA5A52D26F07ED800CACBAA /* XCRemoteSwiftPackageReference "PanModal" */; productName = PanModal; }; DBAC6482267D0B21007FE9FD /* DifferenceKit */ = { isa = XCSwiftPackageProductDependency; - package = DBAC6481267D0B21007FE9FD /* XCRemoteSwiftPackageReference "DifferenceKit.git" */; + package = DBAC6481267D0B21007FE9FD /* XCRemoteSwiftPackageReference "DifferenceKit" */; productName = DifferenceKit; }; DBAC649D267DFE43007FE9FD /* DiffableDataSources */ = { isa = XCSwiftPackageProductDependency; - package = DBAC649C267DFE43007FE9FD /* XCRemoteSwiftPackageReference "DiffableDataSources.git" */; + package = DBAC649C267DFE43007FE9FD /* XCRemoteSwiftPackageReference "DiffableDataSources" */; productName = DiffableDataSources; }; DBAC64A0267E6D02007FE9FD /* Fuzi */ = { isa = XCSwiftPackageProductDependency; - package = DBAC649F267E6D01007FE9FD /* XCRemoteSwiftPackageReference "Fuzi.git" */; + package = DBAC649F267E6D01007FE9FD /* XCRemoteSwiftPackageReference "Fuzi" */; productName = Fuzi; }; DBB525072611EAC0002F1F29 /* Tabman */ = { @@ -5923,7 +5923,7 @@ }; DBF7A0FB26830C33004176A2 /* FPSIndicator */ = { isa = XCSwiftPackageProductDependency; - package = DBF7A0FA26830C33004176A2 /* XCRemoteSwiftPackageReference "FPSIndicator.git" */; + package = DBF7A0FA26830C33004176A2 /* XCRemoteSwiftPackageReference "FPSIndicator" */; productName = FPSIndicator; }; /* End XCSwiftPackageProductDependency section */ diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 3d2d4b728..66a7b7bd6 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -114,7 +114,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 27 + 22 MastodonIntents.xcscheme_^#shared#^_ @@ -129,12 +129,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 29 + 20 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 28 + 21 SuppressBuildableAutocreation diff --git a/Mastodon/Scene/Report/ReportResult/ReportResultView.swift b/Mastodon/Scene/Report/ReportResult/ReportResultView.swift new file mode 100644 index 000000000..aa063ac2d --- /dev/null +++ b/Mastodon/Scene/Report/ReportResult/ReportResultView.swift @@ -0,0 +1,206 @@ +// +// ReportResultView.swift +// Mastodon +// +// Created by MainasuK on 2022-5-11. +// + +import UIKit +import SwiftUI +import MastodonLocalization +import MastodonSDK +import MastodonUI +import MastodonAsset +import CoreDataStack + +struct ReportResultView: View { + + @ObservedObject var viewModel: ReportResultViewModel + + var avatarView: some View { + HStack { + Spacer() + ZStack { + AnimatedImage(imageURL: viewModel.avatarURL) + .frame(width: 106, height: 106, alignment: .center) + .background(Color(UIColor.systemFill)) + .cornerRadius(27) + Text(L10n.Scene.Report.reported) + .font(Font(FontFamily.Staatliches.regular.font(size: 49) as CTFont)) + .foregroundColor(Color(Asset.Scene.Report.reportBanner.color)) + .padding(EdgeInsets(top: 0, leading: 10, bottom: -2, trailing: 10)) + .background(Color(viewModel.backgroundColor)) + .cornerRadius(7) + .padding(7) + .background(Color(Asset.Scene.Report.reportBanner.color)) + .cornerRadius(12) + .rotationEffect(.degrees(-8)) + .offset(x: 0, y: -5) + } + Spacer() + } + .padding() + } + + // TODO: i18n + var body: some View { + ScrollView(.vertical) { + HStack { + VStack(alignment: .leading, spacing: 8) { + Text(viewModel.headline) + .foregroundColor(Color(Asset.Colors.Label.primary.color)) + .font(Font(UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: .systemFont(ofSize: 28, weight: .bold)) as CTFont)) + avatarView + Text(verbatim: "While we review this, you can take action against @\(viewModel.username)") + .foregroundColor(Color(Asset.Colors.Label.secondary.color)) + .font(Font(UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)) as CTFont)) + } + Spacer() + } + .padding() + + VStack(spacing: 32) { + // Follow + VStack(alignment: .leading, spacing: 4) { + Text("Unfollow @\(viewModel.username)") + .font(.headline) + .foregroundColor(Color(Asset.Colors.Label.primary.color)) + ReportActionButton( + action: { + viewModel.followActionPublisher.send() + }, + title: viewModel.relationshipViewModel.isFollowing ? "Unfollow" : "Unfollowed", + isBusy: viewModel.isRequestFollow + ) + } + + // Mute + VStack(alignment: .leading, spacing: 4) { + Text("Mute @\(viewModel.username)") + .font(.headline) + .foregroundColor(Color(Asset.Colors.Label.primary.color)) + Text(verbatim: "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted.") + .foregroundColor(Color(Asset.Colors.Label.secondary.color)) + .font(Font(UIFontMetrics(forTextStyle: .subheadline).scaledFont(for: .systemFont(ofSize: 13, weight: .regular)) as CTFont)) + ReportActionButton( + action: { + viewModel.muteActionPublisher.send() + }, + title: viewModel.relationshipViewModel.isMuting ? L10n.Common.Controls.Friendship.muted : L10n.Common.Controls.Friendship.mute, + isBusy: viewModel.isRequestMute + ) + } + + // Block + VStack(alignment: .leading, spacing: 4) { + Text("Block @\(viewModel.username)") + .font(.headline) + .foregroundColor(Color(Asset.Colors.Label.primary.color)) + Text(verbatim: "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked.") + .foregroundColor(Color(Asset.Colors.Label.secondary.color)) + .font(Font(UIFontMetrics(forTextStyle: .subheadline).scaledFont(for: .systemFont(ofSize: 13, weight: .regular)) as CTFont)) + ReportActionButton( + action: { + viewModel.blockActionPublisher.send() + }, + title: viewModel.relationshipViewModel.isBlocking ? L10n.Common.Controls.Friendship.blocked : L10n.Common.Controls.Friendship.block, + isBusy: viewModel.isRequestBlock + ) + } + } + .padding() + + Spacer() + .frame(minHeight: viewModel.bottomPaddingHeight) + } + .background( + Color(viewModel.backgroundColor) + ) + } + +} + +struct ReportActionButton: View { + + var action: () -> Void + var title: String + var isBusy: Bool + + var body: some View { + Button { + action() + } label: { + ZStack { + ProgressView() + .opacity(isBusy ? 1 : 0) + Text(title) + .font(.headline) + .foregroundColor(Color(Asset.Colors.Label.primary.color)) + .opacity(isBusy ? 0 : 1) + } + .frame(maxWidth: .infinity) + .padding() + .background(Color(UIColor.systemBackground)) + .cornerRadius(10) + .shadow(color: .black.opacity(0.1), radius: 2, x: 0, y: 1) + } + } + +} + +#if DEBUG +struct ReportResultView_Previews: PreviewProvider { + + static var viewModel: ReportResultViewModel { + let context = AppContext.shared + let request = MastodonUser.sortedFetchRequest + request.fetchLimit = 1 + + let property = MastodonUser.Property( + identifier: "1", + domain: "domain.com", + id: "1", + acct: "@user@domain.com", + username: "user", + displayName: "User", + avatar: "", + avatarStatic: "", + header: "", + headerStatic: "", + note: "", + url: "", + statusesCount: Int64(100), + followingCount: Int64(100), + followersCount: Int64(100), + locked: false, + bot: false, + suspended: false, + createdAt: Date(), + updatedAt: Date(), + emojis: [], + fields: [] + ) + let user = try! context.managedObjectContext.fetch(request).first ?? MastodonUser.insert(into: context.managedObjectContext, property: property) + + return ReportResultViewModel( + context: context, + user: .init(objectID: user.objectID) + ) + } + static var previews: some View { + Group { + NavigationView { + ReportResultView(viewModel: viewModel) + .navigationBarTitle(Text("")) + .navigationBarTitleDisplayMode(.inline) + } + NavigationView { + ReportResultView(viewModel: viewModel) + .navigationBarTitle(Text("")) + .navigationBarTitleDisplayMode(.inline) + } + .preferredColorScheme(.dark) + } + } +} +#endif diff --git a/Mastodon/Scene/Report/ReportResult/ReportResultViewController.swift b/Mastodon/Scene/Report/ReportResult/ReportResultViewController.swift index 1073c21a2..957760f38 100644 --- a/Mastodon/Scene/Report/ReportResult/ReportResultViewController.swift +++ b/Mastodon/Scene/Report/ReportResult/ReportResultViewController.swift @@ -7,6 +7,7 @@ import os.log import UIKit +import SwiftUI import Combine import MastodonAsset import MastodonLocalization @@ -20,29 +21,14 @@ final class ReportResultViewController: UIViewController, NeedsDependency, Repor weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } var viewModel: ReportResultViewModel! - + private(set) lazy var reportResultView = ReportResultView(viewModel: viewModel) + lazy var doneBarButtonItem = UIBarButtonItem( barButtonSystemItem: .done, target: self, action: #selector(ReportResultViewController.doneBarButtonItemDidPressed(_:)) ) - let tableView: UITableView = { - let tableView = ControlContainableTableView() - tableView.backgroundColor = Asset.Scene.Report.background.color - tableView.rowHeight = UITableView.automaticDimension - tableView.separatorStyle = .none - tableView.backgroundColor = .clear - tableView.keyboardDismissMode = .onDrag - tableView.allowsMultipleSelection = true - if #available(iOS 15.0, *) { - tableView.sectionHeaderTopPadding = .leastNonzeroMagnitude - } else { - // Fallback on earlier versions - } - return tableView - }() - let navigationActionView: NavigationActionView = { let navigationActionView = NavigationActionView() navigationActionView.backgroundColor = Asset.Scene.Onboarding.background.color @@ -68,20 +54,18 @@ extension ReportResultViewController { navigationItem.hidesBackButton = true navigationItem.rightBarButtonItem = doneBarButtonItem - tableView.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(tableView) + let hostingViewController = UIHostingController(rootView: reportResultView) + hostingViewController.view.preservesSuperviewLayoutMargins = true + addChild(hostingViewController) + hostingViewController.view.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(hostingViewController.view) NSLayoutConstraint.activate([ - tableView.topAnchor.constraint(equalTo: view.topAnchor), - tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), - tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), - tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + hostingViewController.view.topAnchor.constraint(equalTo: view.topAnchor), + hostingViewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor), + hostingViewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor), + hostingViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor), ]) - tableView.delegate = self - viewModel.setupDiffableDataSource( - tableView: tableView - ) - navigationActionView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(navigationActionView) defer { @@ -97,13 +81,84 @@ extension ReportResultViewController { .observe(\.bounds, options: [.initial, .new]) { [weak self] navigationActionView, _ in guard let self = self else { return } let inset = navigationActionView.frame.height - self.tableView.contentInset.bottom = inset - self.tableView.verticalScrollIndicatorInsets.bottom = inset + self.viewModel.bottomPaddingHeight = inset } .store(in: &observations) navigationActionView.nextButton.addTarget(self, action: #selector(ReportSupplementaryViewController.nextButtonDidPressed(_:)), for: .touchUpInside) + + viewModel.followActionPublisher + .throttle(for: 0.3, scheduler: DispatchQueue.main, latest: false) + .sink { [weak self] in + guard let self = self else { return } + guard let authenticationBox = self.context.authenticationService.activeMastodonAuthenticationBox.value else { + return + } + Task { @MainActor in + guard !self.viewModel.isRequestFollow else { return } + self.viewModel.isRequestFollow = true + do { + try await DataSourceFacade.responseToUserFollowAction( + dependency: self, + user: self.viewModel.user, + authenticationBox: authenticationBox + ) + } catch { + // handle error + } + self.viewModel.isRequestFollow = false + } // end Task + } + .store(in: &disposeBag) + + viewModel.muteActionPublisher + .throttle(for: 0.3, scheduler: DispatchQueue.main, latest: false) + .sink { [weak self] in + guard let self = self else { return } + guard let authenticationBox = self.context.authenticationService.activeMastodonAuthenticationBox.value else { + return + } + Task { @MainActor in + guard !self.viewModel.isRequestMute else { return } + self.viewModel.isRequestMute = true + do { + try await DataSourceFacade.responseToUserMuteAction( + dependency: self, + user: self.viewModel.user, + authenticationBox: authenticationBox + ) + } catch { + // handle error + } + self.viewModel.isRequestMute = false + } // end Task + } + .store(in: &disposeBag) + + viewModel.blockActionPublisher + .throttle(for: 0.3, scheduler: DispatchQueue.main, latest: false) + .sink { [weak self] in + guard let self = self else { return } + guard let authenticationBox = self.context.authenticationService.activeMastodonAuthenticationBox.value else { + return + } + Task { @MainActor in + guard !self.viewModel.isRequestBlock else { return } + self.viewModel.isRequestBlock = true + do { + try await DataSourceFacade.responseToUserBlockAction( + dependency: self, + user: self.viewModel.user, + authenticationBox: authenticationBox + ) + } catch { + // handle error + } + self.viewModel.isRequestBlock = false + } // end Task + } + .store(in: &disposeBag) } } @@ -120,9 +175,6 @@ extension ReportResultViewController { } -// MARK: - UITableViewDelegate -extension ReportResultViewController: UITableViewDelegate { } - // MARK: - PanPopableViewController extension ReportResultViewController: PanPopableViewController { var isPanPopable: Bool { false } diff --git a/Mastodon/Scene/Report/ReportResult/ReportResultViewModel+Diffable.swift b/Mastodon/Scene/Report/ReportResult/ReportResultViewModel+Diffable.swift deleted file mode 100644 index a9c1272df..000000000 --- a/Mastodon/Scene/Report/ReportResult/ReportResultViewModel+Diffable.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// ReportResultViewModel+Diffable.swift -// Mastodon -// -// Created by MainasuK on 2022-2-8. -// - -import UIKit -import Combine -import CoreData -import CoreDataStack -import MastodonAsset -import MastodonLocalization - -extension ReportResultViewModel { - - static let reportItemHeaderContext = ReportItem.HeaderContext( - primaryLabelText: "Thanks for reporting, we’ll look into this.", - secondaryLabelText: "" - ) - - func setupDiffableDataSource( - tableView: UITableView - ) { - diffableDataSource = ReportSection.diffableDataSource( - tableView: tableView, - context: context, - configuration: ReportSection.Configuration() - ) - - var snapshot = NSDiffableDataSourceSnapshot() - snapshot.appendSections([.main]) - snapshot.appendItems([.header(context: ReportResultViewModel.reportItemHeaderContext)], toSection: .main) - snapshot.appendItems([.result(record: user)], toSection: .main) - diffableDataSource?.apply(snapshot) - } -} diff --git a/Mastodon/Scene/Report/ReportResult/ReportResultViewModel.swift b/Mastodon/Scene/Report/ReportResult/ReportResultViewModel.swift index 79fec4936..8617f26f9 100644 --- a/Mastodon/Scene/Report/ReportResult/ReportResultViewModel.swift +++ b/Mastodon/Scene/Report/ReportResult/ReportResultViewModel.swift @@ -12,8 +12,10 @@ import Foundation import MastodonSDK import os.log import UIKit +import MastodonAsset +import MastodonUI -class ReportResultViewModel { +class ReportResultViewModel: ObservableObject { var disposeBag = Set() @@ -21,8 +23,22 @@ class ReportResultViewModel { let context: AppContext let user: ManagedObjectRecord + @Published var headline = "Thanks for reporting, we’ll look into this." + @Published var bottomPaddingHeight: CGFloat = .zero + @Published var backgroundColor: UIColor = Asset.Scene.Report.background.color + + @Published var isRequestFollow = false + @Published var isRequestMute = false + @Published var isRequestBlock = false + // output - var diffableDataSource: UITableViewDiffableDataSource? + @Published var avatarURL: URL? + @Published var username: String = "" + + let relationshipViewModel = RelationshipViewModel() + let muteActionPublisher = PassthroughSubject() + let followActionPublisher = PassthroughSubject() + let blockActionPublisher = PassthroughSubject() init( context: AppContext, @@ -31,6 +47,19 @@ class ReportResultViewModel { self.context = context self.user = user // end init + + Task { @MainActor in + guard let user = user.object(in: context.managedObjectContext) else { return } + guard let me = context.authenticationService.activeMastodonAuthenticationBox.value?.authenticationRecord.object(in: context.managedObjectContext)?.user else { return } + self.relationshipViewModel.user = user + self.relationshipViewModel.me = me + + self.avatarURL = user.avatarImageURL() + self.username = user.acctWithDomain + + } // end Task } } + + From 16dc0adccd625fa479673dfb489b1dc5d2aa1d85 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 11 May 2022 16:26:57 +0800 Subject: [PATCH 082/101] feat: add dislike report path --- .../Report/Report/ReportViewController.swift | 26 ++++++++++++++--- .../ReportResult/ReportResultView.swift | 28 +++++++++++++------ .../ReportResult/ReportResultViewModel.swift | 9 ++++-- 3 files changed, 49 insertions(+), 14 deletions(-) diff --git a/Mastodon/Scene/Report/Report/ReportViewController.swift b/Mastodon/Scene/Report/Report/ReportViewController.swift index 1fa8428e6..1fe1a720c 100644 --- a/Mastodon/Scene/Report/Report/ReportViewController.swift +++ b/Mastodon/Scene/Report/Report/ReportViewController.swift @@ -91,8 +91,16 @@ extension ReportViewController: ReportReasonViewControllerDelegate { guard let reason = viewController.viewModel.selectReason else { return } switch reason { case .dislike: - // TODO: - break + let reportResultViewModel = ReportResultViewModel( + context: context, + user: viewModel.user, + isReported: false + ) + coordinator.present( + scene: .reportResult(viewModel: reportResultViewModel), + from: self, + transition: .show + ) case .violateRule: coordinator.present( scene: .reportServerRules(viewModel: viewModel.reportServerRulesViewModel), @@ -113,7 +121,16 @@ extension ReportViewController: ReportReasonViewControllerDelegate { extension ReportViewController: ReportServerRulesViewControllerDelegate { func reportServerRulesViewController(_ viewController: ReportServerRulesViewController, nextButtonPressed button: UIButton) { if viewController.viewModel.isDislike { - // TODO: + let reportResultViewModel = ReportResultViewModel( + context: context, + user: viewModel.user, + isReported: false + ) + coordinator.present( + scene: .reportResult(viewModel: reportResultViewModel), + from: self, + transition: .show + ) } else if viewController.viewModel.selectRule != nil { coordinator.present( scene: .reportStatus(viewModel: viewModel.reportStatusViewModel), @@ -163,7 +180,8 @@ extension ReportViewController: ReportSupplementaryViewControllerDelegate { let reportResultViewModel = ReportResultViewModel( context: context, - user: viewModel.user + user: viewModel.user, + isReported: true ) coordinator.present( diff --git a/Mastodon/Scene/Report/ReportResult/ReportResultView.swift b/Mastodon/Scene/Report/ReportResult/ReportResultView.swift index aa063ac2d..dff87e356 100644 --- a/Mastodon/Scene/Report/ReportResult/ReportResultView.swift +++ b/Mastodon/Scene/Report/ReportResult/ReportResultView.swift @@ -50,10 +50,16 @@ struct ReportResultView: View { Text(viewModel.headline) .foregroundColor(Color(Asset.Colors.Label.primary.color)) .font(Font(UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: .systemFont(ofSize: 28, weight: .bold)) as CTFont)) - avatarView - Text(verbatim: "While we review this, you can take action against @\(viewModel.username)") - .foregroundColor(Color(Asset.Colors.Label.secondary.color)) - .font(Font(UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)) as CTFont)) + if viewModel.isReported { + avatarView + Text(verbatim: "While we review this, you can take action against @\(viewModel.username)") + .foregroundColor(Color(Asset.Colors.Label.secondary.color)) + .font(Font(UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)) as CTFont)) + } else { + Text(verbatim: "When you see something you don’t like on Mastodon, you can remove the person from your experience.") + .foregroundColor(Color(Asset.Colors.Label.secondary.color)) + .font(Font(UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)) as CTFont)) + } } Spacer() } @@ -151,7 +157,7 @@ struct ReportActionButton: View { #if DEBUG struct ReportResultView_Previews: PreviewProvider { - static var viewModel: ReportResultViewModel { + static func viewModel(isReported: Bool) -> ReportResultViewModel { let context = AppContext.shared let request = MastodonUser.sortedFetchRequest request.fetchLimit = 1 @@ -184,18 +190,24 @@ struct ReportResultView_Previews: PreviewProvider { return ReportResultViewModel( context: context, - user: .init(objectID: user.objectID) + user: .init(objectID: user.objectID), + isReported: isReported ) } static var previews: some View { Group { NavigationView { - ReportResultView(viewModel: viewModel) + ReportResultView(viewModel: viewModel(isReported: true)) .navigationBarTitle(Text("")) .navigationBarTitleDisplayMode(.inline) } NavigationView { - ReportResultView(viewModel: viewModel) + ReportResultView(viewModel: viewModel(isReported: false)) + .navigationBarTitle(Text("")) + .navigationBarTitleDisplayMode(.inline) + } + NavigationView { + ReportResultView(viewModel: viewModel(isReported: true)) .navigationBarTitle(Text("")) .navigationBarTitleDisplayMode(.inline) } diff --git a/Mastodon/Scene/Report/ReportResult/ReportResultViewModel.swift b/Mastodon/Scene/Report/ReportResult/ReportResultViewModel.swift index 8617f26f9..ea949a901 100644 --- a/Mastodon/Scene/Report/ReportResult/ReportResultViewModel.swift +++ b/Mastodon/Scene/Report/ReportResult/ReportResultViewModel.swift @@ -22,8 +22,11 @@ class ReportResultViewModel: ObservableObject { // input let context: AppContext let user: ManagedObjectRecord + let isReported: Bool - @Published var headline = "Thanks for reporting, we’ll look into this." + var headline: String { + isReported ? "Thanks for reporting, we’ll look into this." : "Don’t want to see this?" + } @Published var bottomPaddingHeight: CGFloat = .zero @Published var backgroundColor: UIColor = Asset.Scene.Report.background.color @@ -42,10 +45,12 @@ class ReportResultViewModel: ObservableObject { init( context: AppContext, - user: ManagedObjectRecord + user: ManagedObjectRecord, + isReported: Bool ) { self.context = context self.user = user + self.isReported = isReported // end init Task { @MainActor in From 741e8d998d0f6b0e0c7443ec8c4ea6482f34e622 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 11 May 2022 16:27:32 +0800 Subject: [PATCH 083/101] fix: i18n template --- Localization/app.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/app.json b/Localization/app.json index 44ff04de4..7ac3252f2 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -348,7 +348,7 @@ "logo_label": "Logo Button", "logo_hint": "Tap to scroll to top and tap again to previous location" } - }, + } }, "suggestion_account": { "title": "Find People to Follow", From 92f6b67a63c30178e67a047e6d3728c2c80eacc1 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 11 May 2022 16:34:11 +0800 Subject: [PATCH 084/101] feat: add report i18n words --- Localization/app.json | 4 +++- .../mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Localization/app.json b/Localization/app.json index 7ac3252f2..8de2dc0b3 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -635,10 +635,12 @@ "step_final": { "dont_want_to_see_this": "Don’t want to see this?", "when_you_see_something_you_dont_like_on_mastodon_you_can_remove_the_person_from_your_experience.": "When you see something you don’t like on Mastodon, you can remove the person from your experience.", + "unfollow": "Unfollow", + "unfollowed": "Unfollowed", "unfollow_user": "Unfollow %s", "mute_user": "Mute %s", "you_wont_see_their_posts_or_reblogs_in_your_home_feed_they_wont_know_they_ve_been_muted": "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted.", - "Block_domain": "Block %s", + "block_user": "Block %s", "they_will_no_longer_be_able_to_follow_or_see_your_posts_but_they_can_see_if_theyve_been_blocked": "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked." } }, diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 66a7b7bd6..8e16cec2d 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -114,7 +114,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 22 + 20 MastodonIntents.xcscheme_^#shared#^_ @@ -129,12 +129,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 20 + 21 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 21 + 22 SuppressBuildableAutocreation From c98cb5824f206a50d7bf89888733c596184f1cfd Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 11 May 2022 16:27:32 +0800 Subject: [PATCH 085/101] fix: i18n template (cherry picked from commit 741e8d998d0f6b0e0c7443ec8c4ea6482f34e622) --- Localization/app.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Localization/app.json b/Localization/app.json index 44ff04de4..7ac3252f2 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -348,7 +348,7 @@ "logo_label": "Logo Button", "logo_hint": "Tap to scroll to top and tap again to previous location" } - }, + } }, "suggestion_account": { "title": "Find People to Follow", From 35d572660b13361c1222e9f9dfd9bff6761f8e81 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 11 May 2022 16:34:11 +0800 Subject: [PATCH 086/101] feat: add report i18n words (cherry picked from commit 92f6b67a63c30178e67a047e6d3728c2c80eacc1) --- Localization/app.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Localization/app.json b/Localization/app.json index 7ac3252f2..8de2dc0b3 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -635,10 +635,12 @@ "step_final": { "dont_want_to_see_this": "Don’t want to see this?", "when_you_see_something_you_dont_like_on_mastodon_you_can_remove_the_person_from_your_experience.": "When you see something you don’t like on Mastodon, you can remove the person from your experience.", + "unfollow": "Unfollow", + "unfollowed": "Unfollowed", "unfollow_user": "Unfollow %s", "mute_user": "Mute %s", "you_wont_see_their_posts_or_reblogs_in_your_home_feed_they_wont_know_they_ve_been_muted": "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted.", - "Block_domain": "Block %s", + "block_user": "Block %s", "they_will_no_longer_be_able_to_follow_or_see_your_posts_but_they_can_see_if_theyve_been_blocked": "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked." } }, From 945241e730fef8967eb98ad664a1b3417b5eb057 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 11 May 2022 18:39:34 +0800 Subject: [PATCH 087/101] fix: NewsView image layout not fixed issue --- Mastodon.xcodeproj/project.pbxproj | 12 ------- .../Content/MediaView+Configuration.swift | 28 +-------------- Mastodon/State/AppContext.swift | 3 +- .../Service/BlurhashImageCacheService.swift | 3 ++ .../MastodonUI/Vendor}/BlurHashDecode.swift | 0 .../MastodonUI/Vendor}/BlurHashEncode.swift | 0 .../Content/MediaView+Configuration.swift | 35 +++++++++++++++++++ .../View/Content/NewsView+Configuration.swift | 1 + .../MastodonUI/View/Content/NewsView.swift | 16 +++++++++ 9 files changed, 58 insertions(+), 40 deletions(-) rename {Mastodon => MastodonSDK/Sources/MastodonUI}/Service/BlurhashImageCacheService.swift (96%) rename {Mastodon/Vender => MastodonSDK/Sources/MastodonUI/Vendor}/BlurHashDecode.swift (100%) rename {Mastodon/Vender => MastodonSDK/Sources/MastodonUI/Vendor}/BlurHashEncode.swift (100%) diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index d5f5cbd79..1a185f86c 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -286,8 +286,6 @@ DB4F097F26A03DA600D62E92 /* SearchHistoryFetchedResultController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB4F097E26A03DA600D62E92 /* SearchHistoryFetchedResultController.swift */; }; DB4FFC2B269EC39600D62E92 /* SearchToSearchDetailViewControllerAnimatedTransitioning.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB4FFC29269EC39600D62E92 /* SearchToSearchDetailViewControllerAnimatedTransitioning.swift */; }; DB4FFC2C269EC39600D62E92 /* SearchTransitionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB4FFC2A269EC39600D62E92 /* SearchTransitionController.swift */; }; - DB51D172262832380062B7A1 /* BlurHashDecode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB51D170262832380062B7A1 /* BlurHashDecode.swift */; }; - DB51D173262832380062B7A1 /* BlurHashEncode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB51D171262832380062B7A1 /* BlurHashEncode.swift */; }; DB552D4F26BBD10C00E481F6 /* OrderedCollections in Frameworks */ = {isa = PBXBuildFile; productRef = DB552D4E26BBD10C00E481F6 /* OrderedCollections */; }; DB564BD3269F3B35001E39A7 /* StatusFilterService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB564BD2269F3B35001E39A7 /* StatusFilterService.swift */; }; DB59F10E25EF724F001F1DAB /* APIService+Poll.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB59F10D25EF724F001F1DAB /* APIService+Poll.swift */; }; @@ -415,7 +413,6 @@ DB852D1F26FB037800FC9D81 /* SidebarViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB852D1E26FB037800FC9D81 /* SidebarViewModel.swift */; }; DB87D4452609BE0500D12C0D /* ComposeStatusPollOptionCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB87D4442609BE0500D12C0D /* ComposeStatusPollOptionCollectionViewCell.swift */; }; DB87D4512609CF1E00D12C0D /* ComposeStatusPollOptionAppendEntryCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB87D4502609CF1E00D12C0D /* ComposeStatusPollOptionAppendEntryCollectionViewCell.swift */; }; - DB894CC427A5490600684B74 /* BlurhashImageCacheService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB894CC327A5490600684B74 /* BlurhashImageCacheService.swift */; }; DB8AF52E25C13561002E6C99 /* ViewStateStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB8AF52B25C13561002E6C99 /* ViewStateStore.swift */; }; DB8AF52F25C13561002E6C99 /* DocumentStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB8AF52C25C13561002E6C99 /* DocumentStore.swift */; }; DB8AF53025C13561002E6C99 /* AppContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB8AF52D25C13561002E6C99 /* AppContext.swift */; }; @@ -1041,8 +1038,6 @@ DB519B15281BCC2F00F0C99D /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Intents.strings; sourceTree = ""; }; DB519B16281BCC2F00F0C99D /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/InfoPlist.strings; sourceTree = ""; }; DB519B17281BCC2F00F0C99D /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = tr; path = tr.lproj/Intents.stringsdict; sourceTree = ""; }; - DB51D170262832380062B7A1 /* BlurHashDecode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlurHashDecode.swift; sourceTree = ""; }; - DB51D171262832380062B7A1 /* BlurHashEncode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlurHashEncode.swift; sourceTree = ""; }; DB564BD2269F3B35001E39A7 /* StatusFilterService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusFilterService.swift; sourceTree = ""; }; DB59F10D25EF724F001F1DAB /* APIService+Poll.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Poll.swift"; sourceTree = ""; }; DB5B7294273112B100081888 /* FollowingListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowingListViewController.swift; sourceTree = ""; }; @@ -1167,7 +1162,6 @@ DB852D1E26FB037800FC9D81 /* SidebarViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarViewModel.swift; sourceTree = ""; }; DB87D4442609BE0500D12C0D /* ComposeStatusPollOptionCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusPollOptionCollectionViewCell.swift; sourceTree = ""; }; DB87D4502609CF1E00D12C0D /* ComposeStatusPollOptionAppendEntryCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusPollOptionAppendEntryCollectionViewCell.swift; sourceTree = ""; }; - DB894CC327A5490600684B74 /* BlurhashImageCacheService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurhashImageCacheService.swift; sourceTree = ""; }; DB89BA1025C10FF5008580ED /* Mastodon.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Mastodon.entitlements; sourceTree = ""; }; DB8AF52B25C13561002E6C99 /* ViewStateStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewStateStore.swift; sourceTree = ""; }; DB8AF52C25C13561002E6C99 /* DocumentStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DocumentStore.swift; sourceTree = ""; }; @@ -1665,8 +1659,6 @@ isa = PBXGroup; children = ( 2D5A3D0225CF8742002347D6 /* ControlContainableScrollViews.swift */, - DB51D170262832380062B7A1 /* BlurHashDecode.swift */, - DB51D171262832380062B7A1 /* BlurHashEncode.swift */, DB6180EC26391C6C0018D199 /* TransitioningMath.swift */, DB75BF1D263C1C1B00EDBF1F /* CustomScheduler.swift */, DBF156E32702DB3F00EC00B7 /* HandleTapAction.swift */, @@ -1692,7 +1684,6 @@ DB297B1A2679FAE200704C90 /* PlaceholderImageCacheService.swift */, DB564BD2269F3B35001E39A7 /* StatusFilterService.swift */, DB73BF42271192BB00781945 /* InstanceService.swift */, - DB894CC327A5490600684B74 /* BlurhashImageCacheService.swift */, ); path = Service; sourceTree = ""; @@ -4203,7 +4194,6 @@ 2D5A3D0325CF8742002347D6 /* ControlContainableScrollViews.swift in Sources */, DB36679D268AB91B0027D07F /* ComposeStatusAttachmentTableViewCell.swift in Sources */, DB98336B25C9420100AD9700 /* APIService+App.swift in Sources */, - DB894CC427A5490600684B74 /* BlurhashImageCacheService.swift in Sources */, DBFEF07B26A6BCE8006D7ED1 /* APIService+Status+Publish.swift in Sources */, DBA0A11325FB3FC10079C110 /* ComposeToolbarView.swift in Sources */, 5B90C48526259BF10002E742 /* APIService+Subscriptions.swift in Sources */, @@ -4254,7 +4244,6 @@ DB3E6FE42806A5B800B035AE /* DiscoverySection.swift in Sources */, DB8190C62601FF0400020C08 /* AttachmentContainerView.swift in Sources */, DB697DDB278F4DE3004EF2F7 /* DataSourceProvider+StatusTableViewCellDelegate.swift in Sources */, - DB51D173262832380062B7A1 /* BlurHashEncode.swift in Sources */, 2D32EAAC25CB96DC00C9ED86 /* TimelineMiddleLoaderTableViewCell.swift in Sources */, DB87D4512609CF1E00D12C0D /* ComposeStatusPollOptionAppendEntryCollectionViewCell.swift in Sources */, DBB45B5627B39FC9002DC5A7 /* MediaPreviewVideoViewController.swift in Sources */, @@ -4312,7 +4301,6 @@ DB6180ED26391C6C0018D199 /* TransitioningMath.swift in Sources */, DB63F771279A858500455B82 /* Persistence+Notification.swift in Sources */, 2D6DE40026141DF600A63F6A /* SearchViewModel.swift in Sources */, - DB51D172262832380062B7A1 /* BlurHashDecode.swift in Sources */, DBCCC71E25F73297007E1AB6 /* APIService+Reblog.swift in Sources */, DB0617FD27855BFE0030EE79 /* ServerRuleItem.swift in Sources */, 5BB04FD5262E7AFF0043BFF6 /* ReportViewController.swift in Sources */, diff --git a/Mastodon/Scene/Share/View/Content/MediaView+Configuration.swift b/Mastodon/Scene/Share/View/Content/MediaView+Configuration.swift index 02f9ad5a4..b782f8e8a 100644 --- a/Mastodon/Scene/Share/View/Content/MediaView+Configuration.swift +++ b/Mastodon/Scene/Share/View/Content/MediaView+Configuration.swift @@ -57,33 +57,7 @@ extension MediaView { } // end switch }() - if let previewURL = configuration.previewURL, - let url = URL(string: previewURL) - { - let placeholder = UIImage.placeholder(color: .systemGray6) - let request = URLRequest(url: url) - ImageDownloader.default.download(request, completion: { response in - switch response.result { - case .success(let image): - configuration.previewImage = image - case .failure: - configuration.previewImage = placeholder - } - }) - } - - if let assetURL = configuration.assetURL, - let blurhash = configuration.blurhash - { - AppContext.shared.blurhashImageCacheService.image( - blurhash: blurhash, - size: configuration.aspectRadio, - url: assetURL - ) - .assign(to: \.blurhashImage, on: configuration) - .store(in: &configuration.blurhashImageDisposeBag) - } - + configuration.load() configuration.isReveal = status.isMediaSensitive ? status.isSensitiveToggled : true return configuration diff --git a/Mastodon/State/AppContext.swift b/Mastodon/State/AppContext.swift index 9de19c44f..683c81f33 100644 --- a/Mastodon/State/AppContext.swift +++ b/Mastodon/State/AppContext.swift @@ -11,6 +11,7 @@ import Combine import CoreData import CoreDataStack import AlamofireImage +import MastodonUI class AppContext: ObservableObject { @@ -35,7 +36,7 @@ class AppContext: ObservableObject { let photoLibraryService = PhotoLibraryService() let placeholderImageCacheService = PlaceholderImageCacheService() - let blurhashImageCacheService = BlurhashImageCacheService() + let blurhashImageCacheService = BlurhashImageCacheService.shared let documentStore: DocumentStore private var documentStoreSubscription: AnyCancellable! diff --git a/Mastodon/Service/BlurhashImageCacheService.swift b/MastodonSDK/Sources/MastodonUI/Service/BlurhashImageCacheService.swift similarity index 96% rename from Mastodon/Service/BlurhashImageCacheService.swift rename to MastodonSDK/Sources/MastodonUI/Service/BlurhashImageCacheService.swift index b15a9750b..cc9459b4e 100644 --- a/Mastodon/Service/BlurhashImageCacheService.swift +++ b/MastodonSDK/Sources/MastodonUI/Service/BlurhashImageCacheService.swift @@ -10,6 +10,9 @@ import Combine public final class BlurhashImageCacheService { + // MARK: - Singleton + public static let shared = BlurhashImageCacheService() + static let edgeMaxLength: CGFloat = 20 let cache = NSCache() diff --git a/Mastodon/Vender/BlurHashDecode.swift b/MastodonSDK/Sources/MastodonUI/Vendor/BlurHashDecode.swift similarity index 100% rename from Mastodon/Vender/BlurHashDecode.swift rename to MastodonSDK/Sources/MastodonUI/Vendor/BlurHashDecode.swift diff --git a/Mastodon/Vender/BlurHashEncode.swift b/MastodonSDK/Sources/MastodonUI/Vendor/BlurHashEncode.swift similarity index 100% rename from Mastodon/Vender/BlurHashEncode.swift rename to MastodonSDK/Sources/MastodonUI/Vendor/BlurHashEncode.swift diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/MediaView+Configuration.swift b/MastodonSDK/Sources/MastodonUI/View/Content/MediaView+Configuration.swift index 6026e668f..cfe9e73ce 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/MediaView+Configuration.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/MediaView+Configuration.swift @@ -10,6 +10,7 @@ import UIKit import Combine import CoreData import Photos +import AlamofireImage extension MediaView { public class Configuration: Hashable { @@ -142,3 +143,37 @@ extension MediaView.Configuration { } } + +extension MediaView.Configuration { + + public func load() { + if let previewURL = previewURL, + let url = URL(string: previewURL) + { + let placeholder = UIImage.placeholder(color: .systemGray6) + let request = URLRequest(url: url) + ImageDownloader.default.download(request, completion: { [weak self] response in + guard let self = self else { return } + switch response.result { + case .success(let image): + self.previewImage = image + case .failure: + self.previewImage = placeholder + } + }) + } + + if let assetURL = assetURL, + let blurhash = blurhash + { + BlurhashImageCacheService.shared.image( + blurhash: blurhash, + size: aspectRadio, + url: assetURL + ) + .assign(to: \.blurhashImage, on: self) + .store(in: &blurhashImageDisposeBag) + } + } + +} diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift b/MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift index 397982aaf..7f44232aa 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/NewsView+Configuration.swift @@ -6,6 +6,7 @@ // import UIKit +import Combine import MastodonSDK import MastodonLocalization import AlamofireImage diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/NewsView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/NewsView.swift index 6d4cf3fd7..0d4298035 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/NewsView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/NewsView.swift @@ -6,9 +6,14 @@ // import UIKit +import Combine import MastodonAsset public final class NewsView: UIView { + + static let imageViewWidth: CGFloat = 132 + + var disposeBag = Set() let container = UIStackView() @@ -44,10 +49,14 @@ public final class NewsView: UIView { }() let imageView = MediaView() + +// let imageView = UIImageView() +// var imageViewMediaConfiguration: MediaView.Configuration? public func prepareForReuse() { providerFaviconImageView.tag = (0.. Date: Wed, 11 May 2022 18:40:21 +0800 Subject: [PATCH 088/101] feat: add keyboard commands for discovery posts, tag. And also restore for hashtag timeline and profile scene --- Mastodon.xcodeproj/project.pbxproj | 4 + .../xcschemes/xcschememanagement.plist | 13 +- Mastodon/Protocol/PageboyNavigateable.swift | 92 +++++++++++++++ ...tatusTableViewControllerNavigateable.swift | 2 +- .../DiscoveryCommunityViewController.swift | 17 +++ .../Discovery/DiscoveryViewController.swift | 29 +++++ .../DiscoveryHashtagsViewController.swift | 95 +++++++++++++++ .../Posts/DiscoveryPostsViewController.swift | 17 +++ .../HashtagTimelineViewController.swift | 111 +++--------------- .../Scene/Profile/ProfileViewController.swift | 48 ++++---- .../Root/ContentSplitViewController.swift | 10 ++ 11 files changed, 315 insertions(+), 123 deletions(-) create mode 100644 Mastodon/Protocol/PageboyNavigateable.swift diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 1a185f86c..711334cf7 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -529,6 +529,7 @@ DBC6462826A1736300B0E31B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DB427DDE25BAA00100D1B89D /* Assets.xcassets */; }; DBC7A672260C897100E57475 /* StatusContentWarningEditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC7A671260C897100E57475 /* StatusContentWarningEditorView.swift */; }; DBC7A67C260DFADE00E57475 /* StatusPublishService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBC7A67B260DFADE00E57475 /* StatusPublishService.swift */; }; + DBCA0EBC282BB38A0029E2B0 /* PageboyNavigateable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBCA0EBB282BB38A0029E2B0 /* PageboyNavigateable.swift */; }; DBCBCBF4267CB070000F5B51 /* Decode85.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBCBCBF3267CB070000F5B51 /* Decode85.swift */; }; DBCBCC0D2680B908000F5B51 /* HomeTimelinePreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBCBCC0C2680B908000F5B51 /* HomeTimelinePreference.swift */; }; DBCBED1726132DB500B49291 /* UserTimelineViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBCBED1626132DB500B49291 /* UserTimelineViewModel+Diffable.swift */; }; @@ -1290,6 +1291,7 @@ DBC6462226A1712000B0E31B /* ShareViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShareViewModel.swift; sourceTree = ""; }; DBC7A671260C897100E57475 /* StatusContentWarningEditorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusContentWarningEditorView.swift; sourceTree = ""; }; DBC7A67B260DFADE00E57475 /* StatusPublishService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusPublishService.swift; sourceTree = ""; }; + DBCA0EBB282BB38A0029E2B0 /* PageboyNavigateable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageboyNavigateable.swift; sourceTree = ""; }; DBCBCBF3267CB070000F5B51 /* Decode85.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Decode85.swift; sourceTree = ""; }; DBCBCC0C2680B908000F5B51 /* HomeTimelinePreference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeTimelinePreference.swift; sourceTree = ""; }; DBCBED1626132DB500B49291 /* UserTimelineViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserTimelineViewModel+Diffable.swift"; sourceTree = ""; }; @@ -1697,6 +1699,7 @@ DB4AA6B227BA34B6009EC082 /* CellFrameCacheContainer.swift */, 2D38F20725CD491300561493 /* DisposeBagCollectable.swift */, DB1D84372657B275000346B3 /* SegmentedControlNavigateable.swift */, + DBCA0EBB282BB38A0029E2B0 /* PageboyNavigateable.swift */, DB1D843326579931000346B3 /* TableViewControllerNavigateable.swift */, DB1D842D26552C4D000346B3 /* StatusTableViewControllerNavigateable.swift */, ); @@ -4082,6 +4085,7 @@ DB1D186C25EF5BA7003F1F23 /* PollTableView.swift in Sources */, DBA94434265CBB5300C537E1 /* ProfileFieldSection.swift in Sources */, DB336F28278D6EC70031E64B /* MastodonFieldContainer.swift in Sources */, + DBCA0EBC282BB38A0029E2B0 /* PageboyNavigateable.swift in Sources */, DBF156E42702DB3F00EC00B7 /* HandleTapAction.swift in Sources */, DB98EB4727B0DFAA0082E365 /* ReportViewModel+State.swift in Sources */, 2D5981A125E4A593000FB903 /* MastodonConfirmEmailViewModel.swift in Sources */, diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 07a847a0c..bc5c3a934 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -16,10 +16,15 @@ orderHint 27 + Mastodon - Profile.xcscheme_^#shared#^_ + + orderHint + 19 + Mastodon - RTL.xcscheme_^#shared#^_ orderHint - 6 + 5 Mastodon - Release.xcscheme_^#shared#^_ @@ -109,7 +114,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 28 + 21 MastodonIntents.xcscheme_^#shared#^_ @@ -124,12 +129,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 27 + 20 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 26 + 22 SuppressBuildableAutocreation diff --git a/Mastodon/Protocol/PageboyNavigateable.swift b/Mastodon/Protocol/PageboyNavigateable.swift new file mode 100644 index 000000000..8ff59ef4f --- /dev/null +++ b/Mastodon/Protocol/PageboyNavigateable.swift @@ -0,0 +1,92 @@ +// +// PageboyNavigateable.swift +// Mastodon +// +// Created by MainasuK on 2022-5-11. +// + +import UIKit +import Pageboy +import MastodonLocalization + +typealias PageboyNavigateable = PageboyNavigateableCore & PageboyNavigateableRelay + +protocol PageboyNavigateableCore: AnyObject { + var navigateablePageViewController: PageboyViewController { get } + var pageboyNavigateKeyCommands: [UIKeyCommand] { get } + + func pageboyNavigateKeyCommandHandler(_ sender: UIKeyCommand) + func navigate(direction: PageboyNavigationDirection) +} + +@objc protocol PageboyNavigateableRelay: AnyObject { + func pageboyNavigateKeyCommandHandlerRelay(_ sender: UIKeyCommand) +} + +enum PageboyNavigationDirection: String, CaseIterable { + case previous + case next + + var title: String { + switch self { + case .previous: return L10n.Common.Controls.Keyboard.SegmentedControl.previousSection + case .next: return L10n.Common.Controls.Keyboard.SegmentedControl.nextSection + } + } + + // UIKeyCommand input + var input: String { + switch self { + case .previous: return "[" + case .next: return "]" + } + } + + var modifierFlags: UIKeyModifierFlags { + switch self { + case .previous: return [.shift, .command] + case .next: return [.shift, .command] + } + } + + var propertyList: Any { + return rawValue + } +} + +extension PageboyNavigateableCore where Self: PageboyNavigateableRelay { + var pageboyNavigateKeyCommands: [UIKeyCommand] { + PageboyNavigationDirection.allCases.map { direction in + UIKeyCommand( + title: direction.title, + image: nil, + action: #selector(Self.pageboyNavigateKeyCommandHandlerRelay(_:)), + input: direction.input, + modifierFlags: direction.modifierFlags, + propertyList: direction.propertyList, + alternates: [], + discoverabilityTitle: nil, + attributes: [], + state: .off + ) + } + } + + func pageboyNavigateKeyCommandHandler(_ sender: UIKeyCommand) { + guard let rawValue = sender.propertyList as? String, + let direction = PageboyNavigationDirection(rawValue: rawValue) else { return } + navigate(direction: direction) + } + +} + +extension PageboyNavigateableCore { + func navigate(direction: PageboyNavigationDirection) { + switch direction { + case .previous: + navigateablePageViewController.scrollToPage(.previous, animated: true) + case .next: + navigateablePageViewController.scrollToPage(.next, animated: true) + } + } +} diff --git a/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewControllerNavigateable.swift b/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewControllerNavigateable.swift index fb4a7d843..ce4e03cdb 100644 --- a/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewControllerNavigateable.swift +++ b/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewControllerNavigateable.swift @@ -115,7 +115,7 @@ extension StatusTableViewControllerNavigateableCore where Self: DataSourceProvid guard let provider = self as? (DataSourceProvider & MediaPreviewableViewController) else { return } guard let indexPathForSelectedRow = tableView.indexPathForSelectedRow, - let cell = tableView.cellForRow(at: indexPathForSelectedRow) as? StatusTableViewCell + let cell = tableView.cellForRow(at: indexPathForSelectedRow) as? StatusViewContainerTableViewCell else { return } guard let mediaView = cell.statusView.mediaGridContainerView.mediaViews.first else { return } diff --git a/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewController.swift b/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewController.swift index eabed7a0e..4cc32c250 100644 --- a/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewController.swift +++ b/Mastodon/Scene/Discovery/Community/DiscoveryCommunityViewController.swift @@ -152,3 +152,20 @@ extension DiscoveryCommunityViewController: ScrollViewContainer { tableView } } + +extension DiscoveryCommunityViewController { + override var keyCommands: [UIKeyCommand]? { + return navigationKeyCommands + statusNavigationKeyCommands + } +} + +// MARK: - StatusTableViewControllerNavigateable +extension DiscoveryCommunityViewController: StatusTableViewControllerNavigateable { + @objc func navigateKeyCommandHandlerRelay(_ sender: UIKeyCommand) { + navigateKeyCommandHandler(sender) + } + + @objc func statusKeyCommandHandlerRelay(_ sender: UIKeyCommand) { + statusKeyCommandHandler(sender) + } +} diff --git a/Mastodon/Scene/Discovery/DiscoveryViewController.swift b/Mastodon/Scene/Discovery/DiscoveryViewController.swift index 8e3aab647..1803f687a 100644 --- a/Mastodon/Scene/Discovery/DiscoveryViewController.swift +++ b/Mastodon/Scene/Discovery/DiscoveryViewController.swift @@ -9,6 +9,7 @@ import os.log import UIKit import Combine import Tabman +import Pageboy import MastodonAsset import MastodonUI @@ -126,3 +127,31 @@ extension DiscoveryViewController { } } + +// MARK: - ScrollViewContainer +extension DiscoveryViewController: ScrollViewContainer { + var scrollView: UIScrollView? { + return (currentViewController as? ScrollViewContainer)?.scrollView + } +} + +extension DiscoveryViewController { + + public override var keyCommands: [UIKeyCommand]? { + return pageboyNavigateKeyCommands + } + +} + +// MARK: - PageboyNavigateable +extension DiscoveryViewController: PageboyNavigateable { + + var navigateablePageViewController: PageboyViewController { + return self + } + + @objc func pageboyNavigateKeyCommandHandlerRelay(_ sender: UIKeyCommand) { + pageboyNavigateKeyCommandHandler(sender) + } + +} diff --git a/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift index 91ab5036c..f82a8f9bf 100644 --- a/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift +++ b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift @@ -131,3 +131,98 @@ extension DiscoveryHashtagsViewController: ScrollViewContainer { tableView } } + +extension DiscoveryHashtagsViewController { + override var keyCommands: [UIKeyCommand]? { + return navigationKeyCommands + } +} + +// MARK: - TableViewControllerNavigateable +extension DiscoveryHashtagsViewController: TableViewControllerNavigateable { + @objc func navigateKeyCommandHandlerRelay(_ sender: UIKeyCommand) { + navigateKeyCommandHandler(sender) + } + + func navigate(direction: TableViewNavigationDirection) { + if let indexPathForSelectedRow = tableView.indexPathForSelectedRow { + // navigate up/down on the current selected item + navigateToTag(direction: direction, indexPath: indexPathForSelectedRow) + } else { + // set first visible item selected + navigateToFirstVisibleStatus() + } + } + + private func navigateToTag(direction: TableViewNavigationDirection, indexPath: IndexPath) { + guard let diffableDataSource = viewModel.diffableDataSource else { return } + let items = diffableDataSource.snapshot().itemIdentifiers + guard let selectedItem = diffableDataSource.itemIdentifier(for: indexPath), + let selectedItemIndex = items.firstIndex(of: selectedItem) else { + return + } + + let _navigateToItem: DiscoveryItem? = { + var index = selectedItemIndex + while 0.. 1 { + // drop first when visible not the first cell of table + visibleItems.removeFirst() + } + guard let item = visibleItems.first, let indexPath = diffableDataSource.indexPath(for: item) else { return } + let scrollPosition: UITableView.ScrollPosition = overrideNavigationScrollPosition ?? Self.navigateScrollPosition(tableView: tableView, indexPath: indexPath) + tableView.selectRow(at: indexPath, animated: true, scrollPosition: scrollPosition) + } + + static func validNavigateableItem(_ item: DiscoveryItem) -> Bool { + switch item { + case .hashtag: + return true + default: + return false + } + } + + func open() { + guard let indexPathForSelectedRow = tableView.indexPathForSelectedRow else { return } + guard let diffableDataSource = viewModel.diffableDataSource else { return } + guard let item = diffableDataSource.itemIdentifier(for: indexPathForSelectedRow) else { return } + + guard case let .hashtag(tag) = item else { return } + let hashtagTimelineViewModel = HashtagTimelineViewModel(context: context, hashtag: tag.name) + coordinator.present( + scene: .hashtagTimeline(viewModel: hashtagTimelineViewModel), + from: self, + transition: .show + ) + } +} diff --git a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift index 259b21d36..a1d5b5e76 100644 --- a/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift +++ b/Mastodon/Scene/Discovery/Posts/DiscoveryPostsViewController.swift @@ -171,3 +171,20 @@ extension DiscoveryPostsViewController: DiscoveryIntroBannerViewDelegate { UserDefaults.shared.discoveryIntroBannerNeedsHidden = true } } + +extension DiscoveryPostsViewController { + override var keyCommands: [UIKeyCommand]? { + return navigationKeyCommands + statusNavigationKeyCommands + } +} + +// MARK: - StatusTableViewControllerNavigateable +extension DiscoveryPostsViewController: StatusTableViewControllerNavigateable { + @objc func navigateKeyCommandHandlerRelay(_ sender: UIKeyCommand) { + navigateKeyCommandHandler(sender) + } + + @objc func statusKeyCommandHandlerRelay(_ sender: UIKeyCommand) { + statusKeyCommandHandler(sender) + } +} diff --git a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift index 3b8db5d56..31de401d2 100644 --- a/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift +++ b/Mastodon/Scene/HashtagTimeline/HashtagTimelineViewController.swift @@ -84,7 +84,6 @@ extension HashtagTimelineViewController { ]) tableView.delegate = self -// tableView.prefetchDataSource = self viewModel.setupDiffableDataSource( tableView: tableView, statusTableViewCellDelegate: self @@ -158,27 +157,6 @@ extension HashtagTimelineViewController { } -// MARK: - TableViewCellHeightCacheableContainer -//extension HashtagTimelineViewController: TableViewCellHeightCacheableContainer { -// var cellFrameCache: NSCache { -// return viewModel.cellFrameCache -// } -//} - -//// MARK: - UIScrollViewDelegate -//extension HashtagTimelineViewController { -// func scrollViewDidScroll(_ scrollView: UIScrollView) { -// aspectScrollViewDidScroll(scrollView) -// } -//} - -//extension HashtagTimelineViewController: LoadMoreConfigurableTableViewContainer { -// typealias BottomLoaderTableViewCell = TimelineBottomLoaderTableViewCell -// typealias LoadingState = HashtagTimelineViewModel.LoadOldestState.Loading -// var loadMoreConfigurableTableView: UITableView { return tableView } -// var loadMoreConfigurableStateMachine: GKStateMachine { return viewModel.loadOldestStateMachine } -//} - // MARK: - UITableViewDelegate extension HashtagTimelineViewController: UITableViewDelegate, AutoGenerateTableViewDelegate { // sourcery:inline:HashtagTimelineViewController.AutoGenerateTableViewDelegate @@ -206,82 +184,23 @@ extension HashtagTimelineViewController: UITableViewDelegate, AutoGenerateTableV } // sourcery:end -// func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { -// return aspectTableView(tableView, estimatedHeightForRowAt: indexPath) -// } -// -// func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { -// aspectTableView(tableView, willDisplay: cell, forRowAt: indexPath) -// } -// -// func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) { -// aspectTableView(tableView, didEndDisplaying: cell, forRowAt: indexPath) -// } -// -// func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { -// aspectTableView(tableView, didSelectRowAt: indexPath) -// } -// -// func tableView(_ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? { -// return aspectTableView(tableView, contextMenuConfigurationForRowAt: indexPath, point: point) -// } -// -// func tableView(_ tableView: UITableView, previewForHighlightingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? { -// return aspectTableView(tableView, previewForHighlightingContextMenuWithConfiguration: configuration) -// } -// -// func tableView(_ tableView: UITableView, previewForDismissingContextMenuWithConfiguration configuration: UIContextMenuConfiguration) -> UITargetedPreview? { -// return aspectTableView(tableView, previewForDismissingContextMenuWithConfiguration: configuration) -// } -// -// func tableView(_ tableView: UITableView, willPerformPreviewActionForMenuWith configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionCommitAnimating) { -// aspectTableView(tableView, willPerformPreviewActionForMenuWith: configuration, animator: animator) -// } - } -// MARK: - UITableViewDataSourcePrefetching -//extension HashtagTimelineViewController: UITableViewDataSourcePrefetching { -// func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) { -// aspectTableView(tableView, prefetchRowsAt: indexPaths) -// } -//} - // MARK: - StatusTableViewCellDelegate extension HashtagTimelineViewController: StatusTableViewCellDelegate { } -// MARK: - AVPlayerViewControllerDelegate -//extension HashtagTimelineViewController: AVPlayerViewControllerDelegate { -// -// func playerViewController(_ playerViewController: AVPlayerViewController, willBeginFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) { -// aspectPlayerViewController(playerViewController, willBeginFullScreenPresentationWithAnimationCoordinator: coordinator) -// } -// -// func playerViewController(_ playerViewController: AVPlayerViewController, willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) { -// aspectPlayerViewController(playerViewController, willEndFullScreenPresentationWithAnimationCoordinator: coordinator) -// } -// -//} - -// MARK: - StatusTableViewCellDelegate -//extension HashtagTimelineViewController: StatusTableViewCellDelegate { -// weak var playerViewControllerDelegate: AVPlayerViewControllerDelegate? { return self } -// func parent() -> UIViewController { return self } -//} - -//extension HashtagTimelineViewController { -// override var keyCommands: [UIKeyCommand]? { -// return navigationKeyCommands + statusNavigationKeyCommands -// } -//} -// -//// MARK: - StatusTableViewControllerNavigateable -//extension HashtagTimelineViewController: StatusTableViewControllerNavigateable { -// @objc func navigateKeyCommandHandlerRelay(_ sender: UIKeyCommand) { -// navigateKeyCommandHandler(sender) -// } -// -// @objc func statusKeyCommandHandlerRelay(_ sender: UIKeyCommand) { -// statusKeyCommandHandler(sender) -// } -//} +extension HashtagTimelineViewController { + override var keyCommands: [UIKeyCommand]? { + return navigationKeyCommands + statusNavigationKeyCommands + } +} +// MARK: - StatusTableViewControllerNavigateable +extension HashtagTimelineViewController: StatusTableViewControllerNavigateable { + @objc func navigateKeyCommandHandlerRelay(_ sender: UIKeyCommand) { + navigateKeyCommandHandler(sender) + } + + @objc func statusKeyCommandHandlerRelay(_ sender: UIKeyCommand) { + statusKeyCommandHandler(sender) + } +} diff --git a/Mastodon/Scene/Profile/ProfileViewController.swift b/Mastodon/Scene/Profile/ProfileViewController.swift index b376ebcf9..4c3f9820a 100644 --- a/Mastodon/Scene/Profile/ProfileViewController.swift +++ b/Mastodon/Scene/Profile/ProfileViewController.swift @@ -13,8 +13,9 @@ import MetaTextKit import MastodonAsset import MastodonLocalization import MastodonUI -import Tabman import CoreDataStack +import Tabman +import Pageboy protocol ProfileViewModelEditable { func isEdited() -> Bool @@ -1155,25 +1156,28 @@ extension ProfileViewController: ScrollViewContainer { } } -//extension ProfileViewController { -// -// override var keyCommands: [UIKeyCommand]? { -// if !viewModel.isEditing.value { -// return segmentedControlNavigateKeyCommands -// } -// -// return nil -// } -// -//} +extension ProfileViewController { + + override var keyCommands: [UIKeyCommand]? { + if !viewModel.isEditing.value { + return pageboyNavigateKeyCommands + } + + return nil + } + +} + +// MARK: - PageboyNavigateable +extension ProfileViewController: PageboyNavigateable { + + var navigateablePageViewController: PageboyViewController { + return profileSegmentedViewController.pagingViewController + } + + @objc func pageboyNavigateKeyCommandHandlerRelay(_ sender: UIKeyCommand) { + pageboyNavigateKeyCommandHandler(sender) + } + +} -// MARK: - SegmentedControlNavigateable -//extension ProfileViewController: SegmentedControlNavigateable { -// var navigateableSegmentedControl: UISegmentedControl { -// profileHeaderViewController.pageSegmentedControl -// } -// -// @objc func segmentedControlNavigateKeyCommandHandlerRelay(_ sender: UIKeyCommand) { -// segmentedControlNavigateKeyCommandHandler(sender) -// } -//} diff --git a/Mastodon/Scene/Root/ContentSplitViewController.swift b/Mastodon/Scene/Root/ContentSplitViewController.swift index 03e203107..0058f5f6e 100644 --- a/Mastodon/Scene/Root/ContentSplitViewController.swift +++ b/Mastodon/Scene/Root/ContentSplitViewController.swift @@ -77,6 +77,16 @@ extension ContentSplitViewController { mainTabBarController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor), ]) + // response keyboard command tab switch + mainTabBarController.$currentTab + .sink { [weak self] tab in + guard let self = self else { return } + if tab != self.currentSupplementaryTab { + self.currentSupplementaryTab = tab + } + } + .store(in: &disposeBag) + $currentSupplementaryTab .removeDuplicates() .sink(receiveValue: { [weak self] tab in From a957c8bb732e6dd33d112ec50bdf195f0350c0ac Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 11 May 2022 18:44:17 +0800 Subject: [PATCH 089/101] feat: add keyboard commands for discovery news table --- .../DiscoveryHashtagsViewController.swift | 4 +- .../News/DiscoveryNewsViewController.swift | 96 +++++++++++++++++++ 2 files changed, 98 insertions(+), 2 deletions(-) diff --git a/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift index f82a8f9bf..6e6d96924 100644 --- a/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift +++ b/Mastodon/Scene/Discovery/Hashtags/DiscoveryHashtagsViewController.swift @@ -150,7 +150,7 @@ extension DiscoveryHashtagsViewController: TableViewControllerNavigateable { navigateToTag(direction: direction, indexPath: indexPathForSelectedRow) } else { // set first visible item selected - navigateToFirstVisibleStatus() + navigateToFirstVisibleTag() } } @@ -185,7 +185,7 @@ extension DiscoveryHashtagsViewController: TableViewControllerNavigateable { tableView.selectRow(at: indexPath, animated: true, scrollPosition: scrollPosition) } - private func navigateToFirstVisibleStatus() { + private func navigateToFirstVisibleTag() { guard let indexPathsForVisibleRows = tableView.indexPathsForVisibleRows else { return } guard let diffableDataSource = viewModel.diffableDataSource else { return } diff --git a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewController.swift b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewController.swift index 4042e2cd5..f73602ae4 100644 --- a/Mastodon/Scene/Discovery/News/DiscoveryNewsViewController.swift +++ b/Mastodon/Scene/Discovery/News/DiscoveryNewsViewController.swift @@ -131,3 +131,99 @@ extension DiscoveryNewsViewController: ScrollViewContainer { tableView } } + +extension DiscoveryNewsViewController { + override var keyCommands: [UIKeyCommand]? { + return navigationKeyCommands + } +} + +extension DiscoveryNewsViewController: TableViewControllerNavigateable { + + func navigate(direction: TableViewNavigationDirection) { + if let indexPathForSelectedRow = tableView.indexPathForSelectedRow { + // navigate up/down on the current selected item + navigateToLink(direction: direction, indexPath: indexPathForSelectedRow) + } else { + // set first visible item selected + navigateToFirstVisibleLink() + } + } + + private func navigateToLink(direction: TableViewNavigationDirection, indexPath: IndexPath) { + guard let diffableDataSource = viewModel.diffableDataSource else { return } + let items = diffableDataSource.snapshot().itemIdentifiers + guard let selectedItem = diffableDataSource.itemIdentifier(for: indexPath), + let selectedItemIndex = items.firstIndex(of: selectedItem) else { + return + } + + let _navigateToItem: DiscoveryItem? = { + var index = selectedItemIndex + while 0.. 1 { + // drop first when visible not the first cell of table + visibleItems.removeFirst() + } + guard let item = visibleItems.first, let indexPath = diffableDataSource.indexPath(for: item) else { return } + let scrollPosition: UITableView.ScrollPosition = overrideNavigationScrollPosition ?? Self.navigateScrollPosition(tableView: tableView, indexPath: indexPath) + tableView.selectRow(at: indexPath, animated: true, scrollPosition: scrollPosition) + } + + static func validNavigateableItem(_ item: DiscoveryItem) -> Bool { + switch item { + case .link: + return true + default: + return false + } + } + + func open() { + guard let indexPathForSelectedRow = tableView.indexPathForSelectedRow else { return } + guard let diffableDataSource = viewModel.diffableDataSource else { return } + guard let item = diffableDataSource.itemIdentifier(for: indexPathForSelectedRow) else { return } + + guard case let .link(link) = item else { return } + guard let url = URL(string: link.url) else { return } + coordinator.present( + scene: .safari(url: url), + from: self, + transition: .safariPresent(animated: true, completion: nil) + ) + } + + func navigateKeyCommandHandlerRelay(_ sender: UIKeyCommand) { + navigateKeyCommandHandler(sender) + } + +} From 66d23432c19923f3501609192040719cacbe2513 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 11 May 2022 19:22:22 +0800 Subject: [PATCH 090/101] fix: pick server table margin not works issue --- .../PickServer/MastodonPickServerViewController.swift | 11 ++++++----- .../PickServer/MastodonPickServerViewModel.swift | 3 ++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift index ffc7708f5..d05b446ae 100644 --- a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift +++ b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewController.swift @@ -92,7 +92,7 @@ extension MastodonPickServerViewController { tableView.topAnchor.constraint(equalTo: view.topAnchor), tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), - tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + tableView.bottomAnchor.constraint(equalTo: view.layoutMarginsGuide.bottomAnchor), ]) navigationActionView.translatesAutoresizingMaskIntoConstraints = false @@ -107,10 +107,10 @@ extension MastodonPickServerViewController { ]) navigationActionView - .observe(\.bounds, options: [.initial, .new]) { [weak self] navigationActionView, _ in + .observe(\.bounds, options: [.initial, .new]) { [weak self] _, _ in guard let self = self else { return } - let inset = navigationActionView.frame.height - self.tableView.contentInset.bottom = inset + let inset = self.navigationActionView.frame.height + self.viewModel.additionalTableViewInsets.bottom = inset } .store(in: &observations) @@ -149,7 +149,8 @@ extension MastodonPickServerViewController { KeyboardResponderService .configure( scrollView: tableView, - layoutNeedsUpdate: viewModel.viewDidAppear.eraseToAnyPublisher() + layoutNeedsUpdate: viewModel.viewDidAppear.eraseToAnyPublisher(), + additionalSafeAreaInsets: viewModel.$additionalTableViewInsets.eraseToAnyPublisher() ) .store(in: &disposeBag) diff --git a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift index 749843880..b077cbbe1 100644 --- a/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift +++ b/Mastodon/Scene/Onboarding/PickServer/MastodonPickServerViewModel.swift @@ -46,7 +46,8 @@ class MastodonPickServerViewModel: NSObject { let unindexedServers = CurrentValueSubject<[Mastodon.Entity.Server]?, Never>([]) // set nil when loading let viewWillAppear = PassthroughSubject() let viewDidAppear = CurrentValueSubject(Void()) - + @Published var additionalTableViewInsets: UIEdgeInsets = .zero + // output var diffableDataSource: UITableViewDiffableDataSource? private(set) lazy var loadIndexedServerStateMachine: GKStateMachine = { From 9d0e2b68b45054cfe04f0ce559323085b162f55c Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 11 May 2022 19:39:58 +0800 Subject: [PATCH 091/101] chore: workaround CocoaPods CDN issue --- .github/scripts/setup.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/scripts/setup.sh b/.github/scripts/setup.sh index 9b52d5b9e..0fc93db11 100755 --- a/.github/scripts/setup.sh +++ b/.github/scripts/setup.sh @@ -1,5 +1,8 @@ #!/bin/bash +# workaround https://github.com/CocoaPods/CocoaPods/issues/11355 +echo "$(echo -n 'source "https://github.com/CocoaPods/Specs.git"\n'; cat Podfile)" > Podfile + # Install Ruby Bundler gem install bundler:2.3.11 From ea6c9fc87e1348be26ed6f0bb6af4dd79099e221 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 11 May 2022 19:53:40 +0800 Subject: [PATCH 092/101] chore: update setup.sh --- .github/scripts/setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/setup.sh b/.github/scripts/setup.sh index 0fc93db11..845730f1f 100755 --- a/.github/scripts/setup.sh +++ b/.github/scripts/setup.sh @@ -1,7 +1,7 @@ #!/bin/bash # workaround https://github.com/CocoaPods/CocoaPods/issues/11355 -echo "$(echo -n 'source "https://github.com/CocoaPods/Specs.git"\n'; cat Podfile)" > Podfile +sed -i '' $'1s/^/source "https:\\/\\/github.com\\/CocoaPods\\/Specs.git"\\\n\\\n/' Podfile # Install Ruby Bundler gem install bundler:2.3.11 From 11762100eb9234a13f7d58de3d5520940af23216 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 11 May 2022 20:55:37 +0800 Subject: [PATCH 093/101] chore: update i18n resources --- .../Generated/Strings.swift | 88 +++++++++++++++++++ .../Resources/ar.lproj/Localizable.strings | 38 +++++++- .../Resources/ca.lproj/Localizable.strings | 34 +++++++ .../Resources/ckb.lproj/Localizable.strings | 34 +++++++ .../Resources/de.lproj/Localizable.strings | 34 +++++++ .../Resources/en.lproj/Localizable.strings | 34 +++++++ .../es-419.lproj/Localizable.strings | 34 +++++++ .../Resources/es.lproj/Localizable.strings | 34 +++++++ .../Resources/eu-ES.lproj/Localizable.strings | 34 +++++++ .../Resources/fr.lproj/Localizable.strings | 34 +++++++ .../Resources/gd-GB.lproj/Localizable.strings | 34 +++++++ .../Resources/gl.lproj/Localizable.strings | 34 +++++++ .../Resources/it.lproj/Localizable.strings | 34 +++++++ .../Resources/ja.lproj/Localizable.strings | 34 +++++++ .../Resources/kab.lproj/Localizable.strings | 34 +++++++ .../Resources/ku.lproj/Localizable.strings | 34 +++++++ .../Resources/nl.lproj/Localizable.strings | 34 +++++++ .../Resources/ru.lproj/Localizable.strings | 34 +++++++ .../Resources/th.lproj/Localizable.strings | 34 +++++++ .../Resources/tr.lproj/Localizable.strings | 34 +++++++ .../Resources/vi.lproj/Localizable.strings | 34 +++++++ .../zh-Hans.lproj/Localizable.strings | 34 +++++++ .../zh-Hant.lproj/Localizable.strings | 34 +++++++ 23 files changed, 838 insertions(+), 2 deletions(-) diff --git a/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift b/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift index de6b55cbd..b5403a142 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift +++ b/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift @@ -585,6 +585,12 @@ public enum L10n { public static let published = L10n.tr("Localizable", "Scene.HomeTimeline.NavigationBarState.Published") /// Publishing post... public static let publishing = L10n.tr("Localizable", "Scene.HomeTimeline.NavigationBarState.Publishing") + public enum Accessibility { + /// Tap to scroll to top and tap again to previous location + public static let logoHint = L10n.tr("Localizable", "Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint") + /// Logo Button + public static let logoLabel = L10n.tr("Localizable", "Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel") + } } } public enum Notification { @@ -840,6 +846,86 @@ public enum L10n { } /// Report public static let titleReport = L10n.tr("Localizable", "Scene.Report.TitleReport") + public enum StepFinal { + /// Block %@ + public static func blockUser(_ p1: Any) -> String { + return L10n.tr("Localizable", "Scene.Report.StepFinal.BlockUser", String(describing: p1)) + } + /// Don’t want to see this? + public static let dontWantToSeeThis = L10n.tr("Localizable", "Scene.Report.StepFinal.DontWantToSeeThis") + /// Mute %@ + public static func muteUser(_ p1: Any) -> String { + return L10n.tr("Localizable", "Scene.Report.StepFinal.MuteUser", String(describing: p1)) + } + /// They will no longer be able to follow or see your posts, but they can see if they’ve been blocked. + public static let theyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked = L10n.tr("Localizable", "Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked") + /// Unfollow + public static let unfollow = L10n.tr("Localizable", "Scene.Report.StepFinal.Unfollow") + /// Unfollowed + public static let unfollowed = L10n.tr("Localizable", "Scene.Report.StepFinal.Unfollowed") + /// Unfollow %@ + public static func unfollowUser(_ p1: Any) -> String { + return L10n.tr("Localizable", "Scene.Report.StepFinal.UnfollowUser", String(describing: p1)) + } + /// When you see something you don’t like on Mastodon, you can remove the person from your experience. + public static let whenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience = L10n.tr("Localizable", "Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience.") + /// You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted. + public static let youWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted = L10n.tr("Localizable", "Scene.Report.StepFinal.YouWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted") + } + public enum StepFour { + /// Is there anything else we should know? + public static let isThereAnythingElseWeShouldKnow = L10n.tr("Localizable", "Scene.Report.StepFour.IsThereAnythingElseWeShouldKnow") + /// Step 4 of 4 + public static let step4Of4 = L10n.tr("Localizable", "Scene.Report.StepFour.Step4Of4") + } + public enum StepOne { + /// I don’t like it + public static let iDontLikeIt = L10n.tr("Localizable", "Scene.Report.StepOne.IDontLikeIt") + /// It is not something you want to see + public static let itIsNotSomethingYouWantToSee = L10n.tr("Localizable", "Scene.Report.StepOne.ItIsNotSomethingYouWantToSee") + /// It’s something else + public static let itsSomethingElse = L10n.tr("Localizable", "Scene.Report.StepOne.ItsSomethingElse") + /// It’s spam + public static let itsSpam = L10n.tr("Localizable", "Scene.Report.StepOne.ItsSpam") + /// It violates server rules + public static let itViolatesServerRules = L10n.tr("Localizable", "Scene.Report.StepOne.ItViolatesServerRules") + /// Malicious links, fake engagement, or repetetive replies + public static let maliciousLinksFakeEngagementOrRepetetiveReplies = L10n.tr("Localizable", "Scene.Report.StepOne.MaliciousLinksFakeEngagementOrRepetetiveReplies") + /// Select the best match + public static let selectTheBestMatch = L10n.tr("Localizable", "Scene.Report.StepOne.SelectTheBestMatch") + /// Step 1 of 4 + public static let step1Of4 = L10n.tr("Localizable", "Scene.Report.StepOne.Step1Of4") + /// The issue does not fit into other categories + public static let theIssueDoesNotFitIntoOtherCategories = L10n.tr("Localizable", "Scene.Report.StepOne.TheIssueDoesNotFitIntoOtherCategories") + /// What's wrong with this account? + public static let whatsWrongWithThisAccount = L10n.tr("Localizable", "Scene.Report.StepOne.WhatsWrongWithThisAccount") + /// What's wrong with this post? + public static let whatsWrongWithThisPost = L10n.tr("Localizable", "Scene.Report.StepOne.WhatsWrongWithThisPost") + /// What's wrong with %@? + public static func whatsWrongWithThisUsername(_ p1: Any) -> String { + return L10n.tr("Localizable", "Scene.Report.StepOne.WhatsWrongWithThisUsername", String(describing: p1)) + } + /// You are aware that it breaks specific rules + public static let youAreAwareThatItBreaksSpecificRules = L10n.tr("Localizable", "Scene.Report.StepOne.YouAreAwareThatItBreaksSpecificRules") + } + public enum StepThree { + /// Are there any posts that back up this report? + public static let areThereAnyPostsThatBackUpThisReport = L10n.tr("Localizable", "Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport") + /// Select all that apply + public static let selectAllThatApply = L10n.tr("Localizable", "Scene.Report.StepThree.SelectAllThatApply") + /// Step 3 of 4 + public static let step3Of4 = L10n.tr("Localizable", "Scene.Report.StepThree.Step3Of4") + } + public enum StepTwo { + /// I just don’t like it + public static let iJustDonTLikeIt = L10n.tr("Localizable", "Scene.Report.StepTwo.IJustDon’tLikeIt") + /// Select all that apply + public static let selectAllThatApply = L10n.tr("Localizable", "Scene.Report.StepTwo.SelectAllThatApply") + /// Step 2 of 4 + public static let step2Of4 = L10n.tr("Localizable", "Scene.Report.StepTwo.Step2Of4") + /// Which rules are being violated? + public static let whichRulesAreBeingViolated = L10n.tr("Localizable", "Scene.Report.StepTwo.WhichRulesAreBeingViolated") + } } public enum Search { /// Search @@ -947,6 +1033,8 @@ public enum L10n { public enum Input { /// Search servers public static let placeholder = L10n.tr("Localizable", "Scene.ServerPicker.Input.Placeholder") + /// Search communities or enter URL + public static let searchServersOrEnterUrl = L10n.tr("Localizable", "Scene.ServerPicker.Input.SearchServersOrEnterUrl") } public enum Label { /// CATEGORY diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings index 09ab59f78..c49b9f9d6 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ar.lproj/Localizable.strings @@ -211,6 +211,8 @@ "Scene.Favorite.Title" = "مُفضَّلَتُك"; "Scene.Follower.Footer" = "لا يُمكِن عَرض المُتابِعين مِنَ الخوادم الأُخرى."; "Scene.Following.Footer" = "لا يُمكِن عَرض المُتابَعات مِنَ الخوادم الأُخرى."; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint" = "اُنقُر لِلتمريرِ لأعلى واُنقُر مَرّةً أُخرَى لِلذَّهابِ إلَى المَوقِعِ السَّابِق"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "ُّزِرُّ الشِّعار"; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "إظهار منشورات جديدة"; "Scene.HomeTimeline.NavigationBarState.Offline" = "غَير مُتَّصِل"; "Scene.HomeTimeline.NavigationBarState.Published" = "تمَّ النَّشر!"; @@ -291,8 +293,39 @@ "Scene.Report.Reported" = "مُبْلَغٌ عَنه"; "Scene.Report.Send" = "إرسال البلاغ"; "Scene.Report.SkipToSend" = "إرسال بدون تعليق"; -"Scene.Report.Step1" = "الخطوة الأولى مِن أصل اثنتين"; -"Scene.Report.Step2" = "الخطوة الثانية والأخيرة"; +"Scene.Report.Step1" = "الخطوة 1 مِن أصل 2"; +"Scene.Report.Step2" = "الخطوة 2 مِن أصل 2"; +"Scene.Report.StepFinal.BlockUser" = "حَظرُ %@"; +"Scene.Report.StepFinal.DontWantToSeeThis" = "ألَا تُريدُ رُؤيَةَ هَذَا؟"; +"Scene.Report.StepFinal.MuteUser" = "كَتمُ %@"; +"Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked" = "لَن يَتمكَّنَ بَعدَ الآنِ مِن مُتابَعَةِ مَنشوراتِكَ أو رُؤيَتِها، وَلكِن يُمكِنَهُ مَعرِفَةُ مَا إذا حُظَرِت عَنه."; +"Scene.Report.StepFinal.Unfollow" = "إلغاءُ المُتابَعَة"; +"Scene.Report.StepFinal.UnfollowUser" = "إلغاءُ مُتابَعَةِ %@"; +"Scene.Report.StepFinal.Unfollowed" = "أُلغِيَت المُتابَعَة"; +"Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience." = "عِندما تَرى شيئًا لَا يُعجِبُكَ عَلَى مَاستودُون، يُمكِنُكَ إزالَةُ الشَّخصِ مِن تَجرِبَتِك."; +"Scene.Report.StepFinal.YouWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted" = "لَن تَرى مُشارَكاتِهِ أو إعادَاتِ تَدوينَهِ فِي تغذيَتِكَ الرَّئيسَة. لَن يَعرِفَ أنَّهُ قَد كُتِمَ أيضًا."; +"Scene.Report.StepFour.IsThereAnythingElseWeShouldKnow" = "هَل هُناكَ شَيءٌ آخَرَ يَجِبُ أن نَعلَمَ بِه؟"; +"Scene.Report.StepFour.Step4Of4" = "الخطوة 4 مِن أصل 4"; +"Scene.Report.StepOne.IDontLikeIt" = "لا يُعجِبُني"; +"Scene.Report.StepOne.ItIsNotSomethingYouWantToSee" = "إنَّهُ ليسَ شيئًا تُريدُ رُؤيَتَه"; +"Scene.Report.StepOne.ItViolatesServerRules" = "يَنتَهِكُ قَواعِدَ الخادِم"; +"Scene.Report.StepOne.ItsSomethingElse" = "إنَّهُ شَيءٌ آخَر"; +"Scene.Report.StepOne.ItsSpam" = "إنَّهُ غَيرٌ مَرغوبٍ فيه"; +"Scene.Report.StepOne.MaliciousLinksFakeEngagementOrRepetetiveReplies" = "رَوابِطٌ ضَارَّة، اِرتِباطاتٌ مُزيَّفَة أو رُدودٌ مُتَكَرِّرَة"; +"Scene.Report.StepOne.SelectTheBestMatch" = "اِختَر أفضلَ تَطابُق"; +"Scene.Report.StepOne.Step1Of4" = "الخطوة 1 مِن أصل 4"; +"Scene.Report.StepOne.TheIssueDoesNotFitIntoOtherCategories" = "المُشكِلَةُ لَا تَتَناسَبُ مَعَ الفِئاتِ الأُخرَى"; +"Scene.Report.StepOne.WhatsWrongWithThisAccount" = "ما المُشكِلَةُ فِي هَذَا الحِساب؟"; +"Scene.Report.StepOne.WhatsWrongWithThisPost" = "ما المُشكِلَةُ فِي هَذَا المَنشُور؟"; +"Scene.Report.StepOne.WhatsWrongWithThisUsername" = "ما المُشكِلَة مَعَ %@؟"; +"Scene.Report.StepOne.YouAreAwareThatItBreaksSpecificRules" = "أنتَ مُدِركٌ لِانتِهاكِهِ قَواعِدًا مُحَدَّدَة"; +"Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport" = "هَل هُناكَ أيُّ مَنشُوراتٍ أُخرَى تَتَوافَقُ مَعَ هَذَا التَّقرير؟"; +"Scene.Report.StepThree.SelectAllThatApply" = "اِختَر كُلَّ ما يَنطَبِق"; +"Scene.Report.StepThree.Step3Of4" = "الخطوة 3 مِن أصل 4"; +"Scene.Report.StepTwo.IJustDon’tLikeIt" = "أنا فَقَط لا يُعجِبُني"; +"Scene.Report.StepTwo.SelectAllThatApply" = "اِختَر كُلَّ ما يَنطَبِق"; +"Scene.Report.StepTwo.Step2Of4" = "الخطوة 2 مِن أصل 4"; +"Scene.Report.StepTwo.WhichRulesAreBeingViolated" = "مَا هِيَ القَواعِدُ الَّتي تُنتَهَك؟"; "Scene.Report.TextPlaceholder" = "اكتب أو الصق تعليقات إضافيَّة"; "Scene.Report.Title" = "الإبلاغ عن %@"; "Scene.Report.TitleReport" = "إبلاغ"; @@ -333,6 +366,7 @@ "Scene.ServerPicker.EmptyState.FindingServers" = "يجري إيجاد خوادم متوفِّرَة..."; "Scene.ServerPicker.EmptyState.NoResults" = "لا توجد نتائج"; "Scene.ServerPicker.Input.Placeholder" = "اِبحَث عن خادِم أو انضم إلى آخر خاص بك..."; +"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "اِبحث عَن مُجتَمَعَات أو أدخِل عُنوانَ URL"; "Scene.ServerPicker.Label.Category" = "الفئة"; "Scene.ServerPicker.Label.Language" = "اللُّغة"; "Scene.ServerPicker.Label.Users" = "مُستَخدِم"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings index 3c02a5010..502b26729 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ca.lproj/Localizable.strings @@ -210,6 +210,8 @@ carregat a Mastodon."; "Scene.Favorite.Title" = "Els teus Favorits"; "Scene.Follower.Footer" = "Els seguidors d'altres servidors no son mostrats."; "Scene.Following.Footer" = "Els seguits d'altres servidors no son mostrats."; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint" = "Toca per desplaçar-te cap a dalt i torna a toca de nou per tornar a la ubicació anterior"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Botó de logotip"; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Veure noves publicacions"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Fora de línia"; "Scene.HomeTimeline.NavigationBarState.Published" = "Publicat!"; @@ -292,6 +294,37 @@ carregat a Mastodon."; "Scene.Report.SkipToSend" = "Envia sense comentaris"; "Scene.Report.Step1" = "Pas 1 de 2"; "Scene.Report.Step2" = "Pas 2 de 2"; +"Scene.Report.StepFinal.BlockUser" = "Bloca %@"; +"Scene.Report.StepFinal.DontWantToSeeThis" = "No vols veure això?"; +"Scene.Report.StepFinal.MuteUser" = "Silencia %@"; +"Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked" = "Ja no podran seguir ni veure les teves publicacions, però poden veure si han estat bloquejats."; +"Scene.Report.StepFinal.Unfollow" = "Deixa de seguir"; +"Scene.Report.StepFinal.UnfollowUser" = "Deixa de seguir %@"; +"Scene.Report.StepFinal.Unfollowed" = "S'ha deixat de seguir"; +"Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience." = "Quan veus alguna cosa que no t'agrada a Mastodon, pots eliminar la persona de la vostra experiència."; +"Scene.Report.StepFinal.YouWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted" = "No veuràs les seves publicacions o impulsos a la teva línia de temps personal. No sabran que han estat silenciats."; +"Scene.Report.StepFour.IsThereAnythingElseWeShouldKnow" = "Hi ha res més que hauríem de saber?"; +"Scene.Report.StepFour.Step4Of4" = "Pas 4 de 4"; +"Scene.Report.StepOne.IDontLikeIt" = "No m'agrada"; +"Scene.Report.StepOne.ItIsNotSomethingYouWantToSee" = "No és una cosa que vulguis veure"; +"Scene.Report.StepOne.ItViolatesServerRules" = "Infringeix les normes del servidor"; +"Scene.Report.StepOne.ItsSomethingElse" = "És una altra cosa"; +"Scene.Report.StepOne.ItsSpam" = "És contingut brossa"; +"Scene.Report.StepOne.MaliciousLinksFakeEngagementOrRepetetiveReplies" = "Enllaços maliciosos, compromís falç o respostes repetitives"; +"Scene.Report.StepOne.SelectTheBestMatch" = "Selecciona la millor coincidència"; +"Scene.Report.StepOne.Step1Of4" = "Pas 1 de 4"; +"Scene.Report.StepOne.TheIssueDoesNotFitIntoOtherCategories" = "El problema no encaixa en altres categories"; +"Scene.Report.StepOne.WhatsWrongWithThisAccount" = "Quin és el problema amb aquest compte?"; +"Scene.Report.StepOne.WhatsWrongWithThisPost" = "Quin és el problema amb aquesta publicació?"; +"Scene.Report.StepOne.WhatsWrongWithThisUsername" = "Quin és el problema amb %@?"; +"Scene.Report.StepOne.YouAreAwareThatItBreaksSpecificRules" = "Ets conscient que incompleix normes específiques"; +"Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport" = "Hi ha alguna publicació que recolzi aquest informe?"; +"Scene.Report.StepThree.SelectAllThatApply" = "Selecciona tot el que correspongui"; +"Scene.Report.StepThree.Step3Of4" = "Pas 3 de 4"; +"Scene.Report.StepTwo.IJustDon’tLikeIt" = "Simplement no m'agrada"; +"Scene.Report.StepTwo.SelectAllThatApply" = "Selecciona tot el que correspongui"; +"Scene.Report.StepTwo.Step2Of4" = "Pas 2 de 4"; +"Scene.Report.StepTwo.WhichRulesAreBeingViolated" = "Quines normes s'estan infringint?"; "Scene.Report.TextPlaceholder" = "Escriu o enganxa comentaris addicionals"; "Scene.Report.Title" = "Informa sobre %@"; "Scene.Report.TitleReport" = "Informe"; @@ -332,6 +365,7 @@ carregat a Mastodon."; "Scene.ServerPicker.EmptyState.FindingServers" = "Cercant els servidors disponibles..."; "Scene.ServerPicker.EmptyState.NoResults" = "No hi ha resultats"; "Scene.ServerPicker.Input.Placeholder" = "Cerca servidors"; +"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "Cerca comunitats o introdueix l'URL"; "Scene.ServerPicker.Label.Category" = "CATEGORIA"; "Scene.ServerPicker.Label.Language" = "LLENGUATGE"; "Scene.ServerPicker.Label.Users" = "USUARIS"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ckb.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ckb.lproj/Localizable.strings index 1db4f7936..89ba6315d 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ckb.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ckb.lproj/Localizable.strings @@ -209,6 +209,8 @@ "Scene.Favorite.Title" = "بەدڵبووەکانت"; "Scene.Follower.Footer" = "شوێنکەوتووەکانی لە ڕاژەکارەکانی ترەوە نیشان نادرێت."; "Scene.Following.Footer" = "شوێنکەوتنەکانی بۆ هەژماری ڕاژەکارەکانی تر نیشان نادرێت."; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint" = "Tap to scroll to top and tap again to previous location"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Logo Button"; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "پۆستە نوێکان ببینە"; "Scene.HomeTimeline.NavigationBarState.Offline" = "دەرهێڵ"; "Scene.HomeTimeline.NavigationBarState.Published" = "بڵاوکرایەوە!"; @@ -291,6 +293,37 @@ "Scene.Report.SkipToSend" = "بەبێ لێدوان بینێرە"; "Scene.Report.Step1" = "هەنگاوی 1 لە 2"; "Scene.Report.Step2" = "هەنگاوی 2 لە 2"; +"Scene.Report.StepFinal.BlockUser" = "Block %@"; +"Scene.Report.StepFinal.DontWantToSeeThis" = "Don’t want to see this?"; +"Scene.Report.StepFinal.MuteUser" = "Mute %@"; +"Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked" = "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked."; +"Scene.Report.StepFinal.Unfollow" = "Unfollow"; +"Scene.Report.StepFinal.UnfollowUser" = "Unfollow %@"; +"Scene.Report.StepFinal.Unfollowed" = "Unfollowed"; +"Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience." = "When you see something you don’t like on Mastodon, you can remove the person from your experience."; +"Scene.Report.StepFinal.YouWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted" = "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted."; +"Scene.Report.StepFour.IsThereAnythingElseWeShouldKnow" = "Is there anything else we should know?"; +"Scene.Report.StepFour.Step4Of4" = "Step 4 of 4"; +"Scene.Report.StepOne.IDontLikeIt" = "I don’t like it"; +"Scene.Report.StepOne.ItIsNotSomethingYouWantToSee" = "It is not something you want to see"; +"Scene.Report.StepOne.ItViolatesServerRules" = "It violates server rules"; +"Scene.Report.StepOne.ItsSomethingElse" = "It’s something else"; +"Scene.Report.StepOne.ItsSpam" = "It’s spam"; +"Scene.Report.StepOne.MaliciousLinksFakeEngagementOrRepetetiveReplies" = "Malicious links, fake engagement, or repetetive replies"; +"Scene.Report.StepOne.SelectTheBestMatch" = "Select the best match"; +"Scene.Report.StepOne.Step1Of4" = "Step 1 of 4"; +"Scene.Report.StepOne.TheIssueDoesNotFitIntoOtherCategories" = "The issue does not fit into other categories"; +"Scene.Report.StepOne.WhatsWrongWithThisAccount" = "What's wrong with this account?"; +"Scene.Report.StepOne.WhatsWrongWithThisPost" = "What's wrong with this post?"; +"Scene.Report.StepOne.WhatsWrongWithThisUsername" = "What's wrong with %@?"; +"Scene.Report.StepOne.YouAreAwareThatItBreaksSpecificRules" = "You are aware that it breaks specific rules"; +"Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport" = "Are there any posts that back up this report?"; +"Scene.Report.StepThree.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepThree.Step3Of4" = "Step 3 of 4"; +"Scene.Report.StepTwo.IJustDon’tLikeIt" = "I just don’t like it"; +"Scene.Report.StepTwo.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepTwo.Step2Of4" = "Step 2 of 4"; +"Scene.Report.StepTwo.WhichRulesAreBeingViolated" = "Which rules are being violated?"; "Scene.Report.TextPlaceholder" = "ڕوونکردنەوەی زۆرتر بدە"; "Scene.Report.Title" = "سکاڵا لە %@ بکە"; "Scene.Report.TitleReport" = "سکاڵای لێ بکە"; @@ -331,6 +364,7 @@ "Scene.ServerPicker.EmptyState.FindingServers" = "ڕاژەکار دەدۆزرێتەوە..."; "Scene.ServerPicker.EmptyState.NoResults" = "ئەنجام نییە"; "Scene.ServerPicker.Input.Placeholder" = "بگەڕێ"; +"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "Search communities or enter URL"; "Scene.ServerPicker.Label.Category" = "بەش"; "Scene.ServerPicker.Label.Language" = "زمان"; "Scene.ServerPicker.Label.Users" = "بەکارهێنەر"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings index 7c3e16ec5..7b3af4622 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/de.lproj/Localizable.strings @@ -211,6 +211,8 @@ tippe darin auf den Link, um Dein Konto zu bestätigen."; "Scene.Favorite.Title" = "Deine Favoriten"; "Scene.Follower.Footer" = "Follower von anderen Servern werden nicht angezeigt."; "Scene.Following.Footer" = "Wem das Konto folgt wird von anderen Servern werden nicht angezeigt."; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint" = "Tap to scroll to top and tap again to previous location"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Logo Button"; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Neue Beiträge anzeigen"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Offline"; "Scene.HomeTimeline.NavigationBarState.Published" = "Veröffentlicht!"; @@ -293,6 +295,37 @@ tippe darin auf den Link, um Dein Konto zu bestätigen."; "Scene.Report.SkipToSend" = "Ohne Kommentar abschicken"; "Scene.Report.Step1" = "Schritt 1 von 2"; "Scene.Report.Step2" = "Schritt 2 von 2"; +"Scene.Report.StepFinal.BlockUser" = "Block %@"; +"Scene.Report.StepFinal.DontWantToSeeThis" = "Don’t want to see this?"; +"Scene.Report.StepFinal.MuteUser" = "Mute %@"; +"Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked" = "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked."; +"Scene.Report.StepFinal.Unfollow" = "Unfollow"; +"Scene.Report.StepFinal.UnfollowUser" = "Unfollow %@"; +"Scene.Report.StepFinal.Unfollowed" = "Unfollowed"; +"Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience." = "When you see something you don’t like on Mastodon, you can remove the person from your experience."; +"Scene.Report.StepFinal.YouWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted" = "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted."; +"Scene.Report.StepFour.IsThereAnythingElseWeShouldKnow" = "Is there anything else we should know?"; +"Scene.Report.StepFour.Step4Of4" = "Step 4 of 4"; +"Scene.Report.StepOne.IDontLikeIt" = "I don’t like it"; +"Scene.Report.StepOne.ItIsNotSomethingYouWantToSee" = "It is not something you want to see"; +"Scene.Report.StepOne.ItViolatesServerRules" = "It violates server rules"; +"Scene.Report.StepOne.ItsSomethingElse" = "It’s something else"; +"Scene.Report.StepOne.ItsSpam" = "It’s spam"; +"Scene.Report.StepOne.MaliciousLinksFakeEngagementOrRepetetiveReplies" = "Malicious links, fake engagement, or repetetive replies"; +"Scene.Report.StepOne.SelectTheBestMatch" = "Select the best match"; +"Scene.Report.StepOne.Step1Of4" = "Step 1 of 4"; +"Scene.Report.StepOne.TheIssueDoesNotFitIntoOtherCategories" = "The issue does not fit into other categories"; +"Scene.Report.StepOne.WhatsWrongWithThisAccount" = "What's wrong with this account?"; +"Scene.Report.StepOne.WhatsWrongWithThisPost" = "What's wrong with this post?"; +"Scene.Report.StepOne.WhatsWrongWithThisUsername" = "What's wrong with %@?"; +"Scene.Report.StepOne.YouAreAwareThatItBreaksSpecificRules" = "You are aware that it breaks specific rules"; +"Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport" = "Are there any posts that back up this report?"; +"Scene.Report.StepThree.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepThree.Step3Of4" = "Step 3 of 4"; +"Scene.Report.StepTwo.IJustDon’tLikeIt" = "I just don’t like it"; +"Scene.Report.StepTwo.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepTwo.Step2Of4" = "Step 2 of 4"; +"Scene.Report.StepTwo.WhichRulesAreBeingViolated" = "Which rules are being violated?"; "Scene.Report.TextPlaceholder" = "Zusätzliche Kommentare eingeben oder einfügen"; "Scene.Report.Title" = "%@ melden"; "Scene.Report.TitleReport" = "Melden"; @@ -333,6 +366,7 @@ tippe darin auf den Link, um Dein Konto zu bestätigen."; "Scene.ServerPicker.EmptyState.FindingServers" = "Verfügbare Server werden gesucht..."; "Scene.ServerPicker.EmptyState.NoResults" = "Keine Ergebnisse"; "Scene.ServerPicker.Input.Placeholder" = "Finde einen Server oder trete deinem eigenen bei..."; +"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "Search communities or enter URL"; "Scene.ServerPicker.Label.Category" = "KATEGORIE"; "Scene.ServerPicker.Label.Language" = "SPRACHE"; "Scene.ServerPicker.Label.Users" = "BENUTZER"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings index fe66593f4..91ad3a0e3 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings @@ -210,6 +210,8 @@ uploaded to Mastodon."; "Scene.Favorite.Title" = "Your Favorites"; "Scene.Follower.Footer" = "Followers from other servers are not displayed."; "Scene.Following.Footer" = "Follows from other servers are not displayed."; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint" = "Tap to scroll to top and tap again to previous location"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Logo Button"; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "See new posts"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Offline"; "Scene.HomeTimeline.NavigationBarState.Published" = "Published!"; @@ -292,6 +294,37 @@ uploaded to Mastodon."; "Scene.Report.SkipToSend" = "Send without comment"; "Scene.Report.Step1" = "Step 1 of 2"; "Scene.Report.Step2" = "Step 2 of 2"; +"Scene.Report.StepFinal.BlockUser" = "Block %@"; +"Scene.Report.StepFinal.DontWantToSeeThis" = "Don’t want to see this?"; +"Scene.Report.StepFinal.MuteUser" = "Mute %@"; +"Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked" = "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked."; +"Scene.Report.StepFinal.Unfollow" = "Unfollow"; +"Scene.Report.StepFinal.UnfollowUser" = "Unfollow %@"; +"Scene.Report.StepFinal.Unfollowed" = "Unfollowed"; +"Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience." = "When you see something you don’t like on Mastodon, you can remove the person from your experience."; +"Scene.Report.StepFinal.YouWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted" = "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted."; +"Scene.Report.StepFour.IsThereAnythingElseWeShouldKnow" = "Is there anything else we should know?"; +"Scene.Report.StepFour.Step4Of4" = "Step 4 of 4"; +"Scene.Report.StepOne.IDontLikeIt" = "I don’t like it"; +"Scene.Report.StepOne.ItIsNotSomethingYouWantToSee" = "It is not something you want to see"; +"Scene.Report.StepOne.ItViolatesServerRules" = "It violates server rules"; +"Scene.Report.StepOne.ItsSomethingElse" = "It’s something else"; +"Scene.Report.StepOne.ItsSpam" = "It’s spam"; +"Scene.Report.StepOne.MaliciousLinksFakeEngagementOrRepetetiveReplies" = "Malicious links, fake engagement, or repetetive replies"; +"Scene.Report.StepOne.SelectTheBestMatch" = "Select the best match"; +"Scene.Report.StepOne.Step1Of4" = "Step 1 of 4"; +"Scene.Report.StepOne.TheIssueDoesNotFitIntoOtherCategories" = "The issue does not fit into other categories"; +"Scene.Report.StepOne.WhatsWrongWithThisAccount" = "What's wrong with this account?"; +"Scene.Report.StepOne.WhatsWrongWithThisPost" = "What's wrong with this post?"; +"Scene.Report.StepOne.WhatsWrongWithThisUsername" = "What's wrong with %@?"; +"Scene.Report.StepOne.YouAreAwareThatItBreaksSpecificRules" = "You are aware that it breaks specific rules"; +"Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport" = "Are there any posts that back up this report?"; +"Scene.Report.StepThree.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepThree.Step3Of4" = "Step 3 of 4"; +"Scene.Report.StepTwo.IJustDon’tLikeIt" = "I just don’t like it"; +"Scene.Report.StepTwo.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepTwo.Step2Of4" = "Step 2 of 4"; +"Scene.Report.StepTwo.WhichRulesAreBeingViolated" = "Which rules are being violated?"; "Scene.Report.TextPlaceholder" = "Type or paste additional comments"; "Scene.Report.Title" = "Report %@"; "Scene.Report.TitleReport" = "Report"; @@ -332,6 +365,7 @@ uploaded to Mastodon."; "Scene.ServerPicker.EmptyState.FindingServers" = "Finding available servers..."; "Scene.ServerPicker.EmptyState.NoResults" = "No results"; "Scene.ServerPicker.Input.Placeholder" = "Search servers"; +"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "Search communities or enter URL"; "Scene.ServerPicker.Label.Category" = "CATEGORY"; "Scene.ServerPicker.Label.Language" = "LANGUAGE"; "Scene.ServerPicker.Label.Users" = "USERS"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.strings index af5d453b7..5b05b535d 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/es-419.lproj/Localizable.strings @@ -211,6 +211,8 @@ pulsá en el enlace para confirmar tu cuenta."; "Scene.Favorite.Title" = "Tus favoritos"; "Scene.Follower.Footer" = "No se muestran los seguidores de otros servidores."; "Scene.Following.Footer" = "No se muestran las cuentas de otros servidores que seguís."; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint" = "Tap to scroll to top and tap again to previous location"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Logo Button"; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Ver nuevos mensajes"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Desconectado"; "Scene.HomeTimeline.NavigationBarState.Published" = "¡Enviado!"; @@ -293,6 +295,37 @@ pulsá en el enlace para confirmar tu cuenta."; "Scene.Report.SkipToSend" = "Enviar sin comentarios"; "Scene.Report.Step1" = "Paso 1 de 2"; "Scene.Report.Step2" = "Paso 2 de 2"; +"Scene.Report.StepFinal.BlockUser" = "Block %@"; +"Scene.Report.StepFinal.DontWantToSeeThis" = "Don’t want to see this?"; +"Scene.Report.StepFinal.MuteUser" = "Mute %@"; +"Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked" = "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked."; +"Scene.Report.StepFinal.Unfollow" = "Unfollow"; +"Scene.Report.StepFinal.UnfollowUser" = "Unfollow %@"; +"Scene.Report.StepFinal.Unfollowed" = "Unfollowed"; +"Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience." = "When you see something you don’t like on Mastodon, you can remove the person from your experience."; +"Scene.Report.StepFinal.YouWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted" = "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted."; +"Scene.Report.StepFour.IsThereAnythingElseWeShouldKnow" = "Is there anything else we should know?"; +"Scene.Report.StepFour.Step4Of4" = "Step 4 of 4"; +"Scene.Report.StepOne.IDontLikeIt" = "I don’t like it"; +"Scene.Report.StepOne.ItIsNotSomethingYouWantToSee" = "It is not something you want to see"; +"Scene.Report.StepOne.ItViolatesServerRules" = "It violates server rules"; +"Scene.Report.StepOne.ItsSomethingElse" = "It’s something else"; +"Scene.Report.StepOne.ItsSpam" = "It’s spam"; +"Scene.Report.StepOne.MaliciousLinksFakeEngagementOrRepetetiveReplies" = "Malicious links, fake engagement, or repetetive replies"; +"Scene.Report.StepOne.SelectTheBestMatch" = "Select the best match"; +"Scene.Report.StepOne.Step1Of4" = "Step 1 of 4"; +"Scene.Report.StepOne.TheIssueDoesNotFitIntoOtherCategories" = "The issue does not fit into other categories"; +"Scene.Report.StepOne.WhatsWrongWithThisAccount" = "What's wrong with this account?"; +"Scene.Report.StepOne.WhatsWrongWithThisPost" = "What's wrong with this post?"; +"Scene.Report.StepOne.WhatsWrongWithThisUsername" = "What's wrong with %@?"; +"Scene.Report.StepOne.YouAreAwareThatItBreaksSpecificRules" = "You are aware that it breaks specific rules"; +"Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport" = "Are there any posts that back up this report?"; +"Scene.Report.StepThree.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepThree.Step3Of4" = "Step 3 of 4"; +"Scene.Report.StepTwo.IJustDon’tLikeIt" = "I just don’t like it"; +"Scene.Report.StepTwo.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepTwo.Step2Of4" = "Step 2 of 4"; +"Scene.Report.StepTwo.WhichRulesAreBeingViolated" = "Which rules are being violated?"; "Scene.Report.TextPlaceholder" = "Escribí o pegá comentarios adicionales"; "Scene.Report.Title" = "Denunciar a %@"; "Scene.Report.TitleReport" = "Denunciar"; @@ -333,6 +366,7 @@ pulsá en el enlace para confirmar tu cuenta."; "Scene.ServerPicker.EmptyState.FindingServers" = "Buscando servidores disponibles…"; "Scene.ServerPicker.EmptyState.NoResults" = "No hay resultados"; "Scene.ServerPicker.Input.Placeholder" = "Encontrá un servidor o unite al tuyo…"; +"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "Search communities or enter URL"; "Scene.ServerPicker.Label.Category" = "CATEGORÍA"; "Scene.ServerPicker.Label.Language" = "IDIOMA"; "Scene.ServerPicker.Label.Users" = "CUENTAS"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.strings index 09fba0b42..48b14608a 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/es.lproj/Localizable.strings @@ -211,6 +211,8 @@ pulsa en el enlace para confirmar tu cuenta."; "Scene.Favorite.Title" = "Tus Favoritos"; "Scene.Follower.Footer" = "No se muestran los seguidores de otros servidores."; "Scene.Following.Footer" = "No se muestran los seguidos de otros servidores."; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint" = "Tap to scroll to top and tap again to previous location"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Logo Button"; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Ver nuevas publicaciones"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Sin Conexión"; "Scene.HomeTimeline.NavigationBarState.Published" = "¡Publicado!"; @@ -293,6 +295,37 @@ pulsa en el enlace para confirmar tu cuenta."; "Scene.Report.SkipToSend" = "Enviar sin comentarios"; "Scene.Report.Step1" = "Paso 1 de 2"; "Scene.Report.Step2" = "Paso 2 de 2"; +"Scene.Report.StepFinal.BlockUser" = "Block %@"; +"Scene.Report.StepFinal.DontWantToSeeThis" = "Don’t want to see this?"; +"Scene.Report.StepFinal.MuteUser" = "Mute %@"; +"Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked" = "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked."; +"Scene.Report.StepFinal.Unfollow" = "Unfollow"; +"Scene.Report.StepFinal.UnfollowUser" = "Unfollow %@"; +"Scene.Report.StepFinal.Unfollowed" = "Unfollowed"; +"Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience." = "When you see something you don’t like on Mastodon, you can remove the person from your experience."; +"Scene.Report.StepFinal.YouWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted" = "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted."; +"Scene.Report.StepFour.IsThereAnythingElseWeShouldKnow" = "Is there anything else we should know?"; +"Scene.Report.StepFour.Step4Of4" = "Step 4 of 4"; +"Scene.Report.StepOne.IDontLikeIt" = "I don’t like it"; +"Scene.Report.StepOne.ItIsNotSomethingYouWantToSee" = "It is not something you want to see"; +"Scene.Report.StepOne.ItViolatesServerRules" = "It violates server rules"; +"Scene.Report.StepOne.ItsSomethingElse" = "It’s something else"; +"Scene.Report.StepOne.ItsSpam" = "It’s spam"; +"Scene.Report.StepOne.MaliciousLinksFakeEngagementOrRepetetiveReplies" = "Malicious links, fake engagement, or repetetive replies"; +"Scene.Report.StepOne.SelectTheBestMatch" = "Select the best match"; +"Scene.Report.StepOne.Step1Of4" = "Step 1 of 4"; +"Scene.Report.StepOne.TheIssueDoesNotFitIntoOtherCategories" = "The issue does not fit into other categories"; +"Scene.Report.StepOne.WhatsWrongWithThisAccount" = "What's wrong with this account?"; +"Scene.Report.StepOne.WhatsWrongWithThisPost" = "What's wrong with this post?"; +"Scene.Report.StepOne.WhatsWrongWithThisUsername" = "What's wrong with %@?"; +"Scene.Report.StepOne.YouAreAwareThatItBreaksSpecificRules" = "You are aware that it breaks specific rules"; +"Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport" = "Are there any posts that back up this report?"; +"Scene.Report.StepThree.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepThree.Step3Of4" = "Step 3 of 4"; +"Scene.Report.StepTwo.IJustDon’tLikeIt" = "I just don’t like it"; +"Scene.Report.StepTwo.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepTwo.Step2Of4" = "Step 2 of 4"; +"Scene.Report.StepTwo.WhichRulesAreBeingViolated" = "Which rules are being violated?"; "Scene.Report.TextPlaceholder" = "Escribe o pega comentarios adicionales"; "Scene.Report.Title" = "Reportar %@"; "Scene.Report.TitleReport" = "Reportar"; @@ -333,6 +366,7 @@ pulsa en el enlace para confirmar tu cuenta."; "Scene.ServerPicker.EmptyState.FindingServers" = "Encontrando servidores disponibles..."; "Scene.ServerPicker.EmptyState.NoResults" = "Sin resultados"; "Scene.ServerPicker.Input.Placeholder" = "Encuentra un servidor o únete al tuyo propio..."; +"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "Search communities or enter URL"; "Scene.ServerPicker.Label.Category" = "CATEGORÍA"; "Scene.ServerPicker.Label.Language" = "IDIOMA"; "Scene.ServerPicker.Label.Users" = "USUARIOS"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.strings index e682977e9..8f2055df9 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/eu-ES.lproj/Localizable.strings @@ -211,6 +211,8 @@ sakatu kontua berresteko esteka."; "Scene.Favorite.Title" = "Zure gogokoak"; "Scene.Follower.Footer" = "Beste zerbitzarietako jarraitzaileak ez dira bistaratzen."; "Scene.Following.Footer" = "Beste zerbitzarietan jarraitutakoak ez dira bistaratzen."; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint" = "Tap to scroll to top and tap again to previous location"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Logo Button"; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Ikusi bidal. berriak"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Konexio gabe"; "Scene.HomeTimeline.NavigationBarState.Published" = "Argitaratua!"; @@ -293,6 +295,37 @@ sakatu kontua berresteko esteka."; "Scene.Report.SkipToSend" = "Bidali iruzkinik gabe"; "Scene.Report.Step1" = "1. urratsa 2tik"; "Scene.Report.Step2" = "2. urratsa 2tik"; +"Scene.Report.StepFinal.BlockUser" = "Block %@"; +"Scene.Report.StepFinal.DontWantToSeeThis" = "Don’t want to see this?"; +"Scene.Report.StepFinal.MuteUser" = "Mute %@"; +"Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked" = "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked."; +"Scene.Report.StepFinal.Unfollow" = "Unfollow"; +"Scene.Report.StepFinal.UnfollowUser" = "Unfollow %@"; +"Scene.Report.StepFinal.Unfollowed" = "Unfollowed"; +"Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience." = "When you see something you don’t like on Mastodon, you can remove the person from your experience."; +"Scene.Report.StepFinal.YouWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted" = "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted."; +"Scene.Report.StepFour.IsThereAnythingElseWeShouldKnow" = "Is there anything else we should know?"; +"Scene.Report.StepFour.Step4Of4" = "Step 4 of 4"; +"Scene.Report.StepOne.IDontLikeIt" = "I don’t like it"; +"Scene.Report.StepOne.ItIsNotSomethingYouWantToSee" = "It is not something you want to see"; +"Scene.Report.StepOne.ItViolatesServerRules" = "It violates server rules"; +"Scene.Report.StepOne.ItsSomethingElse" = "It’s something else"; +"Scene.Report.StepOne.ItsSpam" = "It’s spam"; +"Scene.Report.StepOne.MaliciousLinksFakeEngagementOrRepetetiveReplies" = "Malicious links, fake engagement, or repetetive replies"; +"Scene.Report.StepOne.SelectTheBestMatch" = "Select the best match"; +"Scene.Report.StepOne.Step1Of4" = "Step 1 of 4"; +"Scene.Report.StepOne.TheIssueDoesNotFitIntoOtherCategories" = "The issue does not fit into other categories"; +"Scene.Report.StepOne.WhatsWrongWithThisAccount" = "What's wrong with this account?"; +"Scene.Report.StepOne.WhatsWrongWithThisPost" = "What's wrong with this post?"; +"Scene.Report.StepOne.WhatsWrongWithThisUsername" = "What's wrong with %@?"; +"Scene.Report.StepOne.YouAreAwareThatItBreaksSpecificRules" = "You are aware that it breaks specific rules"; +"Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport" = "Are there any posts that back up this report?"; +"Scene.Report.StepThree.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepThree.Step3Of4" = "Step 3 of 4"; +"Scene.Report.StepTwo.IJustDon’tLikeIt" = "I just don’t like it"; +"Scene.Report.StepTwo.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepTwo.Step2Of4" = "Step 2 of 4"; +"Scene.Report.StepTwo.WhichRulesAreBeingViolated" = "Which rules are being violated?"; "Scene.Report.TextPlaceholder" = "Idatzi edo itsatsi iruzkin gehigarriak"; "Scene.Report.Title" = "Salatu %@"; "Scene.Report.TitleReport" = "Salatu"; @@ -333,6 +366,7 @@ sakatu kontua berresteko esteka."; "Scene.ServerPicker.EmptyState.FindingServers" = "Erabilgarri dauden zerbitzariak bilatzen..."; "Scene.ServerPicker.EmptyState.NoResults" = "Emaitzarik ez"; "Scene.ServerPicker.Input.Placeholder" = "Bilatu zerbitzari bat edo sortu zurea..."; +"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "Search communities or enter URL"; "Scene.ServerPicker.Label.Category" = "KATEGORIA"; "Scene.ServerPicker.Label.Language" = "HIZKUNTZA"; "Scene.ServerPicker.Label.Users" = "ERABILTZAILEAK"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.strings index 880612b29..f5c60fcb7 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/fr.lproj/Localizable.strings @@ -211,6 +211,8 @@ tapotez le lien pour confirmer votre compte."; "Scene.Favorite.Title" = "Vos favoris"; "Scene.Follower.Footer" = "Les abonné·e·s issus des autres serveurs ne sont pas affiché·e·s."; "Scene.Following.Footer" = "Les abonnés issus des autres serveurs ne sont pas affichés."; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint" = "Tap to scroll to top and tap again to previous location"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Logo Button"; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Voir les nouvelles publications"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Hors ligne"; "Scene.HomeTimeline.NavigationBarState.Published" = "Publié!"; @@ -293,6 +295,37 @@ tapotez le lien pour confirmer votre compte."; "Scene.Report.SkipToSend" = "Envoyer sans commentaire"; "Scene.Report.Step1" = "Étape 1 de 2"; "Scene.Report.Step2" = "Étape 2 de 2"; +"Scene.Report.StepFinal.BlockUser" = "Block %@"; +"Scene.Report.StepFinal.DontWantToSeeThis" = "Don’t want to see this?"; +"Scene.Report.StepFinal.MuteUser" = "Mute %@"; +"Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked" = "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked."; +"Scene.Report.StepFinal.Unfollow" = "Unfollow"; +"Scene.Report.StepFinal.UnfollowUser" = "Unfollow %@"; +"Scene.Report.StepFinal.Unfollowed" = "Unfollowed"; +"Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience." = "When you see something you don’t like on Mastodon, you can remove the person from your experience."; +"Scene.Report.StepFinal.YouWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted" = "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted."; +"Scene.Report.StepFour.IsThereAnythingElseWeShouldKnow" = "Is there anything else we should know?"; +"Scene.Report.StepFour.Step4Of4" = "Step 4 of 4"; +"Scene.Report.StepOne.IDontLikeIt" = "I don’t like it"; +"Scene.Report.StepOne.ItIsNotSomethingYouWantToSee" = "It is not something you want to see"; +"Scene.Report.StepOne.ItViolatesServerRules" = "It violates server rules"; +"Scene.Report.StepOne.ItsSomethingElse" = "It’s something else"; +"Scene.Report.StepOne.ItsSpam" = "It’s spam"; +"Scene.Report.StepOne.MaliciousLinksFakeEngagementOrRepetetiveReplies" = "Malicious links, fake engagement, or repetetive replies"; +"Scene.Report.StepOne.SelectTheBestMatch" = "Select the best match"; +"Scene.Report.StepOne.Step1Of4" = "Step 1 of 4"; +"Scene.Report.StepOne.TheIssueDoesNotFitIntoOtherCategories" = "The issue does not fit into other categories"; +"Scene.Report.StepOne.WhatsWrongWithThisAccount" = "What's wrong with this account?"; +"Scene.Report.StepOne.WhatsWrongWithThisPost" = "What's wrong with this post?"; +"Scene.Report.StepOne.WhatsWrongWithThisUsername" = "What's wrong with %@?"; +"Scene.Report.StepOne.YouAreAwareThatItBreaksSpecificRules" = "You are aware that it breaks specific rules"; +"Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport" = "Are there any posts that back up this report?"; +"Scene.Report.StepThree.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepThree.Step3Of4" = "Step 3 of 4"; +"Scene.Report.StepTwo.IJustDon’tLikeIt" = "I just don’t like it"; +"Scene.Report.StepTwo.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepTwo.Step2Of4" = "Step 2 of 4"; +"Scene.Report.StepTwo.WhichRulesAreBeingViolated" = "Which rules are being violated?"; "Scene.Report.TextPlaceholder" = "Tapez ou collez des informations supplémentaires"; "Scene.Report.Title" = "Signaler %@"; "Scene.Report.TitleReport" = "Signalement"; @@ -333,6 +366,7 @@ tapotez le lien pour confirmer votre compte."; "Scene.ServerPicker.EmptyState.FindingServers" = "Recherche des serveurs disponibles..."; "Scene.ServerPicker.EmptyState.NoResults" = "Aucun résultat"; "Scene.ServerPicker.Input.Placeholder" = "Trouvez un serveur ou rejoignez le vôtre..."; +"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "Search communities or enter URL"; "Scene.ServerPicker.Label.Category" = "CATÉGORIE"; "Scene.ServerPicker.Label.Language" = "LANGUE"; "Scene.ServerPicker.Label.Users" = "UTILISATEUR·RICE·S"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.strings index d14d7acd3..a1576bb9e 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/gd-GB.lproj/Localizable.strings @@ -211,6 +211,8 @@ thoir gnogag air a’ chunntas a dhearbhadh a’ chunntais agad."; "Scene.Favorite.Title" = "Na h-annsachdan agad"; "Scene.Follower.Footer" = "Cha dèid luchd-leantainn o fhrithealaichean eile a shealltainn."; "Scene.Following.Footer" = "Cha dèid cò air a leanas tu air frithealaichean eile a shealltainn."; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint" = "Tap to scroll to top and tap again to previous location"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Logo Button"; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Seall na postaichean ùra"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Far loidhne"; "Scene.HomeTimeline.NavigationBarState.Published" = "Chaidh fhoillseachadh!"; @@ -293,6 +295,37 @@ thoir gnogag air a’ chunntas a dhearbhadh a’ chunntais agad."; "Scene.Report.SkipToSend" = "Cuir gun bheachd ris"; "Scene.Report.Step1" = "Ceum 1 à 2"; "Scene.Report.Step2" = "Ceum 2 à 2"; +"Scene.Report.StepFinal.BlockUser" = "Block %@"; +"Scene.Report.StepFinal.DontWantToSeeThis" = "Don’t want to see this?"; +"Scene.Report.StepFinal.MuteUser" = "Mute %@"; +"Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked" = "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked."; +"Scene.Report.StepFinal.Unfollow" = "Unfollow"; +"Scene.Report.StepFinal.UnfollowUser" = "Unfollow %@"; +"Scene.Report.StepFinal.Unfollowed" = "Unfollowed"; +"Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience." = "When you see something you don’t like on Mastodon, you can remove the person from your experience."; +"Scene.Report.StepFinal.YouWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted" = "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted."; +"Scene.Report.StepFour.IsThereAnythingElseWeShouldKnow" = "Is there anything else we should know?"; +"Scene.Report.StepFour.Step4Of4" = "Step 4 of 4"; +"Scene.Report.StepOne.IDontLikeIt" = "I don’t like it"; +"Scene.Report.StepOne.ItIsNotSomethingYouWantToSee" = "It is not something you want to see"; +"Scene.Report.StepOne.ItViolatesServerRules" = "It violates server rules"; +"Scene.Report.StepOne.ItsSomethingElse" = "It’s something else"; +"Scene.Report.StepOne.ItsSpam" = "It’s spam"; +"Scene.Report.StepOne.MaliciousLinksFakeEngagementOrRepetetiveReplies" = "Malicious links, fake engagement, or repetetive replies"; +"Scene.Report.StepOne.SelectTheBestMatch" = "Select the best match"; +"Scene.Report.StepOne.Step1Of4" = "Step 1 of 4"; +"Scene.Report.StepOne.TheIssueDoesNotFitIntoOtherCategories" = "The issue does not fit into other categories"; +"Scene.Report.StepOne.WhatsWrongWithThisAccount" = "What's wrong with this account?"; +"Scene.Report.StepOne.WhatsWrongWithThisPost" = "What's wrong with this post?"; +"Scene.Report.StepOne.WhatsWrongWithThisUsername" = "What's wrong with %@?"; +"Scene.Report.StepOne.YouAreAwareThatItBreaksSpecificRules" = "You are aware that it breaks specific rules"; +"Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport" = "Are there any posts that back up this report?"; +"Scene.Report.StepThree.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepThree.Step3Of4" = "Step 3 of 4"; +"Scene.Report.StepTwo.IJustDon’tLikeIt" = "I just don’t like it"; +"Scene.Report.StepTwo.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepTwo.Step2Of4" = "Step 2 of 4"; +"Scene.Report.StepTwo.WhichRulesAreBeingViolated" = "Which rules are being violated?"; "Scene.Report.TextPlaceholder" = "Sgrìobh no cuir ann beachdan a bharrachd"; "Scene.Report.Title" = "Dèan gearan mu %@"; "Scene.Report.TitleReport" = "Dèan gearan"; @@ -333,6 +366,7 @@ thoir gnogag air a’ chunntas a dhearbhadh a’ chunntais agad."; "Scene.ServerPicker.EmptyState.FindingServers" = "A’ lorg nam frithealaichean ri am faighinn…"; "Scene.ServerPicker.EmptyState.NoResults" = "Gun toradh"; "Scene.ServerPicker.Input.Placeholder" = "Lorg frithealaiche no gabh pàirt san fhear agad fhèin…"; +"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "Search communities or enter URL"; "Scene.ServerPicker.Label.Category" = "ROINN-SEÒRSA"; "Scene.ServerPicker.Label.Language" = "CÀNAN"; "Scene.ServerPicker.Label.Users" = "CLEACHDAICHEAN"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/gl.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/gl.lproj/Localizable.strings index 35fe4066d..9aa918938 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/gl.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/gl.lproj/Localizable.strings @@ -210,6 +210,8 @@ ser subido a Mastodon."; "Scene.Favorite.Title" = "Publicacións Favoritas"; "Scene.Follower.Footer" = "Non se mostran seguidoras desde outros servidores."; "Scene.Following.Footer" = "Non se mostran os seguimentos desde outros servidores."; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint" = "Tap to scroll to top and tap again to previous location"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Logo Button"; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Novas publicacións"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Sen conexión"; "Scene.HomeTimeline.NavigationBarState.Published" = "Publicado!"; @@ -292,6 +294,37 @@ ser subido a Mastodon."; "Scene.Report.SkipToSend" = "Enviar sen comentarios"; "Scene.Report.Step1" = "Paso 1 de 2"; "Scene.Report.Step2" = "Paso 2 de 2"; +"Scene.Report.StepFinal.BlockUser" = "Block %@"; +"Scene.Report.StepFinal.DontWantToSeeThis" = "Don’t want to see this?"; +"Scene.Report.StepFinal.MuteUser" = "Mute %@"; +"Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked" = "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked."; +"Scene.Report.StepFinal.Unfollow" = "Unfollow"; +"Scene.Report.StepFinal.UnfollowUser" = "Unfollow %@"; +"Scene.Report.StepFinal.Unfollowed" = "Unfollowed"; +"Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience." = "When you see something you don’t like on Mastodon, you can remove the person from your experience."; +"Scene.Report.StepFinal.YouWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted" = "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted."; +"Scene.Report.StepFour.IsThereAnythingElseWeShouldKnow" = "Is there anything else we should know?"; +"Scene.Report.StepFour.Step4Of4" = "Step 4 of 4"; +"Scene.Report.StepOne.IDontLikeIt" = "I don’t like it"; +"Scene.Report.StepOne.ItIsNotSomethingYouWantToSee" = "It is not something you want to see"; +"Scene.Report.StepOne.ItViolatesServerRules" = "It violates server rules"; +"Scene.Report.StepOne.ItsSomethingElse" = "It’s something else"; +"Scene.Report.StepOne.ItsSpam" = "It’s spam"; +"Scene.Report.StepOne.MaliciousLinksFakeEngagementOrRepetetiveReplies" = "Malicious links, fake engagement, or repetetive replies"; +"Scene.Report.StepOne.SelectTheBestMatch" = "Select the best match"; +"Scene.Report.StepOne.Step1Of4" = "Step 1 of 4"; +"Scene.Report.StepOne.TheIssueDoesNotFitIntoOtherCategories" = "The issue does not fit into other categories"; +"Scene.Report.StepOne.WhatsWrongWithThisAccount" = "What's wrong with this account?"; +"Scene.Report.StepOne.WhatsWrongWithThisPost" = "What's wrong with this post?"; +"Scene.Report.StepOne.WhatsWrongWithThisUsername" = "What's wrong with %@?"; +"Scene.Report.StepOne.YouAreAwareThatItBreaksSpecificRules" = "You are aware that it breaks specific rules"; +"Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport" = "Are there any posts that back up this report?"; +"Scene.Report.StepThree.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepThree.Step3Of4" = "Step 3 of 4"; +"Scene.Report.StepTwo.IJustDon’tLikeIt" = "I just don’t like it"; +"Scene.Report.StepTwo.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepTwo.Step2Of4" = "Step 2 of 4"; +"Scene.Report.StepTwo.WhichRulesAreBeingViolated" = "Which rules are being violated?"; "Scene.Report.TextPlaceholder" = "Escribe ou pega comentarios adicionais"; "Scene.Report.Title" = "Denunciar a %@"; "Scene.Report.TitleReport" = "Denunciar"; @@ -332,6 +365,7 @@ ser subido a Mastodon."; "Scene.ServerPicker.EmptyState.FindingServers" = "Buscando servidores dispoñibles..."; "Scene.ServerPicker.EmptyState.NoResults" = "Sen resultados"; "Scene.ServerPicker.Input.Placeholder" = "Buscar comunidades"; +"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "Search communities or enter URL"; "Scene.ServerPicker.Label.Category" = "CATEGORÍA"; "Scene.ServerPicker.Label.Language" = "IDIOMA"; "Scene.ServerPicker.Label.Users" = "USUARIAS"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/it.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/it.lproj/Localizable.strings index 8a80b11da..38b0ed65d 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/it.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/it.lproj/Localizable.strings @@ -210,6 +210,8 @@ caricato su Mastodon."; "Scene.Favorite.Title" = "I tuoi preferiti"; "Scene.Follower.Footer" = "I seguaci da altri server non vengono visualizzati."; "Scene.Following.Footer" = "I follow da altri server non vengono visualizzati."; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint" = "Tocca per scorrere verso l'alto e tocca di nuovo verso la posizione precedente"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Pulsante Logo"; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Vedi nuovi post"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Non in linea"; "Scene.HomeTimeline.NavigationBarState.Published" = "Pubblicato!"; @@ -292,6 +294,37 @@ caricato su Mastodon."; "Scene.Report.SkipToSend" = "Invia senza commento"; "Scene.Report.Step1" = "Fase 1 di 2"; "Scene.Report.Step2" = "Fase 2 di 2"; +"Scene.Report.StepFinal.BlockUser" = "Blocca %@"; +"Scene.Report.StepFinal.DontWantToSeeThis" = "Non vuoi vedere questo?"; +"Scene.Report.StepFinal.MuteUser" = "Silenzia %@"; +"Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked" = "Non saranno più in grado di seguire o vedere i tuoi post, ma possono vedere se sono stati bloccati."; +"Scene.Report.StepFinal.Unfollow" = "Smetti di seguire"; +"Scene.Report.StepFinal.UnfollowUser" = "Smetti di seguire %@"; +"Scene.Report.StepFinal.Unfollowed" = "Non seguito"; +"Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience." = "Quando vedi qualcosa che non ti piace su Mastodon, puoi rimuovere la persona dalla tua esperienza."; +"Scene.Report.StepFinal.YouWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted" = "Non vedrai i loro post o le condivisioni nel tuo feed. Non sapranno di essere stati silenziati."; +"Scene.Report.StepFour.IsThereAnythingElseWeShouldKnow" = "C'è altro che dovremmo sapere?"; +"Scene.Report.StepFour.Step4Of4" = "Fase 4 di 4"; +"Scene.Report.StepOne.IDontLikeIt" = "Non mi piace"; +"Scene.Report.StepOne.ItIsNotSomethingYouWantToSee" = "È qualcosa che non vuoi vedere"; +"Scene.Report.StepOne.ItViolatesServerRules" = "Viola le regole del server"; +"Scene.Report.StepOne.ItsSomethingElse" = "È qualcos'altro"; +"Scene.Report.StepOne.ItsSpam" = "È spam"; +"Scene.Report.StepOne.MaliciousLinksFakeEngagementOrRepetetiveReplies" = "Collegamenti malevoli, false interazioni o risposte ripetitive"; +"Scene.Report.StepOne.SelectTheBestMatch" = "Scegli la migliore corrispondenza"; +"Scene.Report.StepOne.Step1Of4" = "Fase 1 di 4"; +"Scene.Report.StepOne.TheIssueDoesNotFitIntoOtherCategories" = "Il problema non rientra in altre categorie"; +"Scene.Report.StepOne.WhatsWrongWithThisAccount" = "Cosa c'è che non va con questo account?"; +"Scene.Report.StepOne.WhatsWrongWithThisPost" = "Cosa c'è che non va con questo post?"; +"Scene.Report.StepOne.WhatsWrongWithThisUsername" = "Cosa c'è che non va con %@?"; +"Scene.Report.StepOne.YouAreAwareThatItBreaksSpecificRules" = "Sei consapevole che violi regole specifiche"; +"Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport" = "Ci sono post a sostegno di questa segnalazione?"; +"Scene.Report.StepThree.SelectAllThatApply" = "Seleziona tutte le risposte pertinenti"; +"Scene.Report.StepThree.Step3Of4" = "Fase 3 di 4"; +"Scene.Report.StepTwo.IJustDon’tLikeIt" = "Non mi piace"; +"Scene.Report.StepTwo.SelectAllThatApply" = "Seleziona tutte le risposte pertinenti"; +"Scene.Report.StepTwo.Step2Of4" = "Fase 2 di 4"; +"Scene.Report.StepTwo.WhichRulesAreBeingViolated" = "Quali regole vengono violate?"; "Scene.Report.TextPlaceholder" = "Digita o incolla commenti aggiuntivi"; "Scene.Report.Title" = "Segnala %@"; "Scene.Report.TitleReport" = "Segnala"; @@ -332,6 +365,7 @@ caricato su Mastodon."; "Scene.ServerPicker.EmptyState.FindingServers" = "Ricerca server disponibili..."; "Scene.ServerPicker.EmptyState.NoResults" = "Nessun risultato"; "Scene.ServerPicker.Input.Placeholder" = "Cerca comunità"; +"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "Cerca comunità o inserisci l'URL"; "Scene.ServerPicker.Label.Category" = "CATEGORIA"; "Scene.ServerPicker.Label.Language" = "LINGUA"; "Scene.ServerPicker.Label.Users" = "UTENTI"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings index 015a88551..d746c1962 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ja.lproj/Localizable.strings @@ -205,6 +205,8 @@ "Scene.Favorite.Title" = "お気に入り"; "Scene.Follower.Footer" = "他のサーバーからのフォロワーは表示されません。"; "Scene.Following.Footer" = "他のサーバーにいるフォローは表示されません。"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint" = "Tap to scroll to top and tap again to previous location"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Logo Button"; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "新しい投稿を見る"; "Scene.HomeTimeline.NavigationBarState.Offline" = "オフライン"; "Scene.HomeTimeline.NavigationBarState.Published" = "投稿しました!"; @@ -287,6 +289,37 @@ "Scene.Report.SkipToSend" = "コメントなしで送信"; "Scene.Report.Step1" = "ステップ 1/2"; "Scene.Report.Step2" = "ステップ 2/2"; +"Scene.Report.StepFinal.BlockUser" = "Block %@"; +"Scene.Report.StepFinal.DontWantToSeeThis" = "Don’t want to see this?"; +"Scene.Report.StepFinal.MuteUser" = "Mute %@"; +"Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked" = "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked."; +"Scene.Report.StepFinal.Unfollow" = "Unfollow"; +"Scene.Report.StepFinal.UnfollowUser" = "Unfollow %@"; +"Scene.Report.StepFinal.Unfollowed" = "Unfollowed"; +"Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience." = "When you see something you don’t like on Mastodon, you can remove the person from your experience."; +"Scene.Report.StepFinal.YouWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted" = "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted."; +"Scene.Report.StepFour.IsThereAnythingElseWeShouldKnow" = "Is there anything else we should know?"; +"Scene.Report.StepFour.Step4Of4" = "Step 4 of 4"; +"Scene.Report.StepOne.IDontLikeIt" = "I don’t like it"; +"Scene.Report.StepOne.ItIsNotSomethingYouWantToSee" = "It is not something you want to see"; +"Scene.Report.StepOne.ItViolatesServerRules" = "It violates server rules"; +"Scene.Report.StepOne.ItsSomethingElse" = "It’s something else"; +"Scene.Report.StepOne.ItsSpam" = "It’s spam"; +"Scene.Report.StepOne.MaliciousLinksFakeEngagementOrRepetetiveReplies" = "Malicious links, fake engagement, or repetetive replies"; +"Scene.Report.StepOne.SelectTheBestMatch" = "Select the best match"; +"Scene.Report.StepOne.Step1Of4" = "Step 1 of 4"; +"Scene.Report.StepOne.TheIssueDoesNotFitIntoOtherCategories" = "The issue does not fit into other categories"; +"Scene.Report.StepOne.WhatsWrongWithThisAccount" = "What's wrong with this account?"; +"Scene.Report.StepOne.WhatsWrongWithThisPost" = "What's wrong with this post?"; +"Scene.Report.StepOne.WhatsWrongWithThisUsername" = "What's wrong with %@?"; +"Scene.Report.StepOne.YouAreAwareThatItBreaksSpecificRules" = "You are aware that it breaks specific rules"; +"Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport" = "Are there any posts that back up this report?"; +"Scene.Report.StepThree.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepThree.Step3Of4" = "Step 3 of 4"; +"Scene.Report.StepTwo.IJustDon’tLikeIt" = "I just don’t like it"; +"Scene.Report.StepTwo.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepTwo.Step2Of4" = "Step 2 of 4"; +"Scene.Report.StepTwo.WhichRulesAreBeingViolated" = "Which rules are being violated?"; "Scene.Report.TextPlaceholder" = "追加コメントを入力"; "Scene.Report.Title" = "%@を通報"; "Scene.Report.TitleReport" = "報告する"; @@ -327,6 +360,7 @@ "Scene.ServerPicker.EmptyState.FindingServers" = "利用可能なサーバーの検索..."; "Scene.ServerPicker.EmptyState.NoResults" = "なし"; "Scene.ServerPicker.Input.Placeholder" = "サーバーを探す"; +"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "Search communities or enter URL"; "Scene.ServerPicker.Label.Category" = "カテゴリー"; "Scene.ServerPicker.Label.Language" = "言語"; "Scene.ServerPicker.Label.Users" = "ユーザー"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.strings index 3ea1700cd..bbc9856c3 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/kab.lproj/Localizable.strings @@ -210,6 +210,8 @@ Ad d-yettwasali ɣef Mastodon."; "Scene.Favorite.Title" = "Ismenyifen-ik·im"; "Scene.Follower.Footer" = "Ineḍfaren seg yiqeddacen-nniḍen ur d-ttwaskanen ara."; "Scene.Following.Footer" = "Ineḍfaren seg yiqeddacen-nniḍen ur d-ttwaskanen ara."; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint" = "Tap to scroll to top and tap again to previous location"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Logo Button"; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Tissufaɣ timaynutin"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Beṛṛa n tuqqna"; "Scene.HomeTimeline.NavigationBarState.Published" = "Yettwasuffeɣ!"; @@ -292,6 +294,37 @@ Ad d-yettwasali ɣef Mastodon."; "Scene.Report.SkipToSend" = "Azen s war awennit"; "Scene.Report.Step1" = "Aḥric 1 seg 2"; "Scene.Report.Step2" = "Aḥric 2 seg 2"; +"Scene.Report.StepFinal.BlockUser" = "Block %@"; +"Scene.Report.StepFinal.DontWantToSeeThis" = "Don’t want to see this?"; +"Scene.Report.StepFinal.MuteUser" = "Mute %@"; +"Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked" = "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked."; +"Scene.Report.StepFinal.Unfollow" = "Unfollow"; +"Scene.Report.StepFinal.UnfollowUser" = "Unfollow %@"; +"Scene.Report.StepFinal.Unfollowed" = "Unfollowed"; +"Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience." = "When you see something you don’t like on Mastodon, you can remove the person from your experience."; +"Scene.Report.StepFinal.YouWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted" = "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted."; +"Scene.Report.StepFour.IsThereAnythingElseWeShouldKnow" = "Is there anything else we should know?"; +"Scene.Report.StepFour.Step4Of4" = "Step 4 of 4"; +"Scene.Report.StepOne.IDontLikeIt" = "I don’t like it"; +"Scene.Report.StepOne.ItIsNotSomethingYouWantToSee" = "It is not something you want to see"; +"Scene.Report.StepOne.ItViolatesServerRules" = "It violates server rules"; +"Scene.Report.StepOne.ItsSomethingElse" = "It’s something else"; +"Scene.Report.StepOne.ItsSpam" = "It’s spam"; +"Scene.Report.StepOne.MaliciousLinksFakeEngagementOrRepetetiveReplies" = "Malicious links, fake engagement, or repetetive replies"; +"Scene.Report.StepOne.SelectTheBestMatch" = "Select the best match"; +"Scene.Report.StepOne.Step1Of4" = "Step 1 of 4"; +"Scene.Report.StepOne.TheIssueDoesNotFitIntoOtherCategories" = "The issue does not fit into other categories"; +"Scene.Report.StepOne.WhatsWrongWithThisAccount" = "What's wrong with this account?"; +"Scene.Report.StepOne.WhatsWrongWithThisPost" = "What's wrong with this post?"; +"Scene.Report.StepOne.WhatsWrongWithThisUsername" = "What's wrong with %@?"; +"Scene.Report.StepOne.YouAreAwareThatItBreaksSpecificRules" = "You are aware that it breaks specific rules"; +"Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport" = "Are there any posts that back up this report?"; +"Scene.Report.StepThree.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepThree.Step3Of4" = "Step 3 of 4"; +"Scene.Report.StepTwo.IJustDon’tLikeIt" = "I just don’t like it"; +"Scene.Report.StepTwo.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepTwo.Step2Of4" = "Step 2 of 4"; +"Scene.Report.StepTwo.WhichRulesAreBeingViolated" = "Which rules are being violated?"; "Scene.Report.TextPlaceholder" = "Aru neɣ senteḍ iwenniten-nniḍen"; "Scene.Report.Title" = "Aneqqis %@"; "Scene.Report.TitleReport" = "Aneqqis"; @@ -332,6 +365,7 @@ Ad d-yettwasali ɣef Mastodon."; "Scene.ServerPicker.EmptyState.FindingServers" = "Tifin n yiqeddacen yellan..."; "Scene.ServerPicker.EmptyState.NoResults" = "Ulac igemmaḍ"; "Scene.ServerPicker.Input.Placeholder" = "Nadi timɣiwnin"; +"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "Search communities or enter URL"; "Scene.ServerPicker.Label.Category" = "TAGGAYT"; "Scene.ServerPicker.Label.Language" = "TUTLAYT"; "Scene.ServerPicker.Label.Users" = "ISEQDACEN"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings index f9c237770..6f46f990d 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ku.lproj/Localizable.strings @@ -211,6 +211,8 @@ girêdanê bitikne da ku ajimêra xwe bidî piştrastkirin."; "Scene.Favorite.Title" = "Bijarteyên te"; "Scene.Follower.Footer" = "Şopîner ji rajekerên din nayê dîtin."; "Scene.Following.Footer" = "Şopandin ji rajekerên din nayê dîtin."; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint" = "Tap to scroll to top and tap again to previous location"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Logo Button"; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Şandiyên nû bibîne"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Derhêl"; "Scene.HomeTimeline.NavigationBarState.Published" = "Hate weşandin!"; @@ -293,6 +295,37 @@ girêdanê bitikne da ku ajimêra xwe bidî piştrastkirin."; "Scene.Report.SkipToSend" = "Bêyî şirove bişîne"; "Scene.Report.Step1" = "Gav 1 ji 2"; "Scene.Report.Step2" = "Gav 2 ji 2"; +"Scene.Report.StepFinal.BlockUser" = "Block %@"; +"Scene.Report.StepFinal.DontWantToSeeThis" = "Don’t want to see this?"; +"Scene.Report.StepFinal.MuteUser" = "Mute %@"; +"Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked" = "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked."; +"Scene.Report.StepFinal.Unfollow" = "Unfollow"; +"Scene.Report.StepFinal.UnfollowUser" = "Unfollow %@"; +"Scene.Report.StepFinal.Unfollowed" = "Unfollowed"; +"Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience." = "When you see something you don’t like on Mastodon, you can remove the person from your experience."; +"Scene.Report.StepFinal.YouWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted" = "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted."; +"Scene.Report.StepFour.IsThereAnythingElseWeShouldKnow" = "Is there anything else we should know?"; +"Scene.Report.StepFour.Step4Of4" = "Step 4 of 4"; +"Scene.Report.StepOne.IDontLikeIt" = "I don’t like it"; +"Scene.Report.StepOne.ItIsNotSomethingYouWantToSee" = "It is not something you want to see"; +"Scene.Report.StepOne.ItViolatesServerRules" = "It violates server rules"; +"Scene.Report.StepOne.ItsSomethingElse" = "It’s something else"; +"Scene.Report.StepOne.ItsSpam" = "It’s spam"; +"Scene.Report.StepOne.MaliciousLinksFakeEngagementOrRepetetiveReplies" = "Malicious links, fake engagement, or repetetive replies"; +"Scene.Report.StepOne.SelectTheBestMatch" = "Select the best match"; +"Scene.Report.StepOne.Step1Of4" = "Step 1 of 4"; +"Scene.Report.StepOne.TheIssueDoesNotFitIntoOtherCategories" = "The issue does not fit into other categories"; +"Scene.Report.StepOne.WhatsWrongWithThisAccount" = "What's wrong with this account?"; +"Scene.Report.StepOne.WhatsWrongWithThisPost" = "What's wrong with this post?"; +"Scene.Report.StepOne.WhatsWrongWithThisUsername" = "What's wrong with %@?"; +"Scene.Report.StepOne.YouAreAwareThatItBreaksSpecificRules" = "You are aware that it breaks specific rules"; +"Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport" = "Are there any posts that back up this report?"; +"Scene.Report.StepThree.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepThree.Step3Of4" = "Step 3 of 4"; +"Scene.Report.StepTwo.IJustDon’tLikeIt" = "I just don’t like it"; +"Scene.Report.StepTwo.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepTwo.Step2Of4" = "Step 2 of 4"; +"Scene.Report.StepTwo.WhichRulesAreBeingViolated" = "Which rules are being violated?"; "Scene.Report.TextPlaceholder" = "Şiroveyên daxwazkirê binivîsine an jî pê ve bike"; "Scene.Report.Title" = "%@ ragihîne"; "Scene.Report.TitleReport" = "Ragihandin"; @@ -333,6 +366,7 @@ girêdanê bitikne da ku ajimêra xwe bidî piştrastkirin."; "Scene.ServerPicker.EmptyState.FindingServers" = "Peydakirina rajekarên berdest..."; "Scene.ServerPicker.EmptyState.NoResults" = "Encam tune"; "Scene.ServerPicker.Input.Placeholder" = "Li rajekaran bigere"; +"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "Search communities or enter URL"; "Scene.ServerPicker.Label.Category" = "BEŞ"; "Scene.ServerPicker.Label.Language" = "ZIMAN"; "Scene.ServerPicker.Label.Users" = "BIKARHÊNER"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.strings index 63586def9..f0b5eb42d 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/nl.lproj/Localizable.strings @@ -205,6 +205,8 @@ klik op de link om uw account te bevestigen."; "Scene.Favorite.Title" = "Uw favorieten"; "Scene.Follower.Footer" = "Volgers van andere servers worden niet weergegeven."; "Scene.Following.Footer" = "Volgers van andere servers worden niet weergegeven."; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint" = "Tap to scroll to top and tap again to previous location"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Logo Button"; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Bekijk nieuwe berichten"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Offline"; "Scene.HomeTimeline.NavigationBarState.Published" = "Gepubliceerd!"; @@ -287,6 +289,37 @@ klik op de link om uw account te bevestigen."; "Scene.Report.SkipToSend" = "Verstuur zonder opmerkingen"; "Scene.Report.Step1" = "Stap 1 van 2"; "Scene.Report.Step2" = "Stap 2 van 2"; +"Scene.Report.StepFinal.BlockUser" = "Block %@"; +"Scene.Report.StepFinal.DontWantToSeeThis" = "Don’t want to see this?"; +"Scene.Report.StepFinal.MuteUser" = "Mute %@"; +"Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked" = "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked."; +"Scene.Report.StepFinal.Unfollow" = "Unfollow"; +"Scene.Report.StepFinal.UnfollowUser" = "Unfollow %@"; +"Scene.Report.StepFinal.Unfollowed" = "Unfollowed"; +"Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience." = "When you see something you don’t like on Mastodon, you can remove the person from your experience."; +"Scene.Report.StepFinal.YouWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted" = "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted."; +"Scene.Report.StepFour.IsThereAnythingElseWeShouldKnow" = "Is there anything else we should know?"; +"Scene.Report.StepFour.Step4Of4" = "Step 4 of 4"; +"Scene.Report.StepOne.IDontLikeIt" = "I don’t like it"; +"Scene.Report.StepOne.ItIsNotSomethingYouWantToSee" = "It is not something you want to see"; +"Scene.Report.StepOne.ItViolatesServerRules" = "It violates server rules"; +"Scene.Report.StepOne.ItsSomethingElse" = "It’s something else"; +"Scene.Report.StepOne.ItsSpam" = "It’s spam"; +"Scene.Report.StepOne.MaliciousLinksFakeEngagementOrRepetetiveReplies" = "Malicious links, fake engagement, or repetetive replies"; +"Scene.Report.StepOne.SelectTheBestMatch" = "Select the best match"; +"Scene.Report.StepOne.Step1Of4" = "Step 1 of 4"; +"Scene.Report.StepOne.TheIssueDoesNotFitIntoOtherCategories" = "The issue does not fit into other categories"; +"Scene.Report.StepOne.WhatsWrongWithThisAccount" = "What's wrong with this account?"; +"Scene.Report.StepOne.WhatsWrongWithThisPost" = "What's wrong with this post?"; +"Scene.Report.StepOne.WhatsWrongWithThisUsername" = "What's wrong with %@?"; +"Scene.Report.StepOne.YouAreAwareThatItBreaksSpecificRules" = "You are aware that it breaks specific rules"; +"Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport" = "Are there any posts that back up this report?"; +"Scene.Report.StepThree.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepThree.Step3Of4" = "Step 3 of 4"; +"Scene.Report.StepTwo.IJustDon’tLikeIt" = "I just don’t like it"; +"Scene.Report.StepTwo.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepTwo.Step2Of4" = "Step 2 of 4"; +"Scene.Report.StepTwo.WhichRulesAreBeingViolated" = "Which rules are being violated?"; "Scene.Report.TextPlaceholder" = "Schrijf of plak aanvullende opmerkingen"; "Scene.Report.Title" = "Rapporteer %@"; "Scene.Report.TitleReport" = "Rapporteer"; @@ -327,6 +360,7 @@ klik op de link om uw account te bevestigen."; "Scene.ServerPicker.EmptyState.FindingServers" = "Beschikbare servers zoeken..."; "Scene.ServerPicker.EmptyState.NoResults" = "Geen resultaten"; "Scene.ServerPicker.Input.Placeholder" = "Zoek uw server of sluit u bij een nieuwe server aan..."; +"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "Search communities or enter URL"; "Scene.ServerPicker.Label.Category" = "CATEGORIE"; "Scene.ServerPicker.Label.Language" = "TAAL"; "Scene.ServerPicker.Label.Users" = "GEBRUIKERS"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings index 7353b6209..ba32a979e 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/ru.lproj/Localizable.strings @@ -221,6 +221,8 @@ "Scene.Favorite.Title" = "Ваше избранное"; "Scene.Follower.Footer" = "Followers from other servers are not displayed."; "Scene.Following.Footer" = "Follows from other servers are not displayed."; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint" = "Tap to scroll to top and tap again to previous location"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Logo Button"; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Показать новые"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Не в сети"; "Scene.HomeTimeline.NavigationBarState.Published" = "Опубликовано!"; @@ -303,6 +305,37 @@ "Scene.Report.SkipToSend" = "Отправить без комментария"; "Scene.Report.Step1" = "Шаг 1 из 2"; "Scene.Report.Step2" = "Шаг 2 из 2"; +"Scene.Report.StepFinal.BlockUser" = "Block %@"; +"Scene.Report.StepFinal.DontWantToSeeThis" = "Don’t want to see this?"; +"Scene.Report.StepFinal.MuteUser" = "Mute %@"; +"Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked" = "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked."; +"Scene.Report.StepFinal.Unfollow" = "Unfollow"; +"Scene.Report.StepFinal.UnfollowUser" = "Unfollow %@"; +"Scene.Report.StepFinal.Unfollowed" = "Unfollowed"; +"Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience." = "When you see something you don’t like on Mastodon, you can remove the person from your experience."; +"Scene.Report.StepFinal.YouWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted" = "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted."; +"Scene.Report.StepFour.IsThereAnythingElseWeShouldKnow" = "Is there anything else we should know?"; +"Scene.Report.StepFour.Step4Of4" = "Step 4 of 4"; +"Scene.Report.StepOne.IDontLikeIt" = "I don’t like it"; +"Scene.Report.StepOne.ItIsNotSomethingYouWantToSee" = "It is not something you want to see"; +"Scene.Report.StepOne.ItViolatesServerRules" = "It violates server rules"; +"Scene.Report.StepOne.ItsSomethingElse" = "It’s something else"; +"Scene.Report.StepOne.ItsSpam" = "It’s spam"; +"Scene.Report.StepOne.MaliciousLinksFakeEngagementOrRepetetiveReplies" = "Malicious links, fake engagement, or repetetive replies"; +"Scene.Report.StepOne.SelectTheBestMatch" = "Select the best match"; +"Scene.Report.StepOne.Step1Of4" = "Step 1 of 4"; +"Scene.Report.StepOne.TheIssueDoesNotFitIntoOtherCategories" = "The issue does not fit into other categories"; +"Scene.Report.StepOne.WhatsWrongWithThisAccount" = "What's wrong with this account?"; +"Scene.Report.StepOne.WhatsWrongWithThisPost" = "What's wrong with this post?"; +"Scene.Report.StepOne.WhatsWrongWithThisUsername" = "What's wrong with %@?"; +"Scene.Report.StepOne.YouAreAwareThatItBreaksSpecificRules" = "You are aware that it breaks specific rules"; +"Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport" = "Are there any posts that back up this report?"; +"Scene.Report.StepThree.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepThree.Step3Of4" = "Step 3 of 4"; +"Scene.Report.StepTwo.IJustDon’tLikeIt" = "I just don’t like it"; +"Scene.Report.StepTwo.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepTwo.Step2Of4" = "Step 2 of 4"; +"Scene.Report.StepTwo.WhichRulesAreBeingViolated" = "Which rules are being violated?"; "Scene.Report.TextPlaceholder" = "Дополнительные комментарии"; "Scene.Report.Title" = "Пожаловаться на %@"; "Scene.Report.TitleReport" = "Жалоба"; @@ -343,6 +376,7 @@ "Scene.ServerPicker.EmptyState.FindingServers" = "Ищем доступные сервера..."; "Scene.ServerPicker.EmptyState.NoResults" = "Нет результатов"; "Scene.ServerPicker.Input.Placeholder" = "Найдите сервер или присоединитесь к своему..."; +"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "Search communities or enter URL"; "Scene.ServerPicker.Label.Category" = "КАТЕГОРИЯ"; "Scene.ServerPicker.Label.Language" = "ЯЗЫК"; "Scene.ServerPicker.Label.Users" = "ПОЛЬЗОВАТЕЛИ"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings index ef723027d..204700321 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/th.lproj/Localizable.strings @@ -210,6 +210,8 @@ "Scene.Favorite.Title" = "รายการโปรดของคุณ"; "Scene.Follower.Footer" = "ไม่ได้แสดงผู้ติดตามจากเซิร์ฟเวอร์อื่น ๆ"; "Scene.Following.Footer" = "ไม่ได้แสดงการติดตามจากเซิร์ฟเวอร์อื่น ๆ"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint" = "Tap to scroll to top and tap again to previous location"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Logo Button"; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "ดูโพสต์ใหม่"; "Scene.HomeTimeline.NavigationBarState.Offline" = "ออฟไลน์"; "Scene.HomeTimeline.NavigationBarState.Published" = "เผยแพร่แล้ว!"; @@ -292,6 +294,37 @@ "Scene.Report.SkipToSend" = "ส่งโดยไม่มีความคิดเห็น"; "Scene.Report.Step1" = "ขั้นตอนที่ 1 จาก 2"; "Scene.Report.Step2" = "ขั้นตอนที่ 2 จาก 2"; +"Scene.Report.StepFinal.BlockUser" = "Block %@"; +"Scene.Report.StepFinal.DontWantToSeeThis" = "Don’t want to see this?"; +"Scene.Report.StepFinal.MuteUser" = "Mute %@"; +"Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked" = "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked."; +"Scene.Report.StepFinal.Unfollow" = "Unfollow"; +"Scene.Report.StepFinal.UnfollowUser" = "Unfollow %@"; +"Scene.Report.StepFinal.Unfollowed" = "Unfollowed"; +"Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience." = "When you see something you don’t like on Mastodon, you can remove the person from your experience."; +"Scene.Report.StepFinal.YouWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted" = "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted."; +"Scene.Report.StepFour.IsThereAnythingElseWeShouldKnow" = "Is there anything else we should know?"; +"Scene.Report.StepFour.Step4Of4" = "Step 4 of 4"; +"Scene.Report.StepOne.IDontLikeIt" = "I don’t like it"; +"Scene.Report.StepOne.ItIsNotSomethingYouWantToSee" = "It is not something you want to see"; +"Scene.Report.StepOne.ItViolatesServerRules" = "It violates server rules"; +"Scene.Report.StepOne.ItsSomethingElse" = "It’s something else"; +"Scene.Report.StepOne.ItsSpam" = "It’s spam"; +"Scene.Report.StepOne.MaliciousLinksFakeEngagementOrRepetetiveReplies" = "Malicious links, fake engagement, or repetetive replies"; +"Scene.Report.StepOne.SelectTheBestMatch" = "Select the best match"; +"Scene.Report.StepOne.Step1Of4" = "Step 1 of 4"; +"Scene.Report.StepOne.TheIssueDoesNotFitIntoOtherCategories" = "The issue does not fit into other categories"; +"Scene.Report.StepOne.WhatsWrongWithThisAccount" = "What's wrong with this account?"; +"Scene.Report.StepOne.WhatsWrongWithThisPost" = "What's wrong with this post?"; +"Scene.Report.StepOne.WhatsWrongWithThisUsername" = "What's wrong with %@?"; +"Scene.Report.StepOne.YouAreAwareThatItBreaksSpecificRules" = "You are aware that it breaks specific rules"; +"Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport" = "Are there any posts that back up this report?"; +"Scene.Report.StepThree.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepThree.Step3Of4" = "Step 3 of 4"; +"Scene.Report.StepTwo.IJustDon’tLikeIt" = "I just don’t like it"; +"Scene.Report.StepTwo.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepTwo.Step2Of4" = "Step 2 of 4"; +"Scene.Report.StepTwo.WhichRulesAreBeingViolated" = "Which rules are being violated?"; "Scene.Report.TextPlaceholder" = "พิมพ์หรือวางความคิดเห็นเพิ่มเติม"; "Scene.Report.Title" = "รายงาน %@"; "Scene.Report.TitleReport" = "รายงาน"; @@ -332,6 +365,7 @@ "Scene.ServerPicker.EmptyState.FindingServers" = "กำลังค้นหาเซิร์ฟเวอร์ที่พร้อมใช้งาน..."; "Scene.ServerPicker.EmptyState.NoResults" = "ไม่มีผลลัพธ์"; "Scene.ServerPicker.Input.Placeholder" = "ค้นหาเซิร์ฟเวอร์"; +"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "Search communities or enter URL"; "Scene.ServerPicker.Label.Category" = "หมวดหมู่"; "Scene.ServerPicker.Label.Language" = "ภาษา"; "Scene.ServerPicker.Label.Users" = "ผู้ใช้"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/tr.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/tr.lproj/Localizable.strings index 887fa0641..9467072f6 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/tr.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/tr.lproj/Localizable.strings @@ -209,6 +209,8 @@ yüklenemiyor."; "Scene.Favorite.Title" = "Favorilerin"; "Scene.Follower.Footer" = "Diğer sunucudaki takipçiler gösterilemiyor."; "Scene.Following.Footer" = "Diğer sunucudaki takip edilenler gösterilemiyor."; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint" = "Tap to scroll to top and tap again to previous location"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Logo Button"; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Yeni gönderiler gör"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Çevrimdışı"; "Scene.HomeTimeline.NavigationBarState.Published" = "Yayınlandı!"; @@ -291,6 +293,37 @@ yüklenemiyor."; "Scene.Report.SkipToSend" = "Yorum yapmadan gönder"; "Scene.Report.Step1" = "Adım 1/2"; "Scene.Report.Step2" = "Adım 2/2"; +"Scene.Report.StepFinal.BlockUser" = "Block %@"; +"Scene.Report.StepFinal.DontWantToSeeThis" = "Bunu görmek istemiyor musunuz?"; +"Scene.Report.StepFinal.MuteUser" = "Mute %@"; +"Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked" = "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked."; +"Scene.Report.StepFinal.Unfollow" = "Takibi bırak"; +"Scene.Report.StepFinal.UnfollowUser" = "Unfollow %@"; +"Scene.Report.StepFinal.Unfollowed" = "Unfollowed"; +"Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience." = "When you see something you don’t like on Mastodon, you can remove the person from your experience."; +"Scene.Report.StepFinal.YouWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted" = "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted."; +"Scene.Report.StepFour.IsThereAnythingElseWeShouldKnow" = "Bilmemiz gereken başka bir şey var mı?"; +"Scene.Report.StepFour.Step4Of4" = "Adım 4/4"; +"Scene.Report.StepOne.IDontLikeIt" = "Beğenmedim"; +"Scene.Report.StepOne.ItIsNotSomethingYouWantToSee" = "Görmek isteyeceğim bir şey değil"; +"Scene.Report.StepOne.ItViolatesServerRules" = "Sunucu kurallarını ihlal ediyor"; +"Scene.Report.StepOne.ItsSomethingElse" = "Başka bir şey"; +"Scene.Report.StepOne.ItsSpam" = "Spam"; +"Scene.Report.StepOne.MaliciousLinksFakeEngagementOrRepetetiveReplies" = "Malicious links, fake engagement, or repetetive replies"; +"Scene.Report.StepOne.SelectTheBestMatch" = "En iyi seçeneceği seçiniz"; +"Scene.Report.StepOne.Step1Of4" = "Adım 1/4"; +"Scene.Report.StepOne.TheIssueDoesNotFitIntoOtherCategories" = "Sorun bunlardan biri değil"; +"Scene.Report.StepOne.WhatsWrongWithThisAccount" = "Bu hesap ile ilgili sorun nedir?"; +"Scene.Report.StepOne.WhatsWrongWithThisPost" = "Bu gönderi ile ilgili sorun nedir?"; +"Scene.Report.StepOne.WhatsWrongWithThisUsername" = "%@ kişisinin sorunu nedir?"; +"Scene.Report.StepOne.YouAreAwareThatItBreaksSpecificRules" = "You are aware that it breaks specific rules"; +"Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport" = "Bu bildirimi destekleyecek herhangi bir gönderi var mı?"; +"Scene.Report.StepThree.SelectAllThatApply" = "Geçerli olanların tümünü seçiniz"; +"Scene.Report.StepThree.Step3Of4" = "Adım 3/4"; +"Scene.Report.StepTwo.IJustDon’tLikeIt" = "Beğenmedim"; +"Scene.Report.StepTwo.SelectAllThatApply" = "Geçerli olan tümünü seçiniz"; +"Scene.Report.StepTwo.Step2Of4" = "Adım 2/4"; +"Scene.Report.StepTwo.WhichRulesAreBeingViolated" = "Hangi kurallar ihlal ediliyor?"; "Scene.Report.TextPlaceholder" = "Ek yorum yazın veya yapıştırın"; "Scene.Report.Title" = "%@ kişisini bildir"; "Scene.Report.TitleReport" = "Raporla"; @@ -331,6 +364,7 @@ yüklenemiyor."; "Scene.ServerPicker.EmptyState.FindingServers" = "Mevcut sunucular aranıyor..."; "Scene.ServerPicker.EmptyState.NoResults" = "Sonuç yok"; "Scene.ServerPicker.Input.Placeholder" = "Toplulukları ara"; +"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "Search communities or enter URL"; "Scene.ServerPicker.Label.Category" = "KATEGORİ"; "Scene.ServerPicker.Label.Language" = "DİL"; "Scene.ServerPicker.Label.Users" = "KULLANICILAR"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.strings index d7853fa79..d93f0607d 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/vi.lproj/Localizable.strings @@ -210,6 +210,8 @@ tải lên Mastodon."; "Scene.Favorite.Title" = "Lượt thích"; "Scene.Follower.Footer" = "Không hiển thị người theo dõi từ máy chủ khác."; "Scene.Following.Footer" = "Không hiển thị người bạn theo dõi từ máy chủ khác."; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint" = "Tap to scroll to top and tap again to previous location"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Logo Button"; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "Đọc những tút mới"; "Scene.HomeTimeline.NavigationBarState.Offline" = "Ngoại tuyến"; "Scene.HomeTimeline.NavigationBarState.Published" = "Đã đăng!"; @@ -292,6 +294,37 @@ tải lên Mastodon."; "Scene.Report.SkipToSend" = "Gửi không ghi chú"; "Scene.Report.Step1" = "Bước 1 trong 2"; "Scene.Report.Step2" = "Bước 2 trong 2"; +"Scene.Report.StepFinal.BlockUser" = "Block %@"; +"Scene.Report.StepFinal.DontWantToSeeThis" = "Don’t want to see this?"; +"Scene.Report.StepFinal.MuteUser" = "Mute %@"; +"Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked" = "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked."; +"Scene.Report.StepFinal.Unfollow" = "Unfollow"; +"Scene.Report.StepFinal.UnfollowUser" = "Unfollow %@"; +"Scene.Report.StepFinal.Unfollowed" = "Unfollowed"; +"Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience." = "When you see something you don’t like on Mastodon, you can remove the person from your experience."; +"Scene.Report.StepFinal.YouWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted" = "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted."; +"Scene.Report.StepFour.IsThereAnythingElseWeShouldKnow" = "Is there anything else we should know?"; +"Scene.Report.StepFour.Step4Of4" = "Step 4 of 4"; +"Scene.Report.StepOne.IDontLikeIt" = "I don’t like it"; +"Scene.Report.StepOne.ItIsNotSomethingYouWantToSee" = "It is not something you want to see"; +"Scene.Report.StepOne.ItViolatesServerRules" = "It violates server rules"; +"Scene.Report.StepOne.ItsSomethingElse" = "It’s something else"; +"Scene.Report.StepOne.ItsSpam" = "It’s spam"; +"Scene.Report.StepOne.MaliciousLinksFakeEngagementOrRepetetiveReplies" = "Malicious links, fake engagement, or repetetive replies"; +"Scene.Report.StepOne.SelectTheBestMatch" = "Select the best match"; +"Scene.Report.StepOne.Step1Of4" = "Step 1 of 4"; +"Scene.Report.StepOne.TheIssueDoesNotFitIntoOtherCategories" = "The issue does not fit into other categories"; +"Scene.Report.StepOne.WhatsWrongWithThisAccount" = "What's wrong with this account?"; +"Scene.Report.StepOne.WhatsWrongWithThisPost" = "What's wrong with this post?"; +"Scene.Report.StepOne.WhatsWrongWithThisUsername" = "What's wrong with %@?"; +"Scene.Report.StepOne.YouAreAwareThatItBreaksSpecificRules" = "You are aware that it breaks specific rules"; +"Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport" = "Are there any posts that back up this report?"; +"Scene.Report.StepThree.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepThree.Step3Of4" = "Step 3 of 4"; +"Scene.Report.StepTwo.IJustDon’tLikeIt" = "I just don’t like it"; +"Scene.Report.StepTwo.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepTwo.Step2Of4" = "Step 2 of 4"; +"Scene.Report.StepTwo.WhichRulesAreBeingViolated" = "Which rules are being violated?"; "Scene.Report.TextPlaceholder" = "Nhập hoặc bổ sung chú thích"; "Scene.Report.Title" = "Báo cáo %@"; "Scene.Report.TitleReport" = "Báo cáo"; @@ -332,6 +365,7 @@ tải lên Mastodon."; "Scene.ServerPicker.EmptyState.FindingServers" = "Đang tìm máy chủ hoạt động..."; "Scene.ServerPicker.EmptyState.NoResults" = "Không có kết quả"; "Scene.ServerPicker.Input.Placeholder" = "Tìm máy chủ"; +"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "Search communities or enter URL"; "Scene.ServerPicker.Label.Category" = "PHÂN LOẠI"; "Scene.ServerPicker.Label.Language" = "NGÔN NGỮ"; "Scene.ServerPicker.Label.Users" = "NGƯỜI DÙNG"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.strings index 438747344..50e5b42bf 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hans.lproj/Localizable.strings @@ -211,6 +211,8 @@ "Scene.Favorite.Title" = "你的喜欢"; "Scene.Follower.Footer" = "不会显示来自其它服务器的关注者"; "Scene.Following.Footer" = "不会显示来自其它服务器的关注"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint" = "Tap to scroll to top and tap again to previous location"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Logo Button"; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "查看新帖子"; "Scene.HomeTimeline.NavigationBarState.Offline" = "离线"; "Scene.HomeTimeline.NavigationBarState.Published" = "已发送"; @@ -293,6 +295,37 @@ "Scene.Report.SkipToSend" = "直接发送"; "Scene.Report.Step1" = "步骤 1 / 2"; "Scene.Report.Step2" = "步骤 2 / 2"; +"Scene.Report.StepFinal.BlockUser" = "Block %@"; +"Scene.Report.StepFinal.DontWantToSeeThis" = "Don’t want to see this?"; +"Scene.Report.StepFinal.MuteUser" = "Mute %@"; +"Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked" = "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked."; +"Scene.Report.StepFinal.Unfollow" = "Unfollow"; +"Scene.Report.StepFinal.UnfollowUser" = "Unfollow %@"; +"Scene.Report.StepFinal.Unfollowed" = "Unfollowed"; +"Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience." = "When you see something you don’t like on Mastodon, you can remove the person from your experience."; +"Scene.Report.StepFinal.YouWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted" = "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted."; +"Scene.Report.StepFour.IsThereAnythingElseWeShouldKnow" = "Is there anything else we should know?"; +"Scene.Report.StepFour.Step4Of4" = "Step 4 of 4"; +"Scene.Report.StepOne.IDontLikeIt" = "I don’t like it"; +"Scene.Report.StepOne.ItIsNotSomethingYouWantToSee" = "It is not something you want to see"; +"Scene.Report.StepOne.ItViolatesServerRules" = "It violates server rules"; +"Scene.Report.StepOne.ItsSomethingElse" = "It’s something else"; +"Scene.Report.StepOne.ItsSpam" = "It’s spam"; +"Scene.Report.StepOne.MaliciousLinksFakeEngagementOrRepetetiveReplies" = "Malicious links, fake engagement, or repetetive replies"; +"Scene.Report.StepOne.SelectTheBestMatch" = "Select the best match"; +"Scene.Report.StepOne.Step1Of4" = "Step 1 of 4"; +"Scene.Report.StepOne.TheIssueDoesNotFitIntoOtherCategories" = "The issue does not fit into other categories"; +"Scene.Report.StepOne.WhatsWrongWithThisAccount" = "What's wrong with this account?"; +"Scene.Report.StepOne.WhatsWrongWithThisPost" = "What's wrong with this post?"; +"Scene.Report.StepOne.WhatsWrongWithThisUsername" = "What's wrong with %@?"; +"Scene.Report.StepOne.YouAreAwareThatItBreaksSpecificRules" = "You are aware that it breaks specific rules"; +"Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport" = "Are there any posts that back up this report?"; +"Scene.Report.StepThree.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepThree.Step3Of4" = "Step 3 of 4"; +"Scene.Report.StepTwo.IJustDon’tLikeIt" = "I just don’t like it"; +"Scene.Report.StepTwo.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepTwo.Step2Of4" = "Step 2 of 4"; +"Scene.Report.StepTwo.WhichRulesAreBeingViolated" = "Which rules are being violated?"; "Scene.Report.TextPlaceholder" = "输入或粘贴额外的注释"; "Scene.Report.Title" = "举报 %@"; "Scene.Report.TitleReport" = "举报"; @@ -333,6 +366,7 @@ "Scene.ServerPicker.EmptyState.FindingServers" = "正在查找可用的服务器..."; "Scene.ServerPicker.EmptyState.NoResults" = "无结果"; "Scene.ServerPicker.Input.Placeholder" = "查找或加入你自己的服务器..."; +"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "Search communities or enter URL"; "Scene.ServerPicker.Label.Category" = "类别"; "Scene.ServerPicker.Label.Language" = "语言"; "Scene.ServerPicker.Label.Users" = "用户"; diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hant.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hant.lproj/Localizable.strings index e76396f15..0de6127e6 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hant.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/zh-Hant.lproj/Localizable.strings @@ -205,6 +205,8 @@ "Scene.Favorite.Title" = "您的最愛"; "Scene.Follower.Footer" = "來自其他伺服器的跟隨者不會被顯示。"; "Scene.Following.Footer" = "來自其他伺服器的跟隨中不會被顯示。"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoHint" = "Tap to scroll to top and tap again to previous location"; +"Scene.HomeTimeline.NavigationBarState.Accessibility.LogoLabel" = "Logo Button"; "Scene.HomeTimeline.NavigationBarState.NewPosts" = "檢視最新嘟文"; "Scene.HomeTimeline.NavigationBarState.Offline" = "離線"; "Scene.HomeTimeline.NavigationBarState.Published" = "嘟出去!"; @@ -287,6 +289,37 @@ "Scene.Report.SkipToSend" = "不加入備註並傳送"; "Scene.Report.Step1" = "兩個步驟中的第一步"; "Scene.Report.Step2" = "兩個步驟中的第二步"; +"Scene.Report.StepFinal.BlockUser" = "Block %@"; +"Scene.Report.StepFinal.DontWantToSeeThis" = "Don’t want to see this?"; +"Scene.Report.StepFinal.MuteUser" = "Mute %@"; +"Scene.Report.StepFinal.TheyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked" = "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked."; +"Scene.Report.StepFinal.Unfollow" = "Unfollow"; +"Scene.Report.StepFinal.UnfollowUser" = "Unfollow %@"; +"Scene.Report.StepFinal.Unfollowed" = "Unfollowed"; +"Scene.Report.StepFinal.WhenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience." = "When you see something you don’t like on Mastodon, you can remove the person from your experience."; +"Scene.Report.StepFinal.YouWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted" = "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted."; +"Scene.Report.StepFour.IsThereAnythingElseWeShouldKnow" = "Is there anything else we should know?"; +"Scene.Report.StepFour.Step4Of4" = "Step 4 of 4"; +"Scene.Report.StepOne.IDontLikeIt" = "I don’t like it"; +"Scene.Report.StepOne.ItIsNotSomethingYouWantToSee" = "It is not something you want to see"; +"Scene.Report.StepOne.ItViolatesServerRules" = "It violates server rules"; +"Scene.Report.StepOne.ItsSomethingElse" = "It’s something else"; +"Scene.Report.StepOne.ItsSpam" = "It’s spam"; +"Scene.Report.StepOne.MaliciousLinksFakeEngagementOrRepetetiveReplies" = "Malicious links, fake engagement, or repetetive replies"; +"Scene.Report.StepOne.SelectTheBestMatch" = "Select the best match"; +"Scene.Report.StepOne.Step1Of4" = "Step 1 of 4"; +"Scene.Report.StepOne.TheIssueDoesNotFitIntoOtherCategories" = "The issue does not fit into other categories"; +"Scene.Report.StepOne.WhatsWrongWithThisAccount" = "What's wrong with this account?"; +"Scene.Report.StepOne.WhatsWrongWithThisPost" = "What's wrong with this post?"; +"Scene.Report.StepOne.WhatsWrongWithThisUsername" = "What's wrong with %@?"; +"Scene.Report.StepOne.YouAreAwareThatItBreaksSpecificRules" = "You are aware that it breaks specific rules"; +"Scene.Report.StepThree.AreThereAnyPostsThatBackUpThisReport" = "Are there any posts that back up this report?"; +"Scene.Report.StepThree.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepThree.Step3Of4" = "Step 3 of 4"; +"Scene.Report.StepTwo.IJustDon’tLikeIt" = "I just don’t like it"; +"Scene.Report.StepTwo.SelectAllThatApply" = "Select all that apply"; +"Scene.Report.StepTwo.Step2Of4" = "Step 2 of 4"; +"Scene.Report.StepTwo.WhichRulesAreBeingViolated" = "Which rules are being violated?"; "Scene.Report.TextPlaceholder" = "請輸入或貼上額外的備註"; "Scene.Report.Title" = "檢舉 %@"; "Scene.Report.TitleReport" = "檢舉"; @@ -327,6 +360,7 @@ "Scene.ServerPicker.EmptyState.FindingServers" = "尋找可用的伺服器..."; "Scene.ServerPicker.EmptyState.NoResults" = "沒有結果"; "Scene.ServerPicker.Input.Placeholder" = "搜尋伺服器"; +"Scene.ServerPicker.Input.SearchServersOrEnterUrl" = "Search communities or enter URL"; "Scene.ServerPicker.Label.Category" = "分類"; "Scene.ServerPicker.Label.Language" = "語言"; "Scene.ServerPicker.Label.Users" = "使用者"; From 70a6e11d30a8dedf442d48b5a593b57dd9766e07 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 11 May 2022 21:10:10 +0800 Subject: [PATCH 094/101] chore: use i18n strings for report flow --- .../View/DiscoveryIntroBannerView.swift | 3 ++- .../Paging/ProfilePagingViewModel.swift | 2 +- .../Scene/Report/Report/ReportViewModel.swift | 8 ++++---- .../ReportReason/ReportReasonView.swift | 5 ++--- .../ReportReason/ReportReasonViewModel.swift | 19 ++++++++++--------- .../ReportResult/ReportResultView.swift | 15 +++++++-------- .../ReportResult/ReportResultViewModel.swift | 3 ++- .../ReportServerRulesView.swift | 7 +++---- .../ReportServerRulesViewModel.swift | 5 +++-- .../ReportStatusViewModel+Diffable.swift | 2 +- ...eportSupplementaryViewModel+Diffable.swift | 4 ++-- .../View/Control/ActionToolbarContainer.swift | 2 +- 12 files changed, 38 insertions(+), 37 deletions(-) diff --git a/Mastodon/Scene/Discovery/View/DiscoveryIntroBannerView.swift b/Mastodon/Scene/Discovery/View/DiscoveryIntroBannerView.swift index e3e1c4547..afc2cb7db 100644 --- a/Mastodon/Scene/Discovery/View/DiscoveryIntroBannerView.swift +++ b/Mastodon/Scene/Discovery/View/DiscoveryIntroBannerView.swift @@ -9,6 +9,7 @@ import os.log import UIKit import Combine import MastodonAsset +import MastodonLocalization public protocol DiscoveryIntroBannerViewDelegate: AnyObject { func discoveryIntroBannerView(_ bannerView: DiscoveryIntroBannerView, closeButtonDidPressed button: UIButton) @@ -26,7 +27,7 @@ public final class DiscoveryIntroBannerView: UIView { let label = UILabel() label.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 16, weight: .regular)) label.textColor = Asset.Colors.Label.primary.color - label.text = "These are the posts gaining traction in your corner of Mastodon." // TODO: i18n + label.text = L10n.Scene.Discovery.intro label.numberOfLines = 0 return label }() diff --git a/Mastodon/Scene/Profile/Segmented/Paging/ProfilePagingViewModel.swift b/Mastodon/Scene/Profile/Segmented/Paging/ProfilePagingViewModel.swift index e5220ef79..67a0ca93d 100644 --- a/Mastodon/Scene/Profile/Segmented/Paging/ProfilePagingViewModel.swift +++ b/Mastodon/Scene/Profile/Segmented/Paging/ProfilePagingViewModel.swift @@ -44,7 +44,7 @@ final class ProfilePagingViewModel: NSObject { let barItems: [TMBarItemable] = { let items = [ TMBarItem(title: L10n.Scene.Profile.SegmentedControl.posts), - TMBarItem(title: L10n.Scene.Profile.SegmentedControl.postsAndReplies), // TODO: i18n + TMBarItem(title: L10n.Scene.Profile.SegmentedControl.postsAndReplies), TMBarItem(title: L10n.Scene.Profile.SegmentedControl.media), TMBarItem(title: L10n.Scene.Profile.SegmentedControl.about), ] diff --git a/Mastodon/Scene/Report/Report/ReportViewModel.swift b/Mastodon/Scene/Report/Report/ReportViewModel.swift index 590aed87d..f94a92d39 100644 --- a/Mastodon/Scene/Report/Report/ReportViewModel.swift +++ b/Mastodon/Scene/Report/Report/ReportViewModel.swift @@ -14,6 +14,7 @@ import MastodonSDK import OrderedCollections import os.log import UIKit +import MastodonLocalization class ReportViewModel { @@ -53,8 +54,7 @@ class ReportViewModel { // setup reason viewModel if status != nil { - // TODO: i18n - reportReasonViewModel.headline = "What’s wrong with post?" + reportReasonViewModel.headline = L10n.Scene.Report.StepOne.whatsWrongWithThisPost } else { Task { @MainActor in let managedObjectContext = context.managedObjectContext @@ -63,9 +63,9 @@ class ReportViewModel { return user?.acctWithDomain } if let username = _username { - reportReasonViewModel.headline = "What’s wrong with @\(username)?" + reportReasonViewModel.headline = L10n.Scene.Report.StepOne.whatsWrongWithThisUsername(username) } else { - reportReasonViewModel.headline = "What’s wrong with this account?" + reportReasonViewModel.headline = L10n.Scene.Report.StepOne.whatsWrongWithThisAccount } } // end Task } diff --git a/Mastodon/Scene/Report/ReportReason/ReportReasonView.swift b/Mastodon/Scene/Report/ReportReason/ReportReasonView.swift index 3a8b4579f..67e948727 100644 --- a/Mastodon/Scene/Report/ReportReason/ReportReasonView.swift +++ b/Mastodon/Scene/Report/ReportReason/ReportReasonView.swift @@ -15,18 +15,17 @@ struct ReportReasonView: View { @ObservedObject var viewModel: ReportReasonViewModel - // TODO: i18n var body: some View { ScrollView(.vertical) { HStack { VStack(alignment: .leading, spacing: 8) { - Text("Step 1 of 4") + Text(L10n.Scene.Report.StepOne.step1Of4) .foregroundColor(Color(Asset.Colors.Label.secondary.color)) .font(Font(UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)) as CTFont)) Text(viewModel.headline) .foregroundColor(Color(Asset.Colors.Label.primary.color)) .font(Font(UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: .systemFont(ofSize: 28, weight: .bold)) as CTFont)) - Text("Select the best match") + Text(L10n.Scene.Report.StepOne.selectTheBestMatch) .foregroundColor(Color(Asset.Colors.Label.secondary.color)) .font(Font(UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)) as CTFont)) } diff --git a/Mastodon/Scene/Report/ReportReason/ReportReasonViewModel.swift b/Mastodon/Scene/Report/ReportReason/ReportReasonViewModel.swift index b156ea311..91715cba8 100644 --- a/Mastodon/Scene/Report/ReportReason/ReportReasonViewModel.swift +++ b/Mastodon/Scene/Report/ReportReason/ReportReasonViewModel.swift @@ -9,6 +9,7 @@ import UIKit import SwiftUI import MastodonAsset import MastodonSDK +import MastodonLocalization final class ReportReasonViewModel: ObservableObject { @@ -17,7 +18,7 @@ final class ReportReasonViewModel: ObservableObject { // input let context: AppContext - @Published var headline = "What's wrong with this account?" + @Published var headline = L10n.Scene.Report.StepOne.whatsWrongWithThisAccount @Published var serverRules: [Mastodon.Entity.Instance.Rule]? @Published var bottomPaddingHeight: CGFloat = .zero @@ -43,26 +44,26 @@ extension ReportReasonViewModel { var title: String { switch self { case .dislike: - return "I don’t like it" + return L10n.Scene.Report.StepOne.iDontLikeIt case .spam: - return "It’s spam" + return L10n.Scene.Report.StepOne.itsSpam case .violateRule: - return "It violates server rules" + return L10n.Scene.Report.StepOne.itViolatesServerRules case .other: - return "It’s something else" + return L10n.Scene.Report.StepOne.itsSomethingElse } } var subtitle: String { switch self { case .dislike: - return "It is not something you want to see" + return L10n.Scene.Report.StepOne.itIsNotSomethingYouWantToSee case .spam: - return "Malicious links, fake engagement, or repetetive replies" + return L10n.Scene.Report.StepOne.maliciousLinksFakeEngagementOrRepetetiveReplies case .violateRule: - return "You are aware that it breaks specific rules" + return L10n.Scene.Report.StepOne.youAreAwareThatItBreaksSpecificRules case .other: - return "The issue does not fit into other categories" + return L10n.Scene.Report.StepOne.theIssueDoesNotFitIntoOtherCategories } } diff --git a/Mastodon/Scene/Report/ReportResult/ReportResultView.swift b/Mastodon/Scene/Report/ReportResult/ReportResultView.swift index dff87e356..7931538fc 100644 --- a/Mastodon/Scene/Report/ReportResult/ReportResultView.swift +++ b/Mastodon/Scene/Report/ReportResult/ReportResultView.swift @@ -7,10 +7,10 @@ import UIKit import SwiftUI -import MastodonLocalization import MastodonSDK import MastodonUI import MastodonAsset +import MastodonLocalization import CoreDataStack struct ReportResultView: View { @@ -42,7 +42,6 @@ struct ReportResultView: View { .padding() } - // TODO: i18n var body: some View { ScrollView(.vertical) { HStack { @@ -56,7 +55,7 @@ struct ReportResultView: View { .foregroundColor(Color(Asset.Colors.Label.secondary.color)) .font(Font(UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)) as CTFont)) } else { - Text(verbatim: "When you see something you don’t like on Mastodon, you can remove the person from your experience.") + Text(verbatim: L10n.Scene.Report.StepFinal.whenYouSeeSomethingYouDontLikeOnMastodonYouCanRemoveThePersonFromYourExperience) .foregroundColor(Color(Asset.Colors.Label.secondary.color)) .font(Font(UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)) as CTFont)) } @@ -68,7 +67,7 @@ struct ReportResultView: View { VStack(spacing: 32) { // Follow VStack(alignment: .leading, spacing: 4) { - Text("Unfollow @\(viewModel.username)") + Text(L10n.Scene.Report.StepFinal.unfollowUser("@\(viewModel.username)")) .font(.headline) .foregroundColor(Color(Asset.Colors.Label.primary.color)) ReportActionButton( @@ -82,10 +81,10 @@ struct ReportResultView: View { // Mute VStack(alignment: .leading, spacing: 4) { - Text("Mute @\(viewModel.username)") + Text(L10n.Scene.Report.StepFinal.muteUser("@\(viewModel.username)")) .font(.headline) .foregroundColor(Color(Asset.Colors.Label.primary.color)) - Text(verbatim: "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted.") + Text(verbatim: L10n.Scene.Report.StepFinal.youWontSeeTheirPostsOrReblogsInYourHomeFeedTheyWontKnowTheyVeBeenMuted) .foregroundColor(Color(Asset.Colors.Label.secondary.color)) .font(Font(UIFontMetrics(forTextStyle: .subheadline).scaledFont(for: .systemFont(ofSize: 13, weight: .regular)) as CTFont)) ReportActionButton( @@ -99,10 +98,10 @@ struct ReportResultView: View { // Block VStack(alignment: .leading, spacing: 4) { - Text("Block @\(viewModel.username)") + Text(L10n.Scene.Report.StepFinal.blockUser("@\(viewModel.username)")) .font(.headline) .foregroundColor(Color(Asset.Colors.Label.primary.color)) - Text(verbatim: "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked.") + Text(verbatim: L10n.Scene.Report.StepFinal.theyWillNoLongerBeAbleToFollowOrSeeYourPostsButTheyCanSeeIfTheyveBeenBlocked) .foregroundColor(Color(Asset.Colors.Label.secondary.color)) .font(Font(UIFontMetrics(forTextStyle: .subheadline).scaledFont(for: .systemFont(ofSize: 13, weight: .regular)) as CTFont)) ReportActionButton( diff --git a/Mastodon/Scene/Report/ReportResult/ReportResultViewModel.swift b/Mastodon/Scene/Report/ReportResult/ReportResultViewModel.swift index ea949a901..67d7475dd 100644 --- a/Mastodon/Scene/Report/ReportResult/ReportResultViewModel.swift +++ b/Mastodon/Scene/Report/ReportResult/ReportResultViewModel.swift @@ -14,6 +14,7 @@ import os.log import UIKit import MastodonAsset import MastodonUI +import MastodonLocalization class ReportResultViewModel: ObservableObject { @@ -25,7 +26,7 @@ class ReportResultViewModel: ObservableObject { let isReported: Bool var headline: String { - isReported ? "Thanks for reporting, we’ll look into this." : "Don’t want to see this?" + isReported ? L10n.Scene.Report.reportSentTitle : L10n.Scene.Report.StepFinal.dontWantToSeeThis } @Published var bottomPaddingHeight: CGFloat = .zero @Published var backgroundColor: UIColor = Asset.Scene.Report.background.color diff --git a/Mastodon/Scene/Report/ReportServerRules/ReportServerRulesView.swift b/Mastodon/Scene/Report/ReportServerRules/ReportServerRulesView.swift index e8dcfa886..57406402b 100644 --- a/Mastodon/Scene/Report/ReportServerRules/ReportServerRulesView.swift +++ b/Mastodon/Scene/Report/ReportServerRules/ReportServerRulesView.swift @@ -15,18 +15,17 @@ struct ReportServerRulesView: View { @ObservedObject var viewModel: ReportServerRulesViewModel - // TODO: i18n var body: some View { ScrollView(.vertical) { HStack { VStack(alignment: .leading, spacing: 8) { - Text("Step 2 of 4") + Text(L10n.Scene.Report.StepTwo.step2Of4) .foregroundColor(Color(Asset.Colors.Label.secondary.color)) .font(Font(UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)) as CTFont)) Text(viewModel.headline) .foregroundColor(Color(Asset.Colors.Label.primary.color)) .font(Font(UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: .systemFont(ofSize: 28, weight: .bold)) as CTFont)) - Text("Select all that apply") + Text(L10n.Scene.Report.StepTwo.selectAllThatApply) .foregroundColor(Color(Asset.Colors.Label.secondary.color)) .font(Font(UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: .systemFont(ofSize: 17, weight: .regular)) as CTFont)) } @@ -49,7 +48,7 @@ struct ReportServerRulesView: View { } } ReportServerRulesRowView( - title: "I just don’t like it", + title: L10n.Scene.Report.StepTwo.iJustDonTLikeIt, isSelect: viewModel.isDislike ) .background( diff --git a/Mastodon/Scene/Report/ReportServerRules/ReportServerRulesViewModel.swift b/Mastodon/Scene/Report/ReportServerRules/ReportServerRulesViewModel.swift index 1960899a9..e0e21f301 100644 --- a/Mastodon/Scene/Report/ReportServerRules/ReportServerRulesViewModel.swift +++ b/Mastodon/Scene/Report/ReportServerRules/ReportServerRulesViewModel.swift @@ -9,6 +9,7 @@ import UIKit import SwiftUI import MastodonAsset import MastodonSDK +import MastodonLocalization final class ReportServerRulesViewModel: ObservableObject { @@ -16,8 +17,8 @@ final class ReportServerRulesViewModel: ObservableObject { // input let context: AppContext - - @Published var headline = "Which rules are being violated?" + + @Published var headline = L10n.Scene.Report.StepTwo.whichRulesAreBeingViolated @Published var serverRules: [Mastodon.Entity.Instance.Rule] = [] @Published var bottomPaddingHeight: CGFloat = .zero diff --git a/Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel+Diffable.swift b/Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel+Diffable.swift index 5bcc2f3d6..4610a38d3 100644 --- a/Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel+Diffable.swift +++ b/Mastodon/Scene/Report/ReportStatus/ReportStatusViewModel+Diffable.swift @@ -16,7 +16,7 @@ extension ReportStatusViewModel { static let reportItemHeaderContext = ReportItem.HeaderContext( primaryLabelText: L10n.Scene.Report.content1, - secondaryLabelText: "Step 3 of 4" + secondaryLabelText: L10n.Scene.Report.StepThree.step3Of4 ) func setupDiffableDataSource( diff --git a/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewModel+Diffable.swift b/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewModel+Diffable.swift index e59617c35..8cbc16242 100644 --- a/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewModel+Diffable.swift +++ b/Mastodon/Scene/Report/ReportSupplementary/ReportSupplementaryViewModel+Diffable.swift @@ -15,8 +15,8 @@ import MastodonLocalization extension ReportSupplementaryViewModel { static let reportItemHeaderContext = ReportItem.HeaderContext( - primaryLabelText: "Is there anything else we should know?", - secondaryLabelText: "Step 4 of 4" + primaryLabelText: L10n.Scene.Report.StepFour.isThereAnythingElseWeShouldKnow, + secondaryLabelText: L10n.Scene.Report.StepFour.step4Of4 ) func setupDiffableDataSource( diff --git a/MastodonSDK/Sources/MastodonUI/View/Control/ActionToolbarContainer.swift b/MastodonSDK/Sources/MastodonUI/View/Control/ActionToolbarContainer.swift index c3a9b96f3..4a5c44850 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Control/ActionToolbarContainer.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Control/ActionToolbarContainer.swift @@ -216,7 +216,7 @@ extension ActionToolbarContainer { public func configureReply(count: Int, isEnabled: Bool) { let title = ActionToolbarContainer.title(from: count) replyButton.setTitle(title, for: .normal) - replyButton.accessibilityLabel = "\(count) reply" // TODO: i18n + replyButton.accessibilityLabel = L10n.Plural.Count.reply(count) } public func configureReblog(count: Int, isEnabled: Bool, isHighlighted: Bool) { From 635b7a8d97563c60c474dd2e45a02ee344f5d649 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 11 May 2022 21:11:58 +0800 Subject: [PATCH 095/101] chore: add i18n words --- Localization/Localizable.stringsdict | 22 ++++++++++++++++++++++ Localization/app.json | 3 ++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/Localization/Localizable.stringsdict b/Localization/Localizable.stringsdict index 4b9a12762..0b9a6ff60 100644 --- a/Localization/Localizable.stringsdict +++ b/Localization/Localizable.stringsdict @@ -90,6 +90,28 @@ posts + plural.count.media + + NSStringLocalizedFormatKey + %#@media_count@ + media_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + zero + 0 media + one + 1 media + few + %ld media + many + %ld media + other + %ld media + + plural.count.post NSStringLocalizedFormatKey diff --git a/Localization/app.json b/Localization/app.json index 8de2dc0b3..12dd1e030 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -641,7 +641,8 @@ "mute_user": "Mute %s", "you_wont_see_their_posts_or_reblogs_in_your_home_feed_they_wont_know_they_ve_been_muted": "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted.", "block_user": "Block %s", - "they_will_no_longer_be_able_to_follow_or_see_your_posts_but_they_can_see_if_theyve_been_blocked": "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked." + "they_will_no_longer_be_able_to_follow_or_see_your_posts_but_they_can_see_if_theyve_been_blocked": "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked.", + "while_we_review_this_you_can_take_action_against_user": "While we review this, you can take action against %s" } }, "preview": { From 971c8674b69837cbfef761435fbbccb29a2de7bd Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 11 May 2022 21:12:38 +0800 Subject: [PATCH 096/101] chore: update version to 1.4.2 (127) --- AppShared/Info.plist | 4 +- Mastodon.xcodeproj/project.pbxproj | 48 +++++++++---------- .../xcschemes/xcschememanagement.plist | 8 ++-- Mastodon/Info.plist | 4 +- MastodonIntent/Info.plist | 4 +- MastodonTests/Info.plist | 4 +- MastodonUITests/Info.plist | 4 +- NotificationService/Info.plist | 4 +- ShareActionExtension/Info.plist | 4 +- 9 files changed, 42 insertions(+), 42 deletions(-) diff --git a/AppShared/Info.plist b/AppShared/Info.plist index 92f442892..a187ca268 100644 --- a/AppShared/Info.plist +++ b/AppShared/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.4.1 + 1.4.2 CFBundleVersion - 126 + 127 diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 99f517dd7..fb9e834cb 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -4763,7 +4763,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 126; + CURRENT_PROJECT_VERSION = 127; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4793,7 +4793,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 126; + CURRENT_PROJECT_VERSION = 127; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4901,11 +4901,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 126; + CURRENT_PROJECT_VERSION = 127; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 126; + DYLIB_CURRENT_VERSION = 127; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -4932,11 +4932,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 126; + CURRENT_PROJECT_VERSION = 127; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 126; + DYLIB_CURRENT_VERSION = 127; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5027,7 +5027,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 126; + CURRENT_PROJECT_VERSION = 127; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5095,11 +5095,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 126; + CURRENT_PROJECT_VERSION = 127; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 126; + DYLIB_CURRENT_VERSION = 127; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5124,7 +5124,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 126; + CURRENT_PROJECT_VERSION = 127; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5147,7 +5147,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 126; + CURRENT_PROJECT_VERSION = 127; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5171,7 +5171,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 126; + CURRENT_PROJECT_VERSION = 127; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5195,7 +5195,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 126; + CURRENT_PROJECT_VERSION = 127; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5219,7 +5219,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 126; + CURRENT_PROJECT_VERSION = 127; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5243,7 +5243,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 126; + CURRENT_PROJECT_VERSION = 127; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5267,7 +5267,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 126; + CURRENT_PROJECT_VERSION = 127; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5354,7 +5354,7 @@ CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 126; + CURRENT_PROJECT_VERSION = 127; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -5421,11 +5421,11 @@ APPLICATION_EXTENSION_API_ONLY = YES; CLANG_ENABLE_MODULES = YES; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 126; + CURRENT_PROJECT_VERSION = 127; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 5Z4GVSS33P; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 126; + DYLIB_CURRENT_VERSION = 127; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = AppShared/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -5449,7 +5449,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 126; + CURRENT_PROJECT_VERSION = 127; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5472,7 +5472,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 126; + CURRENT_PROJECT_VERSION = 127; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = ShareActionExtension/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5496,7 +5496,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = MastodonIntent/MastodonIntent.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 126; + CURRENT_PROJECT_VERSION = 127; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = MastodonIntent/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5520,7 +5520,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 126; + CURRENT_PROJECT_VERSION = 127; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -5543,7 +5543,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 126; + CURRENT_PROJECT_VERSION = 127; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index 8e16cec2d..5041bc0be 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -24,7 +24,7 @@ Mastodon - RTL.xcscheme_^#shared#^_ orderHint - 7 + 8 Mastodon - Release.xcscheme_^#shared#^_ @@ -114,7 +114,7 @@ MastodonIntent.xcscheme_^#shared#^_ orderHint - 20 + 31 MastodonIntents.xcscheme_^#shared#^_ @@ -129,12 +129,12 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 21 + 30 ShareActionExtension.xcscheme_^#shared#^_ orderHint - 22 + 32 SuppressBuildableAutocreation diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index c93fd9a65..0c3dea8f5 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -30,7 +30,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.4.1 + 1.4.2 CFBundleURLTypes @@ -43,7 +43,7 @@ CFBundleVersion - 126 + 127 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/MastodonIntent/Info.plist b/MastodonIntent/Info.plist index 3f1630945..f1f54a5e0 100644 --- a/MastodonIntent/Info.plist +++ b/MastodonIntent/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.4.1 + 1.4.2 CFBundleVersion - 126 + 127 NSExtension NSExtensionAttributes diff --git a/MastodonTests/Info.plist b/MastodonTests/Info.plist index 92f442892..a187ca268 100644 --- a/MastodonTests/Info.plist +++ b/MastodonTests/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.4.1 + 1.4.2 CFBundleVersion - 126 + 127 diff --git a/MastodonUITests/Info.plist b/MastodonUITests/Info.plist index 92f442892..a187ca268 100644 --- a/MastodonUITests/Info.plist +++ b/MastodonUITests/Info.plist @@ -15,8 +15,8 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.4.1 + 1.4.2 CFBundleVersion - 126 + 127 diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist index f074db82b..fa2356db2 100644 --- a/NotificationService/Info.plist +++ b/NotificationService/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.4.1 + 1.4.2 CFBundleVersion - 126 + 127 NSExtension NSExtensionPointIdentifier diff --git a/ShareActionExtension/Info.plist b/ShareActionExtension/Info.plist index 31c7447fe..95cd141f7 100644 --- a/ShareActionExtension/Info.plist +++ b/ShareActionExtension/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.4.1 + 1.4.2 CFBundleVersion - 126 + 127 NSExtension NSExtensionAttributes From 2be08a719dad9188a84747b45023cc0cd7d12f42 Mon Sep 17 00:00:00 2001 From: CMK Date: Wed, 11 May 2022 21:11:58 +0800 Subject: [PATCH 097/101] chore: add i18n words (cherry picked from commit 635b7a8d97563c60c474dd2e45a02ee344f5d649) --- Localization/Localizable.stringsdict | 22 ++++++++++++++++++++++ Localization/app.json | 3 ++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/Localization/Localizable.stringsdict b/Localization/Localizable.stringsdict index 4b9a12762..0b9a6ff60 100644 --- a/Localization/Localizable.stringsdict +++ b/Localization/Localizable.stringsdict @@ -90,6 +90,28 @@ posts + plural.count.media + + NSStringLocalizedFormatKey + %#@media_count@ + media_count + + NSStringFormatSpecTypeKey + NSStringPluralRuleType + NSStringFormatValueTypeKey + ld + zero + 0 media + one + 1 media + few + %ld media + many + %ld media + other + %ld media + + plural.count.post NSStringLocalizedFormatKey diff --git a/Localization/app.json b/Localization/app.json index 8de2dc0b3..12dd1e030 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -641,7 +641,8 @@ "mute_user": "Mute %s", "you_wont_see_their_posts_or_reblogs_in_your_home_feed_they_wont_know_they_ve_been_muted": "You won’t see their posts or reblogs in your home feed. They won’t know they’ve been muted.", "block_user": "Block %s", - "they_will_no_longer_be_able_to_follow_or_see_your_posts_but_they_can_see_if_theyve_been_blocked": "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked." + "they_will_no_longer_be_able_to_follow_or_see_your_posts_but_they_can_see_if_theyve_been_blocked": "They will no longer be able to follow or see your posts, but they can see if they’ve been blocked.", + "while_we_review_this_you_can_take_action_against_user": "While we review this, you can take action against %s" } }, "preview": { From 070ff477b7d3955f8485d9673bee8ad2999edcac Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 13 May 2022 11:21:11 +0800 Subject: [PATCH 098/101] chore: update i18n template --- Localization/app.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Localization/app.json b/Localization/app.json index 12dd1e030..6a2534c5d 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -321,6 +321,7 @@ "confirm_email": { "title": "One last thing.", "subtitle": "Tap the link we emailed to you to verify your account.", + "tap_the_link_we_emailed_to_you_to_verify_your_account": "Tap the link we emailed to you to verify your account", "button": { "open_email_app": "Open Email App", "resend": "Resend" From 951a47936e71be33cbd86681e9c590306f05055c Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 13 May 2022 11:22:16 +0800 Subject: [PATCH 099/101] chore: update i18n template --- Localization/app.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Localization/app.json b/Localization/app.json index 6a2534c5d..32eaea9d2 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -251,6 +251,7 @@ }, "register": { "title": "Let’s get you set up on %s", + "lets_get_you_set_up_on_domain": "Let’s get you set up on %s", "input": { "avatar": { "delete": "Delete" From 556e28362d7a287403527f61f8fff12bf351b2df Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 13 May 2022 11:43:37 +0800 Subject: [PATCH 100/101] chore: remove "update_option" option from crowdin config --- crowdin.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crowdin.yml b/crowdin.yml index 38421efa6..526099422 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -20,7 +20,7 @@ files: [ # The parameter "update_option" is optional. If it is not set, after the files update the translations for changed strings will be removed. Use to fix typos and for minor changes in the source strings # e.g. "update_as_unapproved" or "update_without_changes" # - "update_option" : "update_as_unapproved", + # "update_option" : "update_as_unapproved", # }, { @@ -33,18 +33,18 @@ files: [ # App strings dict "source" : "/Localization/Localizable.stringsdict", "translation" : "/Localization/StringsConvertor/input/%locale_with_underscore%/%original_file_name%", - "update_option" : "update_as_unapproved", + # "update_option" : "update_as_unapproved", }, { # intents strings "source" : "/MastodonIntent/en.lproj/Intents.strings", "translation" : "/Localization/StringsConvertor/Intents/input/%locale_with_underscore%/%original_file_name%", - "update_option" : "update_as_unapproved", + # "update_option" : "update_as_unapproved", }, { # intents strings dict "source" : "/MastodonIntent/en.lproj/Intents.stringsdict", "translation" : "/Localization/StringsConvertor/Intents/input/%locale_with_underscore%/%original_file_name%", - "update_option" : "update_as_unapproved", + # "update_option" : "update_as_unapproved", }, ] \ No newline at end of file From 975f8205d2183900c5363cdf40bce1f833a8008a Mon Sep 17 00:00:00 2001 From: CMK Date: Fri, 13 May 2022 11:50:04 +0800 Subject: [PATCH 101/101] chore: fix placeholders conflict for some languages issue --- crowdin.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crowdin.yml b/crowdin.yml index 526099422..9fdca4a22 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -14,7 +14,7 @@ files: [ # Where translations will be placed # e.g. "/resources/%two_letters_code%/%original_file_name%" # - "translation" : "/Localization/StringsConvertor/input/%locale_with_underscore%/%original_file_name%", + "translation" : "/Localization/StringsConvertor/input/%osx_code%/%original_file_name%", # # The parameter "update_option" is optional. If it is not set, after the files update the translations for changed strings will be removed. Use to fix typos and for minor changes in the source strings @@ -26,25 +26,25 @@ files: [ { # App info plist strings template "source" : "/Localization/ios-infoPlist.json", - "translation" : "/Localization/StringsConvertor/input/%locale_with_underscore%/%original_file_name%", + "translation" : "/Localization/StringsConvertor/input/%osx_code%/%original_file_name%", "update_option" : "update_as_unapproved", }, { # App strings dict "source" : "/Localization/Localizable.stringsdict", - "translation" : "/Localization/StringsConvertor/input/%locale_with_underscore%/%original_file_name%", + "translation" : "/Localization/StringsConvertor/input/%osx_code%/%original_file_name%", # "update_option" : "update_as_unapproved", }, { # intents strings "source" : "/MastodonIntent/en.lproj/Intents.strings", - "translation" : "/Localization/StringsConvertor/Intents/input/%locale_with_underscore%/%original_file_name%", + "translation" : "/Localization/StringsConvertor/Intents/input/%osx_code%/%original_file_name%", # "update_option" : "update_as_unapproved", }, { # intents strings dict "source" : "/MastodonIntent/en.lproj/Intents.stringsdict", - "translation" : "/Localization/StringsConvertor/Intents/input/%locale_with_underscore%/%original_file_name%", + "translation" : "/Localization/StringsConvertor/Intents/input/%osx_code%/%original_file_name%", # "update_option" : "update_as_unapproved", }, ] \ No newline at end of file