diff --git a/ResumeBuilder.xcodeproj/project.pbxproj b/ResumeBuilder.xcodeproj/project.pbxproj index 1e0c36f..f46d3d8 100644 --- a/ResumeBuilder.xcodeproj/project.pbxproj +++ b/ResumeBuilder.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 880A8C212AFE3B0C000ABBFA /* PhoneNumberKit in Frameworks */ = {isa = PBXBuildFile; productRef = 880A8C202AFE3B0C000ABBFA /* PhoneNumberKit */; }; 886AD6452AB9CD9100B1A00D /* ColorScheme+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 886AD6442AB9CD9100B1A00D /* ColorScheme+Extensions.swift */; }; E267D1742A8E0DE80069112B /* ResumeBuilderApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = E267D1732A8E0DE80069112B /* ResumeBuilderApp.swift */; }; E267D1762A8E0DE80069112B /* CV.swift in Sources */ = {isa = PBXBuildFile; fileRef = E267D1752A8E0DE80069112B /* CV.swift */; }; @@ -84,6 +85,7 @@ buildActionMask = 2147483647; files = ( E267D1882A8E12D60069112B /* SFSafeSymbols in Frameworks */, + 880A8C212AFE3B0C000ABBFA /* PhoneNumberKit in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -220,6 +222,7 @@ name = ResumeBuilder; packageProductDependencies = ( E267D1872A8E12D60069112B /* SFSafeSymbols */, + 880A8C202AFE3B0C000ABBFA /* PhoneNumberKit */, ); productName = ResumeBuilder; productReference = E267D1702A8E0DE80069112B /* ResumeBuilder.app */; @@ -251,6 +254,7 @@ mainGroup = E267D1672A8E0DE80069112B; packageReferences = ( E267D1862A8E12D60069112B /* XCRemoteSwiftPackageReference "SFSafeSymbols" */, + 880A8C1F2AFE3B0C000ABBFA /* XCRemoteSwiftPackageReference "PhoneNumberKit" */, ); productRefGroup = E267D1712A8E0DE80069112B /* Products */; projectDirPath = ""; @@ -516,6 +520,14 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ + 880A8C1F2AFE3B0C000ABBFA /* XCRemoteSwiftPackageReference "PhoneNumberKit" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/marmelroy/PhoneNumberKit"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 3.7.4; + }; + }; E267D1862A8E12D60069112B /* XCRemoteSwiftPackageReference "SFSafeSymbols" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/SFSafeSymbols/SFSafeSymbols"; @@ -527,6 +539,11 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ + 880A8C202AFE3B0C000ABBFA /* PhoneNumberKit */ = { + isa = XCSwiftPackageProductDependency; + package = 880A8C1F2AFE3B0C000ABBFA /* XCRemoteSwiftPackageReference "PhoneNumberKit" */; + productName = PhoneNumberKit; + }; E267D1872A8E12D60069112B /* SFSafeSymbols */ = { isa = XCSwiftPackageProductDependency; package = E267D1862A8E12D60069112B /* XCRemoteSwiftPackageReference "SFSafeSymbols" */; diff --git a/ResumeBuilder.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ResumeBuilder.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index e8341d6..07827d5 100644 --- a/ResumeBuilder.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/ResumeBuilder.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,14 @@ { "pins" : [ + { + "identity" : "phonenumberkit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/marmelroy/PhoneNumberKit", + "state" : { + "revision" : "b456f2f9be10c1d183158220b831afd22697dd68", + "version" : "3.7.4" + } + }, { "identity" : "sfsafesymbols", "kind" : "remoteSourceControl", diff --git a/ResumeBuilder.xcodeproj/project.xcworkspace/xcuserdata/imac.xcuserdatad/UserInterfaceState.xcuserstate b/ResumeBuilder.xcodeproj/project.xcworkspace/xcuserdata/imac.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..fb1063b Binary files /dev/null and b/ResumeBuilder.xcodeproj/project.xcworkspace/xcuserdata/imac.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/ResumeBuilder.xcodeproj/xcuserdata/imac.xcuserdatad/xcschemes/xcschememanagement.plist b/ResumeBuilder.xcodeproj/xcuserdata/imac.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..f00878d --- /dev/null +++ b/ResumeBuilder.xcodeproj/xcuserdata/imac.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + ResumeBuilder.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/ResumeBuilder/Generic Elements/LeftImageLabel.swift b/ResumeBuilder/Generic Elements/LeftImageLabel.swift index 79b0ca6..c69aca5 100644 --- a/ResumeBuilder/Generic Elements/LeftImageLabel.swift +++ b/ResumeBuilder/Generic Elements/LeftImageLabel.swift @@ -1,20 +1,20 @@ import SwiftUI import SFSafeSymbols -struct LeftImageLabel: View { - - let text: String +struct LeftImageLabel: View where Content: View { let systemSymbol: SFSymbol + + let content: Content - init(_ text: String, systemSymbol: SFSymbol) { - self.text = text + init(systemSymbol: SFSymbol, @ViewBuilder content: () -> Content) { self.systemSymbol = systemSymbol + self.content = content() } var body: some View { - HStack(alignment: .firstTextBaseline, spacing: 0) { - Text(text) + HStack(alignment: .center, spacing: 0) { + content Image(systemSymbol: systemSymbol) .frame(width: 20) } @@ -23,6 +23,6 @@ struct LeftImageLabel: View { struct LeftImageLabel_Previews: PreviewProvider { static var previews: some View { - LeftImageLabel("Home address", systemSymbol: .house) + LeftImageLabel(systemSymbol: .house) { Text("Home address") } } } diff --git a/ResumeBuilder/Main Elements/TopView.swift b/ResumeBuilder/Main Elements/TopView.swift index 67ece5b..f613169 100644 --- a/ResumeBuilder/Main Elements/TopView.swift +++ b/ResumeBuilder/Main Elements/TopView.swift @@ -1,5 +1,8 @@ import SwiftUI import SFSafeSymbols +import PhoneNumberKit + +private let emailPattern = #"^\S+@\S+\.\S+$"# struct TopView: View { @@ -8,6 +11,21 @@ struct TopView: View { let style: HeaderStyle let accent: Color + + private let phoneNumberKit = PhoneNumberKit() + + var isValidEmail: Bool { + info.email.range(of: emailPattern, options: .regularExpression) != nil + } + + var isValidPhoneNumber: Bool { + do { + _ = try phoneNumberKit.parse(info.phone) + return true + } catch { + return false + } + } var body: some View { GeometryReader { geo in @@ -34,18 +52,26 @@ struct TopView: View { shadow: style.imageShadowSize, lineWidth: style.imageBorderWidth) VStack(alignment: .trailing) { - LeftImageLabel(info.web, systemSymbol: .globe) - .frame(maxHeight: style.iconHeight) + LeftImageLabel(systemSymbol: .globe) { + Link(info.web, destination: URL(string: "https://" + info.web)!) + } + .frame(maxHeight: style.iconHeight) Spacer() - LeftImageLabel(info.email, systemSymbol: .envelope) - .frame(maxHeight: style.iconHeight) + LeftImageLabel(systemSymbol: .envelope) { + Link(info.email, destination: URL(string: "mailto:" + info.email)!) + .disabled(!isValidEmail) + } + .frame(maxHeight: style.iconHeight) Spacer() - LeftImageLabel(info.phone, systemSymbol: .phone) - .frame(maxHeight: style.iconHeight) + LeftImageLabel(systemSymbol: .phone) { + Link(info.phone, destination: URL(string: "tel:" + info.phone)!) + .disabled(!isValidPhoneNumber) + } + .frame(maxHeight: style.iconHeight) Spacer() HStack(spacing: 0) { Spacer() - Text(info.github) + Link(info.github, destination: URL(string: "https://" + info.github)!) Image("Github") .resizable() .aspectRatio(1.0, contentMode: .fit) @@ -55,6 +81,7 @@ struct TopView: View { } .font(.subheadline) .frame(width: sideWidth) + .foregroundStyle(.primary) } } }