From 7c6a404e4aa2e7925e8e036d24458cbf33c16ca1 Mon Sep 17 00:00:00 2001 From: Davide De Rosa Date: Tue, 7 Jul 2020 23:34:42 +0200 Subject: [PATCH] Add Child Safe VPN provider --- .gitignore | 1 + CHANGELOG.md | 4 + Passepartout-iOS/Global/SwiftGen+Assets.swift | 107 ++++++------------ Passepartout-iOS/Global/SwiftGen+Scenes.swift | 10 +- Passepartout-iOS/Global/SwiftGen+Segues.swift | 8 +- .../Global/SwiftGen+Strings.swift | 106 ++++++++--------- Passepartout-iOS/Global/Theme.swift | 2 +- .../csv.imageset/Contents.json | 22 ++++ .../csv.imageset/csv@2x.png | Bin 0 -> 3435 bytes .../csv.imageset/csv@3x.png | Bin 0 -> 5407 bytes README.md | 2 + Submodules/API | 2 +- 12 files changed, 138 insertions(+), 126 deletions(-) create mode 100644 Passepartout-iOS/Providers.xcassets/csv.imageset/Contents.json create mode 100644 Passepartout-iOS/Providers.xcassets/csv.imageset/csv@2x.png create mode 100644 Passepartout-iOS/Providers.xcassets/csv.imageset/csv@3x.png 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 0000000000000000000000000000000000000000..1c79287bd13300eb97ba9a1e90c6cf8cca02c16e GIT binary patch literal 3435 zcmV-x4V3bUP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00006 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