Compare commits
10 Commits
testing
...
feature/ios
| Author | SHA1 | Date | |
|---|---|---|---|
| f194fb9cca | |||
| 36a4f93127 | |||
| aae5adef38 | |||
| 51754f737c | |||
| 85ccd835ab | |||
| 8e302bfdde | |||
| b609331b8e | |||
| 59845174e7 | |||
| 0bdb6a626d | |||
| 7f0256cc33 |
@@ -0,0 +1,8 @@
|
||||
.DS_Store
|
||||
/.build
|
||||
/Packages
|
||||
/*.xcodeproj
|
||||
xcuserdata/
|
||||
DerivedData/
|
||||
.swiftpm
|
||||
NymVPM.xcworkspace/
|
||||
@@ -0,0 +1,149 @@
|
||||
# List of rules with definitions
|
||||
# https://github.com/realm/SwiftLint/blob/master/Rules.md
|
||||
|
||||
disabled_rules:
|
||||
- todo
|
||||
|
||||
opt_in_rules:
|
||||
- anyobject_protocol
|
||||
- attributes
|
||||
- balanced_xctest_lifecycle
|
||||
- capture_variable
|
||||
- closure_body_length
|
||||
- closure_end_indentation
|
||||
- closure_parameter_position
|
||||
- closure_spacing
|
||||
- collection_alignment
|
||||
- colon
|
||||
- conditional_returns_on_newline
|
||||
- contains_over_filter_count
|
||||
- contains_over_filter_is_empty
|
||||
- contains_over_first_not_nil
|
||||
- contains_over_range_nil_comparison
|
||||
- discouraged_none_name
|
||||
- discouraged_object_literal
|
||||
- empty_collection_literal
|
||||
- empty_count
|
||||
- empty_string
|
||||
- empty_xctest_method
|
||||
- enum_case_associated_values_count
|
||||
- expiring_todo
|
||||
- explicit_init
|
||||
- fallthrough
|
||||
- fatal_error_message
|
||||
- file_header
|
||||
- file_name
|
||||
- file_name_no_space
|
||||
- first_where
|
||||
- flatmap_over_map_reduce
|
||||
- force_cast
|
||||
- force_try
|
||||
- force_unwrapping
|
||||
- function_default_parameter_at_end
|
||||
- identical_operands
|
||||
- implicit_return
|
||||
- indentation_width
|
||||
- joined_default_parameter
|
||||
- last_where
|
||||
- legacy_random
|
||||
- line_length
|
||||
- literal_expression_end_indentation
|
||||
- lower_acl_than_parent
|
||||
- multiline_arguments
|
||||
- multiline_arguments_brackets
|
||||
- multiline_function_chains
|
||||
- multiline_literal_brackets
|
||||
- multiline_parameters
|
||||
- multiline_parameters_brackets
|
||||
- operator_usage_whitespace
|
||||
- overridden_super_call
|
||||
- pattern_matching_keywords
|
||||
- prefer_self_type_over_type_of_self
|
||||
- prefer_zero_over_explicit_init
|
||||
- private_action
|
||||
- private_outlet
|
||||
- prohibited_interface_builder
|
||||
- prohibited_super_call
|
||||
- redundant_nil_coalescing
|
||||
- redundant_type_annotation
|
||||
- sorted_first_last
|
||||
- switch_case_on_newline
|
||||
- test_case_accessibility
|
||||
- toggle_bool
|
||||
- trailing_closure
|
||||
- unavailable_function
|
||||
- unneeded_parentheses_in_closure_argument
|
||||
- unused_declaration
|
||||
- unused_import
|
||||
- vertical_parameter_alignment_on_call
|
||||
- vertical_whitespace_closing_braces
|
||||
- weak_delegate
|
||||
- xct_specific_matcher
|
||||
- yoda_condition
|
||||
|
||||
attributes:
|
||||
always_on_same_line:
|
||||
- "@IBSegueAction"
|
||||
- "@IBAction"
|
||||
- "@NSManaged"
|
||||
- "@objc"
|
||||
- "@MainActor"
|
||||
- "@discardableResult"
|
||||
|
||||
conditional_returns_on_newline:
|
||||
if_only: true
|
||||
|
||||
cyclomatic_complexity:
|
||||
ignores_case_statements: true
|
||||
|
||||
enum_case_associated_values_count:
|
||||
warning: 4
|
||||
error: 6
|
||||
|
||||
function_parameter_count:
|
||||
warning: 6
|
||||
error: 8
|
||||
|
||||
identifier_name:
|
||||
min_length: 2
|
||||
max_length: 60
|
||||
|
||||
indentation_width:
|
||||
indentation_width: 4
|
||||
|
||||
legacy_hashing: error
|
||||
|
||||
line_length:
|
||||
ignores_urls: true
|
||||
ignores_comments: true
|
||||
ignores_function_declarations: false
|
||||
ignores_interpolated_strings: true
|
||||
warning: 120
|
||||
error: 240
|
||||
|
||||
multiline_parameters:
|
||||
allowsSingleLine: false
|
||||
|
||||
nesting:
|
||||
type_level: 3
|
||||
|
||||
private_outlet:
|
||||
allow_private_set: true
|
||||
|
||||
trailing_closure:
|
||||
only_single_muted_parameter: true
|
||||
|
||||
trailing_whitespace:
|
||||
ignores_comments: true
|
||||
|
||||
type_body_length:
|
||||
warning: 400
|
||||
error: 500
|
||||
|
||||
type_name:
|
||||
min_length: 2
|
||||
max_length: 60
|
||||
|
||||
warning_threshold: 15
|
||||
|
||||
reporter: "xcode"
|
||||
@@ -0,0 +1,8 @@
|
||||
.DS_Store
|
||||
/.build
|
||||
/Packages
|
||||
xcuserdata/
|
||||
DerivedData/
|
||||
.swiftpm/configuration/registries.json
|
||||
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
|
||||
.netrc
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,36 @@
|
||||
// swift-tools-version: 5.9
|
||||
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "Home",
|
||||
defaultLocalization: "en",
|
||||
platforms: [
|
||||
.iOS(.v16)
|
||||
],
|
||||
products: [
|
||||
.library(
|
||||
name: "Home",
|
||||
targets: ["Home"]
|
||||
)
|
||||
],
|
||||
dependencies: [
|
||||
.package(path: "../UIComponents"),
|
||||
.package(path: "../Settings")
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
name: "Home",
|
||||
dependencies: [
|
||||
"UIComponents",
|
||||
"Settings"
|
||||
],
|
||||
path: "Sources"
|
||||
),
|
||||
.testTarget(
|
||||
name: "HomeTests",
|
||||
dependencies: ["Home"]
|
||||
)
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,29 @@
|
||||
import SwiftUI
|
||||
import Settings
|
||||
|
||||
struct HomeFlowCoordinator<Content: View>: View {
|
||||
@ObservedObject var state: HomeFlowState
|
||||
let content: () -> Content
|
||||
|
||||
var body: some View {
|
||||
NavigationStack(path: $state.path) {
|
||||
ZStack {
|
||||
content()
|
||||
}
|
||||
.navigationDestination(for: HomeLink.self, destination: linkDestination)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension HomeFlowCoordinator {
|
||||
@ViewBuilder private func linkDestination(link: HomeLink) -> some View {
|
||||
switch link {
|
||||
case .firstHop(text: _):
|
||||
HopListView(viewModel: HopListViewModel(path: $state.path, type: .first))
|
||||
case .lastHop:
|
||||
HopListView(viewModel: HopListViewModel(path: $state.path, type: .last))
|
||||
case .settings:
|
||||
SettingsView(viewModel: SettingsViewModel(path: $state.path))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import SwiftUI
|
||||
|
||||
public class HomeFlowState: ObservableObject {
|
||||
@Published var path = NavigationPath()
|
||||
@Published var presentedItem: HomeLink?
|
||||
@Published var coverItem: HomeLink?
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import Foundation
|
||||
|
||||
enum HomeLink: Hashable, Identifiable {
|
||||
case firstHop(text: String?)
|
||||
case lastHop
|
||||
case settings
|
||||
|
||||
var id: String {
|
||||
String(describing: self)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
import SwiftUI
|
||||
import AppSettings
|
||||
import Modifiers
|
||||
import Theme
|
||||
import UIComponents
|
||||
|
||||
public struct HomeView: View {
|
||||
@ObservedObject private var viewModel: HomeViewModel
|
||||
|
||||
public init(viewModel: HomeViewModel) {
|
||||
self.viewModel = viewModel
|
||||
}
|
||||
|
||||
public var body: some View {
|
||||
HomeFlowCoordinator(state: viewModel, content: content)
|
||||
}
|
||||
}
|
||||
|
||||
private extension HomeView {
|
||||
@ViewBuilder
|
||||
func content() -> some View {
|
||||
VStack {
|
||||
navbar()
|
||||
Spacer()
|
||||
statusAreaSection()
|
||||
Spacer()
|
||||
networkSection()
|
||||
connectionSection()
|
||||
connectButton()
|
||||
}
|
||||
.appearanceUpdate()
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.background {
|
||||
NymColor.background
|
||||
.ignoresSafeArea()
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func navbar() -> some View {
|
||||
CustomNavBar(
|
||||
title: "NymVPN".localizedString,
|
||||
rightButton: CustomNavBarButton(type: .settings, action: { viewModel.navigateToSettings() })
|
||||
)
|
||||
Spacer()
|
||||
.frame(height: 50)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func statusAreaSection() -> some View {
|
||||
StatusButton(config: .disconnected)
|
||||
Spacer()
|
||||
.frame(height: 8)
|
||||
|
||||
StatusInfoView()
|
||||
Spacer()
|
||||
.frame(height: 24)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func networkSection() -> some View {
|
||||
HStack {
|
||||
Text("selectNetwork".localizedString)
|
||||
.textStyle(.Title.Medium.primary)
|
||||
Spacer()
|
||||
}
|
||||
.padding(.horizontal, 16)
|
||||
Spacer()
|
||||
.frame(height: 24)
|
||||
|
||||
NetworkButton(viewModel: NetworkButtonViewModel(type: .mixnet, selectedNetwork: $viewModel.selectedNetwork))
|
||||
.padding(EdgeInsets(top: 0, leading: 16, bottom: 16, trailing: 16))
|
||||
.onTapGesture {
|
||||
viewModel.selectedNetwork = .mixnet
|
||||
}
|
||||
|
||||
NetworkButton(viewModel: NetworkButtonViewModel(type: .wireguard, selectedNetwork: $viewModel.selectedNetwork))
|
||||
.padding(.horizontal, 16)
|
||||
.onTapGesture {
|
||||
viewModel.selectedNetwork = .wireguard
|
||||
}
|
||||
Spacer()
|
||||
.frame(height: 32)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func connectionSection() -> some View {
|
||||
HStack {
|
||||
Text("connectTo".localizedString)
|
||||
.foregroundStyle(NymColor.sysOnSurfaceWhite)
|
||||
.textStyle(.Title.Medium.primary)
|
||||
Spacer()
|
||||
}
|
||||
.padding(.horizontal, 16)
|
||||
|
||||
Spacer()
|
||||
.frame(height: 24)
|
||||
|
||||
VStack {
|
||||
HopButton(hopType: .first, country: Country(name: "Germany", code: "de"))
|
||||
.onTapGesture {
|
||||
viewModel.navigateToFirstHopSelection()
|
||||
}
|
||||
Spacer()
|
||||
.frame(height: 24)
|
||||
HopButton(hopType: .last, country: Country(name: "Switzerland", code: "ch"))
|
||||
.onTapGesture {
|
||||
viewModel.navigateToLastHopSelection()
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, 16)
|
||||
|
||||
Spacer()
|
||||
.frame(height: 32)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func connectButton() -> some View {
|
||||
ConnectButton()
|
||||
.padding(.horizontal, 16)
|
||||
.onTapGesture {
|
||||
viewModel.connect()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import SwiftUI
|
||||
import UIComponents
|
||||
import Tunnels
|
||||
|
||||
public class HomeViewModel: HomeFlowState {
|
||||
private let tunnelsManager: TunnelsManager
|
||||
|
||||
@Published var selectedNetwork: NetworkButtonViewModel.ButtonType
|
||||
|
||||
public init(
|
||||
selectedNetwork: NetworkButtonViewModel.ButtonType,
|
||||
tunnelsManager: TunnelsManager = TunnelsManager.shared
|
||||
) {
|
||||
self.selectedNetwork = selectedNetwork
|
||||
self.tunnelsManager = tunnelsManager
|
||||
|
||||
tunnelsManager.loadConfigurations()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Navigation -
|
||||
|
||||
public extension HomeViewModel {
|
||||
func navigateToSettings() {
|
||||
path.append(HomeLink.settings)
|
||||
}
|
||||
|
||||
func navigateToFirstHopSelection() {
|
||||
path.append(HomeLink.firstHop(text: ""))
|
||||
}
|
||||
|
||||
func navigateToLastHopSelection() {
|
||||
path.append(HomeLink.lastHop)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Tunnel testing -
|
||||
|
||||
public extension HomeViewModel {
|
||||
func connect() {
|
||||
if let tunnel = tunnelsManager.currentTunnel, tunnel.tunnel.connection.status == .connected {
|
||||
tunnelsManager.disconnect()
|
||||
} else {
|
||||
tunnelsManager.test()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
import SwiftUI
|
||||
import Theme
|
||||
import UIComponents
|
||||
|
||||
public struct HopListView: View {
|
||||
private let viewModel: HopListViewModel
|
||||
|
||||
public init(viewModel: HopListViewModel) {
|
||||
self.viewModel = viewModel
|
||||
}
|
||||
|
||||
public var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
navbar()
|
||||
Spacer()
|
||||
.frame(height: 24)
|
||||
|
||||
countryButton()
|
||||
Spacer()
|
||||
.frame(height: 24)
|
||||
|
||||
countryButton2()
|
||||
Spacer()
|
||||
.frame(height: 24)
|
||||
|
||||
searchView()
|
||||
Spacer()
|
||||
.frame(height: 24)
|
||||
|
||||
availableCountryList()
|
||||
}
|
||||
.navigationBarBackButtonHidden(true)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.background {
|
||||
NymColor.background
|
||||
.ignoresSafeArea()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension HopListView {
|
||||
@ViewBuilder
|
||||
func navbar() -> some View {
|
||||
CustomNavBar(
|
||||
title: viewModel.type.selectHopLocalizedTitle,
|
||||
leftButton: CustomNavBarButton(type: .back, action: { viewModel.navigateHome() })
|
||||
)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func countryButton() -> some View {
|
||||
CountryCellButton(
|
||||
viewModel: CountryCellButtonViewModel(
|
||||
type: .fastest(
|
||||
country: Country(name: "Germany", code: "de")
|
||||
),
|
||||
isSelected: false
|
||||
)
|
||||
)
|
||||
.padding(.horizontal, 15)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func countryButton2() -> some View {
|
||||
CountryCellButton(
|
||||
viewModel: CountryCellButtonViewModel(
|
||||
type: .country(
|
||||
country: Country(name: "Germany", code: "de")
|
||||
),
|
||||
isSelected: true
|
||||
)
|
||||
)
|
||||
.padding(.horizontal, 15)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func searchView() -> some View {
|
||||
SearchView(viewModel: SearchViewModel())
|
||||
.padding(.horizontal, 40)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func availableCountryList() -> some View {
|
||||
ScrollView {
|
||||
switzerland()
|
||||
germany()
|
||||
switzerland()
|
||||
germany()
|
||||
switzerland()
|
||||
germany()
|
||||
switzerland()
|
||||
germany()
|
||||
switzerland()
|
||||
germany()
|
||||
switzerland()
|
||||
germany()
|
||||
switzerland()
|
||||
germany()
|
||||
switzerland()
|
||||
germany()
|
||||
switzerland()
|
||||
germany()
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.ignoresSafeArea(.all)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func germany() -> some View {
|
||||
CountryCellButton(
|
||||
viewModel: CountryCellButtonViewModel(
|
||||
type: .country(
|
||||
country: Country(name: "Germany", code: "de")
|
||||
),
|
||||
isSelected: false
|
||||
)
|
||||
)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.ignoresSafeArea(.all)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func switzerland() -> some View {
|
||||
CountryCellButton(
|
||||
viewModel: CountryCellButtonViewModel(
|
||||
type: .country(
|
||||
country: Country(name: "Switzerland", code: "ch")
|
||||
),
|
||||
isSelected: false
|
||||
)
|
||||
)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.ignoresSafeArea(.all)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import SwiftUI
|
||||
|
||||
public struct HopListViewModel {
|
||||
public let type: HopType
|
||||
|
||||
@Binding var path: NavigationPath
|
||||
|
||||
public init(path: Binding<NavigationPath>, type: HopType) {
|
||||
self.type = type
|
||||
_path = path
|
||||
}
|
||||
}
|
||||
|
||||
extension HopListViewModel {
|
||||
func navigateHome() {
|
||||
path = .init()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import Foundation
|
||||
|
||||
public enum HopType {
|
||||
case first
|
||||
case last
|
||||
|
||||
var selectHopLocalizedTitle: String {
|
||||
switch self {
|
||||
case .first:
|
||||
"firstHopSelection".localizedString
|
||||
case .last:
|
||||
"lastHopSelection".localizedString
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import XCTest
|
||||
@testable import Home
|
||||
|
||||
final class HomeTests: XCTestCase {}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
<string>com.apple.networkextension.packet-tunnel</string>
|
||||
<key>NSExtensionPrincipalClass</key>
|
||||
<string>$(PRODUCT_MODULE_NAME).PacketTunnelProvider</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.developer.networking.networkextension</key>
|
||||
<array>
|
||||
<string>packet-tunnel-provider</string>
|
||||
</array>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.net.nymtech.vpn</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,45 @@
|
||||
import NetworkExtension
|
||||
import OSLog
|
||||
|
||||
class PacketTunnelProvider: NEPacketTunnelProvider {
|
||||
override func startTunnel(options: [String: NSObject]?, completionHandler: @escaping (Error?) -> Void) {
|
||||
NSLog("🏁 Starting tunnel with options: \(options ?? [:])")
|
||||
os_log("🏁 Starting tunnel with options: \(options ?? [:])")
|
||||
|
||||
fetchData()
|
||||
completionHandler(nil)
|
||||
}
|
||||
|
||||
func fetchData() {
|
||||
// Do not use the NSTimer here that will not run in background
|
||||
let popTime = DispatchTime.now() + DispatchTimeInterval.seconds(Int(1))
|
||||
DispatchQueue.global(qos: .background).asyncAfter(deadline: popTime) { [weak self] in
|
||||
// Fetch your data from server and generate local notification by using UserNotifications framework
|
||||
self?.doSomeStuff()
|
||||
self?.fetchData()
|
||||
}
|
||||
}
|
||||
|
||||
@objc func doSomeStuff() {
|
||||
NSLog("🔥 ROKAS TIMER TIC TAK")
|
||||
os_log("🔥 ROKAS TIMER TIC TAK")
|
||||
}
|
||||
|
||||
override func stopTunnel(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
|
||||
NSLog("🛑 Rokas stopping tunnel")
|
||||
completionHandler()
|
||||
}
|
||||
|
||||
override func handleAppMessage(_ messageData: Data, completionHandler: ((Data?) -> Void)?) {
|
||||
|
||||
if let handler = completionHandler {
|
||||
handler(messageData)
|
||||
}
|
||||
}
|
||||
|
||||
override func sleep(completionHandler: @escaping () -> Void) {
|
||||
completionHandler()
|
||||
}
|
||||
|
||||
override func wake() {}
|
||||
}
|
||||
@@ -0,0 +1,622 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 56;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
D9264E262B3DA062004594A8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D9264E252B3DA062004594A8 /* Assets.xcassets */; };
|
||||
D954C0B92B51C1CA00C6BAAC /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D954C0A62B51C17200C6BAAC /* NetworkExtension.framework */; };
|
||||
D954C0BC2B51C1CA00C6BAAC /* PacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = D954C0BB2B51C1CA00C6BAAC /* PacketTunnelProvider.swift */; };
|
||||
D954C0C12B51C1CA00C6BAAC /* NymMixnetTunnel.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = D954C0B82B51C1CA00C6BAAC /* NymMixnetTunnel.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
D96740232B56A67A001F6891 /* Tunnels in Frameworks */ = {isa = PBXBuildFile; productRef = D96740222B56A67A001F6891 /* Tunnels */; };
|
||||
D968BDC92B6AEA9D003F42E5 /* AppSettings in Frameworks */ = {isa = PBXBuildFile; productRef = D968BDC82B6AEA9D003F42E5 /* AppSettings */; };
|
||||
D968BDCB2B6BC98E003F42E5 /* AppVersionProvider in Frameworks */ = {isa = PBXBuildFile; productRef = D968BDCA2B6BC98E003F42E5 /* AppVersionProvider */; };
|
||||
D99A147A2B357E9900F2728B /* NymVPNApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = D99A14792B357E9900F2728B /* NymVPNApp.swift */; };
|
||||
D99A148A2B35A73F00F2728B /* Home in Frameworks */ = {isa = PBXBuildFile; productRef = D99A14892B35A73F00F2728B /* Home */; };
|
||||
D99A148C2B35A74200F2728B /* Theme in Frameworks */ = {isa = PBXBuildFile; productRef = D99A148B2B35A74200F2728B /* Theme */; };
|
||||
D9CD835D2B6C32D4008DA864 /* Modifiers in Frameworks */ = {isa = PBXBuildFile; productRef = D9CD835C2B6C32D4008DA864 /* Modifiers */; };
|
||||
D9F699E02B4C1862005576A9 /* Settings in Frameworks */ = {isa = PBXBuildFile; productRef = D9F699DF2B4C1862005576A9 /* Settings */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
D954C0BF2B51C1CA00C6BAAC /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = D99A146E2B357E9900F2728B /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = D954C0B72B51C1CA00C6BAAC;
|
||||
remoteInfo = NymMixnetTunnel;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
D954C0B32B51C17200C6BAAC /* Embed Foundation Extensions */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 13;
|
||||
files = (
|
||||
D954C0C12B51C1CA00C6BAAC /* NymMixnetTunnel.appex in Embed Foundation Extensions */,
|
||||
);
|
||||
name = "Embed Foundation Extensions";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
D9264E252B3DA062004594A8 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
D954C0A62B51C17200C6BAAC /* NetworkExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkExtension.framework; path = System/Library/Frameworks/NetworkExtension.framework; sourceTree = SDKROOT; };
|
||||
D954C0B82B51C1CA00C6BAAC /* NymMixnetTunnel.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NymMixnetTunnel.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D954C0BB2B51C1CA00C6BAAC /* PacketTunnelProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PacketTunnelProvider.swift; sourceTree = "<group>"; };
|
||||
D954C0BD2B51C1CA00C6BAAC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
D954C0BE2B51C1CA00C6BAAC /* NymMixnetTunnel.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NymMixnetTunnel.entitlements; sourceTree = "<group>"; };
|
||||
D99A14762B357E9900F2728B /* NymVPN.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = NymVPN.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D99A14792B357E9900F2728B /* NymVPNApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NymVPNApp.swift; sourceTree = "<group>"; };
|
||||
D9F699E32B4C47DE005576A9 /* Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
D9F699E62B4C89F1005576A9 /* NymVPN.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NymVPN.entitlements; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
D954C0B52B51C1CA00C6BAAC /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D954C0B92B51C1CA00C6BAAC /* NetworkExtension.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D99A14732B357E9900F2728B /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D968BDCB2B6BC98E003F42E5 /* AppVersionProvider in Frameworks */,
|
||||
D96740232B56A67A001F6891 /* Tunnels in Frameworks */,
|
||||
D9F699E02B4C1862005576A9 /* Settings in Frameworks */,
|
||||
D968BDC92B6AEA9D003F42E5 /* AppSettings in Frameworks */,
|
||||
D99A148C2B35A74200F2728B /* Theme in Frameworks */,
|
||||
D99A148A2B35A73F00F2728B /* Home in Frameworks */,
|
||||
D9CD835D2B6C32D4008DA864 /* Modifiers in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
D954C0BA2B51C1CA00C6BAAC /* NymMixnetTunnel */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D954C0BB2B51C1CA00C6BAAC /* PacketTunnelProvider.swift */,
|
||||
D954C0BD2B51C1CA00C6BAAC /* Info.plist */,
|
||||
D954C0BE2B51C1CA00C6BAAC /* NymMixnetTunnel.entitlements */,
|
||||
);
|
||||
path = NymMixnetTunnel;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D967402C2B56CA1A001F6891 /* Resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D9F699E32B4C47DE005576A9 /* Bridging-Header.h */,
|
||||
);
|
||||
path = Resources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D99A146D2B357E9900F2728B = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D99A14782B357E9900F2728B /* NymVPN */,
|
||||
D954C0BA2B51C1CA00C6BAAC /* NymMixnetTunnel */,
|
||||
D99A14772B357E9900F2728B /* Products */,
|
||||
D99A14882B35A73F00F2728B /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D99A14772B357E9900F2728B /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D99A14762B357E9900F2728B /* NymVPN.app */,
|
||||
D954C0B82B51C1CA00C6BAAC /* NymMixnetTunnel.appex */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D99A14782B357E9900F2728B /* NymVPN */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D9F699E62B4C89F1005576A9 /* NymVPN.entitlements */,
|
||||
D99A14792B357E9900F2728B /* NymVPNApp.swift */,
|
||||
D9264E252B3DA062004594A8 /* Assets.xcassets */,
|
||||
D967402C2B56CA1A001F6891 /* Resources */,
|
||||
);
|
||||
path = NymVPN;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D99A14882B35A73F00F2728B /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D954C0A62B51C17200C6BAAC /* NetworkExtension.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
D954C0B72B51C1CA00C6BAAC /* NymMixnetTunnel */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = D954C0C22B51C1CA00C6BAAC /* Build configuration list for PBXNativeTarget "NymMixnetTunnel" */;
|
||||
buildPhases = (
|
||||
D954C0B42B51C1CA00C6BAAC /* Sources */,
|
||||
D954C0B52B51C1CA00C6BAAC /* Frameworks */,
|
||||
D954C0B62B51C1CA00C6BAAC /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = NymMixnetTunnel;
|
||||
productName = NymMixnetTunnel;
|
||||
productReference = D954C0B82B51C1CA00C6BAAC /* NymMixnetTunnel.appex */;
|
||||
productType = "com.apple.product-type.app-extension";
|
||||
};
|
||||
D99A14752B357E9900F2728B /* NymVPN */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = D99A14842B357E9A00F2728B /* Build configuration list for PBXNativeTarget "NymVPN" */;
|
||||
buildPhases = (
|
||||
D99A14722B357E9900F2728B /* Sources */,
|
||||
D99A14732B357E9900F2728B /* Frameworks */,
|
||||
D99A14742B357E9900F2728B /* Resources */,
|
||||
D99A14872B359C8800F2728B /* Run Swiftlint */,
|
||||
D954C0B32B51C17200C6BAAC /* Embed Foundation Extensions */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
D954C0C02B51C1CA00C6BAAC /* PBXTargetDependency */,
|
||||
);
|
||||
name = NymVPN;
|
||||
packageProductDependencies = (
|
||||
D99A14892B35A73F00F2728B /* Home */,
|
||||
D99A148B2B35A74200F2728B /* Theme */,
|
||||
D9F699DF2B4C1862005576A9 /* Settings */,
|
||||
D96740222B56A67A001F6891 /* Tunnels */,
|
||||
D968BDC82B6AEA9D003F42E5 /* AppSettings */,
|
||||
D968BDCA2B6BC98E003F42E5 /* AppVersionProvider */,
|
||||
D9CD835C2B6C32D4008DA864 /* Modifiers */,
|
||||
);
|
||||
productName = NymVPN;
|
||||
productReference = D99A14762B357E9900F2728B /* NymVPN.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
D99A146E2B357E9900F2728B /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = 1;
|
||||
LastSwiftUpdateCheck = 1520;
|
||||
LastUpgradeCheck = 1510;
|
||||
TargetAttributes = {
|
||||
D954C0B72B51C1CA00C6BAAC = {
|
||||
CreatedOnToolsVersion = 15.2;
|
||||
};
|
||||
D99A14752B357E9900F2728B = {
|
||||
CreatedOnToolsVersion = 15.1;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = D99A14712B357E9900F2728B /* Build configuration list for PBXProject "NymVPN" */;
|
||||
compatibilityVersion = "Xcode 14.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = D99A146D2B357E9900F2728B;
|
||||
productRefGroup = D99A14772B357E9900F2728B /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
D99A14752B357E9900F2728B /* NymVPN */,
|
||||
D954C0B72B51C1CA00C6BAAC /* NymMixnetTunnel */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
D954C0B62B51C1CA00C6BAAC /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D99A14742B357E9900F2728B /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D9264E262B3DA062004594A8 /* Assets.xcassets in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
D99A14872B359C8800F2728B /* Run Swiftlint */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Run Swiftlint";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "if [[ \"$(uname -m)\" == arm64 ]]; then\n export PATH=\"/opt/homebrew/bin:$PATH\"\nfi\n\nif which swiftlint > /dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
D954C0B42B51C1CA00C6BAAC /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D954C0BC2B51C1CA00C6BAAC /* PacketTunnelProvider.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D99A14722B357E9900F2728B /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D99A147A2B357E9900F2728B /* NymVPNApp.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
D954C0C02B51C1CA00C6BAAC /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = D954C0B72B51C1CA00C6BAAC /* NymMixnetTunnel */;
|
||||
targetProxy = D954C0BF2B51C1CA00C6BAAC /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
D954C0C32B51C1CA00C6BAAC /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = NymMixnetTunnel/NymMixnetTunnel.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = VW5DZLFHM5;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = NymMixnetTunnel/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = NymMixnetTunnel;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 17.2;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "net.nymtech.vpn.network-extension";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
D954C0C42B51C1CA00C6BAAC /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = NymMixnetTunnel/NymMixnetTunnel.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = VW5DZLFHM5;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = NymMixnetTunnel/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = NymMixnetTunnel;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 17.2;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "net.nymtech.vpn.network-extension";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
D99A14822B357E9A00F2728B /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
D99A14832B357E9A00F2728B /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
D99A14852B357E9A00F2728B /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_ENTITLEMENTS = NymVPN/NymVPN.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = VW5DZLFHM5;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = NymVPN;
|
||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = net.nymtech.vpn;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "$(PROJECT_DIR)/NymVPN/Resources/Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
D99A14862B357E9A00F2728B /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_ENTITLEMENTS = NymVPN/NymVPN.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = VW5DZLFHM5;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = NymVPN;
|
||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = net.nymtech.vpn;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "$(PROJECT_DIR)/NymVPN/Resources/Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
D954C0C22B51C1CA00C6BAAC /* Build configuration list for PBXNativeTarget "NymMixnetTunnel" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
D954C0C32B51C1CA00C6BAAC /* Debug */,
|
||||
D954C0C42B51C1CA00C6BAAC /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
D99A14712B357E9900F2728B /* Build configuration list for PBXProject "NymVPN" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
D99A14822B357E9A00F2728B /* Debug */,
|
||||
D99A14832B357E9A00F2728B /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
D99A14842B357E9A00F2728B /* Build configuration list for PBXNativeTarget "NymVPN" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
D99A14852B357E9A00F2728B /* Debug */,
|
||||
D99A14862B357E9A00F2728B /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
D96740222B56A67A001F6891 /* Tunnels */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = Tunnels;
|
||||
};
|
||||
D968BDC82B6AEA9D003F42E5 /* AppSettings */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = AppSettings;
|
||||
};
|
||||
D968BDCA2B6BC98E003F42E5 /* AppVersionProvider */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = AppVersionProvider;
|
||||
};
|
||||
D99A14892B35A73F00F2728B /* Home */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = Home;
|
||||
};
|
||||
D99A148B2B35A74200F2728B /* Theme */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = Theme;
|
||||
};
|
||||
D9CD835C2B6C32D4008DA864 /* Modifiers */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = Modifiers;
|
||||
};
|
||||
D9F699DF2B4C1862005576A9 /* Settings */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = Settings;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
};
|
||||
rootObject = D99A146E2B357E9900F2728B /* Project object */;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:NymVPN.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Home">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Services">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Settings">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Theme">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:UIComponents">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict/>
|
||||
</plist>
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Icon.png",
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ch.svg",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-ch" viewBox="0 0 512 512">
|
||||
<g fill-rule="evenodd" stroke-width="1pt">
|
||||
<path fill="red" d="M0 0h512v512H0z"/>
|
||||
<g fill="#fff">
|
||||
<path d="M96 208h320v96H96z"/>
|
||||
<path d="M208 96h96v320h-96z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 288 B |
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "de.svg",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"preserves-vector-representation" : true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-de" viewBox="0 0 512 512">
|
||||
<path fill="#ffce00" d="M0 341.3h512V512H0z"/>
|
||||
<path fill="#000001" d="M0 0h512v170.7H0z"/>
|
||||
<path fill="red" d="M0 170.7h512v170.6H0z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 232 B |
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.developer.networking.networkextension</key>
|
||||
<array>
|
||||
<string>packet-tunnel-provider</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,29 @@
|
||||
import SwiftUI
|
||||
import Home
|
||||
import Theme
|
||||
import AppSettings
|
||||
import Tunnels
|
||||
|
||||
@main
|
||||
struct NymVPNApp: App {
|
||||
|
||||
init() {
|
||||
setup()
|
||||
}
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
NavigationStack {
|
||||
HomeView(viewModel: HomeViewModel(selectedNetwork: .mixnet))
|
||||
}
|
||||
.environmentObject(AppSettings.shared)
|
||||
.environmentObject(TunnelsManager.shared)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension NymVPNApp {
|
||||
func setup() {
|
||||
ThemeConfiguration.setup()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef Bridging_Header_h
|
||||
#define Bridging_Header_h
|
||||
|
||||
//#import "libwg.h"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,8 @@
|
||||
.DS_Store
|
||||
/.build
|
||||
/Packages
|
||||
xcuserdata/
|
||||
DerivedData/
|
||||
.swiftpm/configuration/registries.json
|
||||
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
|
||||
.netrc
|
||||
@@ -0,0 +1,54 @@
|
||||
// swift-tools-version: 5.9
|
||||
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "Services",
|
||||
defaultLocalization: "en",
|
||||
platforms: [
|
||||
.iOS(.v16)
|
||||
],
|
||||
products: [
|
||||
.library(
|
||||
name: "AppSettings",
|
||||
targets: ["AppSettings"]
|
||||
),
|
||||
.library(
|
||||
name: "AppVersionProvider",
|
||||
targets: ["AppVersionProvider"]
|
||||
),
|
||||
.library(
|
||||
name: "Modifiers",
|
||||
targets: ["Modifiers"]
|
||||
),
|
||||
.library(
|
||||
name: "Tunnels",
|
||||
targets: ["Tunnels"]
|
||||
)
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
name: "AppSettings",
|
||||
dependencies: [],
|
||||
path: "Sources/Services/AppSettings"
|
||||
),
|
||||
.target(
|
||||
name: "AppVersionProvider",
|
||||
dependencies: [],
|
||||
path: "Sources/Services/AppVersionProvider"
|
||||
),
|
||||
.target(
|
||||
name: "Modifiers",
|
||||
dependencies: [
|
||||
"AppSettings"
|
||||
],
|
||||
path: "Sources/Services/Modifiers"
|
||||
),
|
||||
.target(
|
||||
name: "Tunnels",
|
||||
dependencies: [],
|
||||
path: "Sources/Services/Tunnels"
|
||||
)
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,7 @@
|
||||
import SwiftUI
|
||||
|
||||
public final class AppSettings: ObservableObject {
|
||||
public static let shared = AppSettings()
|
||||
|
||||
@AppStorage("currentAppearance") public var currentTheme: AppSetting.Appearance = .automatic
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import SwiftUI
|
||||
|
||||
public struct AppSetting {
|
||||
public enum Appearance: Int, CaseIterable {
|
||||
case automatic
|
||||
case light
|
||||
case dark
|
||||
|
||||
public var colorScheme: ColorScheme? {
|
||||
switch self {
|
||||
case .light:
|
||||
return .light
|
||||
case .dark:
|
||||
return .dark
|
||||
case .automatic:
|
||||
return ColorScheme(.unspecified)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import Foundation
|
||||
|
||||
public enum AppVersionProvider {
|
||||
public static func appVersion(in bundle: Bundle = .main) -> String {
|
||||
guard let version = bundle.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String
|
||||
else {
|
||||
fatalError("Missing CFBundleShortVersionString")
|
||||
}
|
||||
return version
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import SwiftUI
|
||||
import AppSettings
|
||||
|
||||
public struct AppearanceUpdate: ViewModifier {
|
||||
@EnvironmentObject private var appSettings: AppSettings
|
||||
|
||||
public func body(content: Content) -> some View {
|
||||
content
|
||||
.preferredColorScheme(appSettings.currentTheme.colorScheme)
|
||||
}
|
||||
}
|
||||
|
||||
public extension View {
|
||||
func appearanceUpdate() -> some View {
|
||||
modifier(AppearanceUpdate())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import NetworkExtension
|
||||
|
||||
public final class Tunnel: ObservableObject {
|
||||
public var tunnel: NETunnelProviderManager
|
||||
@Published public var isEnabled: Bool
|
||||
|
||||
private var observers = [AnyObject]()
|
||||
|
||||
public init(tunnel: NETunnelProviderManager) {
|
||||
self.tunnel = tunnel
|
||||
isEnabled = tunnel.isEnabled
|
||||
|
||||
let configurationChangeNotification = NotificationCenter.default.addObserver(
|
||||
forName: .NEVPNConfigurationChange,
|
||||
object: tunnel,
|
||||
queue: .main
|
||||
) { [weak self] _ in
|
||||
print("Tunnel isEnabled: \(tunnel.isEnabled)")
|
||||
self?.isEnabled = tunnel.isEnabled
|
||||
}
|
||||
observers.append(configurationChangeNotification)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
import NetworkExtension
|
||||
import OSLog
|
||||
|
||||
public final class TunnelsManager: ObservableObject {
|
||||
public static let shared = TunnelsManager()
|
||||
|
||||
public var currentTunnel: Tunnel?
|
||||
|
||||
private var observers = [AnyObject]()
|
||||
|
||||
private init() {
|
||||
setup()
|
||||
}
|
||||
|
||||
public func loadConfigurations() {
|
||||
NETunnelProviderManager.loadAllFromPreferences { [weak self] managers, error in
|
||||
print("1. Loading VPN Configurations")
|
||||
if let error {
|
||||
print("Error: \(String(describing: error))")
|
||||
}
|
||||
|
||||
managers?.forEach {
|
||||
print("Found VPN Configuration")
|
||||
print("\($0)")
|
||||
self?.currentTunnel = Tunnel(tunnel: $0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func test() {
|
||||
loadConfigurations()
|
||||
os_log("2 Starting test")
|
||||
if currentTunnel == nil {
|
||||
let manager = createTestManager()
|
||||
manager.saveToPreferences { error in
|
||||
if error == nil {
|
||||
print("3 Added config Successfully")
|
||||
} else {
|
||||
print("3 Failure to add config")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
print("3 Current tunnel already exists")
|
||||
currentTunnel?.tunnel.isEnabled = true
|
||||
}
|
||||
|
||||
print("4 Connecting")
|
||||
connect()
|
||||
}
|
||||
|
||||
public func connect() {
|
||||
do {
|
||||
let options = [
|
||||
NEVPNConnectionStartOptionUsername: "john",
|
||||
NEVPNConnectionStartOptionPassword: "password"
|
||||
] as [String: NSObject]
|
||||
|
||||
try currentTunnel?.tunnel.connection.startVPNTunnel(options: options)
|
||||
} catch {
|
||||
print("FAILED to connect: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
public func disconnect() {
|
||||
print("5 Disconnecting")
|
||||
// currentTunnel?.tunnel.connection.stopVPNTunnel()
|
||||
|
||||
NEVPNManager.shared().loadFromPreferences { [weak self] error in
|
||||
if let error {
|
||||
print("Error: \(error)")
|
||||
}
|
||||
self?.currentTunnel?.tunnel.connection.stopVPNTunnel()
|
||||
NEVPNManager.shared().connection.stopVPNTunnel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension TunnelsManager {
|
||||
func createTestManager() -> NETunnelProviderManager {
|
||||
let manager = NETunnelProviderManager()
|
||||
manager.localizedDescription = "NymVPN Mixnet"
|
||||
|
||||
let tunnelConfiguration = NETunnelProviderProtocol()
|
||||
tunnelConfiguration.providerBundleIdentifier = "net.nymtech.vpn.network-extension"
|
||||
tunnelConfiguration.serverAddress = "127.0.0.1:4009"
|
||||
tunnelConfiguration.providerConfiguration = [:]
|
||||
|
||||
manager.protocolConfiguration = tunnelConfiguration
|
||||
manager.isEnabled = true
|
||||
return manager
|
||||
}
|
||||
}
|
||||
|
||||
private extension TunnelsManager {
|
||||
func setup() {
|
||||
registerNotifications()
|
||||
}
|
||||
|
||||
func registerNotifications() {
|
||||
let statusDidChangeNotification = NotificationCenter.default.addObserver(
|
||||
forName: .NEVPNStatusDidChange,
|
||||
object: nil,
|
||||
queue: .main
|
||||
) { status in
|
||||
print("VPN Status: \(status)")
|
||||
}
|
||||
observers.append(statusDidChangeNotification)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import XCTest
|
||||
@testable import Services
|
||||
|
||||
final class TunnelsTests: XCTestCase {}
|
||||
@@ -0,0 +1,8 @@
|
||||
.DS_Store
|
||||
/.build
|
||||
/Packages
|
||||
xcuserdata/
|
||||
DerivedData/
|
||||
.swiftpm/configuration/registries.json
|
||||
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
|
||||
.netrc
|
||||
@@ -0,0 +1,33 @@
|
||||
// swift-tools-version: 5.9
|
||||
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "Settings",
|
||||
defaultLocalization: "en",
|
||||
platforms: [
|
||||
.iOS(.v16)
|
||||
],
|
||||
products: [
|
||||
.library(
|
||||
name: "Settings",
|
||||
targets: ["Settings"]
|
||||
)
|
||||
],
|
||||
dependencies: [
|
||||
.package(path: "../UIComponents")
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
name: "Settings",
|
||||
dependencies: [
|
||||
"UIComponents"
|
||||
]
|
||||
),
|
||||
.testTarget(
|
||||
name: "SettingsTests",
|
||||
dependencies: ["Settings"]
|
||||
)
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,19 @@
|
||||
import SwiftUI
|
||||
import AppSettings
|
||||
|
||||
struct SettingsFlowCoordinator<Content: View>: View {
|
||||
@ObservedObject var state: SettingsFlowState
|
||||
let content: () -> Content
|
||||
|
||||
var body: some View {
|
||||
content()
|
||||
.navigationDestination(for: SettingsLink.self, destination: linkDestination)
|
||||
}
|
||||
|
||||
@ViewBuilder private func linkDestination(link: SettingsLink) -> some View {
|
||||
switch link {
|
||||
case .theme:
|
||||
AppearanceView(viewModel: AppearanceViewModel(path: $state.path, appSettings: AppSettings.shared))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import SwiftUI
|
||||
|
||||
public class SettingsFlowState: ObservableObject {
|
||||
@Published var presentedItem: SettingsLink?
|
||||
|
||||
@Binding var path: NavigationPath
|
||||
|
||||
public init(path: Binding<NavigationPath>) {
|
||||
_path = path
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import Foundation
|
||||
|
||||
enum SettingsLink: Hashable, Identifiable {
|
||||
case theme
|
||||
|
||||
var id: String {
|
||||
String(describing: self)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import SwiftUI
|
||||
import AppSettings
|
||||
import Modifiers
|
||||
import UIComponents
|
||||
import Theme
|
||||
|
||||
public struct SettingsView: View {
|
||||
@StateObject private var viewModel: SettingsViewModel
|
||||
|
||||
public init(viewModel: SettingsViewModel) {
|
||||
_viewModel = StateObject(wrappedValue: viewModel)
|
||||
}
|
||||
|
||||
public var body: some View {
|
||||
SettingsFlowCoordinator(state: viewModel, content: content)
|
||||
}
|
||||
}
|
||||
|
||||
private extension SettingsView {
|
||||
@ViewBuilder
|
||||
func content() -> some View {
|
||||
VStack {
|
||||
navbar()
|
||||
settingsList()
|
||||
Spacer()
|
||||
}
|
||||
.appearanceUpdate()
|
||||
.navigationBarBackButtonHidden(true)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.ignoresSafeArea(edges: [.bottom])
|
||||
.background {
|
||||
NymColor.background
|
||||
.ignoresSafeArea()
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func navbar() -> some View {
|
||||
CustomNavBar(
|
||||
title: viewModel.settingsTitle,
|
||||
leftButton: CustomNavBarButton(type: .back, action: { viewModel.navigateHome() })
|
||||
)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func settingsList() -> some View {
|
||||
SettingsList(
|
||||
viewModel:
|
||||
SettingsListViewModel(
|
||||
sections: viewModel.sections,
|
||||
appVersion: viewModel.appVersion()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
import Foundation
|
||||
import AppVersionProvider
|
||||
import UIComponents
|
||||
|
||||
public class SettingsViewModel: SettingsFlowState {
|
||||
let settingsTitle = "settings".localizedString
|
||||
|
||||
var sections: [SettingsSection] {
|
||||
[
|
||||
connectionSection(),
|
||||
themeSection(),
|
||||
logsSection(),
|
||||
feedbackSection(),
|
||||
legalSection()
|
||||
]
|
||||
}
|
||||
|
||||
func navigateHome() {
|
||||
path = .init()
|
||||
}
|
||||
|
||||
func appVersion() -> String {
|
||||
AppVersionProvider.appVersion()
|
||||
}
|
||||
}
|
||||
|
||||
private extension SettingsViewModel {
|
||||
func navigateToTheme() {
|
||||
path.append(SettingsLink.theme)
|
||||
}
|
||||
}
|
||||
|
||||
private extension SettingsViewModel {
|
||||
func connectionSection() -> SettingsSection {
|
||||
.connection(
|
||||
viewModels: [
|
||||
SettingsListItemViewModel(
|
||||
accessory: .arrow,
|
||||
title: "autoConnectTitle".localizedString,
|
||||
subtitle: "autoConnectSubtitle".localizedString,
|
||||
imageName: "autoConnect",
|
||||
action: {}
|
||||
),
|
||||
SettingsListItemViewModel(
|
||||
accessory: .toggle,
|
||||
title: "entryLocationTitle".localizedString,
|
||||
subtitle: "entryLocationSubtitle".localizedString,
|
||||
imageName: "entryHop",
|
||||
action: {}
|
||||
)
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
func themeSection() -> SettingsSection {
|
||||
.theme(
|
||||
viewModels: [
|
||||
SettingsListItemViewModel(
|
||||
accessory: .arrow,
|
||||
title: "displayTheme".localizedString,
|
||||
imageName: "displayTheme",
|
||||
action: { [weak self] in
|
||||
self?.navigateToTheme()
|
||||
}
|
||||
)
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
func logsSection() -> SettingsSection {
|
||||
.logs(
|
||||
viewModels: [
|
||||
SettingsListItemViewModel(
|
||||
accessory: .arrow,
|
||||
title: "logs".localizedString,
|
||||
imageName: "logs",
|
||||
action: {}
|
||||
)
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
func feedbackSection() -> SettingsSection {
|
||||
.feedback(
|
||||
viewModels: [
|
||||
SettingsListItemViewModel(
|
||||
accessory: .arrow,
|
||||
title: "feedback".localizedString,
|
||||
imageName: "feedback",
|
||||
action: {}
|
||||
),
|
||||
SettingsListItemViewModel(
|
||||
accessory: .arrow,
|
||||
title: "support".localizedString,
|
||||
imageName: "support",
|
||||
action: {}
|
||||
)
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
func legalSection() -> SettingsSection {
|
||||
.legal(
|
||||
viewModels: [
|
||||
SettingsListItemViewModel(
|
||||
accessory: .arrow,
|
||||
title: "legal".localizedString,
|
||||
action: {}
|
||||
)
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import SwiftUI
|
||||
import AppSettings
|
||||
import Modifiers
|
||||
import Theme
|
||||
import UIComponents
|
||||
|
||||
public struct AppearanceView: View {
|
||||
private let viewModel: AppearanceViewModel
|
||||
|
||||
public init(viewModel: AppearanceViewModel) {
|
||||
self.viewModel = viewModel
|
||||
}
|
||||
|
||||
public var body: some View {
|
||||
VStack {
|
||||
navbar()
|
||||
themeOptions()
|
||||
Spacer()
|
||||
}
|
||||
.appearanceUpdate()
|
||||
.navigationBarBackButtonHidden(true)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.ignoresSafeArea(edges: [.bottom])
|
||||
.background {
|
||||
NymColor.background
|
||||
.ignoresSafeArea()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension AppearanceView {
|
||||
@ViewBuilder
|
||||
func navbar() -> some View {
|
||||
CustomNavBar(
|
||||
title: viewModel.title,
|
||||
leftButton: CustomNavBarButton(type: .back, action: { viewModel.navigateBack() })
|
||||
)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func themeOptions() -> some View {
|
||||
ForEach(viewModel.themes, id: \.self) { theme in
|
||||
SettingButton(
|
||||
viewModel:
|
||||
SettingButtonViewModel(
|
||||
title: viewModel.themeTitle(for: theme),
|
||||
subtitle: viewModel.themeSubtitle(for: theme),
|
||||
isSelected: viewModel.isSelected(for: theme)
|
||||
)
|
||||
)
|
||||
.onTapGesture {
|
||||
viewModel.setCurrentTheme(with: theme)
|
||||
}
|
||||
.padding(EdgeInsets(top: 24, leading: 16, bottom: 0, trailing: 16))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
import SwiftUI
|
||||
import AppSettings
|
||||
import Theme
|
||||
|
||||
public struct AppearanceViewModel {
|
||||
private let appSettings: AppSettings
|
||||
|
||||
let title = "displayTheme".localizedString
|
||||
|
||||
@Binding var path: NavigationPath
|
||||
|
||||
var themes: [AppSetting.Appearance] {
|
||||
AppSetting.Appearance.allCases
|
||||
}
|
||||
|
||||
var currentTheme: AppSetting.Appearance {
|
||||
appSettings.currentTheme
|
||||
}
|
||||
|
||||
public init(path: Binding<NavigationPath>, appSettings: AppSettings) {
|
||||
_path = path
|
||||
self.appSettings = appSettings
|
||||
}
|
||||
|
||||
func setCurrentTheme(with theme: AppSetting.Appearance) {
|
||||
appSettings.currentTheme = theme
|
||||
}
|
||||
}
|
||||
|
||||
extension AppearanceViewModel {
|
||||
func themeTitle(for theme: AppSetting.Appearance) -> String {
|
||||
switch theme {
|
||||
case .light:
|
||||
return "lightThemeTitle".localizedString
|
||||
case .dark:
|
||||
return "darkThemeTitle".localizedString
|
||||
case .automatic:
|
||||
return "automaticThemeTitle".localizedString
|
||||
}
|
||||
}
|
||||
|
||||
func themeSubtitle(for theme: AppSetting.Appearance) -> String? {
|
||||
switch theme {
|
||||
case .light, .dark:
|
||||
return nil
|
||||
case .automatic:
|
||||
return "automaticThemeSubtitle".localizedString
|
||||
}
|
||||
}
|
||||
|
||||
func isSelected(for theme: AppSetting.Appearance) -> Bool {
|
||||
appSettings.currentTheme == theme
|
||||
}
|
||||
}
|
||||
|
||||
extension AppearanceViewModel {
|
||||
func navigateBack() {
|
||||
path.removeLast()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import XCTest
|
||||
@testable import Settings
|
||||
|
||||
final class SettingsTests: XCTestCase {}
|
||||
@@ -0,0 +1,8 @@
|
||||
.DS_Store
|
||||
/.build
|
||||
/Packages
|
||||
xcuserdata/
|
||||
DerivedData/
|
||||
.swiftpm/configuration/registries.json
|
||||
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
|
||||
.netrc
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,35 @@
|
||||
// swift-tools-version: 5.9
|
||||
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "Theme",
|
||||
defaultLocalization: "en",
|
||||
platforms: [
|
||||
.iOS(.v16)
|
||||
],
|
||||
products: [
|
||||
.library(
|
||||
name: "Theme",
|
||||
targets: ["Theme"]
|
||||
)
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
name: "Theme",
|
||||
resources: [
|
||||
.copy("Resources/Fonts/Lato-Bold.ttf"),
|
||||
.copy("Resources/Fonts/Lato-Regular.ttf"),
|
||||
.copy("Resources/Fonts/Lato-SemiBold.ttf"),
|
||||
.copy("Resources/Fonts/Lato-Medium.ttf"),
|
||||
.process("Resources/Colors.xcassets"),
|
||||
.process("Resources/Localizable.xcstrings")
|
||||
]
|
||||
),
|
||||
.testTarget(
|
||||
name: "ThemeTests",
|
||||
dependencies: ["Theme"]
|
||||
)
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,40 @@
|
||||
import SwiftUI
|
||||
|
||||
public struct NymColor {
|
||||
// MARK: - Navigation bar -
|
||||
public static let navigationBarBackground = Color(.navigationBarBackground)
|
||||
public static let navigationBarSettingsGear = Color(.navigationBarSettingsGear)
|
||||
|
||||
// MARK: - Status button -
|
||||
public static let statusButtonBackground = Color(.statusButtonBackground)
|
||||
public static let sysOnSurfaceWhite = Color(.sysOnSurfaceWhite)
|
||||
public static let statusInfoText = Color(.statusInfoText)
|
||||
public static let statusTimer = Color(.statusTimer)
|
||||
|
||||
public static let countrySelectionSelectedBackground = Color(.countrySelectionSelectedBackground)
|
||||
|
||||
// MARK: - Network button -
|
||||
public static let networkButtonCircle = Color(.networkButtonCircle)
|
||||
|
||||
// MARK: - Connect -
|
||||
public static let connectTitle = Color(.connectTitle)
|
||||
|
||||
// MARK: - Background
|
||||
public static let background = Color(.background)
|
||||
|
||||
// MARK: - Sys -
|
||||
public static let sysOnSecondary = Color(.sysOnSecondary)
|
||||
public static let sysOnSurface = Color(.sysOnSurface)
|
||||
public static let sysOutline = Color(.sysOutline)
|
||||
|
||||
// MARK: - Key -
|
||||
public static let confirm = Color(.confirm)
|
||||
public static let statusGreen = Color(.statusGreen)
|
||||
|
||||
// MARK: - Primary -
|
||||
public static let primaryOrange = Color(.primaryOrange)
|
||||
|
||||
// MARK: - Settings -
|
||||
public static let settingsSeparator = Color(.settingsSeparator)
|
||||
public static let settingsVersion = Color(.settingsVersion)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import Foundation
|
||||
|
||||
extension Bundle {
|
||||
func localizedString(forKey key: String) -> String {
|
||||
localizedString(forKey: key, value: nil, table: nil)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import SwiftUI
|
||||
|
||||
extension Color {
|
||||
init(_ name: String) {
|
||||
guard let namedColor = UIColor(named: name, in: Bundle.module, compatibleWith: nil)
|
||||
else {
|
||||
fatalError("Could not load color from Theme module")
|
||||
}
|
||||
self.init(namedColor)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import Foundation
|
||||
|
||||
public extension String {
|
||||
var localizedString: String {
|
||||
Bundle.module.localizedString(forKey: self)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import SwiftUI
|
||||
|
||||
public enum NymFont {
|
||||
case lato(size: CGFloat, weight: LatoWeight)
|
||||
|
||||
public var font: Font {
|
||||
switch self {
|
||||
case let .lato(size, weight):
|
||||
Font.custom("Lato-\(weight.rawValue)", size: size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Weights -
|
||||
|
||||
extension NymFont {
|
||||
public enum LatoWeight: String, CaseIterable {
|
||||
case regular = "Regular"
|
||||
case bold = "Bold"
|
||||
case semibold = "SemiBold"
|
||||
case medium = "Medium"
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Register fonts -
|
||||
|
||||
extension NymFont {
|
||||
public static func register() {
|
||||
for latoWeight in NymFont.LatoWeight.allCases {
|
||||
let fontName = "Lato-\(latoWeight.rawValue)"
|
||||
guard let fontURL = Bundle.module.url(forResource: fontName, withExtension: "ttf") else { continue }
|
||||
CTFontManagerRegisterFontsForURL(fontURL as CFURL, .process, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import SwiftUI
|
||||
|
||||
public struct NymTextStyle {
|
||||
let nymFont: NymFont
|
||||
let lineSpacing: CGFloat
|
||||
let kerning: CGFloat
|
||||
|
||||
init(nymFont: NymFont, lineSpacing: CGFloat = 0, kerning: CGFloat = 0) {
|
||||
self.nymFont = nymFont
|
||||
self.lineSpacing = lineSpacing
|
||||
self.kerning = kerning
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Styles -
|
||||
extension NymTextStyle {
|
||||
// MARK: - Title -
|
||||
public struct Title {
|
||||
public struct Large {
|
||||
public static var primary: NymTextStyle {
|
||||
NymTextStyle(nymFont: .lato(size: 22, weight: .regular))
|
||||
}
|
||||
}
|
||||
|
||||
public struct Medium {
|
||||
public static var primary: NymTextStyle {
|
||||
NymTextStyle(nymFont: .lato(size: 16, weight: .semibold), kerning: 0.15)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Label -
|
||||
public struct Label {
|
||||
public struct Huge {
|
||||
public static var primary: NymTextStyle {
|
||||
NymTextStyle(nymFont: .lato(size: 18, weight: .bold))
|
||||
}
|
||||
}
|
||||
|
||||
public struct Large {
|
||||
public static var primary: NymTextStyle {
|
||||
NymTextStyle(nymFont: .lato(size: 14, weight: .bold), kerning: 0.1)
|
||||
}
|
||||
}
|
||||
|
||||
public struct Small {
|
||||
public static var primary: NymTextStyle {
|
||||
NymTextStyle(nymFont: .lato(size: 11, weight: .medium), kerning: 0.5)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Body -
|
||||
public struct Body {
|
||||
public struct Large {
|
||||
public static var primary: NymTextStyle {
|
||||
NymTextStyle(nymFont: .lato(size: 16, weight: .semibold), kerning: 0.5)
|
||||
}
|
||||
}
|
||||
|
||||
public struct Medium {
|
||||
public static var primary: NymTextStyle {
|
||||
NymTextStyle(nymFont: .lato(size: 14, weight: .regular), kerning: 0.25)
|
||||
}
|
||||
}
|
||||
|
||||
public struct Small {
|
||||
public static var primary: NymTextStyle {
|
||||
NymTextStyle(nymFont: .lato(size: 12, weight: .regular), kerning: 0.4)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import SwiftUI
|
||||
|
||||
public struct NymTextStyleModifier: ViewModifier {
|
||||
public let textStyle: NymTextStyle
|
||||
|
||||
public init(textStyle: NymTextStyle) {
|
||||
self.textStyle = textStyle
|
||||
}
|
||||
|
||||
public func body(content: Content) -> some View {
|
||||
content
|
||||
.font(textStyle.nymFont.font)
|
||||
.kerning(textStyle.kerning)
|
||||
.lineSpacing(textStyle.lineSpacing)
|
||||
}
|
||||
}
|
||||
|
||||
public extension View {
|
||||
func textStyle(_ textStyle: NymTextStyle) -> some View {
|
||||
modifier(NymTextStyleModifier(textStyle: textStyle))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "97",
|
||||
"green" : "199",
|
||||
"red" : "43"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "0.100",
|
||||
"blue" : "93",
|
||||
"green" : "196",
|
||||
"red" : "71"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "0.080",
|
||||
"blue" : "0x71",
|
||||
"green" : "0x5B",
|
||||
"red" : "0x61"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "0.160",
|
||||
"blue" : "0x33",
|
||||
"green" : "0x30",
|
||||
"red" : "0x30"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "113",
|
||||
"green" : "101",
|
||||
"red" : "105"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "153",
|
||||
"green" : "143",
|
||||
"red" : "147"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "display-p3",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "31",
|
||||
"green" : "28",
|
||||
"red" : "28"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "display-p3",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "255",
|
||||
"green" : "250",
|
||||
"red" : "254"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "display-p3",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.639",
|
||||
"green" : "0.639",
|
||||
"red" : "0.639"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "display-p3",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.349",
|
||||
"green" : "0.329",
|
||||
"red" : "0.337"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "31",
|
||||
"green" : "27",
|
||||
"red" : "28"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "229",
|
||||
"green" : "225",
|
||||
"red" : "230"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "31",
|
||||
"green" : "27",
|
||||
"red" : "28"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "1.000",
|
||||
"green" : "1.000",
|
||||
"red" : "1.000"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "126",
|
||||
"green" : "116",
|
||||
"red" : "121"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "153",
|
||||
"green" : "143",
|
||||
"red" : "147"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "display-p3",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.965",
|
||||
"green" : "0.957",
|
||||
"red" : "0.949"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "display-p3",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "31",
|
||||
"green" : "27",
|
||||
"red" : "28"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "255",
|
||||
"green" : "255",
|
||||
"red" : "255"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "31",
|
||||
"green" : "27",
|
||||
"red" : "28"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "0.120",
|
||||
"blue" : "0x4F",
|
||||
"green" : "0x45",
|
||||
"red" : "0x49"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "0.160",
|
||||
"blue" : "0xD0",
|
||||
"green" : "0xC4",
|
||||
"red" : "0xCA"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "display-p3",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "1.000",
|
||||
"green" : "1.000",
|
||||
"red" : "1.000"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "display-p3",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.192",
|
||||
"green" : "0.157",
|
||||
"red" : "0.165"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "display-p3",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.122",
|
||||
"green" : "0.106",
|
||||
"red" : "0.110"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "display-p3",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.812",
|
||||
"green" : "0.769",
|
||||
"red" : "0.788"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "126",
|
||||
"green" : "116",
|
||||
"red" : "121"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "display-p3",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "208",
|
||||
"green" : "196",
|
||||
"red" : "202"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "78",
|
||||
"green" : "110",
|
||||
"red" : "251"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "229",
|
||||
"green" : "225",
|
||||
"red" : "230"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "79",
|
||||
"green" : "69",
|
||||
"red" : "73"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "126",
|
||||
"green" : "116",
|
||||
"red" : "121"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "113",
|
||||
"green" : "91",
|
||||
"red" : "98"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,391 @@
|
||||
{
|
||||
"sourceLanguage" : "en",
|
||||
"strings" : {
|
||||
"2hopWireGuardSubtitle" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Best for browsing, streaming, sharing"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"2hopWireGuardTitle" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "2-hop WireGuard"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"5hopMixnetSubtitle" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Best for payments, emails, messages"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"5hopMixnetTitle" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "5-hop mixnet"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"autoConnectSubtitle" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Auto connect at app startup"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"autoConnectTitle" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Auto-connect"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"automaticThemeSubtitle" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Use device theme"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"automaticThemeTitle" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Automatic"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"connect" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Connect"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"connected" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Connected"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"connecting" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Connecting..."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"connectTo" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Connect to"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"darkThemeTitle" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Dark theme"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"disconnected" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Disconnected"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"disconnecting" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Disconnecting..."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"displayTheme" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Display theme"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"entryLocationSubtitle" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Manually select your entry hop"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"entryLocationTitle" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Entry location selector"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"fastest" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Fastest"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"feedback" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Feedback"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"firstHop" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "First hop"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"firstHopSelection" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "First hop selection"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"lastHop" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Last hop"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"lastHopSelection" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Last hop selection"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"legal" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Legal"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"lightThemeTitle" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Light theme"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"logs" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Logs"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"NymVPN" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "NymVPN"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"search" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Search"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"searchCountry" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Search country"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"selected" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Selected"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"selectNetwork" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Select network"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"settings" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Settings"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"support" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Support"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"version" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Version"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"version" : "1.0"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import Foundation
|
||||
|
||||
public struct ThemeConfiguration {
|
||||
public static func setup() {
|
||||
NymFont.register()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import XCTest
|
||||
@testable import Theme
|
||||
|
||||
final class ThemeTests: XCTestCase {}
|
||||
@@ -0,0 +1,8 @@
|
||||
.DS_Store
|
||||
/.build
|
||||
/Packages
|
||||
xcuserdata/
|
||||
DerivedData/
|
||||
.swiftpm/configuration/registries.json
|
||||
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
|
||||
.netrc
|
||||
@@ -0,0 +1,36 @@
|
||||
// swift-tools-version: 5.9
|
||||
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "UIComponents",
|
||||
defaultLocalization: "en",
|
||||
platforms: [
|
||||
.iOS(.v16)
|
||||
],
|
||||
products: [
|
||||
.library(
|
||||
name: "UIComponents",
|
||||
targets: ["UIComponents"]
|
||||
)
|
||||
],
|
||||
dependencies: [
|
||||
.package(path: "../Theme")
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
name: "UIComponents",
|
||||
dependencies: [
|
||||
"Theme"
|
||||
],
|
||||
resources: [
|
||||
.process("Resources/Assets.xcassets")
|
||||
]
|
||||
),
|
||||
.testTarget(
|
||||
name: "UIComponentsTests",
|
||||
dependencies: ["UIComponents"]
|
||||
)
|
||||
]
|
||||
)
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
import SwiftUI
|
||||
import Theme
|
||||
|
||||
public struct ConnectButton: View {
|
||||
public init() {}
|
||||
|
||||
public var body: some View {
|
||||
HStack {
|
||||
Text("connect".localizedString)
|
||||
.foregroundStyle(NymColor.connectTitle)
|
||||
.textStyle(.Label.Huge.primary)
|
||||
}
|
||||
.frame(maxWidth: .infinity, minHeight: 56, maxHeight: 56)
|
||||
.background(NymColor.primaryOrange)
|
||||
.cornerRadius(8)
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
import SwiftUI
|
||||
import Theme
|
||||
|
||||
public struct CountryCellButton: View {
|
||||
private let viewModel: CountryCellButtonViewModel
|
||||
|
||||
public init(viewModel: CountryCellButtonViewModel) {
|
||||
self.viewModel = viewModel
|
||||
}
|
||||
|
||||
public var body: some View {
|
||||
HStack {
|
||||
flagOrBoltImage()
|
||||
|
||||
Text(viewModel.title)
|
||||
.foregroundStyle(NymColor.sysOnSurface)
|
||||
.textStyle(.Body.Large.primary)
|
||||
|
||||
Spacer()
|
||||
selectedTitleView()
|
||||
}
|
||||
.contentShape(
|
||||
RoundedRectangle(cornerRadius: 8)
|
||||
)
|
||||
|
||||
.frame(width: 360, height: 56, alignment: .center)
|
||||
.background(viewModel.backgroundColor)
|
||||
.cornerRadius(8)
|
||||
}
|
||||
}
|
||||
|
||||
private extension CountryCellButton {
|
||||
@ViewBuilder
|
||||
func boltImage() -> some View {
|
||||
Image(viewModel.boltImageName, bundle: .module)
|
||||
.resizable()
|
||||
.frame(width: 24, height: 24)
|
||||
.foregroundStyle(NymColor.sysOnSurface)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func flagOrBoltImage() -> some View {
|
||||
switch viewModel.type {
|
||||
case .fastest:
|
||||
boltImage()
|
||||
.padding(.horizontal, 16)
|
||||
case .country:
|
||||
FlagImage(countryCode: viewModel.type.country.code)
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
func selectedTitleView() -> some View {
|
||||
if viewModel.isSelected {
|
||||
Text(viewModel.selectedTitle)
|
||||
.textStyle(.Label.Small.primary)
|
||||
.padding(.trailing, 24)
|
||||
}
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
import SwiftUI
|
||||
import Theme
|
||||
|
||||
public struct CountryCellButtonViewModel {
|
||||
public enum CountryCellButtonType {
|
||||
case fastest(country: Country)
|
||||
case country(country: Country)
|
||||
|
||||
var country: Country {
|
||||
switch self {
|
||||
case .fastest(let country):
|
||||
return country
|
||||
case .country(let country):
|
||||
return country
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public let boltImageName = "bolt"
|
||||
public let selectedTitle = "selected".localizedString
|
||||
public let type: CountryCellButtonType
|
||||
public let isSelected: Bool
|
||||
|
||||
public init(type: CountryCellButtonType, isSelected: Bool) {
|
||||
self.type = type
|
||||
self.isSelected = isSelected
|
||||
}
|
||||
|
||||
public var title: String {
|
||||
switch type {
|
||||
case .fastest(let country):
|
||||
return "fastest".localizedString + " (\(country.name))"
|
||||
case .country(let country):
|
||||
return country.name
|
||||
}
|
||||
}
|
||||
|
||||
public var backgroundColor: Color {
|
||||
isSelected ? NymColor.countrySelectionSelectedBackground : .clear
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user