diff --git a/Images/.gitignore b/Images/.gitignore new file mode 100644 index 000000000..0023a5340 --- /dev/null +++ b/Images/.gitignore @@ -0,0 +1,8 @@ +.DS_Store +/.build +/Packages +xcuserdata/ +DerivedData/ +.swiftpm/configuration/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc diff --git a/Images/Package.swift b/Images/Package.swift new file mode 100644 index 000000000..074499dc3 --- /dev/null +++ b/Images/Package.swift @@ -0,0 +1,27 @@ +// swift-tools-version: 5.10 + +import PackageDescription + +let package = Package( + name: "Images", + platforms: [.macOS(.v14), .iOS(.v17)], + products: [ + .library( + name: "Images", + targets: ["Images"]), + ], + targets: [ + .target( + name: "Images", + dependencies: [ + + ], + swiftSettings: [ + .enableExperimentalFeature("StrictConcurrency") + ] + ), + .testTarget( + name: "ImagesTests", + dependencies: ["Images"]), + ] +) diff --git a/Shared/Favicons/ColorHash.swift b/Images/Sources/Images/ColorHash.swift similarity index 91% rename from Shared/Favicons/ColorHash.swift rename to Images/Sources/Images/ColorHash.swift index 5cd55d05a..1ae639d51 100644 --- a/Shared/Favicons/ColorHash.swift +++ b/Images/Sources/Images/ColorHash.swift @@ -16,8 +16,8 @@ import WatchKit import AppKit #endif -public class ColorHash { - +public struct ColorHash: Sendable { + public static let defaultSaturation = [CGFloat(0.35), CGFloat(0.5), CGFloat(0.65)] public static let defaultBrightness = [CGFloat(0.5), CGFloat(0.65), CGFloat(0.80)] @@ -26,10 +26,10 @@ public class ColorHash { let maxSafeInteger = 9007199254740991.0 / CGFloat(137.0) let full = CGFloat(360.0) - public private(set) var str: String - public private(set) var brightness: [CGFloat] - public private(set) var saturation: [CGFloat] - + public let str: String + public let brightness: [CGFloat] + public let saturation: [CGFloat] + public init(_ str: String, _ saturation: [CGFloat] = defaultSaturation, _ brightness: [CGFloat] = defaultBrightness) { self.str = str self.saturation = saturation @@ -70,5 +70,4 @@ public class ColorHash { return NSColor(hue: H, saturation: S, brightness: B, alpha: 1.0) } #endif - } diff --git a/Images/Tests/ImagesTests/ImagesTests.swift b/Images/Tests/ImagesTests/ImagesTests.swift new file mode 100644 index 000000000..7add8faab --- /dev/null +++ b/Images/Tests/ImagesTests/ImagesTests.swift @@ -0,0 +1,12 @@ +import XCTest +@testable import Images + +final class ImagesTests: XCTestCase { + func testExample() throws { + // XCTest Documentation + // https://developer.apple.com/documentation/xctest + + // Defining Test Cases and Test Methods + // https://developer.apple.com/documentation/xctest/defining_test_cases_and_test_methods + } +} diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index d0731d89d..f84af7181 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -337,8 +337,6 @@ 51EAED96231363EF00A9EEE3 /* NonIntrinsicButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EAED95231363EF00A9EEE3 /* NonIntrinsicButton.swift */; }; 51EC114C2149FE3300B296E3 /* FolderTreeMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EC114B2149FE3300B296E3 /* FolderTreeMenu.swift */; }; 51EF0F77227716200050506E /* FaviconGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EF0F76227716200050506E /* FaviconGenerator.swift */; }; - 51EF0F79227716380050506E /* ColorHash.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EF0F78227716380050506E /* ColorHash.swift */; }; - 51EF0F7A22771B890050506E /* ColorHash.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EF0F78227716380050506E /* ColorHash.swift */; }; 51EF0F7E2277A57D0050506E /* TimelineAccessibilityCellLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EF0F7D2277A57D0050506E /* TimelineAccessibilityCellLayout.swift */; }; 51EF0F802277A8330050506E /* TimelineCellLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EF0F7F2277A8330050506E /* TimelineCellLayout.swift */; }; 51EFDA1B24E6D16A0085C3D6 /* SafariExt.js in Resources */ = {isa = PBXBuildFile; fileRef = 515D4FCB2325815A00EE1167 /* SafariExt.js */; }; @@ -403,7 +401,6 @@ 65ED3FB8235DEF6C0081F399 /* CrashReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848B937121C8C5540038DC0D /* CrashReporter.swift */; }; 65ED3FB9235DEF6C0081F399 /* IconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847CD6C9232F4CBF00FAC46D /* IconView.swift */; }; 65ED3FBB235DEF6C0081F399 /* InspectorWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84BBB12C20142A4700F054F5 /* InspectorWindowController.swift */; }; - 65ED3FBC235DEF6C0081F399 /* ColorHash.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51EF0F78227716380050506E /* ColorHash.swift */; }; 65ED3FBD235DEF6C0081F399 /* AppDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E46C7C1F75EF7B005ECFB3 /* AppDefaults.swift */; }; 65ED3FBE235DEF6C0081F399 /* Account+Scriptability.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5907D962004B7EB005947E5 /* Account+Scriptability.swift */; }; 65ED3FBF235DEF6C0081F399 /* NothingInspectorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841ABA4D20145E7300980E11 /* NothingInspectorViewController.swift */; }; @@ -718,6 +715,8 @@ 84CC88181FE59CBF00644329 /* SmartFeedsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84CC88171FE59CBF00644329 /* SmartFeedsController.swift */; }; 84D52E951FE588BB00D14F5B /* DetailStatusBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D52E941FE588BB00D14F5B /* DetailStatusBarView.swift */; }; 84D9582C2BABE53B0053E7B2 /* FoundationExtras in Frameworks */ = {isa = PBXBuildFile; productRef = 84D9582B2BABE53B0053E7B2 /* FoundationExtras */; }; + 84DC5FFA2BCE31D200F04682 /* Images in Frameworks */ = {isa = PBXBuildFile; productRef = 84DC5FF92BCE31D200F04682 /* Images */; }; + 84DC5FFC2BCE31DB00F04682 /* Images in Frameworks */ = {isa = PBXBuildFile; productRef = 84DC5FFB2BCE31DB00F04682 /* Images */; }; 84DCA5122BABB75600792720 /* FoundationExtras in Frameworks */ = {isa = PBXBuildFile; productRef = 84DCA5112BABB75600792720 /* FoundationExtras */; }; 84DCA5142BABB76100792720 /* AppKitExtras in Frameworks */ = {isa = PBXBuildFile; productRef = 84DCA5132BABB76100792720 /* AppKitExtras */; }; 84DCA5162BABB76B00792720 /* CloudKitExtras in Frameworks */ = {isa = PBXBuildFile; productRef = 84DCA5152BABB76B00792720 /* CloudKitExtras */; }; @@ -1245,7 +1244,6 @@ 51EAED95231363EF00A9EEE3 /* NonIntrinsicButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonIntrinsicButton.swift; sourceTree = ""; }; 51EC114B2149FE3300B296E3 /* FolderTreeMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = FolderTreeMenu.swift; path = AddFeed/FolderTreeMenu.swift; sourceTree = ""; }; 51EF0F76227716200050506E /* FaviconGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FaviconGenerator.swift; sourceTree = ""; }; - 51EF0F78227716380050506E /* ColorHash.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorHash.swift; sourceTree = ""; }; 51EF0F7D2277A57D0050506E /* TimelineAccessibilityCellLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineAccessibilityCellLayout.swift; sourceTree = ""; }; 51EF0F7F2277A8330050506E /* TimelineCellLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineCellLayout.swift; sourceTree = ""; }; 51F805D32428499E0022C792 /* NetNewsWire-dev.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "NetNewsWire-dev.entitlements"; sourceTree = ""; }; @@ -1427,6 +1425,7 @@ 84CC98D92BC1DD25006A05C9 /* ReaderAPI */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = ReaderAPI; sourceTree = ""; }; 84D2200922B0BC4B0019E085 /* CONTRIBUTING.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CONTRIBUTING.md; sourceTree = ""; }; 84D52E941FE588BB00D14F5B /* DetailStatusBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailStatusBarView.swift; sourceTree = ""; }; + 84DC5FF82BCE308500F04682 /* Images */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = Images; sourceTree = ""; }; 84DCA50D2BAB643700792720 /* FoundationExtras */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = FoundationExtras; sourceTree = ""; }; 84DCA50E2BABB5D800792720 /* AppKitExtras */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = AppKitExtras; sourceTree = ""; }; 84DCA50F2BABB65600792720 /* CloudKitExtras */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = CloudKitExtras; sourceTree = ""; }; @@ -1593,6 +1592,7 @@ 179D280B26F6F93D003B2E0A /* Zip in Frameworks */, 84DCA51E2BABB79900792720 /* FoundationExtras in Frameworks */, 8410C4A52BC1E28200D4F799 /* ReaderAPI in Frameworks */, + 84DC5FFC2BCE31DB00F04682 /* Images in Frameworks */, 84C1A8582BBBA5BD006E3E96 /* Web in Frameworks */, 516B695F24D2F33B00B5702F /* Account in Frameworks */, 84A699152BC34F3D00605AB8 /* ArticleExtractor in Frameworks */, @@ -1614,6 +1614,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 84DC5FFA2BCE31D200F04682 /* Images in Frameworks */, 513277642590FC640064F1E7 /* SyncDatabase in Frameworks */, 17192ADA2567B3D500AAEACA /* RSSparkle in Frameworks */, 8438C2DB2BABE0B00040C9EE /* CoreResources in Frameworks */, @@ -2205,7 +2206,6 @@ 848F6AE31FC29CFA002D422E /* Favicons */ = { isa = PBXGroup; children = ( - 51EF0F78227716380050506E /* ColorHash.swift */, 848F6AE41FC29CFA002D422E /* FaviconDownloader.swift */, 51EF0F76227716200050506E /* FaviconGenerator.swift */, 84FF69B01FC3793300DC198E /* FaviconURLFinder.swift */, @@ -2349,6 +2349,7 @@ D5907CDA2002F084005947E5 /* xcconfig */, 849C64611ED37A5D003D8FC0 /* Products */, 51C452B22265141B00C03939 /* Frameworks */, + 84DC5FF82BCE308500F04682 /* Images */, 84A699132BC34E8500605AB8 /* ArticleExtractor */, 84FB9FAE2BC3494B00B7AFC3 /* FeedFinder */, 51CD32C624D2DEF9009ABAEF /* Account */, @@ -2978,6 +2979,7 @@ 845611732BBD145D00507B73 /* ParserObjC */, 8410C4A42BC1E28200D4F799 /* ReaderAPI */, 84A699142BC34F3D00605AB8 /* ArticleExtractor */, + 84DC5FFB2BCE31DB00F04682 /* Images */, ); productName = "NetNewsWire-iOS"; productReference = 840D617C2029031C009BC708 /* NetNewsWire.app */; @@ -3026,6 +3028,7 @@ 8456116D2BBD145200507B73 /* ParserObjC */, 8410C4A22BC1E27A00D4F799 /* ReaderAPI */, 84A699162BC34F4400605AB8 /* ArticleExtractor */, + 84DC5FF92BCE31D200F04682 /* Images */, ); productName = NetNewsWire; productReference = 849C64601ED37A5D003D8FC0 /* NetNewsWire.app */; @@ -3734,7 +3737,6 @@ 65ED3FB8235DEF6C0081F399 /* CrashReporter.swift in Sources */, 65ED3FB9235DEF6C0081F399 /* IconView.swift in Sources */, 65ED3FBB235DEF6C0081F399 /* InspectorWindowController.swift in Sources */, - 65ED3FBC235DEF6C0081F399 /* ColorHash.swift in Sources */, 65ED3FBD235DEF6C0081F399 /* AppDefaults.swift in Sources */, 65ED3FBE235DEF6C0081F399 /* Account+Scriptability.swift in Sources */, 65ED3FBF235DEF6C0081F399 /* NothingInspectorViewController.swift in Sources */, @@ -3911,7 +3913,6 @@ 51236339236915B100951F16 /* RoundedProgressView.swift in Sources */, 512E08E72268801200BDCFDD /* FeedTreeControllerDelegate.swift in Sources */, 51C452A422650A2D00C03939 /* ArticleUtilities.swift in Sources */, - 51EF0F79227716380050506E /* ColorHash.swift in Sources */, 51F9F3FB23DFB25700A314FD /* Animations.swift in Sources */, 5195C1DA2720205F00888867 /* ShadowTableChanges.swift in Sources */, 5183CCDA226E31A50010922C /* NonIntrinsicImageView.swift in Sources */, @@ -4082,7 +4083,6 @@ 848B937221C8C5540038DC0D /* CrashReporter.swift in Sources */, 847CD6CA232F4CBF00FAC46D /* IconView.swift in Sources */, 84BBB12E20142A4700F054F5 /* InspectorWindowController.swift in Sources */, - 51EF0F7A22771B890050506E /* ColorHash.swift in Sources */, 84E46C7D1F75EF7B005ECFB3 /* AppDefaults.swift in Sources */, 51868BF1254386630011A17B /* SidebarDeleteItemsAlert.swift in Sources */, D5907D972004B7EB005947E5 /* Account+Scriptability.swift in Sources */, @@ -4949,6 +4949,14 @@ isa = XCSwiftPackageProductDependency; productName = FoundationExtras; }; + 84DC5FF92BCE31D200F04682 /* Images */ = { + isa = XCSwiftPackageProductDependency; + productName = Images; + }; + 84DC5FFB2BCE31DB00F04682 /* Images */ = { + isa = XCSwiftPackageProductDependency; + productName = Images; + }; 84DCA5112BABB75600792720 /* FoundationExtras */ = { isa = XCSwiftPackageProductDependency; productName = FoundationExtras; diff --git a/Shared/Favicons/FaviconGenerator.swift b/Shared/Favicons/FaviconGenerator.swift index 94e866750..ab4fece88 100644 --- a/Shared/Favicons/FaviconGenerator.swift +++ b/Shared/Favicons/FaviconGenerator.swift @@ -8,6 +8,7 @@ import Foundation import Account +import Images @MainActor final class FaviconGenerator {