diff --git a/.gitignore b/.gitignore index 91716a5e..e6ed1d5b 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ templates/ Preview.html l10n passepartout-translations.zip +default.profraw diff --git a/CHANGELOG.md b/CHANGELOG.md index 7cb7f333..ed99c731 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## Added + +- Child Safe VPN provider. + ## Changed - Use active profile name in iOS settings. diff --git a/Passepartout-iOS/Global/SwiftGen+Assets.swift b/Passepartout-iOS/Global/SwiftGen+Assets.swift index ff3155d8..40b213ac 100644 --- a/Passepartout-iOS/Global/SwiftGen+Assets.swift +++ b/Passepartout-iOS/Global/SwiftGen+Assets.swift @@ -1,18 +1,19 @@ // swiftlint:disable all // Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen -#if os(OSX) - import AppKit.NSImage - internal typealias AssetColorTypeAlias = NSColor - internal typealias AssetImageTypeAlias = NSImage -#elseif os(iOS) || os(tvOS) || os(watchOS) - import UIKit.UIImage - internal typealias AssetColorTypeAlias = UIColor - internal typealias AssetImageTypeAlias = UIImage +#if os(macOS) + import AppKit +#elseif os(iOS) + import UIKit +#elseif os(tvOS) || os(watchOS) + import UIKit #endif -// swiftlint:disable superfluous_disable_command -// swiftlint:disable file_length +// Deprecated typealiases +@available(*, deprecated, renamed: "ImageAsset.Image", message: "This typealias will be removed in SwiftGen 7.0") +internal typealias AssetImageTypeAlias = ImageAsset.Image + +// swiftlint:disable superfluous_disable_command file_length implicit_return // MARK: - Asset Catalogs @@ -281,6 +282,7 @@ internal enum Asset { internal static let zw = ImageAsset(name: "zw") } internal enum Providers { + internal static let csv = ImageAsset(name: "csv") internal static let hideme = ImageAsset(name: "hideme") internal static let mullvad = ImageAsset(name: "mullvad") internal static let nordvpn = ImageAsset(name: "nordvpn") @@ -297,80 +299,39 @@ internal enum Asset { // MARK: - Implementation Details -internal struct ColorAsset { - internal fileprivate(set) var name: String - - @available(iOS 11.0, tvOS 11.0, watchOS 4.0, OSX 10.13, *) - internal var color: AssetColorTypeAlias { - return AssetColorTypeAlias(asset: self) - } -} - -internal extension AssetColorTypeAlias { - @available(iOS 11.0, tvOS 11.0, watchOS 4.0, OSX 10.13, *) - convenience init!(asset: ColorAsset) { - let bundle = Bundle(for: BundleToken.self) - #if os(iOS) || os(tvOS) - self.init(named: asset.name, in: bundle, compatibleWith: nil) - #elseif os(OSX) - self.init(named: NSColor.Name(asset.name), bundle: bundle) - #elseif os(watchOS) - self.init(named: asset.name) - #endif - } -} - -internal struct DataAsset { - internal fileprivate(set) var name: String - - #if os(iOS) || os(tvOS) || os(OSX) - @available(iOS 9.0, tvOS 9.0, OSX 10.11, *) - internal var data: NSDataAsset { - return NSDataAsset(asset: self) - } - #endif -} - -#if os(iOS) || os(tvOS) || os(OSX) -@available(iOS 9.0, tvOS 9.0, OSX 10.11, *) -internal extension NSDataAsset { - convenience init!(asset: DataAsset) { - let bundle = Bundle(for: BundleToken.self) - #if os(iOS) || os(tvOS) - self.init(name: asset.name, bundle: bundle) - #elseif os(OSX) - self.init(name: NSDataAsset.Name(asset.name), bundle: bundle) - #endif - } -} -#endif - internal struct ImageAsset { internal fileprivate(set) var name: String - internal var image: AssetImageTypeAlias { - let bundle = Bundle(for: BundleToken.self) + #if os(macOS) + internal typealias Image = NSImage + #elseif os(iOS) || os(tvOS) || os(watchOS) + internal typealias Image = UIImage + #endif + + internal var image: Image { + let bundle = BundleToken.bundle #if os(iOS) || os(tvOS) - let image = AssetImageTypeAlias(named: name, in: bundle, compatibleWith: nil) - #elseif os(OSX) + let image = Image(named: name, in: bundle, compatibleWith: nil) + #elseif os(macOS) let image = bundle.image(forResource: NSImage.Name(name)) #elseif os(watchOS) - let image = AssetImageTypeAlias(named: name) + let image = Image(named: name) #endif - guard let result = image else { fatalError("Unable to load image named \(name).") } + guard let result = image else { + fatalError("Unable to load image named \(name).") + } return result } } -internal extension AssetImageTypeAlias { - @available(iOS 1.0, tvOS 1.0, watchOS 1.0, *) - @available(OSX, deprecated, +internal extension ImageAsset.Image { + @available(macOS, deprecated, message: "This initializer is unsafe on macOS, please use the ImageAsset.image property") convenience init!(asset: ImageAsset) { #if os(iOS) || os(tvOS) - let bundle = Bundle(for: BundleToken.self) + let bundle = BundleToken.bundle self.init(named: asset.name, in: bundle, compatibleWith: nil) - #elseif os(OSX) + #elseif os(macOS) self.init(named: NSImage.Name(asset.name)) #elseif os(watchOS) self.init(named: asset.name) @@ -378,4 +339,10 @@ internal extension AssetImageTypeAlias { } } -private final class BundleToken {} +// swiftlint:disable convenience_type +private final class BundleToken { + static let bundle: Bundle = { + Bundle(for: BundleToken.self) + }() +} +// swiftlint:enable convenience_type diff --git a/Passepartout-iOS/Global/SwiftGen+Scenes.swift b/Passepartout-iOS/Global/SwiftGen+Scenes.swift index 999e5fce..86553a15 100644 --- a/Passepartout-iOS/Global/SwiftGen+Scenes.swift +++ b/Passepartout-iOS/Global/SwiftGen+Scenes.swift @@ -65,7 +65,7 @@ internal protocol StoryboardType { internal extension StoryboardType { static var storyboard: UIStoryboard { let name = self.storyboardName - return UIStoryboard(name: name, bundle: Bundle(for: BundleToken.self)) + return UIStoryboard(name: name, bundle: BundleToken.bundle) } } @@ -93,4 +93,10 @@ internal struct InitialSceneType { } } -private final class BundleToken {} +// swiftlint:disable convenience_type +private final class BundleToken { + static let bundle: Bundle = { + Bundle(for: BundleToken.self) + }() +} +// swiftlint:enable convenience_type diff --git a/Passepartout-iOS/Global/SwiftGen+Segues.swift b/Passepartout-iOS/Global/SwiftGen+Segues.swift index f782a266..44b91b58 100644 --- a/Passepartout-iOS/Global/SwiftGen+Segues.swift +++ b/Passepartout-iOS/Global/SwiftGen+Segues.swift @@ -57,4 +57,10 @@ internal extension SegueType where RawValue == String { } } -private final class BundleToken {} +// swiftlint:disable convenience_type +private final class BundleToken { + static let bundle: Bundle = { + Bundle(for: BundleToken.self) + }() +} +// swiftlint:enable convenience_type diff --git a/Passepartout-iOS/Global/SwiftGen+Strings.swift b/Passepartout-iOS/Global/SwiftGen+Strings.swift index d57b48ce..2e8e82a6 100644 --- a/Passepartout-iOS/Global/SwiftGen+Strings.swift +++ b/Passepartout-iOS/Global/SwiftGen+Strings.swift @@ -3,8 +3,7 @@ import Foundation -// swiftlint:disable superfluous_disable_command -// swiftlint:disable file_length +// swiftlint:disable superfluous_disable_command file_length implicit_return // MARK: - Strings @@ -98,8 +97,8 @@ internal enum L10n { internal enum Cells { internal enum FullVersion { /// - All providers (including future ones)\n%@ - internal static func extraDescription(_ p1: String) -> String { - return L10n.tr("App", "purchase.cells.full_version.extra_description", p1) + internal static func extraDescription(_ p1: Any) -> String { + return L10n.tr("App", "purchase.cells.full_version.extra_description", String(describing: p1)) } } internal enum Restore { @@ -264,8 +263,8 @@ internal enum L10n { } internal enum Signup { /// Register with %@ - internal static func caption(_ p1: String) -> String { - return L10n.tr("Core", "account.cells.signup.caption", p1) + internal static func caption(_ p1: Any) -> String { + return L10n.tr("Core", "account.cells.signup.caption", String(describing: p1)) } } internal enum Username { @@ -280,48 +279,48 @@ internal enum L10n { internal enum Footer { internal enum Infrastructure { /// Use your %@ website credentials. - internal static func hideme(_ p1: String) -> String { - return L10n.tr("Core", "account.sections.guidance.footer.infrastructure.hideme", p1) + internal static func hideme(_ p1: Any) -> String { + return L10n.tr("Core", "account.sections.guidance.footer.infrastructure.hideme", String(describing: p1)) } /// Use your %@ website credentials. Your username is usually numeric (without spaces). - internal static func mullvad(_ p1: String) -> String { - return L10n.tr("Core", "account.sections.guidance.footer.infrastructure.mullvad", p1) + internal static func mullvad(_ p1: Any) -> String { + return L10n.tr("Core", "account.sections.guidance.footer.infrastructure.mullvad", String(describing: p1)) } /// Use your %@ website credentials. Your username is usually your e-mail. - internal static func nordvpn(_ p1: String) -> String { - return L10n.tr("Core", "account.sections.guidance.footer.infrastructure.nordvpn", p1) + internal static func nordvpn(_ p1: Any) -> String { + return L10n.tr("Core", "account.sections.guidance.footer.infrastructure.nordvpn", String(describing: p1)) } /// Use your %@ website credentials. Your username is usually numeric with a "p" prefix. - internal static func pia(_ p1: String) -> String { - return L10n.tr("Core", "account.sections.guidance.footer.infrastructure.pia", p1) + internal static func pia(_ p1: Any) -> String { + return L10n.tr("Core", "account.sections.guidance.footer.infrastructure.pia", String(describing: p1)) } /// Find your %@ credentials in the "Account > OpenVPN / IKEv2 Username" section of the website. - internal static func protonvpn(_ p1: String) -> String { - return L10n.tr("Core", "account.sections.guidance.footer.infrastructure.protonvpn", p1) + internal static func protonvpn(_ p1: Any) -> String { + return L10n.tr("Core", "account.sections.guidance.footer.infrastructure.protonvpn", String(describing: p1)) } /// Use your %@ service credentials, which may differ from website credentials. - internal static func torguard(_ p1: String) -> String { - return L10n.tr("Core", "account.sections.guidance.footer.infrastructure.torguard", p1) + internal static func torguard(_ p1: Any) -> String { + return L10n.tr("Core", "account.sections.guidance.footer.infrastructure.torguard", String(describing: p1)) } /// Use your %@ website credentials. Your username is usually your e-mail. - internal static func tunnelbear(_ p1: String) -> String { - return L10n.tr("Core", "account.sections.guidance.footer.infrastructure.tunnelbear", p1) + internal static func tunnelbear(_ p1: Any) -> String { + return L10n.tr("Core", "account.sections.guidance.footer.infrastructure.tunnelbear", String(describing: p1)) } /// Use your %@ website credentials. Your username is usually your e-mail. - internal static func vyprvpn(_ p1: String) -> String { - return L10n.tr("Core", "account.sections.guidance.footer.infrastructure.vyprvpn", p1) + internal static func vyprvpn(_ p1: Any) -> String { + return L10n.tr("Core", "account.sections.guidance.footer.infrastructure.vyprvpn", String(describing: p1)) } /// Find your %@ credentials in the OpenVPN Config Generator on the website. - internal static func windscribe(_ p1: String) -> String { - return L10n.tr("Core", "account.sections.guidance.footer.infrastructure.windscribe", p1) + internal static func windscribe(_ p1: Any) -> String { + return L10n.tr("Core", "account.sections.guidance.footer.infrastructure.windscribe", String(describing: p1)) } } } } internal enum Registration { /// Go get an account on the %@ website. - internal static func footer(_ p1: String) -> String { - return L10n.tr("Core", "account.sections.registration.footer", p1) + internal static func footer(_ p1: Any) -> String { + return L10n.tr("Core", "account.sections.registration.footer", String(describing: p1)) } } } @@ -393,8 +392,8 @@ internal enum L10n { internal static let caption = L10n.tr("Core", "configuration.cells.renegotiation_seconds.caption") internal enum Value { /// after %@ - internal static func after(_ p1: String) -> String { - return L10n.tr("Core", "configuration.cells.renegotiation_seconds.value.after", p1) + internal static func after(_ p1: Any) -> String { + return L10n.tr("Core", "configuration.cells.renegotiation_seconds.value.after", String(describing: p1)) } } } @@ -479,8 +478,8 @@ internal enum L10n { internal enum Purchase { internal enum Failure { /// Unable to perform the donation. %@ - internal static func message(_ p1: String) -> String { - return L10n.tr("Core", "donation.alerts.purchase.failure.message", p1) + internal static func message(_ p1: Any) -> String { + return L10n.tr("Core", "donation.alerts.purchase.failure.message", String(describing: p1)) } } internal enum Success { @@ -628,8 +627,8 @@ internal enum L10n { internal enum Cells { internal enum About { /// About %@ - internal static func caption(_ p1: String) -> String { - return L10n.tr("Core", "organizer.cells.about.caption", p1) + internal static func caption(_ p1: Any) -> String { + return L10n.tr("Core", "organizer.cells.about.caption", String(describing: p1)) } } internal enum Donate { @@ -712,32 +711,32 @@ internal enum L10n { } internal enum Malformed { /// The configuration file contains a malformed option (%@). - internal static func message(_ p1: String) -> String { - return L10n.tr("Core", "parsed_file.alerts.malformed.message", p1) + internal static func message(_ p1: Any) -> String { + return L10n.tr("Core", "parsed_file.alerts.malformed.message", String(describing: p1)) } } internal enum Missing { /// The configuration file lacks a required option (%@). - internal static func message(_ p1: String) -> String { - return L10n.tr("Core", "parsed_file.alerts.missing.message", p1) + internal static func message(_ p1: Any) -> String { + return L10n.tr("Core", "parsed_file.alerts.missing.message", String(describing: p1)) } } internal enum Parsing { /// Unable to parse the provided configuration file (%@). - internal static func message(_ p1: String) -> String { - return L10n.tr("Core", "parsed_file.alerts.parsing.message", p1) + internal static func message(_ p1: Any) -> String { + return L10n.tr("Core", "parsed_file.alerts.parsing.message", String(describing: p1)) } } internal enum PotentiallyUnsupported { /// The configuration file is correct but contains a potentially unsupported option (%@).\n\nConnectivity may break depending on server settings. - internal static func message(_ p1: String) -> String { - return L10n.tr("Core", "parsed_file.alerts.potentially_unsupported.message", p1) + internal static func message(_ p1: Any) -> String { + return L10n.tr("Core", "parsed_file.alerts.potentially_unsupported.message", String(describing: p1)) } } internal enum Unsupported { /// The configuration file contains an unsupported option (%@). - internal static func message(_ p1: String) -> String { - return L10n.tr("Core", "parsed_file.alerts.unsupported.message", p1) + internal static func message(_ p1: Any) -> String { + return L10n.tr("Core", "parsed_file.alerts.unsupported.message", String(describing: p1)) } } } @@ -780,12 +779,12 @@ internal enum L10n { } internal enum Download { /// Failed to download configuration files. %@ - internal static func failed(_ p1: String) -> String { - return L10n.tr("Core", "service.alerts.download.failed", p1) + internal static func failed(_ p1: Any) -> String { + return L10n.tr("Core", "service.alerts.download.failed", String(describing: p1)) } /// %@ requires the download of additional configuration files.\n\nConfirm to start the download. - internal static func message(_ p1: String) -> String { - return L10n.tr("Core", "service.alerts.download.message", p1) + internal static func message(_ p1: Any) -> String { + return L10n.tr("Core", "service.alerts.download.message", String(describing: p1)) } /// Download required internal static let title = L10n.tr("Core", "service.alerts.download.title") @@ -908,8 +907,8 @@ internal enum L10n { } internal enum ProviderInfrastructure { /// Last updated on %@. - internal static func footer(_ p1: String) -> String { - return L10n.tr("Core", "service.sections.provider_infrastructure.footer", p1) + internal static func footer(_ p1: Any) -> String { + return L10n.tr("Core", "service.sections.provider_infrastructure.footer", String(describing: p1)) } } internal enum Trusted { @@ -1081,10 +1080,15 @@ internal enum L10n { extension L10n { private static func tr(_ table: String, _ key: String, _ args: CVarArg...) -> String { - // swiftlint:disable:next nslocalizedstring_key - let format = NSLocalizedString(key, tableName: table, bundle: Bundle(for: BundleToken.self), comment: "") + let format = BundleToken.bundle.localizedString(forKey: key, value: nil, table: table) return String(format: format, locale: Locale.current, arguments: args) } } -private final class BundleToken {} +// swiftlint:disable convenience_type +private final class BundleToken { + static let bundle: Bundle = { + Bundle(for: BundleToken.self) + }() +} +// swiftlint:enable convenience_type diff --git a/Passepartout-iOS/Global/Theme.swift b/Passepartout-iOS/Global/Theme.swift index 01a4d2fe..858e02e7 100644 --- a/Passepartout-iOS/Global/Theme.swift +++ b/Passepartout-iOS/Global/Theme.swift @@ -194,7 +194,7 @@ extension MFMailComposeViewController { extension Infrastructure.Metadata { var logo: UIImage? { let bundle = Bundle(for: AppDelegate.self) - guard let image = AssetImageTypeAlias(named: name, in: bundle, compatibleWith: nil) else { + guard let image = ImageAsset.Image(named: name, in: bundle, compatibleWith: nil) else { return Asset.Providers.placeholder.image } return image diff --git a/Passepartout-iOS/Providers.xcassets/csv.imageset/Contents.json b/Passepartout-iOS/Providers.xcassets/csv.imageset/Contents.json new file mode 100644 index 00000000..68bb32b9 --- /dev/null +++ b/Passepartout-iOS/Providers.xcassets/csv.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "csv@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "csv@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Passepartout-iOS/Providers.xcassets/csv.imageset/csv@2x.png b/Passepartout-iOS/Providers.xcassets/csv.imageset/csv@2x.png new file mode 100644 index 00000000..1c79287b Binary files /dev/null and b/Passepartout-iOS/Providers.xcassets/csv.imageset/csv@2x.png differ diff --git a/Passepartout-iOS/Providers.xcassets/csv.imageset/csv@3x.png b/Passepartout-iOS/Providers.xcassets/csv.imageset/csv@3x.png new file mode 100644 index 00000000..d92972fa Binary files /dev/null and b/Passepartout-iOS/Providers.xcassets/csv.imageset/csv@3x.png differ diff --git a/README.md b/README.md index 5c366e72..6d8c949b 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ Passepartout is a VPN client and does absolutely nothing else without your conse Passepartout can connect to a few well-known VPN providers with an existing account: +- [Child Safe VPN][app-net-csv] - [Hide.me][app-net-hideme] - [Mullvad][app-net-mullvad] - [NordVPN][app-net-nordvpn] @@ -177,6 +178,7 @@ Website: [passepartoutvpn.app][about-website] [openvpn]: https://openvpn.net/index.php/open-source/overview.html [app-api]: https://github.com/passepartoutvpn/passepartout-api +[app-net-csv]: https://childsafevpn.com [app-net-hideme]: https://member.hide.me/en/checkout?plan=new_default_prices&coupon=6CB-BDB-802&duration=24 [app-net-mullvad]: https://mullvad.net/en/account/create/ [app-net-nordvpn]: https://go.nordvpn.net/SH21Z diff --git a/Submodules/API b/Submodules/API index 52d86ee5..ccc00bf1 160000 --- a/Submodules/API +++ b/Submodules/API @@ -1 +1 @@ -Subproject commit 52d86ee536c84d9f440fa6a2914c54cea4563c73 +Subproject commit ccc00bf1f0f2b497cc68b18be92cc521a78dfb52