From 715a29fe3b0b809c7fec0d6e09b22c1331955c35 Mon Sep 17 00:00:00 2001 From: Josh Brown Date: Fri, 3 Jan 2025 12:03:26 -0500 Subject: [PATCH] Revert "Merge pull request #1698 from planetary-social/xcode-16" This reverts commit 45b90a43be2e9a320b485547aef9874d596f5f26, reversing changes made to 1a005079b0d20b638588d86d2b0fd479ce065b8f. # Conflicts: # CHANGELOG.md # Nos.xcodeproj/project.pbxproj --- .github/workflows/test.yml | 4 +- .xcode-version | 2 +- CHANGELOG.md | 1 - Nos.xcodeproj/project.pbxproj | 24 +-- .../xcshareddata/xcschemes/Nos.xcscheme | 2 +- .../xcschemes/NosDiagnostics.xcscheme | 2 +- .../xcschemes/NosLocalization.xcscheme | 2 +- .../xcschemes/NosPerformance Tests.xcscheme | 2 +- .../xcschemes/NosProduction.xcscheme | 2 +- .../xcschemes/NosStaging.xcscheme | 2 +- .../xcshareddata/xcschemes/NosTests.xcscheme | 2 +- .../xcschemes/NosUITests.xcscheme | 2 +- Nos/AppDelegate.swift | 1 - .../newPostButton.imageset/Contents.json | 3 - .../tab-profile.imageset/Contents.json | 3 - Nos/Controller/RawEventController.swift | 2 +- Nos/Extensions/Foundation+Sendable.swift | 3 +- Nos/Models/AppDestination.swift | 14 -- Nos/Models/CoreData/Event+CoreDataClass.swift | 2 +- Nos/Models/JSONEvent.swift | 7 +- Nos/Models/KeyPair.swift | 4 +- .../OpenGraph/SoupOpenGraphParser.swift | 6 +- Nos/Models/RawNostrID.swift | 2 +- Nos/Service/CurrentUser+PublishEvents.swift | 5 +- Nos/Service/CurrentUser.swift | 8 +- Nos/Service/DependencyInjection.swift | 8 +- Nos/Service/PushNotificationRegistrar.swift | 5 +- Nos/Service/Relay/RelayService.swift | 8 +- .../Relay/RelaySubscriptionManager.swift | 4 +- Nos/Service/ReportPublisher.swift | 5 +- Nos/Views/AppView.swift | 189 ++++++++++-------- Nos/Views/Components/Author/AuthorCard.swift | 2 +- Nos/Views/Components/KnownFollowersView.swift | 2 +- Nos/Views/Components/NosNavigationStack.swift | 2 +- Nos/Views/Components/NosToggle.swift | 2 +- Nos/Views/Components/NoteTextEditor.swift | 7 +- Nos/Views/Components/PagedNoteListView.swift | 10 +- Nos/Views/Components/RelayPicker.swift | 14 +- Nos/Views/Components/WarningView.swift | 2 +- Nos/Views/Discover/DiscoverContentsView.swift | 2 +- Nos/Views/Fixtures/PreviewData.swift | 88 ++++---- Nos/Views/Home/HomeFeedView.swift | 4 +- Nos/Views/Note/NoteCard.swift | 2 +- .../NoteComposer/ComposerActionBar.swift | 2 +- Nos/Views/NoteComposer/NoteComposer.swift | 2 +- Nos/Views/NoteComposer/ReplyPreview.swift | 2 +- .../Notifications/NotificationCard.swift | 13 +- .../Notifications/NotificationsView.swift | 2 +- .../Onboarding/Components/CopyKeyView.swift | 8 +- Nos/Views/Onboarding/DisplayNameView.swift | 2 +- Nos/Views/Onboarding/UsernameView.swift | 2 +- Nos/Views/Profile/ActivityPubBadgeView.swift | 2 +- Nos/Views/Profile/BioSheet.swift | 2 +- .../ConfirmUsernameDeletionSheet.swift | 2 +- .../DeleteUsernameWizard.swift | 2 +- Nos/Views/Profile/ProfileHeader.swift | 19 +- Nos/Views/Profile/ProfileView.swift | 2 +- Nos/Views/TabBarController.swift | 71 ------- .../ContentWarningControllerTests.swift | 2 +- NosTests/Models/CoreData/EventTests.swift | 4 +- 60 files changed, 263 insertions(+), 339 deletions(-) delete mode 100644 Nos/Views/TabBarController.swift diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index dc9f75fb7..003c403c0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,7 +11,7 @@ on: push: branches: main env: - SIMULATOR: platform=iOS Simulator,name=iPhone 16,OS=18.1 + SIMULATOR: platform=iOS Simulator,name=iPhone 15,OS=17.4 jobs: unit_test: @@ -38,6 +38,6 @@ jobs: steps: - uses: actions/checkout@v1 - name: SwiftLint - uses: docker://norionomura/swiftlint:0.57.1 + uses: docker://norionomura/swiftlint:0.55.1 with: args: swiftlint --strict --reporter github-actions-logging diff --git a/.xcode-version b/.xcode-version index c32b0ec5a..232a7fc1a 100644 --- a/.xcode-version +++ b/.xcode-version @@ -1 +1 @@ -16.1 +15.4 diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a718a8a9..7a04cd145 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Updated the default relays that are added when you create an account. [#17](https://github.com/verse-pbc/issues/issues/17) ### Internal Changes -- Upgraded to Xcode 16. [#1570](https://github.com/planetary-social/nos/issues/1570) - Download and parse an author’s lists when viewing their profile. [#49](https://github.com/verse-pbc/issues/issues/49) - Updated fastlane scripts to fix the TestFlight deployment pipeline. [#97](https://github.com/verse-pbc/issues/issues/97) - Removed inactive accounts from Discover tab. [#94](https://github.com/verse-pbc/issues/issues/94) diff --git a/Nos.xcodeproj/project.pbxproj b/Nos.xcodeproj/project.pbxproj index b1cf16735..74b2e7a30 100644 --- a/Nos.xcodeproj/project.pbxproj +++ b/Nos.xcodeproj/project.pbxproj @@ -11,7 +11,6 @@ 030036852C5D39DD002C71F5 /* RefreshController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 030036842C5D39DD002C71F5 /* RefreshController.swift */; }; 030036942C5D3AD3002C71F5 /* RefreshController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 030036842C5D39DD002C71F5 /* RefreshController.swift */; }; 030036AB2C5D872B002C71F5 /* NewNotesButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 030036AA2C5D872B002C71F5 /* NewNotesButton.swift */; }; - 0301495C2CFFA8B7000A0152 /* TabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0301495B2CFFA8B7000A0152 /* TabBarController.swift */; }; 0303B1532D025C9A00077929 /* AuthorList+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0303B13E2D025BDD00077929 /* AuthorList+CoreDataProperties.swift */; }; 0303B1542D025C9A00077929 /* AuthorList+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0303B13E2D025BDD00077929 /* AuthorList+CoreDataProperties.swift */; }; 0304D0A72C9B4BF2001D16C7 /* OpenGraphMetatdata.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0304D0A62C9B4BF2001D16C7 /* OpenGraphMetatdata.swift */; }; @@ -139,8 +138,6 @@ 03ED93472C46C48400C8D443 /* JSONEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03ED93462C46C48400C8D443 /* JSONEventTests.swift */; }; 03F7C4F32C10DF79006FF613 /* URLSessionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F7C4F22C10DF79006FF613 /* URLSessionProtocol.swift */; }; 03F7C4F42C10E05B006FF613 /* URLSessionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F7C4F22C10DF79006FF613 /* URLSessionProtocol.swift */; }; - 03F866692CF7D39900527C39 /* Foundation+Sendable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F866682CF7D39900527C39 /* Foundation+Sendable.swift */; }; - 03F8666A2CF7D39900527C39 /* Foundation+Sendable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F866682CF7D39900527C39 /* Foundation+Sendable.swift */; }; 03FE3F792C87A9D900D25810 /* EventError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03FE3F782C87A9D900D25810 /* EventError.swift */; }; 03FE3F7A2C87A9DC00D25810 /* EventError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03FE3F782C87A9D900D25810 /* EventError.swift */; }; 03FE3F7C2C87AC9900D25810 /* Event+InlineMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03FE3F7B2C87AC9900D25810 /* Event+InlineMetadata.swift */; }; @@ -480,6 +477,8 @@ C9B5C78E2C24AF650070445B /* MockRelaySubscriptionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0320C1142BFE63DC00C4C080 /* MockRelaySubscriptionManager.swift */; }; C9B678DB29EEBF3B00303F33 /* DependencyInjection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9B678DA29EEBF3B00303F33 /* DependencyInjection.swift */; }; C9B678DC29EEBF3B00303F33 /* DependencyInjection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9B678DA29EEBF3B00303F33 /* DependencyInjection.swift */; }; + C9B678DE29EEC35B00303F33 /* Foundation+Sendable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9B678DD29EEC35B00303F33 /* Foundation+Sendable.swift */; }; + C9B678DF29EEC35B00303F33 /* Foundation+Sendable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9B678DD29EEC35B00303F33 /* Foundation+Sendable.swift */; }; C9B678E129EEC41000303F33 /* SocialGraphCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9B678E029EEC41000303F33 /* SocialGraphCache.swift */; }; C9B678E229EEC41000303F33 /* SocialGraphCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9B678E029EEC41000303F33 /* SocialGraphCache.swift */; }; C9B678E729F01A8500303F33 /* FullscreenProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9B678E629F01A8500303F33 /* FullscreenProgressView.swift */; }; @@ -615,7 +614,6 @@ 030036842C5D39DD002C71F5 /* RefreshController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshController.swift; sourceTree = ""; }; 030036AA2C5D872B002C71F5 /* NewNotesButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewNotesButton.swift; sourceTree = ""; }; 0303B11E2D0257D400077929 /* Nos 21.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Nos 21.xcdatamodel"; sourceTree = ""; }; - 0301495B2CFFA8B7000A0152 /* TabBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarController.swift; sourceTree = ""; }; 0303B13E2D025BDD00077929 /* AuthorList+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AuthorList+CoreDataProperties.swift"; sourceTree = ""; }; 0304D0A62C9B4BF2001D16C7 /* OpenGraphMetatdata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGraphMetatdata.swift; sourceTree = ""; }; 0304D0B12C9B731F001D16C7 /* MockOpenGraphService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockOpenGraphService.swift; sourceTree = ""; }; @@ -710,7 +708,6 @@ 03EB47062CB080110004FF35 /* BrokenLinkView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrokenLinkView.swift; sourceTree = ""; }; 03ED93462C46C48400C8D443 /* JSONEventTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONEventTests.swift; sourceTree = ""; }; 03F7C4F22C10DF79006FF613 /* URLSessionProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLSessionProtocol.swift; sourceTree = ""; }; - 03F866682CF7D39900527C39 /* Foundation+Sendable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Foundation+Sendable.swift"; sourceTree = ""; }; 03FE3F782C87A9D900D25810 /* EventError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventError.swift; sourceTree = ""; }; 03FE3F7B2C87AC9900D25810 /* Event+InlineMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Event+InlineMetadata.swift"; sourceTree = ""; }; 03FE3F8A2C87BC9500D25810 /* text_note_multiple_media.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = text_note_multiple_media.json; sourceTree = ""; }; @@ -964,6 +961,7 @@ C9ADB14029951CB10075E7F8 /* NSManagedObject+Nos.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSManagedObject+Nos.swift"; sourceTree = ""; }; C9B597642BBC8300002EC76A /* ImagePickerUIViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImagePickerUIViewController.swift; sourceTree = ""; }; C9B678DA29EEBF3B00303F33 /* DependencyInjection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DependencyInjection.swift; sourceTree = ""; }; + C9B678DD29EEC35B00303F33 /* Foundation+Sendable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Foundation+Sendable.swift"; sourceTree = ""; }; C9B678E029EEC41000303F33 /* SocialGraphCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SocialGraphCache.swift; sourceTree = ""; }; C9B678E629F01A8500303F33 /* FullscreenProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullscreenProgressView.swift; sourceTree = ""; }; C9B708BA2A13BE41006C613A /* NoteTextEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteTextEditor.swift; sourceTree = ""; }; @@ -1898,7 +1896,7 @@ C9F84C1B298DBBF400C6714D /* Data+Sha.swift */, C942566829B66A2800C4202C /* Date+Elapsed.swift */, C987F85729BA981800B44E7A /* Font+Clarity.swift */, - 03F866682CF7D39900527C39 /* Foundation+Sendable.swift */, + C9B678DD29EEC35B00303F33 /* Foundation+Sendable.swift */, C9F0BB6829A5039D000547FC /* Int+Bool.swift */, C9ADB14029951CB10075E7F8 /* NSManagedObject+Nos.swift */, C97A1C8D29E58EC7009D9E8D /* NSManagedObjectContext+Nos.swift */, @@ -1906,7 +1904,6 @@ C93EC2F329C34C860012EE2A /* NSPredicate+Bool.swift */, 50E2EB712C86175900D4B360 /* NSRegularExpression+Replacement.swift */, C93EC2F629C351470012EE2A /* Optional+Unwrap.swift */, - 045EDD042CAC025700B67964 /* ScrollViewProxy+Animate.swift */, C99721CA2AEBED26004EBEAB /* String+Empty.swift */, C9ADB13729928CC30075E7F8 /* String+Hex.swift */, C9DEC002298945150078B43A /* String+Lorem.swift */, @@ -1914,6 +1911,7 @@ DC2E54C72A700F1400C2CAAB /* UIDevice+Simulator.swift */, C92DF80429C25DE900400561 /* URL+Extensions.swift */, C9C2B77B29E072E400548B4A /* WebSocket+Nos.swift */, + 045EDD042CAC025700B67964 /* ScrollViewProxy+Animate.swift */, ); path = Extensions; sourceTree = ""; @@ -2028,7 +2026,6 @@ children = ( C9F84C20298DC36800C6714D /* AppView.swift */, 030024182CC00DF70073ED56 /* SplashScreenView.swift */, - 0301495B2CFFA8B7000A0152 /* TabBarController.swift */, 5B79F6402BA11618002DA9BE /* Components */, 65BD8DC12BDAF2C300802039 /* Discover */, 03618B112C825D8700BCBC55 /* Fixtures */, @@ -2149,7 +2146,7 @@ attributes = { BuildIndependentTargetsInParallel = 1; LastSwiftUpdateCheck = 1420; - LastUpgradeCheck = 1610; + LastUpgradeCheck = 1530; TargetAttributes = { C90862BA29E9804B00C35A71 = { CreatedOnToolsVersion = 14.2; @@ -2363,6 +2360,7 @@ 50089A0C2C97182200834588 /* CurrentUser+PublishEvents.swift in Sources */, C97A1C8E29E58EC7009D9E8D /* NSManagedObjectContext+Nos.swift in Sources */, 5BBA5E9C2BAE052F00D57D76 /* NiceWorkSheet.swift in Sources */, + C9B678DE29EEC35B00303F33 /* Foundation+Sendable.swift in Sources */, 5B88051A2A21027C00E21F06 /* SHA256Key.swift in Sources */, C9B71DC22A9003670031ED9F /* CrashReporting.swift in Sources */, C987F81729BA4C6A00B44E7A /* BigActionButton.swift in Sources */, @@ -2482,8 +2480,6 @@ C9F84C27298DC98800C6714D /* KeyPair.swift in Sources */, 5B8C96B629DDD3B200B73AEC /* NoteUITextViewRepresentable.swift in Sources */, C93EC2F129C337EB0012EE2A /* RelayPicker.swift in Sources */, - 0301495C2CFFA8B7000A0152 /* TabBarController.swift in Sources */, - 03F866692CF7D39900527C39 /* Foundation+Sendable.swift in Sources */, 5BBA5E912BADF98E00D57D76 /* AlreadyHaveANIP05View.swift in Sources */, C9F0BB6F29A50437000547FC /* NostrIdentifierPrefix.swift in Sources */, C96D39272B61B6D200D3D0A1 /* RawNostrID.swift in Sources */, @@ -2727,6 +2723,7 @@ 03E711672C935114000B6F96 /* SoupOpenGraphParserTests.swift in Sources */, C9C5475C2A4F1D8C006B0741 /* NosNotification+CoreDataProperties.swift in Sources */, 03C49AC32C938DE100502321 /* SoupOpenGraphParser.swift in Sources */, + C9B678DF29EEC35B00303F33 /* Foundation+Sendable.swift in Sources */, 03EB470C2CB080180004FF35 /* BrokenLinkView.swift in Sources */, A3B943D7299D6DB700A15A08 /* Follow+CoreDataClass.swift in Sources */, C9ADB13E29929EEF0075E7F8 /* Bech32.swift in Sources */, @@ -2784,7 +2781,6 @@ C9DEC06F2989668E0078B43A /* Relay+CoreDataClass.swift in Sources */, C9ADB13F29929F1F0075E7F8 /* String+Hex.swift in Sources */, 500899F32C95C1F900834588 /* PushNotificationRegistrar.swift in Sources */, - 03F8666A2CF7D39900527C39 /* Foundation+Sendable.swift in Sources */, C973AB622A323167002AED16 /* Author+CoreDataProperties.swift in Sources */, C93EC2F529C34C860012EE2A /* NSPredicate+Bool.swift in Sources */, C9DEC05B298950A90078B43A /* String+Lorem.swift in Sources */, @@ -2986,6 +2982,7 @@ 5B7888CD2B5A0FB800B6761F /* Staging */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_GENERATE_ASSET_SYMBOLS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = NO; CODE_SIGN_STYLE = Automatic; @@ -3159,6 +3156,7 @@ 5BE460732BAB3028004B83ED /* Dev */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_GENERATE_ASSET_SYMBOLS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = NO; CODE_SIGN_STYLE = Automatic; @@ -3486,6 +3484,7 @@ C9DEBFFC298941020078B43A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_GENERATE_ASSET_SYMBOLS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = NO; CODE_SIGN_STYLE = Automatic; @@ -3515,6 +3514,7 @@ C9DEBFFD298941020078B43A /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_GENERATE_ASSET_SYMBOLS = NO; ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = NO; CODE_SIGN_STYLE = Automatic; diff --git a/Nos.xcodeproj/xcshareddata/xcschemes/Nos.xcscheme b/Nos.xcodeproj/xcshareddata/xcschemes/Nos.xcscheme index 0726952d7..69d8b3ad3 100644 --- a/Nos.xcodeproj/xcshareddata/xcschemes/Nos.xcscheme +++ b/Nos.xcodeproj/xcshareddata/xcschemes/Nos.xcscheme @@ -1,6 +1,6 @@ String? { let encoder = JSONEncoder() let data = try encoder.encode(self) - return String(data: data, encoding: .utf8) + return String(decoding: data, as: UTF8.self) } mutating func sign(withKey privateKey: KeyPair) throws { @@ -164,10 +164,7 @@ struct JSONEvent: Codable, Hashable, VerifiableEvent { func buildPublishRequest() throws -> String { let request: [Any] = ["EVENT", dictionary] let requestData = try JSONSerialization.data(withJSONObject: request) - guard let requestString = String(data: requestData, encoding: .utf8) else { - throw RelayError.parseError - } - return requestString + return String(decoding: requestData, as: UTF8.self) } } diff --git a/Nos/Models/KeyPair.swift b/Nos/Models/KeyPair.swift index c298c7bf1..b53fafc8d 100644 --- a/Nos/Models/KeyPair.swift +++ b/Nos/Models/KeyPair.swift @@ -116,9 +116,9 @@ extension KeyPair: RawRepresentable { } public var rawValue: String { - guard let data = try? JSONEncoder().encode(self), let string = String(data: data, encoding: .utf8) else { + guard let data = try? JSONEncoder().encode(self) else { return "{}" } - return string + return String(decoding: data, as: UTF8.self) } } diff --git a/Nos/Models/OpenGraph/SoupOpenGraphParser.swift b/Nos/Models/OpenGraph/SoupOpenGraphParser.swift index 2a9ebdff8..280ce0888 100644 --- a/Nos/Models/OpenGraph/SoupOpenGraphParser.swift +++ b/Nos/Models/OpenGraph/SoupOpenGraphParser.swift @@ -4,10 +4,8 @@ import SwiftSoup /// Parses the Open Graph metadata from an HTML document using SwiftSoup. struct SoupOpenGraphParser: OpenGraphParser { func metadata(html: Data) -> OpenGraphMetadata? { - guard - let htmlString = String(data: html, encoding: .utf8), - let document = try? SwiftSoup.parse(htmlString) - else { return nil } + let htmlString = String(decoding: html, as: UTF8.self) + guard let document = try? SwiftSoup.parse(htmlString) else { return nil } let title = stringValue(.title, from: document) let type = typeMetadata(from: document) diff --git a/Nos/Models/RawNostrID.swift b/Nos/Models/RawNostrID.swift index a2d979640..63391f9da 100644 --- a/Nos/Models/RawNostrID.swift +++ b/Nos/Models/RawNostrID.swift @@ -20,7 +20,7 @@ public typealias RawEventID = RawNostrID /// An alias for a RawNostrID that we know is for an Author. See docs for `RawNostrID`. public typealias RawAuthorID = RawNostrID -extension RawNostrID { +extension RawNostrID: Identifiable { public var id: String { self diff --git a/Nos/Service/CurrentUser+PublishEvents.swift b/Nos/Service/CurrentUser+PublishEvents.swift index f513966b9..e24268695 100644 --- a/Nos/Service/CurrentUser+PublishEvents.swift +++ b/Nos/Service/CurrentUser+PublishEvents.swift @@ -61,10 +61,7 @@ extension CurrentUser { let jsonObject = buildMetadataJSONObject(author: author) let data = try JSONSerialization.data(withJSONObject: jsonObject) - guard let content = String(data: data, encoding: .utf8) else { - Log.error("Error: Couldn't convert data to string") - throw CurrentUserError.errorWhilePublishingToRelays - } + let content = String(decoding: data, as: UTF8.self) let jsonEvent = JSONEvent( pubKey: pubKey, diff --git a/Nos/Service/CurrentUser.swift b/Nos/Service/CurrentUser.swift index d3e37f7e8..4ff0ffd07 100644 --- a/Nos/Service/CurrentUser.swift +++ b/Nos/Service/CurrentUser.swift @@ -83,7 +83,7 @@ import Dependencies self.socialGraph = SocialGraphCache(userKey: nil, context: persistenceController.newBackgroundContext()) if let privateKeyData = keychain.load(key: keychain.keychainPrivateKey) { Log.info("CurrentUser loaded a private key from keychain") - let hexString = String(data: privateKeyData, encoding: .utf8) + let hexString = String(decoding: privateKeyData, as: UTF8.self) _privateKeyHex = hexString setUp() if let keyPair { @@ -286,10 +286,8 @@ import Dependencies // MARK: - NSFetchedResultsControllerDelegate - func controllerDidChangeContent(_ controller: NSFetchedResultsController) { - Task { @MainActor in - author = controller.fetchedObjects?.first as? Author - } + @MainActor func controllerDidChangeContent(_ controller: NSFetchedResultsController) { + author = controller.fetchedObjects?.first as? Author } } // swiftlint:enable type_body_length diff --git a/Nos/Service/DependencyInjection.swift b/Nos/Service/DependencyInjection.swift index 5cef90ab2..0d6c37979 100644 --- a/Nos/Service/DependencyInjection.swift +++ b/Nos/Service/DependencyInjection.swift @@ -102,7 +102,7 @@ fileprivate enum AnalyticsKey: DependencyKey { static let previewValue = Analytics(mock: true) } -fileprivate enum CurrentUserKey: @preconcurrency DependencyKey { +fileprivate enum CurrentUserKey: DependencyKey { @MainActor static let liveValue = CurrentUser() @MainActor static let testValue = CurrentUser() @MainActor static let previewValue = CurrentUser() @@ -112,7 +112,7 @@ fileprivate enum FileStorageAPIClientKey: DependencyKey { static var liveValue: any FileStorageAPIClient = NostrBuildAPIClient() } -fileprivate enum RouterKey: @preconcurrency DependencyKey { +fileprivate enum RouterKey: DependencyKey { @MainActor static let liveValue = Router() @MainActor static let testValue = Router() @MainActor static let previewValue = Router() @@ -124,7 +124,7 @@ private enum RelayServiceKey: DependencyKey { static let previewValue: RelayService = MockRelayService() } -fileprivate enum PushNotificationServiceKey: @preconcurrency DependencyKey { +fileprivate enum PushNotificationServiceKey: DependencyKey { @MainActor static let liveValue = PushNotificationService() @MainActor static let testValue: PushNotificationService = MockPushNotificationService() @MainActor static let previewValue: PushNotificationService = MockPushNotificationService() @@ -177,7 +177,7 @@ fileprivate enum FeatureFlagsKey: DependencyKey { static let previewValue: any FeatureFlags = MockFeatureFlags() } -fileprivate enum KeychainKey: @preconcurrency DependencyKey { +fileprivate enum KeychainKey: DependencyKey { @MainActor static let liveValue: Keychain = SystemKeychain() @MainActor static let testValue: Keychain = InMemoryKeychain() @MainActor static let previewValue: Keychain = InMemoryKeychain() diff --git a/Nos/Service/PushNotificationRegistrar.swift b/Nos/Service/PushNotificationRegistrar.swift index f15d639d8..a730dda0a 100644 --- a/Nos/Service/PushNotificationRegistrar.swift +++ b/Nos/Service/PushNotificationRegistrar.swift @@ -93,10 +93,7 @@ final class PushNotificationRegistrar { publicKey: publicKeyHex, relays: relays ) - guard let string = String(data: try JSONEncoder().encode(content), encoding: .utf8) else { - throw PushNotificationError.unexpected - } - return string + return String(decoding: try JSONEncoder().encode(content), as: UTF8.self) } } diff --git a/Nos/Service/Relay/RelayService.swift b/Nos/Service/Relay/RelayService.swift index 93537f642..499f5d5ef 100644 --- a/Nos/Service/Relay/RelayService.swift +++ b/Nos/Service/Relay/RelayService.swift @@ -113,9 +113,7 @@ extension RelayService { await subscriptionManager.forceCloseSubscriptionCount(for: subscriptionID) let request: [Any] = ["CLOSE", subscriptionID] let requestData = try JSONSerialization.data(withJSONObject: request) - guard let requestString = String(data: requestData, encoding: .utf8) else { - throw RelayError.parseError - } + let requestString = String(decoding: requestData, as: UTF8.self) client.write(string: requestString) } catch { Log.error("Error: Could not send close \(error.localizedDescription)") @@ -531,9 +529,7 @@ extension RelayService { let request: [Any] = ["AUTH", jsonEvent.dictionary] let requestData = try JSONSerialization.data(withJSONObject: request) - guard let string = String(data: requestData, encoding: .utf8) else { - throw RelayError.parseError - } + let string = String(decoding: requestData, as: UTF8.self) socket.write(string: string) } catch { Log.error("Error authenticating with \(relayAddress)", error.localizedDescription) diff --git a/Nos/Service/Relay/RelaySubscriptionManager.swift b/Nos/Service/Relay/RelaySubscriptionManager.swift index 64aa3849f..5cfe64843 100644 --- a/Nos/Service/Relay/RelaySubscriptionManager.swift +++ b/Nos/Service/Relay/RelaySubscriptionManager.swift @@ -308,9 +308,7 @@ actor RelaySubscriptionManagerActor: RelaySubscriptionManager { // Track this so we can close requests if needed let request: [Any] = ["REQ", subscription.id, subscription.filter.dictionary] let requestData = try JSONSerialization.data(withJSONObject: request) - guard let requestString = String(data: requestData, encoding: .utf8) else { - throw RelayError.parseError - } + let requestString = String(decoding: requestData, as: UTF8.self) socket.write(string: requestString) } catch { Log.error("Error: Could not send request \(error.localizedDescription)") diff --git a/Nos/Service/ReportPublisher.swift b/Nos/Service/ReportPublisher.swift index b4c8f10a7..09a430bb5 100644 --- a/Nos/Service/ReportPublisher.swift +++ b/Nos/Service/ReportPublisher.swift @@ -145,9 +145,6 @@ struct ReportRequest { } let data = try JSONSerialization.data(withJSONObject: dictionary) - guard let string = String(data: data, encoding: .utf8) else { - throw ReportError.encodingFailed("Could not convert JSON data to a String") - } - return string + return String(decoding: data, as: UTF8.self) } } diff --git a/Nos/Views/AppView.swift b/Nos/Views/AppView.swift index 5bd1d21e0..f6ec3abf1 100644 --- a/Nos/Views/AppView.swift +++ b/Nos/Views/AppView.swift @@ -50,90 +50,123 @@ struct AppView: View { } private var tabView: some View { - TabBarController(selectedIndex: $router.selectedTab, viewControllers: makeViewControllers()) - .onChange(of: router.selectedTab) { _, newTab in - if case let AppDestination.noteComposer(contents) = newTab { - newPostContents = contents - showNewPost = true - router.selectedTab = lastSelectedTab - } else if !showNewPost { - lastSelectedTab = newTab - } + TabView(selection: $router.selectedTab) { + if let author = currentUser.author { + HomeTab(user: author) + .tabItem { + VStack { + let text = Text("homeFeed") + if $router.selectedTab.wrappedValue == .home { + Image.tabIconHomeSelected + text + } else { + Image.tabIconHome + text.foregroundColor(.secondaryTxt) + } + } + } + .toolbarBackground(.visible, for: .tabBar) + .toolbarBackground(Color.cardBgBottom, for: .tabBar) + .tag(AppDestination.home) + .onAppear { + // TODO: Move this somewhere better like CurrentUser when it becomes the source of truth + // for who is logged in + if let keyPair = currentUser.keyPair { + analytics.identify( + with: keyPair, + nip05: currentUser.author?.nip05 + ) + crashReporting.identify(with: keyPair) + } + } } - .overlay { - if router.isLoading { - ZStack { - Rectangle().fill(.black.opacity(0.4)) - ProgressView() + + DiscoverTab() + .tabItem { + VStack { + let text = Text("discover") + if $router.selectedTab.wrappedValue == .discover { + Image.tabIconEveryoneSelected + text.foregroundColor(.primaryTxt) + } else { + Image.tabIconEveryone + text.foregroundColor(.secondaryTxt) + } } } + .toolbarBackground(.visible, for: .tabBar) + .toolbarBackground(Color.cardBgBottom, for: .tabBar) + .tag(AppDestination.discover) + + VStack {} + .tabItem { + VStack { + Image.newPostButton + Text("post") + } + } + .tag(AppDestination.noteComposer(nil)) + + NotificationsView(user: currentUser.author) + .tabItem { + VStack { + let text = Text("notifications") + if $router.selectedTab.wrappedValue == .notifications { + Image.tabIconNotificationsSelected + text.foregroundColor(.primaryTxt) + } else { + Image.tabIconNotifications + text.foregroundColor(.secondaryTxt) + } + } + } + .toolbarBackground(.visible, for: .tabBar) + .toolbarBackground(Color.cardBgBottom, for: .tabBar) + .tag(AppDestination.notifications) + .badge(pushNotificationService.badgeCount) + + if let author = currentUser.author { + ProfileTab(author: author, path: $router.profilePath) + .tabItem { + VStack { + let text = Text("profileTitle") + if $router.selectedTab.wrappedValue == .profile { + Image.tabProfileSelected + text.foregroundColor(.primaryTxt) + } else { + Image.tabProfile + text.foregroundColor(.secondaryTxt) + } + } + } + .toolbarBackground(.visible, for: .tabBar) + .toolbarBackground(Color.cardBgBottom, for: .tabBar) + .tag(AppDestination.profile) } - .sheet(isPresented: $showNewPost) { - NoteComposer(initialContents: newPostContents, isPresented: $showNewPost) - .environment(currentUser) - .environment(relayService) - .interactiveDismissDisabled() + } + .onChange(of: router.selectedTab) { _, newTab in + if case let AppDestination.noteComposer(contents) = newTab { + newPostContents = contents + showNewPost = true + router.selectedTab = lastSelectedTab + } else if !showNewPost { + lastSelectedTab = newTab } - .ignoresSafeArea() - } - - private func makeViewControllers() -> [UIViewController] { - guard let author = currentUser.author else { return [] } - - var controllers: [UIViewController] = [] - - let homeVC = UIHostingController(rootView: HomeTab(user: author) - .onAppear { - if let keyPair = currentUser.keyPair { - analytics.identify( - with: keyPair, - nip05: currentUser.author?.nip05 - ) - crashReporting.identify(with: keyPair) + } + .overlay { + if router.isLoading { + ZStack { + Rectangle().fill(.black.opacity(0.4)) + ProgressView() } - }) - homeVC.tabBarItem = UITabBarItem( - title: String(localized: "homeFeed"), - image: UIImage.tabIconHome, - selectedImage: UIImage.tabIconHomeSelected - ) - controllers.append(homeVC) - - let discoverVC = UIHostingController(rootView: DiscoverTab()) - discoverVC.tabBarItem = UITabBarItem( - title: String(localized: "discover"), - image: UIImage.tabIconEveryone, - selectedImage: UIImage.tabIconEveryoneSelected - ) - controllers.append(discoverVC) - - let composerVC = UIViewController() - composerVC.tabBarItem = UITabBarItem( - title: String(localized: "post"), - image: UIImage.newPostButton, - selectedImage: UIImage.newPostButton - ) - controllers.append(composerVC) - - let notificationsVC = UIHostingController(rootView: NotificationsView(user: currentUser.author)) - notificationsVC.tabBarItem = UITabBarItem( - title: String(localized: "notifications"), - image: UIImage.tabIconNotifications, - selectedImage: UIImage.tabIconNotificationsSelected - ) - notificationsVC.tabBarItem.badgeValue = - pushNotificationService.badgeCount > 0 ? "\(pushNotificationService.badgeCount)" : nil - controllers.append(notificationsVC) - - let profileVC = UIHostingController(rootView: ProfileTab(author: author, path: $router.profilePath)) - profileVC.tabBarItem = UITabBarItem( - title: String(localized: "profileTitle"), - image: UIImage.tabProfile, - selectedImage: UIImage.tabProfileSelected - ) - controllers.append(profileVC) - - return controllers + } + } + .sheet(isPresented: $showNewPost) { + NoteComposer(initialContents: newPostContents, isPresented: $showNewPost) + .environment(currentUser) + .environment(relayService) + .interactiveDismissDisabled() + } } } diff --git a/Nos/Views/Components/Author/AuthorCard.swift b/Nos/Views/Components/Author/AuthorCard.swift index 3004c9e9a..22c1c94ae 100644 --- a/Nos/Views/Components/Author/AuthorCard.swift +++ b/Nos/Views/Components/Author/AuthorCard.swift @@ -93,7 +93,7 @@ struct AuthorCard: View { } #Preview { - @Previewable @State var previewData = PreviewData() + var previewData = PreviewData() return VStack { AuthorCard(author: previewData.alice) diff --git a/Nos/Views/Components/KnownFollowersView.swift b/Nos/Views/Components/KnownFollowersView.swift index 2690bdfaf..b10a9f778 100644 --- a/Nos/Views/Components/KnownFollowersView.swift +++ b/Nos/Views/Components/KnownFollowersView.swift @@ -94,7 +94,7 @@ struct KnownFollowersView: View { } #Preview { - @Previewable @State var previewData = PreviewData() + var previewData = PreviewData() return VStack { KnownFollowersView(source: previewData.currentUser.author, destination: previewData.alice) diff --git a/Nos/Views/Components/NosNavigationStack.swift b/Nos/Views/Components/NosNavigationStack.swift index fe3b6927a..0c975f87e 100644 --- a/Nos/Views/Components/NosNavigationStack.swift +++ b/Nos/Views/Components/NosNavigationStack.swift @@ -44,7 +44,7 @@ struct NosNavigationStack: View { } #Preview { - @Previewable @State var path = NavigationPath() + @State var path = NavigationPath() return NosNavigationStack(path: $path) { Text("hello world") diff --git a/Nos/Views/Components/NosToggle.swift b/Nos/Views/Components/NosToggle.swift index e17eb274d..71c1b5c9c 100644 --- a/Nos/Views/Components/NosToggle.swift +++ b/Nos/Views/Components/NosToggle.swift @@ -24,7 +24,7 @@ struct NosToggle: View { } #Preview { - @Previewable @State var isOn = true + @State var isOn = true return NosToggle( "useReportsFromFollows", diff --git a/Nos/Views/Components/NoteTextEditor.swift b/Nos/Views/Components/NoteTextEditor.swift index dee356d75..4c6716244 100644 --- a/Nos/Views/Components/NoteTextEditor.swift +++ b/Nos/Views/Components/NoteTextEditor.swift @@ -50,9 +50,10 @@ struct NoteTextEditor: View { } #Preview { - @Previewable @State var controller = NoteEditorController() - @Previewable @State var previewData = PreviewData() - + + var previewData = PreviewData() + @State var controller = NoteEditorController() + return NavigationStack { NoteTextEditor( controller: $controller, diff --git a/Nos/Views/Components/PagedNoteListView.swift b/Nos/Views/Components/PagedNoteListView.swift index 1eb085b88..6dac7b442 100644 --- a/Nos/Views/Components/PagedNoteListView.swift +++ b/Nos/Views/Components/PagedNoteListView.swift @@ -238,15 +238,15 @@ extension Notification.Name { } #Preview { - @Previewable @State var refreshController = RefreshController() - @Previewable @State var previewData = PreviewData() - + var previewData = PreviewData() + @State var refreshController = RefreshController() + return PagedNoteListView( refreshController: $refreshController, databaseFilter: previewData.alice.allPostsRequest(onlyRootPosts: false), relayFilter: Filter(), relay: nil, - managedObjectContext: previewData.context, + managedObjectContext: previewData.previewContext, tab: .home, header: { ProfileHeader(author: previewData.alice, selectedTab: .constant(.activity)) @@ -262,7 +262,7 @@ extension Notification.Name { .inject(previewData: previewData) .onAppear { for i in 0..<100 { - let note = Event(context: previewData.context) + let note = Event(context: previewData.previewContext) note.identifier = "ProfileNotesView-\(i)" note.kind = EventKind.text.rawValue note.content = "\(i)" diff --git a/Nos/Views/Components/RelayPicker.swift b/Nos/Views/Components/RelayPicker.swift index f01bb5abc..f24b7e413 100644 --- a/Nos/Views/Components/RelayPicker.swift +++ b/Nos/Views/Components/RelayPicker.swift @@ -145,14 +145,15 @@ struct RelayPickerRow: View { } #Preview("Without ScrollView") { - @Previewable @State var selectedRelay: Relay? - @Previewable @State var previewData = PreviewData() + @State var selectedRelay: Relay? + var previewData = PreviewData() + func createTestData() { let user = previewData.alice let addresses = ["wss://nostr.com", "wss://nos.social", "wss://alongdomainnametoseewhathappens.com"] addresses.forEach { address in - let relay = try? Relay.findOrCreate(by: address, context: previewData.context) + let relay = try? Relay.findOrCreate(by: address, context: previewData.previewContext) relay?.relayDescription = "A Nostr relay that aims to cultivate a healthy community." relay?.addToAuthors(user) } @@ -170,14 +171,15 @@ struct RelayPickerRow: View { } #Preview("With ScrollView") { - @Previewable @State var selectedRelay: Relay? - @Previewable @State var previewData = PreviewData() + + @State var selectedRelay: Relay? + var previewData = PreviewData() func createTestData() { let user = previewData.alice let addresses = Relay.allKnown addresses.forEach { address in - let relay = try? Relay.findOrCreate(by: address, context: previewData.context) + let relay = try? Relay.findOrCreate(by: address, context: previewData.previewContext) relay?.relayDescription = "A Nostr relay that aims to cultivate a healthy community." relay?.addToAuthors(user) } diff --git a/Nos/Views/Components/WarningView.swift b/Nos/Views/Components/WarningView.swift index 0e19e590b..408750076 100644 --- a/Nos/Views/Components/WarningView.swift +++ b/Nos/Views/Components/WarningView.swift @@ -165,7 +165,7 @@ struct ContentWarningMessage: View { } #Preview { - @Previewable @State var previewData = PreviewData() + var previewData = PreviewData() return VStack { ContentWarningMessage(reports: [previewData.shortNoteReportOne], type: .author) diff --git a/Nos/Views/Discover/DiscoverContentsView.swift b/Nos/Views/Discover/DiscoverContentsView.swift index a0c49c434..ff17274ac 100644 --- a/Nos/Views/Discover/DiscoverContentsView.swift +++ b/Nos/Views/Discover/DiscoverContentsView.swift @@ -82,7 +82,7 @@ struct DiscoverContentsView: View { LazyVStack { categoryPicker - ForEach(featuredAuthorIDs, id: \.self) { authorID in + ForEach(featuredAuthorIDs) { authorID in AuthorObservationView(authorID: authorID) { author in VStack { if author.lastUpdatedMetadata != nil { diff --git a/Nos/Views/Fixtures/PreviewData.swift b/Nos/Views/Fixtures/PreviewData.swift index 036034473..9e1de7760 100644 --- a/Nos/Views/Fixtures/PreviewData.swift +++ b/Nos/Views/Fixtures/PreviewData.swift @@ -27,7 +27,7 @@ struct PreviewData { @Dependency(\.relayService) var relayService @Dependency(\.currentUser) var currentUser - lazy var context: NSManagedObjectContext = { + lazy var previewContext: NSManagedObjectContext = { persistenceController.viewContext }() @@ -38,7 +38,7 @@ struct PreviewData { }() lazy var alice: Author = { - let author = try! Author.findOrCreate(by: KeyFixture.alice.publicKeyHex, context: context) + let author = try! Author.findOrCreate(by: KeyFixture.alice.publicKeyHex, context: previewContext) author.name = "Alice" author.nip05 = "alice@nos.social" author.profilePhotoURL = URL(string: "https://github.com/planetary-social/nos/assets/1165004/07f83f00-4555-4db3-85fc-f1a05b1908a2") @@ -49,7 +49,7 @@ struct PreviewData { }() lazy var bob: Author = { - let author = try! Author.findOrCreate(by: KeyFixture.bob.publicKeyHex, context: context) + let author = try! Author.findOrCreate(by: KeyFixture.bob.publicKeyHex, context: previewContext) author.hexadecimalPublicKey = KeyFixture.bob.publicKeyHex author.name = "Bob" author.profilePhotoURL = URL(string: "https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Ftse1.mm.bing.net%2Fth%3Fid%3DOIP.r1ZOH5E3M6WiK6aw5GRdlAHaEK%26pid%3DApi&f=1&ipt=42ae9de7730da3bda152c5980cd64b14ccef37d8f55b8791e41b4667fc38ddf1&ipo=images") @@ -58,7 +58,7 @@ struct PreviewData { }() lazy var eve: Author = { - let author = try! Author.findOrCreate(by: KeyFixture.eve.publicKeyHex, context: context) + let author = try! Author.findOrCreate(by: KeyFixture.eve.publicKeyHex, context: previewContext) author.name = "Eve" author.nip05 = "eve@nos.social" @@ -66,7 +66,7 @@ struct PreviewData { }() lazy var blockedUser: Author = { - let author = try! Author.findOrCreate(by: KeyFixture.eve.publicKeyHex, context: context) + let author = try! Author.findOrCreate(by: KeyFixture.eve.publicKeyHex, context: previewContext) author.name = "Sam" author.about = "I am a terrible person" author.muted = true @@ -78,18 +78,18 @@ struct PreviewData { // MARK: - Notes lazy var shortNote: Event = { - let note = Event(context: context) + let note = Event(context: previewContext) note.identifier = "1" note.kind = EventKind.text.rawValue note.content = "Hello, world!" note.author = previewAuthor note.createdAt = .now - try? context.save() + try? previewContext.save() return note }() lazy var expiringNote: Event = { - let note = Event(context: context) + let note = Event(context: previewContext) note.identifier = "10" note.kind = EventKind.text.rawValue note.content = "Hello, world!" @@ -101,56 +101,56 @@ struct PreviewData { dateComponents.day = 1 let tomorrow = calendar.date(byAdding: dateComponents, to: currentDate)! note.expirationDate = tomorrow - try? context.save() + try? previewContext.save() return note }() lazy var imageNote: Event = { - let note = Event(context: context) + let note = Event(context: previewContext) note.identifier = "2" note.kind = EventKind.text.rawValue note.content = "Hello, world!https://cdn.ymaws.com/nacfm.com/resource/resmgr/images/blog_photos/footprints.jpg" note.author = previewAuthor note.createdAt = .now - try? context.save() + try? previewContext.save() return note }() lazy var verticalImageNote: Event = { - let note = Event(context: context) + let note = Event(context: previewContext) note.identifier = "3" note.kind = EventKind.text.rawValue note.content = "Hello, world!https://nostr.build/i/nostr.build_1b958a2af7a2c3fcb2758dd5743912e697ba34d3a6199bfb1300fa6be1dc62ee.jpeg" note.author = previewAuthor note.createdAt = .now - try? context.save() + try? previewContext.save() return note }() lazy var veryWideImageNote: Event = { - let note = Event(context: context) + let note = Event(context: previewContext) note.identifier = "4" note.kind = EventKind.text.rawValue note.content = "Hello, world! https://nostr.build/i/nostr.build_db8287dde9aedbc65df59972386fde14edf9e1afc210e80c764706e61cd1cdfa.png" note.author = previewAuthor note.createdAt = .now - try? context.save() + try? previewContext.save() return note }() lazy var longNote: Event = { - let note = Event(context: context) + let note = Event(context: previewContext) note.identifier = "5" note.kind = EventKind.text.rawValue note.createdAt = .now note.content = .loremIpsum(5) note.author = previewAuthor - try? context.save() + try? previewContext.save() return note }() lazy var longFormNote: Event = { - let note = Event(context: context) + let note = Event(context: previewContext) note.identifier = "6" note.createdAt = .now note.kind = EventKind.longFormContent.rawValue @@ -164,12 +164,12 @@ struct PreviewData { And it has a link to [nos.social](https://nos.social). """ note.author = previewAuthor - try? context.save() + try? previewContext.save() return note }() lazy var doubleImageNote: Event = { - let note = Event(context: context) + let note = Event(context: previewContext) note.identifier = "7" note.kind = EventKind.text.rawValue note.content = """ @@ -182,12 +182,12 @@ struct PreviewData { """ note.author = previewAuthor note.createdAt = .now - try? context.save() + try? previewContext.save() return note }() lazy var linkNote: Event = { - let note = Event(context: context) + let note = Event(context: previewContext) note.identifier = "8" note.kind = EventKind.text.rawValue note.content = """ @@ -209,17 +209,17 @@ struct PreviewData { """ note.author = previewAuthor note.createdAt = .now - try? context.save() + try? previewContext.save() return note }() lazy var repost: Event = { - let originalPostAuthor = Author(context: context) + let originalPostAuthor = Author(context: previewContext) originalPostAuthor.hexadecimalPublicKey = KeyFixture.bob.publicKeyHex originalPostAuthor.name = "Bob" originalPostAuthor.profilePhotoURL = URL(string: "https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Ftse1.mm.bing.net%2Fth%3Fid%3DOIP.r1ZOH5E3M6WiK6aw5GRdlAHaEK%26pid%3DApi&f=1&ipt=42ae9de7730da3bda152c5980cd64b14ccef37d8f55b8791e41b4667fc38ddf1&ipo=images") - let repostedNote = Event(context: context) + let repostedNote = Event(context: previewContext) repostedNote.identifier = "3" repostedNote.kind = EventKind.text.rawValue repostedNote.createdAt = .now @@ -228,81 +228,81 @@ struct PreviewData { let reference: EventReference do { - reference = try EventReference(jsonTag: ["e", "3", ""], context: context) + reference = try EventReference(jsonTag: ["e", "3", ""], context: previewContext) } catch { print(error) - reference = EventReference(context: context) + reference = EventReference(context: previewContext) } - let repost = Event(context: context) + let repost = Event(context: previewContext) repost.identifier = "4" repost.kind = EventKind.repost.rawValue repost.createdAt = .now repost.author = previewAuthor repost.eventReferences = NSOrderedSet(array: [reference]) - try? context.save() + try? previewContext.save() return repost }() lazy var reply: Event = { let rootNote = longNote - let note = Event(context: context) + let note = Event(context: previewContext) note.identifier = "11" note.kind = EventKind.text.rawValue note.content = "Well that's pretty neat" note.author = bob note.createdAt = .now - let rootReference = EventReference(context: context) + let rootReference = EventReference(context: previewContext) rootReference.eventId = rootNote.identifier rootReference.marker = "root" rootReference.referencedEvent = rootNote note.insertIntoEventReferences(rootReference, at: 0) - try? context.save() + try? previewContext.save() return note }() // MARK: Reports lazy var shortNoteReportOne: Event = { - let note = Event(context: context) + let note = Event(context: previewContext) note.identifier = "r1" note.kind = EventKind.report.rawValue note.content = "impersonation" note.author = bob note.createdAt = .now - let reference = EventReference(context: context) + let reference = EventReference(context: previewContext) reference.eventId = "1" reference.referencedEvent = shortNote note.insertIntoEventReferences(reference, at: 0) - try? context.save() + try? previewContext.save() return note }() lazy var reportBobTwo: Event = { - let note = Event(context: context) + let note = Event(context: previewContext) note.identifier = "r4" note.kind = EventKind.report.rawValue note.content = "harassment" note.author = bob note.createdAt = .now - let reference = EventReference(context: context) + let reference = EventReference(context: previewContext) reference.eventId = "1" reference.referencedEvent = shortNote note.insertIntoEventReferences(reference, at: 0) - try? context.save() + try? previewContext.save() return note }() lazy var shortNoteReportTwo: Event = { - let note = Event(context: context) + let note = Event(context: previewContext) note.identifier = "r2" note.kind = EventKind.report.rawValue note.content = "harassment" @@ -312,17 +312,17 @@ struct PreviewData { note.author = eve note.createdAt = .now - let reference = EventReference(context: context) + let reference = EventReference(context: previewContext) reference.eventId = "1" reference.referencedEvent = shortNote note.insertIntoEventReferences(reference, at: 0) - try? context.save() + try? previewContext.save() return note }() lazy var shortNoteReportThree: Event = { - let note = Event(context: context) + let note = Event(context: previewContext) note.identifier = "r3" note.kind = EventKind.report.rawValue note.content = "this person is spammy" @@ -333,12 +333,12 @@ struct PreviewData { note.author = alice note.createdAt = .now - let reference = EventReference(context: context) + let reference = EventReference(context: previewContext) reference.eventId = "1" reference.referencedEvent = shortNote note.insertIntoEventReferences(reference, at: 0) - try? context.save() + try? previewContext.save() return note }() } diff --git a/Nos/Views/Home/HomeFeedView.swift b/Nos/Views/Home/HomeFeedView.swift index d36e73fc1..dd866310f 100644 --- a/Nos/Views/Home/HomeFeedView.swift +++ b/Nos/Views/Home/HomeFeedView.swift @@ -168,13 +168,13 @@ struct HomeFeedView: View { } #Preview { - @Previewable @State var previewData = PreviewData() + var previewData = PreviewData() func createTestData() { let user = previewData.alice let addresses = Relay.recommended addresses.forEach { address in - let relay = try? Relay.findOrCreate(by: address, context: previewData.context) + let relay = try? Relay.findOrCreate(by: address, context: previewData.previewContext) relay?.relayDescription = "A Nostr relay that aims to cultivate a healthy community." relay?.addToAuthors(user) } diff --git a/Nos/Views/Note/NoteCard.swift b/Nos/Views/Note/NoteCard.swift index afb62cf24..30f844bd3 100644 --- a/Nos/Views/Note/NoteCard.swift +++ b/Nos/Views/Note/NoteCard.swift @@ -225,7 +225,7 @@ struct NoteCard_Previews: PreviewProvider { } } } - .environment(\.managedObjectContext, previewData.context) + .environment(\.managedObjectContext, previewData.previewContext) .environment(previewData.relayService) .environmentObject(previewData.router) .environment(previewData.currentUser) diff --git a/Nos/Views/NoteComposer/ComposerActionBar.swift b/Nos/Views/NoteComposer/ComposerActionBar.swift index 55adedc71..dd9e5da5a 100644 --- a/Nos/Views/NoteComposer/ComposerActionBar.swift +++ b/Nos/Views/NoteComposer/ComposerActionBar.swift @@ -180,7 +180,7 @@ struct ComposerActionBar: View { do { startUploadingImage() let url = try await fileStorageAPIClient.upload(fileAt: imageURL, isProfilePhoto: false) - editingController.append(url) + await editingController.append(url) endUploadingImage() } catch { endUploadingImage() diff --git a/Nos/Views/NoteComposer/NoteComposer.swift b/Nos/Views/NoteComposer/NoteComposer.swift index e4013085c..b94c87ff0 100644 --- a/Nos/Views/NoteComposer/NoteComposer.swift +++ b/Nos/Views/NoteComposer/NoteComposer.swift @@ -399,7 +399,7 @@ struct NoteComposer: View { } #Preview { - @Previewable @State var previewData = PreviewData() + var previewData = PreviewData() return NoteComposer(replyTo: previewData.longNote, isPresented: .constant(true)) .inject(previewData: previewData) diff --git a/Nos/Views/NoteComposer/ReplyPreview.swift b/Nos/Views/NoteComposer/ReplyPreview.swift index 3278f80af..f66c8c551 100644 --- a/Nos/Views/NoteComposer/ReplyPreview.swift +++ b/Nos/Views/NoteComposer/ReplyPreview.swift @@ -38,7 +38,7 @@ struct ReplyPreview: View { } #Preview { - @Previewable @State var previewData = PreviewData() + var previewData = PreviewData() return ReplyPreview(note: previewData.longNote) .background(Color.appBg) diff --git a/Nos/Views/Notifications/NotificationCard.swift b/Nos/Views/Notifications/NotificationCard.swift index 0b1482a08..82ffc2d49 100644 --- a/Nos/Views/Notifications/NotificationCard.swift +++ b/Nos/Views/Notifications/NotificationCard.swift @@ -92,9 +92,10 @@ struct NotificationCard: View { } #Preview { - @Previewable @State var previewData = PreviewData() - let context = previewData.context - + var previewData = PreviewData() + + let previewContext = previewData.previewContext + var alice: Author { previewData.alice } @@ -104,16 +105,16 @@ struct NotificationCard: View { } let note: Event = { - let mentionNote = Event(context: context) + let mentionNote = Event(context: previewContext) mentionNote.content = "Hello, bob!" mentionNote.kind = 1 mentionNote.createdAt = .now mentionNote.author = alice - let authorRef = AuthorReference(context: context) + let authorRef = AuthorReference(context: previewContext) authorRef.pubkey = bob.hexadecimalPublicKey mentionNote.authorReferences = NSMutableOrderedSet(array: [authorRef]) try? mentionNote.sign(withKey: KeyFixture.alice) - try? context.save() + try? previewContext.save() return mentionNote }() diff --git a/Nos/Views/Notifications/NotificationsView.swift b/Nos/Views/Notifications/NotificationsView.swift index 296c2cb38..ce962c4a8 100644 --- a/Nos/Views/Notifications/NotificationsView.swift +++ b/Nos/Views/Notifications/NotificationsView.swift @@ -127,7 +127,7 @@ struct NotificationsView_Previews: PreviewProvider { static var previewData = PreviewData() - static var previewContext = previewData.context + static var previewContext = previewData.previewContext static var alice: Author { previewData.alice diff --git a/Nos/Views/Onboarding/Components/CopyKeyView.swift b/Nos/Views/Onboarding/Components/CopyKeyView.swift index 14700c1fc..457ec1296 100644 --- a/Nos/Views/Onboarding/Components/CopyKeyView.swift +++ b/Nos/Views/Onboarding/Components/CopyKeyView.swift @@ -45,11 +45,11 @@ struct CopyKeyView: View { } #Preview { - @Previewable @State var privateKey = KeyFixture.nsec - @Previewable @State var privateCopyButtonState = CopyButtonState.copy + @State var privateKey = KeyFixture.nsec + @State var privateCopyButtonState = CopyButtonState.copy - @Previewable @State var publicKey = KeyFixture.npub - @Previewable @State var publicCopyButtonState = CopyButtonState.copied + @State var publicKey = KeyFixture.npub + @State var publicCopyButtonState = CopyButtonState.copied return VStack(spacing: 40) { CopyKeyView("copyPrivateKey", keyString: $privateKey, copyButtonState: $privateCopyButtonState) diff --git a/Nos/Views/Onboarding/DisplayNameView.swift b/Nos/Views/Onboarding/DisplayNameView.swift index 52396983c..92af67a85 100644 --- a/Nos/Views/Onboarding/DisplayNameView.swift +++ b/Nos/Views/Onboarding/DisplayNameView.swift @@ -73,7 +73,7 @@ struct DisplayNameView: View { /// Saves the display name locally and publishes the event to relays. Sets `showError` if it fails. func save() async { - guard let author = currentUser.author else { + guard let author = await currentUser.author else { showError = true return } diff --git a/Nos/Views/Onboarding/UsernameView.swift b/Nos/Views/Onboarding/UsernameView.swift index 1b44238cc..df8235d8d 100644 --- a/Nos/Views/Onboarding/UsernameView.swift +++ b/Nos/Views/Onboarding/UsernameView.swift @@ -152,7 +152,7 @@ struct UsernameView: View { func save() async { usernameState = .loading - guard let author = currentUser.author, + guard let author = await currentUser.author, let keyPair = currentUser.keyPair else { usernameState = .errorAlert return diff --git a/Nos/Views/Profile/ActivityPubBadgeView.swift b/Nos/Views/Profile/ActivityPubBadgeView.swift index 779141fa6..09ba5ec2d 100644 --- a/Nos/Views/Profile/ActivityPubBadgeView.swift +++ b/Nos/Views/Profile/ActivityPubBadgeView.swift @@ -29,7 +29,7 @@ struct ActivityPubBadgeView: View { } #Preview { - @Previewable @State var previewData = PreviewData() + var previewData = PreviewData() return VStack { ActivityPubBadgeView(author: previewData.alice) diff --git a/Nos/Views/Profile/BioSheet.swift b/Nos/Views/Profile/BioSheet.swift index c160dc45e..9bc0c31aa 100644 --- a/Nos/Views/Profile/BioSheet.swift +++ b/Nos/Views/Profile/BioSheet.swift @@ -154,7 +154,7 @@ struct BioSheet: View { } #Preview("BioSheet") { - @Previewable @State var previewData = PreviewData() + var previewData = PreviewData() return Group { BioSheet(author: previewData.eve) diff --git a/Nos/Views/Profile/Edit/DeleteUsernameWizard/ConfirmUsernameDeletionSheet.swift b/Nos/Views/Profile/Edit/DeleteUsernameWizard/ConfirmUsernameDeletionSheet.swift index 10cd3c186..4ba32e58f 100644 --- a/Nos/Views/Profile/Edit/DeleteUsernameWizard/ConfirmUsernameDeletionSheet.swift +++ b/Nos/Views/Profile/Edit/DeleteUsernameWizard/ConfirmUsernameDeletionSheet.swift @@ -166,7 +166,7 @@ fileprivate enum DeleteError: LocalizedError { } #Preview { - @Previewable @State var previewData = PreviewData() + var previewData = PreviewData() return Color.clear.sheet(isPresented: .constant(true)) { ConfirmUsernameDeletionSheet( author: previewData.alice, diff --git a/Nos/Views/Profile/Edit/DeleteUsernameWizard/DeleteUsernameWizard.swift b/Nos/Views/Profile/Edit/DeleteUsernameWizard/DeleteUsernameWizard.swift index 3f8d2d009..52cfe4261 100644 --- a/Nos/Views/Profile/Edit/DeleteUsernameWizard/DeleteUsernameWizard.swift +++ b/Nos/Views/Profile/Edit/DeleteUsernameWizard/DeleteUsernameWizard.swift @@ -16,7 +16,7 @@ struct DeleteUsernameWizard: View { } #Preview { - @Previewable @State var previewData = PreviewData() + var previewData = PreviewData() return Color.clear.sheet(isPresented: .constant(true)) { DeleteUsernameWizard( author: previewData.alice, diff --git a/Nos/Views/Profile/ProfileHeader.swift b/Nos/Views/Profile/ProfileHeader.swift index 92bc28ff7..e916c9f10 100644 --- a/Nos/Views/Profile/ProfileHeader.swift +++ b/Nos/Views/Profile/ProfileHeader.swift @@ -278,7 +278,7 @@ struct ProfileHeader: View { } #Preview { - @Previewable @State var previewData = PreviewData() + var previewData = PreviewData() return Group { // ProfileHeader(author: author) @@ -290,28 +290,28 @@ struct ProfileHeader: View { } #Preview { - @Previewable @State var previewData = PreviewData() + var previewData = PreviewData() var author: Author { - let context = previewData.context - let author = Author(context: context) + let previewContext = previewData.previewContext + let author = Author(context: previewContext) author.hexadecimalPublicKey = KeyFixture.pubKeyHex - author.add(relay: Relay(context: context)) + author.add(relay: Relay(context: previewContext)) author.name = "Sebastian Heit" author.nip05 = "chardot@nostr.fan" author.about = "Go programmer working on Nos/Planetary. You can find me at various European events related to" + " Chaos Computer Club, the hacker community and free software." - let first = Author(context: context) + let first = Author(context: previewContext) first.name = "Craig Nichols" - let second = Author(context: context) + let second = Author(context: previewContext) second.name = "Justin Pool" - let firstFollow = Follow(context: context) + let firstFollow = Follow(context: previewContext) firstFollow.source = first firstFollow.destination = author - let secondFollow = Follow(context: context) + let secondFollow = Follow(context: previewContext) secondFollow.source = second secondFollow.destination = author @@ -324,6 +324,7 @@ struct ProfileHeader: View { ProfileHeader(author: author, selectedTab: .constant(.activity)) } .inject(previewData: previewData) + .previewDevice("iPhone SE (2nd generation)") .padding() .background(Color.previewBg) } diff --git a/Nos/Views/Profile/ProfileView.swift b/Nos/Views/Profile/ProfileView.swift index 5a6075375..5e7e31869 100644 --- a/Nos/Views/Profile/ProfileView.swift +++ b/Nos/Views/Profile/ProfileView.swift @@ -245,7 +245,7 @@ struct ProfileView: View { } #Preview("Generic user") { - @Previewable @State var previewData = PreviewData() + var previewData = PreviewData() return NavigationStack { ProfileView(author: previewData.previewAuthor) diff --git a/Nos/Views/TabBarController.swift b/Nos/Views/TabBarController.swift deleted file mode 100644 index 8d30f4302..000000000 --- a/Nos/Views/TabBarController.swift +++ /dev/null @@ -1,71 +0,0 @@ -import SwiftUI -import UIKit - -struct TabBarController: UIViewControllerRepresentable { - @Binding var selectedIndex: AppDestination - let viewControllers: [UIViewController] - - func makeUIViewController(context: Context) -> UITabBarController { - let tabController = WorkaroundTabBarController() - tabController.viewControllers = viewControllers - tabController.delegate = context.coordinator - - tabController.tabBar.backgroundColor = .cardBgBottom - tabController.tabBar.isTranslucent = true - tabController.tabBar.tintColor = .primaryTxt - tabController.tabBar.unselectedItemTintColor = .secondaryTxt - - // removes the translucency to match the design - tabController.tabBar.backgroundImage = UIImage() - tabController.tabBar.shadowImage = UIImage() - - return tabController - } - - func updateUIViewController(_ tabController: UITabBarController, context: Context) { - if case .noteComposer = selectedIndex { - // Don't update tab selection for composer - return - } - tabController.selectedIndex = selectedIndex.tabIndex - } - - func makeCoordinator() -> Coordinator { - Coordinator(self) - } - - class Coordinator: NSObject, UITabBarControllerDelegate { - var parent: TabBarController - - init(_ parent: TabBarController) { - self.parent = parent - } - - func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) { - parent.selectedIndex = AppDestination.tabDestinations[tabBarController.selectedIndex] - } - } -} - -class WorkaroundTabBarController: UITabBarController { - init() { - super.init(nibName: nil, bundle: nil) - - // Fix for macOS Sequoia: without this, the tabs appear twice and the view crashes regularly. - if #available(iOS 18, *), ProcessInfo.processInfo.isiOSAppOnMac { - // Hides the top tabs - mode = .tabSidebar - sidebar.isHidden = true - additionalSafeAreaInsets.bottom = 10 - traitOverrides.horizontalSizeClass = .compact - } else if traitCollection.userInterfaceIdiom == .pad { - additionalSafeAreaInsets.bottom = 10 - traitOverrides.horizontalSizeClass = .compact - } - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} diff --git a/NosTests/Controller/ContentWarningControllerTests.swift b/NosTests/Controller/ContentWarningControllerTests.swift index 11f7518fc..36c7e6520 100644 --- a/NosTests/Controller/ContentWarningControllerTests.swift +++ b/NosTests/Controller/ContentWarningControllerTests.swift @@ -10,7 +10,7 @@ final class ContentWarningControllerTests: CoreDataTestCase { override func setUp() async throws { try await super.setUp() fixture = PreviewData() - fixture.context = testContext + fixture.previewContext = testContext } func test_noReports() throws { diff --git a/NosTests/Models/CoreData/EventTests.swift b/NosTests/Models/CoreData/EventTests.swift index 178d758c3..85fb72a20 100644 --- a/NosTests/Models/CoreData/EventTests.swift +++ b/NosTests/Models/CoreData/EventTests.swift @@ -20,8 +20,8 @@ final class EventTests: CoreDataTestCase { // Act let serializedData = try JSONSerialization.data(withJSONObject: event.serializedEventForSigning) - let actualString = try XCTUnwrap(String(data: serializedData, encoding: .utf8)) - + let actualString = String(decoding: serializedData, as: UTF8.self) + // Assert XCTAssertEqual(actualString, expectedString) }