diff --git a/.gitattributes b/.gitattributes
index b7909861..4695966a 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -22,4 +22,5 @@ TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database7.swift filter=git-
TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database8.swift filter=git-crypt diff=git-crypt
TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database9.swift filter=git-crypt diff=git-crypt
TwoFAS/Content/Assets/Assets.car filter=git-crypt diff=git-crypt
+TwoFAS/Content/AssetsWatch/Assets.car filter=git-crypt diff=git-crypt
TwoFAS/TwoFAS/Other/Guides/** filter=git-crypt diff=git-crypt
\ No newline at end of file
diff --git a/TwoFAS/Base32/Base32Watch.h b/TwoFAS/Base32/Base32Watch.h
new file mode 100644
index 00000000..4c2d053d
--- /dev/null
+++ b/TwoFAS/Base32/Base32Watch.h
@@ -0,0 +1,30 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2023 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+#import
+
+//! Project version number for Base32.
+FOUNDATION_EXPORT double Base32VersionNumber;
+
+//! Project version string for Base32.
+FOUNDATION_EXPORT const unsigned char Base32VersionString[];
+
+// In this header, you should import all the public headers of your framework using statements like #import
+
+#import "MF_Base32Additions.h"
diff --git a/TwoFAS/Common/Assets/ThemeColor.xcassets/ColorTheme.colorset/Contents.json b/TwoFAS/Common/Assets/ThemeColor.xcassets/ColorTheme.colorset/Contents.json
index 19533fff..722aa5dd 100644
--- a/TwoFAS/Common/Assets/ThemeColor.xcassets/ColorTheme.colorset/Contents.json
+++ b/TwoFAS/Common/Assets/ThemeColor.xcassets/ColorTheme.colorset/Contents.json
@@ -29,6 +29,18 @@
}
},
"idiom" : "universal"
+ },
+ {
+ "color" : {
+ "color-space" : "srgb",
+ "components" : {
+ "alpha" : "1.000",
+ "blue" : "0.137",
+ "green" : "0.110",
+ "red" : "0.898"
+ }
+ },
+ "idiom" : "watch"
}
],
"info" : {
diff --git a/TwoFAS/Common/Assets/TintColor.xcassets/tintDefaultColor.colorset/Contents.json b/TwoFAS/Common/Assets/TintColor.xcassets/tintDefaultColor.colorset/Contents.json
index 27620577..4b4b4ecf 100644
--- a/TwoFAS/Common/Assets/TintColor.xcassets/tintDefaultColor.colorset/Contents.json
+++ b/TwoFAS/Common/Assets/TintColor.xcassets/tintDefaultColor.colorset/Contents.json
@@ -29,6 +29,18 @@
}
},
"idiom" : "universal"
+ },
+ {
+ "color" : {
+ "color-space" : "srgb",
+ "components" : {
+ "alpha" : "1.000",
+ "blue" : "0x28",
+ "green" : "0x24",
+ "red" : "0x23"
+ }
+ },
+ "idiom" : "watch"
}
],
"info" : {
diff --git a/TwoFAS/Common/Sources/Colors/TintColor.swift b/TwoFAS/Common/Sources/Colors/TintColor.swift
index 65fb0322..fb9a3d57 100644
--- a/TwoFAS/Common/Sources/Colors/TintColor.swift
+++ b/TwoFAS/Common/Sources/Colors/TintColor.swift
@@ -18,6 +18,9 @@
//
import UIKit
+#if os(watchOS)
+import SwiftUI
+#endif
public enum TintColor: String, Hashable, CaseIterable, Codable {
case `default`
@@ -108,6 +111,7 @@ public extension TintColor {
}
}
+ #if os(iOS)
var color: UIColor {
let bundle = Bundle(for: CountdownTimer.self)
switch self {
@@ -124,4 +128,22 @@ public extension TintColor {
case .brown: return UIColor(named: "tintBrownColor", in: bundle, compatibleWith: nil)!
}
}
+ #elseif os(watchOS)
+ var color: Color {
+ let bundle = Bundle(for: CoreDataStack.self)
+ switch self {
+ case .`default`: return Color("tintDefaultColor", bundle: bundle)
+ case .lightBlue: return Color("tintLightBlueColor", bundle: bundle)
+ case .indigo: return Color("tintIndigoColor", bundle: bundle)
+ case .purple: return Color("tintPurpleColor", bundle: bundle)
+ case .turquoise: return Color("tintTurquoiseColor", bundle: bundle)
+ case .green: return Color("tintGreenColor", bundle: bundle)
+ case .red: return Color("tintRedColor", bundle: bundle)
+ case .orange: return Color("tintOrangeColor", bundle: bundle)
+ case .yellow: return Color("tintYellowColor", bundle: bundle)
+ case .pink: return Color("tintPinkColor", bundle: bundle)
+ case .brown: return Color("tintBrownColor", bundle: bundle)
+ }
+ }
+ #endif
}
diff --git a/TwoFAS/Common/Sources/Models/CloudState.swift b/TwoFAS/Common/Sources/Models/CloudState.swift
new file mode 100644
index 00000000..b9e72c14
--- /dev/null
+++ b/TwoFAS/Common/Sources/Models/CloudState.swift
@@ -0,0 +1,43 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import Foundation
+
+public enum CloudState: Equatable {
+ public enum NotAvailableReason: Equatable {
+ case overQuota
+ case disabledByUser
+ case error(error: NSError?)
+ case useriCloudProblem
+ case other
+ case newerVersion
+ case incorrectService(serviceName: String)
+ case cloudEncrypted
+ }
+
+ public enum Sync: Equatable {
+ case syncing
+ case synced
+ }
+
+ case unknown
+ case disabledNotAvailable(reason: NotAvailableReason)
+ case disabledAvailable
+ case enabled(sync: Sync)
+}
diff --git a/TwoFAS/Data/MainRepository/DataTypes/PINType.swift b/TwoFAS/Common/Sources/Models/PINType.swift
similarity index 95%
rename from TwoFAS/Data/MainRepository/DataTypes/PINType.swift
rename to TwoFAS/Common/Sources/Models/PINType.swift
index 9e840d70..091f5ec0 100644
--- a/TwoFAS/Data/MainRepository/DataTypes/PINType.swift
+++ b/TwoFAS/Common/Sources/Models/PINType.swift
@@ -19,7 +19,7 @@
import Foundation
-public enum PINType: CaseIterable {
+public enum PINType: CaseIterable, Codable, Hashable {
case digits4
case digits6
}
diff --git a/TwoFAS/Common/Sources/Models/TypeAliases.swift b/TwoFAS/Common/Sources/Models/TypeAliases.swift
index 5379a434..e24ce855 100644
--- a/TwoFAS/Common/Sources/Models/TypeAliases.swift
+++ b/TwoFAS/Common/Sources/Models/TypeAliases.swift
@@ -27,6 +27,8 @@ public typealias ServiceTypeID = UUID
public typealias IconTypeID = UUID
public typealias SectionID = UUID
public typealias DeviceName = String
+public typealias CloudStateListenerID = String
+public typealias CloudStateListener = (CloudState) -> Void
public typealias Secret = String
public typealias TokenValue = String
diff --git a/TwoFAS/CommonUIKit/ServiceIcon.swift b/TwoFAS/CommonUIKit/ServiceIcon.swift
index 7aebfe91..d905b6d4 100644
--- a/TwoFAS/CommonUIKit/ServiceIcon.swift
+++ b/TwoFAS/CommonUIKit/ServiceIcon.swift
@@ -18,8 +18,13 @@
//
import UIKit
+#if os(iOS)
import Common
import Content
+#elseif os(watchOS)
+import CommonWatch
+import ContentWatch
+#endif
// swiftlint:disable convenience_type
public final class ServiceIcon {
@@ -28,7 +33,7 @@ public final class ServiceIcon {
public static func `for`(iconTypeID: IconTypeID) -> UIImage {
if let img = UIImage(
named: iconTypeID.uuidString,
- in: Content.IconDescriptionDatabaseImpl.bundle,
+ in: IconDescriptionDatabaseImpl.bundle,
with: nil
) {
return img
@@ -38,7 +43,7 @@ public final class ServiceIcon {
// assert(false, "Can't find icon for service \(iconTypeID.uuidString)")
return UIImage(
named: IconTypeID.default.uuidString,
- in: Content.IconDescriptionDatabaseImpl.bundle,
+ in: IconDescriptionDatabaseImpl.bundle,
with: nil
)!
}
diff --git a/TwoFAS/Content/Assets/Assets.car b/TwoFAS/Content/Assets/Assets.car
index ea454fc1..924ed153 100644
Binary files a/TwoFAS/Content/Assets/Assets.car and b/TwoFAS/Content/Assets/Assets.car differ
diff --git a/TwoFAS/Content/AssetsWatch/Assets.car b/TwoFAS/Content/AssetsWatch/Assets.car
new file mode 100644
index 00000000..77dfa03e
Binary files /dev/null and b/TwoFAS/Content/AssetsWatch/Assets.car differ
diff --git a/TwoFAS/Content/Sources/IconDescriptionDatabase.swift b/TwoFAS/Content/Sources/IconDescriptionDatabase.swift
index 592fb314..eadc4a95 100644
--- a/TwoFAS/Content/Sources/IconDescriptionDatabase.swift
+++ b/TwoFAS/Content/Sources/IconDescriptionDatabase.swift
@@ -18,7 +18,11 @@
//
import UIKit
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
public protocol IconDescriptionDatabase: AnyObject {
func name(for iconTypeID: IconTypeID) -> String?
diff --git a/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database.swift b/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database.swift
index d7af20ec..12132b9b 100644
--- a/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database.swift
+++ b/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database.swift
@@ -18,7 +18,11 @@
//
import Foundation
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
// swiftlint:disable all
final class IconDescriptionDatabaseGenerated {
diff --git a/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database0.swift b/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database0.swift
index c20c6500..dae6c133 100644
Binary files a/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database0.swift and b/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database0.swift differ
diff --git a/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database1.swift b/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database1.swift
index 486a5d6b..76fe720a 100644
Binary files a/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database1.swift and b/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database1.swift differ
diff --git a/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database2.swift b/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database2.swift
index a344f4be..47be866c 100644
Binary files a/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database2.swift and b/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database2.swift differ
diff --git a/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database3.swift b/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database3.swift
index ccd50e9f..f6e4471d 100644
Binary files a/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database3.swift and b/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database3.swift differ
diff --git a/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database4.swift b/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database4.swift
index 0c4c7312..b02b481f 100644
Binary files a/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database4.swift and b/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database4.swift differ
diff --git a/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database5.swift b/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database5.swift
index 315bfcf9..58efb077 100644
Binary files a/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database5.swift and b/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database5.swift differ
diff --git a/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database6.swift b/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database6.swift
index d37d8b4d..3bdecce2 100644
Binary files a/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database6.swift and b/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database6.swift differ
diff --git a/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database7.swift b/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database7.swift
index 7cef2c7f..ed7ac442 100644
Binary files a/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database7.swift and b/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database7.swift differ
diff --git a/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database8.swift b/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database8.swift
index 4023d45c..b4df2fdb 100644
Binary files a/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database8.swift and b/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database8.swift differ
diff --git a/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database9.swift b/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database9.swift
index 752e5fa7..ac56ad07 100644
Binary files a/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database9.swift and b/TwoFAS/Content/Sources/IconDescriptionDatabaseImpl+Database9.swift differ
diff --git a/TwoFAS/Content/Sources/ServiceDefinitionDatabase.swift b/TwoFAS/Content/Sources/ServiceDefinitionDatabase.swift
index 0afddd8f..0bce87ed 100644
--- a/TwoFAS/Content/Sources/ServiceDefinitionDatabase.swift
+++ b/TwoFAS/Content/Sources/ServiceDefinitionDatabase.swift
@@ -18,7 +18,11 @@
//
import UIKit
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
public protocol ServiceDefinitionDatabase: AnyObject {
func listAll() -> [ServiceDefinition]
diff --git a/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database.swift b/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database.swift
index 30792c47..4c28569d 100644
--- a/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database.swift
+++ b/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database.swift
@@ -18,7 +18,11 @@
//
import UIKit
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
// swiftlint:disable all
final class ServiceDefinitionDatabaseGenerated {
diff --git a/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database0.swift b/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database0.swift
index 135d1ab8..b7a493c8 100644
Binary files a/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database0.swift and b/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database0.swift differ
diff --git a/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database1.swift b/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database1.swift
index dac4bb1a..11f62d8c 100644
Binary files a/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database1.swift and b/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database1.swift differ
diff --git a/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database2.swift b/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database2.swift
index 112d75f0..d5dd09b2 100644
Binary files a/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database2.swift and b/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database2.swift differ
diff --git a/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database3.swift b/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database3.swift
index 086f1970..77d793ae 100644
Binary files a/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database3.swift and b/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database3.swift differ
diff --git a/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database4.swift b/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database4.swift
index 49b98a64..fc3e6b4c 100644
Binary files a/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database4.swift and b/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database4.swift differ
diff --git a/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database5.swift b/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database5.swift
index 7f0497d3..3c98664e 100644
Binary files a/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database5.swift and b/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database5.swift differ
diff --git a/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database6.swift b/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database6.swift
index a401fb7e..bd6ac393 100644
Binary files a/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database6.swift and b/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database6.swift differ
diff --git a/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database7.swift b/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database7.swift
index e88c243e..5ae010b2 100644
Binary files a/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database7.swift and b/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database7.swift differ
diff --git a/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database8.swift b/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database8.swift
index e8b65b63..bfea3e44 100644
Binary files a/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database8.swift and b/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database8.swift differ
diff --git a/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database9.swift b/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database9.swift
index 5848c4e7..b2ef242a 100644
Binary files a/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database9.swift and b/TwoFAS/Content/Sources/ServiceDefinitionDatabaseImpl+Database9.swift differ
diff --git a/TwoFAS/Data/Extensions/String+.swift b/TwoFAS/Data/Extensions/String+.swift
index a61a639a..c7b883a3 100644
--- a/TwoFAS/Data/Extensions/String+.swift
+++ b/TwoFAS/Data/Extensions/String+.swift
@@ -18,7 +18,11 @@
//
import Foundation
+#if os(iOS)
import Base32
+#elseif os(watchOS)
+import Base32Watch
+#endif
extension String {
func dataFromBase32String() -> Data? {
diff --git a/TwoFAS/Data/External/OneTimePassword/Crypto.swift b/TwoFAS/Data/External/OneTimePassword/Crypto.swift
index 4ad90401..6e34e2ad 100644
--- a/TwoFAS/Data/External/OneTimePassword/Crypto.swift
+++ b/TwoFAS/Data/External/OneTimePassword/Crypto.swift
@@ -19,7 +19,11 @@
import Foundation
import CommonCrypto
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
func HMAC(algorithm: Algorithm, key: Data, data: Data) -> Data {
let (hashFunction, hashLength) = algorithm.hashInfo
diff --git a/TwoFAS/Data/External/OneTimePassword/Generator.swift b/TwoFAS/Data/External/OneTimePassword/Generator.swift
index 1f195cb2..c67a9f14 100644
--- a/TwoFAS/Data/External/OneTimePassword/Generator.swift
+++ b/TwoFAS/Data/External/OneTimePassword/Generator.swift
@@ -24,7 +24,11 @@
//
import Foundation
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
/// A `Generator` contains all of the parameters needed to generate a one-time password.
struct Generator: Equatable {
diff --git a/TwoFAS/Data/Interactors/LogUploadingInteractor.swift b/TwoFAS/Data/Interactors/LogUploadingInteractor.swift
index 39e955c2..f7cd16b8 100644
--- a/TwoFAS/Data/Interactors/LogUploadingInteractor.swift
+++ b/TwoFAS/Data/Interactors/LogUploadingInteractor.swift
@@ -20,6 +20,7 @@
import Foundation
import Sync
import Storage
+import Common
public enum LogUploadingInteractorError: Error {
case notExists
diff --git a/TwoFAS/Data/MainRepository/MainRepository.swift b/TwoFAS/Data/MainRepository/MainRepository.swift
index f58182d6..70421d41 100644
--- a/TwoFAS/Data/MainRepository/MainRepository.swift
+++ b/TwoFAS/Data/MainRepository/MainRepository.swift
@@ -23,9 +23,6 @@ import Common
import NetworkStack
@_implementationOnly import PushNotifications
-typealias CloudStateListenerID = String
-typealias CloudStateListener = (CloudState) -> Void
-
protocol MainRepository: AnyObject {
// MARK: - Security
var isPINSet: Bool { get }
diff --git a/TwoFAS/Data/MainRepository/MainRepositoryImpl+Cloud.swift b/TwoFAS/Data/MainRepository/MainRepositoryImpl+Cloud.swift
index dec37178..28216990 100644
--- a/TwoFAS/Data/MainRepository/MainRepositoryImpl+Cloud.swift
+++ b/TwoFAS/Data/MainRepository/MainRepositoryImpl+Cloud.swift
@@ -19,29 +19,7 @@
import UIKit
import Sync
-
-public enum CloudState: Equatable {
- public enum NotAvailableReason: Equatable {
- case overQuota
- case disabledByUser
- case error(error: NSError?)
- case useriCloudProblem
- case other
- case newerVersion
- case incorrectService(serviceName: String)
- case cloudEncrypted
- }
-
- public enum Sync: Equatable {
- case syncing
- case synced
- }
-
- case unknown
- case disabledNotAvailable(reason: NotAvailableReason)
- case disabledAvailable
- case enabled(sync: Sync)
-}
+import Common
extension MainRepositoryImpl {
var successSyncDate: Date? {
@@ -57,13 +35,10 @@ extension MainRepositoryImpl {
}
}
var isCloudBackupConnected: Bool { cloudHandler.isConnected }
- var cloudCurrentState: CloudState { cloudCurrentStateToCloudState(cloudHandler.currentState) }
+ var cloudCurrentState: CloudState { cloudHandler.currentState.toCloudState }
func registerForCloudStateChanges(_ listener: @escaping CloudStateListener, id: CloudStateListenerID) {
- cloudHandler.registerForStateChange({ [weak self] cloudCurrentState in
- guard let cloudState = self?.cloudCurrentStateToCloudState(cloudCurrentState) else { return }
- listener(cloudState)
- }, with: id)
+ cloudHandler.registerForStateChange({ listener($0.toCloudState) }, with: id)
cloudHandler.checkState()
}
@@ -98,40 +73,3 @@ extension MainRepositoryImpl {
userDefaultsRepository.saveSuccessSyncDate(date)
}
}
-
-private extension MainRepositoryImpl {
- func cloudCurrentStateToCloudState(_ cloudCurrentState: CloudCurrentState) -> CloudState {
- switch cloudCurrentState {
- case .unknown:
- return .unknown
- case .disabledNotAvailable(let reason):
- switch reason {
- case .overQuota:
- return .disabledNotAvailable(reason: .overQuota)
- case .disabledByUser:
- return .disabledNotAvailable(reason: .disabledByUser)
- case .error(let error):
- return .disabledNotAvailable(reason: .error(error: error))
- case .useriCloudProblem:
- return .disabledNotAvailable(reason: .useriCloudProblem)
- case .other:
- return .disabledNotAvailable(reason: .other)
- case .incorrectService(let serviceName):
- return .disabledNotAvailable(reason: .incorrectService(serviceName: serviceName))
- case .newerVersion:
- return .disabledNotAvailable(reason: .newerVersion)
- case .cloudEncrypted:
- return .disabledNotAvailable(reason: .cloudEncrypted)
- }
- case .disabledAvailable:
- return .disabledAvailable
- case .enabled(let sync):
- switch sync {
- case .syncing:
- return .enabled(sync: .synced)
- case .synced:
- return .enabled(sync: .synced)
- }
- }
- }
-}
diff --git a/TwoFAS/Data/MainRepository/MainRepositoryImpl+Security.swift b/TwoFAS/Data/MainRepository/MainRepositoryImpl+Security.swift
index b749e6ad..fb8e887f 100644
--- a/TwoFAS/Data/MainRepository/MainRepositoryImpl+Security.swift
+++ b/TwoFAS/Data/MainRepository/MainRepositoryImpl+Security.swift
@@ -19,6 +19,7 @@
import Foundation
import Protection
+import Common
extension MainRepositoryImpl {
var isPINSet: Bool {
diff --git a/TwoFAS/Data/ServiceMigration/ServiceMigrationController.swift b/TwoFAS/Data/ServiceMigration/ServiceMigrationController.swift
index dd406ee4..7dfdff86 100644
--- a/TwoFAS/Data/ServiceMigration/ServiceMigrationController.swift
+++ b/TwoFAS/Data/ServiceMigration/ServiceMigrationController.swift
@@ -18,21 +18,30 @@
//
import Foundation
+#if os(iOS)
import Storage
import Common
import Content
+#elseif os(watchOS)
+import CommonWatch
+import ContentWatch
+#endif
// Migrate to interactor when main architecture will be refactored
-final class ServiceMigrationController {
+public final class ServiceMigrationController {
private let migrationKey = "ServiceMigrationController"
private let storageRepository: StorageRepository
private var serviceDatabase: ServiceDefinitionDatabase?
- init(storageRepository: StorageRepository) {
+ #if os(watchOS)
+ public var serviceNameTranslation: String?
+ #endif
+
+ public init(storageRepository: StorageRepository) {
self.storageRepository = storageRepository
}
- func migrateIfNeeded() {
+ public func migrateIfNeeded() {
guard
let currentVersionString = Bundle.main.appVersion,
let currentVersion = currentVersionString.splitVersion()
@@ -43,7 +52,9 @@ final class ServiceMigrationController {
if let sv = savedVersionString {
if sv < currentVersion {
+ #if os(iOS)
AppEventLog(.appUpdate(currentVersionString))
+ #endif
userDefaults.set(currentVersionString, forKey: migrationKey)
userDefaults.synchronize()
} else {
@@ -75,9 +86,16 @@ final class ServiceMigrationController {
else { continue }
let name: String = {
+ #if os(iOS)
if s.name.contains(MainRepositoryImpl.shared.serviceNameTranslation) {
return def.name
}
+ #elseif os(watchOS)
+ if let serviceNameTranslation, s.name.contains(serviceNameTranslation) {
+ return def.name
+ }
+ #endif
+
return s.name
}()
diff --git a/TwoFAS/Data/Token/TokenGenerator.swift b/TwoFAS/Data/Token/TokenGenerator.swift
index 965fd575..a51ef3c4 100644
--- a/TwoFAS/Data/Token/TokenGenerator.swift
+++ b/TwoFAS/Data/Token/TokenGenerator.swift
@@ -18,7 +18,11 @@
//
import Foundation
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
public enum TokenGenerator {
// swiftlint:disable function_default_parameter_at_end
diff --git a/TwoFAS/Data/Token/TokenHandler.swift b/TwoFAS/Data/Token/TokenHandler.swift
index 0b4238bc..3272e609 100644
--- a/TwoFAS/Data/Token/TokenHandler.swift
+++ b/TwoFAS/Data/Token/TokenHandler.swift
@@ -18,16 +18,22 @@
//
import Foundation
+#if os(iOS)
import Common
+public typealias Algo = Common.Algorithm
+#elseif os(watchOS)
+import CommonWatch
+public typealias Algo = CommonWatch.Algorithm
+#endif
public struct TimedSecret {
public let secret: Secret
public let period: Period
public let digits: Digits
public let tokenType: TokenType
- public let algorithm: Common.Algorithm
+ public let algorithm: Algo
- public init(secret: Secret, period: Period, digits: Digits, algorithm: Common.Algorithm, tokenType: TokenType) {
+ public init(secret: Secret, period: Period, digits: Digits, algorithm: Algo, tokenType: TokenType) {
self.secret = secret
self.period = period
self.digits = digits
@@ -40,9 +46,9 @@ public struct CounterSecret {
public let secret: Secret
public let counter: Int
public let digits: Digits
- public let algorithm: Common.Algorithm
+ public let algorithm: Algo
- public init(secret: Secret, counter: Int, digits: Digits, algorithm: Common.Algorithm) {
+ public init(secret: Secret, counter: Int, digits: Digits, algorithm: Algo) {
self.secret = secret
self.counter = counter
self.digits = digits
@@ -56,7 +62,7 @@ public enum TokenHandler {
time: Date? = nil,
digits: Digits,
period: Period,
- algorithm: Common.Algorithm,
+ algorithm: Algo,
counter: Int,
tokenType: TokenType
) -> TokenValue {
@@ -73,8 +79,10 @@ public enum TokenHandler {
return TokenGenerator.generateHOTP(secret: secret, counter: counter, digits: digits, algoritm: algorithm)
}
+#if os(iOS)
public static let timer = TimerHandler()
public static let counter = CounterHandler()
+#endif
}
public extension TokenValue {
diff --git a/TwoFAS/Protection/ExchangeFileEncryption.swift b/TwoFAS/Protection/ExchangeFileEncryption.swift
index 330bfd74..d2b7a8c9 100644
--- a/TwoFAS/Protection/ExchangeFileEncryption.swift
+++ b/TwoFAS/Protection/ExchangeFileEncryption.swift
@@ -20,7 +20,11 @@
import Foundation
import CryptoKit
import CommonCrypto
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
public final class ExchangeFileEncryption {
public struct EncryptionResult {
diff --git a/TwoFAS/Protection/LocalKeyEncryption.swift b/TwoFAS/Protection/LocalKeyEncryption.swift
index 67747f6b..171e6d05 100644
--- a/TwoFAS/Protection/LocalKeyEncryption.swift
+++ b/TwoFAS/Protection/LocalKeyEncryption.swift
@@ -18,7 +18,11 @@
//
import Foundation
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
public final class LocalKeyEncryption: CommonLocalKeyEncryption {
private let encryption = KeyEncryption(
@@ -26,6 +30,8 @@ public final class LocalKeyEncryption: CommonLocalKeyEncryption {
alphabet: Keys.LocalKeyEncryption.alphabet
)
+ public init() {}
+
public func encrypt(_ str: String) -> String { encryption.encipher(str) }
public func decrypt(_ str: String) -> String { encryption.decipher(str) }
}
diff --git a/TwoFAS/Protection/Protection+.swift b/TwoFAS/Protection/Protection+.swift
new file mode 100644
index 00000000..b4837ed2
--- /dev/null
+++ b/TwoFAS/Protection/Protection+.swift
@@ -0,0 +1,54 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import Foundation
+
+extension Protection.CodeType: RawRepresentable {
+ private enum Keys {
+ static let PIN4 = "PIN4"
+ static let PIN6 = "PIN6"
+ }
+ public typealias RawValue = String
+
+ public init?(rawValue: String) {
+ if rawValue == Keys.PIN4 {
+ self = .PIN4
+ } else if rawValue == Keys.PIN6 {
+ self = .PIN6
+ } else {
+ return nil
+ }
+ }
+
+ public var rawValue: String {
+ switch self {
+ case .PIN4: return Keys.PIN4
+ case .PIN6: return Keys.PIN6
+ }
+ }
+}
+
+public extension Protection.CodeType {
+ var intValue: Int {
+ switch self {
+ case .PIN4: return 4
+ case .PIN6: return 6
+ }
+ }
+}
diff --git a/TwoFAS/Protection/Protection.swift b/TwoFAS/Protection/Protection.swift
index d6d7ed12..06f25135 100644
--- a/TwoFAS/Protection/Protection.swift
+++ b/TwoFAS/Protection/Protection.swift
@@ -18,12 +18,16 @@
//
import Foundation
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
public final class Protection {
public typealias PIN = String
- public enum CodeType {
+ public enum CodeType: CaseIterable {
case PIN4
case PIN6
}
@@ -32,7 +36,7 @@ public final class Protection {
let PINvalue: PIN
let codeType: CodeType
}
-
+ #if os(iOS)
private let encryptedStorage: LocalEncryptedStorage
public let biometricAuth: BiometricAuth
@@ -53,40 +57,15 @@ public final class Protection {
migrationHandler = MigrationHandler(storage: encryptedStorage)
migrationHandler.migrateIfNeeded()
}
-}
-
-extension Protection.CodeType: RawRepresentable {
- private enum Keys {
- static let PIN4 = "PIN4"
- static let PIN6 = "PIN6"
- }
- public typealias RawValue = String
-
- public init?(rawValue: String) {
- if rawValue == Keys.PIN4 {
- self = .PIN4
- } else if rawValue == Keys.PIN6 {
- self = .PIN6
- } else {
- return nil
- }
- }
-
- public var rawValue: String {
- switch self {
- case .PIN4: return Keys.PIN4
- case .PIN6: return Keys.PIN6
- }
- }
-}
-
-public extension Protection.CodeType {
- var intValue: Int {
- switch self {
- case .PIN4: return 4
- case .PIN6: return 6
- }
+ #elseif os(watchOS)
+// private let encryptedStorage: LocalEncryptedStorage
+// public let codeStorage: CodeStorage
+ public let localKeyEncryption: CommonLocalKeyEncryption
+//
+ public init() {
+// encryptedStorage = LocalEncryptedStorage(defaults: UserDefaults(suiteName: Config.suiteName)!)
+// codeStorage = CodeStorage(storage: encryptedStorage)
+ localKeyEncryption = LocalKeyEncryption()
}
+ #endif
}
-
-extension Protection.CodeType: CaseIterable {}
diff --git a/TwoFAS/Storage/AuthRequest/AuthRequestEntity+CoreDataClass.swift b/TwoFAS/Storage/AuthRequest/AuthRequestEntity+CoreDataClass.swift
index d5fd21aa..690290d1 100644
--- a/TwoFAS/Storage/AuthRequest/AuthRequestEntity+CoreDataClass.swift
+++ b/TwoFAS/Storage/AuthRequest/AuthRequestEntity+CoreDataClass.swift
@@ -19,7 +19,11 @@
import Foundation
import CoreData
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
@objc(AuthRequestEntity)
final class AuthRequestEntity: NSManagedObject {
diff --git a/TwoFAS/Storage/AuthRequest/AuthRequestEntityToPairedAuthRequest.swift b/TwoFAS/Storage/AuthRequest/AuthRequestEntityToPairedAuthRequest.swift
index 5873429f..cb4ef431 100644
--- a/TwoFAS/Storage/AuthRequest/AuthRequestEntityToPairedAuthRequest.swift
+++ b/TwoFAS/Storage/AuthRequest/AuthRequestEntityToPairedAuthRequest.swift
@@ -18,7 +18,11 @@
//
import Foundation
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
extension AuthRequestEntity {
var pairedAuthRequest: PairedAuthRequest {
diff --git a/TwoFAS/Storage/AuthRequest/AuthRequestFilterOptions.swift b/TwoFAS/Storage/AuthRequest/AuthRequestFilterOptions.swift
index 407170d3..ce7e7897 100644
--- a/TwoFAS/Storage/AuthRequest/AuthRequestFilterOptions.swift
+++ b/TwoFAS/Storage/AuthRequest/AuthRequestFilterOptions.swift
@@ -18,7 +18,11 @@
//
import Foundation
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
enum AuthRequestFilterOptions {
case domainExtension(domain: String, extensionID: ExtensionID)
diff --git a/TwoFAS/Storage/CategoryData.swift b/TwoFAS/Storage/CategoryData.swift
index 02e0d036..d6edffe0 100644
--- a/TwoFAS/Storage/CategoryData.swift
+++ b/TwoFAS/Storage/CategoryData.swift
@@ -18,7 +18,11 @@
//
import Foundation
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
public struct CategoryData: Equatable, Hashable {
public let section: SectionData?
diff --git a/TwoFAS/Storage/CategoryHandler.swift b/TwoFAS/Storage/CategoryHandler.swift
index d537337e..6a9a9431 100644
--- a/TwoFAS/Storage/CategoryHandler.swift
+++ b/TwoFAS/Storage/CategoryHandler.swift
@@ -18,7 +18,11 @@
//
import Foundation
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
public final class CategoryHandler {
private let sectionHandler: SectionHandler
diff --git a/TwoFAS/Storage/DynamicTypesEntityMigrationPolicy.swift b/TwoFAS/Storage/DynamicTypesEntityMigrationPolicy.swift
index cb767a9c..13b2c461 100644
--- a/TwoFAS/Storage/DynamicTypesEntityMigrationPolicy.swift
+++ b/TwoFAS/Storage/DynamicTypesEntityMigrationPolicy.swift
@@ -19,8 +19,13 @@
import Foundation
import CoreData
+#if os(iOS)
import Common
import Content
+#elseif os(watchOS)
+import CommonWatch
+import ContentWatch
+#endif
@objc(DynamicTypesEntityMigrationPolicy)
final class DynamicTypesEntityMigrationPolicy: NSEntityMigrationPolicy {
diff --git a/TwoFAS/Storage/EncryptSecretEntityMigrationPolicy.swift b/TwoFAS/Storage/EncryptSecretEntityMigrationPolicy.swift
index 9801c9da..244b89b0 100644
--- a/TwoFAS/Storage/EncryptSecretEntityMigrationPolicy.swift
+++ b/TwoFAS/Storage/EncryptSecretEntityMigrationPolicy.swift
@@ -19,7 +19,11 @@
import Foundation
import CoreData
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
@objc(EncryptSecretEntityMigrationPolicy)
final class EncryptSecretEntityMigrationPolicy: NSEntityMigrationPolicy {
diff --git a/TwoFAS/Storage/Extensions.swift b/TwoFAS/Storage/Extensions.swift
index e24adfd2..28fd1b4b 100644
--- a/TwoFAS/Storage/Extensions.swift
+++ b/TwoFAS/Storage/Extensions.swift
@@ -18,7 +18,11 @@
//
import Foundation
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
extension Array where Element: Equatable {
mutating func move(_ element: Element, to newIndex: Index) {
diff --git a/TwoFAS/Storage/Log/LogEntry.swift b/TwoFAS/Storage/Log/LogEntry.swift
index 7a05939a..7a86b486 100644
--- a/TwoFAS/Storage/Log/LogEntry.swift
+++ b/TwoFAS/Storage/Log/LogEntry.swift
@@ -18,7 +18,11 @@
//
import Foundation
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
public struct LogEntry: Hashable {
public let content: String
diff --git a/TwoFAS/Storage/Log/LogEntryEntity+CoreDataClass.swift b/TwoFAS/Storage/Log/LogEntryEntity+CoreDataClass.swift
index afafef90..b2709a4d 100644
--- a/TwoFAS/Storage/Log/LogEntryEntity+CoreDataClass.swift
+++ b/TwoFAS/Storage/Log/LogEntryEntity+CoreDataClass.swift
@@ -19,7 +19,11 @@
import Foundation
import CoreData
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
@objc(LogEntryEntity)
final class LogEntryEntity: NSManagedObject {
diff --git a/TwoFAS/Storage/Log/LogHandler.swift b/TwoFAS/Storage/Log/LogHandler.swift
index af702135..d6bf89be 100644
--- a/TwoFAS/Storage/Log/LogHandler.swift
+++ b/TwoFAS/Storage/Log/LogHandler.swift
@@ -18,8 +18,12 @@
//
import Foundation
-import Common
import CoreData
+#if os(iOS)
+import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
public final class LogHandler: LogStorageHandling {
private struct CachedEntry {
@@ -48,6 +52,7 @@ public final class LogHandler: LogStorageHandling {
context = coreDataStack.createBackgroundContext()
context.automaticallyMergesChangesFromParent = true
+ #if os(iOS)
NotificationCenter.default.addObserver(
self,
selector: #selector(save),
@@ -66,6 +71,7 @@ public final class LogHandler: LogStorageHandling {
name: UIApplication.didEnterBackgroundNotification,
object: nil
)
+ #endif
}
public func markZoneStart() {
diff --git a/TwoFAS/Storage/News/NewsEntity+CoreDataClass.swift b/TwoFAS/Storage/News/NewsEntity+CoreDataClass.swift
index 8e712133..ed133d3c 100644
--- a/TwoFAS/Storage/News/NewsEntity+CoreDataClass.swift
+++ b/TwoFAS/Storage/News/NewsEntity+CoreDataClass.swift
@@ -19,7 +19,11 @@
import Foundation
import CoreData
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
@objc(NewsEntity)
final class NewsEntity: NSManagedObject {
diff --git a/TwoFAS/Storage/Pairing/PairingEntity+CoreDataClass.swift b/TwoFAS/Storage/Pairing/PairingEntity+CoreDataClass.swift
index d754fa95..9ed2948e 100644
--- a/TwoFAS/Storage/Pairing/PairingEntity+CoreDataClass.swift
+++ b/TwoFAS/Storage/Pairing/PairingEntity+CoreDataClass.swift
@@ -19,7 +19,11 @@
import Foundation
import CoreData
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
@objc(PairingEntity)
final class PairingEntity: NSManagedObject {
diff --git a/TwoFAS/Storage/Section/SectionData.swift b/TwoFAS/Storage/Section/SectionData.swift
index d8457a38..ba51eb60 100644
--- a/TwoFAS/Storage/Section/SectionData.swift
+++ b/TwoFAS/Storage/Section/SectionData.swift
@@ -19,7 +19,11 @@
import Foundation
import CoreData
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
public struct SectionData: Hashable {
public let title: String
diff --git a/TwoFAS/Storage/Section/SectionEntity+CoreDataClass.swift b/TwoFAS/Storage/Section/SectionEntity+CoreDataClass.swift
index 1f90ef6b..2eb69593 100644
--- a/TwoFAS/Storage/Section/SectionEntity+CoreDataClass.swift
+++ b/TwoFAS/Storage/Section/SectionEntity+CoreDataClass.swift
@@ -19,7 +19,11 @@
import Foundation
import CoreData
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
@objc(SectionEntity)
final class SectionEntity: NSManagedObject {
diff --git a/TwoFAS/Storage/Section/SectionEntity+CoreDataProperties.swift b/TwoFAS/Storage/Section/SectionEntity+CoreDataProperties.swift
index 832ddd99..dace2493 100644
--- a/TwoFAS/Storage/Section/SectionEntity+CoreDataProperties.swift
+++ b/TwoFAS/Storage/Section/SectionEntity+CoreDataProperties.swift
@@ -19,7 +19,11 @@
import Foundation
import CoreData
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
extension SectionEntity {
@nonobjc static func request() -> NSFetchRequest {
diff --git a/TwoFAS/Storage/Section/SectionHandler.swift b/TwoFAS/Storage/Section/SectionHandler.swift
index 1bf94e77..08d22dad 100644
--- a/TwoFAS/Storage/Section/SectionHandler.swift
+++ b/TwoFAS/Storage/Section/SectionHandler.swift
@@ -19,7 +19,11 @@
import Foundation
import CoreData
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
public final class SectionHandler: CommonSectionHandler {
private let coreDataStack: CoreDataStack
diff --git a/TwoFAS/Storage/Service/ServiceData+Extensions.swift b/TwoFAS/Storage/Service/ServiceData+Extensions.swift
index 6e0350a8..0eef6ffe 100644
--- a/TwoFAS/Storage/Service/ServiceData+Extensions.swift
+++ b/TwoFAS/Storage/Service/ServiceData+Extensions.swift
@@ -18,7 +18,11 @@
//
import Foundation
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
extension ServiceData {
static func createFromManagedObject(entity: ServiceEntity) -> ServiceData {
diff --git a/TwoFAS/Storage/Service/ServiceEntity+CoreDataClass.swift b/TwoFAS/Storage/Service/ServiceEntity+CoreDataClass.swift
index 08715bb1..473825a1 100644
--- a/TwoFAS/Storage/Service/ServiceEntity+CoreDataClass.swift
+++ b/TwoFAS/Storage/Service/ServiceEntity+CoreDataClass.swift
@@ -19,7 +19,11 @@
import Foundation
import CoreData
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
@objc(ServiceEntity)
final class ServiceEntity: NSManagedObject {
diff --git a/TwoFAS/Storage/Service/ServiceEntity+Extensions.swift b/TwoFAS/Storage/Service/ServiceEntity+Extensions.swift
index cb88d978..0dbf0cb5 100644
--- a/TwoFAS/Storage/Service/ServiceEntity+Extensions.swift
+++ b/TwoFAS/Storage/Service/ServiceEntity+Extensions.swift
@@ -18,7 +18,11 @@
//
import Foundation
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
extension Array where Element == ServiceEntity {
var groupByCategory: ServiceEntity.ServicesWithinSections {
diff --git a/TwoFAS/Storage/Service/ServiceHandler.swift b/TwoFAS/Storage/Service/ServiceHandler.swift
index 52de91d0..e01043c0 100644
--- a/TwoFAS/Storage/Service/ServiceHandler.swift
+++ b/TwoFAS/Storage/Service/ServiceHandler.swift
@@ -19,7 +19,11 @@
import Foundation
import CoreData
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
// DEPRECATED - use Storage Repository
public final class ServiceHandler {
diff --git a/TwoFAS/Storage/Service/ServiceOptions.swift b/TwoFAS/Storage/Service/ServiceOptions.swift
index 3b95c1e1..ca82c4c2 100644
--- a/TwoFAS/Storage/Service/ServiceOptions.swift
+++ b/TwoFAS/Storage/Service/ServiceOptions.swift
@@ -18,7 +18,11 @@
//
import Foundation
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
public enum ServiceOptions {
public enum TrashOptions {
diff --git a/TwoFAS/Storage/Storage.swift b/TwoFAS/Storage/Storage.swift
index 8a5cd17c..0aeca7c2 100644
--- a/TwoFAS/Storage/Storage.swift
+++ b/TwoFAS/Storage/Storage.swift
@@ -18,7 +18,11 @@
//
import Foundation
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
public final class Storage {
private let coreDataStack: CoreDataStack
@@ -31,11 +35,9 @@ public final class Storage {
public init(readOnly: Bool = false, logError: ((String) -> Void)?) {
let packageName = "TwoFAS"
let bundle = Bundle(for: Storage.self)
- coreDataStack = CoreDataStack(
- readOnly: readOnly,
- name: packageName,
- bundle: bundle,
- migrator: CoreDataMigrator(
+ let migrator: CoreDataMigratorProtocol? = {
+ #if os(iOS)
+ CoreDataMigrator(
momdSubdirectory: packageName,
versions: [
CoreDataMigrationVersion(rawValue: "TwoFAS"),
@@ -47,6 +49,15 @@ public final class Storage {
CoreDataMigrationVersion(rawValue: "TwoFAS7")
]
)
+ #elseif os(watchOS)
+ return nil
+ #endif
+ }()
+ coreDataStack = CoreDataStack(
+ readOnly: readOnly,
+ name: packageName,
+ bundle: bundle,
+ migrator: migrator
)
coreDataStack.logError = logError
diff --git a/TwoFAS/Storage/StorageRepository.swift b/TwoFAS/Storage/StorageRepository.swift
index 87e134c6..92eea47d 100644
--- a/TwoFAS/Storage/StorageRepository.swift
+++ b/TwoFAS/Storage/StorageRepository.swift
@@ -18,7 +18,11 @@
//
import Foundation
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
public protocol StorageRepository: AnyObject {
var hasServices: Bool { get }
diff --git a/TwoFAS/Storage/StorageRepositoryImpl+AuthRequest.swift b/TwoFAS/Storage/StorageRepositoryImpl+AuthRequest.swift
index 783b0e19..ec2414ca 100644
--- a/TwoFAS/Storage/StorageRepositoryImpl+AuthRequest.swift
+++ b/TwoFAS/Storage/StorageRepositoryImpl+AuthRequest.swift
@@ -18,7 +18,11 @@
//
import Foundation
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
extension StorageRepositoryImpl {
func removeAuthRequest(_ authRequest: PairedAuthRequest) {
diff --git a/TwoFAS/Storage/StorageRepositoryImpl+CategoriesSections.swift b/TwoFAS/Storage/StorageRepositoryImpl+CategoriesSections.swift
index c1f2a940..b8245865 100644
--- a/TwoFAS/Storage/StorageRepositoryImpl+CategoriesSections.swift
+++ b/TwoFAS/Storage/StorageRepositoryImpl+CategoriesSections.swift
@@ -18,7 +18,11 @@
//
import Foundation
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
extension StorageRepositoryImpl {
func listAllSections() -> [SectionData] {
diff --git a/TwoFAS/Storage/StorageRepositoryImpl+News.swift b/TwoFAS/Storage/StorageRepositoryImpl+News.swift
index 39b00e32..b5084192 100644
--- a/TwoFAS/Storage/StorageRepositoryImpl+News.swift
+++ b/TwoFAS/Storage/StorageRepositoryImpl+News.swift
@@ -18,7 +18,11 @@
//
import Foundation
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
extension StorageRepositoryImpl {
func createNewsEntry(from newsEntry: ListNewsEntry) {
diff --git a/TwoFAS/Storage/StorageRepositoryImpl+Pairing.swift b/TwoFAS/Storage/StorageRepositoryImpl+Pairing.swift
index b5f628a7..6907766c 100644
--- a/TwoFAS/Storage/StorageRepositoryImpl+Pairing.swift
+++ b/TwoFAS/Storage/StorageRepositoryImpl+Pairing.swift
@@ -18,8 +18,12 @@
//
import Foundation
-import Common
import CoreData
+#if os(iOS)
+import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
extension StorageRepositoryImpl {
func createPairing(name: String, extensionID: ExtensionID, publicKey: String) {
diff --git a/TwoFAS/Storage/StorageRepositoryImpl.swift b/TwoFAS/Storage/StorageRepositoryImpl.swift
index 8134fc37..ef42f2a3 100644
--- a/TwoFAS/Storage/StorageRepositoryImpl.swift
+++ b/TwoFAS/Storage/StorageRepositoryImpl.swift
@@ -19,7 +19,11 @@
import Foundation
import CoreData
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
final class StorageRepositoryImpl: StorageRepository {
private let coreDataStack: CoreDataStack
diff --git a/TwoFAS/Storage/Watch/TwoFAS.xcdatamodeld/TwoFAS.xcdatamodel/contents b/TwoFAS/Storage/Watch/TwoFAS.xcdatamodeld/TwoFAS.xcdatamodel/contents
new file mode 100644
index 00000000..e015300b
--- /dev/null
+++ b/TwoFAS/Storage/Watch/TwoFAS.xcdatamodeld/TwoFAS.xcdatamodel/contents
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TwoFAS/Sync/ClearHandler.swift b/TwoFAS/Sync/ClearHandler.swift
index 25794bb8..4e370361 100644
--- a/TwoFAS/Sync/ClearHandler.swift
+++ b/TwoFAS/Sync/ClearHandler.swift
@@ -18,7 +18,11 @@
//
import Foundation
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
import CloudKit
final class ClearHandler {
diff --git a/TwoFAS/Sync/CloudAvailability.swift b/TwoFAS/Sync/CloudAvailability.swift
index d7a70700..a0063616 100644
--- a/TwoFAS/Sync/CloudAvailability.swift
+++ b/TwoFAS/Sync/CloudAvailability.swift
@@ -19,7 +19,11 @@
import Foundation
import CloudKit
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
enum CloudAvailabilityStatus {
case available
diff --git a/TwoFAS/Sync/CloudHandler.swift b/TwoFAS/Sync/CloudHandler.swift
index 811a6eae..f00df082 100644
--- a/TwoFAS/Sync/CloudHandler.swift
+++ b/TwoFAS/Sync/CloudHandler.swift
@@ -18,7 +18,11 @@
//
import UIKit
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
public enum CloudCurrentState: Equatable {
public enum NotAvailableReason: Equatable {
@@ -42,6 +46,41 @@ public enum CloudCurrentState: Equatable {
case disabledNotAvailable(reason: NotAvailableReason)
case disabledAvailable
case enabled(sync: Sync)
+
+ public var toCloudState: CloudState {
+ switch self {
+ case .unknown:
+ return .unknown
+ case .disabledNotAvailable(let reason):
+ switch reason {
+ case .overQuota:
+ return .disabledNotAvailable(reason: .overQuota)
+ case .disabledByUser:
+ return .disabledNotAvailable(reason: .disabledByUser)
+ case .error(let error):
+ return .disabledNotAvailable(reason: .error(error: error))
+ case .useriCloudProblem:
+ return .disabledNotAvailable(reason: .useriCloudProblem)
+ case .other:
+ return .disabledNotAvailable(reason: .other)
+ case .incorrectService(let serviceName):
+ return .disabledNotAvailable(reason: .incorrectService(serviceName: serviceName))
+ case .newerVersion:
+ return .disabledNotAvailable(reason: .newerVersion)
+ case .cloudEncrypted:
+ return .disabledNotAvailable(reason: .cloudEncrypted)
+ }
+ case .disabledAvailable:
+ return .disabledAvailable
+ case .enabled(let sync):
+ switch sync {
+ case .syncing:
+ return .enabled(sync: .synced)
+ case .synced:
+ return .enabled(sync: .synced)
+ }
+ }
+ }
}
public typealias CloudHandlerStateListener = (CloudCurrentState) -> Void
@@ -54,7 +93,7 @@ public protocol CloudHandlerType: AnyObject {
func registerForStateChange(_ listener: @escaping CloudHandlerStateListener, with id: String)
func didReceiveRemoteNotification(
userInfo: [AnyHashable: Any],
- fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void
+ fetchCompletionHandler completionHandler: @escaping (BackgroundFetchResult) -> Void
)
func unregisterForStateChange(id: String)
@@ -213,7 +252,7 @@ final class CloudHandler: CloudHandlerType {
func didReceiveRemoteNotification(
userInfo: [AnyHashable: Any],
- fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void
+ fetchCompletionHandler completionHandler: @escaping (BackgroundFetchResult) -> Void
) {
switch currentState {
case .enabled:
diff --git a/TwoFAS/Sync/CloudKit.swift b/TwoFAS/Sync/CloudKit.swift
index a9cae23f..7f8cc542 100644
--- a/TwoFAS/Sync/CloudKit.swift
+++ b/TwoFAS/Sync/CloudKit.swift
@@ -19,8 +19,13 @@
import Foundation
import CloudKit
-import Common
+#if os(iOS)
import UIKit
+import Common
+#elseif os(watchOS)
+import CommonWatch
+import WatchKit
+#endif
final class CloudKit {
typealias DeletedEntries = ([(name: String, type: String)]) -> Void
@@ -474,6 +479,7 @@ final class CloudKit {
zoneUpdated = false
DispatchQueue.main.async {
+ #if os(iOS)
if UIApplication.shared.applicationState == .background {
self.abortSync?()
self.syncTokenHandler.prepare()
@@ -482,6 +488,17 @@ final class CloudKit {
self.operation = nil
return
}
+ #elseif os(watchOS)
+ if WKApplication.shared()
+ .applicationState == .background || WKApplication.shared().applicationState == .inactive {
+ self.abortSync?()
+ self.syncTokenHandler.prepare()
+ self.clearRecordChanges()
+ self.operation?.cancel()
+ self.operation = nil
+ return
+ }
+ #endif
if !self.deletedRecords.isEmpty {
Log("CloudKit - deletedRecords not empty", module: .cloudSync)
diff --git a/TwoFAS/Sync/CommonItemHandler.swift b/TwoFAS/Sync/CommonItemHandler.swift
index d31f652a..78d60874 100644
--- a/TwoFAS/Sync/CommonItemHandler.swift
+++ b/TwoFAS/Sync/CommonItemHandler.swift
@@ -18,7 +18,11 @@
//
import Foundation
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
final class CommonItemHandler {
private let commonSectionHandler: CommonSectionHandler
diff --git a/TwoFAS/Sync/Info/InfoRecord.swift b/TwoFAS/Sync/Info/InfoRecord.swift
index c4714dd2..ee2ea032 100644
--- a/TwoFAS/Sync/Info/InfoRecord.swift
+++ b/TwoFAS/Sync/Info/InfoRecord.swift
@@ -19,7 +19,11 @@
import Foundation
import CloudKit
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
enum InfoEntryKey: String {
case version
diff --git a/TwoFAS/Sync/Item/ItemHandler.swift b/TwoFAS/Sync/Item/ItemHandler.swift
index 10f54e05..2768c992 100644
--- a/TwoFAS/Sync/Item/ItemHandler.swift
+++ b/TwoFAS/Sync/Item/ItemHandler.swift
@@ -19,8 +19,13 @@
import Foundation
import CloudKit
+#if os(iOS)
import Common
import Protection
+#elseif os(watchOS)
+import CommonWatch
+import ProtectionWatch
+#endif
final class ItemHandler {
typealias SecretError = (String) -> Void
diff --git a/TwoFAS/Sync/Item/ItemHandlerMigrationProxyWatch.swift b/TwoFAS/Sync/Item/ItemHandlerMigrationProxyWatch.swift
new file mode 100644
index 00000000..653dd17f
--- /dev/null
+++ b/TwoFAS/Sync/Item/ItemHandlerMigrationProxyWatch.swift
@@ -0,0 +1,126 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2023 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import Foundation
+import CloudKit
+import CommonWatch
+import ContentWatch
+
+final class ItemHandlerMigrationProxy {
+ var newerVersion: (() -> Void)?
+ var cloudEncrypted: (() -> Void)?
+
+ private let itemHandler: ItemHandler
+
+ private var isFirstStart = false
+
+ private var deletedEntries: [EntityOfKind] = []
+ private var updatedCreated: [CKRecord] = []
+
+ private var itemsToDelete: [CKRecord.ID] = []
+ private var itemsToAdd: [ServiceData] = []
+
+ init(itemHandler: ItemHandler) {
+ self.itemHandler = itemHandler
+ }
+
+ func firstStart() {
+ Log("Migration proxy - first start!", module: .cloudSync)
+ isFirstStart = true
+ }
+}
+
+extension ItemHandlerMigrationProxy: ItemHandling {
+ func commit() {
+ Log("Migration proxy - commit", module: .cloudSync)
+ if isFirstStart {
+ if let infoRecord = updatedCreated.first(where: { RecordType(rawValue: $0.recordType) == .info }) {
+ let info = InfoRecord(record: infoRecord)
+ if info.version > Info().version {
+ Log("Migration proxy - newer version! Aborting...", module: .cloudSync)
+ newerVersion?()
+ return
+ }
+ if let encryption = Info.Encryption(rawValue: info.encryption), encryption == .user {
+ Log("Migration proxy - cloud encrypted! Aborting...", module: .cloudSync)
+ cloudEncrypted?()
+ return
+ }
+ }
+
+ isFirstStart = false
+ }
+ itemHandler.deleteEntries(deletedEntries)
+ itemHandler.updateOrCreate(with: updatedCreated)
+ deletedEntries = []
+ updatedCreated = []
+ }
+
+ func purge() {
+ itemHandler.purge()
+ }
+
+ func itemsToDeleteAfterMigration() -> [CKRecord.ID] {
+ let list = itemsToDelete
+ itemsToDelete = []
+ return list
+ }
+
+ func servicesToAppend() -> [ServiceData] {
+ let services = itemsToAdd
+ itemsToAdd = []
+ return services
+ }
+
+ func listAllCommonItems() -> [RecordType: [Any]] {
+ itemHandler.listAllCommonItems()
+ }
+
+ func findItemsRecordIDs(for items: [EntityOfKind], zoneID: CKRecordZone.ID) -> [CKRecord.ID] {
+ itemHandler.findItemsRecordIDs(for: items, zoneID: zoneID)
+ }
+
+ func filterDeleted(from items: [RecordType: [Any]], deleted: [EntityOfKind]) -> [RecordType: [Any]] {
+ itemHandler.filterDeleted(from: items, deleted: deleted)
+ }
+
+ func findItem(for item: Any, type: RecordType, in items: [RecordType: [Any]]) -> CommonDataIndex? {
+ itemHandler.findItem(for: item, type: type, in: items)
+ }
+
+ func findItemForEntryID(_ entryID: String, type: RecordType, in items: [RecordType: [Any]]) -> CommonDataIndex? {
+ itemHandler.findItemForEntryID(entryID, type: type, in: items)
+ }
+
+ func record(for type: RecordType, item: Any, modifiedData from: [RecordType: [Any]]) -> CKRecord? {
+ itemHandler.record(for: type, item: item, modifiedData: from)
+ }
+
+ func record(for type: RecordType, item: Any, index: Int, zoneID: CKRecordZone.ID, allItems: [Any]) -> CKRecord? {
+ itemHandler.record(for: type, item: item, index: index, zoneID: zoneID, allItems: allItems)
+ }
+
+ func deleteEntries(_ entries: [EntityOfKind]) {
+ deletedEntries = entries
+ }
+
+ func updateOrCreate(with entries: [CKRecord]) {
+ updatedCreated = entries
+ }
+}
diff --git a/TwoFAS/Sync/Log/LogEntity+CoreDataClass.swift b/TwoFAS/Sync/Log/LogEntity+CoreDataClass.swift
index 2edaf7ea..b6ef4835 100644
--- a/TwoFAS/Sync/Log/LogEntity+CoreDataClass.swift
+++ b/TwoFAS/Sync/Log/LogEntity+CoreDataClass.swift
@@ -19,7 +19,11 @@
import Foundation
import CoreData
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
@objc(LogEntity)
final class LogEntity: NSManagedObject {
diff --git a/TwoFAS/Sync/Log/LogHandler.swift b/TwoFAS/Sync/Log/LogHandler.swift
index 19569062..d68e8a39 100644
--- a/TwoFAS/Sync/Log/LogHandler.swift
+++ b/TwoFAS/Sync/Log/LogHandler.swift
@@ -18,7 +18,11 @@
//
import Foundation
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
import CoreData
public enum LogActionType: String {
diff --git a/TwoFAS/Sync/Other/CloudKitErrorParser.swift b/TwoFAS/Sync/Other/CloudKitErrorParser.swift
index 7696291a..685e3ffe 100644
--- a/TwoFAS/Sync/Other/CloudKitErrorParser.swift
+++ b/TwoFAS/Sync/Other/CloudKitErrorParser.swift
@@ -19,7 +19,11 @@
import Foundation
import CloudKit
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
enum CloudKitAction {
enum Reason {
diff --git a/TwoFAS/Sync/Other/DynamicTypesEntityMigrationPolicySync.swift b/TwoFAS/Sync/Other/DynamicTypesEntityMigrationPolicySync.swift
index 638e0164..ca236bba 100644
--- a/TwoFAS/Sync/Other/DynamicTypesEntityMigrationPolicySync.swift
+++ b/TwoFAS/Sync/Other/DynamicTypesEntityMigrationPolicySync.swift
@@ -19,7 +19,11 @@
import Foundation
import CoreData
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
@objc(DynamicTypesEntityMigrationPolicySync)
final class DynamicTypesEntityMigrationPolicySync: NSEntityMigrationPolicy {
diff --git a/TwoFAS/Sync/Other/Extensions.swift b/TwoFAS/Sync/Other/Extensions.swift
index 81e6c784..e3aa0bff 100644
--- a/TwoFAS/Sync/Other/Extensions.swift
+++ b/TwoFAS/Sync/Other/Extensions.swift
@@ -18,7 +18,11 @@
//
import Foundation
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
extension ServiceData {
var comparisionDate: Date {
diff --git a/TwoFAS/Sync/Other/SecretValidation.swift b/TwoFAS/Sync/Other/SecretValidation.swift
index 94da4f4b..b26f9669 100644
--- a/TwoFAS/Sync/Other/SecretValidation.swift
+++ b/TwoFAS/Sync/Other/SecretValidation.swift
@@ -18,7 +18,11 @@
//
import Foundation
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
enum SecretValidation {
private static let maxLenght: Int = 255
diff --git a/TwoFAS/Sync/Other/Types.swift b/TwoFAS/Sync/Other/Types.swift
index 60cd012e..d76a3f3e 100644
--- a/TwoFAS/Sync/Other/Types.swift
+++ b/TwoFAS/Sync/Other/Types.swift
@@ -19,5 +19,17 @@
import Foundation
+#if os(iOS)
+import UIKit
+#elseif os(watchOS)
+import WatchKit
+#endif
+
typealias Callback = () -> Void
typealias EntityOfKind = (entityID: String, type: RecordType)
+
+#if os(iOS)
+public typealias BackgroundFetchResult = UIBackgroundFetchResult
+#elseif os(watchOS)
+public typealias BackgroundFetchResult = WKBackgroundFetchResult
+#endif
diff --git a/TwoFAS/Sync/Other/iCloudIdentifier.swift b/TwoFAS/Sync/Other/iCloudIdentifier.swift
index 375ec460..da880931 100644
--- a/TwoFAS/Sync/Other/iCloudIdentifier.swift
+++ b/TwoFAS/Sync/Other/iCloudIdentifier.swift
@@ -18,8 +18,12 @@
//
import Foundation
-import Common
import CryptoKit
+#if os(iOS)
+import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
enum iCloudIdentifier {
private static let v2Identifier = "_V2"
diff --git a/TwoFAS/Sync/Section/SectionCacheEntity+CoreDataClass.swift b/TwoFAS/Sync/Section/SectionCacheEntity+CoreDataClass.swift
index 98cff028..1c2b99c1 100644
--- a/TwoFAS/Sync/Section/SectionCacheEntity+CoreDataClass.swift
+++ b/TwoFAS/Sync/Section/SectionCacheEntity+CoreDataClass.swift
@@ -19,7 +19,11 @@
import Foundation
import CoreData
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
@objc(SectionCacheEntity)
final class SectionCacheEntity: NSManagedObject {
diff --git a/TwoFAS/Sync/Section/SectionHandler.swift b/TwoFAS/Sync/Section/SectionHandler.swift
index b97a1200..04aa768c 100644
--- a/TwoFAS/Sync/Section/SectionHandler.swift
+++ b/TwoFAS/Sync/Section/SectionHandler.swift
@@ -18,7 +18,11 @@
//
import Foundation
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
import CoreData
final class SectionHandler {
diff --git a/TwoFAS/Sync/Service/ServiceCacheEntity+CoreDataClass.swift b/TwoFAS/Sync/Service/ServiceCacheEntity+CoreDataClass.swift
index a5a67b25..1611046b 100644
--- a/TwoFAS/Sync/Service/ServiceCacheEntity+CoreDataClass.swift
+++ b/TwoFAS/Sync/Service/ServiceCacheEntity+CoreDataClass.swift
@@ -19,7 +19,11 @@
import Foundation
import CoreData
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
@objc(ServiceCacheEntity)
final class ServiceCacheEntity: NSManagedObject {
diff --git a/TwoFAS/Sync/Service/ServiceCacheEntity+toServiceData.swift b/TwoFAS/Sync/Service/ServiceCacheEntity+toServiceData.swift
index 12f51d9e..c16351be 100644
--- a/TwoFAS/Sync/Service/ServiceCacheEntity+toServiceData.swift
+++ b/TwoFAS/Sync/Service/ServiceCacheEntity+toServiceData.swift
@@ -18,7 +18,11 @@
//
import Foundation
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
extension ServiceCacheEntity {
var serviceData: ServiceData {
diff --git a/TwoFAS/Sync/Service/ServiceHandler.swift b/TwoFAS/Sync/Service/ServiceHandler.swift
index ee4b9db8..195afd57 100644
--- a/TwoFAS/Sync/Service/ServiceHandler.swift
+++ b/TwoFAS/Sync/Service/ServiceHandler.swift
@@ -18,9 +18,14 @@
//
import Foundation
-import Common
import CoreData
+#if os(iOS)
+import Common
import Protection
+#elseif os(watchOS)
+import CommonWatch
+import ProtectionWatch
+#endif
final class ServiceHandler {
private let coreDataStack: CoreDataStack
diff --git a/TwoFAS/Sync/Service/ServiceRecord.swift b/TwoFAS/Sync/Service/ServiceRecord.swift
index 0ae0278b..2e7ebf2e 100644
--- a/TwoFAS/Sync/Service/ServiceRecord.swift
+++ b/TwoFAS/Sync/Service/ServiceRecord.swift
@@ -19,7 +19,11 @@
import Foundation
import CloudKit
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
enum ServiceEntryKey: String {
case name
diff --git a/TwoFAS/Sync/Service/ServiceRecord2.swift b/TwoFAS/Sync/Service/ServiceRecord2.swift
index 08eaf4d3..ba57e999 100644
--- a/TwoFAS/Sync/Service/ServiceRecord2.swift
+++ b/TwoFAS/Sync/Service/ServiceRecord2.swift
@@ -19,7 +19,11 @@
import Foundation
import CloudKit
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
enum ServiceEntryKey2: String {
case name
diff --git a/TwoFAS/Sync/SyncHandler.swift b/TwoFAS/Sync/SyncHandler.swift
index 48f2610a..d75982b2 100644
--- a/TwoFAS/Sync/SyncHandler.swift
+++ b/TwoFAS/Sync/SyncHandler.swift
@@ -18,7 +18,11 @@
//
import UIKit
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
import CloudKit
final class SyncHandler {
@@ -32,7 +36,7 @@ final class SyncHandler {
private var timeOffset: Int = 0
- private var fromNotificationCompletionHandler: ((UIBackgroundFetchResult) -> Void)?
+ private var fromNotificationCompletionHandler: ((BackgroundFetchResult) -> Void)?
typealias OtherError = (NSError) -> Void
@@ -60,7 +64,17 @@ final class SyncHandler {
cloudKit.deletedEntries = { [weak self] entries in self?.deleteEntries(entries) }
cloudKit.updatedEntries = { [weak self] entries in self?.updateEntries(entries) }
- cloudKit.fetchFinishedSuccessfuly = { [weak self] in self?.fetchFinishedSuccessfuly() }
+ cloudKit.fetchFinishedSuccessfuly = { [weak self] in
+ #if os(watchOS)
+ Log("SyncHandler - WatchOS doesn't modify iCloud - returning", module: .cloudSync)
+ self?.itemHandler.commit()
+ self?.logHandler.deleteAll()
+ self?.applyingChanges = false
+ self?.syncCompleted()
+ #else
+ self?.fetchFinishedSuccessfuly()
+ #endif
+ }
cloudKit.changesSavedSuccessfuly = { [weak self] in self?.changesSavedSuccessfuly() }
cloudKit.abortSync = { [weak self] in self?.abortSync() }
@@ -93,8 +107,9 @@ final class SyncHandler {
func didReceiveRemoteNotification(
userInfo: [AnyHashable: Any],
- fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void
+ fetchCompletionHandler completionHandler: @escaping (BackgroundFetchResult) -> Void
) {
+ #if os(iOS)
let dict = userInfo as! [String: NSObject]
guard let notification: CKDatabaseNotification = CKNotification(
fromRemoteNotificationDictionary: dict
@@ -103,6 +118,10 @@ final class SyncHandler {
return
}
Log("SyncHandler - We have a notification! \(notification)", module: .cloudSync)
+ #elseif os(watchOS)
+ Log("SyncHandler - We have a notification!", module: .cloudSync)
+ #endif
+
fromNotificationCompletionHandler = completionHandler
synchronize()
}
diff --git a/TwoFAS/Sync/SyncInstanceWatch.swift b/TwoFAS/Sync/SyncInstanceWatch.swift
new file mode 100644
index 00000000..1bc03433
--- /dev/null
+++ b/TwoFAS/Sync/SyncInstanceWatch.swift
@@ -0,0 +1,97 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2023 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import Foundation
+import CloudKit
+import CommonWatch
+
+public enum SyncInstanceWatch {
+ private static var cloudHandler: CloudHandlerType!
+ private static var logDataChangeImpl: LogDataChangeImpl!
+
+ public static func initialize(
+ commonSectionHandler: CommonSectionHandler,
+ commonServiceHandler: CommonServiceHandler,
+ errorLog: @escaping (String) -> Void
+ ) {
+ coreDataStack.logError = { errorLog($0) }
+
+ let logHandler = LogHandler(coreDataStack: coreDataStack)
+ let sectionHandler = SectionHandler(coreDataStack: coreDataStack)
+ let serviceHandler = ServiceHandler(coreDataStack: coreDataStack)
+ let infoHandler = InfoHandler()
+ let commonItemHandler = CommonItemHandler(
+ commonSectionHandler: commonSectionHandler,
+ commonServiceHandler: commonServiceHandler,
+ logHandler: logHandler
+ )
+ let cloudKit = CloudKit()
+
+ let itemHandler = ItemHandler(
+ sectionHandler: sectionHandler,
+ serviceHandler: serviceHandler,
+ infoHandler: infoHandler,
+ logHandler: logHandler
+ )
+ let itemHandlerMigrationProxy = ItemHandlerMigrationProxy(
+ itemHandler: itemHandler
+ )
+ let syncHandler = SyncHandler(
+ itemHandler: itemHandlerMigrationProxy,
+ commonItemHandler: commonItemHandler,
+ logHandler: logHandler,
+ cloudKit: cloudKit
+ )
+ let cloudAvailability = CloudAvailability(container: syncHandler.container)
+ cloudHandler = CloudHandler(
+ cloudAvailability: cloudAvailability,
+ syncHandler: syncHandler,
+ itemHandler: itemHandler,
+ itemHandlerMigrationProxy: itemHandlerMigrationProxy,
+ cloudKit: cloudKit
+ )
+
+ logDataChangeImpl = LogDataChangeImpl(logHandler: logHandler)
+ }
+ public static func getCloudHandler() -> CloudHandlerType { cloudHandler }
+
+ public static func didReceiveRemoteNotification(
+ userInfo: [AnyHashable: Any],
+ fetchCompletionHandler completionHandler: @escaping (BackgroundFetchResult) -> Void
+ ) {
+ cloudHandler.didReceiveRemoteNotification(userInfo: userInfo, fetchCompletionHandler: completionHandler)
+ }
+
+ public static var logDataChange: LogDataChange {
+ logDataChangeImpl
+ }
+
+ public static func migrateStoreIfNeeded() {
+ coreDataStack.performInBackground { context in
+ Log("Migrating if needed. Trigger value \(context.hasChanges)", module: .cloudSync)
+ }
+ }
+
+ private static let coreDataStack = CoreDataStack(
+ readOnly: false,
+ name: "Sync",
+ bundle: Bundle(for: SyncHandler.self),
+ migrator: nil
+ )
+}
diff --git a/TwoFAS/Sync/SyncTokenHandler.swift b/TwoFAS/Sync/SyncTokenHandler.swift
index 64ef85b4..332bfa01 100644
--- a/TwoFAS/Sync/SyncTokenHandler.swift
+++ b/TwoFAS/Sync/SyncTokenHandler.swift
@@ -19,7 +19,11 @@
import Foundation
import CloudKit
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
final class SyncTokenHandler {
private var databaseChangeToken: CKServerChangeToken?
diff --git a/TwoFAS/Sync/Watch/Sync.xcdatamodeld/Sync.xcdatamodel/contents b/TwoFAS/Sync/Watch/Sync.xcdatamodeld/Sync.xcdatamodel/contents
new file mode 100644
index 00000000..6963d27f
--- /dev/null
+++ b/TwoFAS/Sync/Watch/Sync.xcdatamodeld/Sync.xcdatamodel/contents
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TwoFAS/TimeVerification/TimeVerificationController.swift b/TwoFAS/TimeVerification/TimeVerificationController.swift
index dd3af13e..6e5a78b9 100644
--- a/TwoFAS/TimeVerification/TimeVerificationController.swift
+++ b/TwoFAS/TimeVerification/TimeVerificationController.swift
@@ -18,7 +18,11 @@
//
import Foundation
+#if os(iOS)
import Common
+#elseif os(watchOS)
+import CommonWatch
+#endif
public final class TimeVerificationController {
private let timeVerificator: TimeVerificator
diff --git a/TwoFAS/TwoFAS.xcodeproj/project.pbxproj b/TwoFAS/TwoFAS.xcodeproj/project.pbxproj
index 609ff115..b17ded86 100644
--- a/TwoFAS/TwoFAS.xcodeproj/project.pbxproj
+++ b/TwoFAS/TwoFAS.xcodeproj/project.pbxproj
@@ -73,6 +73,48 @@
C21247F827B70D420044D9F2 /* LabelComposeFlowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C21247F727B70D420044D9F2 /* LabelComposeFlowController.swift */; };
C21247FB27B7181A0044D9F2 /* ComposeServiceModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = C21247FA27B7181A0044D9F2 /* ComposeServiceModels.swift */; };
C212ACDE2AF6F929001C8665 /* RootInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C212ACDD2AF6F929001C8665 /* RootInteractor.swift */; };
+ C213BC192BAC3BD5000794C9 /* CommonItemHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C24EECF926878C5C00C6ABAA /* CommonItemHandler.swift */; };
+ C213BC202BAC3C82000794C9 /* Storage.h in Headers */ = {isa = PBXBuildFile; fileRef = C200E49C1FB3911B00D7C748 /* Storage.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ C213BC232BAC3C82000794C9 /* StorageRepositoryImpl+CategoriesSections.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2BDF4512868B39000D46FA4 /* StorageRepositoryImpl+CategoriesSections.swift */; };
+ C213BC242BAC3C82000794C9 /* CategoryData.swift in Sources */ = {isa = PBXBuildFile; fileRef = C22C1398267682B4001AA5F1 /* CategoryData.swift */; };
+ C213BC252BAC3C82000794C9 /* StorageRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27ABD30277A450C00AE073B /* StorageRepository.swift */; };
+ C213BC262BAC3C82000794C9 /* StorageRepositoryImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27ABD32277A453000AE073B /* StorageRepositoryImpl.swift */; };
+ C213BC272BAC3C82000794C9 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2B3D1A7267E6BEC009E6DE0 /* Extensions.swift */; };
+ C213BC292BAC3C82000794C9 /* StorageRepositoryImpl+AuthRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2FA3E7C280ADCC90097ED71 /* StorageRepositoryImpl+AuthRequest.swift */; };
+ C213BC2A2BAC3C82000794C9 /* ServiceHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C200E4AA1FB3913A00D7C748 /* ServiceHandler.swift */; };
+ C213BC2D2BAC3C82000794C9 /* StorageRepositoryImpl+Pairing.swift in Sources */ = {isa = PBXBuildFile; fileRef = C258594E280374F4002DC749 /* StorageRepositoryImpl+Pairing.swift */; };
+ C213BC2E2BAC3C82000794C9 /* StorageRepositoryImpl+News.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2D39DE22823302200E864E9 /* StorageRepositoryImpl+News.swift */; };
+ C213BC2F2BAC3C82000794C9 /* LogEntryEntity+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = C22CF3E127414073004F6A03 /* LogEntryEntity+CoreDataClass.swift */; };
+ C213BC302BAC3C82000794C9 /* PairingEntity+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = C258594428034E85002DC749 /* PairingEntity+CoreDataClass.swift */; };
+ C213BC312BAC3C82000794C9 /* AuthRequestEntity+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = C258594A28035205002DC749 /* AuthRequestEntity+CoreDataClass.swift */; };
+ C213BC322BAC3C82000794C9 /* LogEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = C22CF3E5274143A1004F6A03 /* LogEntry.swift */; };
+ C213BC332BAC3C82000794C9 /* CategoryHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C22C139A267684DC001AA5F1 /* CategoryHandler.swift */; };
+ C213BC342BAC3C82000794C9 /* SectionEntity+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C25E8993266402AD00A60CE5 /* SectionEntity+CoreDataProperties.swift */; };
+ C213BC352BAC3C82000794C9 /* ServiceOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2872DDF27A6EFB0000F5AE9 /* ServiceOptions.swift */; };
+ C213BC362BAC3C82000794C9 /* AuthRequestFilterOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2FA3E7A280AD60D0097ED71 /* AuthRequestFilterOptions.swift */; };
+ C213BC372BAC3C82000794C9 /* NewsEntity+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2D39DDB28232A4E00E864E9 /* NewsEntity+CoreDataClass.swift */; };
+ C213BC382BAC3C82000794C9 /* ServiceEntity+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27FBA4B1FBA23DD00D424D8 /* ServiceEntity+CoreDataProperties.swift */; };
+ C213BC392BAC3C82000794C9 /* LogHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C22CF3E727416271004F6A03 /* LogHandler.swift */; };
+ C213BC3A2BAC3C82000794C9 /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C200E4AD1FB3913A00D7C748 /* Storage.swift */; };
+ C213BC3B2BAC3C82000794C9 /* LogStorage.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = C22CF3DD27413F0F004F6A03 /* LogStorage.xcdatamodeld */; };
+ C213BC3C2BAC3C82000794C9 /* NewsEntity+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2D39DDC28232A4E00E864E9 /* NewsEntity+CoreDataProperties.swift */; };
+ C213BC3E2BAC3C82000794C9 /* AuthRequestEntityToPairedAuthRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2FA3E7E280ADDB40097ED71 /* AuthRequestEntityToPairedAuthRequest.swift */; };
+ C213BC402BAC3C82000794C9 /* ServiceEntity+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27FBA471FBA239600D424D8 /* ServiceEntity+CoreDataClass.swift */; };
+ C213BC412BAC3C82000794C9 /* SectionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2DEC7A226767B28006DB1E6 /* SectionHandler.swift */; };
+ C213BC422BAC3C82000794C9 /* AuthRequestEntity+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C258594B28035205002DC749 /* AuthRequestEntity+CoreDataProperties.swift */; };
+ C213BC432BAC3C82000794C9 /* SectionEntity+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = C25E8992266402AD00A60CE5 /* SectionEntity+CoreDataClass.swift */; };
+ C213BC442BAC3C82000794C9 /* ServiceEntity+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2872DDD27A6DF48000F5AE9 /* ServiceEntity+Extensions.swift */; };
+ C213BC452BAC3C82000794C9 /* SectionData.swift in Sources */ = {isa = PBXBuildFile; fileRef = C25E898F2663F11900A60CE5 /* SectionData.swift */; };
+ C213BC462BAC3C82000794C9 /* LogEntryEntity+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C22CF3E227414073004F6A03 /* LogEntryEntity+CoreDataProperties.swift */; };
+ C213BC472BAC3C82000794C9 /* PairingEntity+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C258594528034E85002DC749 /* PairingEntity+CoreDataProperties.swift */; };
+ C213BC482BAC3C82000794C9 /* ServiceData+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2BDC65C1FBB87C200967D0E /* ServiceData+Extensions.swift */; };
+ C213BC522BAC3C97000794C9 /* CommonWatch.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C274CA232BAB8B92008E7212 /* CommonWatch.framework */; };
+ C213BC562BAC3C97000794C9 /* ContentWatch.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C274CA492BAB8BE3008E7212 /* ContentWatch.framework */; };
+ C213BC5B2BAC3DBF000794C9 /* StorageWatch.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C213BC502BAC3C82000794C9 /* StorageWatch.framework */; };
+ C213BC5C2BAC3DBF000794C9 /* StorageWatch.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C213BC502BAC3C82000794C9 /* StorageWatch.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+ C213BC602BAC3FE3000794C9 /* ServiceMigrationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2ACF9DE20A8A30E003E0987 /* ServiceMigrationController.swift */; };
+ C213BC702BAC5758000794C9 /* TwoFAS.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = C213BC6E2BAC5758000794C9 /* TwoFAS.xcdatamodeld */; };
+ C213BC732BAC5771000794C9 /* Sync.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = C213BC712BAC5771000794C9 /* Sync.xcdatamodeld */; };
C2147CB9205D78600001D011 /* Protection.h in Headers */ = {isa = PBXBuildFile; fileRef = C2147CB7205D78600001D011 /* Protection.h */; settings = {ATTRIBUTES = (Public, ); }; };
C2147CBC205D78600001D011 /* Protection.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2147CB5205D78600001D011 /* Protection.framework */; };
C2147CBD205D78600001D011 /* Protection.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C2147CB5205D78600001D011 /* Protection.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
@@ -209,6 +251,7 @@
C23BAB042545A861009B1EF8 /* CloudKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = C23BAB032545A861009B1EF8 /* CloudKit.swift */; };
C23BAB142545AEF5009B1EF8 /* ConstStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C23BAB132545AEF5009B1EF8 /* ConstStorage.swift */; };
C23EBF122651276800FA9E81 /* Kronos in Frameworks */ = {isa = PBXBuildFile; productRef = C23EBF112651276800FA9E81 /* Kronos */; };
+ C23FC6312BCD49BB0040FE5C /* Assets.car in Resources */ = {isa = PBXBuildFile; fileRef = C23FC62F2BCD49BB0040FE5C /* Assets.car */; };
C23FD50A2814635400E4E9C5 /* ComposeServiceWebExtensionFlowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C23FD5092814635400E4E9C5 /* ComposeServiceWebExtensionFlowController.swift */; };
C23FD5102814648C00E4E9C5 /* ComposeServiceWebExtensionModuleInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C23FD50F2814648C00E4E9C5 /* ComposeServiceWebExtensionModuleInteractor.swift */; };
C23FD51228146E2E00E4E9C5 /* ComposeServiceWebExtensionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C23FD51128146E2E00E4E9C5 /* ComposeServiceWebExtensionPresenter.swift */; };
@@ -348,12 +391,15 @@
C25E8994266402AD00A60CE5 /* SectionEntity+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = C25E8992266402AD00A60CE5 /* SectionEntity+CoreDataClass.swift */; };
C25E8995266402AD00A60CE5 /* SectionEntity+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C25E8993266402AD00A60CE5 /* SectionEntity+CoreDataProperties.swift */; };
C25F4FDB2622207F008F7755 /* TokensViewEmptySearchScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = C25F4FDA2622207F008F7755 /* TokensViewEmptySearchScreen.swift */; };
+ C260DCC22BC885F1007807CC /* ServiceCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C260DCC12BC885F1007807CC /* ServiceCellView.swift */; };
C2625F8C28BB853D00D84C5C /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2625F8B28BB853D00D84C5C /* AboutViewController.swift */; };
C2625F8E28BB858600D84C5C /* AboutPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2625F8D28BB858600D84C5C /* AboutPresenter.swift */; };
C2625F9028BB85B100D84C5C /* AboutModuleInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2625F8F28BB85B100D84C5C /* AboutModuleInteractor.swift */; };
C2625F9228BBB87700D84C5C /* AboutModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2625F9128BBB87700D84C5C /* AboutModels.swift */; };
C2625F9428BBC01900D84C5C /* AboutPresenter+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2625F9328BBC01900D84C5C /* AboutPresenter+Menu.swift */; };
C2625F9628BBC86B00D84C5C /* AboutFooter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2625F9528BBC86B00D84C5C /* AboutFooter.swift */; };
+ C2627F3A2BC72E96009F93A9 /* ServicePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2627F392BC72E96009F93A9 /* ServicePresenter.swift */; };
+ C2627F3C2BC72EA0009F93A9 /* ServiceInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2627F3B2BC72EA0009F93A9 /* ServiceInteractor.swift */; };
C2633F1F265B045F0034B836 /* UIApplication.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2633F1E265B045F0034B836 /* UIApplication.swift */; };
C263F45A29900DED009B0837 /* MainMenuModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = C263F45929900DED009B0837 /* MainMenuModels.swift */; };
C263F45E29901C4F009B0837 /* MainSplitFlowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C263F45D29901C4F009B0837 /* MainSplitFlowController.swift */; };
@@ -372,6 +418,12 @@
C26764B02872483900D468B2 /* ComposeServiceCategorySelectionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C26764AF2872483900D468B2 /* ComposeServiceCategorySelectionPresenter.swift */; };
C26764B22872494100D468B2 /* ComposeServiceCategorySelectionPresenter+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C26764B12872494100D468B2 /* ComposeServiceCategorySelectionPresenter+Menu.swift */; };
C26764B428724A4200D468B2 /* ComposeServiceCategorySelectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C26764B328724A4200D468B2 /* ComposeServiceCategorySelectionViewController.swift */; };
+ C268918A2BC4960600713078 /* ServiceListPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C26891892BC4960600713078 /* ServiceListPresenter.swift */; };
+ C268918D2BC4962300713078 /* ServiceListInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C268918C2BC4962300713078 /* ServiceListInteractor.swift */; };
+ C268918F2BC4974800713078 /* Category.swift in Sources */ = {isa = PBXBuildFile; fileRef = C268918E2BC4974800713078 /* Category.swift */; };
+ C269837B2BCC5D03009B3BE2 /* PINKeyboardPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C269837A2BCC5D03009B3BE2 /* PINKeyboardPresenter.swift */; };
+ C26983802BCC718D009B3BE2 /* PINKeyboardInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C269837F2BCC718D009B3BE2 /* PINKeyboardInteractor.swift */; };
+ C26983822BCC8326009B3BE2 /* AppPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C26983812BCC8326009B3BE2 /* AppPresenter.swift */; };
C2698B632986860F00EBC179 /* SelectServiceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2698B622986860F00EBC179 /* SelectServiceViewController.swift */; };
C2698B652986863E00EBC179 /* ComposeServiceAdvancedEditViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2698B642986863E00EBC179 /* ComposeServiceAdvancedEditViewController.swift */; };
C2698B6C2986B42400EBC179 /* MainTabViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2698B6B2986B42400EBC179 /* MainTabViewController.swift */; };
@@ -408,6 +460,153 @@
C274C7742ADD3CB000B8AAC1 /* CounterState.swift in Sources */ = {isa = PBXBuildFile; fileRef = C24DFB2027D1770D00F3EACC /* CounterState.swift */; };
C274C7762ADD3DF900B8AAC1 /* FirebaseMessaging in Frameworks */ = {isa = PBXBuildFile; productRef = C274C7752ADD3DF900B8AAC1 /* FirebaseMessaging */; };
C274C77C2ADD3E3500B8AAC1 /* FirebaseCrashlytics in Frameworks */ = {isa = PBXBuildFile; productRef = C274C77B2ADD3E3500B8AAC1 /* FirebaseCrashlytics */; };
+ C274C9942BAB89C7008E7212 /* Sync.h in Headers */ = {isa = PBXBuildFile; fileRef = C24D1C1C253C744E0029D27D /* Sync.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ C274C9962BAB89C7008E7212 /* CloudKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = C23BAB032545A861009B1EF8 /* CloudKit.swift */; };
+ C274C9972BAB89C7008E7212 /* SecretValidation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C201F24C25BDD017001DA257 /* SecretValidation.swift */; };
+ C274C9992BAB89C7008E7212 /* SectionCacheEntity+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = C24EECEF2687772800C6ABAA /* SectionCacheEntity+CoreDataClass.swift */; };
+ C274C99A2BAB89C7008E7212 /* LogDataChange.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2058E08277D24940015F17E /* LogDataChange.swift */; };
+ C274C99B2BAB89C7008E7212 /* ItemHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2C4F64628FDEF8400285B81 /* ItemHandling.swift */; };
+ C274C99C2BAB89C7008E7212 /* ServiceCacheEntity+toServiceData.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27E6FB728FC995100AC9FD1 /* ServiceCacheEntity+toServiceData.swift */; };
+ C274C99D2BAB89C7008E7212 /* ConstStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C23BAB132545AEF5009B1EF8 /* ConstStorage.swift */; };
+ C274C99E2BAB89C7008E7212 /* CloudKitErrorParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = C207C11E2559F1CB0053975E /* CloudKitErrorParser.swift */; };
+ C274C99F2BAB89C7008E7212 /* SectionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C24EECF5268787B400C6ABAA /* SectionHandler.swift */; };
+ C274C9A02BAB89C7008E7212 /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2F543DC25672E7600611716 /* Types.swift */; };
+ C274C9A22BAB89C7008E7212 /* CloudHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2D507B5256477DA00151359 /* CloudHandler.swift */; };
+ C274C9A32BAB89C7008E7212 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C244EF10268674650040A58F /* Extensions.swift */; };
+ C274C9A42BAB89C7008E7212 /* LogHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2D61E512560393000C5BE3A /* LogHandler.swift */; };
+ C274C9A52BAB89C7008E7212 /* SectionCacheEntity+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C24EECF02687772800C6ABAA /* SectionCacheEntity+CoreDataProperties.swift */; };
+ C274C9A62BAB89C7008E7212 /* RecordType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C24EECEB268772B600C6ABAA /* RecordType.swift */; };
+ C274C9A72BAB89C7008E7212 /* ClearHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2EFCE0625D05E320031293F /* ClearHandler.swift */; };
+ C274C9A82BAB89C7008E7212 /* SyncTokenHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2A7ABF1286328E60085CFEF /* SyncTokenHandler.swift */; };
+ C274C9A92BAB89C7008E7212 /* ServiceRecord2.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27E6FB028FC7E3800AC9FD1 /* ServiceRecord2.swift */; };
+ C274C9AA2BAB89C7008E7212 /* LogEntity+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2D61E3025602F4100C5BE3A /* LogEntity+CoreDataProperties.swift */; };
+ C274C9AB2BAB89C7008E7212 /* CloudAvailability.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2EF21D625630C9D0075743D /* CloudAvailability.swift */; };
+ C274C9AC2BAB89C7008E7212 /* ServiceCacheEntity+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2EF402425582AFB0006735E /* ServiceCacheEntity+CoreDataClass.swift */; };
+ C274C9AD2BAB89C7008E7212 /* DynamicTypesEntityMigrationPolicySync.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27E6FAE28FC57FD00AC9FD1 /* DynamicTypesEntityMigrationPolicySync.swift */; };
+ C274C9B12BAB89C7008E7212 /* ServiceRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2EF3F6D25575D730006735E /* ServiceRecord.swift */; };
+ C274C9B22BAB89C7008E7212 /* iCloudIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2D75D36297D51B60002531E /* iCloudIdentifier.swift */; };
+ C274C9B32BAB89C7008E7212 /* ServiceCacheEntity+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2EF402525582AFB0006735E /* ServiceCacheEntity+CoreDataProperties.swift */; };
+ C274C9B42BAB89C7008E7212 /* ServiceHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2EF4044255860FC0006735E /* ServiceHandler.swift */; };
+ C274C9B52BAB89C7008E7212 /* ItemHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C24EECF7268789DE00C6ABAA /* ItemHandler.swift */; };
+ C274C9B62BAB89C7008E7212 /* SyncHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C23BAAF32545A1E9009B1EF8 /* SyncHandler.swift */; };
+ C274C9B72BAB89C7008E7212 /* SectionRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = C24EECF32687837D00C6ABAA /* SectionRecord.swift */; };
+ C274C9B82BAB89C7008E7212 /* LogEntity+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2D61E2F25602F4100C5BE3A /* LogEntity+CoreDataClass.swift */; };
+ C274C9BA2BAB89C7008E7212 /* InfoRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27E6FB228FC87AD00AC9FD1 /* InfoRecord.swift */; };
+ C274C9BB2BAB89C7008E7212 /* InfoHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2C4F64A28FE08EB00285B81 /* InfoHandler.swift */; };
+ C274C9BC2BAB89C7008E7212 /* Info.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27E6FB528FC8B0000AC9FD1 /* Info.swift */; };
+ C274C9BD2BAB89C7008E7212 /* RecordIDGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2C4F64828FE002F00285B81 /* RecordIDGenerator.swift */; };
+ C274C9D02BAB8ABB008E7212 /* TwoFASWatchApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = C274C9CF2BAB8ABB008E7212 /* TwoFASWatchApp.swift */; };
+ C274C9D42BAB8ABC008E7212 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C274C9D32BAB8ABC008E7212 /* Assets.xcassets */; };
+ C274C9D72BAB8ABC008E7212 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C274C9D62BAB8ABC008E7212 /* Preview Assets.xcassets */; };
+ C274C9DA2BAB8ABC008E7212 /* TwoFASWatch Watch App.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = C274C9CD2BAB8ABB008E7212 /* TwoFASWatch Watch App.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
+ C274C9DF2BAB8B2E008E7212 /* SyncWatch.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C274C9C62BAB89C7008E7212 /* SyncWatch.framework */; };
+ C274C9E02BAB8B2E008E7212 /* SyncWatch.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C274C9C62BAB89C7008E7212 /* SyncWatch.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+ C274C9E62BAB8B92008E7212 /* Common.h in Headers */ = {isa = PBXBuildFile; fileRef = C2E53AC72B62DD6C008E1E70 /* Common.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ C274C9E82BAB8B92008E7212 /* Collection+.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AFF2B62DDAF008E1E70 /* Collection+.swift */; };
+ C274C9E92BAB8B92008E7212 /* String+.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B012B62DDAF008E1E70 /* String+.swift */; };
+ C274C9EA2BAB8B92008E7212 /* EncryptionHolder.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AD72B62DDAF008E1E70 /* EncryptionHolder.swift */; };
+ C274C9EB2BAB8B92008E7212 /* CommonSectionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B0A2B62DDAF008E1E70 /* CommonSectionHandler.swift */; };
+ C274C9EC2BAB8B92008E7212 /* LegacyServiceDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53ADD2B62DDAF008E1E70 /* LegacyServiceDatabase.swift */; };
+ C274C9ED2BAB8B92008E7212 /* CoreDataMigrator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AE32B62DDAF008E1E70 /* CoreDataMigrator.swift */; };
+ C274C9EF2BAB8B92008E7212 /* Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AD92B62DDAF008E1E70 /* Log.swift */; };
+ C274C9F02BAB8B92008E7212 /* CountdownTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AD82B62DDAF008E1E70 /* CountdownTimer.swift */; };
+ C274C9F12BAB8B92008E7212 /* CommonLocalKeyEncryption.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B0C2B62DDAF008E1E70 /* CommonLocalKeyEncryption.swift */; };
+ C274C9F22BAB8B92008E7212 /* PairedAuthRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AF22B62DDAF008E1E70 /* PairedAuthRequest.swift */; };
+ C274C9F32BAB8B92008E7212 /* IconDescriptionGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AE82B62DDAF008E1E70 /* IconDescriptionGroup.swift */; };
+ C274C9F42BAB8B92008E7212 /* ListNewsEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AFB2B62DDAF008E1E70 /* ListNewsEntry.swift */; };
+ C274C9F52BAB8B92008E7212 /* ServiceData.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AEE2B62DDAF008E1E70 /* ServiceData.swift */; };
+ C274C9F62BAB8B92008E7212 /* PushNotificationsConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AD52B62DDAF008E1E70 /* PushNotificationsConfig.swift */; };
+ C274C9F72BAB8B92008E7212 /* ServiceRules.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AD22B62DDAF008E1E70 /* ServiceRules.swift */; };
+ C274C9F82BAB8B92008E7212 /* ServiceData+.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AFE2B62DDAF008E1E70 /* ServiceData+.swift */; };
+ C274C9F92BAB8B92008E7212 /* Notifications+.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B042B62DDAF008E1E70 /* Notifications+.swift */; };
+ C274C9FA2BAB8B92008E7212 /* Array+.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B002B62DDAF008E1E70 /* Array+.swift */; };
+ C274C9FB2BAB8B92008E7212 /* CommonServiceHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B0B2B62DDAF008E1E70 /* CommonServiceHandler.swift */; };
+ C274C9FC2BAB8B92008E7212 /* ServiceMatchRules+.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B022B62DDAF008E1E70 /* ServiceMatchRules+.swift */; };
+ C274C9FD2BAB8B92008E7212 /* Character+.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AFD2B62DDAF008E1E70 /* Character+.swift */; };
+ C274C9FE2BAB8B92008E7212 /* CoreDataMigrationVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AE22B62DDAF008E1E70 /* CoreDataMigrationVersion.swift */; };
+ C274C9FF2BAB8B92008E7212 /* LogoType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AFA2B62DDAF008E1E70 /* LogoType.swift */; };
+ C274CA002BAB8B92008E7212 /* IconDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AF72B62DDAF008E1E70 /* IconDescription.swift */; };
+ C274CA012BAB8B92008E7212 /* ServiceExistenceStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AE72B62DDAF008E1E70 /* ServiceExistenceStatus.swift */; };
+ C274CA022BAB8B92008E7212 /* ServiceDefinition.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AF52B62DDAF008E1E70 /* ServiceDefinition.swift */; };
+ C274CA032BAB8B92008E7212 /* Period.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AE92B62DDAF008E1E70 /* Period.swift */; };
+ C274CA042BAB8B92008E7212 /* IconType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AEA2B62DDAF008E1E70 /* IconType.swift */; };
+ C274CA052BAB8B92008E7212 /* LastNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AF32B62DDAF008E1E70 /* LastNotification.swift */; };
+ C274CA062BAB8B92008E7212 /* HOTPDefaultValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AF82B62DDAF008E1E70 /* HOTPDefaultValue.swift */; };
+ C274CA072BAB8B92008E7212 /* CoreDataStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AE12B62DDAF008E1E70 /* CoreDataStack.swift */; };
+ C274CA082BAB8B92008E7212 /* VersionDecoded.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AED2B62DDAF008E1E70 /* VersionDecoded.swift */; };
+ C274CA092BAB8B92008E7212 /* ListStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AF02B62DDAF008E1E70 /* ListStyle.swift */; };
+ C274CA0A2BAB8B92008E7212 /* RefreshTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53ADA2B62DDAF008E1E70 /* RefreshTimer.swift */; };
+ C274CA0B2BAB8B92008E7212 /* CoreDataMigrationStep.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AE02B62DDAF008E1E70 /* CoreDataMigrationStep.swift */; };
+ C274CA0C2BAB8B92008E7212 /* ThemeMetrics.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AD42B62DDAF008E1E70 /* ThemeMetrics.swift */; };
+ C274CA0D2BAB8B92008E7212 /* Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AD32B62DDAF008E1E70 /* Config.swift */; };
+ C274CA0E2BAB8B92008E7212 /* LegacyExchangeDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53ADE2B62DDAF008E1E70 /* LegacyExchangeDatabase.swift */; };
+ C274CA0F2BAB8B92008E7212 /* TokenType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AF62B62DDAF008E1E70 /* TokenType.swift */; };
+ C274CA102BAB8B92008E7212 /* CommonSectionData.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AEB2B62DDAF008E1E70 /* CommonSectionData.swift */; };
+ C274CA112BAB8B92008E7212 /* Date+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B052B62DDAF008E1E70 /* Date+Extensions.swift */; };
+ C274CA122BAB8B92008E7212 /* AttributedText+Formatting.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B032B62DDAF008E1E70 /* AttributedText+Formatting.swift */; };
+ C274CA132BAB8B92008E7212 /* WidgetServiceHandlerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AE52B62DDAF008E1E70 /* WidgetServiceHandlerType.swift */; };
+ C274CA142BAB8B92008E7212 /* TintColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B072B62DDAF008E1E70 /* TintColor.swift */; };
+ C274CA152BAB8B92008E7212 /* PairedWebExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AF12B62DDAF008E1E70 /* PairedWebExtension.swift */; };
+ C274CA162BAB8B92008E7212 /* Digits.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AEC2B62DDAF008E1E70 /* Digits.swift */; };
+ C274CA172BAB8B92008E7212 /* SortType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AF92B62DDAF008E1E70 /* SortType.swift */; };
+ C274CA182BAB8B92008E7212 /* TypeAliases.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AF42B62DDAF008E1E70 /* TypeAliases.swift */; };
+ C274CA192BAB8B92008E7212 /* Algorithm.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AEF2B62DDAF008E1E70 /* Algorithm.swift */; };
+ C274CA1A2BAB8B92008E7212 /* ServiceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53ADC2B62DDAF008E1E70 /* ServiceType.swift */; };
+ C274CA1B2BAB8B92008E7212 /* ServiceSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53AE62B62DDAF008E1E70 /* ServiceSource.swift */; };
+ C274CA1E2BAB8B92008E7212 /* TintColor.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C2E53B0F2B62DDAF008E1E70 /* TintColor.xcassets */; };
+ C274CA1F2BAB8B92008E7212 /* ThemeColor.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C2E53B0E2B62DDAF008E1E70 /* ThemeColor.xcassets */; };
+ C274CA282BAB8BE3008E7212 /* Content.h in Headers */ = {isa = PBXBuildFile; fileRef = C2E53B4D2B62DDCB008E1E70 /* Content.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ C274CA2A2BAB8BE3008E7212 /* IconDescriptionDatabaseImpl+Database5.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B652B62DDFB008E1E70 /* IconDescriptionDatabaseImpl+Database5.swift */; };
+ C274CA2B2BAB8BE3008E7212 /* IconDescriptionDatabaseImpl+Database7.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B662B62DDFB008E1E70 /* IconDescriptionDatabaseImpl+Database7.swift */; };
+ C274CA2C2BAB8BE3008E7212 /* ServiceDefinitionDatabaseImpl+Database5.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B642B62DDFB008E1E70 /* ServiceDefinitionDatabaseImpl+Database5.swift */; };
+ C274CA2D2BAB8BE3008E7212 /* IconDescriptionDatabaseImpl+Database3.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B5F2B62DDFB008E1E70 /* IconDescriptionDatabaseImpl+Database3.swift */; };
+ C274CA2E2BAB8BE3008E7212 /* IconDescriptionDatabaseImpl+Database6.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B5C2B62DDFB008E1E70 /* IconDescriptionDatabaseImpl+Database6.swift */; };
+ C274CA2F2BAB8BE3008E7212 /* ServiceDefinitionDatabaseImpl+Database8.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B6C2B62DDFB008E1E70 /* ServiceDefinitionDatabaseImpl+Database8.swift */; };
+ C274CA302BAB8BE3008E7212 /* IconDescriptionDatabaseImpl+Database2.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B5A2B62DDFB008E1E70 /* IconDescriptionDatabaseImpl+Database2.swift */; };
+ C274CA312BAB8BE3008E7212 /* IconDescriptionDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B612B62DDFB008E1E70 /* IconDescriptionDatabase.swift */; };
+ C274CA322BAB8BE3008E7212 /* IconDescriptionDatabaseImpl+Database0.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B572B62DDFB008E1E70 /* IconDescriptionDatabaseImpl+Database0.swift */; };
+ C274CA332BAB8BE3008E7212 /* ServiceDefinitionDatabaseImpl+Database2.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B592B62DDFB008E1E70 /* ServiceDefinitionDatabaseImpl+Database2.swift */; };
+ C274CA342BAB8BE3008E7212 /* ServiceDefinitionDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B6A2B62DDFB008E1E70 /* ServiceDefinitionDatabase.swift */; };
+ C274CA352BAB8BE3008E7212 /* ServiceDefinitionDatabaseImpl+Database6.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B5B2B62DDFB008E1E70 /* ServiceDefinitionDatabaseImpl+Database6.swift */; };
+ C274CA362BAB8BE3008E7212 /* ServiceDefinitionDatabaseImpl+Database4.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B5E2B62DDFB008E1E70 /* ServiceDefinitionDatabaseImpl+Database4.swift */; };
+ C274CA372BAB8BE3008E7212 /* IconDescriptionDatabaseImpl+Database9.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B682B62DDFB008E1E70 /* IconDescriptionDatabaseImpl+Database9.swift */; };
+ C274CA382BAB8BE3008E7212 /* IconDescriptionDatabaseImpl+Database4.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B5D2B62DDFB008E1E70 /* IconDescriptionDatabaseImpl+Database4.swift */; };
+ C274CA392BAB8BE3008E7212 /* IconDescriptionDatabaseImpl+Database1.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B632B62DDFB008E1E70 /* IconDescriptionDatabaseImpl+Database1.swift */; };
+ C274CA3A2BAB8BE3008E7212 /* ServiceDefinitionDatabaseImpl+Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B6E2B62DDFB008E1E70 /* ServiceDefinitionDatabaseImpl+Database.swift */; };
+ C274CA3B2BAB8BE3008E7212 /* ServiceDefinitionDatabaseImpl+Database3.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B602B62DDFB008E1E70 /* ServiceDefinitionDatabaseImpl+Database3.swift */; };
+ C274CA3C2BAB8BE3008E7212 /* ServiceDefinitionDatabaseImpl+Database9.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B692B62DDFB008E1E70 /* ServiceDefinitionDatabaseImpl+Database9.swift */; };
+ C274CA3D2BAB8BE3008E7212 /* IconDescriptionDatabaseImpl+Database8.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B6D2B62DDFB008E1E70 /* IconDescriptionDatabaseImpl+Database8.swift */; };
+ C274CA3E2BAB8BE3008E7212 /* IconDescriptionDatabaseImpl+Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B6B2B62DDFB008E1E70 /* IconDescriptionDatabaseImpl+Database.swift */; };
+ C274CA3F2BAB8BE3008E7212 /* ServiceDefinitionDatabaseImpl+Database7.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B672B62DDFB008E1E70 /* ServiceDefinitionDatabaseImpl+Database7.swift */; };
+ C274CA402BAB8BE3008E7212 /* ServiceDefinitionDatabaseImpl+Database1.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B622B62DDFB008E1E70 /* ServiceDefinitionDatabaseImpl+Database1.swift */; };
+ C274CA412BAB8BE3008E7212 /* ServiceDefinitionDatabaseImpl+Database0.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E53B582B62DDFB008E1E70 /* ServiceDefinitionDatabaseImpl+Database0.swift */; };
+ C274CA4A2BAB8C23008E7212 /* CommonWatch.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C274CA232BAB8B92008E7212 /* CommonWatch.framework */; };
+ C274CA4F2BAB8C35008E7212 /* CommonWatch.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C274CA232BAB8B92008E7212 /* CommonWatch.framework */; };
+ C274CA532BAB8C35008E7212 /* ContentWatch.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C274CA492BAB8BE3008E7212 /* ContentWatch.framework */; };
+ C274CA602BAB8C3F008E7212 /* Protection.h in Headers */ = {isa = PBXBuildFile; fileRef = C2147CB7205D78600001D011 /* Protection.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ C274CA622BAB8C3F008E7212 /* ExtensionsStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C23443DD26B08EAA00C9F645 /* ExtensionsStorage.swift */; };
+ C274CA632BAB8C3F008E7212 /* CodeStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2147CC3205D78790001D011 /* CodeStorage.swift */; };
+ C274CA692BAB8C3F008E7212 /* Keys.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2C1513F294E831300F8B511 /* Keys.swift */; };
+ C274CA6A2BAB8C3F008E7212 /* LocalKeyEncryption.swift in Sources */ = {isa = PBXBuildFile; fileRef = C20F00DD25698F0A0026FBB2 /* LocalKeyEncryption.swift */; };
+ C274CA6D2BAB8C3F008E7212 /* ExportPublicKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = C278121B27F9F3E600F31453 /* ExportPublicKey.swift */; };
+ C274CA6E2BAB8C3F008E7212 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2147CC4205D78790001D011 /* Extensions.swift */; };
+ C274CA6F2BAB8C3F008E7212 /* LocalEncryptedStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = C22E417825DF076300105195 /* LocalEncryptedStorage.swift */; };
+ C274CA702BAB8C3F008E7212 /* BiometricAuthDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2147CC5205D78790001D011 /* BiometricAuthDelegate.swift */; };
+ C274CA722BAB8C3F008E7212 /* KeyEncryption.swift in Sources */ = {isa = PBXBuildFile; fileRef = C22E418725DF07B300105195 /* KeyEncryption.swift */; };
+ C274CA7E2BAB8C5B008E7212 /* CommonWatch.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C274CA232BAB8B92008E7212 /* CommonWatch.framework */; };
+ C274CA832BAB8C70008E7212 /* ProtectionWatch.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C274CA7C2BAB8C3F008E7212 /* ProtectionWatch.framework */; };
+ C274CA882BAB8CBD008E7212 /* CommonWatch.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C274CA232BAB8B92008E7212 /* CommonWatch.framework */; };
+ C274CA892BAB8CBD008E7212 /* CommonWatch.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C274CA232BAB8B92008E7212 /* CommonWatch.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+ C274CA8C2BAB8CC0008E7212 /* ContentWatch.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C274CA492BAB8BE3008E7212 /* ContentWatch.framework */; };
+ C274CA8D2BAB8CC0008E7212 /* ContentWatch.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C274CA492BAB8BE3008E7212 /* ContentWatch.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+ C274CA902BAB8CC5008E7212 /* ProtectionWatch.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C274CA7C2BAB8C3F008E7212 /* ProtectionWatch.framework */; };
+ C274CA912BAB8CC5008E7212 /* ProtectionWatch.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C274CA7C2BAB8C3F008E7212 /* ProtectionWatch.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+ C274CA952BAB8F92008E7212 /* Protection+.swift in Sources */ = {isa = PBXBuildFile; fileRef = C274CA942BAB8F92008E7212 /* Protection+.swift */; };
+ C274CA962BAB8F97008E7212 /* Protection+.swift in Sources */ = {isa = PBXBuildFile; fileRef = C274CA942BAB8F92008E7212 /* Protection+.swift */; };
+ C274CA972BAB8FD8008E7212 /* Protection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2147CC2205D78790001D011 /* Protection.swift */; };
+ C274CA982BAB91E3008E7212 /* ExchangeFileEncryption.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2F6AF3F273056010015BC59 /* ExchangeFileEncryption.swift */; };
+ C274CA9B2BAB94B8008E7212 /* SyncInstanceWatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = C274CA992BAB94B3008E7212 /* SyncInstanceWatch.swift */; };
+ C274CAA32BAB9D5E008E7212 /* ItemHandlerMigrationProxyWatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = C274CAA12BAB9D59008E7212 /* ItemHandlerMigrationProxyWatch.swift */; };
C276D1712B9A672C008C9CD4 /* LocalNotificationStateInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C276D1702B9A672C008C9CD4 /* LocalNotificationStateInteractor.swift */; };
C277C32C245C3FD6009214F3 /* MainContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C277C32B245C3FD6009214F3 /* MainContainerViewController.swift */; };
C278121C27F9F3E600F31453 /* ExportPublicKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = C278121B27F9F3E600F31453 /* ExportPublicKey.swift */; };
@@ -440,6 +639,8 @@
C27D543F275D393D001E9ABF /* BackupMenuPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27D543E275D393D001E9ABF /* BackupMenuPresenter.swift */; };
C27D5441275D462D001E9ABF /* BackupMenuViewController+TableCellHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27D5440275D462D001E9ABF /* BackupMenuViewController+TableCellHandling.swift */; };
C27D5443275D478E001E9ABF /* BackupMenuViewControlling.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27D5442275D478E001E9ABF /* BackupMenuViewControlling.swift */; };
+ C27D99DF2BD52C8A0008203F /* WatchConsts.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27D99DE2BD52C8A0008203F /* WatchConsts.swift */; };
+ C27D99E12BD53AB30008203F /* LogoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27D99E02BD53AB30008203F /* LogoView.swift */; };
C27E6FAF28FC57FD00AC9FD1 /* DynamicTypesEntityMigrationPolicySync.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27E6FAE28FC57FD00AC9FD1 /* DynamicTypesEntityMigrationPolicySync.swift */; };
C27E6FB128FC7E3800AC9FD1 /* ServiceRecord2.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27E6FB028FC7E3800AC9FD1 /* ServiceRecord2.swift */; };
C27E6FB328FC87AD00AC9FD1 /* InfoRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27E6FB228FC87AD00AC9FD1 /* InfoRecord.swift */; };
@@ -448,6 +649,10 @@
C27E6FBA28FCA73400AC9FD1 /* ItemHandlerMigrationProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27E6FB928FCA73400AC9FD1 /* ItemHandlerMigrationProxy.swift */; };
C27FBA491FBA239600D424D8 /* ServiceEntity+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27FBA471FBA239600D424D8 /* ServiceEntity+CoreDataClass.swift */; };
C27FBA4C1FBA23DD00D424D8 /* ServiceEntity+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27FBA4B1FBA23DD00D424D8 /* ServiceEntity+CoreDataProperties.swift */; };
+ C281A2732BD47D6C0068451C /* SuccessView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C281A2722BD47D6C0068451C /* SuccessView.swift */; };
+ C281A2772BD489590068451C /* IntroductionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C281A2762BD489590068451C /* IntroductionView.swift */; };
+ C281A2782BD48A930068451C /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = C225E617241CFCE90041C238 /* Localizable.strings */; };
+ C281A2792BD48A9C0068451C /* T.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = C24AEDBF291BD119005F59CB /* T.generated.swift */; };
C2823B1626F3E84F00583586 /* RevealPasswordInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2823B1526F3E84F00583586 /* RevealPasswordInput.swift */; };
C2830D7A293D440900B3DDAF /* TokensPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2830D79293D440900B3DDAF /* TokensPresenter.swift */; };
C2830D7C293D49E700B3DDAF /* TokensViewController+CommonSearchDataSourceSearchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2830D7B293D49E700B3DDAF /* TokensViewController+CommonSearchDataSourceSearchable.swift */; };
@@ -486,6 +691,12 @@
C28B38C927CD784D00BD4A96 /* RefreshTokenCounter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C28B38C827CD784D00BD4A96 /* RefreshTokenCounter.swift */; };
C28B9120268A3D330020A44A /* TwoFas3-TwoFas4.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = C28B911F268A3D330020A44A /* TwoFas3-TwoFas4.xcmappingmodel */; };
C28C441724A67B7000534B30 /* CommonSearchBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = C28C441624A67B7000534B30 /* CommonSearchBar.swift */; };
+ C29378302BD1A218008D5125 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C293782F2BD1A218008D5125 /* SettingsView.swift */; };
+ C29378342BD1A342008D5125 /* SecurityView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C29378332BD1A342008D5125 /* SecurityView.swift */; };
+ C29378362BD1A3B6008D5125 /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C29378352BD1A3B6008D5125 /* AboutView.swift */; };
+ C29378382BD1BF15008D5125 /* SecurityPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C29378372BD1BF15008D5125 /* SecurityPresenter.swift */; };
+ C293783A2BD1BF23008D5125 /* SecurityInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C29378392BD1BF23008D5125 /* SecurityInteractor.swift */; };
+ C293783D2BD1C24A008D5125 /* PINTypeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C293783C2BD1C24A008D5125 /* PINTypeView.swift */; };
C2959627267F4D090086DEB1 /* NSDiffableDataSourceSnapshot+.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2959626267F4D090086DEB1 /* NSDiffableDataSourceSnapshot+.swift */; };
C295962B267F79190086DEB1 /* TokensSectionHeader+.swift in Sources */ = {isa = PBXBuildFile; fileRef = C295962A267F79190086DEB1 /* TokensSectionHeader+.swift */; };
C29626B8236F80A200C133BC /* Animate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C29626B7236F80A200C133BC /* Animate.swift */; };
@@ -514,12 +725,31 @@
C29FEFFB2756DDA7002FC523 /* SettingsMenuViewController+TableCellHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = C29FEFFA2756DDA7002FC523 /* SettingsMenuViewController+TableCellHandling.swift */; };
C2A026B32AF7C42500DB2E52 /* MainRepositoryImpl+TimeVerification.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2A026B22AF7C42500DB2E52 /* MainRepositoryImpl+TimeVerification.swift */; };
C2A026B52AF82FDB00DB2E52 /* DataExternalTranslations.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2A026B42AF82FDB00DB2E52 /* DataExternalTranslations.swift */; };
+ C2A1B3B42BB6071C00D6B923 /* PINKeyboardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2A1B3B32BB6071C00D6B923 /* PINKeyboardView.swift */; };
+ C2A1B3B52BB6084100D6B923 /* PINType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2117178276CD11900042D28 /* PINType.swift */; };
+ C2A1B3B62BB6084100D6B923 /* PINType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2117178276CD11900042D28 /* PINType.swift */; };
C2A283352186071200967022 /* AlertControllerPromptFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2A283342186071200967022 /* AlertControllerPromptFactory.swift */; };
C2A2AF6F23D8EA710059094D /* UIActivityIndicator+.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2A2AF6E23D8EA710059094D /* UIActivityIndicator+.swift */; };
C2A4C8352A10F13800AFD67C /* TokensTOTPCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2A4C8342A10F13800AFD67C /* TokensTOTPCell.swift */; };
C2A4C8372A11141D00AFD67C /* TokensNextTokenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2A4C8362A11141D00AFD67C /* TokensNextTokenView.swift */; };
C2A4C8392A1153A200AFD67C /* TokensTokenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2A4C8382A1153A200AFD67C /* TokensTokenView.swift */; };
C2A4C83B2A11736200AFD67C /* TokensCircleProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2A4C83A2A11736200AFD67C /* TokensCircleProgress.swift */; };
+ C2A4D3152BC097F80001587C /* MainRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2A4D3142BC097F80001587C /* MainRepository.swift */; };
+ C2A4D32C2BC0B0C30001587C /* ServiceIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = C21AF6A526A237EA00BDAA37 /* ServiceIcon.swift */; };
+ C2A4D32D2BC0B1AD0001587C /* TokenHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C26D14642263A45100599101 /* TokenHandler.swift */; };
+ C2A4D32E2BC0B1B20001587C /* Token.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2D672F625DB2BD3004BD697 /* Token.swift */; };
+ C2A4D32F2BC0B1B50001587C /* Generator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2D672F325DB2BD2004BD697 /* Generator.swift */; };
+ C2A4D3302BC0B1B80001587C /* Crypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2D672F425DB2BD2004BD697 /* Crypto.swift */; };
+ C2A4D3312BC0B2540001587C /* TokenGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2BDC67A1FBE264B00967D0E /* TokenGenerator.swift */; };
+ C2A4D3322BC0B2B30001587C /* String+.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2B2B9AE2AE932BD00AB61FD /* String+.swift */; };
+ C2A4D3382BC0B3D60001587C /* CloudState.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2A4D3372BC0B3D60001587C /* CloudState.swift */; };
+ C2A4D3392BC0B3DC0001587C /* CloudState.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2A4D3372BC0B3D60001587C /* CloudState.swift */; };
+ C2A4D33C2BC0B5ED0001587C /* PINType+.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2AE5F532ADC1A0D00AED670 /* PINType+.swift */; };
+ C2A4D3402BC0B6B00001587C /* MF_Base32Additions.h in Headers */ = {isa = PBXBuildFile; fileRef = C251EDE02AE871A2007722F2 /* MF_Base32Additions.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ C2A4D3422BC0B6B00001587C /* MF_Base32Additions.m in Sources */ = {isa = PBXBuildFile; fileRef = C251EDE12AE871A2007722F2 /* MF_Base32Additions.m */; };
+ C2A4D3492BC0B6C00001587C /* Base32Watch.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2A4D3482BC0B6B00001587C /* Base32Watch.framework */; };
+ C2A4D34A2BC0B6C00001587C /* Base32Watch.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C2A4D3482BC0B6B00001587C /* Base32Watch.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+ C2A4D34F2BC0B9640001587C /* Base32Watch.h in Headers */ = {isa = PBXBuildFile; fileRef = C2A4D34D2BC0B9620001587C /* Base32Watch.h */; settings = {ATTRIBUTES = (Public, ); }; };
C2A57C5A26ACAB2800D3B344 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2A57C5826ACAAD000D3B344 /* Extensions.swift */; };
C2A6E7041FC7664800C83DCE /* PushNotifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2A6E7031FC7664800C83DCE /* PushNotifications.swift */; };
C2A6E7081FC9D14500C83DCE /* APNS.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2A6E7071FC9D14500C83DCE /* APNS.swift */; };
@@ -585,7 +815,6 @@
C2AE5F502ADC0F2E00AED670 /* CameraPermissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C28ECE971FEDBCD8000EBB9D /* CameraPermissions.swift */; };
C2AE5F512ADC199F00AED670 /* AppEventController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27A1EB0291279E400702DB9 /* AppEventController.swift */; };
C2AE5F522ADC19E600AED670 /* Notifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2AA9D102088C124001B14FF /* Notifications.swift */; };
- C2AE5F542ADC1A0D00AED670 /* PINType+.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2AE5F532ADC1A0D00AED670 /* PINType+.swift */; };
C2AE5F552ADC1A4A00AED670 /* SecurityProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2147CE9205D7FC90001D011 /* SecurityProtocol.swift */; };
C2AE5F582ADC1C5600AED670 /* PermissionsStateDataControllerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C257FD061FD9F6F300CF6898 /* PermissionsStateDataControllerProtocol.swift */; };
C2AE5F592ADC1C5B00AED670 /* PermissionsStateDataController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2B563F41FD895460011CAAA /* PermissionsStateDataController.swift */; };
@@ -657,6 +886,17 @@
C2B811D5284D1CFE009FD99D /* FirebaseCrashlytics in Frameworks */ = {isa = PBXBuildFile; productRef = C2B811D4284D1CFE009FD99D /* FirebaseCrashlytics */; };
C2B811D9284D1D2C009FD99D /* FirebaseRemoteConfig in Frameworks */ = {isa = PBXBuildFile; productRef = C2B811D8284D1D2C009FD99D /* FirebaseRemoteConfig */; };
C2B811DB284D1D62009FD99D /* FirebaseMessaging in Frameworks */ = {isa = PBXBuildFile; productRef = C2B811DA284D1D62009FD99D /* FirebaseMessaging */; };
+ C2B86D222BC3058A00AAAC63 /* UserDefaultsRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2B86D212BC3058A00AAAC63 /* UserDefaultsRepository.swift */; };
+ C2B86D242BC3070F00AAAC63 /* AppPIN.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2B86D232BC3070F00AAAC63 /* AppPIN.swift */; };
+ C2B86D262BC32F9200AAAC63 /* MainInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2B86D252BC32F9200AAAC63 /* MainInteractor.swift */; };
+ C2B86D282BC32FA300AAAC63 /* InteractorFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2B86D272BC32FA300AAAC63 /* InteractorFactory.swift */; };
+ C2B86D2A2BC33D3000AAAC63 /* AppDelegateInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2B86D292BC33D3000AAAC63 /* AppDelegateInteractor.swift */; };
+ C2B86D2C2BC3492A00AAAC63 /* Service.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2B86D2B2BC3492A00AAAC63 /* Service.swift */; };
+ C2B86D2E2BC3498D00AAAC63 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2B86D2D2BC3498D00AAAC63 /* MainView.swift */; };
+ C2B86D302BC349AE00AAAC63 /* MainPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2B86D2F2BC349AE00AAAC63 /* MainPresenter.swift */; };
+ C2B86D322BC356BA00AAAC63 /* ServiceListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2B86D312BC356BA00AAAC63 /* ServiceListView.swift */; };
+ C2B86D342BC3571E00AAAC63 /* ServiceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2B86D332BC3571E00AAAC63 /* ServiceView.swift */; };
+ C2B86D382BC35B8300AAAC63 /* IconRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2B86D372BC35B8300AAAC63 /* IconRenderer.swift */; };
C2B90EEE281EB3CF004B8AEC /* MainRepositoryImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2B90EED281EB3CF004B8AEC /* MainRepositoryImpl.swift */; };
C2B90EF0281EB3F8004B8AEC /* MainRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2B90EEF281EB3F8004B8AEC /* MainRepository.swift */; };
C2B90EF1281EC622004B8AEC /* NetworkStack.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C241D445278B9E0E00D7C604 /* NetworkStack.framework */; platformFilter = ios; };
@@ -781,6 +1021,7 @@
C2E2C81127B03E7300F04B70 /* SearchResultEmptyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E2C81027B03E7300F04B70 /* SearchResultEmptyView.swift */; };
C2E2C81427B0702300F04B70 /* CollectionViewAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E2C81327B0702300F04B70 /* CollectionViewAdapter.swift */; };
C2E2C81627B070B700F04B70 /* CollectionViewDataSnapshot.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E2C81527B070B700F04B70 /* CollectionViewDataSnapshot.swift */; };
+ C2E3A2B12BD4600F00DCBEF6 /* SecurityPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E3A2B02BD4600F00DCBEF6 /* SecurityPath.swift */; };
C2E3CBF629210320006A1522 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = C2E3CBF429210320006A1522 /* Localizable.strings */; };
C2E3CBF829210624006A1522 /* T.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E3CBF729210624006A1522 /* T.generated.swift */; };
C2E3D55927D94ECB0050AF48 /* BrowserExtensionIntroView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E3D55827D94ECB0050AF48 /* BrowserExtensionIntroView.swift */; };
@@ -1000,7 +1241,6 @@
C2E7C40C2ADB2BE500478D89 /* AndOTPData.swift in Sources */ = {isa = PBXBuildFile; fileRef = C229403D2AB3A50700D55B58 /* AndOTPData.swift */; };
C2E7C40D2ADB2BE500478D89 /* Guides.swift in Sources */ = {isa = PBXBuildFile; fileRef = C237368F2ABF5E2C00792054 /* Guides.swift */; };
C2E7C40E2ADB2BE500478D89 /* LastPassData.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27A31C929C8EEE40094679F /* LastPassData.swift */; };
- C2E7C40F2ADB2BE500478D89 /* PINType.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2117178276CD11900042D28 /* PINType.swift */; };
C2E7C4102ADB2BE500478D89 /* ExchangeConsts.swift in Sources */ = {isa = PBXBuildFile; fileRef = C21BC54C25B37C8900B15F99 /* ExchangeConsts.swift */; };
C2E7C4112ADB2BE500478D89 /* RaivoData.swift in Sources */ = {isa = PBXBuildFile; fileRef = C27A31CB29C90B110094679F /* RaivoData.swift */; };
C2E7C4122ADB2BE500478D89 /* ExchangeData2.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2E881D928F35C030053A89D /* ExchangeData2.swift */; };
@@ -1106,6 +1346,27 @@
remoteGlobalIDString = C200E4991FB3911B00D7C748;
remoteInfo = Storage;
};
+ C213BC542BAC3C97000794C9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = C236666B1FB2644900989ACA /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C274C9E42BAB8B92008E7212;
+ remoteInfo = CommonWatch;
+ };
+ C213BC582BAC3C97000794C9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = C236666B1FB2644900989ACA /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C274CA242BAB8BE3008E7212;
+ remoteInfo = ContentWatch;
+ };
+ C213BC5D2BAC3DBF000794C9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = C236666B1FB2644900989ACA /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C213BC1A2BAC3C82000794C9;
+ remoteInfo = StorageWatch;
+ };
C2147CBA205D78600001D011 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = C236666B1FB2644900989ACA /* Project object */;
@@ -1197,6 +1458,76 @@
remoteGlobalIDString = C29626D52370BD7F00C133BC;
remoteInfo = TimeVerification;
};
+ C274C9D82BAB8ABC008E7212 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = C236666B1FB2644900989ACA /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C274C9CC2BAB8ABB008E7212;
+ remoteInfo = "TwoFASWatch Watch App";
+ };
+ C274C9E12BAB8B2E008E7212 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = C236666B1FB2644900989ACA /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C274C98C2BAB89C7008E7212;
+ remoteInfo = SyncWatch;
+ };
+ C274CA4C2BAB8C23008E7212 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = C236666B1FB2644900989ACA /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C274C9E42BAB8B92008E7212;
+ remoteInfo = CommonWatch;
+ };
+ C274CA512BAB8C35008E7212 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = C236666B1FB2644900989ACA /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C274C9E42BAB8B92008E7212;
+ remoteInfo = CommonWatch;
+ };
+ C274CA552BAB8C35008E7212 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = C236666B1FB2644900989ACA /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C274CA242BAB8BE3008E7212;
+ remoteInfo = ContentWatch;
+ };
+ C274CA802BAB8C5B008E7212 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = C236666B1FB2644900989ACA /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C274C9E42BAB8B92008E7212;
+ remoteInfo = CommonWatch;
+ };
+ C274CA852BAB8C70008E7212 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = C236666B1FB2644900989ACA /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C274CA582BAB8C3F008E7212;
+ remoteInfo = ProtectionWatch;
+ };
+ C274CA8A2BAB8CBD008E7212 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = C236666B1FB2644900989ACA /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C274C9E42BAB8B92008E7212;
+ remoteInfo = CommonWatch;
+ };
+ C274CA8E2BAB8CC0008E7212 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = C236666B1FB2644900989ACA /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C274CA242BAB8BE3008E7212;
+ remoteInfo = ContentWatch;
+ };
+ C274CA922BAB8CC5008E7212 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = C236666B1FB2644900989ACA /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C274CA582BAB8C3F008E7212;
+ remoteInfo = ProtectionWatch;
+ };
C28633D71FFABD2200C8F4B4 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = C236666B1FB2644900989ACA /* Project object */;
@@ -1211,6 +1542,13 @@
remoteGlobalIDString = C29626D52370BD7F00C133BC;
remoteInfo = TimeVerification;
};
+ C2A4D34B2BC0B6C00001587C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = C236666B1FB2644900989ACA /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C2A4D33D2BC0B6B00001587C;
+ remoteInfo = Base32Watch;
+ };
C2ACF9E920A8A918003E0987 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = C236666B1FB2644900989ACA /* Project object */;
@@ -1494,6 +1832,33 @@
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
+ C274C9DE2BAB8ABC008E7212 /* Embed Watch Content */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "$(CONTENTS_FOLDER_PATH)/Watch";
+ dstSubfolderSpec = 16;
+ files = (
+ C274C9DA2BAB8ABC008E7212 /* TwoFASWatch Watch App.app in Embed Watch Content */,
+ );
+ name = "Embed Watch Content";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C274C9E32BAB8B2E008E7212 /* Embed Frameworks */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "";
+ dstSubfolderSpec = 10;
+ files = (
+ C274C9E02BAB8B2E008E7212 /* SyncWatch.framework in Embed Frameworks */,
+ C274CA892BAB8CBD008E7212 /* CommonWatch.framework in Embed Frameworks */,
+ C2A4D34A2BC0B6C00001587C /* Base32Watch.framework in Embed Frameworks */,
+ C274CA8D2BAB8CC0008E7212 /* ContentWatch.framework in Embed Frameworks */,
+ C274CA912BAB8CC5008E7212 /* ProtectionWatch.framework in Embed Frameworks */,
+ C213BC5C2BAC3DBF000794C9 /* StorageWatch.framework in Embed Frameworks */,
+ );
+ name = "Embed Frameworks";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
C28633DD1FFABD2200C8F4B4 /* Embed Foundation Extensions */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
@@ -1594,6 +1959,9 @@
C21247F727B70D420044D9F2 /* LabelComposeFlowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelComposeFlowController.swift; sourceTree = ""; };
C21247FA27B7181A0044D9F2 /* ComposeServiceModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeServiceModels.swift; sourceTree = ""; };
C212ACDD2AF6F929001C8665 /* RootInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootInteractor.swift; sourceTree = ""; };
+ C213BC502BAC3C82000794C9 /* StorageWatch.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = StorageWatch.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ C213BC6F2BAC5758000794C9 /* TwoFAS.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = TwoFAS.xcdatamodel; sourceTree = ""; };
+ C213BC722BAC5771000794C9 /* Sync.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Sync.xcdatamodel; sourceTree = ""; };
C2147CB5205D78600001D011 /* Protection.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Protection.framework; sourceTree = BUILT_PRODUCTS_DIR; };
C2147CB7205D78600001D011 /* Protection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Protection.h; sourceTree = ""; };
C2147CB8205D78600001D011 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
@@ -1758,6 +2126,7 @@
C23BAAF32545A1E9009B1EF8 /* SyncHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncHandler.swift; sourceTree = ""; };
C23BAB032545A861009B1EF8 /* CloudKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudKit.swift; sourceTree = ""; };
C23BAB132545AEF5009B1EF8 /* ConstStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConstStorage.swift; sourceTree = ""; };
+ C23FC62F2BCD49BB0040FE5C /* Assets.car */ = {isa = PBXFileReference; lastKnownFileType = file; path = Assets.car; sourceTree = ""; };
C23FD5092814635400E4E9C5 /* ComposeServiceWebExtensionFlowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ComposeServiceWebExtensionFlowController.swift; sourceTree = ""; };
C23FD50F2814648C00E4E9C5 /* ComposeServiceWebExtensionModuleInteractor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ComposeServiceWebExtensionModuleInteractor.swift; sourceTree = ""; };
C23FD51128146E2E00E4E9C5 /* ComposeServiceWebExtensionPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ComposeServiceWebExtensionPresenter.swift; sourceTree = ""; };
@@ -1915,6 +2284,8 @@
C25E8992266402AD00A60CE5 /* SectionEntity+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SectionEntity+CoreDataClass.swift"; sourceTree = ""; };
C25E8993266402AD00A60CE5 /* SectionEntity+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SectionEntity+CoreDataProperties.swift"; sourceTree = ""; };
C25F4FDA2622207F008F7755 /* TokensViewEmptySearchScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokensViewEmptySearchScreen.swift; sourceTree = ""; };
+ C260DCC02BC882AD007807CC /* TwoFASWatch-Watch-App-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "TwoFASWatch-Watch-App-Info.plist"; sourceTree = SOURCE_ROOT; };
+ C260DCC12BC885F1007807CC /* ServiceCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceCellView.swift; sourceTree = ""; };
C261A1212A12BECC00A1519F /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/TwoFASWidget.strings; sourceTree = ""; };
C261A1222A12BECC00A1519F /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = ""; };
C261A1232A12BECD00A1519F /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/InfoPlist.strings; sourceTree = ""; };
@@ -1924,6 +2295,8 @@
C2625F9128BBB87700D84C5C /* AboutModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutModels.swift; sourceTree = ""; };
C2625F9328BBC01900D84C5C /* AboutPresenter+Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AboutPresenter+Menu.swift"; sourceTree = ""; };
C2625F9528BBC86B00D84C5C /* AboutFooter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AboutFooter.swift; sourceTree = ""; };
+ C2627F392BC72E96009F93A9 /* ServicePresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServicePresenter.swift; sourceTree = ""; };
+ C2627F3B2BC72EA0009F93A9 /* ServiceInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceInteractor.swift; sourceTree = ""; };
C262E83529E9AA96008D148E /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/TwoFASWidget.strings; sourceTree = ""; };
C262E83629E9AA96008D148E /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; };
C262E83729E9AA97008D148E /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = ""; };
@@ -1948,6 +2321,12 @@
C26764AF2872483900D468B2 /* ComposeServiceCategorySelectionPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeServiceCategorySelectionPresenter.swift; sourceTree = ""; };
C26764B12872494100D468B2 /* ComposeServiceCategorySelectionPresenter+Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ComposeServiceCategorySelectionPresenter+Menu.swift"; sourceTree = ""; };
C26764B328724A4200D468B2 /* ComposeServiceCategorySelectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ComposeServiceCategorySelectionViewController.swift; sourceTree = ""; };
+ C26891892BC4960600713078 /* ServiceListPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceListPresenter.swift; sourceTree = ""; };
+ C268918C2BC4962300713078 /* ServiceListInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceListInteractor.swift; sourceTree = ""; };
+ C268918E2BC4974800713078 /* Category.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Category.swift; sourceTree = ""; };
+ C269837A2BCC5D03009B3BE2 /* PINKeyboardPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PINKeyboardPresenter.swift; sourceTree = ""; };
+ C269837F2BCC718D009B3BE2 /* PINKeyboardInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PINKeyboardInteractor.swift; sourceTree = ""; };
+ C26983812BCC8326009B3BE2 /* AppPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppPresenter.swift; sourceTree = ""; };
C2698B622986860F00EBC179 /* SelectServiceViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectServiceViewController.swift; sourceTree = ""; };
C2698B642986863E00EBC179 /* ComposeServiceAdvancedEditViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ComposeServiceAdvancedEditViewController.swift; sourceTree = ""; };
C2698B6B2986B42400EBC179 /* MainTabViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabViewController.swift; sourceTree = ""; };
@@ -1981,6 +2360,18 @@
C274BDC1276941FB00EE28BC /* AppSecurityPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSecurityPresenter.swift; sourceTree = ""; };
C274BDC32769425900EE28BC /* AppSecurityPresenter+Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppSecurityPresenter+Menu.swift"; sourceTree = ""; };
C274BDC52769428700EE28BC /* AppSecurityModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSecurityModels.swift; sourceTree = ""; };
+ C274C9C62BAB89C7008E7212 /* SyncWatch.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SyncWatch.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ C274C9CD2BAB8ABB008E7212 /* TwoFASWatch Watch App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "TwoFASWatch Watch App.app"; sourceTree = BUILT_PRODUCTS_DIR; };
+ C274C9CF2BAB8ABB008E7212 /* TwoFASWatchApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoFASWatchApp.swift; sourceTree = ""; };
+ C274C9D32BAB8ABC008E7212 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
+ C274C9D62BAB8ABC008E7212 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
+ C274CA232BAB8B92008E7212 /* CommonWatch.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CommonWatch.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ C274CA492BAB8BE3008E7212 /* ContentWatch.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ContentWatch.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ C274CA7C2BAB8C3F008E7212 /* ProtectionWatch.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ProtectionWatch.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ C274CA942BAB8F92008E7212 /* Protection+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Protection+.swift"; sourceTree = ""; };
+ C274CA992BAB94B3008E7212 /* SyncInstanceWatch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncInstanceWatch.swift; sourceTree = ""; };
+ C274CAA02BAB98A5008E7212 /* TwoFASWatch Watch App.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "TwoFASWatch Watch App.entitlements"; sourceTree = ""; };
+ C274CAA12BAB9D59008E7212 /* ItemHandlerMigrationProxyWatch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemHandlerMigrationProxyWatch.swift; sourceTree = ""; };
C276D1702B9A672C008C9CD4 /* LocalNotificationStateInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalNotificationStateInteractor.swift; sourceTree = ""; };
C277C32B245C3FD6009214F3 /* MainContainerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainContainerViewController.swift; sourceTree = ""; };
C278121B27F9F3E600F31453 /* ExportPublicKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExportPublicKey.swift; sourceTree = ""; };
@@ -2034,6 +2425,8 @@
C27D543E275D393D001E9ABF /* BackupMenuPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackupMenuPresenter.swift; sourceTree = ""; };
C27D5440275D462D001E9ABF /* BackupMenuViewController+TableCellHandling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BackupMenuViewController+TableCellHandling.swift"; sourceTree = ""; };
C27D5442275D478E001E9ABF /* BackupMenuViewControlling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackupMenuViewControlling.swift; sourceTree = ""; };
+ C27D99DE2BD52C8A0008203F /* WatchConsts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchConsts.swift; sourceTree = ""; };
+ C27D99E02BD53AB30008203F /* LogoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogoView.swift; sourceTree = ""; };
C27E6FAB28FC463600AC9FD1 /* Sync5.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Sync5.xcdatamodel; sourceTree = ""; };
C27E6FAE28FC57FD00AC9FD1 /* DynamicTypesEntityMigrationPolicySync.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DynamicTypesEntityMigrationPolicySync.swift; sourceTree = ""; };
C27E6FB028FC7E3800AC9FD1 /* ServiceRecord2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceRecord2.swift; sourceTree = ""; };
@@ -2046,6 +2439,8 @@
C281909C2B0B84910042BB7D /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/TwoFASWidget.strings; sourceTree = ""; };
C281909D2B0B84910042BB7D /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Localizable.strings; sourceTree = ""; };
C281909E2B0B84910042BB7D /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/InfoPlist.strings; sourceTree = ""; };
+ C281A2722BD47D6C0068451C /* SuccessView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuccessView.swift; sourceTree = ""; };
+ C281A2762BD489590068451C /* IntroductionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntroductionView.swift; sourceTree = ""; };
C2823B1526F3E84F00583586 /* RevealPasswordInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RevealPasswordInput.swift; sourceTree = ""; };
C2830D79293D440900B3DDAF /* TokensPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokensPresenter.swift; sourceTree = ""; };
C2830D7B293D49E700B3DDAF /* TokensViewController+CommonSearchDataSourceSearchable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TokensViewController+CommonSearchDataSourceSearchable.swift"; sourceTree = ""; };
@@ -2098,6 +2493,12 @@
C28ECE991FEDBFB3000EBB9D /* CameraDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraDelegate.swift; sourceTree = ""; };
C28ECE9F1FEE8273000EBB9D /* CodeParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeParser.swift; sourceTree = ""; };
C28ECEA51FEEA9CE000EBB9D /* QueryItemsType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueryItemsType.swift; sourceTree = ""; };
+ C293782F2BD1A218008D5125 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; };
+ C29378332BD1A342008D5125 /* SecurityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecurityView.swift; sourceTree = ""; };
+ C29378352BD1A3B6008D5125 /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutView.swift; sourceTree = ""; };
+ C29378372BD1BF15008D5125 /* SecurityPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecurityPresenter.swift; sourceTree = ""; };
+ C29378392BD1BF23008D5125 /* SecurityInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecurityInteractor.swift; sourceTree = ""; };
+ C293783C2BD1C24A008D5125 /* PINTypeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PINTypeView.swift; sourceTree = ""; };
C2959626267F4D090086DEB1 /* NSDiffableDataSourceSnapshot+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSDiffableDataSourceSnapshot+.swift"; sourceTree = ""; };
C295962A267F79190086DEB1 /* TokensSectionHeader+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TokensSectionHeader+.swift"; sourceTree = ""; };
C29626B7236F80A200C133BC /* Animate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Animate.swift; sourceTree = ""; };
@@ -2135,6 +2536,7 @@
C29FEFFA2756DDA7002FC523 /* SettingsMenuViewController+TableCellHandling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SettingsMenuViewController+TableCellHandling.swift"; sourceTree = ""; };
C2A026B22AF7C42500DB2E52 /* MainRepositoryImpl+TimeVerification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MainRepositoryImpl+TimeVerification.swift"; sourceTree = ""; };
C2A026B42AF82FDB00DB2E52 /* DataExternalTranslations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataExternalTranslations.swift; sourceTree = ""; };
+ C2A1B3B32BB6071C00D6B923 /* PINKeyboardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PINKeyboardView.swift; sourceTree = ""; };
C2A2255B293BFE1E00B76115 /* TokenInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenInteractor.swift; sourceTree = ""; };
C2A283342186071200967022 /* AlertControllerPromptFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertControllerPromptFactory.swift; sourceTree = ""; };
C2A2AF6E23D8EA710059094D /* UIActivityIndicator+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIActivityIndicator+.swift"; sourceTree = ""; };
@@ -2143,6 +2545,10 @@
C2A4C8362A11141D00AFD67C /* TokensNextTokenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokensNextTokenView.swift; sourceTree = ""; };
C2A4C8382A1153A200AFD67C /* TokensTokenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokensTokenView.swift; sourceTree = ""; };
C2A4C83A2A11736200AFD67C /* TokensCircleProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokensCircleProgress.swift; sourceTree = ""; };
+ C2A4D3142BC097F80001587C /* MainRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainRepository.swift; sourceTree = ""; };
+ C2A4D3372BC0B3D60001587C /* CloudState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudState.swift; sourceTree = ""; };
+ C2A4D3482BC0B6B00001587C /* Base32Watch.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Base32Watch.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ C2A4D34D2BC0B9620001587C /* Base32Watch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Base32Watch.h; sourceTree = ""; };
C2A57C5826ACAAD000D3B344 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; };
C2A6E7031FC7664800C83DCE /* PushNotifications.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushNotifications.swift; sourceTree = ""; };
C2A6E7071FC9D14500C83DCE /* APNS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APNS.swift; sourceTree = ""; };
@@ -2259,6 +2665,17 @@
C2B5BF582946616900E5092D /* TokensNavigationFlowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokensNavigationFlowController.swift; sourceTree = ""; };
C2B6D78D260BB024005B599E /* ColorPickerButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorPickerButton.swift; sourceTree = ""; };
C2B71D1C23DDEEEE007C5896 /* MainContainerPaging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainContainerPaging.swift; sourceTree = ""; };
+ C2B86D212BC3058A00AAAC63 /* UserDefaultsRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsRepository.swift; sourceTree = ""; };
+ C2B86D232BC3070F00AAAC63 /* AppPIN.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppPIN.swift; sourceTree = ""; };
+ C2B86D252BC32F9200AAAC63 /* MainInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainInteractor.swift; sourceTree = ""; };
+ C2B86D272BC32FA300AAAC63 /* InteractorFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractorFactory.swift; sourceTree = ""; };
+ C2B86D292BC33D3000AAAC63 /* AppDelegateInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegateInteractor.swift; sourceTree = ""; };
+ C2B86D2B2BC3492A00AAAC63 /* Service.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Service.swift; sourceTree = ""; };
+ C2B86D2D2BC3498D00AAAC63 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = ""; };
+ C2B86D2F2BC349AE00AAAC63 /* MainPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainPresenter.swift; sourceTree = ""; };
+ C2B86D312BC356BA00AAAC63 /* ServiceListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceListView.swift; sourceTree = ""; };
+ C2B86D332BC3571E00AAAC63 /* ServiceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceView.swift; sourceTree = ""; };
+ C2B86D372BC35B8300AAAC63 /* IconRenderer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconRenderer.swift; sourceTree = ""; };
C2B90EED281EB3CF004B8AEC /* MainRepositoryImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainRepositoryImpl.swift; sourceTree = ""; };
C2B90EEF281EB3F8004B8AEC /* MainRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainRepository.swift; sourceTree = ""; };
C2B90EFD281EDE80004B8AEC /* NotificationPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationPresenter.swift; sourceTree = ""; };
@@ -2430,6 +2847,7 @@
C2E2C81027B03E7300F04B70 /* SearchResultEmptyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultEmptyView.swift; sourceTree = ""; };
C2E2C81327B0702300F04B70 /* CollectionViewAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionViewAdapter.swift; sourceTree = ""; };
C2E2C81527B070B700F04B70 /* CollectionViewDataSnapshot.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionViewDataSnapshot.swift; sourceTree = ""; };
+ C2E3A2B02BD4600F00DCBEF6 /* SecurityPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecurityPath.swift; sourceTree = ""; };
C2E3CBF529210320006A1522 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = TwoFAS/Other/en.lproj/Localizable.strings; sourceTree = SOURCE_ROOT; };
C2E3CBF729210624006A1522 /* T.generated.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = T.generated.swift; sourceTree = ""; };
C2E3D55827D94ECB0050AF48 /* BrowserExtensionIntroView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowserExtensionIntroView.swift; sourceTree = ""; };
@@ -2638,6 +3056,15 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ C213BC492BAC3C82000794C9 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C213BC562BAC3C97000794C9 /* ContentWatch.framework in Frameworks */,
+ C213BC522BAC3C97000794C9 /* CommonWatch.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
C2147CB1205D78600001D011 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -2702,6 +3129,52 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ C274C9BE2BAB89C7008E7212 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C274CA4F2BAB8C35008E7212 /* CommonWatch.framework in Frameworks */,
+ C274CA532BAB8C35008E7212 /* ContentWatch.framework in Frameworks */,
+ C274CA832BAB8C70008E7212 /* ProtectionWatch.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C274C9CA2BAB8ABB008E7212 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C274C9DF2BAB8B2E008E7212 /* SyncWatch.framework in Frameworks */,
+ C274CA882BAB8CBD008E7212 /* CommonWatch.framework in Frameworks */,
+ C2A4D3492BC0B6C00001587C /* Base32Watch.framework in Frameworks */,
+ C274CA8C2BAB8CC0008E7212 /* ContentWatch.framework in Frameworks */,
+ C274CA902BAB8CC5008E7212 /* ProtectionWatch.framework in Frameworks */,
+ C213BC5B2BAC3DBF000794C9 /* StorageWatch.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C274CA1C2BAB8B92008E7212 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C274CA422BAB8BE3008E7212 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C274CA4A2BAB8C23008E7212 /* CommonWatch.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C274CA742BAB8C3F008E7212 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C274CA7E2BAB8C5B008E7212 /* CommonWatch.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
C28633C81FFABD2200C8F4B4 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -2728,6 +3201,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ C2A4D3432BC0B6B00001587C /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
C2ACF9E120A8A918003E0987 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@@ -2844,6 +3324,7 @@
C200E49B1FB3911B00D7C748 /* Storage */ = {
isa = PBXGroup;
children = (
+ C213BC612BAC4777000794C9 /* Watch */,
C200E4AD1FB3913A00D7C748 /* Storage.swift */,
C27ABD30277A450C00AE073B /* StorageRepository.swift */,
C27ABD32277A453000AE073B /* StorageRepositoryImpl.swift */,
@@ -3436,6 +3917,22 @@
path = Modules;
sourceTree = "";
};
+ C213BC612BAC4777000794C9 /* Watch */ = {
+ isa = PBXGroup;
+ children = (
+ C213BC6E2BAC5758000794C9 /* TwoFAS.xcdatamodeld */,
+ );
+ path = Watch;
+ sourceTree = "";
+ };
+ C213BC652BAC4883000794C9 /* Watch */ = {
+ isa = PBXGroup;
+ children = (
+ C213BC712BAC5771000794C9 /* Sync.xcdatamodeld */,
+ );
+ path = Watch;
+ sourceTree = "";
+ };
C2147CB6205D78600001D011 /* Protection */ = {
isa = PBXGroup;
children = (
@@ -3459,6 +3956,7 @@
C278122227FA16BC00F31453 /* RSAKeyStorage.swift */,
C27CDA7A29A2CFA200DC7C98 /* BiometryFingerprintStorage.swift */,
C2C1513F294E831300F8B511 /* Keys.swift */,
+ C274CA942BAB8F92008E7212 /* Protection+.swift */,
);
path = Protection;
sourceTree = "";
@@ -4056,6 +4554,7 @@
C2DF710C2B5DD31200D85D87 /* DataTests */,
C2E53AC62B62DD6C008E1E70 /* Common */,
C2E53B4C2B62DDCB008E1E70 /* Content */,
+ C274C9CE2BAB8ABB008E7212 /* TwoFASWatch Watch App */,
C23666741FB2644900989ACA /* Products */,
C200E46A1FB38E6200D7C748 /* Frameworks */,
);
@@ -4082,6 +4581,13 @@
C2DF710B2B5DD31200D85D87 /* DataTests.xctest */,
C2E53AC52B62DD6C008E1E70 /* Common.framework */,
C2E53B4B2B62DDCB008E1E70 /* Content.framework */,
+ C274C9C62BAB89C7008E7212 /* SyncWatch.framework */,
+ C274C9CD2BAB8ABB008E7212 /* TwoFASWatch Watch App.app */,
+ C274CA232BAB8B92008E7212 /* CommonWatch.framework */,
+ C274CA492BAB8BE3008E7212 /* ContentWatch.framework */,
+ C274CA7C2BAB8C3F008E7212 /* ProtectionWatch.framework */,
+ C213BC502BAC3C82000794C9 /* StorageWatch.framework */,
+ C2A4D3482BC0B6B00001587C /* Base32Watch.framework */,
);
name = Products;
sourceTree = "";
@@ -4154,6 +4660,14 @@
path = Flow;
sourceTree = "";
};
+ C23FC6302BCD49BB0040FE5C /* AssetsWatch */ = {
+ isa = PBXGroup;
+ children = (
+ C23FC62F2BCD49BB0040FE5C /* Assets.car */,
+ );
+ path = AssetsWatch;
+ sourceTree = "";
+ };
C23FD50828144A4B00E4E9C5 /* WebExtension */ = {
isa = PBXGroup;
children = (
@@ -4296,7 +4810,6 @@
C27A1EA92912791100702DB9 /* ExternalLinks.swift */,
C287D4F8276A90EC0001B272 /* AppLock.swift */,
C287D4FC276A98FE0001B272 /* BiometryType.swift */,
- C2117178276CD11900042D28 /* PINType.swift */,
C25859372802E75A002DC749 /* PushNotificationState.swift */,
C2069C9028C2922A00321E44 /* AEGISData.swift */,
C27A31C929C8EEE40094679F /* LastPassData.swift */,
@@ -4455,6 +4968,38 @@
path = NetworkStack;
sourceTree = "";
};
+ C244BE492BD07AA000F7E566 /* Settings */ = {
+ isa = PBXGroup;
+ children = (
+ C244BE4B2BD07AFF00F7E566 /* Security */,
+ C244BE4A2BD07AFA00F7E566 /* About */,
+ C293782F2BD1A218008D5125 /* SettingsView.swift */,
+ );
+ path = Settings;
+ sourceTree = "";
+ };
+ C244BE4A2BD07AFA00F7E566 /* About */ = {
+ isa = PBXGroup;
+ children = (
+ C29378352BD1A3B6008D5125 /* AboutView.swift */,
+ C27D99E02BD53AB30008203F /* LogoView.swift */,
+ );
+ path = About;
+ sourceTree = "";
+ };
+ C244BE4B2BD07AFF00F7E566 /* Security */ = {
+ isa = PBXGroup;
+ children = (
+ C293783B2BD1C240008D5125 /* PINType */,
+ C29378332BD1A342008D5125 /* SecurityView.swift */,
+ C29378372BD1BF15008D5125 /* SecurityPresenter.swift */,
+ C29378392BD1BF23008D5125 /* SecurityInteractor.swift */,
+ C2E3A2B02BD4600F00DCBEF6 /* SecurityPath.swift */,
+ C281A2722BD47D6C0068451C /* SuccessView.swift */,
+ );
+ path = Security;
+ sourceTree = "";
+ };
C244F9DF22762955009992D3 /* Cell */ = {
isa = PBXGroup;
children = (
@@ -4628,7 +5173,9 @@
C24D1C1B253C744E0029D27D /* Sync */ = {
isa = PBXGroup;
children = (
+ C213BC652BAC4883000794C9 /* Watch */,
C2F5443425685C2100611716 /* SyncInstance.swift */,
+ C274CA992BAB94B3008E7212 /* SyncInstanceWatch.swift */,
C2D507B5256477DA00151359 /* CloudHandler.swift */,
C23BAAF32545A1E9009B1EF8 /* SyncHandler.swift */,
C23BAB032545A861009B1EF8 /* CloudKit.swift */,
@@ -4740,6 +5287,7 @@
isa = PBXGroup;
children = (
C251EDD72AE87150007722F2 /* Base32.h */,
+ C2A4D34D2BC0B9620001587C /* Base32Watch.h */,
C251EDE02AE871A2007722F2 /* MF_Base32Additions.h */,
C251EDE12AE871A2007722F2 /* MF_Base32Additions.m */,
);
@@ -5006,6 +5554,16 @@
path = Types;
sourceTree = "";
};
+ C2627F382BC72E19009F93A9 /* Service */ = {
+ isa = PBXGroup;
+ children = (
+ C2627F3B2BC72EA0009F93A9 /* ServiceInteractor.swift */,
+ C2627F392BC72E96009F93A9 /* ServicePresenter.swift */,
+ C2B86D332BC3571E00AAAC63 /* ServiceView.swift */,
+ );
+ path = Service;
+ sourceTree = "";
+ };
C26764A628723CFD00D468B2 /* CategorySelection */ = {
isa = PBXGroup;
children = (
@@ -5050,6 +5608,56 @@
path = Flow;
sourceTree = "";
};
+ C268918B2BC4960C00713078 /* ServiceList */ = {
+ isa = PBXGroup;
+ children = (
+ C260DCC12BC885F1007807CC /* ServiceCellView.swift */,
+ C2B86D312BC356BA00AAAC63 /* ServiceListView.swift */,
+ C26891892BC4960600713078 /* ServiceListPresenter.swift */,
+ C268918C2BC4962300713078 /* ServiceListInteractor.swift */,
+ );
+ path = ServiceList;
+ sourceTree = "";
+ };
+ C269837C2BCC715C009B3BE2 /* Models */ = {
+ isa = PBXGroup;
+ children = (
+ C2B86D2B2BC3492A00AAAC63 /* Service.swift */,
+ C268918E2BC4974800713078 /* Category.swift */,
+ C2B86D232BC3070F00AAAC63 /* AppPIN.swift */,
+ );
+ path = Models;
+ sourceTree = "";
+ };
+ C269837D2BCC7175009B3BE2 /* Repositories */ = {
+ isa = PBXGroup;
+ children = (
+ C2A4D3142BC097F80001587C /* MainRepository.swift */,
+ C2B86D212BC3058A00AAAC63 /* UserDefaultsRepository.swift */,
+ );
+ path = Repositories;
+ sourceTree = "";
+ };
+ C269837E2BCC7180009B3BE2 /* PIN */ = {
+ isa = PBXGroup;
+ children = (
+ C2A1B3B32BB6071C00D6B923 /* PINKeyboardView.swift */,
+ C269837A2BCC5D03009B3BE2 /* PINKeyboardPresenter.swift */,
+ C269837F2BCC718D009B3BE2 /* PINKeyboardInteractor.swift */,
+ );
+ path = PIN;
+ sourceTree = "";
+ };
+ C26983832BCC8F6B009B3BE2 /* Main */ = {
+ isa = PBXGroup;
+ children = (
+ C2B86D2D2BC3498D00AAAC63 /* MainView.swift */,
+ C2B86D2F2BC349AE00AAAC63 /* MainPresenter.swift */,
+ C2B86D252BC32F9200AAAC63 /* MainInteractor.swift */,
+ );
+ path = Main;
+ sourceTree = "";
+ };
C2698B662986B3E500EBC179 /* MainTab */ = {
isa = PBXGroup;
children = (
@@ -5158,6 +5766,34 @@
path = Flow;
sourceTree = "";
};
+ C274C9CE2BAB8ABB008E7212 /* TwoFASWatch Watch App */ = {
+ isa = PBXGroup;
+ children = (
+ C274C9D52BAB8ABC008E7212 /* Preview Content */,
+ C27D99DD2BD52A690008203F /* Data */,
+ C260DCC02BC882AD007807CC /* TwoFASWatch-Watch-App-Info.plist */,
+ C274CAA02BAB98A5008E7212 /* TwoFASWatch Watch App.entitlements */,
+ C274C9CF2BAB8ABB008E7212 /* TwoFASWatchApp.swift */,
+ C27D99DC2BD52A5E0008203F /* App */,
+ C274C9D32BAB8ABC008E7212 /* Assets.xcassets */,
+ C281A2762BD489590068451C /* IntroductionView.swift */,
+ C26983832BCC8F6B009B3BE2 /* Main */,
+ C244BE492BD07AA000F7E566 /* Settings */,
+ C269837E2BCC7180009B3BE2 /* PIN */,
+ C268918B2BC4960C00713078 /* ServiceList */,
+ C2627F382BC72E19009F93A9 /* Service */,
+ );
+ path = "TwoFASWatch Watch App";
+ sourceTree = "";
+ };
+ C274C9D52BAB8ABC008E7212 /* Preview Content */ = {
+ isa = PBXGroup;
+ children = (
+ C274C9D62BAB8ABC008E7212 /* Preview Assets.xcassets */,
+ );
+ path = "Preview Content";
+ sourceTree = "";
+ };
C277C32A245C3FB8009214F3 /* Container */ = {
isa = PBXGroup;
children = (
@@ -5323,6 +5959,27 @@
path = View;
sourceTree = "";
};
+ C27D99DC2BD52A5E0008203F /* App */ = {
+ isa = PBXGroup;
+ children = (
+ C26983812BCC8326009B3BE2 /* AppPresenter.swift */,
+ C2B86D292BC33D3000AAAC63 /* AppDelegateInteractor.swift */,
+ );
+ path = App;
+ sourceTree = "";
+ };
+ C27D99DD2BD52A690008203F /* Data */ = {
+ isa = PBXGroup;
+ children = (
+ C27D99DE2BD52C8A0008203F /* WatchConsts.swift */,
+ C2B86D272BC32FA300AAAC63 /* InteractorFactory.swift */,
+ C269837D2BCC7175009B3BE2 /* Repositories */,
+ C269837C2BCC715C009B3BE2 /* Models */,
+ C2B86D372BC35B8300AAAC63 /* IconRenderer.swift */,
+ );
+ path = Data;
+ sourceTree = "";
+ };
C27E6FB428FC8AF200AC9FD1 /* Info */ = {
isa = PBXGroup;
children = (
@@ -5506,6 +6163,14 @@
path = ComposeService;
sourceTree = "";
};
+ C293783B2BD1C240008D5125 /* PINType */ = {
+ isa = PBXGroup;
+ children = (
+ C293783C2BD1C24A008D5125 /* PINTypeView.swift */,
+ );
+ path = PINType;
+ sourceTree = "";
+ };
C29626D72370BD7F00C133BC /* TimeVerification */ = {
isa = PBXGroup;
children = (
@@ -6281,9 +6946,9 @@
C2F8702A262C7A900032DB1F /* FileIcons */,
C2CB5D1125DB1B7E00A362A9 /* External */,
C2355B4A2221D33300BA001D /* GoogleService-Info.plist */,
+ C225E617241CFCE90041C238 /* Localizable.strings */,
C2BDC6DE1FC1F66F00967D0E /* TwoFAS.entitlements */,
C2D291DB2955FC9E0084FE1E /* Settings.bundle */,
- C225E617241CFCE90041C238 /* Localizable.strings */,
C23666801FB2644900989ACA /* Assets.xcassets */,
C27C104826AE093200F00191 /* TwoFASWidgetExtension.entitlements */,
C23666821FB2644900989ACA /* LaunchScreen.storyboard */,
@@ -6482,6 +7147,7 @@
children = (
C2C4F64628FDEF8400285B81 /* ItemHandling.swift */,
C27E6FB928FCA73400AC9FD1 /* ItemHandlerMigrationProxy.swift */,
+ C274CAA12BAB9D59008E7212 /* ItemHandlerMigrationProxyWatch.swift */,
C24EECF7268789DE00C6ABAA /* ItemHandler.swift */,
);
path = Item;
@@ -7053,6 +7719,7 @@
C2E53AE72B62DDAF008E1E70 /* ServiceExistenceStatus.swift */,
C2E53AE82B62DDAF008E1E70 /* IconDescriptionGroup.swift */,
C2E53AE92B62DDAF008E1E70 /* Period.swift */,
+ C2117178276CD11900042D28 /* PINType.swift */,
C2E53AEA2B62DDAF008E1E70 /* IconType.swift */,
C2E53AEB2B62DDAF008E1E70 /* CommonSectionData.swift */,
C2E53AEC2B62DDAF008E1E70 /* Digits.swift */,
@@ -7071,6 +7738,7 @@
C2E53AF92B62DDAF008E1E70 /* SortType.swift */,
C2E53AFA2B62DDAF008E1E70 /* LogoType.swift */,
C2E53AFB2B62DDAF008E1E70 /* ListNewsEntry.swift */,
+ C2A4D3372BC0B3D60001587C /* CloudState.swift */,
);
path = Models;
sourceTree = "";
@@ -7122,6 +7790,7 @@
C2E53B4C2B62DDCB008E1E70 /* Content */ = {
isa = PBXGroup;
children = (
+ C23FC6302BCD49BB0040FE5C /* AssetsWatch */,
C2E53B872B62DE13008E1E70 /* Assets */,
C2E53B562B62DDFB008E1E70 /* Sources */,
C2E53B4D2B62DDCB008E1E70 /* Content.h */,
@@ -7577,6 +8246,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ C213BC1F2BAC3C82000794C9 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C213BC202BAC3C82000794C9 /* Storage.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
C2147CB2205D78600001D011 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
@@ -7618,6 +8295,38 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ C274C9932BAB89C7008E7212 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C274C9942BAB89C7008E7212 /* Sync.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C274C9E52BAB8B92008E7212 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C274C9E62BAB8B92008E7212 /* Common.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C274CA272BAB8BE3008E7212 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C274CA282BAB8BE3008E7212 /* Content.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C274CA5F2BAB8C3F008E7212 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C274CA602BAB8C3F008E7212 /* Protection.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
C29626D12370BD7F00C133BC /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
@@ -7626,6 +8335,15 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ C2A4D33E2BC0B6B00001587C /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C2A4D34F2BC0B9640001587C /* Base32Watch.h in Headers */,
+ C2A4D3402BC0B6B00001587C /* MF_Base32Additions.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
C2E53AC02B62DD6C008E1E70 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
@@ -7683,26 +8401,48 @@
productReference = C200E49A1FB3911B00D7C748 /* Storage.framework */;
productType = "com.apple.product-type.framework";
};
- C2147CB4205D78600001D011 /* Protection */ = {
+ C213BC1A2BAC3C82000794C9 /* StorageWatch */ = {
isa = PBXNativeTarget;
- buildConfigurationList = C2147CC0205D78600001D011 /* Build configuration list for PBXNativeTarget "Protection" */;
+ buildConfigurationList = C213BC4D2BAC3C82000794C9 /* Build configuration list for PBXNativeTarget "StorageWatch" */;
buildPhases = (
- C2147CB2205D78600001D011 /* Headers */,
- C2147CB0205D78600001D011 /* Sources */,
- C2147CB1205D78600001D011 /* Frameworks */,
- C2147CB3205D78600001D011 /* Resources */,
+ C213BC1F2BAC3C82000794C9 /* Headers */,
+ C213BC212BAC3C82000794C9 /* Sources */,
+ C213BC492BAC3C82000794C9 /* Frameworks */,
+ C213BC4C2BAC3C82000794C9 /* Resources */,
);
buildRules = (
);
dependencies = (
- C2E53BA42B62DE45008E1E70 /* PBXTargetDependency */,
+ C213BC552BAC3C97000794C9 /* PBXTargetDependency */,
+ C213BC592BAC3C97000794C9 /* PBXTargetDependency */,
);
- name = Protection;
+ name = StorageWatch;
packageProductDependencies = (
- C2CF23FD23623DE000B759DD /* KeychainAccess */,
- C278121E27F9F4C000F31453 /* SwCrypt */,
);
- productName = Protection;
+ productName = Storage;
+ productReference = C213BC502BAC3C82000794C9 /* StorageWatch.framework */;
+ productType = "com.apple.product-type.framework";
+ };
+ C2147CB4205D78600001D011 /* Protection */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = C2147CC0205D78600001D011 /* Build configuration list for PBXNativeTarget "Protection" */;
+ buildPhases = (
+ C2147CB2205D78600001D011 /* Headers */,
+ C2147CB0205D78600001D011 /* Sources */,
+ C2147CB1205D78600001D011 /* Frameworks */,
+ C2147CB3205D78600001D011 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ C2E53BA42B62DE45008E1E70 /* PBXTargetDependency */,
+ );
+ name = Protection;
+ packageProductDependencies = (
+ C2CF23FD23623DE000B759DD /* KeychainAccess */,
+ C278121E27F9F4C000F31453 /* SwCrypt */,
+ );
+ productName = Protection;
productReference = C2147CB5205D78600001D011 /* Protection.framework */;
productType = "com.apple.product-type.framework";
};
@@ -7740,6 +8480,7 @@
C200E4941FB38E8E00D7C748 /* Embed Frameworks */,
C28633DD1FFABD2200C8F4B4 /* Embed Foundation Extensions */,
C2035D422938143C00B94834 /* SwiftLint */,
+ C274C9DE2BAB8ABC008E7212 /* Embed Watch Content */,
);
buildRules = (
);
@@ -7758,6 +8499,7 @@
C251EDDA2AE87150007722F2 /* PBXTargetDependency */,
C2E53ACA2B62DD6C008E1E70 /* PBXTargetDependency */,
C2E53B502B62DDCB008E1E70 /* PBXTargetDependency */,
+ C274C9D92BAB8ABC008E7212 /* PBXTargetDependency */,
);
name = TwoFAS;
packageProductDependencies = (
@@ -7828,6 +8570,111 @@
productReference = C251EDD52AE87150007722F2 /* Base32.framework */;
productType = "com.apple.product-type.framework";
};
+ C274C98C2BAB89C7008E7212 /* SyncWatch */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = C274C9C32BAB89C7008E7212 /* Build configuration list for PBXNativeTarget "SyncWatch" */;
+ buildPhases = (
+ C274C9932BAB89C7008E7212 /* Headers */,
+ C274C9952BAB89C7008E7212 /* Sources */,
+ C274C9BE2BAB89C7008E7212 /* Frameworks */,
+ C274C9C22BAB89C7008E7212 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ C274CA522BAB8C35008E7212 /* PBXTargetDependency */,
+ C274CA562BAB8C35008E7212 /* PBXTargetDependency */,
+ C274CA862BAB8C70008E7212 /* PBXTargetDependency */,
+ );
+ name = SyncWatch;
+ packageProductDependencies = (
+ );
+ productName = Sync;
+ productReference = C274C9C62BAB89C7008E7212 /* SyncWatch.framework */;
+ productType = "com.apple.product-type.framework";
+ };
+ C274C9CC2BAB8ABB008E7212 /* TwoFASWatch Watch App */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = C274C9DB2BAB8ABC008E7212 /* Build configuration list for PBXNativeTarget "TwoFASWatch Watch App" */;
+ buildPhases = (
+ C274C9C92BAB8ABB008E7212 /* Sources */,
+ C274C9CA2BAB8ABB008E7212 /* Frameworks */,
+ C274C9CB2BAB8ABB008E7212 /* Resources */,
+ C274C9E32BAB8B2E008E7212 /* Embed Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ C274C9E22BAB8B2E008E7212 /* PBXTargetDependency */,
+ C274CA8B2BAB8CBD008E7212 /* PBXTargetDependency */,
+ C274CA8F2BAB8CC0008E7212 /* PBXTargetDependency */,
+ C274CA932BAB8CC5008E7212 /* PBXTargetDependency */,
+ C213BC5E2BAC3DBF000794C9 /* PBXTargetDependency */,
+ C2A4D34C2BC0B6C00001587C /* PBXTargetDependency */,
+ );
+ name = "TwoFASWatch Watch App";
+ productName = "TwoFASWatch Watch App";
+ productReference = C274C9CD2BAB8ABB008E7212 /* TwoFASWatch Watch App.app */;
+ productType = "com.apple.product-type.application";
+ };
+ C274C9E42BAB8B92008E7212 /* CommonWatch */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = C274CA202BAB8B92008E7212 /* Build configuration list for PBXNativeTarget "CommonWatch" */;
+ buildPhases = (
+ C274C9E52BAB8B92008E7212 /* Headers */,
+ C274C9E72BAB8B92008E7212 /* Sources */,
+ C274CA1C2BAB8B92008E7212 /* Frameworks */,
+ C274CA1D2BAB8B92008E7212 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = CommonWatch;
+ productName = Common;
+ productReference = C274CA232BAB8B92008E7212 /* CommonWatch.framework */;
+ productType = "com.apple.product-type.framework";
+ };
+ C274CA242BAB8BE3008E7212 /* ContentWatch */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = C274CA462BAB8BE3008E7212 /* Build configuration list for PBXNativeTarget "ContentWatch" */;
+ buildPhases = (
+ C274CA272BAB8BE3008E7212 /* Headers */,
+ C274CA292BAB8BE3008E7212 /* Sources */,
+ C274CA422BAB8BE3008E7212 /* Frameworks */,
+ C274CA442BAB8BE3008E7212 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ C274CA4D2BAB8C23008E7212 /* PBXTargetDependency */,
+ );
+ name = ContentWatch;
+ productName = Content;
+ productReference = C274CA492BAB8BE3008E7212 /* ContentWatch.framework */;
+ productType = "com.apple.product-type.framework";
+ };
+ C274CA582BAB8C3F008E7212 /* ProtectionWatch */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = C274CA792BAB8C3F008E7212 /* Build configuration list for PBXNativeTarget "ProtectionWatch" */;
+ buildPhases = (
+ C274CA5F2BAB8C3F008E7212 /* Headers */,
+ C274CA612BAB8C3F008E7212 /* Sources */,
+ C274CA742BAB8C3F008E7212 /* Frameworks */,
+ C274CA782BAB8C3F008E7212 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ C274CA812BAB8C5B008E7212 /* PBXTargetDependency */,
+ );
+ name = ProtectionWatch;
+ packageProductDependencies = (
+ );
+ productName = Protection;
+ productReference = C274CA7C2BAB8C3F008E7212 /* ProtectionWatch.framework */;
+ productType = "com.apple.product-type.framework";
+ };
C28633CA1FFABD2200C8F4B4 /* TwoFASAuth */ = {
isa = PBXNativeTarget;
buildConfigurationList = C28633DC1FFABD2200C8F4B4 /* Build configuration list for PBXNativeTarget "TwoFASAuth" */;
@@ -7876,6 +8723,24 @@
productReference = C29626D62370BD7F00C133BC /* TimeVerification.framework */;
productType = "com.apple.product-type.framework";
};
+ C2A4D33D2BC0B6B00001587C /* Base32Watch */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = C2A4D3452BC0B6B00001587C /* Build configuration list for PBXNativeTarget "Base32Watch" */;
+ buildPhases = (
+ C2A4D33E2BC0B6B00001587C /* Headers */,
+ C2A4D3412BC0B6B00001587C /* Sources */,
+ C2A4D3432BC0B6B00001587C /* Frameworks */,
+ C2A4D3442BC0B6B00001587C /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = Base32Watch;
+ productName = Base32;
+ productReference = C2A4D3482BC0B6B00001587C /* Base32Watch.framework */;
+ productType = "com.apple.product-type.framework";
+ };
C2ACF9E320A8A918003E0987 /* TwoFASTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = C2ACF9EB20A8A918003E0987 /* Build configuration list for PBXNativeTarget "TwoFASTests" */;
@@ -8076,7 +8941,7 @@
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
- LastSwiftUpdateCheck = 1520;
+ LastSwiftUpdateCheck = 1530;
LastUpgradeCheck = 1530;
ORGANIZATIONNAME = "Two Factor Authentication Service, Inc.";
TargetAttributes = {
@@ -8124,6 +8989,9 @@
C251EDD42AE87150007722F2 = {
CreatedOnToolsVersion = 15.0.1;
};
+ C274C9CC2BAB8ABB008E7212 = {
+ CreatedOnToolsVersion = 15.3;
+ };
C28633CA1FFABD2200C8F4B4 = {
CreatedOnToolsVersion = 9.2;
LastSwiftMigration = 1020;
@@ -8226,6 +9094,13 @@
C2C3AE0C269E224A00506ACF /* TwoFASWidgetExtension */,
C2C3AE24269E274700506ACF /* TwoFASServiceIntent */,
C2DF710A2B5DD31200D85D87 /* DataTests */,
+ C274C9CC2BAB8ABB008E7212 /* TwoFASWatch Watch App */,
+ C274C98C2BAB89C7008E7212 /* SyncWatch */,
+ C274C9E42BAB8B92008E7212 /* CommonWatch */,
+ C274CA242BAB8BE3008E7212 /* ContentWatch */,
+ C274CA582BAB8C3F008E7212 /* ProtectionWatch */,
+ C213BC1A2BAC3C82000794C9 /* StorageWatch */,
+ C2A4D33D2BC0B6B00001587C /* Base32Watch */,
);
};
/* End PBXProject section */
@@ -8238,6 +9113,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ C213BC4C2BAC3C82000794C9 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
C2147CB3205D78600001D011 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -8299,6 +9181,47 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ C274C9C22BAB89C7008E7212 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C274C9CB2BAB8ABB008E7212 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C274C9D72BAB8ABC008E7212 /* Preview Assets.xcassets in Resources */,
+ C281A2782BD48A930068451C /* Localizable.strings in Resources */,
+ C274C9D42BAB8ABC008E7212 /* Assets.xcassets in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C274CA1D2BAB8B92008E7212 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C274CA1E2BAB8B92008E7212 /* TintColor.xcassets in Resources */,
+ C274CA1F2BAB8B92008E7212 /* ThemeColor.xcassets in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C274CA442BAB8BE3008E7212 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C23FC6312BCD49BB0040FE5C /* Assets.car in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C274CA782BAB8C3F008E7212 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
C28633C91FFABD2200C8F4B4 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -8315,6 +9238,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ C2A4D3442BC0B6B00001587C /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
C2ACF9E220A8A918003E0987 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
@@ -8455,6 +9385,48 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ C213BC212BAC3C82000794C9 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C213BC232BAC3C82000794C9 /* StorageRepositoryImpl+CategoriesSections.swift in Sources */,
+ C213BC242BAC3C82000794C9 /* CategoryData.swift in Sources */,
+ C213BC252BAC3C82000794C9 /* StorageRepository.swift in Sources */,
+ C213BC262BAC3C82000794C9 /* StorageRepositoryImpl.swift in Sources */,
+ C213BC272BAC3C82000794C9 /* Extensions.swift in Sources */,
+ C213BC292BAC3C82000794C9 /* StorageRepositoryImpl+AuthRequest.swift in Sources */,
+ C213BC2A2BAC3C82000794C9 /* ServiceHandler.swift in Sources */,
+ C213BC2D2BAC3C82000794C9 /* StorageRepositoryImpl+Pairing.swift in Sources */,
+ C213BC2E2BAC3C82000794C9 /* StorageRepositoryImpl+News.swift in Sources */,
+ C213BC2F2BAC3C82000794C9 /* LogEntryEntity+CoreDataClass.swift in Sources */,
+ C213BC302BAC3C82000794C9 /* PairingEntity+CoreDataClass.swift in Sources */,
+ C213BC312BAC3C82000794C9 /* AuthRequestEntity+CoreDataClass.swift in Sources */,
+ C213BC322BAC3C82000794C9 /* LogEntry.swift in Sources */,
+ C213BC332BAC3C82000794C9 /* CategoryHandler.swift in Sources */,
+ C213BC342BAC3C82000794C9 /* SectionEntity+CoreDataProperties.swift in Sources */,
+ C213BC352BAC3C82000794C9 /* ServiceOptions.swift in Sources */,
+ C213BC702BAC5758000794C9 /* TwoFAS.xcdatamodeld in Sources */,
+ C213BC602BAC3FE3000794C9 /* ServiceMigrationController.swift in Sources */,
+ C213BC362BAC3C82000794C9 /* AuthRequestFilterOptions.swift in Sources */,
+ C213BC372BAC3C82000794C9 /* NewsEntity+CoreDataClass.swift in Sources */,
+ C213BC382BAC3C82000794C9 /* ServiceEntity+CoreDataProperties.swift in Sources */,
+ C213BC392BAC3C82000794C9 /* LogHandler.swift in Sources */,
+ C213BC3A2BAC3C82000794C9 /* Storage.swift in Sources */,
+ C213BC3B2BAC3C82000794C9 /* LogStorage.xcdatamodeld in Sources */,
+ C213BC3C2BAC3C82000794C9 /* NewsEntity+CoreDataProperties.swift in Sources */,
+ C213BC3E2BAC3C82000794C9 /* AuthRequestEntityToPairedAuthRequest.swift in Sources */,
+ C213BC402BAC3C82000794C9 /* ServiceEntity+CoreDataClass.swift in Sources */,
+ C213BC412BAC3C82000794C9 /* SectionHandler.swift in Sources */,
+ C213BC422BAC3C82000794C9 /* AuthRequestEntity+CoreDataProperties.swift in Sources */,
+ C213BC432BAC3C82000794C9 /* SectionEntity+CoreDataClass.swift in Sources */,
+ C213BC442BAC3C82000794C9 /* ServiceEntity+Extensions.swift in Sources */,
+ C213BC452BAC3C82000794C9 /* SectionData.swift in Sources */,
+ C213BC462BAC3C82000794C9 /* LogEntryEntity+CoreDataProperties.swift in Sources */,
+ C213BC472BAC3C82000794C9 /* PairingEntity+CoreDataProperties.swift in Sources */,
+ C213BC482BAC3C82000794C9 /* ServiceData+Extensions.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
C2147CB0205D78600001D011 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -8464,6 +9436,7 @@
C2673BE523D4765200A2CBA8 /* TokenStorageType.swift in Sources */,
C278122327FA16BC00F31453 /* RSAKeyStorage.swift in Sources */,
C2147CC7205D787A0001D011 /* Protection.swift in Sources */,
+ C274CA952BAB8F92008E7212 /* Protection+.swift in Sources */,
C2673BE223D46F5D00A2CBA8 /* TokenStorage.swift in Sources */,
C27CDA7B29A2CFA200DC7C98 /* BiometryFingerprintStorage.swift in Sources */,
C2C15140294E831300F8B511 /* Keys.swift in Sources */,
@@ -8525,6 +9498,7 @@
C27A549F27F0CAA400321D2B /* BrowserExtensionIntroModuleInteractor.swift in Sources */,
C2BDC6FD1FC4BC8A00967D0E /* UIViewController+Extensions.swift in Sources */,
C2F7FE072A8AB7D4004B2C95 /* AddingServiceManuallyViewController.swift in Sources */,
+ C2A4D33C2BC0B5ED0001587C /* PINType+.swift in Sources */,
C2A70680276D36E100885D79 /* NewPINModuleInteractor.swift in Sources */,
C2B39C7027A5882D00D3B579 /* SelectFromGalleryFlowController.swift in Sources */,
C2A70684276D39A800885D79 /* NewPINViewController.swift in Sources */,
@@ -8959,7 +9933,6 @@
C240486027654E370076376E /* ImporterEnterPasswordModuleInteractor.swift in Sources */,
C235A013298FE785008F4FD0 /* MainMenuPresenter.swift in Sources */,
C2EA567128569ADD00026BFE /* AskForAuthFlowController.swift in Sources */,
- C2AE5F542ADC1A0D00AED670 /* PINType+.swift in Sources */,
C20E2E0B2A7C52AA00DB64BB /* AddingServiceMainPresenter.swift in Sources */,
C2A74FF52610DDF5007E5AB3 /* Array+.swift in Sources */,
C2CC0A3C29D05DC900677A7B /* ExternalImportPresenter.swift in Sources */,
@@ -9162,6 +10135,210 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ C274C9952BAB89C7008E7212 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C274C9962BAB89C7008E7212 /* CloudKit.swift in Sources */,
+ C274C9972BAB89C7008E7212 /* SecretValidation.swift in Sources */,
+ C274C9992BAB89C7008E7212 /* SectionCacheEntity+CoreDataClass.swift in Sources */,
+ C274C99A2BAB89C7008E7212 /* LogDataChange.swift in Sources */,
+ C274C99B2BAB89C7008E7212 /* ItemHandling.swift in Sources */,
+ C274C99C2BAB89C7008E7212 /* ServiceCacheEntity+toServiceData.swift in Sources */,
+ C274C99D2BAB89C7008E7212 /* ConstStorage.swift in Sources */,
+ C274C99E2BAB89C7008E7212 /* CloudKitErrorParser.swift in Sources */,
+ C213BC192BAC3BD5000794C9 /* CommonItemHandler.swift in Sources */,
+ C274CAA32BAB9D5E008E7212 /* ItemHandlerMigrationProxyWatch.swift in Sources */,
+ C274C99F2BAB89C7008E7212 /* SectionHandler.swift in Sources */,
+ C274C9A02BAB89C7008E7212 /* Types.swift in Sources */,
+ C274C9A22BAB89C7008E7212 /* CloudHandler.swift in Sources */,
+ C274C9A32BAB89C7008E7212 /* Extensions.swift in Sources */,
+ C274C9A42BAB89C7008E7212 /* LogHandler.swift in Sources */,
+ C274C9A52BAB89C7008E7212 /* SectionCacheEntity+CoreDataProperties.swift in Sources */,
+ C274C9A62BAB89C7008E7212 /* RecordType.swift in Sources */,
+ C274C9A72BAB89C7008E7212 /* ClearHandler.swift in Sources */,
+ C274C9A82BAB89C7008E7212 /* SyncTokenHandler.swift in Sources */,
+ C274C9A92BAB89C7008E7212 /* ServiceRecord2.swift in Sources */,
+ C274C9AA2BAB89C7008E7212 /* LogEntity+CoreDataProperties.swift in Sources */,
+ C274C9AB2BAB89C7008E7212 /* CloudAvailability.swift in Sources */,
+ C274C9AC2BAB89C7008E7212 /* ServiceCacheEntity+CoreDataClass.swift in Sources */,
+ C274C9AD2BAB89C7008E7212 /* DynamicTypesEntityMigrationPolicySync.swift in Sources */,
+ C274C9B12BAB89C7008E7212 /* ServiceRecord.swift in Sources */,
+ C274C9B22BAB89C7008E7212 /* iCloudIdentifier.swift in Sources */,
+ C274C9B32BAB89C7008E7212 /* ServiceCacheEntity+CoreDataProperties.swift in Sources */,
+ C274C9B42BAB89C7008E7212 /* ServiceHandler.swift in Sources */,
+ C274C9B52BAB89C7008E7212 /* ItemHandler.swift in Sources */,
+ C274C9B62BAB89C7008E7212 /* SyncHandler.swift in Sources */,
+ C274C9B72BAB89C7008E7212 /* SectionRecord.swift in Sources */,
+ C274C9B82BAB89C7008E7212 /* LogEntity+CoreDataClass.swift in Sources */,
+ C213BC732BAC5771000794C9 /* Sync.xcdatamodeld in Sources */,
+ C274C9BA2BAB89C7008E7212 /* InfoRecord.swift in Sources */,
+ C274C9BB2BAB89C7008E7212 /* InfoHandler.swift in Sources */,
+ C274C9BC2BAB89C7008E7212 /* Info.swift in Sources */,
+ C274C9BD2BAB89C7008E7212 /* RecordIDGenerator.swift in Sources */,
+ C274CA9B2BAB94B8008E7212 /* SyncInstanceWatch.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C274C9C92BAB8ABB008E7212 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C2A4D3302BC0B1B80001587C /* Crypto.swift in Sources */,
+ C2B86D2E2BC3498D00AAAC63 /* MainView.swift in Sources */,
+ C29378362BD1A3B6008D5125 /* AboutView.swift in Sources */,
+ C2A4D3152BC097F80001587C /* MainRepository.swift in Sources */,
+ C281A2772BD489590068451C /* IntroductionView.swift in Sources */,
+ C281A2792BD48A9C0068451C /* T.generated.swift in Sources */,
+ C2B86D2A2BC33D3000AAAC63 /* AppDelegateInteractor.swift in Sources */,
+ C2A4D32E2BC0B1B20001587C /* Token.swift in Sources */,
+ C268918A2BC4960600713078 /* ServiceListPresenter.swift in Sources */,
+ C26983822BCC8326009B3BE2 /* AppPresenter.swift in Sources */,
+ C274C9D02BAB8ABB008E7212 /* TwoFASWatchApp.swift in Sources */,
+ C2627F3A2BC72E96009F93A9 /* ServicePresenter.swift in Sources */,
+ C29378302BD1A218008D5125 /* SettingsView.swift in Sources */,
+ C29378342BD1A342008D5125 /* SecurityView.swift in Sources */,
+ C2B86D282BC32FA300AAAC63 /* InteractorFactory.swift in Sources */,
+ C269837B2BCC5D03009B3BE2 /* PINKeyboardPresenter.swift in Sources */,
+ C2A4D32F2BC0B1B50001587C /* Generator.swift in Sources */,
+ C2A1B3B42BB6071C00D6B923 /* PINKeyboardView.swift in Sources */,
+ C268918D2BC4962300713078 /* ServiceListInteractor.swift in Sources */,
+ C2A4D32C2BC0B0C30001587C /* ServiceIcon.swift in Sources */,
+ C2A4D3312BC0B2540001587C /* TokenGenerator.swift in Sources */,
+ C29378382BD1BF15008D5125 /* SecurityPresenter.swift in Sources */,
+ C2A4D32D2BC0B1AD0001587C /* TokenHandler.swift in Sources */,
+ C2B86D222BC3058A00AAAC63 /* UserDefaultsRepository.swift in Sources */,
+ C2B86D342BC3571E00AAAC63 /* ServiceView.swift in Sources */,
+ C27D99E12BD53AB30008203F /* LogoView.swift in Sources */,
+ C2A4D3322BC0B2B30001587C /* String+.swift in Sources */,
+ C2B86D2C2BC3492A00AAAC63 /* Service.swift in Sources */,
+ C293783A2BD1BF23008D5125 /* SecurityInteractor.swift in Sources */,
+ C27D99DF2BD52C8A0008203F /* WatchConsts.swift in Sources */,
+ C2B86D382BC35B8300AAAC63 /* IconRenderer.swift in Sources */,
+ C2B86D322BC356BA00AAAC63 /* ServiceListView.swift in Sources */,
+ C281A2732BD47D6C0068451C /* SuccessView.swift in Sources */,
+ C268918F2BC4974800713078 /* Category.swift in Sources */,
+ C2B86D302BC349AE00AAAC63 /* MainPresenter.swift in Sources */,
+ C2B86D262BC32F9200AAAC63 /* MainInteractor.swift in Sources */,
+ C2E3A2B12BD4600F00DCBEF6 /* SecurityPath.swift in Sources */,
+ C260DCC22BC885F1007807CC /* ServiceCellView.swift in Sources */,
+ C293783D2BD1C24A008D5125 /* PINTypeView.swift in Sources */,
+ C2B86D242BC3070F00AAAC63 /* AppPIN.swift in Sources */,
+ C26983802BCC718D009B3BE2 /* PINKeyboardInteractor.swift in Sources */,
+ C2627F3C2BC72EA0009F93A9 /* ServiceInteractor.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C274C9E72BAB8B92008E7212 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C274C9E82BAB8B92008E7212 /* Collection+.swift in Sources */,
+ C274C9E92BAB8B92008E7212 /* String+.swift in Sources */,
+ C274C9EA2BAB8B92008E7212 /* EncryptionHolder.swift in Sources */,
+ C274C9EB2BAB8B92008E7212 /* CommonSectionHandler.swift in Sources */,
+ C274C9EC2BAB8B92008E7212 /* LegacyServiceDatabase.swift in Sources */,
+ C2A4D3392BC0B3DC0001587C /* CloudState.swift in Sources */,
+ C274C9ED2BAB8B92008E7212 /* CoreDataMigrator.swift in Sources */,
+ C274C9EF2BAB8B92008E7212 /* Log.swift in Sources */,
+ C274C9F02BAB8B92008E7212 /* CountdownTimer.swift in Sources */,
+ C274C9F12BAB8B92008E7212 /* CommonLocalKeyEncryption.swift in Sources */,
+ C2A1B3B62BB6084100D6B923 /* PINType.swift in Sources */,
+ C274C9F22BAB8B92008E7212 /* PairedAuthRequest.swift in Sources */,
+ C274C9F32BAB8B92008E7212 /* IconDescriptionGroup.swift in Sources */,
+ C274C9F42BAB8B92008E7212 /* ListNewsEntry.swift in Sources */,
+ C274C9F52BAB8B92008E7212 /* ServiceData.swift in Sources */,
+ C274C9F62BAB8B92008E7212 /* PushNotificationsConfig.swift in Sources */,
+ C274C9F72BAB8B92008E7212 /* ServiceRules.swift in Sources */,
+ C274C9F82BAB8B92008E7212 /* ServiceData+.swift in Sources */,
+ C274C9F92BAB8B92008E7212 /* Notifications+.swift in Sources */,
+ C274C9FA2BAB8B92008E7212 /* Array+.swift in Sources */,
+ C274C9FB2BAB8B92008E7212 /* CommonServiceHandler.swift in Sources */,
+ C274C9FC2BAB8B92008E7212 /* ServiceMatchRules+.swift in Sources */,
+ C274C9FD2BAB8B92008E7212 /* Character+.swift in Sources */,
+ C274C9FE2BAB8B92008E7212 /* CoreDataMigrationVersion.swift in Sources */,
+ C274C9FF2BAB8B92008E7212 /* LogoType.swift in Sources */,
+ C274CA002BAB8B92008E7212 /* IconDescription.swift in Sources */,
+ C274CA012BAB8B92008E7212 /* ServiceExistenceStatus.swift in Sources */,
+ C274CA022BAB8B92008E7212 /* ServiceDefinition.swift in Sources */,
+ C274CA032BAB8B92008E7212 /* Period.swift in Sources */,
+ C274CA042BAB8B92008E7212 /* IconType.swift in Sources */,
+ C274CA052BAB8B92008E7212 /* LastNotification.swift in Sources */,
+ C274CA062BAB8B92008E7212 /* HOTPDefaultValue.swift in Sources */,
+ C274CA072BAB8B92008E7212 /* CoreDataStack.swift in Sources */,
+ C274CA082BAB8B92008E7212 /* VersionDecoded.swift in Sources */,
+ C274CA092BAB8B92008E7212 /* ListStyle.swift in Sources */,
+ C274CA0A2BAB8B92008E7212 /* RefreshTimer.swift in Sources */,
+ C274CA0B2BAB8B92008E7212 /* CoreDataMigrationStep.swift in Sources */,
+ C274CA0C2BAB8B92008E7212 /* ThemeMetrics.swift in Sources */,
+ C274CA0D2BAB8B92008E7212 /* Config.swift in Sources */,
+ C274CA0E2BAB8B92008E7212 /* LegacyExchangeDatabase.swift in Sources */,
+ C274CA0F2BAB8B92008E7212 /* TokenType.swift in Sources */,
+ C274CA102BAB8B92008E7212 /* CommonSectionData.swift in Sources */,
+ C274CA112BAB8B92008E7212 /* Date+Extensions.swift in Sources */,
+ C274CA122BAB8B92008E7212 /* AttributedText+Formatting.swift in Sources */,
+ C274CA132BAB8B92008E7212 /* WidgetServiceHandlerType.swift in Sources */,
+ C274CA142BAB8B92008E7212 /* TintColor.swift in Sources */,
+ C274CA152BAB8B92008E7212 /* PairedWebExtension.swift in Sources */,
+ C274CA162BAB8B92008E7212 /* Digits.swift in Sources */,
+ C274CA172BAB8B92008E7212 /* SortType.swift in Sources */,
+ C274CA182BAB8B92008E7212 /* TypeAliases.swift in Sources */,
+ C274CA192BAB8B92008E7212 /* Algorithm.swift in Sources */,
+ C274CA1A2BAB8B92008E7212 /* ServiceType.swift in Sources */,
+ C274CA1B2BAB8B92008E7212 /* ServiceSource.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C274CA292BAB8BE3008E7212 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C274CA2A2BAB8BE3008E7212 /* IconDescriptionDatabaseImpl+Database5.swift in Sources */,
+ C274CA2B2BAB8BE3008E7212 /* IconDescriptionDatabaseImpl+Database7.swift in Sources */,
+ C274CA2C2BAB8BE3008E7212 /* ServiceDefinitionDatabaseImpl+Database5.swift in Sources */,
+ C274CA2D2BAB8BE3008E7212 /* IconDescriptionDatabaseImpl+Database3.swift in Sources */,
+ C274CA2E2BAB8BE3008E7212 /* IconDescriptionDatabaseImpl+Database6.swift in Sources */,
+ C274CA2F2BAB8BE3008E7212 /* ServiceDefinitionDatabaseImpl+Database8.swift in Sources */,
+ C274CA302BAB8BE3008E7212 /* IconDescriptionDatabaseImpl+Database2.swift in Sources */,
+ C274CA312BAB8BE3008E7212 /* IconDescriptionDatabase.swift in Sources */,
+ C274CA322BAB8BE3008E7212 /* IconDescriptionDatabaseImpl+Database0.swift in Sources */,
+ C274CA332BAB8BE3008E7212 /* ServiceDefinitionDatabaseImpl+Database2.swift in Sources */,
+ C274CA342BAB8BE3008E7212 /* ServiceDefinitionDatabase.swift in Sources */,
+ C274CA352BAB8BE3008E7212 /* ServiceDefinitionDatabaseImpl+Database6.swift in Sources */,
+ C274CA362BAB8BE3008E7212 /* ServiceDefinitionDatabaseImpl+Database4.swift in Sources */,
+ C274CA372BAB8BE3008E7212 /* IconDescriptionDatabaseImpl+Database9.swift in Sources */,
+ C274CA382BAB8BE3008E7212 /* IconDescriptionDatabaseImpl+Database4.swift in Sources */,
+ C274CA392BAB8BE3008E7212 /* IconDescriptionDatabaseImpl+Database1.swift in Sources */,
+ C274CA3A2BAB8BE3008E7212 /* ServiceDefinitionDatabaseImpl+Database.swift in Sources */,
+ C274CA3B2BAB8BE3008E7212 /* ServiceDefinitionDatabaseImpl+Database3.swift in Sources */,
+ C274CA3C2BAB8BE3008E7212 /* ServiceDefinitionDatabaseImpl+Database9.swift in Sources */,
+ C274CA3D2BAB8BE3008E7212 /* IconDescriptionDatabaseImpl+Database8.swift in Sources */,
+ C274CA3E2BAB8BE3008E7212 /* IconDescriptionDatabaseImpl+Database.swift in Sources */,
+ C274CA3F2BAB8BE3008E7212 /* ServiceDefinitionDatabaseImpl+Database7.swift in Sources */,
+ C274CA402BAB8BE3008E7212 /* ServiceDefinitionDatabaseImpl+Database1.swift in Sources */,
+ C274CA412BAB8BE3008E7212 /* ServiceDefinitionDatabaseImpl+Database0.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C274CA612BAB8C3F008E7212 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C274CA622BAB8C3F008E7212 /* ExtensionsStorage.swift in Sources */,
+ C274CA632BAB8C3F008E7212 /* CodeStorage.swift in Sources */,
+ C274CA972BAB8FD8008E7212 /* Protection.swift in Sources */,
+ C274CA692BAB8C3F008E7212 /* Keys.swift in Sources */,
+ C274CA6A2BAB8C3F008E7212 /* LocalKeyEncryption.swift in Sources */,
+ C274CA962BAB8F97008E7212 /* Protection+.swift in Sources */,
+ C274CA6D2BAB8C3F008E7212 /* ExportPublicKey.swift in Sources */,
+ C274CA6E2BAB8C3F008E7212 /* Extensions.swift in Sources */,
+ C274CA6F2BAB8C3F008E7212 /* LocalEncryptedStorage.swift in Sources */,
+ C274CA702BAB8C3F008E7212 /* BiometricAuthDelegate.swift in Sources */,
+ C274CA722BAB8C3F008E7212 /* KeyEncryption.swift in Sources */,
+ C274CA982BAB91E3008E7212 /* ExchangeFileEncryption.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
C28633C71FFABD2200C8F4B4 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -9187,6 +10364,14 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
+ C2A4D3412BC0B6B00001587C /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C2A4D3422BC0B6B00001587C /* MF_Base32Additions.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
C2ACF9E020A8A918003E0987 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@@ -9278,12 +10463,14 @@
C2E53B2D2B62DDAF008E1E70 /* LastNotification.swift in Sources */,
C2E53B322B62DDAF008E1E70 /* HOTPDefaultValue.swift in Sources */,
C2E53B1C2B62DDAF008E1E70 /* CoreDataStack.swift in Sources */,
+ C2A4D3382BC0B3D60001587C /* CloudState.swift in Sources */,
C2E53B272B62DDAF008E1E70 /* VersionDecoded.swift in Sources */,
C2E53B2A2B62DDAF008E1E70 /* ListStyle.swift in Sources */,
C2E53B172B62DDAF008E1E70 /* RefreshTimer.swift in Sources */,
C2E53B1B2B62DDAF008E1E70 /* CoreDataMigrationStep.swift in Sources */,
C2E53B122B62DDAF008E1E70 /* ThemeMetrics.swift in Sources */,
C2E53B112B62DDAF008E1E70 /* Config.swift in Sources */,
+ C2A1B3B52BB6084100D6B923 /* PINType.swift in Sources */,
C2E53B1A2B62DDAF008E1E70 /* LegacyExchangeDatabase.swift in Sources */,
C2E53B302B62DDAF008E1E70 /* TokenType.swift in Sources */,
C2E53B252B62DDAF008E1E70 /* CommonSectionData.swift in Sources */,
@@ -9476,7 +10663,6 @@
C2AE5F692ADC5D9D00AED670 /* Security.swift in Sources */,
C2E7C3DD2ADB2BB400478D89 /* RegisterDeviceInteractor.swift in Sources */,
C276D1712B9A672C008C9CD4 /* LocalNotificationStateInteractor.swift in Sources */,
- C2E7C40F2ADB2BE500478D89 /* PINType.swift in Sources */,
C2E7C3CB2ADB2B9C00478D89 /* MainRepositoryImpl+Appearance.swift in Sources */,
C2E7C3F62ADB2BB400478D89 /* WebExtensionAuthInteractor.swift in Sources */,
C2E7C4092ADB2BE500478D89 /* ExchangeDataFormat.swift in Sources */,
@@ -9512,6 +10698,21 @@
target = C200E4991FB3911B00D7C748 /* Storage */;
targetProxy = C200E49F1FB3911B00D7C748 /* PBXContainerItemProxy */;
};
+ C213BC552BAC3C97000794C9 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C274C9E42BAB8B92008E7212 /* CommonWatch */;
+ targetProxy = C213BC542BAC3C97000794C9 /* PBXContainerItemProxy */;
+ };
+ C213BC592BAC3C97000794C9 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C274CA242BAB8BE3008E7212 /* ContentWatch */;
+ targetProxy = C213BC582BAC3C97000794C9 /* PBXContainerItemProxy */;
+ };
+ C213BC5E2BAC3DBF000794C9 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C213BC1A2BAC3C82000794C9 /* StorageWatch */;
+ targetProxy = C213BC5D2BAC3DBF000794C9 /* PBXContainerItemProxy */;
+ };
C2147CBB205D78600001D011 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = C2147CB4205D78600001D011 /* Protection */;
@@ -9577,6 +10778,56 @@
target = C29626D52370BD7F00C133BC /* TimeVerification */;
targetProxy = C264AE6A26D2DF4200AE61E7 /* PBXContainerItemProxy */;
};
+ C274C9D92BAB8ABC008E7212 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C274C9CC2BAB8ABB008E7212 /* TwoFASWatch Watch App */;
+ targetProxy = C274C9D82BAB8ABC008E7212 /* PBXContainerItemProxy */;
+ };
+ C274C9E22BAB8B2E008E7212 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C274C98C2BAB89C7008E7212 /* SyncWatch */;
+ targetProxy = C274C9E12BAB8B2E008E7212 /* PBXContainerItemProxy */;
+ };
+ C274CA4D2BAB8C23008E7212 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C274C9E42BAB8B92008E7212 /* CommonWatch */;
+ targetProxy = C274CA4C2BAB8C23008E7212 /* PBXContainerItemProxy */;
+ };
+ C274CA522BAB8C35008E7212 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C274C9E42BAB8B92008E7212 /* CommonWatch */;
+ targetProxy = C274CA512BAB8C35008E7212 /* PBXContainerItemProxy */;
+ };
+ C274CA562BAB8C35008E7212 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C274CA242BAB8BE3008E7212 /* ContentWatch */;
+ targetProxy = C274CA552BAB8C35008E7212 /* PBXContainerItemProxy */;
+ };
+ C274CA812BAB8C5B008E7212 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C274C9E42BAB8B92008E7212 /* CommonWatch */;
+ targetProxy = C274CA802BAB8C5B008E7212 /* PBXContainerItemProxy */;
+ };
+ C274CA862BAB8C70008E7212 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C274CA582BAB8C3F008E7212 /* ProtectionWatch */;
+ targetProxy = C274CA852BAB8C70008E7212 /* PBXContainerItemProxy */;
+ };
+ C274CA8B2BAB8CBD008E7212 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C274C9E42BAB8B92008E7212 /* CommonWatch */;
+ targetProxy = C274CA8A2BAB8CBD008E7212 /* PBXContainerItemProxy */;
+ };
+ C274CA8F2BAB8CC0008E7212 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C274CA242BAB8BE3008E7212 /* ContentWatch */;
+ targetProxy = C274CA8E2BAB8CC0008E7212 /* PBXContainerItemProxy */;
+ };
+ C274CA932BAB8CC5008E7212 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C274CA582BAB8C3F008E7212 /* ProtectionWatch */;
+ targetProxy = C274CA922BAB8CC5008E7212 /* PBXContainerItemProxy */;
+ };
C28633D81FFABD2200C8F4B4 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = C28633CA1FFABD2200C8F4B4 /* TwoFASAuth */;
@@ -9587,6 +10838,11 @@
target = C29626D52370BD7F00C133BC /* TimeVerification */;
targetProxy = C29626DB2370BD7F00C133BC /* PBXContainerItemProxy */;
};
+ C2A4D34C2BC0B6C00001587C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C2A4D33D2BC0B6B00001587C /* Base32Watch */;
+ targetProxy = C2A4D34B2BC0B6C00001587C /* PBXContainerItemProxy */;
+ };
C2ACF9EA20A8A918003E0987 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
platformFilter = ios;
@@ -9922,7 +11178,7 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
- MARKETING_VERSION = 5.3.5;
+ MARKETING_VERSION = 5.3.6;
MERGEABLE_LIBRARY = NO;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14";
@@ -9965,7 +11221,7 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
- MARKETING_VERSION = 5.3.5;
+ MARKETING_VERSION = 5.3.6;
MERGEABLE_LIBRARY = NO;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14";
@@ -9983,7 +11239,7 @@
};
name = Release;
};
- C2147CBE205D78600001D011 /* Debug */ = {
+ C213BC4E2BAC3C82000794C9 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
@@ -9997,8 +11253,7 @@
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
- FRAMEWORK_SEARCH_PATHS = "";
- INFOPLIST_FILE = Protection/Info.plist;
+ GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Two Factor Authentication Service, Inc. All rights reserved.";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
@@ -10007,27 +11262,28 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
- MARKETING_VERSION = 5.3.5;
+ MARKETING_VERSION = 1.0;
MERGEABLE_LIBRARY = NO;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14";
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
- PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.Protection;
- PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+ PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.watchkitapp.StorageWatch;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = watchos;
SKIP_INSTALL = YES;
- SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+ SUPPORTED_PLATFORMS = "watchos watchsimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
+ TARGETED_DEVICE_FAMILY = 4;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
- C2147CBF205D78600001D011 /* Release */ = {
+ C213BC4F2BAC3C82000794C9 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
@@ -10041,8 +11297,7 @@
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
- FRAMEWORK_SEARCH_PATHS = "";
- INFOPLIST_FILE = Protection/Info.plist;
+ GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Two Factor Authentication Service, Inc. All rights reserved.";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
@@ -10051,25 +11306,26 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
- MARKETING_VERSION = 5.3.5;
+ MARKETING_VERSION = 1.0;
MERGEABLE_LIBRARY = NO;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14";
- PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.Protection;
- PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+ PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.watchkitapp.StorageWatch;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = watchos;
SKIP_INSTALL = YES;
- SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+ SUPPORTED_PLATFORMS = "watchos watchsimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
+ TARGETED_DEVICE_FAMILY = 4;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
- C21F05C31FC761450038E28F /* Debug */ = {
+ C2147CBE205D78600001D011 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
@@ -10084,7 +11340,7 @@
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_SEARCH_PATHS = "";
- INFOPLIST_FILE = PushNotifications/Info.plist;
+ INFOPLIST_FILE = Protection/Info.plist;
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Two Factor Authentication Service, Inc. All rights reserved.";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
@@ -10093,16 +11349,12 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
- MARKETING_VERSION = 5.3.5;
+ MARKETING_VERSION = 5.3.6;
MERGEABLE_LIBRARY = NO;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14";
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
- OTHER_LDFLAGS = (
- "$(OTHER_LDFLAGS)",
- "-ObjC",
- );
- PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.PushNotifications;
+ PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.Protection;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
@@ -10117,7 +11369,7 @@
};
name = Debug;
};
- C21F05C41FC761450038E28F /* Release */ = {
+ C2147CBF205D78600001D011 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
@@ -10132,7 +11384,7 @@
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_SEARCH_PATHS = "";
- INFOPLIST_FILE = PushNotifications/Info.plist;
+ INFOPLIST_FILE = Protection/Info.plist;
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Two Factor Authentication Service, Inc. All rights reserved.";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
@@ -10141,15 +11393,11 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
- MARKETING_VERSION = 5.3.5;
+ MARKETING_VERSION = 5.3.6;
MERGEABLE_LIBRARY = NO;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14";
- OTHER_LDFLAGS = (
- "$(OTHER_LDFLAGS)",
- "-ObjC",
- );
- PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.PushNotifications;
+ PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.Protection;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
@@ -10163,27 +11411,121 @@
};
name = Release;
};
- C23666861FB2644900989ACA /* Debug */ = {
+ C21F05C31FC761450038E28F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
- CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
- CLANG_ANALYZER_NONNULL = YES;
- CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
- CLANG_CXX_LIBRARY = "libc++";
+ APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = 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;
+ CODE_SIGN_IDENTITY = "";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ DEFINES_MODULE = YES;
+ DEVELOPMENT_TEAM = ZY8UR5ADFW;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ DYLIB_INSTALL_NAME_BASE = "@rpath";
+ FRAMEWORK_SEARCH_PATHS = "";
+ INFOPLIST_FILE = PushNotifications/Info.plist;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Two Factor Authentication Service, Inc. All rights reserved.";
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ IPHONEOS_DEPLOYMENT_TARGET = 16.4;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@loader_path/Frameworks",
+ );
+ MARKETING_VERSION = 5.3.6;
+ MERGEABLE_LIBRARY = NO;
+ MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
+ MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14";
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ OTHER_LDFLAGS = (
+ "$(OTHER_LDFLAGS)",
+ "-ObjC",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.PushNotifications;
+ PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+ SKIP_INSTALL = YES;
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+ SUPPORTS_MACCATALYST = NO;
+ SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
+ SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = "";
+ };
+ name = Debug;
+ };
+ C21F05C41FC761450038E28F /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ APPLICATION_EXTENSION_API_ONLY = YES;
+ CLANG_ENABLE_MODULES = YES;
+ CODE_SIGN_IDENTITY = "";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ DEFINES_MODULE = YES;
+ DEVELOPMENT_TEAM = ZY8UR5ADFW;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ DYLIB_INSTALL_NAME_BASE = "@rpath";
+ FRAMEWORK_SEARCH_PATHS = "";
+ INFOPLIST_FILE = PushNotifications/Info.plist;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Two Factor Authentication Service, Inc. All rights reserved.";
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ IPHONEOS_DEPLOYMENT_TARGET = 16.4;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@loader_path/Frameworks",
+ );
+ MARKETING_VERSION = 5.3.6;
+ MERGEABLE_LIBRARY = NO;
+ MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
+ MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14";
+ OTHER_LDFLAGS = (
+ "$(OTHER_LDFLAGS)",
+ "-ObjC",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.PushNotifications;
+ PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+ SKIP_INSTALL = YES;
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+ SUPPORTS_MACCATALYST = NO;
+ SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
+ SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = "";
+ };
+ name = Release;
+ };
+ C23666861FB2644900989ACA /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = 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;
@@ -10313,7 +11655,7 @@
"@executable_path/Frameworks",
);
MACH_O_TYPE = mh_execute;
- MARKETING_VERSION = 5.3.5;
+ MARKETING_VERSION = 5.3.6;
MERGED_BINARY_TYPE = manual;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
OTHER_LDFLAGS = (
@@ -10358,7 +11700,7 @@
"@executable_path/Frameworks",
);
MACH_O_TYPE = mh_execute;
- MARKETING_VERSION = 5.3.5;
+ MARKETING_VERSION = 5.3.6;
MERGED_BINARY_TYPE = manual;
OTHER_LDFLAGS = (
"$(OTHER_LDFLAGS)",
@@ -10380,22 +11722,461 @@
};
name = Release;
};
- C241D44E278B9E0E00D7C604 /* Debug */ = {
+ C241D44E278B9E0E00D7C604 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ APPLICATION_EXTENSION_API_ONLY = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CODE_SIGN_IDENTITY = "";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ DEFINES_MODULE = YES;
+ DEVELOPMENT_TEAM = ZY8UR5ADFW;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ DYLIB_INSTALL_NAME_BASE = "@rpath";
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Two Factor Authentication Service, Inc. All rights reserved.";
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ IPHONEOS_DEPLOYMENT_TARGET = 16.4;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@loader_path/Frameworks",
+ );
+ MARKETING_VERSION = 5.3.6;
+ MERGEABLE_LIBRARY = NO;
+ MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
+ MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++17";
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.NetworkStack;
+ PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+ SKIP_INSTALL = YES;
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+ SUPPORTS_MACCATALYST = NO;
+ SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
+ SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = "";
+ };
+ name = Debug;
+ };
+ C241D44F278B9E0E00D7C604 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ APPLICATION_EXTENSION_API_ONLY = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CODE_SIGN_IDENTITY = "";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ DEFINES_MODULE = YES;
+ DEVELOPMENT_TEAM = ZY8UR5ADFW;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ DYLIB_INSTALL_NAME_BASE = "@rpath";
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Two Factor Authentication Service, Inc. All rights reserved.";
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ IPHONEOS_DEPLOYMENT_TARGET = 16.4;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@loader_path/Frameworks",
+ );
+ MARKETING_VERSION = 5.3.6;
+ MERGEABLE_LIBRARY = NO;
+ MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
+ MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++17";
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.NetworkStack;
+ PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+ SKIP_INSTALL = YES;
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+ SUPPORTS_MACCATALYST = NO;
+ SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
+ SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = "";
+ };
+ name = Release;
+ };
+ C24D1C32253C744F0029D27D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CODE_SIGN_IDENTITY = "";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ DEFINES_MODULE = YES;
+ DEVELOPMENT_TEAM = ZY8UR5ADFW;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ DYLIB_INSTALL_NAME_BASE = "@rpath";
+ INFOPLIST_FILE = Sync/Other/Info.plist;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Two Factor Authentication Service, Inc. All rights reserved.";
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ IPHONEOS_DEPLOYMENT_TARGET = 16.4;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@loader_path/Frameworks",
+ );
+ MARKETING_VERSION = 5.3.6;
+ MERGEABLE_LIBRARY = NO;
+ MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
+ MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14";
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.Sync;
+ PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+ SKIP_INSTALL = YES;
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+ SUPPORTS_MACCATALYST = NO;
+ SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
+ SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = "";
+ };
+ name = Debug;
+ };
+ C24D1C33253C744F0029D27D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CODE_SIGN_IDENTITY = "";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ DEFINES_MODULE = YES;
+ DEVELOPMENT_TEAM = ZY8UR5ADFW;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ DYLIB_INSTALL_NAME_BASE = "@rpath";
+ INFOPLIST_FILE = Sync/Other/Info.plist;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Two Factor Authentication Service, Inc. All rights reserved.";
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ IPHONEOS_DEPLOYMENT_TARGET = 16.4;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@loader_path/Frameworks",
+ );
+ MARKETING_VERSION = 5.3.6;
+ MERGEABLE_LIBRARY = NO;
+ MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
+ MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14";
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.Sync;
+ PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+ SKIP_INSTALL = YES;
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+ SUPPORTS_MACCATALYST = NO;
+ SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
+ SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = "";
+ };
+ name = Release;
+ };
+ C251EDDD2AE87150007722F2 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CODE_SIGN_IDENTITY = "";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEFINES_MODULE = YES;
+ DEVELOPMENT_TEAM = ZY8UR5ADFW;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ DYLIB_INSTALL_NAME_BASE = "@rpath";
+ ENABLE_MODULE_VERIFIER = NO;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Two Factor Authentication Service, Inc. All rights reserved.";
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ IPHONEOS_DEPLOYMENT_TARGET = 16.4;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@loader_path/Frameworks",
+ );
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MARKETING_VERSION = 5.3.6;
+ MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
+ MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.Base32;
+ PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+ SKIP_INSTALL = YES;
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+ SUPPORTS_MACCATALYST = NO;
+ SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
+ SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = "";
+ };
+ name = Debug;
+ };
+ C251EDDE2AE87150007722F2 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CODE_SIGN_IDENTITY = "";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEFINES_MODULE = YES;
+ DEVELOPMENT_TEAM = ZY8UR5ADFW;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ DYLIB_INSTALL_NAME_BASE = "@rpath";
+ ENABLE_MODULE_VERIFIER = NO;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Two Factor Authentication Service, Inc. All rights reserved.";
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ IPHONEOS_DEPLOYMENT_TARGET = 16.4;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@loader_path/Frameworks",
+ );
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MARKETING_VERSION = 5.3.6;
+ MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
+ MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.Base32;
+ PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+ SKIP_INSTALL = YES;
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+ SUPPORTS_MACCATALYST = NO;
+ SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
+ SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = "";
+ };
+ name = Release;
+ };
+ C274C9C42BAB89C7008E7212 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CODE_SIGN_IDENTITY = "";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ DEFINES_MODULE = YES;
+ DEVELOPMENT_TEAM = ZY8UR5ADFW;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ DYLIB_INSTALL_NAME_BASE = "@rpath";
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Two Factor Authentication Service, Inc. All rights reserved.";
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ IPHONEOS_DEPLOYMENT_TARGET = 16.4;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@loader_path/Frameworks",
+ );
+ MARKETING_VERSION = 1.0;
+ MERGEABLE_LIBRARY = NO;
+ MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
+ MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14";
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.watchkitapp.SyncWatch;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = watchos;
+ SKIP_INSTALL = YES;
+ SUPPORTED_PLATFORMS = "watchos watchsimulator";
+ SUPPORTS_MACCATALYST = NO;
+ SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
+ SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = 4;
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = "";
+ };
+ name = Debug;
+ };
+ C274C9C52BAB89C7008E7212 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CODE_SIGN_IDENTITY = "";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ DEFINES_MODULE = YES;
+ DEVELOPMENT_TEAM = ZY8UR5ADFW;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ DYLIB_INSTALL_NAME_BASE = "@rpath";
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Two Factor Authentication Service, Inc. All rights reserved.";
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ IPHONEOS_DEPLOYMENT_TARGET = 16.4;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@loader_path/Frameworks",
+ );
+ MARKETING_VERSION = 1.0;
+ MERGEABLE_LIBRARY = NO;
+ MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
+ MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14";
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.watchkitapp.SyncWatch;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = watchos;
+ SKIP_INSTALL = YES;
+ SUPPORTED_PLATFORMS = "watchos watchsimulator";
+ SUPPORTS_MACCATALYST = NO;
+ SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
+ SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = 4;
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = "";
+ };
+ name = Release;
+ };
+ C274C9DC2BAB8ABC008E7212 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CODE_SIGN_ENTITLEMENTS = "TwoFASWatch Watch App/TwoFASWatch Watch App.entitlements";
+ CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_ASSET_PATHS = "\"TwoFASWatch Watch App/Preview Content\"";
+ DEVELOPMENT_TEAM = ZY8UR5ADFW;
+ ENABLE_PREVIEWS = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_FILE = "TwoFASWatch-Watch-App-Info.plist";
+ INFOPLIST_KEY_CFBundleDisplayName = "2FAS Auth";
+ INFOPLIST_KEY_NSHumanReadableCopyright = "";
+ INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
+ INFOPLIST_KEY_WKCompanionAppBundleIdentifier = com.twofas.org;
+ INFOPLIST_KEY_WKRunsIndependentlyOfCompanionApp = YES;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MARKETING_VERSION = 1.0;
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.watchkitapp;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = watchos;
+ SKIP_INSTALL = YES;
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = 4;
+ WATCHOS_DEPLOYMENT_TARGET = 10.4;
+ };
+ name = Debug;
+ };
+ C274C9DD2BAB8ABC008E7212 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CODE_SIGN_ENTITLEMENTS = "TwoFASWatch Watch App/TwoFASWatch Watch App.entitlements";
+ CODE_SIGN_IDENTITY = "iPhone Developer";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_ASSET_PATHS = "\"TwoFASWatch Watch App/Preview Content\"";
+ DEVELOPMENT_TEAM = ZY8UR5ADFW;
+ ENABLE_PREVIEWS = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_FILE = "TwoFASWatch-Watch-App-Info.plist";
+ INFOPLIST_KEY_CFBundleDisplayName = "2FAS Auth";
+ INFOPLIST_KEY_NSHumanReadableCopyright = "";
+ INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
+ INFOPLIST_KEY_WKCompanionAppBundleIdentifier = com.twofas.org;
+ INFOPLIST_KEY_WKRunsIndependentlyOfCompanionApp = YES;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MARKETING_VERSION = 1.0;
+ MTL_FAST_MATH = YES;
+ PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.watchkitapp;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = watchos;
+ SKIP_INSTALL = YES;
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = 4;
+ WATCHOS_DEPLOYMENT_TARGET = 10.4;
+ };
+ name = Release;
+ };
+ C274CA212BAB8B92008E7212 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- APPLICATION_EXTENSION_API_ONLY = YES;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
- CLANG_ENABLE_MODULES = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_OBJC_WEAK = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
- DEBUG_INFORMATION_FORMAT = dwarf;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = ZY8UR5ADFW;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
+ ENABLE_MODULE_VERIFIER = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Two Factor Authentication Service, Inc. All rights reserved.";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
@@ -10405,44 +12186,45 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
- MARKETING_VERSION = 5.3.5;
- MERGEABLE_LIBRARY = NO;
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MARKETING_VERSION = 1.0;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
- MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++17";
+ MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
- PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.NetworkStack;
- PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+ PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.watchkitapp.CommonWatch;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = watchos;
SKIP_INSTALL = YES;
- SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+ SUPPORTED_PLATFORMS = "watchos watchsimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
SWIFT_EMIT_LOC_STRINGS = YES;
- SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
+ TARGETED_DEVICE_FAMILY = 4;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
- C241D44F278B9E0E00D7C604 /* Release */ = {
+ C274CA222BAB8B92008E7212 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- APPLICATION_EXTENSION_API_ONLY = YES;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
- CLANG_ENABLE_MODULES = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_OBJC_WEAK = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
- DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = ZY8UR5ADFW;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
+ ENABLE_MODULE_VERIFIER = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Two Factor Authentication Service, Inc. All rights reserved.";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
@@ -10452,41 +12234,44 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
- MARKETING_VERSION = 5.3.5;
- MERGEABLE_LIBRARY = NO;
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MARKETING_VERSION = 1.0;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
- MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++17";
+ MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
MTL_FAST_MATH = YES;
- PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.NetworkStack;
- PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+ PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.watchkitapp.CommonWatch;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = watchos;
SKIP_INSTALL = YES;
- SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+ SUPPORTED_PLATFORMS = "watchos watchsimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
+ TARGETED_DEVICE_FAMILY = 4;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
- C24D1C32253C744F0029D27D /* Debug */ = {
+ C274CA472BAB8BE3008E7212 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- CLANG_ENABLE_MODULES = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_OBJC_WEAK = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
- DEBUG_INFORMATION_FORMAT = dwarf;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = ZY8UR5ADFW;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
- INFOPLIST_FILE = Sync/Other/Info.plist;
+ ENABLE_MODULE_VERIFIER = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Two Factor Authentication Service, Inc. All rights reserved.";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
@@ -10495,42 +12280,46 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
- MARKETING_VERSION = 5.3.5;
- MERGEABLE_LIBRARY = NO;
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MARKETING_VERSION = 1.0;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
- MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14";
+ MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
- PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.Sync;
- PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+ PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.watchkitapp.ContentWatch;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = watchos;
SKIP_INSTALL = YES;
- SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+ SUPPORTED_PLATFORMS = "watchos watchsimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
- SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
+ SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
+ TARGETED_DEVICE_FAMILY = 4;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
- C24D1C33253C744F0029D27D /* Release */ = {
+ C274CA482BAB8BE3008E7212 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- CLANG_ENABLE_MODULES = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_OBJC_WEAK = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
- DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = ZY8UR5ADFW;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
- INFOPLIST_FILE = Sync/Other/Info.plist;
+ ENABLE_MODULE_VERIFIER = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Two Factor Authentication Service, Inc. All rights reserved.";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 16.4;
@@ -10539,41 +12328,42 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
- MARKETING_VERSION = 5.3.5;
- MERGEABLE_LIBRARY = NO;
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MARKETING_VERSION = 1.0;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
- MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14";
+ MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
MTL_FAST_MATH = YES;
- PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.Sync;
- PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+ PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.watchkitapp.ContentWatch;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = watchos;
SKIP_INSTALL = YES;
- SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+ SUPPORTED_PLATFORMS = "watchos watchsimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
+ SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
+ TARGETED_DEVICE_FAMILY = 4;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
- C251EDDD2AE87150007722F2 /* Debug */ = {
+ C274CA7A2BAB8C3F008E7212 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
- CLANG_ENABLE_OBJC_WEAK = YES;
+ APPLICATION_EXTENSION_API_ONLY = YES;
+ CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
+ DEBUG_INFORMATION_FORMAT = dwarf;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = ZY8UR5ADFW;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
- ENABLE_MODULE_VERIFIER = NO;
- ENABLE_USER_SCRIPT_SANDBOXING = YES;
- GCC_C_LANGUAGE_STANDARD = gnu17;
+ FRAMEWORK_SEARCH_PATHS = "";
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Two Factor Authentication Service, Inc. All rights reserved.";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
@@ -10583,42 +12373,42 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
- LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
- MARKETING_VERSION = 5.3.5;
+ MARKETING_VERSION = 1.0;
+ MERGEABLE_LIBRARY = NO;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
- MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
+ MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14";
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
- MTL_FAST_MATH = YES;
- PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.Base32;
- PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+ PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.watchkitapp.ProtectionWatch;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = watchos;
SKIP_INSTALL = YES;
- SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+ SUPPORTED_PLATFORMS = "watchos watchsimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
- SWIFT_EMIT_LOC_STRINGS = YES;
- TARGETED_DEVICE_FAMILY = "1,2";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = 4;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
- C251EDDE2AE87150007722F2 /* Release */ = {
+ C274CA7B2BAB8C3F008E7212 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
- CLANG_ENABLE_OBJC_WEAK = YES;
+ APPLICATION_EXTENSION_API_ONLY = YES;
+ CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = ZY8UR5ADFW;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
- ENABLE_MODULE_VERIFIER = NO;
- ENABLE_USER_SCRIPT_SANDBOXING = YES;
- GCC_C_LANGUAGE_STANDARD = gnu17;
+ FRAMEWORK_SEARCH_PATHS = "";
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Two Factor Authentication Service, Inc. All rights reserved.";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
@@ -10628,20 +12418,20 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
- LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
- MARKETING_VERSION = 5.3.5;
+ MARKETING_VERSION = 1.0;
+ MERGEABLE_LIBRARY = NO;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
- MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
- MTL_FAST_MATH = YES;
- PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.Base32;
- PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+ MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14";
+ PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.watchkitapp.ProtectionWatch;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = watchos;
SKIP_INSTALL = YES;
- SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+ SUPPORTED_PLATFORMS = "watchos watchsimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
- SWIFT_EMIT_LOC_STRINGS = YES;
- TARGETED_DEVICE_FAMILY = "1,2";
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = 4;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
@@ -10666,7 +12456,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 5.3.5;
+ MARKETING_VERSION = 5.3.6;
MERGED_BINARY_TYPE = manual;
PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.TwoFASAuth;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -10700,7 +12490,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 5.3.5;
+ MARKETING_VERSION = 5.3.6;
MERGED_BINARY_TYPE = manual;
PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.TwoFASAuth;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -10739,7 +12529,7 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
- MARKETING_VERSION = 5.3.5;
+ MARKETING_VERSION = 5.3.6;
MERGEABLE_LIBRARY = NO;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14";
@@ -10784,7 +12574,7 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
- MARKETING_VERSION = 5.3.5;
+ MARKETING_VERSION = 5.3.6;
MERGEABLE_LIBRARY = NO;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14";
@@ -10803,6 +12593,101 @@
};
name = Release;
};
+ C2A4D3462BC0B6B00001587C /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CODE_SIGN_IDENTITY = "";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEFINES_MODULE = YES;
+ DEVELOPMENT_TEAM = ZY8UR5ADFW;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ DYLIB_INSTALL_NAME_BASE = "@rpath";
+ ENABLE_MODULE_VERIFIER = NO;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Two Factor Authentication Service, Inc. All rights reserved.";
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ IPHONEOS_DEPLOYMENT_TARGET = 16.4;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@loader_path/Frameworks",
+ );
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MARKETING_VERSION = 1.0;
+ MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
+ MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ MTL_FAST_MATH = YES;
+ PRIVATE_HEADERS_FOLDER_PATH = Base32.framework/PrivateHeaders;
+ PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.watchkitapp.Base32Watch;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PUBLIC_HEADERS_FOLDER_PATH = Base32.framework/Headers;
+ SDKROOT = watchos;
+ SKIP_INSTALL = YES;
+ SUPPORTED_PLATFORMS = "watchos watchsimulator";
+ SUPPORTS_MACCATALYST = NO;
+ SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
+ SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ TARGETED_DEVICE_FAMILY = 4;
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = "";
+ };
+ name = Debug;
+ };
+ C2A4D3472BC0B6B00001587C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CODE_SIGN_IDENTITY = "";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEFINES_MODULE = YES;
+ DEVELOPMENT_TEAM = ZY8UR5ADFW;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ DYLIB_INSTALL_NAME_BASE = "@rpath";
+ ENABLE_MODULE_VERIFIER = NO;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Two Factor Authentication Service, Inc. All rights reserved.";
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ IPHONEOS_DEPLOYMENT_TARGET = 16.4;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@loader_path/Frameworks",
+ );
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MARKETING_VERSION = 1.0;
+ MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
+ MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
+ MTL_FAST_MATH = YES;
+ PRIVATE_HEADERS_FOLDER_PATH = Base32.framework/PrivateHeaders;
+ PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.watchkitapp.Base32Watch;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PUBLIC_HEADERS_FOLDER_PATH = Base32.framework/Headers;
+ SDKROOT = watchos;
+ SKIP_INSTALL = YES;
+ SUPPORTED_PLATFORMS = "watchos watchsimulator";
+ SUPPORTS_MACCATALYST = NO;
+ SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
+ SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ TARGETED_DEVICE_FAMILY = 4;
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = "";
+ };
+ name = Release;
+ };
C2ACF9EC20A8A918003E0987 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@@ -10882,7 +12767,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 5.3.5;
+ MARKETING_VERSION = 5.3.6;
MERGED_BINARY_TYPE = manual;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
@@ -10918,7 +12803,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 5.3.5;
+ MARKETING_VERSION = 5.3.6;
MERGED_BINARY_TYPE = manual;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.TwoFASWidget;
@@ -10951,7 +12836,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 5.3.5;
+ MARKETING_VERSION = 5.3.6;
MERGED_BINARY_TYPE = manual;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
@@ -10985,7 +12870,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 5.3.5;
+ MARKETING_VERSION = 5.3.6;
MERGED_BINARY_TYPE = manual;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.twofas.org.TwoFASServiceIntent;
@@ -11082,7 +12967,7 @@
"@loader_path/Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
- MARKETING_VERSION = 5.3.5;
+ MARKETING_VERSION = 5.3.6;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
@@ -11129,7 +13014,7 @@
"@loader_path/Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
- MARKETING_VERSION = 5.3.5;
+ MARKETING_VERSION = 5.3.6;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
MTL_FAST_MATH = YES;
@@ -11174,7 +13059,7 @@
"@loader_path/Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
- MARKETING_VERSION = 5.3.5;
+ MARKETING_VERSION = 5.3.6;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
@@ -11221,7 +13106,7 @@
"@loader_path/Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
- MARKETING_VERSION = 5.3.5;
+ MARKETING_VERSION = 5.3.6;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
MTL_FAST_MATH = YES;
@@ -11266,7 +13151,7 @@
"@loader_path/Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
- MARKETING_VERSION = 5.3.5;
+ MARKETING_VERSION = 5.3.6;
MERGEABLE_LIBRARY = NO;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
@@ -11314,7 +13199,7 @@
"@loader_path/Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
- MARKETING_VERSION = 5.3.5;
+ MARKETING_VERSION = 5.3.6;
MERGEABLE_LIBRARY = NO;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
@@ -11360,7 +13245,7 @@
"@loader_path/Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
- MARKETING_VERSION = 5.3.5;
+ MARKETING_VERSION = 5.3.6;
MERGEABLE_LIBRARY = NO;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
@@ -11408,7 +13293,7 @@
"@loader_path/Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
- MARKETING_VERSION = 5.3.5;
+ MARKETING_VERSION = 5.3.6;
MERGEABLE_LIBRARY = NO;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
@@ -11502,6 +13387,15 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
+ C213BC4D2BAC3C82000794C9 /* Build configuration list for PBXNativeTarget "StorageWatch" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C213BC4E2BAC3C82000794C9 /* Debug */,
+ C213BC4F2BAC3C82000794C9 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
C2147CC0205D78600001D011 /* Build configuration list for PBXNativeTarget "Protection" */ = {
isa = XCConfigurationList;
buildConfigurations = (
@@ -11565,6 +13459,51 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
+ C274C9C32BAB89C7008E7212 /* Build configuration list for PBXNativeTarget "SyncWatch" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C274C9C42BAB89C7008E7212 /* Debug */,
+ C274C9C52BAB89C7008E7212 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ C274C9DB2BAB8ABC008E7212 /* Build configuration list for PBXNativeTarget "TwoFASWatch Watch App" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C274C9DC2BAB8ABC008E7212 /* Debug */,
+ C274C9DD2BAB8ABC008E7212 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ C274CA202BAB8B92008E7212 /* Build configuration list for PBXNativeTarget "CommonWatch" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C274CA212BAB8B92008E7212 /* Debug */,
+ C274CA222BAB8B92008E7212 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ C274CA462BAB8BE3008E7212 /* Build configuration list for PBXNativeTarget "ContentWatch" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C274CA472BAB8BE3008E7212 /* Debug */,
+ C274CA482BAB8BE3008E7212 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ C274CA792BAB8C3F008E7212 /* Build configuration list for PBXNativeTarget "ProtectionWatch" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C274CA7A2BAB8C3F008E7212 /* Debug */,
+ C274CA7B2BAB8C3F008E7212 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
C28633DC1FFABD2200C8F4B4 /* Build configuration list for PBXNativeTarget "TwoFASAuth" */ = {
isa = XCConfigurationList;
buildConfigurations = (
@@ -11583,6 +13522,15 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
+ C2A4D3452BC0B6B00001587C /* Build configuration list for PBXNativeTarget "Base32Watch" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C2A4D3462BC0B6B00001587C /* Debug */,
+ C2A4D3472BC0B6B00001587C /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
C2ACF9EB20A8A918003E0987 /* Build configuration list for PBXNativeTarget "TwoFASTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
@@ -11784,6 +13732,28 @@
/* End XCSwiftPackageProductDependency section */
/* Begin XCVersionGroup section */
+ C213BC6E2BAC5758000794C9 /* TwoFAS.xcdatamodeld */ = {
+ isa = XCVersionGroup;
+ children = (
+ C213BC6F2BAC5758000794C9 /* TwoFAS.xcdatamodel */,
+ );
+ currentVersion = C213BC6F2BAC5758000794C9 /* TwoFAS.xcdatamodel */;
+ name = TwoFAS.xcdatamodeld;
+ path = /Users/adocyn/Documents/Projects/2FAS/TwoFAS/Storage/Watch/TwoFAS.xcdatamodeld;
+ sourceTree = "";
+ versionGroupType = wrapper.xcdatamodel;
+ };
+ C213BC712BAC5771000794C9 /* Sync.xcdatamodeld */ = {
+ isa = XCVersionGroup;
+ children = (
+ C213BC722BAC5771000794C9 /* Sync.xcdatamodel */,
+ );
+ currentVersion = C213BC722BAC5771000794C9 /* Sync.xcdatamodel */;
+ name = Sync.xcdatamodeld;
+ path = /Users/adocyn/Documents/Projects/2FAS/TwoFAS/Sync/Watch/Sync.xcdatamodeld;
+ sourceTree = "";
+ versionGroupType = wrapper.xcdatamodel;
+ };
C22CF3DD27413F0F004F6A03 /* LogStorage.xcdatamodeld */ = {
isa = XCVersionGroup;
children = (
diff --git a/TwoFAS/TwoFAS.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/TwoFAS/TwoFAS.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
index b01caed1..c2b3dac8 100644
--- a/TwoFAS/TwoFAS.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
+++ b/TwoFAS/TwoFAS.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -1,4 +1,5 @@
{
+ "originHash" : "3a5d1c1c86b0fe1fe7714b4d6f9f919d15a59ac141c544a77363f813f806c0d8",
"pins" : [
{
"identity" : "abseil-cpp-binary",
@@ -163,5 +164,5 @@
}
}
],
- "version" : 2
+ "version" : 3
}
diff --git a/TwoFAS/TwoFAS.xcodeproj/xcshareddata/xcschemes/Base32 copy.xcscheme b/TwoFAS/TwoFAS.xcodeproj/xcshareddata/xcschemes/Base32 copy.xcscheme
new file mode 100644
index 00000000..bd3442c4
--- /dev/null
+++ b/TwoFAS/TwoFAS.xcodeproj/xcshareddata/xcschemes/Base32 copy.xcscheme
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/TwoFAS/TwoFAS.xcodeproj/xcshareddata/xcschemes/CommonWatch.xcscheme b/TwoFAS/TwoFAS.xcodeproj/xcshareddata/xcschemes/CommonWatch.xcscheme
new file mode 100644
index 00000000..ee14e81e
--- /dev/null
+++ b/TwoFAS/TwoFAS.xcodeproj/xcshareddata/xcschemes/CommonWatch.xcscheme
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/TwoFAS/TwoFAS.xcodeproj/xcshareddata/xcschemes/ContentWatch.xcscheme b/TwoFAS/TwoFAS.xcodeproj/xcshareddata/xcschemes/ContentWatch.xcscheme
new file mode 100644
index 00000000..059b73d7
--- /dev/null
+++ b/TwoFAS/TwoFAS.xcodeproj/xcshareddata/xcschemes/ContentWatch.xcscheme
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/TwoFAS/TwoFAS.xcodeproj/xcshareddata/xcschemes/ProtectionWatch.xcscheme b/TwoFAS/TwoFAS.xcodeproj/xcshareddata/xcschemes/ProtectionWatch.xcscheme
new file mode 100644
index 00000000..98263bc3
--- /dev/null
+++ b/TwoFAS/TwoFAS.xcodeproj/xcshareddata/xcschemes/ProtectionWatch.xcscheme
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/TwoFAS/TwoFAS.xcodeproj/xcshareddata/xcschemes/StorageWatch.xcscheme b/TwoFAS/TwoFAS.xcodeproj/xcshareddata/xcschemes/StorageWatch.xcscheme
new file mode 100644
index 00000000..50c430fe
--- /dev/null
+++ b/TwoFAS/TwoFAS.xcodeproj/xcshareddata/xcschemes/StorageWatch.xcscheme
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/TwoFAS/TwoFAS.xcodeproj/xcshareddata/xcschemes/SyncWatch.xcscheme b/TwoFAS/TwoFAS.xcodeproj/xcshareddata/xcschemes/SyncWatch.xcscheme
new file mode 100644
index 00000000..59be5b09
--- /dev/null
+++ b/TwoFAS/TwoFAS.xcodeproj/xcshareddata/xcschemes/SyncWatch.xcscheme
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/TwoFAS/TwoFAS.xcodeproj/xcshareddata/xcschemes/TwoFAS.xcscheme b/TwoFAS/TwoFAS.xcodeproj/xcshareddata/xcschemes/TwoFAS.xcscheme
index 59d243bf..25ebb3e6 100644
--- a/TwoFAS/TwoFAS.xcodeproj/xcshareddata/xcschemes/TwoFAS.xcscheme
+++ b/TwoFAS/TwoFAS.xcodeproj/xcshareddata/xcschemes/TwoFAS.xcscheme
@@ -37,17 +37,6 @@
-
-
-
-
@@ -70,17 +59,6 @@
ReferencedContainer = "container:TwoFAS.xcodeproj">
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/TwoFAS/TwoFAS.xcodeproj/xcshareddata/xcschemes/TwoFASWatch Watch App.xcscheme b/TwoFAS/TwoFAS.xcodeproj/xcshareddata/xcschemes/TwoFASWatch Watch App.xcscheme
new file mode 100644
index 00000000..3c47e1a9
--- /dev/null
+++ b/TwoFAS/TwoFAS.xcodeproj/xcshareddata/xcschemes/TwoFASWatch Watch App.xcscheme
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/TwoFAS/TwoFAS/Common/Controls/HUDNotification.swift b/TwoFAS/TwoFAS/Common/Controls/HUDNotification.swift
index e98838a4..0899b704 100644
--- a/TwoFAS/TwoFAS/Common/Controls/HUDNotification.swift
+++ b/TwoFAS/TwoFAS/Common/Controls/HUDNotification.swift
@@ -22,22 +22,22 @@ import PKHUD
import Common
enum HUDNotification {
- static func presentSuccess(title: String, completion: Callback? = nil) {
+ static func presentSuccess(title: String, on view: UIView? = nil, completion: Callback? = nil) {
HUD.dimsBackground = false
HUD.allowsInteraction = false
PKHUD.sharedHUD.effect = UIBlurEffect(style: .dark)
let notification = NotificationIcon(title: title, iconKind: .success)
- HUD.flash(HUDContentType.customView(view: notification), delay: 1) { _ in
+ HUD.flash(HUDContentType.customView(view: notification), onView: view, delay: 1) { _ in
completion?()
}
}
- static func presentFailure(title: String, completion: Callback? = nil) {
+ static func presentFailure(title: String, on view: UIView? = nil, completion: Callback? = nil) {
HUD.dimsBackground = false
HUD.allowsInteraction = false
PKHUD.sharedHUD.effect = UIBlurEffect(style: .dark)
let notification = NotificationIcon(title: title, iconKind: .failure)
- HUD.flash(HUDContentType.customView(view: notification), delay: 1) { _ in
+ HUD.flash(HUDContentType.customView(view: notification), onView: view, delay: 1) { _ in
completion?()
}
}
diff --git a/TwoFAS/TwoFAS/Common/PINType+.swift b/TwoFAS/TwoFAS/Common/PINType+.swift
index 0872ca31..5231a26e 100644
--- a/TwoFAS/TwoFAS/Common/PINType+.swift
+++ b/TwoFAS/TwoFAS/Common/PINType+.swift
@@ -18,7 +18,7 @@
//
import Foundation
-import Data
+import Common
extension PINType {
var localized: String {
diff --git a/TwoFAS/TwoFAS/Interactors/ModuleInteractorFactory.swift b/TwoFAS/TwoFAS/Interactors/ModuleInteractorFactory.swift
index 5a289acf..c3e166de 100644
--- a/TwoFAS/TwoFAS/Interactors/ModuleInteractorFactory.swift
+++ b/TwoFAS/TwoFAS/Interactors/ModuleInteractorFactory.swift
@@ -24,6 +24,8 @@ import Common
final class ModuleInteractorFactory {
static let shared = ModuleInteractorFactory()
+ private init() {}
+
func rootModuleInteractor() -> RootModuleInteracting {
RootModuleInteractor(
rootInteractor: InteractorFactory.shared.rootInteractor(),
diff --git a/TwoFAS/TwoFAS/Other/Generated/T.generated.swift b/TwoFAS/TwoFAS/Other/Generated/T.generated.swift
index c8741620..8e168167 100644
--- a/TwoFAS/TwoFAS/Other/Generated/T.generated.swift
+++ b/TwoFAS/TwoFAS/Other/Generated/T.generated.swift
@@ -284,8 +284,8 @@ internal enum T {
internal static let name = T.tr("Localizable", "app__name", fallback: "2FAS Authenticator")
}
internal enum Appearance {
- /// Active search on startup
- internal static let activeSearchDescription = T.tr("Localizable", "appearance__active_search_description", fallback: "Active search on startup")
+ /// Active search on startup.
+ internal static let activeSearchDescription = T.tr("Localizable", "appearance__active_search_description", fallback: "Active search on startup.")
/// Active search
internal static let toggleActiveSearch = T.tr("Localizable", "appearance__toggle_active_search", fallback: "Active search")
}
@@ -336,8 +336,8 @@ internal enum T {
internal static let exportToFile = T.tr("Localizable", "backup__export_to_file", fallback: "Export to file")
/// File Backup
internal static let fileBackup = T.tr("Localizable", "backup__file_backup", fallback: "File Backup")
- /// Use File Backup for offline backup of your tokens
- internal static let fileBackupOfflineTitle = T.tr("Localizable", "backup__file_backup_offline_title", fallback: "Use File Backup for offline backup of your tokens")
+ /// Use File Backup for offline backup of your tokens.
+ internal static let fileBackupOfflineTitle = T.tr("Localizable", "backup__file_backup_offline_title", fallback: "Use File Backup for offline backup of your tokens.")
/// File error!
internal static let fileError = T.tr("Localizable", "backup__file_error", fallback: "File error!")
/// Google Drive has been disabled by the user
@@ -442,8 +442,8 @@ internal enum T {
internal static let userOverQuotaIcloud = T.tr("Localizable", "backup__user_over_quota_icloud", fallback: "User is over quota on iCloud")
/// Verify PIN
internal static let verifyPin = T.tr("Localizable", "backup__verify_pin", fallback: "Verify PIN")
- /// Warning! If you delete 2FAS Backup, you will also erase all tokens from other devices synced with this account. To preserve the tokens on other devices, please ensure that you've turned off the 2FAS Backup before the deletion
- internal static let warningIntroduction = T.tr("Localizable", "backup__warning_introduction", fallback: "Warning! If you delete 2FAS Backup, you will also erase all tokens from other devices synced with this account. To preserve the tokens on other devices, please ensure that you've turned off the 2FAS Backup before the deletion")
+ /// Warning! If you delete 2FAS Backup, you will also erase all tokens from other devices synced with this account. To preserve the tokens on other devices, please ensure that you've turned off the 2FAS Backup before the deletion.
+ internal static let warningIntroduction = T.tr("Localizable", "backup__warning_introduction", fallback: "Warning! If you delete 2FAS Backup, you will also erase all tokens from other devices synced with this account. To preserve the tokens on other devices, please ensure that you've turned off the 2FAS Backup before the deletion.")
}
internal enum Browser {
/// Do you want to share the 2FA token for
@@ -482,8 +482,8 @@ internal enum T {
internal static let deviceName = T.tr("Localizable", "browser__device_name", fallback: "Device nickname")
/// Forget this web browser
internal static let forgetThisBrowser = T.tr("Localizable", "browser__forget_this_browser", fallback: "Forget this web browser")
- /// Install the 2FAS browser extension on your desktop computer
- internal static let infoDescriptionFirst = T.tr("Localizable", "browser__info_description_first", fallback: "Install the 2FAS browser extension on your desktop computer")
+ /// Install the 2FAS browser extension on your desktop computer.
+ internal static let infoDescriptionFirst = T.tr("Localizable", "browser__info_description_first", fallback: "Install the 2FAS browser extension on your desktop computer.")
/// Pair it with your 2FAS app.
internal static let infoDescriptionSecond = T.tr("Localizable", "browser__info_description_second", fallback: "Pair it with your 2FAS app.")
/// 2FAS Web Browser extension
@@ -666,6 +666,8 @@ internal enum T {
internal static let `set` = T.tr("Localizable", "commons__set", fallback: "Set")
/// Skip
internal static let skip = T.tr("Localizable", "commons__skip", fallback: "Skip")
+ /// Success
+ internal static let success = T.tr("Localizable", "commons__success", fallback: "Success")
/// The provided text is too long (max. %d chars)
internal static func textLongTitle(_ p1: Int) -> String {
return T.tr("Localizable", "commons__text_long_title", p1, fallback: "The provided text is too long (max. %d chars)")
@@ -970,8 +972,12 @@ internal enum T {
internal static let enterCurrentPin = T.tr("Localizable", "security__enter_current_pin", fallback: "Please enter your current PIN")
/// Please enter your new PIN
internal static let enterNewPin = T.tr("Localizable", "security__enter_new_pin", fallback: "Please enter your new PIN")
+ /// Enter new PIN
+ internal static let enterNewPinShort = T.tr("Localizable", "security__enter_new_pin_short", fallback: "Enter new PIN")
/// Please enter your PIN
internal static let enterPin = T.tr("Localizable", "security__enter_pin", fallback: "Please enter your PIN")
+ /// Enter PIN
+ internal static let enterPinShort = T.tr("Localizable", "security__enter_pin_short", fallback: "Enter PIN")
/// Please enter your new %s PIN
internal static func enterYourNewPin(_ p1: UnsafePointer) -> String {
return T.tr("Localizable", "security__enter_your_new_pin", p1, fallback: "Please enter your new %s PIN")
@@ -980,6 +986,8 @@ internal enum T {
internal static let incorrectPIN = T.tr("Localizable", "security__incorrect_PIN", fallback: "Incorrect PIN")
/// PIN incorrect! Please try again
internal static let pinErrorIncorrect = T.tr("Localizable", "security__pin_error_incorrect", fallback: "PIN incorrect! Please try again")
+ /// Repeat new PIN
+ internal static let repeatNewPinShort = T.tr("Localizable", "security__repeat_new_pin_short", fallback: "Repeat new PIN")
/// Too many attempts. Please try again later.
internal static let tooManyAttemptsError = T.tr("Localizable", "security__too_many_attempts_error", fallback: "Too many attempts. Please try again later.")
/// Too many attempts. Please try after one minute
@@ -1053,16 +1061,15 @@ internal enum T {
internal static let gdSyncInfo = T.tr("Localizable", "settings__gd_sync_info", fallback: "Google Drive sync reminder")
/// General
internal static let general = T.tr("Localizable", "settings__general", fallback: "General")
- /// Tokens will be revealed on tap
- internal static let hideTokensDescription = T.tr("Localizable", "settings__hide_tokens_description", fallback: "Tokens will be revealed on tap")
+ /// Tokens will be revealed on tap.
+ internal static let hideTokensDescription = T.tr("Localizable", "settings__hide_tokens_description", fallback: "Tokens will be revealed on tap.")
/// Hide tokens
internal static let hideTokensTitle = T.tr("Localizable", "settings__hide_tokens_title", fallback: "Hide tokens")
/// Select the maximum number of unsuccessful attempts to enter the passcode before locking the application (lockout time can be changed below).
///
internal static let howManyAttemptsFooter = T.tr("Localizable", "settings__how_many_attempts_footer", fallback: "Select the maximum number of unsuccessful attempts to enter the passcode before locking the application (lockout time can be changed below).\n")
- /// Your support allows us to develop new features and
- /// improvements. Thank you!
- internal static let infoFooter = T.tr("Localizable", "settings__info_footer", fallback: "Your support allows us to develop new features and\nimprovements. Thank you!")
+ /// Your support allows us to develop new features and improvements. Thank you!
+ internal static let infoFooter = T.tr("Localizable", "settings__info_footer", fallback: "Your support allows us to develop new features and improvements. Thank you!")
/// It matters
internal static let itMatters = T.tr("Localizable", "settings__it_matters", fallback: "It matters")
/// Knowledge
@@ -1314,6 +1321,8 @@ internal enum T {
internal static let enterServiceName = T.tr("Localizable", "tokens__enter_service_name", fallback: "Enter Service Name")
/// Add manually
internal static let fabAddmanually = T.tr("Localizable", "tokens__fab_addmanually", fallback: "Add manually")
+ /// Favorite Services
+ internal static let favoriteServices = T.tr("Localizable", "tokens__favorite_services", fallback: "Favorite Services")
/// Service added successfully. We strongly recommend that you
internal static let galleryAdviceContentFirst = T.tr("Localizable", "tokens__gallery_advice_content_first", fallback: "Service added successfully. We strongly recommend that you ")
///
@@ -1339,6 +1348,8 @@ internal enum T {
internal static let groupName = T.tr("Localizable", "tokens__group_name", fallback: "Group name:")
/// HOTP
internal static let hotp = T.tr("Localizable", "tokens__hotp", fallback: "HOTP")
+ /// HOTP services aren't supported yet
+ internal static let hotpNotSupported = T.tr("Localizable", "tokens__hotp_not_supported", fallback: "HOTP services aren't supported yet")
/// Yes, I want to delete this service
internal static let iWantToDeleteThisToken = T.tr("Localizable", "tokens__i_want_to_delete_this_token", fallback: "Yes, I want to delete this service")
/// Incorrect Secret key (only numbers 2 to 7, letters), max. 512 chars long
@@ -1590,6 +1601,36 @@ internal enum T {
/// Use the Add Service button to add a new service
internal static let useAddServiceButtonTitle = T.tr("Localizable", "voiceover__use_add_service_button_title", fallback: "Use the Add Service button to add a new service")
}
+ internal enum Watch {
+ /// 2FAS watchOS app is a companion app for the 2FAS iOS application. It will present services backed up using iCloud sync.
+ ///
+ /// For quick access, add them to Favorite Services.
+ ///
+ /// Please remember to donate so we can further improve the 2FAS platform!
+ internal static let intro = T.tr("Localizable", "watch__intro", fallback: "2FAS watchOS app is a companion app for the 2FAS iOS application. It will present services backed up using iCloud sync.\n\nFor quick access, add them to Favorite Services.\n\nPlease remember to donate so we can further improve the 2FAS platform!")
+ }
+ internal enum Widget {
+ /// My secured account
+ internal static let mySecuredAccount = T.tr("Localizable", "widget__my_secured_account", fallback: "My secured account")
+ /// There are no services in the app available for selection
+ internal static let noServices = T.tr("Localizable", "widget__no_services", fallback: "There are no services in the app available for selection")
+ /// Widget functionality is not enabled in 2FAS Settings section
+ internal static let notEnabled = T.tr("Localizable", "widget__not_enabled", fallback: "Widget functionality is not enabled in 2FAS Settings section")
+ /// Widget functionality is not enabled in 2FAS Settings section and there are no services in the app available for selection
+ internal static let notEnabledNoServices = T.tr("Localizable", "widget__not_enabled_no_services", fallback: "Widget functionality is not enabled in 2FAS Settings section and there are no services in the app available for selection")
+ /// Placeholder
+ internal static let placeholder = T.tr("Localizable", "widget__placeholder", fallback: "Placeholder")
+ /// Select Service you want to show on your 2FAS Widget
+ internal static let selectServiceIntentDescription = T.tr("Localizable", "widget__select_service_intent_description", fallback: "Select Service you want to show on your 2FAS Widget")
+ /// Service icon
+ internal static let serviceIcon = T.tr("Localizable", "widget__service_icon", fallback: "Service icon")
+ /// Select which Services you would like to display on the Widget. If no Services are available, make sure that you've enabled Widgets in app Settings section
+ internal static let settingsDescription = T.tr("Localizable", "widget__settings_description", fallback: "Select which Services you would like to display on the Widget. If no Services are available, make sure that you've enabled Widgets in app Settings section")
+ /// This size is not supported yet
+ internal static let sizeNotSupported = T.tr("Localizable", "widget__size_not_supported", fallback: "This size is not supported yet")
+ /// Token
+ internal static let token = T.tr("Localizable", "widget__token", fallback: "Token")
+ }
internal enum Widgets {
/// Expires in:
internal static let expiresIn = T.tr("Localizable", "widgets__expires_in", fallback: "Expires in:")
diff --git a/TwoFAS/TwoFAS/Other/de.lproj/Localizable.strings b/TwoFAS/TwoFAS/Other/de.lproj/Localizable.strings
index 4a495fd6..4abb1af5 100644
Binary files a/TwoFAS/TwoFAS/Other/de.lproj/Localizable.strings and b/TwoFAS/TwoFAS/Other/de.lproj/Localizable.strings differ
diff --git a/TwoFAS/TwoFAS/Other/en.lproj/Localizable.strings b/TwoFAS/TwoFAS/Other/en.lproj/Localizable.strings
index c120004c..889c1418 100644
Binary files a/TwoFAS/TwoFAS/Other/en.lproj/Localizable.strings and b/TwoFAS/TwoFAS/Other/en.lproj/Localizable.strings differ
diff --git a/TwoFAS/TwoFAS/Other/es.lproj/Localizable.strings b/TwoFAS/TwoFAS/Other/es.lproj/Localizable.strings
index aadb08b5..61eb28cd 100644
Binary files a/TwoFAS/TwoFAS/Other/es.lproj/Localizable.strings and b/TwoFAS/TwoFAS/Other/es.lproj/Localizable.strings differ
diff --git a/TwoFAS/TwoFAS/Other/fr.lproj/Localizable.strings b/TwoFAS/TwoFAS/Other/fr.lproj/Localizable.strings
index 7ba6c21d..5615999e 100644
Binary files a/TwoFAS/TwoFAS/Other/fr.lproj/Localizable.strings and b/TwoFAS/TwoFAS/Other/fr.lproj/Localizable.strings differ
diff --git a/TwoFAS/TwoFAS/Other/id.lproj/Localizable.strings b/TwoFAS/TwoFAS/Other/id.lproj/Localizable.strings
index c481eb0a..90006d5a 100644
Binary files a/TwoFAS/TwoFAS/Other/id.lproj/Localizable.strings and b/TwoFAS/TwoFAS/Other/id.lproj/Localizable.strings differ
diff --git a/TwoFAS/TwoFAS/Other/it.lproj/Localizable.strings b/TwoFAS/TwoFAS/Other/it.lproj/Localizable.strings
index 47588a87..c597df22 100644
Binary files a/TwoFAS/TwoFAS/Other/it.lproj/Localizable.strings and b/TwoFAS/TwoFAS/Other/it.lproj/Localizable.strings differ
diff --git a/TwoFAS/TwoFAS/Other/nl.lproj/Localizable.strings b/TwoFAS/TwoFAS/Other/nl.lproj/Localizable.strings
index 8c53a100..58b06455 100644
Binary files a/TwoFAS/TwoFAS/Other/nl.lproj/Localizable.strings and b/TwoFAS/TwoFAS/Other/nl.lproj/Localizable.strings differ
diff --git a/TwoFAS/TwoFAS/Other/pl.lproj/Localizable.strings b/TwoFAS/TwoFAS/Other/pl.lproj/Localizable.strings
index 7dc0d5b4..09b84b6b 100644
Binary files a/TwoFAS/TwoFAS/Other/pl.lproj/Localizable.strings and b/TwoFAS/TwoFAS/Other/pl.lproj/Localizable.strings differ
diff --git a/TwoFAS/TwoFAS/Other/pt-BR.lproj/Localizable.strings b/TwoFAS/TwoFAS/Other/pt-BR.lproj/Localizable.strings
index acd14dfd..3b78e4f8 100644
Binary files a/TwoFAS/TwoFAS/Other/pt-BR.lproj/Localizable.strings and b/TwoFAS/TwoFAS/Other/pt-BR.lproj/Localizable.strings differ
diff --git a/TwoFAS/TwoFAS/Other/pt-PT.lproj/Localizable.strings b/TwoFAS/TwoFAS/Other/pt-PT.lproj/Localizable.strings
index 85e2fc18..d3b45dd9 100644
Binary files a/TwoFAS/TwoFAS/Other/pt-PT.lproj/Localizable.strings and b/TwoFAS/TwoFAS/Other/pt-PT.lproj/Localizable.strings differ
diff --git a/TwoFAS/TwoFAS/Other/tr.lproj/Localizable.strings b/TwoFAS/TwoFAS/Other/tr.lproj/Localizable.strings
index 51ba0b7d..7ca3215e 100644
Binary files a/TwoFAS/TwoFAS/Other/tr.lproj/Localizable.strings and b/TwoFAS/TwoFAS/Other/tr.lproj/Localizable.strings differ
diff --git a/TwoFAS/TwoFAS/Other/uk.lproj/Localizable.strings b/TwoFAS/TwoFAS/Other/uk.lproj/Localizable.strings
index 64ba1f94..6a97e0ac 100644
Binary files a/TwoFAS/TwoFAS/Other/uk.lproj/Localizable.strings and b/TwoFAS/TwoFAS/Other/uk.lproj/Localizable.strings differ
diff --git a/TwoFAS/TwoFAS/Other/zh-Hans.lproj/Localizable.strings b/TwoFAS/TwoFAS/Other/zh-Hans.lproj/Localizable.strings
index 953cceae..18f92585 100644
Binary files a/TwoFAS/TwoFAS/Other/zh-Hans.lproj/Localizable.strings and b/TwoFAS/TwoFAS/Other/zh-Hans.lproj/Localizable.strings differ
diff --git a/TwoFAS/TwoFAS/Root/Modules/Main/Interactor/MainModuleInteractor.swift b/TwoFAS/TwoFAS/Root/Modules/Main/Interactor/MainModuleInteractor.swift
index fb9c3883..07f02227 100644
--- a/TwoFAS/TwoFAS/Root/Modules/Main/Interactor/MainModuleInteractor.swift
+++ b/TwoFAS/TwoFAS/Root/Modules/Main/Interactor/MainModuleInteractor.swift
@@ -19,6 +19,7 @@
import Foundation
import Data
+import Common
protocol MainModuleInteracting: AnyObject {
var secretSyncError: ((String) -> Void)? { get set }
diff --git a/TwoFAS/TwoFAS/Root/Modules/Main/Presenter/MainPresenter.swift b/TwoFAS/TwoFAS/Root/Modules/Main/Presenter/MainPresenter.swift
index 67595c87..36761240 100644
--- a/TwoFAS/TwoFAS/Root/Modules/Main/Presenter/MainPresenter.swift
+++ b/TwoFAS/TwoFAS/Root/Modules/Main/Presenter/MainPresenter.swift
@@ -19,6 +19,7 @@
import UIKit
import Data
+import Common
final class MainPresenter {
weak var view: MainViewControlling?
diff --git a/TwoFAS/TwoFAS/Root/Modules/Settings/AppSecurity/Flow/AppSecurityFlowController.swift b/TwoFAS/TwoFAS/Root/Modules/Settings/AppSecurity/Flow/AppSecurityFlowController.swift
index ecf3a364..c7036ea5 100644
--- a/TwoFAS/TwoFAS/Root/Modules/Settings/AppSecurity/Flow/AppSecurityFlowController.swift
+++ b/TwoFAS/TwoFAS/Root/Modules/Settings/AppSecurity/Flow/AppSecurityFlowController.swift
@@ -19,6 +19,7 @@
import UIKit
import Data
+import Common
protocol AppSecurityFlowControllerParent: AnyObject {
func appSecurityChaged()
diff --git a/TwoFAS/TwoFAS/Root/Modules/Settings/AppSecurity/Interactor/AppSecurityModuleInteractor.swift b/TwoFAS/TwoFAS/Root/Modules/Settings/AppSecurity/Interactor/AppSecurityModuleInteractor.swift
index f37e67ce..3243ccc9 100644
--- a/TwoFAS/TwoFAS/Root/Modules/Settings/AppSecurity/Interactor/AppSecurityModuleInteractor.swift
+++ b/TwoFAS/TwoFAS/Root/Modules/Settings/AppSecurity/Interactor/AppSecurityModuleInteractor.swift
@@ -19,6 +19,7 @@
import Foundation
import Data
+import Common
protocol AppSecurityModuleInteracting: AnyObject {
var isPINSet: Bool { get }
diff --git a/TwoFAS/TwoFAS/Root/Modules/Settings/AppSecurity/Presenter/AppSecurityPresenter.swift b/TwoFAS/TwoFAS/Root/Modules/Settings/AppSecurity/Presenter/AppSecurityPresenter.swift
index ef1e6303..5b991a75 100644
--- a/TwoFAS/TwoFAS/Root/Modules/Settings/AppSecurity/Presenter/AppSecurityPresenter.swift
+++ b/TwoFAS/TwoFAS/Root/Modules/Settings/AppSecurity/Presenter/AppSecurityPresenter.swift
@@ -19,6 +19,7 @@
import Foundation
import Data
+import Common
final class AppSecurityPresenter {
weak var view: AppSecurityViewControlling?
diff --git a/TwoFAS/TwoFAS/Root/Modules/Settings/Backup/BackupMenu/Presenter/BackupMenuModels.swift b/TwoFAS/TwoFAS/Root/Modules/Settings/Backup/BackupMenu/Presenter/BackupMenuModels.swift
index 8210f1b7..e731a3da 100644
--- a/TwoFAS/TwoFAS/Root/Modules/Settings/Backup/BackupMenu/Presenter/BackupMenuModels.swift
+++ b/TwoFAS/TwoFAS/Root/Modules/Settings/Backup/BackupMenu/Presenter/BackupMenuModels.swift
@@ -19,6 +19,7 @@
import UIKit
import Data
+import Common
struct BackupMenuSection: TableViewSection {
let title: String?
diff --git a/TwoFAS/TwoFAS/Root/Modules/Settings/NewPIN/Flow/NewPINFlowController.swift b/TwoFAS/TwoFAS/Root/Modules/Settings/NewPIN/Flow/NewPINFlowController.swift
index 0624020f..79e9969a 100644
--- a/TwoFAS/TwoFAS/Root/Modules/Settings/NewPIN/Flow/NewPINFlowController.swift
+++ b/TwoFAS/TwoFAS/Root/Modules/Settings/NewPIN/Flow/NewPINFlowController.swift
@@ -19,6 +19,7 @@
import UIKit
import Data
+import Common
protocol NewPINFlowControllerParent: AnyObject {
func hideNewPIN()
diff --git a/TwoFAS/TwoFAS/Root/Modules/Settings/NewPIN/Flow/NewPINNavigationFlowController.swift b/TwoFAS/TwoFAS/Root/Modules/Settings/NewPIN/Flow/NewPINNavigationFlowController.swift
index 07846d46..c42844ce 100644
--- a/TwoFAS/TwoFAS/Root/Modules/Settings/NewPIN/Flow/NewPINNavigationFlowController.swift
+++ b/TwoFAS/TwoFAS/Root/Modules/Settings/NewPIN/Flow/NewPINNavigationFlowController.swift
@@ -19,6 +19,7 @@
import UIKit
import Data
+import Common
protocol NewPINNavigationFlowControllerParent: AnyObject {
func pinGathered(
diff --git a/TwoFAS/TwoFAS/Root/Modules/Settings/NewPIN/Flow/SelectPINLengthController.swift b/TwoFAS/TwoFAS/Root/Modules/Settings/NewPIN/Flow/SelectPINLengthController.swift
index b24101cf..aa82ec26 100644
--- a/TwoFAS/TwoFAS/Root/Modules/Settings/NewPIN/Flow/SelectPINLengthController.swift
+++ b/TwoFAS/TwoFAS/Root/Modules/Settings/NewPIN/Flow/SelectPINLengthController.swift
@@ -19,6 +19,7 @@
import UIKit
import Data
+import Common
enum SelectPINLengthController {
static func make(in view: UIView, completion: @escaping (PINType) -> Void) -> AlertController {
diff --git a/TwoFAS/TwoFAS/Root/Modules/Settings/NewPIN/Interactor/NewPINModuleInteractor.swift b/TwoFAS/TwoFAS/Root/Modules/Settings/NewPIN/Interactor/NewPINModuleInteractor.swift
index 5f6c1c6e..0b887d5c 100644
--- a/TwoFAS/TwoFAS/Root/Modules/Settings/NewPIN/Interactor/NewPINModuleInteractor.swift
+++ b/TwoFAS/TwoFAS/Root/Modules/Settings/NewPIN/Interactor/NewPINModuleInteractor.swift
@@ -19,6 +19,7 @@
import Foundation
import Data
+import Common
protocol NewPINModuleInteracting: AnyObject {
var selectedPIN: String? { get set }
diff --git a/TwoFAS/TwoFAS/Root/Modules/Settings/NewPIN/Presenter/NewPINPresenter.swift b/TwoFAS/TwoFAS/Root/Modules/Settings/NewPIN/Presenter/NewPINPresenter.swift
index f41951d0..7e26682b 100644
--- a/TwoFAS/TwoFAS/Root/Modules/Settings/NewPIN/Presenter/NewPINPresenter.swift
+++ b/TwoFAS/TwoFAS/Root/Modules/Settings/NewPIN/Presenter/NewPINPresenter.swift
@@ -19,6 +19,7 @@
import Foundation
import Data
+import Common
final class NewPINPresenter: PINKeyboardPresenter {
weak var view: NewPINViewControlling?
diff --git a/TwoFAS/TwoFAS/Root/Modules/Settings/VerifyPIN/Flow/VerifyPINFlowController.swift b/TwoFAS/TwoFAS/Root/Modules/Settings/VerifyPIN/Flow/VerifyPINFlowController.swift
index a9934d68..b27dd664 100644
--- a/TwoFAS/TwoFAS/Root/Modules/Settings/VerifyPIN/Flow/VerifyPINFlowController.swift
+++ b/TwoFAS/TwoFAS/Root/Modules/Settings/VerifyPIN/Flow/VerifyPINFlowController.swift
@@ -19,6 +19,7 @@
import UIKit
import Data
+import Common
protocol VerifyPINFlowControllerParent: AnyObject {
func hideVerifyPIN()
diff --git a/TwoFAS/TwoFAS/Root/View/RootViewController.swift b/TwoFAS/TwoFAS/Root/View/RootViewController.swift
index 5b3ffba9..b0ab00f4 100644
--- a/TwoFAS/TwoFAS/Root/View/RootViewController.swift
+++ b/TwoFAS/TwoFAS/Root/View/RootViewController.swift
@@ -57,7 +57,9 @@ extension RootViewController: RootViewControlling {
func tokenCopied() {
func flashNotification() {
VoiceOver.say(T.Notifications.tokenCopied)
- HUDNotification.presentSuccess(title: T.Notifications.tokenCopied)
+ if let keyWindow = UIApplication.keyWindow {
+ HUDNotification.presentSuccess(title: T.Notifications.tokenCopied, on: keyWindow)
+ }
}
if UIApplication.keyWindow != nil && view != nil {
diff --git a/TwoFAS/TwoFASAuth/Generated/T.generated.swift b/TwoFAS/TwoFASAuth/Generated/T.generated.swift
index 1c7a4e5d..8e168167 100644
--- a/TwoFAS/TwoFASAuth/Generated/T.generated.swift
+++ b/TwoFAS/TwoFASAuth/Generated/T.generated.swift
@@ -284,8 +284,8 @@ internal enum T {
internal static let name = T.tr("Localizable", "app__name", fallback: "2FAS Authenticator")
}
internal enum Appearance {
- /// Active search on startup
- internal static let activeSearchDescription = T.tr("Localizable", "appearance__active_search_description", fallback: "Active search on startup")
+ /// Active search on startup.
+ internal static let activeSearchDescription = T.tr("Localizable", "appearance__active_search_description", fallback: "Active search on startup.")
/// Active search
internal static let toggleActiveSearch = T.tr("Localizable", "appearance__toggle_active_search", fallback: "Active search")
}
@@ -336,8 +336,8 @@ internal enum T {
internal static let exportToFile = T.tr("Localizable", "backup__export_to_file", fallback: "Export to file")
/// File Backup
internal static let fileBackup = T.tr("Localizable", "backup__file_backup", fallback: "File Backup")
- /// Use File Backup for offline backup of your tokens
- internal static let fileBackupOfflineTitle = T.tr("Localizable", "backup__file_backup_offline_title", fallback: "Use File Backup for offline backup of your tokens")
+ /// Use File Backup for offline backup of your tokens.
+ internal static let fileBackupOfflineTitle = T.tr("Localizable", "backup__file_backup_offline_title", fallback: "Use File Backup for offline backup of your tokens.")
/// File error!
internal static let fileError = T.tr("Localizable", "backup__file_error", fallback: "File error!")
/// Google Drive has been disabled by the user
@@ -442,8 +442,8 @@ internal enum T {
internal static let userOverQuotaIcloud = T.tr("Localizable", "backup__user_over_quota_icloud", fallback: "User is over quota on iCloud")
/// Verify PIN
internal static let verifyPin = T.tr("Localizable", "backup__verify_pin", fallback: "Verify PIN")
- /// Warning! If you delete 2FAS Backup, you will also erase all tokens from other devices synced with this account. To preserve the tokens on other devices, please ensure that you've turned off the 2FAS Backup before the deletion
- internal static let warningIntroduction = T.tr("Localizable", "backup__warning_introduction", fallback: "Warning! If you delete 2FAS Backup, you will also erase all tokens from other devices synced with this account. To preserve the tokens on other devices, please ensure that you've turned off the 2FAS Backup before the deletion")
+ /// Warning! If you delete 2FAS Backup, you will also erase all tokens from other devices synced with this account. To preserve the tokens on other devices, please ensure that you've turned off the 2FAS Backup before the deletion.
+ internal static let warningIntroduction = T.tr("Localizable", "backup__warning_introduction", fallback: "Warning! If you delete 2FAS Backup, you will also erase all tokens from other devices synced with this account. To preserve the tokens on other devices, please ensure that you've turned off the 2FAS Backup before the deletion.")
}
internal enum Browser {
/// Do you want to share the 2FA token for
@@ -482,8 +482,8 @@ internal enum T {
internal static let deviceName = T.tr("Localizable", "browser__device_name", fallback: "Device nickname")
/// Forget this web browser
internal static let forgetThisBrowser = T.tr("Localizable", "browser__forget_this_browser", fallback: "Forget this web browser")
- /// Install the 2FAS browser extension on your desktop computer
- internal static let infoDescriptionFirst = T.tr("Localizable", "browser__info_description_first", fallback: "Install the 2FAS browser extension on your desktop computer")
+ /// Install the 2FAS browser extension on your desktop computer.
+ internal static let infoDescriptionFirst = T.tr("Localizable", "browser__info_description_first", fallback: "Install the 2FAS browser extension on your desktop computer.")
/// Pair it with your 2FAS app.
internal static let infoDescriptionSecond = T.tr("Localizable", "browser__info_description_second", fallback: "Pair it with your 2FAS app.")
/// 2FAS Web Browser extension
@@ -666,6 +666,8 @@ internal enum T {
internal static let `set` = T.tr("Localizable", "commons__set", fallback: "Set")
/// Skip
internal static let skip = T.tr("Localizable", "commons__skip", fallback: "Skip")
+ /// Success
+ internal static let success = T.tr("Localizable", "commons__success", fallback: "Success")
/// The provided text is too long (max. %d chars)
internal static func textLongTitle(_ p1: Int) -> String {
return T.tr("Localizable", "commons__text_long_title", p1, fallback: "The provided text is too long (max. %d chars)")
@@ -970,8 +972,12 @@ internal enum T {
internal static let enterCurrentPin = T.tr("Localizable", "security__enter_current_pin", fallback: "Please enter your current PIN")
/// Please enter your new PIN
internal static let enterNewPin = T.tr("Localizable", "security__enter_new_pin", fallback: "Please enter your new PIN")
+ /// Enter new PIN
+ internal static let enterNewPinShort = T.tr("Localizable", "security__enter_new_pin_short", fallback: "Enter new PIN")
/// Please enter your PIN
internal static let enterPin = T.tr("Localizable", "security__enter_pin", fallback: "Please enter your PIN")
+ /// Enter PIN
+ internal static let enterPinShort = T.tr("Localizable", "security__enter_pin_short", fallback: "Enter PIN")
/// Please enter your new %s PIN
internal static func enterYourNewPin(_ p1: UnsafePointer) -> String {
return T.tr("Localizable", "security__enter_your_new_pin", p1, fallback: "Please enter your new %s PIN")
@@ -980,6 +986,8 @@ internal enum T {
internal static let incorrectPIN = T.tr("Localizable", "security__incorrect_PIN", fallback: "Incorrect PIN")
/// PIN incorrect! Please try again
internal static let pinErrorIncorrect = T.tr("Localizable", "security__pin_error_incorrect", fallback: "PIN incorrect! Please try again")
+ /// Repeat new PIN
+ internal static let repeatNewPinShort = T.tr("Localizable", "security__repeat_new_pin_short", fallback: "Repeat new PIN")
/// Too many attempts. Please try again later.
internal static let tooManyAttemptsError = T.tr("Localizable", "security__too_many_attempts_error", fallback: "Too many attempts. Please try again later.")
/// Too many attempts. Please try after one minute
@@ -1053,8 +1061,8 @@ internal enum T {
internal static let gdSyncInfo = T.tr("Localizable", "settings__gd_sync_info", fallback: "Google Drive sync reminder")
/// General
internal static let general = T.tr("Localizable", "settings__general", fallback: "General")
- /// Tokens will be revealed on tap
- internal static let hideTokensDescription = T.tr("Localizable", "settings__hide_tokens_description", fallback: "Tokens will be revealed on tap")
+ /// Tokens will be revealed on tap.
+ internal static let hideTokensDescription = T.tr("Localizable", "settings__hide_tokens_description", fallback: "Tokens will be revealed on tap.")
/// Hide tokens
internal static let hideTokensTitle = T.tr("Localizable", "settings__hide_tokens_title", fallback: "Hide tokens")
/// Select the maximum number of unsuccessful attempts to enter the passcode before locking the application (lockout time can be changed below).
@@ -1313,6 +1321,8 @@ internal enum T {
internal static let enterServiceName = T.tr("Localizable", "tokens__enter_service_name", fallback: "Enter Service Name")
/// Add manually
internal static let fabAddmanually = T.tr("Localizable", "tokens__fab_addmanually", fallback: "Add manually")
+ /// Favorite Services
+ internal static let favoriteServices = T.tr("Localizable", "tokens__favorite_services", fallback: "Favorite Services")
/// Service added successfully. We strongly recommend that you
internal static let galleryAdviceContentFirst = T.tr("Localizable", "tokens__gallery_advice_content_first", fallback: "Service added successfully. We strongly recommend that you ")
///
@@ -1338,6 +1348,8 @@ internal enum T {
internal static let groupName = T.tr("Localizable", "tokens__group_name", fallback: "Group name:")
/// HOTP
internal static let hotp = T.tr("Localizable", "tokens__hotp", fallback: "HOTP")
+ /// HOTP services aren't supported yet
+ internal static let hotpNotSupported = T.tr("Localizable", "tokens__hotp_not_supported", fallback: "HOTP services aren't supported yet")
/// Yes, I want to delete this service
internal static let iWantToDeleteThisToken = T.tr("Localizable", "tokens__i_want_to_delete_this_token", fallback: "Yes, I want to delete this service")
/// Incorrect Secret key (only numbers 2 to 7, letters), max. 512 chars long
@@ -1589,6 +1601,14 @@ internal enum T {
/// Use the Add Service button to add a new service
internal static let useAddServiceButtonTitle = T.tr("Localizable", "voiceover__use_add_service_button_title", fallback: "Use the Add Service button to add a new service")
}
+ internal enum Watch {
+ /// 2FAS watchOS app is a companion app for the 2FAS iOS application. It will present services backed up using iCloud sync.
+ ///
+ /// For quick access, add them to Favorite Services.
+ ///
+ /// Please remember to donate so we can further improve the 2FAS platform!
+ internal static let intro = T.tr("Localizable", "watch__intro", fallback: "2FAS watchOS app is a companion app for the 2FAS iOS application. It will present services backed up using iCloud sync.\n\nFor quick access, add them to Favorite Services.\n\nPlease remember to donate so we can further improve the 2FAS platform!")
+ }
internal enum Widget {
/// My secured account
internal static let mySecuredAccount = T.tr("Localizable", "widget__my_secured_account", fallback: "My secured account")
diff --git a/TwoFAS/TwoFASWatch Watch App/App/AppDelegateInteractor.swift b/TwoFAS/TwoFASWatch Watch App/App/AppDelegateInteractor.swift
new file mode 100644
index 00000000..e8a2195c
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/App/AppDelegateInteractor.swift
@@ -0,0 +1,91 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import Foundation
+import WatchKit
+import CommonWatch
+
+final class AppDelegateInteractor: NSObject, WKApplicationDelegate {
+ private lazy var mainRepository: MainRepository = { MainRepositoryImpl.shared }()
+
+ func applicationDidFinishLaunching() {
+ if !WKApplication.shared().isRegisteredForRemoteNotifications {
+ Log("Registering Push Notifications")
+ WKApplication.shared().registerForRemoteNotifications()
+ } else {
+ Log("Push Notifications registered")
+ }
+ mainRepository.registerForCloudStateChanges({ [weak self] state in
+ Log("Cloud state changed: \(state)")
+ self?.handleCloudState(state)
+ }, id: "AppDelegateInteractor")
+ handleCloudState(mainRepository.currentCloudState)
+
+ mainRepository.synchronizeCloudBackup()
+ }
+
+ func applicationDidBecomeActive() {
+ mainRepository.synchronizeCloudBackup()
+ if mainRepository.pin != nil {
+ mainRepository.lockApp()
+ }
+ }
+
+ func applicationWillResignActive() {
+ mainRepository.saveStorage()
+ }
+
+ func applicationWillEnterForeground() {
+ if mainRepository.pin != nil {
+ mainRepository.lockApp()
+ }
+ }
+
+ func applicationDidEnterBackground() {
+ if mainRepository.pin != nil {
+ mainRepository.lockApp()
+ }
+ }
+
+ func didReceiveRemoteNotification(
+ _ userInfo: [AnyHashable: Any],
+ fetchCompletionHandler completionHandler: @escaping (WKBackgroundFetchResult) -> Void
+ ) {
+ Log("didReceiveRemoteNotification")
+ mainRepository.syncDidReceiveRemoteNotification(
+ userInfo: userInfo,
+ fetchCompletionHandler: completionHandler
+ )
+ }
+
+ func didRegisterForRemoteNotifications(withDeviceToken deviceToken: Data) {
+ Log("didRegisterForRemoteNotifications")
+ }
+
+ func didFailToRegisterForRemoteNotificationsWithError(_ error: any Error) {
+ Log("didFailToRegisterForRemoteNotificationsWithError \(error)")
+ }
+
+ private func handleCloudState(_ state: CloudState) {
+ if state == .disabledAvailable {
+ mainRepository.enableCloudBackup()
+ mainRepository.synchronizeCloudBackup()
+ }
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/App/AppPresenter.swift b/TwoFAS/TwoFASWatch Watch App/App/AppPresenter.swift
new file mode 100644
index 00000000..c9c37aeb
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/App/AppPresenter.swift
@@ -0,0 +1,54 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import Foundation
+
+final class AppPresenter: ObservableObject {
+ @Published var isAppLocked: Bool
+ @Published var showIntro: Bool
+
+ private let mainRepository: MainRepository
+ private let notificationCenter = NotificationCenter.default
+
+ init(mainRepository: MainRepository) {
+ self.mainRepository = mainRepository
+ isAppLocked = mainRepository.isAppLocked
+ showIntro = !mainRepository.wasIntroductionShown()
+ notificationCenter.addObserver(self, selector: #selector(update), name: .appLockUpdate, object: nil)
+ }
+
+ @objc
+ func update() {
+ isAppLocked = mainRepository.isAppLocked
+ }
+
+ func unlockApp() {
+ mainRepository.unlockApp()
+ isAppLocked = mainRepository.isAppLocked
+ }
+
+ func markIntroAsShown() {
+ mainRepository.markIntroductionAsShown()
+ showIntro = false
+ }
+
+ deinit {
+ notificationCenter.removeObserver(self)
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Assets.xcassets/AboutLogo.imageset/Contents.json b/TwoFAS/TwoFASWatch Watch App/Assets.xcassets/AboutLogo.imageset/Contents.json
new file mode 100644
index 00000000..78a5bcaa
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Assets.xcassets/AboutLogo.imageset/Contents.json
@@ -0,0 +1,22 @@
+{
+ "images" : [
+ {
+ "filename" : "LogoGrid.pdf",
+ "idiom" : "universal"
+ },
+ {
+ "appearances" : [
+ {
+ "appearance" : "luminosity",
+ "value" : "dark"
+ }
+ ],
+ "filename" : "LogoGridDark.pdf",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Assets.xcassets/AboutLogo.imageset/LogoGrid.pdf b/TwoFAS/TwoFASWatch Watch App/Assets.xcassets/AboutLogo.imageset/LogoGrid.pdf
new file mode 100644
index 00000000..e7db7b29
Binary files /dev/null and b/TwoFAS/TwoFASWatch Watch App/Assets.xcassets/AboutLogo.imageset/LogoGrid.pdf differ
diff --git a/TwoFAS/TwoFASWatch Watch App/Assets.xcassets/AboutLogo.imageset/LogoGridDark.pdf b/TwoFAS/TwoFASWatch Watch App/Assets.xcassets/AboutLogo.imageset/LogoGridDark.pdf
new file mode 100644
index 00000000..d3943d3e
Binary files /dev/null and b/TwoFAS/TwoFASWatch Watch App/Assets.xcassets/AboutLogo.imageset/LogoGridDark.pdf differ
diff --git a/TwoFAS/TwoFASWatch Watch App/Assets.xcassets/AccentColor.colorset/Contents.json b/TwoFAS/TwoFASWatch Watch App/Assets.xcassets/AccentColor.colorset/Contents.json
new file mode 100644
index 00000000..7c31be4f
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Assets.xcassets/AccentColor.colorset/Contents.json
@@ -0,0 +1,20 @@
+{
+ "colors" : [
+ {
+ "color" : {
+ "color-space" : "srgb",
+ "components" : {
+ "alpha" : "1.000",
+ "blue" : "0.137",
+ "green" : "0.110",
+ "red" : "0.898"
+ }
+ },
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Assets.xcassets/AppIcon.appiconset/AppIcon.png b/TwoFAS/TwoFASWatch Watch App/Assets.xcassets/AppIcon.appiconset/AppIcon.png
new file mode 100644
index 00000000..1871f2db
Binary files /dev/null and b/TwoFAS/TwoFASWatch Watch App/Assets.xcassets/AppIcon.appiconset/AppIcon.png differ
diff --git a/TwoFAS/TwoFASWatch Watch App/Assets.xcassets/AppIcon.appiconset/Contents.json b/TwoFAS/TwoFASWatch Watch App/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 00000000..74cc7259
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,14 @@
+{
+ "images" : [
+ {
+ "filename" : "AppIcon.png",
+ "idiom" : "universal",
+ "platform" : "watchos",
+ "size" : "1024x1024"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Assets.xcassets/ColorLabelText.colorset/Contents.json b/TwoFAS/TwoFASWatch Watch App/Assets.xcassets/ColorLabelText.colorset/Contents.json
new file mode 100644
index 00000000..5ac383e4
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Assets.xcassets/ColorLabelText.colorset/Contents.json
@@ -0,0 +1,20 @@
+{
+ "colors" : [
+ {
+ "color" : {
+ "color-space" : "srgb",
+ "components" : {
+ "alpha" : "1.000",
+ "blue" : "0xFE",
+ "green" : "0xFE",
+ "red" : "0xFE"
+ }
+ },
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Assets.xcassets/ColorLabelTextBackground.colorset/Contents.json b/TwoFAS/TwoFASWatch Watch App/Assets.xcassets/ColorLabelTextBackground.colorset/Contents.json
new file mode 100644
index 00000000..525bf3de
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Assets.xcassets/ColorLabelTextBackground.colorset/Contents.json
@@ -0,0 +1,20 @@
+{
+ "colors" : [
+ {
+ "color" : {
+ "color-space" : "srgb",
+ "components" : {
+ "alpha" : "1.000",
+ "blue" : "0x01",
+ "green" : "0x01",
+ "red" : "0x01"
+ }
+ },
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Assets.xcassets/ColorSecondary.colorset/Contents.json b/TwoFAS/TwoFASWatch Watch App/Assets.xcassets/ColorSecondary.colorset/Contents.json
new file mode 100644
index 00000000..d3804234
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Assets.xcassets/ColorSecondary.colorset/Contents.json
@@ -0,0 +1,20 @@
+{
+ "colors" : [
+ {
+ "color" : {
+ "color-space" : "srgb",
+ "components" : {
+ "alpha" : "1.000",
+ "blue" : "0.450",
+ "green" : "0.450",
+ "red" : "0.500"
+ }
+ },
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Assets.xcassets/Contents.json b/TwoFAS/TwoFASWatch Watch App/Assets.xcassets/Contents.json
new file mode 100644
index 00000000..73c00596
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Data/IconRenderer.swift b/TwoFAS/TwoFASWatch Watch App/Data/IconRenderer.swift
new file mode 100644
index 00000000..05dad786
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Data/IconRenderer.swift
@@ -0,0 +1,52 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import SwiftUI
+import CommonWatch
+
+struct IconRenderer: View {
+ let service: Service
+
+ @ViewBuilder
+ var body: some View {
+ Group {
+ switch service.iconType {
+ case .brand:
+ Image(uiImage: ServiceIcon.for(iconTypeID: service.iconTypeID))
+ .resizable()
+ case .label:
+ ZStack(alignment: .center) {
+ Circle()
+ .frame(width: 24, height: 24)
+ .foregroundStyle(service.labelColor)
+ RoundedRectangle(cornerRadius: 14, style: .circular)
+ .frame(width: 17.8, height: 11.22, alignment: .center)
+ .foregroundStyle(Color("ColorLabelTextBackground"))
+ Text(verbatim: service.labelTitle)
+ .foregroundStyle(Color("ColorLabelText"))
+ .font(Font(UIFont.systemFont(ofSize: 6, weight: .bold)))
+ .multilineTextAlignment(.center)
+ .frame(width: 22, height: 6, alignment: .center)
+ }
+ }
+ }
+ .frame(width: 24, height: 24)
+ .aspectRatio(contentMode: .fit)
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Data/InteractorFactory.swift b/TwoFAS/TwoFASWatch Watch App/Data/InteractorFactory.swift
new file mode 100644
index 00000000..753b763e
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Data/InteractorFactory.swift
@@ -0,0 +1,51 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import Foundation
+
+final class InteractorFactory {
+ private init() {}
+
+ static let shared = InteractorFactory()
+
+ func mainInteractor() -> MainInteracting {
+ MainInteractor(mainRepository: MainRepositoryImpl.shared)
+ }
+
+ func serviceListInteractor() -> ServiceListInteracting {
+ ServiceListInteractor(mainRepository: MainRepositoryImpl.shared)
+ }
+
+ func serviceInteractor(service: Service) -> ServiceInteracting {
+ ServiceInteractor(
+ mainRepository: MainRepositoryImpl.shared,
+ service: service
+ )
+ }
+
+ func securityInteractor() -> SecurityInteracting {
+ SecurityInteractor(
+ mainRepository: MainRepositoryImpl.shared
+ )
+ }
+
+ func pinInteractor(variant: PINKeyboardVariant) -> PINKeyboardInteracting {
+ PINKeyboardInteractor(mainRepository: MainRepositoryImpl.shared, variant: variant)
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Data/Models/AppPIN.swift b/TwoFAS/TwoFASWatch Watch App/Data/Models/AppPIN.swift
new file mode 100644
index 00000000..0e7f226a
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Data/Models/AppPIN.swift
@@ -0,0 +1,26 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import Foundation
+import CommonWatch
+
+struct AppPIN: Codable, Hashable {
+ let type: PINType
+ let value: String
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Data/Models/Category.swift b/TwoFAS/TwoFASWatch Watch App/Data/Models/Category.swift
new file mode 100644
index 00000000..b0ae0c4d
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Data/Models/Category.swift
@@ -0,0 +1,51 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import Foundation
+import StorageWatch
+
+struct Category: Identifiable, Hashable {
+ let id: UUID
+ let name: String
+ let services: [Service]
+}
+
+extension CategoryData {
+ func toCategory() -> Category {
+ let id: UUID = {
+ if let section {
+ return section.sectionID
+ }
+ return UUID()
+ }()
+ let name: String = {
+ if let section {
+ return section.title
+ }
+ return T.Tokens.myTokens
+ }()
+ return Category(id: id, name: name, services: services.toServices())
+ }
+}
+
+extension Array where Element == CategoryData {
+ func toCategories() -> [Category] {
+ map { $0.toCategory() }
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Data/Models/Service.swift b/TwoFAS/TwoFASWatch Watch App/Data/Models/Service.swift
new file mode 100644
index 00000000..8a873a5d
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Data/Models/Service.swift
@@ -0,0 +1,53 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import SwiftUI
+import CommonWatch
+
+struct Service: Identifiable, Hashable {
+ let id: String
+ let name: String
+ let additionalInfo: String?
+ let iconType: IconType
+ let iconTypeID: IconTypeID
+ let labelColor: Color
+ let labelTitle: String
+ let badgeColor: Color
+}
+
+extension ServiceData {
+ func toService() -> Service {
+ Service(
+ id: secret,
+ name: name,
+ additionalInfo: additionalInfo,
+ iconType: iconType,
+ iconTypeID: iconTypeID,
+ labelColor: Color(labelColor.color),
+ labelTitle: labelTitle,
+ badgeColor: Color(badgeColor?.color ?? TintColor.default.color)
+ )
+ }
+}
+
+extension Array where Element == ServiceData {
+ func toServices() -> [Service] {
+ map { $0.toService() }
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Data/Repositories/MainRepository.swift b/TwoFAS/TwoFASWatch Watch App/Data/Repositories/MainRepository.swift
new file mode 100644
index 00000000..1ba4499c
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Data/Repositories/MainRepository.swift
@@ -0,0 +1,325 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import UIKit
+import SyncWatch
+import ProtectionWatch
+import CommonWatch
+import StorageWatch
+import ContentWatch
+
+protocol MainRepository: AnyObject {
+ func saveStorage()
+ func service(for secret: String) -> ServiceData?
+ func listAllServicesWithingCategories(
+ for phrase: String?,
+ sorting: SortType,
+ ids: [ServiceTypeID]
+ ) -> [CategoryData]
+ func countServices() -> Int
+ var hasServices: Bool { get }
+ func token(
+ secret: Secret,
+ time: Date?,
+ digits: Digits,
+ period: Period,
+ algorithm: CommonWatch.Algorithm,
+ counter: Int,
+ tokenType: TokenType
+ ) -> TokenValue
+
+ func markIntroductionAsShown()
+ func wasIntroductionShown() -> Bool
+ var sortType: SortType? { get }
+ func setSortType(_ sortType: SortType)
+ var pin: AppPIN? { get }
+ func setPIN(_ pin: AppPIN?)
+
+ func lockApp()
+ func unlockApp()
+ var isAppLocked: Bool { get }
+
+ var currentCloudState: CloudState { get }
+ func registerForCloudStateChanges(_ listener: @escaping CloudStateListener, id: CloudStateListenerID)
+ func unregisterForCloudStageChanges(with id: CloudStateListenerID)
+ func enableCloudBackup()
+ func synchronizeCloudBackup()
+ func syncDidReceiveRemoteNotification(
+ userInfo: [AnyHashable: Any],
+ fetchCompletionHandler completionHandler: @escaping (BackgroundFetchResult) -> Void
+ )
+
+ func serviceDefinition(using serviceTypeID: ServiceTypeID) -> ServiceDefinition?
+ func iconTypeID(for serviceTypeID: ServiceTypeID?) -> UIImage
+
+ func listFavoriteServices() -> [ServiceData]
+ func addFavoriteService(_ secret: Secret)
+ func removeFavoriteService(_ secret: Secret)
+}
+
+final class MainRepositoryImpl: MainRepository {
+ var storageError: ((String) -> Void)?
+
+ let service: ServiceHandler
+ let protection: Protection
+ let storage: Storage
+ let categoryHandler: CategoryHandler
+ let sectionHandler: SectionHandler
+ let cloudHandler: CloudHandlerType
+ let userDefaultsRepository: UserDefaultsRepository
+ let iconDatabase: IconDescriptionDatabase
+ let serviceDefinitionDatabase: ServiceDefinitionDatabase
+ let iconDescriptionDatabase: IconDescriptionDatabase
+ let logDataChange: LogDataChange
+ let storageRepository: StorageRepository
+
+ let notificationCenter = NotificationCenter.default
+
+ private(set) var isAppLocked: Bool
+
+ private static var _shared: MainRepositoryImpl!
+
+ static var shared: MainRepositoryImpl {
+ if _shared == nil {
+ MainRepositoryImpl.create()
+ }
+ return _shared
+ }
+
+ private var favoriteServicesCache: [Secret]?
+
+ static func create() {
+ let protection = Protection()
+
+ EncryptionHolder.initialize(with: protection.localKeyEncryption)
+
+ let storage = Storage(readOnly: false) { Log($0, module: .storage) }
+
+ let serviceMigration = ServiceMigrationController(storageRepository: storage.storageRepository)
+ serviceMigration.serviceNameTranslation = T.Commons.service
+
+ SyncInstanceWatch.initialize(commonSectionHandler: storage.section, commonServiceHandler: storage.service) {
+ Log("Sync: \($0)")
+ }
+ SyncInstanceWatch.migrateStoreIfNeeded()
+ serviceMigration.migrateIfNeeded()
+
+ _ = MainRepositoryImpl(
+ protection: protection,
+ storage: storage,
+ cloudHandler: SyncInstanceWatch.getCloudHandler(),
+ logDataChange: SyncInstanceWatch.logDataChange
+ )
+ }
+
+ private init(
+ protection: Protection,
+ storage: Storage,
+ cloudHandler: CloudHandlerType,
+ logDataChange: LogDataChange
+ ) {
+ self.service = storage.service
+ self.protection = protection
+ self.storage = storage
+ self.categoryHandler = storage.category
+ self.sectionHandler = storage.section
+ self.cloudHandler = cloudHandler
+ self.logDataChange = logDataChange
+
+ iconDatabase = IconDescriptionDatabaseImpl()
+ serviceDefinitionDatabase = ServiceDefinitionDatabaseImpl()
+ iconDescriptionDatabase = IconDescriptionDatabaseImpl()
+
+ userDefaultsRepository = UserDefaultsRepositoryImpl()
+
+ storageRepository = storage.storageRepository
+ isAppLocked = userDefaultsRepository.pin != nil
+ MainRepositoryImpl._shared = self
+
+ storage.addUserPresentableError { [weak self] error in
+ self?.storageError?(error)
+ }
+ }
+}
+
+extension MainRepositoryImpl {
+ func saveStorage() {
+ storage.save()
+ }
+
+ func service(for secret: String) -> ServiceData? {
+ storageRepository.findService(for: secret)
+ }
+
+ func listAllServicesWithingCategories(
+ for phrase: String?,
+ sorting: SortType,
+ ids: [ServiceTypeID]
+ ) -> [CategoryData] {
+ storageRepository.listAllWithingCategories(for: phrase, sorting: sorting, ids: ids)
+ }
+
+ func countServices() -> Int {
+ storageRepository.countServicesNotTrashed()
+ }
+
+ var hasServices: Bool { storageRepository.hasServices }
+
+ func token(
+ secret: Secret,
+ time: Date?,
+ digits: Digits,
+ period: Period,
+ algorithm: CommonWatch.Algorithm,
+ counter: Int,
+ tokenType: TokenType
+ ) -> TokenValue {
+ TokenHandler.generateToken(
+ secret: secret,
+ time: time,
+ digits: digits,
+ period: period,
+ algorithm: algorithm,
+ counter: counter,
+ tokenType: tokenType
+ )
+ }
+}
+
+extension MainRepositoryImpl {
+ func markIntroductionAsShown() {
+ userDefaultsRepository.markIntroductionAsShown()
+ }
+
+ func wasIntroductionShown() -> Bool {
+ userDefaultsRepository.wasIntroductionShown
+ }
+
+ var sortType: SortType? {
+ userDefaultsRepository.sortType
+ }
+
+ func setSortType(_ sortType: SortType) {
+ userDefaultsRepository.setSortType(sortType)
+ }
+
+ var pin: AppPIN? {
+ userDefaultsRepository.pin
+ }
+
+ func setPIN(_ pin: AppPIN?) {
+ userDefaultsRepository.setPIN(pin)
+ }
+}
+
+extension MainRepositoryImpl {
+ func lockApp() {
+ isAppLocked = true
+ notificationCenter.post(name: .appLockUpdate, object: nil)
+ }
+ func unlockApp() {
+ isAppLocked = false
+ notificationCenter.post(name: .appLockUpdate, object: nil)
+ }
+}
+
+extension MainRepositoryImpl {
+ var currentCloudState: CloudState {
+ cloudHandler.currentState.toCloudState
+ }
+
+ func registerForCloudStateChanges(_ listener: @escaping CloudStateListener, id: CloudStateListenerID) {
+ cloudHandler.registerForStateChange({ listener($0.toCloudState) }, with: id)
+ cloudHandler.checkState()
+ }
+
+ func unregisterForCloudStageChanges(with id: CloudStateListenerID) {
+ cloudHandler.unregisterForStateChange(id: id)
+ }
+
+ func enableCloudBackup() {
+ cloudHandler.enable()
+ }
+
+ func synchronizeCloudBackup() {
+ cloudHandler.synchronize()
+ }
+
+ func syncDidReceiveRemoteNotification(
+ userInfo: [AnyHashable: Any],
+ fetchCompletionHandler completionHandler: @escaping (BackgroundFetchResult) -> Void
+ ) {
+ SyncInstanceWatch.didReceiveRemoteNotification(userInfo: userInfo, fetchCompletionHandler: completionHandler)
+ }
+}
+
+extension MainRepositoryImpl {
+ func serviceDefinition(using serviceTypeID: ServiceTypeID) -> ServiceDefinition? {
+ serviceDefinitionDatabase.service(using: serviceTypeID)
+ }
+
+ func iconTypeID(for serviceTypeID: ServiceTypeID?) -> UIImage {
+ guard let serviceTypeID, let serviceDef = serviceDefinitionDatabase.service(using: serviceTypeID) else {
+ return ServiceIcon.for(iconTypeID: IconTypeID.default)
+ }
+ return ServiceIcon.for(iconTypeID: serviceDef.iconTypeID)
+ }
+}
+
+extension MainRepositoryImpl {
+ func listFavoriteServices() -> [ServiceData] {
+ initializeFavoriteServicesCache()
+ guard let favoriteServicesCache else { return [] }
+ return favoriteServicesCache.compactMap({ storageRepository.findService(for: $0) })
+ .sorted(by: { $0.name < $1.name })
+ }
+
+ func addFavoriteService(_ secret: Secret) {
+ initializeFavoriteServicesCache()
+ guard favoriteServicesCache?.first(where: { $0 == secret }) == nil else { return }
+ favoriteServicesCache?.append(secret)
+ saveFavoriteServicesCache()
+ }
+
+ func removeFavoriteService(_ secret: Secret) {
+ initializeFavoriteServicesCache()
+ favoriteServicesCache?.removeAll(where: { $0 == secret })
+ saveFavoriteServicesCache()
+ }
+
+ private func initializeFavoriteServicesCache() {
+ if favoriteServicesCache != nil {
+ return
+ }
+ let value = userDefaultsRepository.favoriteServices() ?? []
+ favoriteServicesCache = Array(Set(value))
+ }
+
+ private func saveFavoriteServicesCache() {
+ guard let favoriteServicesCache else {
+ Log("Can't get Favorite Services for saving")
+ return
+ }
+ userDefaultsRepository.setFavoriteServices(favoriteServicesCache)
+ }
+}
+
+public extension Notification.Name {
+ static let appLockUpdate = Notification.Name("appLockUpdate")
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Data/Repositories/UserDefaultsRepository.swift b/TwoFAS/TwoFASWatch Watch App/Data/Repositories/UserDefaultsRepository.swift
new file mode 100644
index 00000000..44e04b1f
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Data/Repositories/UserDefaultsRepository.swift
@@ -0,0 +1,113 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import Foundation
+import CommonWatch
+import ProtectionWatch
+
+protocol UserDefaultsRepository: AnyObject {
+ var pin: AppPIN? { get }
+ func setPIN(_ pin: AppPIN?)
+
+ var sortType: SortType? { get }
+ func setSortType(_ sortType: SortType)
+
+ var wasIntroductionShown: Bool { get }
+ func markIntroductionAsShown()
+
+ func setFavoriteServices(_ services: [Secret])
+ func favoriteServices() -> [Secret]?
+}
+
+final class UserDefaultsRepositoryImpl: UserDefaultsRepository {
+ private enum Keys: String, CaseIterable {
+ case sortType
+ case introductionShown
+ case pin
+ case favoriteServices
+ }
+ private let userDefaults = UserDefaults()
+
+ private let localEncryption = LocalKeyEncryption()
+
+ private let encoder = JSONEncoder()
+ private let decoder = JSONDecoder()
+
+ var pin: AppPIN? {
+ guard
+ let data = userDefaults.object(forKey: Keys.pin.rawValue) as? Data,
+ let object = try? decoder.decode(AppPIN.self, from: data)
+ else { return nil }
+ let decrypted = AppPIN(type: object.type, value: localEncryption.decrypt(object.value))
+ return decrypted
+ }
+
+ func setPIN(_ pin: AppPIN?) {
+ guard let pin else {
+ userDefaults.set(nil, forKey: Keys.pin.rawValue)
+ userDefaults.synchronize()
+ return
+ }
+ do {
+ let encrypted = AppPIN(type: pin.type, value: localEncryption.encrypt(pin.value))
+ let encodedNode = try encoder.encode(encrypted)
+ userDefaults.set(encodedNode, forKey: Keys.pin.rawValue)
+ userDefaults.synchronize()
+ } catch {
+ Log("Can't save App PIN! Error: \(error)", severity: .error)
+ }
+ }
+
+ var sortType: SortType? {
+ guard let value = userDefaults.string(forKey: Keys.sortType.rawValue) else { return nil }
+ return SortType(rawValue: value)
+ }
+
+ func setSortType(_ sortType: SortType) {
+ userDefaults.set(sortType.rawValue, forKey: Keys.sortType.rawValue)
+ userDefaults.synchronize()
+ }
+
+ var wasIntroductionShown: Bool {
+ userDefaults.bool(forKey: Keys.introductionShown.rawValue)
+ }
+
+ func markIntroductionAsShown() {
+ userDefaults.set(true, forKey: Keys.introductionShown.rawValue)
+ userDefaults.synchronize()
+ }
+
+ func setFavoriteServices(_ services: [Secret]) {
+ do {
+ let encodedNode = try encoder.encode(services)
+ userDefaults.set(encodedNode, forKey: Keys.favoriteServices.rawValue)
+ userDefaults.synchronize()
+ } catch {
+ Log("Can't save Favorite Services! Error: \(error)", severity: .error)
+ }
+ }
+
+ func favoriteServices() -> [Secret]? {
+ guard
+ let data = userDefaults.object(forKey: Keys.favoriteServices.rawValue) as? Data,
+ let list = try? decoder.decode([Secret].self, from: data)
+ else { return nil }
+ return list
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Data/WatchConsts.swift b/TwoFAS/TwoFASWatch Watch App/Data/WatchConsts.swift
new file mode 100644
index 00000000..8b2f6f34
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Data/WatchConsts.swift
@@ -0,0 +1,25 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import Foundation
+
+enum WatchConsts {
+ static let minRowHeight: CGFloat = 60
+ static let listSectionRowSpacing: CGFloat = 4
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/IntroductionView.swift b/TwoFAS/TwoFASWatch Watch App/IntroductionView.swift
new file mode 100644
index 00000000..fa8922f4
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/IntroductionView.swift
@@ -0,0 +1,48 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import SwiftUI
+
+struct IntroductionView: View {
+ var close: () -> Void
+ var body: some View {
+ ScrollView {
+ VStack(alignment: .center, spacing: 4) {
+ LogoView()
+ Spacer()
+
+ Text(T.Watch.intro)
+ .font(.body)
+ .padding(4)
+ .foregroundStyle(.primary)
+
+ Button(action: {
+ close()
+ }, label: {
+ Text(T.Commons.continue)
+ })
+ .padding(.vertical, 12)
+ }
+ }
+ }
+}
+
+#Preview {
+ IntroductionView(close: {})
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Main/MainInteractor.swift b/TwoFAS/TwoFASWatch Watch App/Main/MainInteractor.swift
new file mode 100644
index 00000000..fce93c16
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Main/MainInteractor.swift
@@ -0,0 +1,39 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import Foundation
+import CommonWatch
+
+protocol MainInteracting: AnyObject {
+ func listFavoriteServices() -> [ServiceData]
+}
+
+final class MainInteractor {
+ private let mainRepository: MainRepository
+
+ init(mainRepository: MainRepository) {
+ self.mainRepository = mainRepository
+ }
+}
+
+extension MainInteractor: MainInteracting {
+ func listFavoriteServices() -> [ServiceData] {
+ mainRepository.listFavoriteServices()
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Main/MainPresenter.swift b/TwoFAS/TwoFASWatch Watch App/Main/MainPresenter.swift
new file mode 100644
index 00000000..ee5ef2e4
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Main/MainPresenter.swift
@@ -0,0 +1,42 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import Foundation
+import CommonWatch
+import SwiftUI
+
+final class MainPresenter: ObservableObject {
+ @Published var favoriteList: [Service] = []
+
+ private let interactor: MainInteracting
+
+ init(interactor: MainInteracting) {
+ self.interactor = interactor
+ }
+
+ func onAppear() {
+ refresh()
+ }
+
+ private func refresh() {
+ favoriteList = interactor
+ .listFavoriteServices()
+ .map { $0.toService() }
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Main/MainView.swift b/TwoFAS/TwoFASWatch Watch App/Main/MainView.swift
new file mode 100644
index 00000000..94c0a790
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Main/MainView.swift
@@ -0,0 +1,100 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import SwiftUI
+
+struct MainView: View {
+ @ObservedObject var presenter: MainPresenter
+ @State private var selectedService: Service?
+ @State private var path = NavigationPath()
+
+ var body: some View {
+ NavigationStack(path: $path) {
+ List {
+ if !presenter.favoriteList.isEmpty {
+ Section(header:
+ HStack(alignment: .center) {
+ Image(systemName: "star.fill")
+ Text(T.Tokens.favoriteServices)
+ }
+ ) {
+ ForEach(presenter.favoriteList, id: \.self) { service in
+ NavigationLink(value: MainPath.favorite(service)) {
+ ServiceCellView(service: service)
+ }
+ .listRowBackground(Color.clear)
+ .listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0))
+ .listSectionSpacing(WatchConsts.listSectionRowSpacing)
+ }
+ }
+ }
+ Section {
+ NavigationLink(value: MainPath.tokens) {
+ HStack(alignment: .center) {
+ Image(systemName: "folder")
+ Text(T.Commons.tokens)
+ .font(.callout)
+ .padding(4)
+ .foregroundStyle(.primary)
+ }
+ }
+
+ NavigationLink(value: MainPath.settings) {
+ HStack(alignment: .center) {
+ Image(systemName: "gear")
+ Text(T.Settings.settings)
+ .font(.callout)
+ .padding(4)
+ .foregroundStyle(.primary)
+ }
+ }
+ }
+ }
+ .navigationDestination(for: MainPath.self) { route in
+ switch route {
+ case .settings: SettingsView(path: $path)
+ case .tokens: ServiceListView(presenter: ServiceListPresenter(
+ interactor: InteractorFactory.shared.serviceListInteractor()
+ ))
+ case .favorite(let service):
+ ServiceView(
+ presenter: ServicePresenter(
+ interactor: InteractorFactory.shared.serviceInteractor(service: service)
+ )
+ )
+ }
+ }
+ .onAppear {
+ presenter.onAppear()
+ }
+ .containerBackground(.red.gradient, for: .navigation)
+ .listStyle(.carousel)
+ .environment(\.defaultMinListRowHeight, WatchConsts.minRowHeight)
+ .navigationTitle(T.Commons._2fasToolbar)
+ .navigationBarTitleDisplayMode(.automatic)
+ .listItemTint(.clear)
+ }
+ }
+}
+
+enum MainPath: Hashable {
+ case settings
+ case tokens
+ case favorite(Service)
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/PIN/PINKeyboardInteractor.swift b/TwoFAS/TwoFASWatch Watch App/PIN/PINKeyboardInteractor.swift
new file mode 100644
index 00000000..7f83c119
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/PIN/PINKeyboardInteractor.swift
@@ -0,0 +1,159 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import Foundation
+import CommonWatch
+
+enum PINKeyboardVariant {
+ case PINValidation
+ case PINValidationWithClose
+ case enterNewPIN(PINType)
+ case verifyPIN(AppPIN)
+}
+
+protocol PINKeyboardInteracting: AnyObject {
+ var length: Int { get }
+ var isFull: Bool { get }
+ var isEmpty: Bool { get }
+ var pinLastLetterVisible: String { get }
+ var pinInvisible: String { get }
+ var variant: PINKeyboardVariant { get }
+ var completePIN: AppPIN { get }
+ func validate() -> Bool
+ func save()
+ func remove()
+
+ func addPINNumber(_ number: Int)
+ func removePINNumber()
+ func clearPINNumbers()
+}
+
+final class PINKeyboardInteractor {
+ private let mainRepository: MainRepository
+
+ private let pinType: PINType
+ private let currentPIN: AppPIN?
+ let variant: PINKeyboardVariant
+
+ var completePIN: AppPIN {
+ AppPIN(type: pinType, value: collectedPIN.createPIN())
+ }
+
+ private let placeholder = "•"
+
+ private var collectedPIN: [String] = []
+
+ init(mainRepository: MainRepository, variant: PINKeyboardVariant) {
+ self.mainRepository = mainRepository
+ self.variant = variant
+
+ self.pinType = {
+ switch variant {
+ case .PINValidation, .PINValidationWithClose: mainRepository.pin?.type ?? .digits4
+ case .enterNewPIN(let PINType): PINType
+ case .verifyPIN(let appPIN): appPIN.type
+ }
+ }()
+
+ self.currentPIN = {
+ switch variant {
+ case .PINValidation, .PINValidationWithClose: mainRepository.pin
+ case .enterNewPIN: nil
+ case .verifyPIN(let appPIN): appPIN
+ }
+ }()
+ }
+}
+
+extension PINKeyboardInteractor: PINKeyboardInteracting {
+ var length: Int {
+ collectedPIN.count
+ }
+
+ var isFull: Bool {
+ length == pinType.digits
+ }
+
+ var isEmpty: Bool {
+ collectedPIN.isEmpty
+ }
+
+ var pinLastLetterVisible: String {
+ guard !isEmpty else { return "⠀" }
+ return collectedPIN.enumerated()
+ .map { index, element in
+ if index == collectedPIN.count - 1 {
+ return element
+ }
+ return placeholder
+ }
+ .joined()
+ }
+
+ var pinInvisible: String {
+ guard !isEmpty else { return "⠀" }
+ return collectedPIN.map({ _ in placeholder }).joined()
+ }
+
+ func validate() -> Bool {
+ guard isFull else { return false }
+ if let currentPIN {
+ return currentPIN.value == collectedPIN.createPIN()
+ }
+ return true
+ }
+
+ func save() {
+ guard let currentPIN, variant.canSave else { return }
+ mainRepository.setPIN(currentPIN)
+ }
+
+ func remove() {
+ mainRepository.setPIN(nil)
+ }
+
+ func addPINNumber(_ number: Int) {
+ guard !isFull else { return }
+ collectedPIN.append(String(number))
+ }
+
+ func removePINNumber() {
+ guard !isEmpty else { return }
+ collectedPIN.removeLast()
+ }
+
+ func clearPINNumbers() {
+ collectedPIN = []
+ }
+}
+
+private extension Array where Element == String {
+ func createPIN() -> String {
+ map { String($0) }.reduce("", +)
+ }
+}
+
+private extension PINKeyboardVariant {
+ var canSave: Bool {
+ switch self {
+ case .verifyPIN: true
+ default: false
+ }
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/PIN/PINKeyboardPresenter.swift b/TwoFAS/TwoFASWatch Watch App/PIN/PINKeyboardPresenter.swift
new file mode 100644
index 00000000..e5240db9
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/PIN/PINKeyboardPresenter.swift
@@ -0,0 +1,157 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import Foundation
+import CommonWatch
+import WatchKit
+
+enum PINKeyboardResult: Equatable, Hashable {
+ static func == (lhs: PINKeyboardResult, rhs: PINKeyboardResult) -> Bool {
+ switch (lhs, rhs) {
+ case (.verified, .verified): true
+ case (.closed, .closed): true
+ case (.entered, .entered): true
+ case (.saved, .saved): true
+ default: false
+ }
+ }
+
+ func hash(into hasher: inout Hasher) {
+ hasher.combine(self)
+ }
+
+ case verified
+ case closed
+ case entered(AppPIN)
+ case saved
+}
+
+final class PINKeyboardPresenter: ObservableObject {
+ @Published var isNumKeyboardLocked = false
+ @Published var isDeleteVisible = false
+ @Published var pin: String = "⠀"
+ @Published var animateFailure = false
+ @Published var showCloseButton = false
+ @Published var navigationTitle = ""
+
+ private let interactor: PINKeyboardInteracting
+ private let completion: (PINKeyboardResult) -> Void
+
+ init(interactor: PINKeyboardInteracting, completion: @escaping (PINKeyboardResult) -> Void) {
+ self.interactor = interactor
+ self.completion = completion
+
+ showCloseButton = interactor.variant.showCloseButton
+ navigationTitle = interactor.variant.navigationTitle
+ }
+
+ func onCloseAction() {
+ guard showCloseButton else { return }
+ completion(.closed)
+ }
+
+ func onShakeAnimationEnded() {
+ interactor.clearPINNumbers()
+ pin = interactor.pinInvisible
+
+ animateFailure = false
+ isDeleteVisible = false
+ isNumKeyboardLocked = false
+ }
+
+ func numButtonPressed(_ value: Int) {
+ func validate() {
+ if interactor.validate() {
+ DispatchQueue.main.async {
+ WKInterfaceDevice().play(.success)
+ }
+ isDeleteVisible = false
+ isNumKeyboardLocked = true
+
+ switch interactor.variant {
+ case .PINValidation: completion(.verified)
+ case .PINValidationWithClose: completion(.verified)
+ case .enterNewPIN: completion(.entered(interactor.completePIN))
+ case .verifyPIN:
+ interactor.save()
+ completion(.saved)
+ }
+ } else {
+ wrongPIN()
+ }
+ }
+
+ if interactor.isFull {
+ validate()
+ return
+ }
+
+ interactor.addPINNumber(value)
+
+ updateDeleteButton()
+ pin = interactor.pinLastLetterVisible
+
+ if interactor.isFull {
+ validate()
+ }
+ }
+
+ func onNumButtonRelease(_ value: Int) {
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) { [weak self] in
+ self?.pin = self?.interactor.pinInvisible ?? ""
+ }
+ }
+
+ func onDeleteAction() {
+ guard !interactor.isEmpty else { return }
+ interactor.removePINNumber()
+ pin = interactor.pinInvisible
+ updateDeleteButton()
+ }
+}
+
+private extension PINKeyboardPresenter {
+ func wrongPIN() {
+ isDeleteVisible = false
+ isNumKeyboardLocked = true
+ animateFailure = true
+ }
+
+ func updateDeleteButton() {
+ isDeleteVisible = !interactor.isEmpty
+ }
+}
+
+private extension PINKeyboardVariant {
+ var navigationTitle: String {
+ switch self {
+ case .PINValidation: T.Security.enterPinShort
+ case .PINValidationWithClose: T.Security.enterPinShort
+ case .enterNewPIN: T.Security.enterNewPinShort
+ case .verifyPIN: T.Security.repeatNewPinShort
+ }
+ }
+
+ var showCloseButton: Bool {
+ switch self {
+ case .PINValidation: false
+ default: true
+ }
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/PIN/PINKeyboardView.swift b/TwoFAS/TwoFASWatch Watch App/PIN/PINKeyboardView.swift
new file mode 100644
index 00000000..6f4b4233
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/PIN/PINKeyboardView.swift
@@ -0,0 +1,201 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import SwiftUI
+import CommonWatch
+
+struct PINKeyboardView: View {
+ @State private var shake: CGFloat = 0
+
+ @ObservedObject
+ var presenter: PINKeyboardPresenter
+
+ var body: some View {
+ VStack {
+ Text(presenter.pin)
+ .modifier(Shake(shake: shake))
+ Spacer()
+ Grid(alignment: .center, horizontalSpacing: 1, verticalSpacing: 1) {
+ GridRow {
+ button(1)
+ .disabled(presenter.isNumKeyboardLocked)
+ button(2)
+ .disabled(presenter.isNumKeyboardLocked)
+ button(3)
+ .disabled(presenter.isNumKeyboardLocked)
+ }
+
+ GridRow {
+ button(4)
+ .disabled(presenter.isNumKeyboardLocked)
+ button(5)
+ .disabled(presenter.isNumKeyboardLocked)
+ button(6)
+ .disabled(presenter.isNumKeyboardLocked)
+ }
+
+ GridRow {
+ button(7)
+ .disabled(presenter.isNumKeyboardLocked)
+ button(8)
+ .disabled(presenter.isNumKeyboardLocked)
+ button(9)
+ .disabled(presenter.isNumKeyboardLocked)
+ }
+
+ GridRow {
+ Color.clear.gridCellUnsizedAxes([.horizontal, .vertical])
+ button(0)
+ .disabled(presenter.isNumKeyboardLocked)
+ if presenter.isDeleteVisible {
+ deleteButton()
+ } else {
+ deleteButton()
+ .hidden()
+ }
+ }
+ }
+ }
+ .onChange(of: presenter.animateFailure, { _, newValue in
+ if newValue {
+ withAnimation(.easeInOut(duration: 1)) {
+ shake = 3
+ } completion: {
+ shake = 0
+ presenter.onShakeAnimationEnded()
+ }
+
+ DispatchQueue.main.async {
+ WKInterfaceDevice().play(.failure)
+ }
+ }
+ })
+ .navigationBarBackButtonHidden(presenter.showCloseButton)
+ .ignoresSafeArea(edges: [.horizontal, .bottom])
+ .toolbar(content: {
+ if presenter.showCloseButton {
+ ToolbarItem(placement: .cancellationAction) {
+ Button {
+ presenter.onCloseAction()
+ } label: {
+ Label(T.Commons.close, systemImage: "xmark")
+ }
+ }
+ }
+ })
+ .toolbarTitleDisplayMode(.inline)
+ .navigationTitle(presenter.navigationTitle)
+ }
+
+ @ViewBuilder
+ private func button(_ value: Int) -> some View {
+ Button(action: {}, label: {
+ Text(String(value))
+ .foregroundStyle(.black)
+ .font(.caption)
+ .monospacedDigit()
+ })
+ .buttonStyle(KeyboardButton(
+ press: { presenter.numButtonPressed(value) },
+ release: { presenter.onNumButtonRelease(value) })
+ )
+ }
+
+ @ViewBuilder
+ private func deleteButton() -> some View {
+ Button(action: {
+ presenter.onDeleteAction()
+ }, label: {
+ Image(systemName: "delete.left")
+ .foregroundStyle(.black)
+ })
+ .buttonStyle(KeyboardButton())
+ }
+}
+
+public struct KeyboardButton: ButtonStyle {
+ let press: (() -> Void)?
+ let release: (() -> Void)?
+
+ init(press: (() -> Void)? = nil, release: (() -> Void)? = nil) {
+ self.press = press
+ self.release = release
+ }
+
+ public func makeBody(configuration: Configuration) -> some View {
+ GeometryReader(content: { geometry in
+ if configuration.isPressed {
+ RoundedRectangle(cornerRadius: 10, style: .continuous)
+ .fill(Color.gray.opacity(0.7))
+ .frame(width: geometry.size.width, height: geometry.size.height)
+ .scaleEffect(1.1)
+ } else {
+ RoundedRectangle(cornerRadius: 10, style: .continuous)
+ .fill(Color.gray.opacity(0.5))
+ .frame(width: geometry.size.width, height: geometry.size.height)
+ .scaleEffect(1)
+ }
+
+ configuration.label
+ .background(
+ ZStack {
+ GeometryReader(content: { geometry in
+ RoundedRectangle(cornerRadius: 10, style: .continuous)
+ .fill(Color.clear)
+ .frame(
+ width: configuration.isPressed ? geometry.size.width / 0.75 : geometry.size.width,
+ height: configuration.isPressed ? geometry.size.height / 0.8 : geometry.size.height
+ )
+ })
+ }
+ )
+ .frame(width: geometry.size.width, height: geometry.size.height)
+ .scaleEffect(configuration.isPressed ? 1.2 : 1)
+ })
+ .onChange(of: configuration.isPressed) { old, new in
+ if new {
+ press?()
+ DispatchQueue.main.async {
+ WKInterfaceDevice().play(.click)
+ }
+ } else if old && !new {
+ release?()
+ }
+ }
+ }
+}
+
+struct Shake: AnimatableModifier {
+ var amount: CGFloat = 10
+ var shakesPerUnit = 3
+ var shake: CGFloat = 0
+
+ var animatableData: CGFloat {
+ get { shake }
+ set { shake = newValue }
+ }
+
+ func body(content: Content) -> some View {
+ content.projectionEffect(
+ ProjectionTransform(
+ CGAffineTransform(translationX: amount * sin(shake * .pi * CGFloat(shakesPerUnit)), y: 0)
+ )
+ )
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Preview Content/Preview Assets.xcassets/Contents.json b/TwoFAS/TwoFASWatch Watch App/Preview Content/Preview Assets.xcassets/Contents.json
new file mode 100644
index 00000000..73c00596
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Preview Content/Preview Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Service/ServiceInteractor.swift b/TwoFAS/TwoFASWatch Watch App/Service/ServiceInteractor.swift
new file mode 100644
index 00000000..6af0b2f1
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Service/ServiceInteractor.swift
@@ -0,0 +1,132 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import Foundation
+import CommonWatch
+
+protocol ServiceInteracting: AnyObject {
+ var service: Service { get }
+
+ func initialize()
+ func token(for date: Date) -> TokenValue
+ func timelineEntries(for date: Date) -> [Date]
+ func timeToNextDate(for date: Date) -> Date
+
+ func isFavorite() -> Bool
+ func toogleFavorite()
+
+ func isHOTP() -> Bool
+}
+
+final class ServiceInteractor {
+ private let mainRepository: MainRepository
+ let service: Service
+
+ private let calendar = Calendar.current
+
+ private var serviceData: ServiceData?
+
+ init(mainRepository: MainRepository, service: Service) {
+ self.mainRepository = mainRepository
+ self.service = service
+ }
+}
+
+extension ServiceInteractor: ServiceInteracting {
+ func initialize() {
+ serviceData = mainRepository.service(for: service.id)
+ }
+
+ func token(for date: Date) -> TokenValue {
+ guard let serviceData else { return "" }
+ return mainRepository.token(
+ secret: serviceData.secret,
+ time: date,
+ digits: Digits.create(serviceData.digits),
+ period: Period.create(serviceData.period),
+ algorithm: serviceData.algorithm,
+ counter: 0,
+ tokenType: serviceData.tokenType
+ )
+ .formattedValue(for: serviceData.tokenType)
+ }
+
+ func timeToNextDate(for date: Date) -> Date {
+ guard let serviceData else { return Date.now }
+
+ let secondsToNewOne: Int = {
+ let period = serviceData.period
+ let currentSeconds: Int = calendar.component(.second, from: date)
+ if currentSeconds >= period {
+ let times = (currentSeconds / period) + 1
+ return times * period - currentSeconds
+ }
+ return period - currentSeconds
+ }()
+
+ return calendar.date(byAdding: .second, value: secondsToNewOne, to: date)!
+ }
+
+ func timelineEntries(for date: Date) -> [Date] {
+ guard let serviceData else { return [] }
+ var entries: [Date] = []
+
+ let smallestIncrement = serviceData.period
+
+ let seconds = calendar.component(.second, from: date)
+ let offset: Int = {
+ let rest = seconds % smallestIncrement
+ return smallestIncrement - rest
+ }()
+ let upTo = 256
+
+ for i in 0 ..< upTo {
+ let currentOffset: Int = {
+ if i == 0 {
+ return 0
+ } else if i == 1 {
+ return offset
+ }
+ return offset + smallestIncrement * (i - 1)
+ }()
+ let entryDate = calendar.date(byAdding: .second, value: currentOffset, to: date)!
+
+ entries.append(entryDate)
+ }
+
+ return entries
+ }
+
+ func isFavorite() -> Bool {
+ mainRepository.listFavoriteServices().contains(where: { $0.secret == service.id })
+ }
+
+ func isHOTP() -> Bool {
+ guard let serviceData else { return false }
+ return serviceData.tokenType == .hotp
+ }
+
+ func toogleFavorite() {
+ if isFavorite() {
+ mainRepository.removeFavoriteService(service.id)
+ } else {
+ mainRepository.addFavoriteService(service.id)
+ }
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Service/ServicePresenter.swift b/TwoFAS/TwoFASWatch Watch App/Service/ServicePresenter.swift
new file mode 100644
index 00000000..4e8501ea
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Service/ServicePresenter.swift
@@ -0,0 +1,62 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import Foundation
+import CommonWatch
+
+final class ServicePresenter: ObservableObject {
+ @Published var name = ""
+ @Published var additionalInfo: String?
+ @Published var service: Service
+ @Published var isFavorite: Bool
+ @Published var isHOTP: Bool
+
+ private let interactor: ServiceInteracting
+
+ init(interactor: ServiceInteracting) {
+ self.interactor = interactor
+
+ interactor.initialize()
+
+ name = interactor.service.name
+ additionalInfo = interactor.service.additionalInfo
+ service = interactor.service
+ isFavorite = interactor.isFavorite()
+ isHOTP = interactor.isHOTP()
+ }
+}
+
+extension ServicePresenter {
+ func calculateToken(for date: Date) -> TokenValue {
+ interactor.token(for: date)
+ }
+
+ func timelineEntries() -> [Date] {
+ interactor.timelineEntries(for: Date())
+ }
+
+ func timeToNextDate(for date: Date) -> Date {
+ interactor.timeToNextDate(for: date)
+ }
+
+ func toggleFavorite() {
+ interactor.toogleFavorite()
+ isFavorite = interactor.isFavorite()
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Service/ServiceView.swift b/TwoFAS/TwoFASWatch Watch App/Service/ServiceView.swift
new file mode 100644
index 00000000..21590694
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Service/ServiceView.swift
@@ -0,0 +1,113 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import SwiftUI
+import CommonWatch
+
+struct ServiceView: View {
+ @Environment(\.colorScheme) private var colorScheme
+
+ @ObservedObject
+ var presenter: ServicePresenter
+
+ private let spacing: CGFloat = 8
+
+ @ViewBuilder
+ var body: some View {
+ Group {
+ if presenter.isHOTP {
+ unsupportedHOTP()
+ } else {
+ list()
+ }
+ }
+ .navigationTitle {
+ Text(presenter.name)
+ .lineLimit(1)
+ }
+ .scenePadding()
+ }
+
+ @ViewBuilder
+ private func list() -> some View {
+ TimelineView(.explicit(presenter.timelineEntries())) { context in
+ VStack(alignment: .leading, spacing: nil) {
+ HStack(alignment: .center, spacing: nil) {
+ IconRenderer(service: presenter.service)
+ Spacer()
+ counterText(for: presenter.timeToNextDate(for: context.date))
+ .multilineTextAlignment(.trailing)
+ .font(Font.body.monospacedDigit())
+ .lineLimit(1)
+ .contentTransition(.numericText(countsDown: true))
+ }
+ Spacer()
+ VStack(alignment: .leading, spacing: 3) {
+ Text(presenter.calculateToken(for: context.date))
+ .font(Font.system(.title).weight(.light).monospacedDigit())
+ .multilineTextAlignment(.leading)
+ .minimumScaleFactor(0.2)
+ .contentTransition(.numericText())
+ .foregroundColor(.primary)
+ .layoutPriority(1)
+ if let info = presenter.additionalInfo {
+ Text(info)
+ .lineLimit(1)
+ .font(.caption2)
+ .foregroundColor(.secondary)
+ .multilineTextAlignment(.leading)
+ }
+ Spacer()
+ .frame(maxHeight: .infinity)
+ }
+ .frame(alignment: .leading)
+ .padding(.top, 4)
+ }
+ }
+ .toolbar {
+ ToolbarItem(placement: .bottomBar) {
+ Button {
+ presenter.toggleFavorite()
+ } label: {
+ if presenter.isFavorite {
+ Image(systemName: "star.fill")
+ } else {
+ Image(systemName: "star")
+ }
+ }
+ .controlSize(.mini)
+ .background(Color.accentColor, in: Circle())
+ }
+ }
+ }
+
+ @ViewBuilder
+ private func unsupportedHOTP() -> some View {
+ Text(T.Tokens.hotpNotSupported)
+ }
+
+ @ViewBuilder
+ private func counterText(for date: Date?) -> some View {
+ if let countdownTo = date {
+ Text(countdownTo, style: .timer)
+ } else {
+ Text("0:00")
+ }
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/ServiceList/ServiceCellView.swift b/TwoFAS/TwoFASWatch Watch App/ServiceList/ServiceCellView.swift
new file mode 100644
index 00000000..d98f9493
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/ServiceList/ServiceCellView.swift
@@ -0,0 +1,94 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import SwiftUI
+import CommonWatch
+
+struct ServiceCellView: View {
+ let service: Service
+
+ var body: some View {
+ HStack(alignment: .center, spacing: 8) {
+ UnevenRoundedRectangle(
+ cornerRadii:
+ .init(
+ topLeading: 4,
+ bottomLeading: 4,
+ bottomTrailing: 0,
+ topTrailing: 0
+ ),
+ style: .continuous
+ )
+ .fill(service.badgeColor)
+ .frame(width: 5)
+
+ IconRenderer(service: service)
+ VStack(alignment: .leading, spacing: 0) {
+ Text(service.name)
+ .font(.callout)
+ .lineLimit(1)
+ .foregroundStyle(.primary)
+ if let additionalInfo = service.additionalInfo {
+ Text(additionalInfo)
+ .font(.caption2)
+ .foregroundStyle(.secondary)
+ .lineLimit(1)
+ }
+ }
+ .padding(.vertical, 4)
+ }
+ .padding(.trailing, 4)
+ .frame(maxWidth: .infinity, alignment: .leading)
+ .background(
+ Material.ultraThinMaterial,
+ in: UnevenRoundedRectangle(
+ cornerRadii:
+ .init(
+ topLeading: 4,
+ bottomLeading: 4,
+ bottomTrailing: 8,
+ topTrailing: 8
+ ),
+ style: .continuous
+ )
+ )
+ .listItemTint(.clear)
+ }
+}
+
+#Preview {
+ NavigationStack {
+ List {
+ ServiceCellView(service: .init(
+ id: "ID",
+ name: "2FAS Service",
+ additionalInfo: "contact@2fas.com",
+ iconType: .label,
+ iconTypeID: .default,
+ labelColor: TintColor.green.color,
+ labelTitle: "2F",
+ badgeColor: TintColor.default.color
+ ))
+ .listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0))
+ }
+ .containerBackground(.red.gradient, for: .navigation)
+ .environment(\.defaultMinListRowHeight, WatchConsts.minRowHeight)
+ .listRowBackground(Color.clear)
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/ServiceList/ServiceListInteractor.swift b/TwoFAS/TwoFASWatch Watch App/ServiceList/ServiceListInteractor.swift
new file mode 100644
index 00000000..444212c2
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/ServiceList/ServiceListInteractor.swift
@@ -0,0 +1,42 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import Foundation
+import StorageWatch
+
+protocol ServiceListInteracting: AnyObject {
+ var hasServices: Bool { get }
+ func listAllServices() -> [CategoryData]
+}
+
+final class ServiceListInteractor {
+ private let mainRepository: MainRepository
+
+ init(mainRepository: MainRepository) {
+ self.mainRepository = mainRepository
+ }
+}
+
+extension ServiceListInteractor: ServiceListInteracting {
+ var hasServices: Bool { mainRepository.hasServices }
+
+ func listAllServices() -> [CategoryData] {
+ mainRepository.listAllServicesWithingCategories(for: nil, sorting: .manual, ids: [])
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/ServiceList/ServiceListPresenter.swift b/TwoFAS/TwoFASWatch Watch App/ServiceList/ServiceListPresenter.swift
new file mode 100644
index 00000000..cad0a4b6
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/ServiceList/ServiceListPresenter.swift
@@ -0,0 +1,42 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import Foundation
+import CommonWatch
+
+final class ServiceListPresenter: ObservableObject {
+ @Published var list: [Category] = []
+
+ private let interactor: ServiceListInteracting
+
+ init(interactor: ServiceListInteracting) {
+ self.interactor = interactor
+ }
+}
+
+extension ServiceListPresenter {
+ func onAppear() {
+ refresh()
+ }
+
+ private func refresh() {
+ list = interactor.listAllServices()
+ .toCategories()
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/ServiceList/ServiceListView.swift b/TwoFAS/TwoFASWatch Watch App/ServiceList/ServiceListView.swift
new file mode 100644
index 00000000..9d223977
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/ServiceList/ServiceListView.swift
@@ -0,0 +1,74 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import SwiftUI
+
+struct ServiceListView: View {
+ @ObservedObject var presenter: ServiceListPresenter
+
+ var body: some View {
+ Group {
+ if presenter.list.isEmpty {
+ VStack(alignment: .center, spacing: 8) {
+ Image(systemName: "folder")
+ .font(.system(size: 40))
+ Text(T.Tokens.tokensListIsEmpty)
+ }
+ } else {
+ List {
+ ForEach(presenter.list, id: \.self) { category in
+ Section(header: Text(category.name)) {
+ ForEach(category.services, id: \.self) { service in
+ NavigationLink(value: ServiceListPath.service(service)) {
+ ServiceCellView(service: service)
+ }
+ .listRowBackground(Color.clear)
+ .listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0))
+ .listSectionSpacing(WatchConsts.listSectionRowSpacing)
+ }
+ }
+ }
+ }
+ }
+ }
+ .navigationDestination(for: ServiceListPath.self, destination: { route in
+ switch route {
+ case .service(let service):
+ ServiceView(
+ presenter: ServicePresenter(
+ interactor: InteractorFactory.shared.serviceInteractor(service: service)
+ )
+ )
+ }
+ })
+ .onAppear {
+ presenter.onAppear()
+ }
+ .containerBackground(.red.gradient, for: .navigation)
+ .listStyle(.carousel)
+ .environment(\.defaultMinListRowHeight, WatchConsts.minRowHeight)
+ .navigationTitle(T.Commons.tokens)
+ .navigationBarTitleDisplayMode(.automatic)
+ .listItemTint(.clear)
+ }
+}
+
+enum ServiceListPath: Hashable {
+ case service(Service)
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Settings/About/AboutView.swift b/TwoFAS/TwoFASWatch Watch App/Settings/About/AboutView.swift
new file mode 100644
index 00000000..1af2c0d5
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Settings/About/AboutView.swift
@@ -0,0 +1,52 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import SwiftUI
+
+struct AboutView: View {
+ var body: some View {
+ ScrollView {
+ VStack(alignment: .center, spacing: 4) {
+ LogoView()
+ Spacer()
+
+ Text(T.Watch.intro)
+ .font(.body)
+ .padding(4)
+ .foregroundStyle(.primary)
+
+ Spacer()
+
+ Text(T.Settings.version(appVersion))
+ .font(.body)
+ .padding(4)
+ .foregroundStyle(.primary)
+ }
+ }
+ .navigationTitle(T.Settings.about)
+ }
+
+ private var appVersion: String {
+ Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "-"
+ }
+}
+
+#Preview {
+ AboutView()
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Settings/About/LogoView.swift b/TwoFAS/TwoFASWatch Watch App/Settings/About/LogoView.swift
new file mode 100644
index 00000000..66e6e02e
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Settings/About/LogoView.swift
@@ -0,0 +1,44 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import SwiftUI
+
+struct LogoView: View {
+ var body: some View {
+ VStack(alignment: .leading) {
+ HStack(alignment: .center, spacing: 4) {
+ Image("AboutLogo")
+ .resizable()
+ .aspectRatio(contentMode: .fit)
+ .frame(width: 40)
+ .padding(.leading, 4)
+ .padding(.vertical, 4)
+
+ Text(T.Commons._2fasToolbar)
+ .font(.title)
+ .multilineTextAlignment(.leading)
+ .padding(.horizontal, 12)
+ .foregroundStyle(.primary)
+
+ Spacer()
+ }
+ .frame(maxWidth: .infinity, alignment: .leading)
+ }
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Settings/Security/PINType/PINTypeView.swift b/TwoFAS/TwoFASWatch Watch App/Settings/Security/PINType/PINTypeView.swift
new file mode 100644
index 00000000..370b7ecd
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Settings/Security/PINType/PINTypeView.swift
@@ -0,0 +1,64 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import SwiftUI
+import CommonWatch
+
+struct PINTypeView: View {
+ var didSelect: (PINType) -> Void
+ let showClose: Bool
+ var didClose: (() -> Void)?
+
+ init(didSelect: @escaping (PINType) -> Void, showClose: Bool = false, didClose: (() -> Void)? = nil) {
+ self.didSelect = didSelect
+ self.showClose = showClose
+ self.didClose = didClose
+ }
+
+ var body: some View {
+ VStack {
+ Button {
+ didSelect(.digits4)
+ } label: {
+ Text(T.Settings.pin4Digits)
+ }
+
+ Button {
+ didSelect(.digits6)
+ } label: {
+ Text(T.Settings.pin6Digits)
+ }
+ }
+ .containerBackground(.red.gradient, for: .navigation)
+ .navigationTitle(T.Settings.selectPinLength)
+ .navigationBarTitleDisplayMode(.automatic)
+ .navigationBarBackButtonHidden(showClose)
+ .toolbar(content: {
+ if showClose {
+ ToolbarItem(placement: .cancellationAction) {
+ Button {
+ didClose?()
+ } label: {
+ Label(T.Commons.close, systemImage: "xmark")
+ }
+ }
+ }
+ })
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Settings/Security/SecurityInteractor.swift b/TwoFAS/TwoFASWatch Watch App/Settings/Security/SecurityInteractor.swift
new file mode 100644
index 00000000..f92b3288
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Settings/Security/SecurityInteractor.swift
@@ -0,0 +1,43 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import Foundation
+
+protocol SecurityInteracting: AnyObject {
+ var isPINSet: Bool { get }
+ func disablePIN()
+}
+
+final class SecurityInteractor {
+ private let mainRepository: MainRepository
+
+ init(mainRepository: MainRepository) {
+ self.mainRepository = mainRepository
+ }
+}
+
+extension SecurityInteractor: SecurityInteracting {
+ var isPINSet: Bool {
+ mainRepository.pin != nil
+ }
+
+ func disablePIN() {
+ mainRepository.setPIN(nil)
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Settings/Security/SecurityPath.swift b/TwoFAS/TwoFASWatch Watch App/Settings/Security/SecurityPath.swift
new file mode 100644
index 00000000..5b79cefb
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Settings/Security/SecurityPath.swift
@@ -0,0 +1,45 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import Foundation
+import CommonWatch
+
+enum SecurityPath: Hashable {
+ enum SetPIN: Hashable {
+ case selectLength
+ case enterPIN(PINType)
+ case verifyPIN(AppPIN)
+ case success
+ }
+ enum DisablePIN: Hashable {
+ case verify
+ case success
+ }
+ enum ChangePIN: Hashable {
+ case verify
+ case selectLength
+ case enterPIN(PINType)
+ case verifyPIN(AppPIN)
+ case success
+ }
+
+ case setPIN(SetPIN)
+ case disablePIN(DisablePIN)
+ case changePIN(ChangePIN)
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Settings/Security/SecurityPresenter.swift b/TwoFAS/TwoFASWatch Watch App/Settings/Security/SecurityPresenter.swift
new file mode 100644
index 00000000..b5d32b89
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Settings/Security/SecurityPresenter.swift
@@ -0,0 +1,40 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import Foundation
+
+final class SecurityPresenter: ObservableObject {
+ @Published
+ var isPINset = false
+
+ private let interactor: SecurityInteracting
+
+ init(interactor: SecurityInteracting) {
+ self.interactor = interactor
+ }
+
+ func onAppear() {
+ isPINset = interactor.isPINSet
+ }
+
+ func handleDisablePIN() {
+ interactor.disablePIN()
+ isPINset = false
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Settings/Security/SecurityView.swift b/TwoFAS/TwoFASWatch Watch App/Settings/Security/SecurityView.swift
new file mode 100644
index 00000000..687a4165
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Settings/Security/SecurityView.swift
@@ -0,0 +1,166 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import SwiftUI
+import CommonWatch
+
+struct SecurityView: View {
+ @Binding
+ var path: NavigationPath
+
+ @ObservedObject
+ var presenter: SecurityPresenter
+
+ var body: some View {
+ List {
+ if presenter.isPINset {
+ NavigationLink(value: SecurityPath.changePIN(.verify)) {
+ HStack {
+ Image(systemName: "lock.rotation")
+ Text(T.Security.changePin)
+ }
+ }
+
+ NavigationLink(value: SecurityPath.disablePIN(.verify)) {
+ HStack {
+ Image(systemName: "lock.open.fill")
+ Text(T.Security.disablePin)
+ }
+ }
+ } else {
+ NavigationLink(value: SecurityPath.setPIN(.selectLength)) {
+ HStack {
+ Image(systemName: "lock.fill")
+ Text(T.Security.createPin)
+ }
+ }
+ }
+ }
+ .navigationDestination(for: SecurityPath.self) { route in
+ switch route {
+ case .setPIN(let setPIN):
+ switch setPIN {
+ case .selectLength:
+ PINTypeView { PINType in
+ path.append(SecurityPath.setPIN(.enterPIN(PINType)))
+ }
+ case .enterPIN(let PINType):
+ PINKeyboardView(
+ presenter: .init(
+ interactor: InteractorFactory.shared.pinInteractor(variant: .enterNewPIN(PINType)
+ ), completion: { result in
+ switch result {
+ case .closed: path.removeLast(2)
+ case .entered(let appPIN): path.append(SecurityPath.setPIN(.verifyPIN(appPIN)))
+ default: break
+ }
+ }))
+ case .verifyPIN(let appPIN):
+ PINKeyboardView(
+ presenter: .init(
+ interactor: InteractorFactory.shared.pinInteractor(variant: .verifyPIN(appPIN)
+ ), completion: { result in
+ switch result {
+ case .closed: path.removeLast(3)
+ case .saved: path.append(SecurityPath.setPIN(.success))
+ default: break
+ }
+ }))
+ case .success:
+ SuccessView {
+ path.removeLast(4)
+ }
+ }
+ case .disablePIN(let disablePIN):
+ switch disablePIN {
+ case .verify:
+ PINKeyboardView(
+ presenter: .init(
+ interactor: InteractorFactory.shared.pinInteractor(
+ variant: .PINValidationWithClose), completion: { result in
+ switch result {
+ case .closed: path.removeLast()
+ case .verified:
+ presenter.handleDisablePIN()
+ path.append(SecurityPath.disablePIN(.success))
+ default: break
+ }
+ }))
+ case .success:
+ SuccessView {
+ path.removeLast(2)
+ }
+ }
+ case .changePIN(let changePIN):
+ switch changePIN {
+ case .verify:
+ PINKeyboardView(
+ presenter: .init(
+ interactor: InteractorFactory.shared.pinInteractor(
+ variant: .PINValidationWithClose), completion: { result in
+ switch result {
+ case .closed: path.removeLast()
+ case .verified: path.append(SecurityPath.changePIN(.selectLength))
+ default: break
+ }
+ }))
+ case .selectLength:
+ PINTypeView(didSelect: { PINType in
+ path.append(SecurityPath.changePIN(.enterPIN(PINType)))
+ }, showClose: true) {
+ path.removeLast(2)
+ }
+ case .enterPIN(let PINType):
+ PINKeyboardView(presenter: .init(
+ interactor: InteractorFactory.shared.pinInteractor(
+ variant: .enterNewPIN(PINType)), completion: { result in
+ switch result {
+ case .closed: path.removeLast(3)
+ case .entered(let appPIN): path.append(SecurityPath.changePIN(.verifyPIN(appPIN)))
+ default: break
+ }
+ }))
+ case .verifyPIN(let appPIN):
+ PINKeyboardView(presenter: .init(
+ interactor: InteractorFactory.shared.pinInteractor(
+ variant: .verifyPIN(appPIN)), completion: { result in
+ switch result {
+ case .closed: path.removeLast(4)
+ case .saved: path.append(SecurityPath.changePIN(.success))
+ default: break
+ }
+ }))
+ case .success:
+ SuccessView {
+ path.removeLast(5)
+ }
+ }
+ }
+ }
+ .onAppear {
+ presenter.onAppear()
+ }
+ .containerBackground(.red.gradient, for: .navigation)
+ .listStyle(.carousel)
+ .environment(\.defaultMinListRowHeight, WatchConsts.minRowHeight)
+ .navigationTitle(T.Settings.security)
+ .navigationBarTitleDisplayMode(.automatic)
+ .listItemTint(.clear)
+ }
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Settings/Security/SuccessView.swift b/TwoFAS/TwoFASWatch Watch App/Settings/Security/SuccessView.swift
new file mode 100644
index 00000000..d7d79f25
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Settings/Security/SuccessView.swift
@@ -0,0 +1,43 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import SwiftUI
+
+struct SuccessView: View {
+ var close: () -> Void
+ var body: some View {
+ VStack(spacing: 8) {
+ Image(systemName: "checkmark.shield.fill")
+ .font(.system(size: 40))
+ Text(T.Commons.success)
+ Spacer()
+ Button {
+ close()
+ } label: {
+ Text(T.Commons.close)
+ }
+ .controlSize(.large)
+ }
+ .navigationBarBackButtonHidden()
+ }
+}
+
+#Preview {
+ SuccessView(close: {})
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/Settings/SettingsView.swift b/TwoFAS/TwoFASWatch Watch App/Settings/SettingsView.swift
new file mode 100644
index 00000000..191d8603
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/Settings/SettingsView.swift
@@ -0,0 +1,71 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import SwiftUI
+
+struct SettingsView: View {
+ @Binding
+ var path: NavigationPath
+
+ var body: some View {
+ List {
+ NavigationLink(value: SettingsPath.security) {
+ HStack {
+ Image(systemName: "lock.fill")
+ Text(T.Settings.security)
+ .font(.callout)
+ .padding(4)
+ .foregroundStyle(.primary)
+ }
+ }
+
+ NavigationLink(value: SettingsPath.about) {
+ HStack {
+ Image(systemName: "info.bubble.fill")
+ Text(T.Settings.about)
+ .font(.callout)
+ .padding(4)
+ .foregroundStyle(.primary)
+ }
+ }
+ }
+ .navigationDestination(for: SettingsPath.self) { route in
+ switch route {
+ case .security: SecurityView(
+ path: $path,
+ presenter: SecurityPresenter(
+ interactor: InteractorFactory.shared.securityInteractor()
+ )
+ )
+ case .about: AboutView()
+ }
+ }
+ .containerBackground(.red.gradient, for: .navigation)
+ .listStyle(.carousel)
+ .environment(\.defaultMinListRowHeight, WatchConsts.minRowHeight)
+ .navigationTitle(T.Settings.settings)
+ .navigationBarTitleDisplayMode(.automatic)
+ .listItemTint(.clear)
+ }
+}
+
+enum SettingsPath: Hashable {
+ case security
+ case about
+}
diff --git a/TwoFAS/TwoFASWatch Watch App/TwoFASWatch Watch App.entitlements b/TwoFAS/TwoFASWatch Watch App/TwoFASWatch Watch App.entitlements
new file mode 100644
index 00000000..77e22b2e
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/TwoFASWatch Watch App.entitlements
@@ -0,0 +1,22 @@
+
+
+
+
+ aps-environment
+ development
+ com.apple.developer.icloud-container-identifiers
+
+ iCloud.com.twofas.org.Vault
+
+ com.apple.developer.icloud-services
+
+ CloudKit
+
+ com.apple.developer.ubiquity-kvstore-identifier
+ $(TeamIdentifierPrefix)$(CFBundleIdentifier)
+ com.apple.security.application-groups
+
+ group.twofas.com
+
+
+
diff --git a/TwoFAS/TwoFASWatch Watch App/TwoFASWatchApp.swift b/TwoFAS/TwoFASWatch Watch App/TwoFASWatchApp.swift
new file mode 100644
index 00000000..576f2f83
--- /dev/null
+++ b/TwoFAS/TwoFASWatch Watch App/TwoFASWatchApp.swift
@@ -0,0 +1,65 @@
+//
+// This file is part of the 2FAS iOS app (https://github.com/twofas/2fas-ios)
+// Copyright © 2024 Two Factor Authentication Service, Inc.
+// Contributed by Zbigniew Cisiński. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see
+//
+
+import SwiftUI
+
+@main
+struct TwoFASWatch_Watch_AppApp: App {
+ @WKApplicationDelegateAdaptor var appDelegate: AppDelegateInteractor
+ @State var locked = false
+ @ObservedObject var presenter = AppPresenter(mainRepository: MainRepositoryImpl.shared)
+ var body: some Scene {
+ WindowGroup {
+ if presenter.isAppLocked {
+ NavigationStack {
+ PINKeyboardView(
+ presenter: PINKeyboardPresenter(
+ interactor: PINKeyboardInteractor(
+ mainRepository: MainRepositoryImpl.shared,
+ variant: .PINValidation), completion: { result in
+ guard result == .verified else { return }
+ presenter.unlockApp()
+ }
+ )
+ )
+ }
+ .transition(.opacity)
+ } else {
+ if presenter.showIntro {
+ IntroductionView {
+ presenter.markIntroAsShown()
+ }
+ .transition(.opacity)
+ } else {
+ MainView(
+ presenter: MainPresenter(
+ interactor: InteractorFactory.shared.mainInteractor()
+ )
+ )
+ .containerBackground(.red.gradient, for: .navigation)
+ }
+ }
+ }
+ .onChange(of: WKApplication.shared().applicationState) { _, newValue in
+ if newValue == .active {
+ presenter.update()
+ }
+ }
+ }
+}
diff --git a/TwoFAS/TwoFASWatch-Watch-App-Info.plist b/TwoFAS/TwoFASWatch-Watch-App-Info.plist
new file mode 100644
index 00000000..ca9a074a
--- /dev/null
+++ b/TwoFAS/TwoFASWatch-Watch-App-Info.plist
@@ -0,0 +1,10 @@
+
+
+
+
+ UIBackgroundModes
+
+ remote-notification
+
+
+
diff --git a/TwoFAS/update.swift b/TwoFAS/update.swift
index 7a122ed0..06063daa 100755
Binary files a/TwoFAS/update.swift and b/TwoFAS/update.swift differ