diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a718a8a9..a0bfefc92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - 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) +- Added the Inject framework for hot reloading. [#1710](https://github.com/planetary-social/nos/pull/1710) ## [1.0.3] - 2024-12-04Z diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 82968477f..e14ab2151 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -53,6 +53,10 @@ For now `main` is the main branch and code improvements are made in topic branch A maintainer will review your code and merge it when it has the required number of approvals. +## Hot Reloading + +We make use of the [Inject](https://github.com/krzysztofzablocki/Inject) framework for hot reloading debug builds. To set up hot reloading, follow the [documentation](https://github.com/krzysztofzablocki/Inject?tab=readme-ov-file#individual-developer-setup-once-per-machine). + ## Dependency Management We prefer to install dependencies using the Swift Package Manager. diff --git a/Nos.xcodeproj/project.pbxproj b/Nos.xcodeproj/project.pbxproj index b1cf16735..599e36e1e 100644 --- a/Nos.xcodeproj/project.pbxproj +++ b/Nos.xcodeproj/project.pbxproj @@ -437,6 +437,7 @@ C987F85429BA951E00B44E7A /* ClarityCity-Thin.otf in Resources */ = {isa = PBXBuildFile; fileRef = C987F83129BA951E00B44E7A /* ClarityCity-Thin.otf */; }; C987F85529BA951E00B44E7A /* ClarityCity-Thin.otf in Resources */ = {isa = PBXBuildFile; fileRef = C987F83129BA951E00B44E7A /* ClarityCity-Thin.otf */; }; C987F85B29BA9ED800B44E7A /* Font+Clarity.swift in Sources */ = {isa = PBXBuildFile; fileRef = C987F85729BA981800B44E7A /* Font+Clarity.swift */; }; + C9887D812D1EF3C400CF9101 /* Inject in Frameworks */ = {isa = PBXBuildFile; productRef = C98905A12CD3B8CF00C17EE0 /* Inject */; }; C98A32272A05795E00E3FA13 /* Task+Timeout.swift in Sources */ = {isa = PBXBuildFile; fileRef = C98A32262A05795E00E3FA13 /* Task+Timeout.swift */; }; C98A32282A05795E00E3FA13 /* Task+Timeout.swift in Sources */ = {isa = PBXBuildFile; fileRef = C98A32262A05795E00E3FA13 /* Task+Timeout.swift */; }; C98B8B4029FBF83B009789C8 /* NotificationCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = C98B8B3F29FBF83B009789C8 /* NotificationCard.swift */; }; @@ -1052,6 +1053,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + C9887D812D1EF3C400CF9101 /* Inject in Frameworks */, C9DEC068298965270078B43A /* Starscream in Frameworks */, C9FD35132BCED5A6008F8D95 /* NostrSDK in Frameworks */, C9B71DC02A8E9BAD0031ED9F /* SentrySwiftUI in Frameworks */, @@ -2101,6 +2103,7 @@ C9FD35122BCED5A6008F8D95 /* NostrSDK */, 03C49ABF2C938A9C00502321 /* SwiftSoup */, 039389222CA4985C00698978 /* SDWebImageWebPCoder */, + C98905A12CD3B8CF00C17EE0 /* Inject */, ); productName = Nos; productReference = C9DEBFCE298941000078B43A /* Nos.app */; @@ -2197,6 +2200,7 @@ C9FD35112BCED5A6008F8D95 /* XCRemoteSwiftPackageReference "nostr-sdk-ios" */, 03C49ABE2C938A9C00502321 /* XCRemoteSwiftPackageReference "SwiftSoup" */, 039389212CA4985C00698978 /* XCRemoteSwiftPackageReference "SDWebImageWebPCoder" */, + C98905A02CD3B8CF00C17EE0 /* XCRemoteSwiftPackageReference "Inject" */, ); productRefGroup = C9DEBFCF298941000078B43A /* Products */; projectDirPath = ""; @@ -2919,6 +2923,7 @@ MACOSX_DEPLOYMENT_TARGET = 13.3; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; + OTHER_LDFLAGS = ""; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; }; @@ -3089,6 +3094,7 @@ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; + OTHER_LDFLAGS = ""; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; @@ -3139,6 +3145,11 @@ LOCALIZED_STRING_SWIFTUI_SUPPORT = NO; MACOSX_DEPLOYMENT_TARGET = 13.3; MARKETING_VERSION = 1.0.4; + OTHER_LDFLAGS = ""; + "OTHER_LDFLAGS[sdk=iphonesimulator*]" = ( + "-Xlinker", + "-interposable", + ); PRODUCT_BUNDLE_IDENTIFIER = "com.verse.Nos-dev"; PRODUCT_MODULE_NAME = Nos; PRODUCT_NAME = "$(TARGET_NAME) Dev"; @@ -3306,6 +3317,7 @@ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; + OTHER_LDFLAGS = ""; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; @@ -3364,6 +3376,7 @@ MACOSX_DEPLOYMENT_TARGET = 13.3; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; + OTHER_LDFLAGS = ""; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; }; @@ -3661,6 +3674,14 @@ minimumVersion = 1.0.0; }; }; + C98905A02CD3B8CF00C17EE0 /* XCRemoteSwiftPackageReference "Inject" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/krzysztofzablocki/Inject.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.5.2; + }; + }; C99DBF7C2A9E81CF00F7068F /* XCRemoteSwiftPackageReference "SDWebImageSwiftUI" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/SDWebImage/SDWebImageSwiftUI"; @@ -3812,6 +3833,11 @@ package = C96CB98A2A6040C500498C4E /* XCRemoteSwiftPackageReference "swift-collections" */; productName = DequeModule; }; + C98905A12CD3B8CF00C17EE0 /* Inject */ = { + isa = XCSwiftPackageProductDependency; + package = C98905A02CD3B8CF00C17EE0 /* XCRemoteSwiftPackageReference "Inject" */; + productName = Inject; + }; C99DBF7D2A9E81CF00F7068F /* SDWebImageSwiftUI */ = { isa = XCSwiftPackageProductDependency; package = C99DBF7C2A9E81CF00F7068F /* XCRemoteSwiftPackageReference "SDWebImageSwiftUI" */; diff --git a/Nos.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Nos.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 7590212f9..6ebc64605 100644 --- a/Nos.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Nos.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "f8bae06dbeb84f5992ca8659ee3a2a75550fe8b31994d37a658183a21f1c8131", + "originHash" : "62d037ae150ed2e6e150f06b42119c5158134318243e742971b3ccfa3a3a5323", "pins" : [ { "identity" : "bech32", @@ -37,6 +37,15 @@ "version" : "1.8.2" } }, + { + "identity" : "inject", + "kind" : "remoteSourceControl", + "location" : "https://github.com/krzysztofzablocki/Inject.git", + "state" : { + "revision" : "728c56639ecb3df441d51d5bc6747329afabcfc9", + "version" : "1.5.2" + } + }, { "identity" : "libwebp-xcode", "kind" : "remoteSourceControl", diff --git a/Nos/NosApp.swift b/Nos/NosApp.swift index 48ef27900..1a06325a7 100644 --- a/Nos/NosApp.swift +++ b/Nos/NosApp.swift @@ -2,6 +2,7 @@ import SwiftUI import Logger import Dependencies import TipKit +import Inject @main struct NosApp: App { @@ -15,6 +16,7 @@ struct NosApp: App { private let appController = AppController() @Environment(\.scenePhase) private var scenePhase @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate + @ObserveInjection var inject init() { _ = crashReporting // force crash reporting init as early as possible @@ -24,6 +26,11 @@ struct NosApp: App { UIView.appearance(whenContainedInInstancesOf: [UIAlertController.self]).tintColor = .systemBlue persistenceController.scheduleBackgroundCleanupTask() try? Tips.configure() + + #if DEBUG + Bundle(path: "/Applications/InjectionIII.app/Contents/Resources/iOSInjection.bundle")?.load() + InjectConfiguration.animation = .interactiveSpring() + #endif } var body: some Scene { diff --git a/Nos/Views/Home/HomeFeedView.swift b/Nos/Views/Home/HomeFeedView.swift index d36e73fc1..b0bf4a6d4 100644 --- a/Nos/Views/Home/HomeFeedView.swift +++ b/Nos/Views/Home/HomeFeedView.swift @@ -3,12 +3,14 @@ import CoreData import Combine import Dependencies import TipKit +import Inject struct HomeFeedView: View { @Environment(\.managedObjectContext) private var viewContext @EnvironmentObject private var router: Router @ObservationIgnored @Dependency(\.analytics) private var analytics + @ObserveInjection var inject @State private var refreshController = RefreshController(lastRefreshDate: Date.now + Self.staticLoadTime) @State private var isVisible = false @@ -164,6 +166,7 @@ struct HomeFeedView: View { GoToFeedTip.viewedFeed.sendDonation() } } + .enableInjection() } } diff --git a/Nos/Views/Home/HomeTab.swift b/Nos/Views/Home/HomeTab.swift index 7a0892268..8297f850a 100644 --- a/Nos/Views/Home/HomeTab.swift +++ b/Nos/Views/Home/HomeTab.swift @@ -1,16 +1,19 @@ import SwiftUI import Dependencies +import Inject struct HomeTab: View { @ObservedObject var user: Author @EnvironmentObject private var router: Router + @ObserveInjection var inject var body: some View { NosNavigationStack(path: $router.homeFeedPath) { HomeFeedView(user: user) } + .enableInjection() } } diff --git a/Nos/Views/SideMenu/SideMenuContent.swift b/Nos/Views/SideMenu/SideMenuContent.swift index 6d3bb5f6d..857fffab8 100644 --- a/Nos/Views/SideMenu/SideMenuContent.swift +++ b/Nos/Views/SideMenu/SideMenuContent.swift @@ -1,12 +1,14 @@ import SwiftUI import MessageUI import Dependencies +import Inject struct SideMenuContent: View { @EnvironmentObject private var router: Router @Environment(CurrentUser.self) private var currentUser @Dependency(\.analytics) private var analytics + @ObserveInjection var inject @State private var isShowingReportABugMailView = false @State private var shareNosPressed = false @@ -118,6 +120,7 @@ struct SideMenuContent: View { ProfileEditView(author: destination.profile) } } + .enableInjection() } }