diff --git a/HNReader.xcodeproj/project.pbxproj b/HNReader.xcodeproj/project.pbxproj index ffae84e..8cb8aec 100644 --- a/HNReader.xcodeproj/project.pbxproj +++ b/HNReader.xcodeproj/project.pbxproj @@ -20,6 +20,9 @@ 5F109D602AF704F700AE6AF3 /* IBMPlexSerif-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 5F109D5C2AF704F700AE6AF3 /* IBMPlexSerif-Bold.ttf */; }; 5F109D612AF704F700AE6AF3 /* IBMPlexSerif-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 5F109D5D2AF704F700AE6AF3 /* IBMPlexSerif-Regular.ttf */; }; 5F109D622AF704F700AE6AF3 /* IBMPlexSerif-SemiBold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 5F109D5E2AF704F700AE6AF3 /* IBMPlexSerif-SemiBold.ttf */; }; + 5FCE20A72AF7B25A00BF4097 /* InfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FCE20A62AF7B25A00BF4097 /* InfoView.swift */; }; + 5FCE20A92AF7B47B00BF4097 /* BgButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FCE20A82AF7B47B00BF4097 /* BgButton.swift */; }; + 5FCE20AB2AF7B8EE00BF4097 /* +View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FCE20AA2AF7B8EE00BF4097 /* +View.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 */; }; @@ -59,6 +62,9 @@ 5F109D5C2AF704F700AE6AF3 /* IBMPlexSerif-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "IBMPlexSerif-Bold.ttf"; sourceTree = ""; }; 5F109D5D2AF704F700AE6AF3 /* IBMPlexSerif-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "IBMPlexSerif-Regular.ttf"; sourceTree = ""; }; 5F109D5E2AF704F700AE6AF3 /* IBMPlexSerif-SemiBold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "IBMPlexSerif-SemiBold.ttf"; sourceTree = ""; }; + 5FCE20A62AF7B25A00BF4097 /* InfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoView.swift; sourceTree = ""; }; + 5FCE20A82AF7B47B00BF4097 /* BgButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BgButton.swift; sourceTree = ""; }; + 5FCE20AA2AF7B8EE00BF4097 /* +View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "+View.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 = ""; }; @@ -101,6 +107,7 @@ isa = PBXGroup; children = ( 3307159309D438EFAA1259C7 /* +Date.swift */, + 5FCE20AA2AF7B8EE00BF4097 /* +View.swift */, ); path = Utils; sourceTree = ""; @@ -145,6 +152,7 @@ isa = PBXGroup; children = ( C93F99B9267580CE0046F870 /* HTMLText.swift */, + 5FCE20A82AF7B47B00BF4097 /* BgButton.swift */, ); path = Components; sourceTree = ""; @@ -213,6 +221,7 @@ C93F99B7267557FC0046F870 /* ItemList.swift */, C9926691267588B80035A88F /* Components */, 5F109D582AF6F50D00AE6AF3 /* ConditionalRedactedModifier.swift */, + 5FCE20A62AF7B25A00BF4097 /* InfoView.swift */, ); path = View; sourceTree = ""; @@ -358,6 +367,8 @@ C9D0938026741BBF002CC786 /* Persistence.swift in Sources */, C9D0937926741BBE002CC786 /* HomeView.swift in Sources */, C93F99B6267554F00046F870 /* ItemCell.swift in Sources */, + 5FCE20A92AF7B47B00BF4097 /* BgButton.swift in Sources */, + 5FCE20A72AF7B25A00BF4097 /* InfoView.swift in Sources */, 5F109D592AF6F50D00AE6AF3 /* ConditionalRedactedModifier.swift in Sources */, C93F99B8267557FC0046F870 /* ItemList.swift in Sources */, C9E9BCFD2674C80E001B4E19 /* AppState.swift in Sources */, @@ -369,6 +380,7 @@ 330713D3016ED410AFD53FDF /* ItemListViewModel.swift in Sources */, 330711A9216E762026AF98A0 /* +Date.swift in Sources */, 33071F1C64D4742E1F947FAA /* ItemDownloader.swift in Sources */, + 5FCE20AB2AF7B8EE00BF4097 /* +View.swift in Sources */, 3307147AB95F03650FC40B97 /* ItemCache.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/HNReader.xcodeproj/project.xcworkspace/xcuserdata/mattrighetti.xcuserdatad/UserInterfaceState.xcuserstate b/HNReader.xcodeproj/project.xcworkspace/xcuserdata/mattrighetti.xcuserdatad/UserInterfaceState.xcuserstate index be18bfc..9929683 100644 Binary files a/HNReader.xcodeproj/project.xcworkspace/xcuserdata/mattrighetti.xcuserdatad/UserInterfaceState.xcuserstate and b/HNReader.xcodeproj/project.xcworkspace/xcuserdata/mattrighetti.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/HNReader/Utils/+View.swift b/HNReader/Utils/+View.swift new file mode 100644 index 0000000..3a00527 --- /dev/null +++ b/HNReader/Utils/+View.swift @@ -0,0 +1,20 @@ +// +// +View.swift +// HNReader +// +// Created by Mattia Righetti on 05/11/23. +// + +import SwiftUI + +extension View { + @discardableResult + func openInWindow(title: String, sender: Any?) -> NSWindow { + let controller = NSHostingController(rootView: self) + let win = NSWindow(contentViewController: controller) + win.contentViewController = controller + win.title = title + win.makeKeyAndOrderFront(sender) + return win + } +} diff --git a/HNReader/View/Components/BgButton.swift b/HNReader/View/Components/BgButton.swift new file mode 100644 index 0000000..872843b --- /dev/null +++ b/HNReader/View/Components/BgButton.swift @@ -0,0 +1,47 @@ +// +// BgButton.swift +// HNReader +// +// Created by Mattia Righetti on 05/11/23. +// + +import SwiftUI + +struct BgButton: View { + var text: String? = nil + var icon: String + var disabled: Bool = false + var minSize: CGSize + var onHover: ((Bool) -> Void)? = nil + var action: (() -> ())? = nil + + var body: some View { + ZStack { + RoundedRectangle(cornerRadius: 15) + .foregroundStyle(Color.gray.opacity(0.1)) + .frame(width: minSize.width, height: minSize.height) + + Label(title: { + if text != nil { + Text(text!) + .font(.custom("IBMPlexSerif-Regular", size: 13)) + } + }, icon: { + Image(systemName: icon) + }) + .foregroundStyle(disabled ? .tertiary : .primary) + .padding() + } + .frame(width: minSize.width, height: minSize.height) + .onHover { + onHover?($0) + } + .onTapGesture { + action?() + } + } +} + +#Preview { + BgButton(text: "Rate app", icon: "star", minSize: CGSize(width: 150, height: 50)).padding() +} diff --git a/HNReader/View/InfoView.swift b/HNReader/View/InfoView.swift new file mode 100644 index 0000000..c7bad67 --- /dev/null +++ b/HNReader/View/InfoView.swift @@ -0,0 +1,50 @@ +// +// InfoView.swift +// HNReader +// +// Created by Mattia Righetti on 05/11/23. +// + +import SwiftUI + +struct InfoView: View { + var body: some View { + VStack { + Text("HNReader v1.2") + .font(.title2) + .padding(.bottom) + + Text("This project is open source") + + BgButton(text: "Rate HNReader", icon: "star", minSize: CGSize(width: 200, height: 50), onHover: { h in + DispatchQueue.main.async { + if (h) { + NSCursor.pointingHand.push() + } else { + NSCursor.pop() + } + } + }, action: { + NSWorkspace.shared.open(URL(string: "https://github.com/mattrighetti/HNReader.git")!) + }) + + BgButton(text: "Open on GitHub", icon: "arrow.up.right", minSize: CGSize(width: 200, height: 50), onHover: { h in + DispatchQueue.main.async { + if (h) { + NSCursor.pointingHand.push() + } else { + NSCursor.pop() + } + } + }, action: { + NSWorkspace.shared.open(URL(string: "https://github.com/mattrighetti/HNReader.git")!) + }) + } + .padding() + .frame(minWidth: 300) + } +} + +#Preview { + InfoView() +} diff --git a/HNReader/View/ItemCell.swift b/HNReader/View/ItemCell.swift index 0c14a25..a5dd9a9 100644 --- a/HNReader/View/ItemCell.swift +++ b/HNReader/View/ItemCell.swift @@ -55,20 +55,7 @@ struct ItemCell: View { } HStack { - - ZStack { - RoundedRectangle(cornerRadius: 15) - .foregroundStyle(Color.gray.opacity(0.1)) - .frame(width: 50, height: 50) - - Label(title: {}, icon: { - Image(systemName: "bubble.left") - }) - .foregroundStyle(.primary) - .padding() - } - .frame(width: 50, height: 50) - .onHover { isHovered in + BgButton(icon: "bubble.left", minSize: CGSize(width: 50, height: 50), onHover: { isHovered in DispatchQueue.main.async { if (isHovered) { NSCursor.pointingHand.push() @@ -76,27 +63,14 @@ struct ItemCell: View { NSCursor.pop() } } - } - .onTapGesture { + }, action: { if let item = item { guard let url = URL(string: "https://news.ycombinator.com/item?id=\(item.id)") else { return } NSWorkspace.shared.open(url) } - } + }) - ZStack { - RoundedRectangle(cornerRadius: 15) - .foregroundStyle(Color.gray.opacity(0.1)) - .frame(width: 50, height: 50) - - Label(title: {}, icon: { - Image(systemName: "arrow.up.right") - }) - .foregroundStyle(item?.url != nil ? .primary : .tertiary) - .padding() - } - .frame(width: 50, height: 50) - .onHover { isHovered in + BgButton(icon: "arrow.up.right", disabled: item?.url == nil, minSize: CGSize(width: 50, height: 50), onHover: { isHovered in DispatchQueue.main.async { if (isHovered) { if item?.url == nil { @@ -108,12 +82,12 @@ struct ItemCell: View { NSCursor.pop() } } - } - .onTapGesture { + }, action: { guard let url = item?.url, let url = URL(string: url) else { return } NSWorkspace.shared.open(url) - } - }.padding(.leading) + }) + } + .padding(.leading) } .padding() .background(colorScheme == .dark ? Color.black.opacity(0.3) : Color.gray.opacity(0.1)) diff --git a/HNReader/View/ItemList.swift b/HNReader/View/ItemList.swift index 656ca75..767a845 100644 --- a/HNReader/View/ItemList.swift +++ b/HNReader/View/ItemList.swift @@ -32,6 +32,11 @@ struct ItemList: View { Button(action: viewModel.refreshStories) { Label("Refresh news", systemImage: "arrow.counterclockwise.circle") } + Button(action: { + InfoView().openInWindow(title: "Info", sender: nil) + }, label: { + Label("Info", systemImage: "info.circle") + }) } .navigationTitle("Hacker News") }