diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 index 485dee6..91dc664 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .idea +HNReader/GoogleService-Info.plist \ No newline at end of file diff --git a/HNReader.xcodeproj/project.pbxproj b/HNReader.xcodeproj/project.pbxproj old mode 100644 new mode 100755 index c9c2102..adf3651 --- a/HNReader.xcodeproj/project.pbxproj +++ b/HNReader.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 52; objects = { /* Begin PBXBuildFile section */ @@ -15,21 +15,24 @@ 330718D415D21296AA14E7CA /* HackerNewsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33071291447141A6D31E671B /* HackerNewsTests.swift */; }; 330719203034BDB177F28C41 /* +DateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33071B0E5439D8D207CB68F4 /* +DateTests.swift */; }; 33071F1C64D4742E1F947FAA /* ItemDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33071D0E5913DB91DDDBDADB /* ItemDownloader.swift */; }; - C93F99B6267554F00046F870 /* ItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C93F99B5267554F00046F870 /* ItemCell.swift */; }; - C93F99B8267557FC0046F870 /* ItemList.swift in Sources */ = {isa = PBXBuildFile; fileRef = C93F99B7267557FC0046F870 /* ItemList.swift */; }; - C93F99BA267580CE0046F870 /* HTMLText.swift in Sources */ = {isa = PBXBuildFile; fileRef = C93F99B9267580CE0046F870 /* HTMLText.swift */; }; + C91636D626AB2EFE009CECFB /* HackerNews in Frameworks */ = {isa = PBXBuildFile; productRef = C91636D526AB2EFE009CECFB /* HackerNews */; }; + C93F99B6267554F00046F870 /* StoryCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C93F99B5267554F00046F870 /* StoryCell.swift */; }; + C93F99B8267557FC0046F870 /* StoryList.swift in Sources */ = {isa = PBXBuildFile; fileRef = C93F99B7267557FC0046F870 /* StoryList.swift */; }; + C96E398D27209B6200A01435 /* +Text.swift in Sources */ = {isa = PBXBuildFile; fileRef = C96E398C27209B6200A01435 /* +Text.swift */; }; + C9B58794267C153C005E0A50 /* DetailStoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9B58793267C153C005E0A50 /* DetailStoryView.swift */; }; + C9B83DDF26A8808900036AC6 /* CommentCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9B83DDE26A8808900036AC6 /* CommentCell.swift */; }; + C9B83DE926A8A23C00036AC6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C9B83DE826A8A23C00036AC6 /* Assets.xcassets */; }; + C9B83DEB26A8A76800036AC6 /* +NSTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9B83DEA26A8A76800036AC6 /* +NSTextField.swift */; }; + C9B83DED26A8ACD000036AC6 /* LoadingCircle.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9B83DEC26A8ACD000036AC6 /* LoadingCircle.swift */; }; + C9B83DEF26A8AF4A00036AC6 /* +String.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9B83DEE26A8AF4A00036AC6 /* +String.swift */; }; + C9C75DBE26B03FF000892071 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = C9C75DBD26B03FF000892071 /* GoogleService-Info.plist */; }; C9D0937726741BBE002CC786 /* HNReaderApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D0937626741BBE002CC786 /* HNReaderApp.swift */; }; C9D0937926741BBE002CC786 /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D0937826741BBE002CC786 /* HomeView.swift */; }; - C9D0937B26741BBF002CC786 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C9D0937A26741BBF002CC786 /* Assets.xcassets */; }; C9D0937E26741BBF002CC786 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C9D0937D26741BBF002CC786 /* Preview Assets.xcassets */; }; C9D0938026741BBF002CC786 /* Persistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D0937F26741BBF002CC786 /* Persistence.swift */; }; C9D0938326741BBF002CC786 /* HNReader.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = C9D0938126741BBF002CC786 /* HNReader.xcdatamodeld */; }; C9D0939A26741BC0002CC786 /* HNReaderUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D0939926741BC0002CC786 /* HNReaderUITests.swift */; }; - C9D093AC26741C25002CC786 /* Item.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9D093AB26741C25002CC786 /* Item.swift */; }; C9E9BCFD2674C80E001B4E19 /* AppState.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9E9BCFC2674C80E001B4E19 /* AppState.swift */; }; - C9E9BCFF2674CB6C001B4E19 /* HackerNewsClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9E9BCFE2674CB6C001B4E19 /* HackerNewsClient.swift */; }; - C9E9BD012674D007001B4E19 /* HackerNews.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9E9BD002674D007001B4E19 /* HackerNews.swift */; }; - C9E9BD032674D095001B4E19 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9E9BD022674D095001B4E19 /* User.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -58,13 +61,20 @@ 33071D0E5913DB91DDDBDADB /* ItemDownloader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemDownloader.swift; sourceTree = ""; }; 33071E538EC434DF1A245518 /* HackerNewsClientTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HackerNewsClientTests.swift; sourceTree = ""; }; 33071EEBE46634E658582AE3 /* ItemTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemTests.swift; sourceTree = ""; }; - C93F99B5267554F00046F870 /* ItemCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemCell.swift; sourceTree = ""; }; - C93F99B7267557FC0046F870 /* ItemList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemList.swift; sourceTree = ""; }; - C93F99B9267580CE0046F870 /* HTMLText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTMLText.swift; sourceTree = ""; }; + C93F99B5267554F00046F870 /* StoryCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoryCell.swift; sourceTree = ""; }; + C93F99B7267557FC0046F870 /* StoryList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoryList.swift; sourceTree = ""; }; + C96E398B272092E600A01435 /* HackerNews */ = {isa = PBXFileReference; lastKnownFileType = folder; name = HackerNews; path = ../HackerNews; sourceTree = ""; }; + C96E398C27209B6200A01435 /* +Text.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "+Text.swift"; sourceTree = ""; }; + C9B58793267C153C005E0A50 /* DetailStoryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailStoryView.swift; sourceTree = ""; }; + C9B83DDE26A8808900036AC6 /* CommentCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommentCell.swift; sourceTree = ""; }; + C9B83DE826A8A23C00036AC6 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + C9B83DEA26A8A76800036AC6 /* +NSTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "+NSTextField.swift"; sourceTree = ""; }; + C9B83DEC26A8ACD000036AC6 /* LoadingCircle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingCircle.swift; sourceTree = ""; }; + C9B83DEE26A8AF4A00036AC6 /* +String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "+String.swift"; sourceTree = ""; }; + C9C75DBD26B03FF000892071 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; C9D0937326741BBE002CC786 /* HNReader.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HNReader.app; sourceTree = BUILT_PRODUCTS_DIR; }; C9D0937626741BBE002CC786 /* HNReaderApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HNReaderApp.swift; sourceTree = ""; }; C9D0937826741BBE002CC786 /* HomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = ""; }; - C9D0937A26741BBF002CC786 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; C9D0937D26741BBF002CC786 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; C9D0937F26741BBF002CC786 /* Persistence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Persistence.swift; sourceTree = ""; }; C9D0938226741BBF002CC786 /* HNReader.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = HNReader.xcdatamodel; sourceTree = ""; }; @@ -75,11 +85,7 @@ C9D0939526741BC0002CC786 /* HNReaderUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HNReaderUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; C9D0939926741BC0002CC786 /* HNReaderUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HNReaderUITests.swift; sourceTree = ""; }; C9D0939B26741BC0002CC786 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - C9D093AB26741C25002CC786 /* Item.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Item.swift; sourceTree = ""; }; C9E9BCFC2674C80E001B4E19 /* AppState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppState.swift; sourceTree = ""; }; - C9E9BCFE2674CB6C001B4E19 /* HackerNewsClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HackerNewsClient.swift; sourceTree = ""; }; - C9E9BD002674D007001B4E19 /* HackerNews.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HackerNews.swift; sourceTree = ""; }; - C9E9BD022674D095001B4E19 /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -87,6 +93,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + C91636D626AB2EFE009CECFB /* HackerNews in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -111,6 +118,9 @@ isa = PBXGroup; children = ( 3307159309D438EFAA1259C7 /* +Date.swift */, + C9B83DEA26A8A76800036AC6 /* +NSTextField.swift */, + C9B83DEE26A8AF4A00036AC6 /* +String.swift */, + C96E398C27209B6200A01435 /* +Text.swift */, ); path = Utils; sourceTree = ""; @@ -143,7 +153,9 @@ C9926691267588B80035A88F /* Components */ = { isa = PBXGroup; children = ( - C93F99B9267580CE0046F870 /* HTMLText.swift */, + C93F99B5267554F00046F870 /* StoryCell.swift */, + C9B83DDE26A8808900036AC6 /* CommentCell.swift */, + C9B83DEC26A8ACD000036AC6 /* LoadingCircle.swift */, ); path = Components; sourceTree = ""; @@ -151,6 +163,7 @@ C9D0936A26741BBE002CC786 = { isa = PBXGroup; children = ( + C96E398B272092E600A01435 /* HackerNews */, C9D0937526741BBE002CC786 /* HNReader */, C9D0938D26741BC0002CC786 /* HNReaderTests */, C9D0939826741BC0002CC786 /* HNReaderUITests */, @@ -171,12 +184,12 @@ C9D0937526741BBE002CC786 /* HNReader */ = { isa = PBXGroup; children = ( + C9C75DBD26B03FF000892071 /* GoogleService-Info.plist */, + C9B83DE826A8A23C00036AC6 /* Assets.xcassets */, C9D093AA26741BFD002CC786 /* HNClient */, C9D093A926741BF6002CC786 /* ViewModel */, - C9D093A826741BF0002CC786 /* Model */, C9D093A726741BE1002CC786 /* View */, C9D0937626741BBE002CC786 /* HNReaderApp.swift */, - C9D0937A26741BBF002CC786 /* Assets.xcassets */, C9D0937F26741BBF002CC786 /* Persistence.swift */, C9D0938426741BBF002CC786 /* Info.plist */, C9D0938526741BBF002CC786 /* HNReader.entitlements */, @@ -219,22 +232,13 @@ isa = PBXGroup; children = ( C9D0937826741BBE002CC786 /* HomeView.swift */, - C93F99B5267554F00046F870 /* ItemCell.swift */, - C93F99B7267557FC0046F870 /* ItemList.swift */, + C93F99B7267557FC0046F870 /* StoryList.swift */, C9926691267588B80035A88F /* Components */, + C9B58793267C153C005E0A50 /* DetailStoryView.swift */, ); path = View; sourceTree = ""; }; - C9D093A826741BF0002CC786 /* Model */ = { - isa = PBXGroup; - children = ( - C9D093AB26741C25002CC786 /* Item.swift */, - C9E9BD022674D095001B4E19 /* User.swift */, - ); - path = Model; - sourceTree = ""; - }; C9D093A926741BF6002CC786 /* ViewModel */ = { isa = PBXGroup; children = ( @@ -247,8 +251,6 @@ C9D093AA26741BFD002CC786 /* HNClient */ = { isa = PBXGroup; children = ( - C9E9BCFE2674CB6C001B4E19 /* HackerNewsClient.swift */, - C9E9BD002674D007001B4E19 /* HackerNews.swift */, 33071D0E5913DB91DDDBDADB /* ItemDownloader.swift */, 33071CD8B451FE700B64F387 /* ItemCache.swift */, ); @@ -272,6 +274,7 @@ ); name = HNReader; packageProductDependencies = ( + C91636D526AB2EFE009CECFB /* HackerNews */, ); productName = HNReader; productReference = C9D0937326741BBE002CC786 /* HNReader.app */; @@ -345,6 +348,7 @@ ); mainGroup = C9D0936A26741BBE002CC786; packageReferences = ( + C91636D426AB2EFE009CECFB /* XCRemoteSwiftPackageReference "HackerNews" */, ); productRefGroup = C9D0937426741BBE002CC786 /* Products */; projectDirPath = ""; @@ -362,8 +366,9 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + C9B83DE926A8A23C00036AC6 /* Assets.xcassets in Resources */, + C9C75DBE26B03FF000892071 /* GoogleService-Info.plist in Resources */, C9D0937E26741BBF002CC786 /* Preview Assets.xcassets in Resources */, - C9D0937B26741BBF002CC786 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -388,22 +393,23 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - C9D093AC26741C25002CC786 /* Item.swift in Sources */, + C9B83DEB26A8A76800036AC6 /* +NSTextField.swift in Sources */, C9D0938026741BBF002CC786 /* Persistence.swift in Sources */, C9D0937926741BBE002CC786 /* HomeView.swift in Sources */, - C93F99B6267554F00046F870 /* ItemCell.swift in Sources */, - C93F99B8267557FC0046F870 /* ItemList.swift in Sources */, + C93F99B6267554F00046F870 /* StoryCell.swift in Sources */, + C93F99B8267557FC0046F870 /* StoryList.swift in Sources */, C9E9BCFD2674C80E001B4E19 /* AppState.swift in Sources */, C9D0938326741BBF002CC786 /* HNReader.xcdatamodeld in Sources */, - C9E9BD032674D095001B4E19 /* User.swift in Sources */, - C93F99BA267580CE0046F870 /* HTMLText.swift in Sources */, - C9E9BCFF2674CB6C001B4E19 /* HackerNewsClient.swift in Sources */, - C9E9BD012674D007001B4E19 /* HackerNews.swift in Sources */, + C9B83DEF26A8AF4A00036AC6 /* +String.swift in Sources */, C9D0937726741BBE002CC786 /* HNReaderApp.swift in Sources */, 330713D3016ED410AFD53FDF /* ItemListViewModel.swift in Sources */, 330711A9216E762026AF98A0 /* +Date.swift in Sources */, + C9B58794267C153C005E0A50 /* DetailStoryView.swift in Sources */, 33071F1C64D4742E1F947FAA /* ItemDownloader.swift in Sources */, 3307147AB95F03650FC40B97 /* ItemCache.swift in Sources */, + C9B83DDF26A8808900036AC6 /* CommentCell.swift in Sources */, + C9B83DED26A8ACD000036AC6 /* LoadingCircle.swift in Sources */, + C96E398D27209B6200A01435 /* +Text.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -563,10 +569,10 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = HNReader/HNReader.entitlements; - CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 5; DEVELOPMENT_ASSET_PATHS = "\"HNReader/Preview Content\""; DEVELOPMENT_TEAM = H89RFW5UZ6; ENABLE_HARDENED_RUNTIME = YES; @@ -576,7 +582,8 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 11.0; + MACOSX_DEPLOYMENT_TARGET = 12.0; + MARKETING_VERSION = 1.1.0; PRODUCT_BUNDLE_IDENTIFIER = com.mattrighetti.HNReader; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -589,10 +596,10 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = HNReader/HNReader.entitlements; - CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 5; DEVELOPMENT_ASSET_PATHS = "\"HNReader/Preview Content\""; DEVELOPMENT_TEAM = H89RFW5UZ6; ENABLE_HARDENED_RUNTIME = YES; @@ -602,7 +609,8 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 11.0; + MACOSX_DEPLOYMENT_TARGET = 12.0; + MARKETING_VERSION = 1.1.0; PRODUCT_BUNDLE_IDENTIFIER = com.mattrighetti.HNReader; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -734,6 +742,25 @@ }; /* End XCConfigurationList section */ +/* Begin XCRemoteSwiftPackageReference section */ + C91636D426AB2EFE009CECFB /* XCRemoteSwiftPackageReference "HackerNews" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "file:///Users/matt/Developer/HackerNews"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.0.1; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + C91636D526AB2EFE009CECFB /* HackerNews */ = { + isa = XCSwiftPackageProductDependency; + package = C91636D426AB2EFE009CECFB /* XCRemoteSwiftPackageReference "HackerNews" */; + productName = HackerNews; + }; +/* End XCSwiftPackageProductDependency section */ + /* Begin XCVersionGroup section */ C9D0938126741BBF002CC786 /* HNReader.xcdatamodeld */ = { isa = XCVersionGroup; diff --git a/HNReader.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/HNReader.xcodeproj/project.xcworkspace/contents.xcworkspacedata old mode 100644 new mode 100755 diff --git a/HNReader.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/HNReader.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist old mode 100644 new mode 100755 diff --git a/HNReader.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/HNReader.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100755 index 0000000..b76eb63 --- /dev/null +++ b/HNReader.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,124 @@ +{ + "object": { + "pins": [ + { + "package": "abseil", + "repositoryURL": "https://github.com/firebase/abseil-cpp-SwiftPM.git", + "state": { + "branch": null, + "revision": "fffc3c2729be5747390ad02d5100291a0d9ad26a", + "version": "0.20200225.4" + } + }, + { + "package": "BoringSSL-GRPC", + "repositoryURL": "https://github.com/firebase/boringssl-SwiftPM.git", + "state": { + "branch": null, + "revision": "734a8247442fde37df4364c21f6a0085b6a36728", + "version": "0.7.2" + } + }, + { + "package": "Firebase", + "repositoryURL": "https://github.com/firebase/firebase-ios-sdk.git", + "state": { + "branch": null, + "revision": "7e08e6e2948461493261049cefb6e77728cb3743", + "version": "8.4.0" + } + }, + { + "package": "GoogleAppMeasurement", + "repositoryURL": "https://github.com/google/GoogleAppMeasurement.git", + "state": { + "branch": null, + "revision": "06e74ef7ee7326e1af724d462091eed1e5c6fb4a", + "version": "8.3.1" + } + }, + { + "package": "GoogleDataTransport", + "repositoryURL": "https://github.com/google/GoogleDataTransport.git", + "state": { + "branch": null, + "revision": "9e79fd8deddbef5646fbb5dbb3eaf963e338f007", + "version": "9.1.0" + } + }, + { + "package": "GoogleUtilities", + "repositoryURL": "https://github.com/google/GoogleUtilities.git", + "state": { + "branch": null, + "revision": "beb713a16b50a4df3162b3f3ecdeffa16b74b773", + "version": "7.5.0" + } + }, + { + "package": "gRPC", + "repositoryURL": "https://github.com/firebase/grpc-SwiftPM.git", + "state": { + "branch": null, + "revision": "fb405dd2c7901485f7e158b24e3a0a47e4efd8b5", + "version": "1.28.4" + } + }, + { + "package": "GTMSessionFetcher", + "repositoryURL": "https://github.com/google/gtm-session-fetcher.git", + "state": { + "branch": null, + "revision": "424886f9336a71891aa81852d0c2c08d807d21aa", + "version": "1.6.1" + } + }, + { + "package": "leveldb", + "repositoryURL": "https://github.com/firebase/leveldb.git", + "state": { + "branch": null, + "revision": "0706abcc6b0bd9cedfbb015ba840e4a780b5159b", + "version": "1.22.2" + } + }, + { + "package": "nanopb", + "repositoryURL": "https://github.com/firebase/nanopb.git", + "state": { + "branch": null, + "revision": "7ee9ef9f627d85cbe1b8c4f49a3ed26eed216c77", + "version": "2.30908.0" + } + }, + { + "package": "Promises", + "repositoryURL": "https://github.com/google/promises.git", + "state": { + "branch": null, + "revision": "611337c330350c9c1823ad6d671e7f936af5ee13", + "version": "2.0.0" + } + }, + { + "package": "SwiftProtobuf", + "repositoryURL": "https://github.com/apple/swift-protobuf.git", + "state": { + "branch": null, + "revision": "1f62db409f2c9b0223a3f68567b4a01333aae778", + "version": "1.17.0" + } + }, + { + "package": "SwiftSoup", + "repositoryURL": "https://github.com/scinfu/SwiftSoup.git", + "state": { + "branch": null, + "revision": "11da8c685ddde2d519fad04a7daf8485bbbc773e", + "version": "1.7.5" + } + } + ] + }, + "version": 1 +} diff --git a/HNReader.xcodeproj/project.xcworkspace/xcuserdata/matt.xcuserdatad/xcschemes/xcschememanagement.plist b/HNReader.xcodeproj/project.xcworkspace/xcuserdata/matt.xcuserdatad/xcschemes/xcschememanagement.plist old mode 100644 new mode 100755 diff --git a/HNReader.xcodeproj/xcuserdata/matt.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/HNReader.xcodeproj/xcuserdata/matt.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist old mode 100644 new mode 100755 index 7b2cac4..1f995c4 --- a/HNReader.xcodeproj/xcuserdata/matt.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/HNReader.xcodeproj/xcuserdata/matt.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -3,4 +3,22 @@ uuid = "8DE1C8B6-5F00-414F-B988-E181DD7A8E67" type = "1" version = "2.0"> + + + + + + diff --git a/HNReader.xcodeproj/xcuserdata/matt.xcuserdatad/xcschemes/DateTests.xcscheme b/HNReader.xcodeproj/xcuserdata/matt.xcuserdatad/xcschemes/DateTests.xcscheme old mode 100644 new mode 100755 diff --git a/HNReader.xcodeproj/xcuserdata/matt.xcuserdatad/xcschemes/HNReader.xcscheme b/HNReader.xcodeproj/xcuserdata/matt.xcuserdatad/xcschemes/HNReader.xcscheme old mode 100644 new mode 100755 diff --git a/HNReader.xcodeproj/xcuserdata/matt.xcuserdatad/xcschemes/HackerNewsClientTests.xcscheme b/HNReader.xcodeproj/xcuserdata/matt.xcuserdatad/xcschemes/HackerNewsClientTests.xcscheme old mode 100644 new mode 100755 diff --git a/HNReader.xcodeproj/xcuserdata/matt.xcuserdatad/xcschemes/HackerNewsTests.xcscheme b/HNReader.xcodeproj/xcuserdata/matt.xcuserdatad/xcschemes/HackerNewsTests.xcscheme old mode 100644 new mode 100755 diff --git a/HNReader.xcodeproj/xcuserdata/matt.xcuserdatad/xcschemes/ItemTests.testItemDateIntervalFormatter.xcscheme b/HNReader.xcodeproj/xcuserdata/matt.xcuserdatad/xcschemes/ItemTests.testItemDateIntervalFormatter.xcscheme old mode 100644 new mode 100755 diff --git a/HNReader.xcodeproj/xcuserdata/matt.xcuserdatad/xcschemes/ItemTests.xcscheme b/HNReader.xcodeproj/xcuserdata/matt.xcuserdatad/xcschemes/ItemTests.xcscheme old mode 100644 new mode 100755 diff --git a/HNReader.xcodeproj/xcuserdata/matt.xcuserdatad/xcschemes/xcschememanagement.plist b/HNReader.xcodeproj/xcuserdata/matt.xcuserdatad/xcschemes/xcschememanagement.plist old mode 100644 new mode 100755 index 9f2c11f..050e7e9 --- a/HNReader.xcodeproj/xcuserdata/matt.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/HNReader.xcodeproj/xcuserdata/matt.xcuserdatad/xcschemes/xcschememanagement.plist @@ -4,67 +4,277 @@ SchemeUserState + DateTests.xcscheme + + isShown + + orderHint + 5 + HNReader.xcscheme orderHint 0 - Promises (Playground) 1.xcscheme + HackerNewsClientTests.xcscheme isShown - + orderHint - 2 + 1 - Promises (Playground) 2.xcscheme + HackerNewsTests.xcscheme isShown - + orderHint 3 - Promises (Playground).xcscheme + ItemTests.testItemDateIntervalFormatter.xcscheme isShown - + orderHint - 1 + 2 - HackerNewsClientTests.xcscheme + ItemTests.xcscheme isShown - + orderHint 4 - ItemTests.testItemDateIntervalFormatter.xcscheme + Promises (Playground) 1.xcscheme isShown - + orderHint - 5 + 7 - HackerNewsTests.xcscheme + Promises (Playground) 10.xcscheme isShown - + orderHint - 6 + 16 - ItemTests.xcscheme + Promises (Playground) 11.xcscheme isShown - + orderHint - 7 + 17 - DateTests.xcscheme + Promises (Playground) 12.xcscheme + + isShown + + orderHint + 18 + + Promises (Playground) 13.xcscheme isShown - + + orderHint + 19 + + Promises (Playground) 14.xcscheme + + isShown + + orderHint + 20 + + Promises (Playground) 15.xcscheme + + isShown + + orderHint + 21 + + Promises (Playground) 16.xcscheme + + isShown + + orderHint + 22 + + Promises (Playground) 17.xcscheme + + isShown + + orderHint + 23 + + Promises (Playground) 18.xcscheme + + isShown + + orderHint + 24 + + Promises (Playground) 19.xcscheme + + isShown + + orderHint + 25 + + Promises (Playground) 2.xcscheme + + isShown + orderHint 8 + Promises (Playground) 20.xcscheme + + isShown + + orderHint + 26 + + Promises (Playground) 21.xcscheme + + isShown + + orderHint + 27 + + Promises (Playground) 22.xcscheme + + isShown + + orderHint + 28 + + Promises (Playground) 23.xcscheme + + isShown + + orderHint + 29 + + Promises (Playground) 24.xcscheme + + isShown + + orderHint + 30 + + Promises (Playground) 25.xcscheme + + isShown + + orderHint + 31 + + Promises (Playground) 26.xcscheme + + isShown + + orderHint + 32 + + Promises (Playground) 27.xcscheme + + isShown + + orderHint + 33 + + Promises (Playground) 28.xcscheme + + isShown + + orderHint + 34 + + Promises (Playground) 29.xcscheme + + isShown + + orderHint + 35 + + Promises (Playground) 3.xcscheme + + isShown + + orderHint + 9 + + Promises (Playground) 30.xcscheme + + isShown + + orderHint + 36 + + Promises (Playground) 31.xcscheme + + isShown + + orderHint + 37 + + Promises (Playground) 32.xcscheme + + isShown + + orderHint + 38 + + Promises (Playground) 4.xcscheme + + isShown + + orderHint + 10 + + Promises (Playground) 5.xcscheme + + isShown + + orderHint + 11 + + Promises (Playground) 6.xcscheme + + isShown + + orderHint + 12 + + Promises (Playground) 7.xcscheme + + isShown + + orderHint + 13 + + Promises (Playground) 8.xcscheme + + isShown + + orderHint + 14 + + Promises (Playground) 9.xcscheme + + isShown + + orderHint + 15 + + Promises (Playground).xcscheme + + isShown + + orderHint + 6 + diff --git a/HNReader/Assets.xcassets/AccentColor.colorset/Contents.json b/HNReader/Assets.xcassets/AccentColor.colorset/Contents.json deleted file mode 100644 index 274babb..0000000 --- a/HNReader/Assets.xcassets/AccentColor.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "idiom" : "universal" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/HNReader/Assets.xcassets/AppIcon.appiconset/Contents.json b/HNReader/Assets.xcassets/AppIcon.appiconset/Contents.json old mode 100644 new mode 100755 diff --git a/HNReader/Assets.xcassets/AppIcon.appiconset/icon_128x128.png b/HNReader/Assets.xcassets/AppIcon.appiconset/icon_128x128.png old mode 100644 new mode 100755 diff --git a/HNReader/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png b/HNReader/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png old mode 100644 new mode 100755 diff --git a/HNReader/Assets.xcassets/AppIcon.appiconset/icon_16x16.png b/HNReader/Assets.xcassets/AppIcon.appiconset/icon_16x16.png old mode 100644 new mode 100755 diff --git a/HNReader/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png b/HNReader/Assets.xcassets/AppIcon.appiconset/icon_16x16@2x.png old mode 100644 new mode 100755 diff --git a/HNReader/Assets.xcassets/AppIcon.appiconset/icon_256x256.png b/HNReader/Assets.xcassets/AppIcon.appiconset/icon_256x256.png old mode 100644 new mode 100755 diff --git a/HNReader/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png b/HNReader/Assets.xcassets/AppIcon.appiconset/icon_256x256@2x.png old mode 100644 new mode 100755 diff --git a/HNReader/Assets.xcassets/AppIcon.appiconset/icon_32x32.png b/HNReader/Assets.xcassets/AppIcon.appiconset/icon_32x32.png old mode 100644 new mode 100755 diff --git a/HNReader/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png b/HNReader/Assets.xcassets/AppIcon.appiconset/icon_32x32@2x.png old mode 100644 new mode 100755 diff --git a/HNReader/Assets.xcassets/AppIcon.appiconset/icon_512x512.png b/HNReader/Assets.xcassets/AppIcon.appiconset/icon_512x512.png old mode 100644 new mode 100755 diff --git a/HNReader/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png b/HNReader/Assets.xcassets/AppIcon.appiconset/icon_512x512@2x.png old mode 100644 new mode 100755 diff --git a/HNReader/Assets.xcassets/Contents.json b/HNReader/Assets.xcassets/Contents.json old mode 100644 new mode 100755 diff --git a/HNReader/Assets.xcassets/NoComments.imageset/Contents.json b/HNReader/Assets.xcassets/NoComments.imageset/Contents.json new file mode 100755 index 0000000..de2da7d --- /dev/null +++ b/HNReader/Assets.xcassets/NoComments.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "NoComments.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/HNReader/Assets.xcassets/NoComments.imageset/NoComments.png b/HNReader/Assets.xcassets/NoComments.imageset/NoComments.png new file mode 100755 index 0000000..16fafac Binary files /dev/null and b/HNReader/Assets.xcassets/NoComments.imageset/NoComments.png differ diff --git a/HNReader/Assets.xcassets/Select.imageset/Contents.json b/HNReader/Assets.xcassets/Select.imageset/Contents.json new file mode 100755 index 0000000..33b5bf0 --- /dev/null +++ b/HNReader/Assets.xcassets/Select.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "Select.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/HNReader/Assets.xcassets/Select.imageset/Select.png b/HNReader/Assets.xcassets/Select.imageset/Select.png new file mode 100755 index 0000000..a8b714e Binary files /dev/null and b/HNReader/Assets.xcassets/Select.imageset/Select.png differ diff --git a/HNReader/HNClient/HackerNews.swift b/HNReader/HNClient/HackerNews.swift deleted file mode 100644 index 04b268c..0000000 --- a/HNReader/HNClient/HackerNews.swift +++ /dev/null @@ -1,54 +0,0 @@ -// -// HackerNes.swift -// HNReader -// -// Created by Mattia Righetti on 12/06/21. -// - -import Foundation - -/// HackerNews endpoint data structure -struct HackerNews { - public static let endpoint = "https://hacker-news.firebaseio.com/v0" - - /// HackerNews REST API methods - enum API { - /// HackerNews User REST API methods - enum User { - case id(String) - - public var urlString: String { - switch self { - case .id(let userId): - return "\(HackerNews.endpoint)/user/\(userId).json" - } - } - } - - /// HackerNews Stories REST API methods - enum Stories: String { - case top - case new - case best - case ask - case job - case show - - public var urlString: String { - "\(HackerNews.endpoint)/\(self.rawValue)stories.json" - } - } - - /// HackerNews Item REST API methods - enum Item { - case id(Int) - - public var urlString: String { - switch self { - case .id(let storyId): - return "\(HackerNews.endpoint)/item/\(storyId).json" - } - } - } - } -} diff --git a/HNReader/HNClient/HackerNewsClient.swift b/HNReader/HNClient/HackerNewsClient.swift deleted file mode 100644 index eb7603d..0000000 --- a/HNReader/HNClient/HackerNewsClient.swift +++ /dev/null @@ -1,68 +0,0 @@ -// -// HackerNewsClient.swift -// HNReader -// -// Created by Mattia Righetti on 12/06/21. -// - -import Foundation -import Combine - -/// HackerNews Client that exposes methods to get users, items and stories from https://news.ycombinator.com -class HackerNewsClient { - public static let shared: HackerNewsClient = HackerNewsClient() - private let session: URLSession = URLSession.shared - private let decoder: JSONDecoder = JSONDecoder() - private var subscriptions = Set() - - /// Retrieves user from HackerNews - public func getUser(withId id: String) -> AnyPublisher { - let url = URL(string: HackerNews.API.User.id(id).urlString)! - return session - .dataTaskPublisher(for: url) - .retry(3) - .map(\.data) - .decode(type: User.self, decoder: decoder) - .receive(on: DispatchQueue.main) - .eraseToAnyPublisher() - } - - /// Retrieves item from HackerNews - public func getItem(withId id: Int) -> AnyPublisher { - let url = URL(string: HackerNews.API.Item.id(id).urlString)! - return session - .dataTaskPublisher(for: url) - .retry(3) - .map(\.data) - .decode(type: Item.self, decoder: decoder) - .eraseToAnyPublisher() - } - - /// Retrieves array of items from HackerNews - /// - /// You can specify which kind of stories you would like to retrieve: - /// - `top` - /// - `best` - /// - `new` - public func getStoriesId(by api: HackerNews.API.Stories) -> AnyPublisher<[Int], Error> { - let url = URL(string: api.urlString)! - return session - .dataTaskPublisher(for: url) - .map(\.data) - .decode(type: [Int].self, decoder: decoder) - .eraseToAnyPublisher() - } - - public func getStories(withIds ids: [Int]) -> AnyPublisher<[Item], Error> { - ids.publisher - .flatMap(getItem) - .collect() - .eraseToAnyPublisher() - } - - public func getStories(by category: HackerNews.API.Stories, limit: Int? = 50) -> AnyPublisher<[Item], Error> { - getStoriesId(by: category) - .flatMap(getStories) - .eraseToAnyPublisher() - } -} diff --git a/HNReader/HNClient/ItemCache.swift b/HNReader/HNClient/ItemCache.swift old mode 100644 new mode 100755 index af11265..776e7b3 --- a/HNReader/HNClient/ItemCache.swift +++ b/HNReader/HNClient/ItemCache.swift @@ -3,6 +3,7 @@ // import Foundation +import HackerNews class StructWrapper: NSObject { let value: T @@ -27,4 +28,4 @@ class ItemCache: NSCache> { let itemWrapper = self.object(forKey: keyString) return itemWrapper?.value } -} \ No newline at end of file +} diff --git a/HNReader/HNClient/ItemDownloader.swift b/HNReader/HNClient/ItemDownloader.swift old mode 100644 new mode 100755 index f37343a..9d2b75a --- a/HNReader/HNClient/ItemDownloader.swift +++ b/HNReader/HNClient/ItemDownloader.swift @@ -3,36 +3,14 @@ // import Foundation +import HackerNews protocol ItemDownloader { - var cacheKey: Int { get } - func downloadItem(completion: @escaping (Item?) -> Void) + func downloadItem(itemId: Int, completion: @escaping (Item?) -> Void) } class DefaultItemDownloader: ItemDownloader { - let itemId: Int - var cacheKey: Int { - itemId - } - - init(itemId: Int) { - self.itemId = itemId - } - - func downloadItem(completion: @escaping (Item?) -> ()) { - guard let url = URL(string: HackerNews.API.Item.id(itemId).urlString) else { return } - let task = URLSession.shared.dataTask(with: url) { (data, response, error) in - if let data = data { - var item: Item - do { - item = try JSONDecoder().decode(Item.self, from: data) - completion(item) - } catch { - print("encountered error while downloading item") - completion(nil) - } - } - } - task.resume() + func downloadItem(itemId: Int, completion: @escaping (Item?) -> ()) { + HackerNewsFirebaseClient.shared.getItem(withId: itemId, completionHandler: completion) } } diff --git a/HNReader/HNReader.entitlements b/HNReader/HNReader.entitlements old mode 100644 new mode 100755 diff --git a/HNReader/HNReader.xcdatamodeld/.xccurrentversion b/HNReader/HNReader.xcdatamodeld/.xccurrentversion old mode 100644 new mode 100755 diff --git a/HNReader/HNReader.xcdatamodeld/HNReader.xcdatamodel/contents b/HNReader/HNReader.xcdatamodeld/HNReader.xcdatamodel/contents old mode 100644 new mode 100755 diff --git a/HNReader/HNReaderApp.swift b/HNReader/HNReaderApp.swift old mode 100644 new mode 100755 index 200e9b2..cad443a --- a/HNReader/HNReaderApp.swift +++ b/HNReader/HNReaderApp.swift @@ -6,6 +6,7 @@ // import SwiftUI +import HackerNews @main struct HNReaderApp: App { @@ -14,11 +15,11 @@ struct HNReaderApp: App { private var displayModeBind: Binding { Binding( - get: { appState.getColorScheme() }, - set: { - appState.setColorScheme($0) - displayMode = $0 - } + get: { appState.getColorScheme() }, + set: { + appState.setColorScheme($0) + displayMode = $0 + } ) } @State var displayMode: ColorScheme? @@ -27,26 +28,25 @@ struct HNReaderApp: App { WindowGroup { HomeView() .onAppear { - displayMode = appState.getColorScheme() + displayMode = .dark } .preferredColorScheme(displayMode) .environmentObject(appState) } - Settings { - VStack { - Form { - Picker(selection: displayModeBind, label: Text("Theme")) { - Text("Dark").tag(ColorScheme.dark) - Text("Light").tag(ColorScheme.light) - } - .pickerStyle(SegmentedPickerStyle()) - .frame(maxWidth: 100) - } - } - .frame(minHeight: 100) - .frame(minWidth: 300) - .preferredColorScheme(displayMode) - } +// Settings { +// VStack { +// Form { +// Picker(selection: displayModeBind, label: Text("Theme")) { +// Text("Dark").tag(ColorScheme.dark) +// Text("Light").tag(ColorScheme.light) +// } +// .pickerStyle(SegmentedPickerStyle()) +// .frame(maxWidth: 100) +// } +// } +// .frame(minWidth: 300, minHeight: 100) +// .preferredColorScheme(displayMode) +// } } } diff --git a/HNReader/Info.plist b/HNReader/Info.plist old mode 100644 new mode 100755 index 0622ad3..3874cdb --- a/HNReader/Info.plist +++ b/HNReader/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 1.0 + $(MARKETING_VERSION) CFBundleVersion $(CURRENT_PROJECT_VERSION) LSApplicationCategoryType diff --git a/HNReader/Model/Item.swift b/HNReader/Model/Item.swift deleted file mode 100644 index 2973e6e..0000000 --- a/HNReader/Model/Item.swift +++ /dev/null @@ -1,68 +0,0 @@ -// -// Item.swift -// HNReader -// -// Created by Mattia Righetti on 12/06/21. -// - -import Foundation - -/** - Stories, comments, jobs, Ask HNs and even polls are items. They're identified by their ids, which are unique integers. - - For example, a story: https://hacker-news.firebaseio.com/v0/item/8863.json?print=pretty - ```json - { - "by" : "dhouston", - "descendants" : 71, - "id" : 8863, - "kids" : [ 8952, 9224, 8917, 8884, 8887, 8943, 8869, 8958, 9005, 9671, 8940, 9067, 8908, 9055, 8865, 8881, 8872, 8873, 8955, 10403, 8903, 8928, 9125, 8998, 8901, 8902, 8907, 8894, 8878, 8870, 8980, 8934, 8876 ], - "score" : 111, - "time" : 1175714200, - "title" : "My YC app: Dropbox - Throw away your USB drive", - "type" : "story", - "url" : "http://www.getdropbox.com/u/2/screencast.html" - } - ``` - */ -public struct Item: Decodable { - public let id: Int - public let deleted: Bool? - public let type: ItemType? - public let by: String? - public let time: Int? - public let text: String? - public let dead: Bool? - public let parent: Int? - public let poll: Bool? - public let kids: [Int]? - public let url: String? - public let score: Int? - public let title: String? - public let parts: Int? - public let descendants: Int? - - public var urlHost: String? { - if let url = url { - var hostString = URL(string: url)!.host! - if hostString.contains("www.") { - hostString.removeFirst(4) - } - return hostString - } else { - return nil - } - } - - public var timeStringRepresentation: String? { - Date().timeElapsedStringRepresentation(since: Date(timeIntervalSince1970: TimeInterval(time!))) - } -} - -public enum ItemType: String, Decodable { - case poll - case job - case story - case comment - case pollopt -} diff --git a/HNReader/Model/User.swift b/HNReader/Model/User.swift deleted file mode 100644 index bae3dcc..0000000 --- a/HNReader/Model/User.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// User.swift -// HNReader -// -// Created by Mattia Righetti on 12/06/21. -// - -import Foundation - -public struct User: Decodable { - public let id: String - public let created: Int - public let karma: Int - public let about: String? - public let submitted: [Int]? -} diff --git a/HNReader/Persistence.swift b/HNReader/Persistence.swift old mode 100644 new mode 100755 diff --git a/HNReader/Preview Content/Preview Assets.xcassets/Contents.json b/HNReader/Preview Content/Preview Assets.xcassets/Contents.json old mode 100644 new mode 100755 diff --git a/HNReader/Utils/+Date.swift b/HNReader/Utils/+Date.swift old mode 100644 new mode 100755 diff --git a/HNReader/Utils/+NSTextField.swift b/HNReader/Utils/+NSTextField.swift new file mode 100755 index 0000000..421cf00 --- /dev/null +++ b/HNReader/Utils/+NSTextField.swift @@ -0,0 +1,22 @@ +// +// +NSTextField.swift +// HNReader +// +// Created by Mattia Righetti on 21/07/21. +// + +import AppKit + +extension NSTextField { + func setHTMLFromString(htmlText: String) { + let modifiedFont = String(format:"%@", htmlText) + + let attrStr = try! NSAttributedString( + data: modifiedFont.data(using: .unicode, allowLossyConversion: true)!, + options: [.documentType: NSAttributedString.DocumentType.html, .characterEncoding:String.Encoding.utf8.rawValue], + documentAttributes: nil + ) + + self.stringValue = attrStr.string + } +} diff --git a/HNReader/Utils/+String.swift b/HNReader/Utils/+String.swift new file mode 100755 index 0000000..ad5d6c4 --- /dev/null +++ b/HNReader/Utils/+String.swift @@ -0,0 +1,27 @@ +// +// +String.swift +// HNReader +// +// Created by Mattia Righetti on 21/07/21. +// + +import Foundation + +extension String { + init?(htmlEncodedString: String) { + guard let data = htmlEncodedString.data(using: .utf8) else { + return nil + } + + let options: [NSAttributedString.DocumentReadingOptionKey: Any] = [ + .documentType: NSAttributedString.DocumentType.html, + .characterEncoding: String.Encoding.utf8.rawValue + ] + + guard let attributedString = try? NSAttributedString(data: data, options: options, documentAttributes: nil) else { + return nil + } + + self.init(attributedString.string) + } +} diff --git a/HNReader/Utils/+Text.swift b/HNReader/Utils/+Text.swift new file mode 100644 index 0000000..8d7021d --- /dev/null +++ b/HNReader/Utils/+Text.swift @@ -0,0 +1,109 @@ +// +// +Text.swift +// HNReader +// +// Created by Mattia Righetti on 10/20/21. +// + +import SwiftUI + +extension Text { + init(html htmlString: String, raw: Bool = false, size: CGFloat? = 18.0, fontFamily: String = "-apple-system") { // optional document-wide font family + + let fullHTML: String + if raw { + fullHTML = htmlString + } else { + var sizeCss = "" + if let size = size { + sizeCss = "font-size: \(size)px;" + } + fullHTML = """ + + + + + + + \(htmlString) + + + """ + } + + let attributedString: NSAttributedString + if + let data = fullHTML.data(using: .unicode), + let attrString = try? NSAttributedString(data: data, options: [.documentType: NSAttributedString.DocumentType.html], documentAttributes: nil) { + attributedString = attrString + } else { + attributedString = NSAttributedString() + } + + self.init(attributedString) // uses the NSAttributedString initializer + } + + init(_ attributedString: NSAttributedString) { + self.init("") // initial, empty Text + + // scan the attributed string for distinctly attributed regions + attributedString.enumerateAttributes(in: NSRange(location: 0, length: attributedString.length), options: []) { (attrs, range, _) in + let string = attributedString.attributedSubstring(from: range).string + var text = Text(string) + .foregroundColor(.white) + .font(.system(size: 15)) + + // then, read applicable attributes and apply them to the Text + + if let font = attrs[.font] as? NSFont { + // this takes care of the majority of formatting - text size, font family, + // font weight, if it's italic, etc. + text = text.font(.init(font)) + } + + if let color = attrs[.foregroundColor] as? NSColor { + text = text.foregroundColor(Color(color)) + } + + if let kern = attrs[.kern] as? CGFloat { + text = text.kerning(kern) + } + + if #available(iOS 14.0, *) { + if let tracking = attrs[.tracking] as? CGFloat { + text = text.tracking(tracking) + } + } + + if let strikethroughStyle = attrs[.strikethroughStyle] as? NSNumber, + strikethroughStyle != 0 { + if let strikethroughColor = (attrs[.strikethroughColor] as? NSColor) { + text = text.strikethrough(true, color: Color(strikethroughColor)) + } else { + text = text.strikethrough(true) + } + } + + if let underlineStyle = attrs[.underlineStyle] as? NSNumber, + underlineStyle != 0 { + if let underlineColor = (attrs[.underlineColor] as? NSColor) { + text = text.underline(true, color: Color(underlineColor)) + } else { + text = text.underline(true) + } + } + + if let baselineOffset = attrs[.baselineOffset] as? NSNumber { + text = text.baselineOffset(CGFloat(baselineOffset.floatValue)) + } + + // append the newly styled subtext to the rest of the text + self = self + text + } + } +} diff --git a/HNReader/View/Components/CommentCell.swift b/HNReader/View/Components/CommentCell.swift new file mode 100755 index 0000000..ffe12a0 --- /dev/null +++ b/HNReader/View/Components/CommentCell.swift @@ -0,0 +1,33 @@ +// +// CommentCell.swift +// HNReader +// +// Created by Mattia Righetti on 21/07/21. +// + +import SwiftUI +import HackerNews + +struct CommentCell: View { + let comment: Comment + @Environment(\.colorScheme) var colorScheme + + var body: some View { + VStack(alignment: .leading) { + Text(comment.by ?? "") + .font(.system(.body, design: .rounded)) + .foregroundColor(.yellow) + .padding(.bottom, 3) + + HStack { + Text(html: comment.text ?? "[deleted]") + .textSelection(.enabled) + .foregroundColor(.white) + Spacer() + } + } + .padding() + .background(colorScheme == .dark ? Color.black.opacity(0.3) : Color.white) + .cornerRadius(10) + } +} diff --git a/HNReader/View/Components/HTMLText.swift b/HNReader/View/Components/HTMLText.swift deleted file mode 100644 index 2f520ad..0000000 --- a/HNReader/View/Components/HTMLText.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// HTMLText.swift -// HNReader -// -// Created by Mattia Righetti on 13/06/21. -// - -import SwiftUI - -struct HTMLText: NSViewRepresentable { - var text: String - - func makeNSView(context: Context) -> NSTextField { - let text = NSTextField() - text.isEditable = false - if let attributedString = try? NSAttributedString( - data: self.text.data(using: .utf8)!, - options: [.documentType: NSAttributedString.DocumentType.html], - documentAttributes: nil - ) { - text.attributedStringValue = attributedString - } - text.textColor = .white - return text - } - - func updateNSView(_ nsView: NSViewType, context: Context) {} -} - -struct HTMLText_Previews: PreviewProvider { - static var previews: some View { - HTMLText(text: """ - string <h1>Krupal testing <span style="font-weight: - bold;">Customer WYWO</span></h1> - """) - } -} diff --git a/HNReader/View/Components/LoadingCircle.swift b/HNReader/View/Components/LoadingCircle.swift new file mode 100755 index 0000000..813c05f --- /dev/null +++ b/HNReader/View/Components/LoadingCircle.swift @@ -0,0 +1,41 @@ +// +// LoadingCircle.swift +// HNReader +// +// Created by Mattia Righetti on 21/07/21. +// + +import SwiftUI + +struct LoadingCircle: View { + @State private var isLoading = false + + var body: some View { + ZStack { + Circle() + .stroke(Color.gray.opacity(0.5), lineWidth: 10) + .frame(width: 50, height: 50) + + Circle() + .trim(from: 0, to: 0.2) + .stroke(Color.green.opacity(0.7), style: .init(lineWidth: 7, lineCap: .round)) + .frame(width: 50, height: 50) + .rotationEffect(Angle(degrees: isLoading ? 360 : 0)) + .animation( + Animation + .linear(duration: 1) + .repeatForever(autoreverses: false) + ) + .onAppear() { + self.isLoading = true + } + } + .frame(width: 70, height: 70) + } +} + +struct LoadingCircle_Previews: PreviewProvider { + static var previews: some View { + LoadingCircle() + } +} diff --git a/HNReader/View/ItemCell.swift b/HNReader/View/Components/StoryCell.swift old mode 100644 new mode 100755 similarity index 56% rename from HNReader/View/ItemCell.swift rename to HNReader/View/Components/StoryCell.swift index b286dcb..30e61ff --- a/HNReader/View/ItemCell.swift +++ b/HNReader/View/Components/StoryCell.swift @@ -6,6 +6,7 @@ // import SwiftUI +import HackerNews struct ItemCell: View { var itemId: Int @@ -13,27 +14,34 @@ struct ItemCell: View { @Environment(\.colorScheme) var colorScheme @State var item: Item? + @State private var isHovering: Bool = false init(itemId: Int) { self.itemId = itemId - itemDownloader = DefaultItemDownloader(itemId: itemId) + itemDownloader = DefaultItemDownloader() } var body: some View { VStack(alignment: .leading, spacing: 5) { TitleView() - HostText() + .onHover(perform: updateHoverStatus) + .onTapGesture { + if let item = item { + if let url = item.url { + NSWorkspace.shared.open(URL(string: url)!) + } else { + // TODO apply this logic directly in struct + NSWorkspace.shared.open(URL(string: "https://news.ycombinator.com/item?id=" + String(describing: itemId))!) + } + } + } -// if let text = item.text { -// HTMLText(text: text) -// .font(.body) -// .lineLimit(3) -// .multilineTextAlignment(.leading) -// } + HostText() HStack { ScoreText() AuthorText() + CommentsCountText() Spacer() } } @@ -45,23 +53,17 @@ struct ItemCell: View { fetchItem() } } - .onTapGesture { - if let item = item { - guard let url = URL(string: item.url!) else { return } - NSWorkspace.shared.open(url) - } - } } @ViewBuilder private func TitleView() -> some View { if let item = item { Text(item.title ?? "No title") - .font(.system(.title, design: .rounded)) + .font(.system(size: 15.0)) .fontWeight(.bold) } else { Text("No title") - .font(.system(.title, design: .rounded)) + .font(.system(size: 15.0)) .fontWeight(.bold) .redacted(reason: .placeholder) } @@ -71,12 +73,12 @@ struct ItemCell: View { private func HostText() -> some View { if let item = item { Text(item.urlHost ?? "") - .font(.callout) + .font(.system(size: 10.0)) .fontWeight(.semibold) .foregroundColor(.blue) } else { Text("No url") - .font(.callout) + .font(.system(size: 10.0)) .fontWeight(.semibold) .foregroundColor(.blue) .redacted(reason: .placeholder) @@ -87,12 +89,12 @@ struct ItemCell: View { private func ScoreText() -> some View { if let item = item { Text("\(item.score ?? 0)") - .font(.system(.callout, design: .rounded)) + .font(.system(size: 10.0)) .foregroundColor(.orange) .fontWeight(.bold) } else { Text("0") - .font(.system(.callout, design: .rounded)) + .font(.system(size: 10.0)) .foregroundColor(.orange) .fontWeight(.bold) .redacted(reason: .placeholder) @@ -106,24 +108,27 @@ struct ItemCell: View { .padding(.horizontal, 1) Text("Posted by") .foregroundColor(.gray) - if let item = item { - Text("\(item.by ?? "anonymous")") - .foregroundColor(.yellow) - .fontWeight(.bold) - } else { - Text("No author") - .redacted(reason: .placeholder) - } + + OptionalText(item?.by?.description, other: "unknown user") + .foregroundColor(.yellow) + Text("•") .padding(.horizontal, 1) - if let item = item { - Text("\(item.timeStringRepresentation ?? "")") - .foregroundColor(.gray) + } + .font(.system(size: 10.0, weight: .bold, design: .rounded)) + } + + @ViewBuilder + private func CommentsCountText() -> some View { + if let item = self.item { + if let descendants = item.descendants { + Text("\(descendants) comments") + .font(.system(size: 10.0)) } else { - Text("").redacted(reason: .placeholder) + Text("no comments") + .font(.system(size: 10.0)) } } - .font(.system(.callout, design: .rounded)) } private func fetchItem() { @@ -131,7 +136,7 @@ struct ItemCell: View { if let cachedItem = ItemCache.shared.getItem(for: cacheKey) { self.item = cachedItem } else { - itemDownloader.downloadItem(completion: { item in + itemDownloader.downloadItem(itemId: cacheKey, completion: { item in guard let item = item else { return } ItemCache.shared.cache(item, for: cacheKey) DispatchQueue.main.async { @@ -140,6 +145,35 @@ struct ItemCell: View { }) } } + + private func updateHoverStatus(hovering: Bool) -> Void { + self.isHovering.toggle() + DispatchQueue.main.async { + if (self.isHovering) { + NSCursor.pointingHand.push() + } else { + NSCursor.pop() + } + } + } +} + +struct OptionalText: View { + let content: Content? + let other: String + + init(_ content: Content?, other: String) { + self.content = content + self.other = other + } + + var body: some View { + if let content = content { + Text(content) + } else { + Text(other) + } + } } struct ItemCell_Previews: PreviewProvider { diff --git a/HNReader/View/DetailStoryView.swift b/HNReader/View/DetailStoryView.swift new file mode 100755 index 0000000..a26e216 --- /dev/null +++ b/HNReader/View/DetailStoryView.swift @@ -0,0 +1,173 @@ +// +// ItemView.swift +// HNReader +// +// Created by Mattia Righetti on 18/06/21. +// + +import SwiftUI +import HackerNews + +struct DetailStoryView: View { + var itemId: Int + + @Environment(\.colorScheme) var colorScheme + @State var item: Item? + @State var fetching: Bool = false + @State var comments: [Comment]? + @State var nextPage: Int = 1 + @State var showMore: Bool = false + let dispatchQueue = DispatchQueue(label: "CommentScrapingThreadQueue", qos: .background) + + init(itemId: Int) { + self.itemId = itemId + } + + var body: some View { + ScrollView { + ItemSection() + .padding() + + LoadingView( + condition: .init( + get: { self.fetching && self.comments == nil }, + set: { _ in return } + ) + ) { + CommentsSection() + .padding() + } + }.onAppear { + self.item = ItemCache.shared.getItem(for: self.itemId) + fetchComments() + } + } + + @ViewBuilder + func ItemSection() -> some View { + switch self.item?.type { + case .story, .job: + StorySection() + default: + Text("No view available for this element with id: \(self.itemId)") + } + } + + @ViewBuilder + func StorySection() -> some View { + VStack(alignment: .leading) { + Text(item?.title ?? "") + .font(.largeTitle) + .fixedSize(horizontal: false, vertical: true) + .padding(.vertical, 5) + + if let text = item?.text { + Text(html: text) + .font(.body) + .fixedSize(horizontal: false, vertical: true) + .padding(.vertical, 5) + } + + HStack { + Text("Posted by ") + .font(.system(.callout, design: .rounded)) + .foregroundColor(.gray) + + Text(item?.by ?? "") + .font(.system(.callout, design: .rounded)) + .foregroundColor(.yellow) + .fontWeight(.bold) + + Spacer() + } + } + } + + @ViewBuilder + func CommentsSection() -> some View { + if let comments = comments { + VStack(alignment: .leading) { + ForEach(comments, id: \.id) { comment in + CommentCell(comment: comment) + .padding(.leading, 20 * CGFloat(comment.indentLevel)) + } + if showMore { + Button("More...", action: { + fetchComments() + }) + .padding(.top, 5) + } + } + } else { + VStack { + Spacer() + Image("NoComments") + .resizable() + .frame(width: 400, height: 400, alignment: .center) + Spacer() + } + } + } + + private func fetchComments() { + guard item!.kids != nil else { return } + self.fetching.toggle() + dispatchQueue.async { + HackerNewsScraperClient.shared.getComments(forItemId: item!.id, page: self.nextPage) { success, comments, hasMore in + DispatchQueue.main.async { + self.showMore = hasMore + self.nextPage += 1 + + if self.comments == nil { + self.comments = comments + } else { + self.comments!.append(contentsOf: comments) + } + + self.fetching.toggle() + } + } + } + } + + private func parseToNSAttributedString(string: String) -> NSAttributedString? { + guard let data = string.data(using: .utf8) else { + return nil + } + + let options: [NSAttributedString.DocumentReadingOptionKey: Any] = [ + .documentType: NSAttributedString.DocumentType.html, + .characterEncoding: String.Encoding.utf8.rawValue + ] + + guard let attributedString = try? NSAttributedString(data: data, options: options, documentAttributes: nil) else { + return nil + } + + return attributedString + } +} + +struct LoadingView: View { + @Binding var condition: Bool + let content: Content + + init(condition: Binding, @ViewBuilder content: () -> Content) { + self._condition = condition + self.content = content() + } + + var body: some View { + if condition { + LoadingCircle() + } else { + content + } + } +} + +struct ItemView_Previews: PreviewProvider { + static var previews: some View { + DetailStoryView(itemId: 27545257) + } +} diff --git a/HNReader/View/HNReader/HNReader.app/Contents/Info.plist b/HNReader/View/HNReader/HNReader.app/Contents/Info.plist old mode 100644 new mode 100755 diff --git a/HNReader/View/HNReader/HNReader.app/Contents/PkgInfo b/HNReader/View/HNReader/HNReader.app/Contents/PkgInfo old mode 100644 new mode 100755 diff --git a/HNReader/View/HNReader/HNReader.app/Contents/Resources/AppIcon.icns b/HNReader/View/HNReader/HNReader.app/Contents/Resources/AppIcon.icns old mode 100644 new mode 100755 diff --git a/HNReader/View/HNReader/HNReader.app/Contents/Resources/Assets.car b/HNReader/View/HNReader/HNReader.app/Contents/Resources/Assets.car old mode 100644 new mode 100755 diff --git a/HNReader/View/HNReader/HNReader.app/Contents/Resources/HNReader.momd/HNReader.mom b/HNReader/View/HNReader/HNReader.app/Contents/Resources/HNReader.momd/HNReader.mom old mode 100644 new mode 100755 diff --git a/HNReader/View/HNReader/HNReader.app/Contents/Resources/HNReader.momd/HNReader.omo b/HNReader/View/HNReader/HNReader.app/Contents/Resources/HNReader.momd/HNReader.omo old mode 100644 new mode 100755 diff --git a/HNReader/View/HNReader/HNReader.app/Contents/Resources/HNReader.momd/VersionInfo.plist b/HNReader/View/HNReader/HNReader.app/Contents/Resources/HNReader.momd/VersionInfo.plist old mode 100644 new mode 100755 diff --git a/HNReader/View/HNReader/HNReader.app/Contents/_CodeSignature/CodeResources b/HNReader/View/HNReader/HNReader.app/Contents/_CodeSignature/CodeResources old mode 100644 new mode 100755 diff --git a/HNReader/View/HomeView.swift b/HNReader/View/HomeView.swift old mode 100644 new mode 100755 index 24bb587..e662c1d --- a/HNReader/View/HomeView.swift +++ b/HNReader/View/HomeView.swift @@ -9,10 +9,24 @@ import SwiftUI import CoreData struct HomeView: View { + @EnvironmentObject var appState: AppState + @State var selectedItem: Int? = nil + var body: some View { NavigationView { Sidebar() - ItemList() + StoryList(selectedItem: $selectedItem).frame(minWidth: 400) + SelectStoryPlaceholderImage() + } + } +} + +struct SelectStoryPlaceholderImage: View { + var body: some View { + VStack { + Image("Select") + .resizable() + .frame(width: 400, height: 400, alignment: .center) } } } diff --git a/HNReader/View/ItemList.swift b/HNReader/View/StoryList.swift old mode 100644 new mode 100755 similarity index 65% rename from HNReader/View/ItemList.swift rename to HNReader/View/StoryList.swift index d8e7c5b..d254c34 --- a/HNReader/View/ItemList.swift +++ b/HNReader/View/StoryList.swift @@ -6,28 +6,37 @@ // import SwiftUI +import HackerNews import OSLog -struct ItemList: View { +struct StoryList: View { @EnvironmentObject var appState: AppState @StateObject var viewModel = ItemListViewModel() - @State private var itemLimitSelection: Int = 1 - private var itemLimitOptions: [Int] = [25, 50, 100] + @State var itemLimitSelection: Int = 1 + @Binding var selectedItem: Int? + var itemLimitOptions: [Int] = [25, 50, 100] var body: some View { - ScrollView { - LazyVStack(alignment: .leading) { + ScrollViewReader { proxy in + List { ForEach(viewModel.storiesIds, id: \.self) { itemId in - ItemCell(itemId: itemId) - .padding(.horizontal) + NavigationLink( + destination: DetailStoryView(itemId: itemId), + label: { + ItemCell(itemId: itemId) + } + ).id(itemId) } - } - .padding(.vertical) + }.onChange(of: appState.newsSelection, perform: { value in + fetchItems(by: value) + withAnimation { + proxy.scrollTo(viewModel.storiesIds.first) + } + }) } .onAppear { viewModel.currentNewsSelection = appState.newsSelection } - .onChange(of: appState.newsSelection, perform: fetchItems) .toolbar { MaxItemPicker(enabled: false) Button(action: viewModel.refreshStories) { @@ -62,6 +71,7 @@ struct ItemList: View { struct ItemList_Previews: PreviewProvider { static var previews: some View { - ItemList() + StoryList(selectedItem: .constant(nil)) + .environmentObject(AppState()) } } diff --git a/HNReader/ViewModel/AppState.swift b/HNReader/ViewModel/AppState.swift old mode 100644 new mode 100755 index 2900e73..daa04a5 --- a/HNReader/ViewModel/AppState.swift +++ b/HNReader/ViewModel/AppState.swift @@ -6,10 +6,11 @@ // import Combine +import HackerNews import SwiftUI class AppState: ObservableObject { - @AppStorage("displayMode") var displayMode: DisplayMode = .system + @AppStorage("displayMode") var displayMode: DisplayMode = .dark @Published var sidebarSelection: SidebarSelection? = SidebarSelection.top { willSet { switch newValue { diff --git a/HNReader/ViewModel/ItemListViewModel.swift b/HNReader/ViewModel/ItemListViewModel.swift old mode 100644 new mode 100755 index c7492c4..53fc5f7 --- a/HNReader/ViewModel/ItemListViewModel.swift +++ b/HNReader/ViewModel/ItemListViewModel.swift @@ -4,7 +4,7 @@ import Combine import SwiftUI -import OSLog +import HackerNews class ItemListViewModel: ObservableObject { @Published var currentNewsSelection: HackerNews.API.Stories = .top { @@ -13,22 +13,13 @@ class ItemListViewModel: ObservableObject { } } @Published var storiesIds: [Int] = [] - public var subscriptions = Set() public func fetchStories(by category: HackerNews.API.Stories) { - HackerNewsClient.shared.getStoriesId(by: category) - .receive(on: DispatchQueue.main) - .sink(receiveCompletion: { completion in - switch completion { - case .failure(let error): - NSLog("encountered error while completing fetch task: \(error)") - case .finished: - break - } - }, receiveValue: { [unowned self] itemIds in - storiesIds = itemIds - }) - .store(in: &subscriptions) + HackerNewsFirebaseClient.shared.getStoriesIds(category) { ids in + DispatchQueue.main.async { + self.storiesIds = ids + } + } } public func refreshStories() { diff --git a/HNReaderTests/HNClientTests/HackerNewsClientTests.swift b/HNReaderTests/HNClientTests/HackerNewsClientTests.swift old mode 100644 new mode 100755 index d975c7b..1e70db5 --- a/HNReaderTests/HNClientTests/HackerNewsClientTests.swift +++ b/HNReaderTests/HNClientTests/HackerNewsClientTests.swift @@ -94,7 +94,6 @@ class HackerNewsClientTests: XCTestCase { XCTAssertNil(error) XCTAssertNotNil(stories) - print(stories) XCTAssertFalse(stories!.isEmpty) } } diff --git a/HNReaderTests/HNClientTests/HackerNewsTests.swift b/HNReaderTests/HNClientTests/HackerNewsTests.swift old mode 100644 new mode 100755 diff --git a/HNReaderTests/Info.plist b/HNReaderTests/Info.plist old mode 100644 new mode 100755 diff --git a/HNReaderTests/ModelTests/ItemTests.swift b/HNReaderTests/ModelTests/ItemTests.swift old mode 100644 new mode 100755 diff --git a/HNReaderTests/UtilsTests/+DateTests.swift b/HNReaderTests/UtilsTests/+DateTests.swift old mode 100644 new mode 100755 diff --git a/HNReaderUITests/HNReaderUITests.swift b/HNReaderUITests/HNReaderUITests.swift old mode 100644 new mode 100755 diff --git a/HNReaderUITests/Info.plist b/HNReaderUITests/Info.plist old mode 100644 new mode 100755 diff --git a/LICENSE b/LICENSE old mode 100644 new mode 100755 diff --git a/Logo/HNReader Logo.sketch b/Logo/HNReader Logo.sketch old mode 100644 new mode 100755 diff --git a/Logo/Logo.png b/Logo/Logo.png old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 98ec36b..085378c --- a/README.md +++ b/README.md @@ -17,10 +17,8 @@ The application is still in beta for the moment and needs optimizations. When th ## Application preview ### Dark mode -Screenshot 2021-06-14 at 18 14 16 - -### Light mode -Screenshot 2021-06-14 at 21 13 59 +Screenshot 2021-06-14 at 18 14 16 +Screenshot 2021-06-14 at 18 14 16 ## License [MIT](LICENSE) or [APACHE 2.0](LICENSE) diff --git a/resources/appstore.png b/resources/appstore.png old mode 100644 new mode 100755 diff --git a/resources/main.png b/resources/main.png new file mode 100644 index 0000000..a2bda51 Binary files /dev/null and b/resources/main.png differ diff --git a/resources/mainwithdetailview.png b/resources/mainwithdetailview.png new file mode 100644 index 0000000..26a2a83 Binary files /dev/null and b/resources/mainwithdetailview.png differ diff --git a/resources/screenshot.png b/resources/screenshot.png deleted file mode 100644 index 9b2dbea..0000000 Binary files a/resources/screenshot.png and /dev/null differ