Enable SwiftLint
This commit is contained in:
parent
d465d46956
commit
789333f234
|
@ -2,8 +2,8 @@
|
||||||
# https://github.com/raywenderlich/swift-style-guide
|
# https://github.com/raywenderlich/swift-style-guide
|
||||||
|
|
||||||
excluded:
|
excluded:
|
||||||
- ${PWD}/Pods
|
- Pods
|
||||||
- ${PWD}/xctemplates
|
- xctemplates
|
||||||
|
|
||||||
disabled_rules:
|
disabled_rules:
|
||||||
- notification_center_detachment
|
- notification_center_detachment
|
||||||
|
@ -37,7 +37,7 @@ opt_in_rules:
|
||||||
- legacy_random
|
- legacy_random
|
||||||
- literal_expression_end_indentation
|
- literal_expression_end_indentation
|
||||||
- multiline_arguments
|
- multiline_arguments
|
||||||
- multiline_argument_brackets
|
- multiline_arguments_brackets
|
||||||
- multiline_function_chains
|
- multiline_function_chains
|
||||||
- multiline_literal_brackets
|
- multiline_literal_brackets
|
||||||
- multiline_parameters
|
- multiline_parameters
|
||||||
|
@ -70,26 +70,26 @@ custom_rules:
|
||||||
severity: warning
|
severity: warning
|
||||||
|
|
||||||
string_concatenation:
|
string_concatenation:
|
||||||
included: ".*\.swift"
|
included: ".*\\.swift"
|
||||||
excluded: ".*Test\.swift"
|
excluded: ".*Test\\.swift"
|
||||||
name: "String Concatenation"
|
name: "String Concatenation"
|
||||||
regex: '' \+ "|" \+ |\+= "'
|
regex: " \\+ \"|\" \\+ |\\+= \""
|
||||||
message: "Please use string interpolation instead of concatenation"
|
message: "Please use string interpolation instead of concatenation"
|
||||||
severity: error
|
severity: error
|
||||||
|
|
||||||
print_function_usage:
|
print_function_usage:
|
||||||
included: ".*\.swift"
|
included: ".*\\.swift"
|
||||||
excluded: ".*Test\.swift"
|
excluded: ".*Test\\.swift"
|
||||||
name: "Swift print() or debugPrint() should not be used in App Code"
|
name: "Swift print() or debugPrint() should not be used in App Code"
|
||||||
regex: "print\(|debugPrint\("
|
regex: "print\\(|debugPrint\\("
|
||||||
message: "The Swift print() or debugPrint() functions should not be used."
|
message: "The Swift print() or debugPrint() functions should not be used."
|
||||||
severity: warning
|
severity: warning
|
||||||
|
|
||||||
nslog_function_usage:
|
nslog_function_usage:
|
||||||
included: ".*\.swift"
|
included: ".*\\.swift"
|
||||||
excluded: ".*Test\.swift"
|
excluded: ".*Test\\.swift"
|
||||||
name: "Swift NSLog() should not be used in App Code"
|
name: "Swift NSLog() should not be used in App Code"
|
||||||
regex: "NSLog\("
|
regex: "NSLog\\("
|
||||||
message: "The swift NSLog function should not be used."
|
message: "The swift NSLog function should not be used."
|
||||||
severity: error
|
severity: error
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ identifier_name:
|
||||||
- z
|
- z
|
||||||
|
|
||||||
indentation_width:
|
indentation_width:
|
||||||
indentation_width: 2
|
indentation_width: 4
|
||||||
|
|
||||||
line_length:
|
line_length:
|
||||||
warning: 150
|
warning: 150
|
||||||
|
@ -127,7 +127,7 @@ line_length:
|
||||||
|
|
||||||
file_length:
|
file_length:
|
||||||
warning: 600
|
warning: 600
|
||||||
ignore_comment_only_lines: false: true
|
ignore_comment_only_lines: true
|
||||||
|
|
||||||
multiline_arguments:
|
multiline_arguments:
|
||||||
first_argument_location: next_line
|
first_argument_location: next_line
|
||||||
|
@ -141,4 +141,4 @@ trailing_whitespace:
|
||||||
ignores_comments: true
|
ignores_comments: true
|
||||||
|
|
||||||
vertical_whitespace:
|
vertical_whitespace:
|
||||||
max_empty_lines: 2
|
max_empty_lines: 1
|
|
@ -385,6 +385,7 @@
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 0D4E7A2A26B364180058B01E /* Build configuration list for PBXNativeTarget "secant-testnet" */;
|
buildConfigurationList = 0D4E7A2A26B364180058B01E /* Build configuration list for PBXNativeTarget "secant-testnet" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
|
6696BA8726F0B1D200D5C875 /* SwiftLint */,
|
||||||
0D4E7A0126B364170058B01E /* Sources */,
|
0D4E7A0126B364170058B01E /* Sources */,
|
||||||
0D4E7A0226B364170058B01E /* Frameworks */,
|
0D4E7A0226B364170058B01E /* Frameworks */,
|
||||||
0D4E7A0326B364170058B01E /* Resources */,
|
0D4E7A0326B364170058B01E /* Resources */,
|
||||||
|
@ -503,6 +504,27 @@
|
||||||
};
|
};
|
||||||
/* End PBXResourcesBuildPhase section */
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXShellScriptBuildPhase section */
|
||||||
|
6696BA8726F0B1D200D5C875 /* SwiftLint */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
|
name = SwiftLint;
|
||||||
|
outputFileListPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "swiftlint_version=0.44.0\n\nif which swiftlint >/dev/null; then\n if [ $(swiftlint version) = $swiftlint_version ]; then\n swiftlint\n else\n echo \"warning: Compatible SwiftLint version not installed, download version $swiftlint_version from https://github.com/realm/SwiftLint. Currently installed version is $(swiftlint version)\"\n fi \nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n";
|
||||||
|
};
|
||||||
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
0D4E7A0126B364170058B01E /* Sources */ = {
|
0D4E7A0126B364170058B01E /* Sources */ = {
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
|
|
|
@ -10,6 +10,6 @@ import SwiftUI
|
||||||
|
|
||||||
public protocol Router: ObservableObject {
|
public protocol Router: ObservableObject {
|
||||||
associatedtype ViewOutput: View
|
associatedtype ViewOutput: View
|
||||||
|
|
||||||
func rootView() -> ViewOutput
|
func rootView() -> ViewOutput
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,9 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
open class BaseViewModel<S> {
|
open class BaseViewModel<S> {
|
||||||
|
|
||||||
public var services: S
|
public var services: S
|
||||||
|
|
||||||
public init(services: S) {
|
public init(services: S) {
|
||||||
self.services = services
|
self.services = services
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,30 +7,31 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
protocol KeyStoring {
|
protocol KeyStoring {
|
||||||
func importBirthday(_ height: BlockHeight) throws
|
func importBirthday(_ height: BlockHeight) throws
|
||||||
func exportBirthday() throws -> BlockHeight
|
func exportBirthday() throws -> BlockHeight
|
||||||
func importPhrase(bip39 phrase: String) throws
|
func importPhrase(bip39 phrase: String) throws
|
||||||
func exportPhrase() throws -> String
|
func exportPhrase() throws -> String
|
||||||
var keysPresent: Bool { get }
|
|
||||||
/**
|
/**
|
||||||
Use carefully: Deletes the seed phrase from the keychain
|
Use carefully: Deletes the seed phrase from the keychain
|
||||||
*/
|
*/
|
||||||
func nukePhrase()
|
func nukePhrase()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Use carefully: deletes the wallet birthday from the keychain
|
Use carefully: deletes the wallet birthday from the keychain
|
||||||
*/
|
*/
|
||||||
func nukeBirthday()
|
func nukeBirthday()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
There's no fate but what we make for ourselves - Sarah Connor
|
There's no fate but what we make for ourselves - Sarah Connor
|
||||||
*/
|
*/
|
||||||
func nukeWallet()
|
func nukeWallet()
|
||||||
|
|
||||||
|
var keysPresent: Bool { get }
|
||||||
}
|
}
|
||||||
|
|
||||||
enum KeyStoringError : Error {
|
enum KeyStoringError: Error {
|
||||||
case alreadyImported
|
case alreadyImported
|
||||||
case uninitializedWallet
|
case uninitializedWallet
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
enum MnemonicError: Error {
|
enum MnemonicError: Error {
|
||||||
case invalidSeed
|
case invalidSeed
|
||||||
case checksumFailed
|
case checksumFailed
|
||||||
|
@ -14,26 +15,27 @@ enum MnemonicError: Error {
|
||||||
|
|
||||||
protocol MnemonicSeedPhraseHandling {
|
protocol MnemonicSeedPhraseHandling {
|
||||||
/**
|
/**
|
||||||
random 24 words mnemonic phrase
|
Random 24 words mnemonic phrase
|
||||||
*/
|
*/
|
||||||
func randomMnemonic() throws -> String
|
func randomMnemonic() throws -> String
|
||||||
|
|
||||||
/**
|
/**
|
||||||
random 24 words mnemonic phrase as array of words
|
Random 24 words mnemonic phrase as array of words
|
||||||
*/
|
*/
|
||||||
func randomMnemonicWords() throws -> [String]
|
func randomMnemonicWords() throws -> [String]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
generate deterministic seed from mnemonic phrase
|
Generate deterministic seed from mnemonic phrase
|
||||||
*/
|
*/
|
||||||
func toSeed(mnemonic: String) throws -> [UInt8]
|
func toSeed(mnemonic: String) throws -> [UInt8]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
get this mnemonic
|
Get this mnemonic
|
||||||
*/
|
*/
|
||||||
func asWords(mnemonic: String) throws -> [String]
|
func asWords(mnemonic: String) throws -> [String]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
validates whether the given mnemonic is correct
|
Validates whether the given mnemonic is correct
|
||||||
*/
|
*/
|
||||||
func isValid(mnemonic: String) throws
|
func isValid(mnemonic: String) throws
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ protocol Services {
|
||||||
var keyStorage: KeyStoring { get }
|
var keyStorage: KeyStoring { get }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protocol ZcashNetworkProvider {
|
protocol ZcashNetworkProvider {
|
||||||
func currentNetwork() -> ZcashNetwork
|
func currentNetwork() -> ZcashNetwork
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,67 +6,92 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Funds Expressed in Zatoshis
|
Funds Expressed in Zatoshis
|
||||||
*/
|
*/
|
||||||
protocol Funds {
|
protocol Funds {
|
||||||
/**
|
/**
|
||||||
Confirmed, spendable funds
|
Confirmed, spendable funds
|
||||||
*/
|
*/
|
||||||
var confirmed: Int64 { get }
|
var confirmed: Int64 { get }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Unconfirmed, not yet spendable funds.
|
Unconfirmed, not yet spendable funds.
|
||||||
*/
|
*/
|
||||||
var unconfirmed: Int64 { get }
|
var unconfirmed: Int64 { get }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Represents a null value of Funds with Zero confirmed and Zero unconfirmed funds.
|
Represents a null value of Funds with Zero confirmed and Zero unconfirmed funds.
|
||||||
*/
|
*/
|
||||||
static var noFunds: Funds { get}
|
static var noFunds: Funds { get }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Wallet Balance that condenses transpant, Sapling and Orchard funds
|
Wallet Balance that condenses transpant, Sapling and Orchard funds
|
||||||
*/
|
*/
|
||||||
protocol WalletBalance {
|
protocol WalletBalance {
|
||||||
/**
|
/**
|
||||||
Transparent funds. This is the sum of the UTXOs of the user found at a given time
|
Transparent funds. This is the sum of the UTXOs of the user found at a given time
|
||||||
*/
|
*/
|
||||||
var transaparent: Funds { get }
|
var transaparent: Funds { get }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Funds on the Sapling shielded pool for a given user.
|
Funds on the Sapling shielded pool for a given user.
|
||||||
*/
|
*/
|
||||||
var sapling: Funds { get }
|
var sapling: Funds { get }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Funds on the Orchard shielded pool for a given user.
|
Funds on the Orchard shielded pool for a given user.
|
||||||
*/
|
*/
|
||||||
var orchard: Funds { get }
|
var orchard: Funds { get }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The sum of all confirmed funds, transparent, sapling and orchard funds (calculated)
|
The sum of all confirmed funds, transparent, sapling and orchard funds (calculated)
|
||||||
*/
|
*/
|
||||||
var totalAvailableBalance: Int64 { get }
|
var totalAvailableBalance: Int64 { get }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
the sum of all unconfirmed funds: transparent, sapling, and orchard funds (calculated
|
The sum of all unconfirmed funds: transparent, sapling, and orchard funds (calculated
|
||||||
*/
|
*/
|
||||||
var totalUnconfirmedBalance: Int64 { get }
|
var totalUnconfirmedBalance: Int64 { get }
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
the sum of all funds confirmed and unconfirmed of all pools (transparent, sapling and orchard).
|
The sum of all funds confirmed and unconfirmed of all pools (transparent, sapling and orchard).
|
||||||
*/
|
*/
|
||||||
var totalBalance: Int64 { get }
|
var totalBalance: Int64 { get }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
represents a the value of Zero funds.
|
Represents a the value of Zero funds.
|
||||||
*/
|
*/
|
||||||
static var nullBalance: WalletBalance { get }
|
static var nullBalance: WalletBalance { get }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension WalletBalance {
|
||||||
|
static var nullBalance: WalletBalance {
|
||||||
|
Balance(
|
||||||
|
transaparent: ZcashFunds.noFunds,
|
||||||
|
sapling: ZcashFunds.noFunds,
|
||||||
|
orchard: ZcashFunds.noFunds
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
var totalAvailableBalance: Int64 {
|
||||||
|
transaparent.confirmed + sapling.confirmed + orchard.confirmed
|
||||||
|
}
|
||||||
|
|
||||||
|
var totalUnconfirmedBalance: Int64 {
|
||||||
|
transaparent.unconfirmed + sapling.unconfirmed + orchard.unconfirmed
|
||||||
|
}
|
||||||
|
|
||||||
|
var totalBalance: Int64 {
|
||||||
|
totalAvailableBalance + totalUnconfirmedBalance
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Concrete Wallet Balance.
|
Concrete Wallet Balance.
|
||||||
*/
|
*/
|
||||||
struct Balance: WalletBalance {
|
struct Balance: WalletBalance {
|
||||||
var transaparent: Funds
|
var transaparent: Funds
|
||||||
var sapling: Funds
|
var sapling: Funds
|
||||||
|
@ -77,25 +102,7 @@ struct ZcashFunds: Funds {
|
||||||
static var noFunds: Funds {
|
static var noFunds: Funds {
|
||||||
ZcashFunds(confirmed: 0, unconfirmed: 0)
|
ZcashFunds(confirmed: 0, unconfirmed: 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
var confirmed: Int64
|
var confirmed: Int64
|
||||||
var unconfirmed: Int64
|
var unconfirmed: Int64
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
extension WalletBalance {
|
|
||||||
static var nullBalance: WalletBalance {
|
|
||||||
Balance(transaparent: ZcashFunds.noFunds, sapling: ZcashFunds.noFunds, orchard: ZcashFunds.noFunds)
|
|
||||||
}
|
|
||||||
|
|
||||||
var totalAvailableBalance: Int64 {
|
|
||||||
transaparent.confirmed + sapling.confirmed + orchard.confirmed
|
|
||||||
}
|
|
||||||
|
|
||||||
var totalUnconfirmedBalance: Int64 {
|
|
||||||
transaparent.unconfirmed + sapling.unconfirmed + orchard.unconfirmed
|
|
||||||
}
|
|
||||||
|
|
||||||
var totalBalance: Int64 {
|
|
||||||
totalAvailableBalance + totalUnconfirmedBalance
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,60 +15,40 @@ enum AppRouterScreen {
|
||||||
}
|
}
|
||||||
|
|
||||||
class AppRouter: Router {
|
class AppRouter: Router {
|
||||||
|
|
||||||
// MARK: - Published vars
|
|
||||||
@Published var screen: AppRouterScreen = .appLoading
|
@Published var screen: AppRouterScreen = .appLoading
|
||||||
|
|
||||||
// MARK: - Private vars
|
|
||||||
|
|
||||||
// MARK: - Internal vars
|
|
||||||
var services: Services
|
var services: Services
|
||||||
|
|
||||||
// MARK: - Initialization
|
|
||||||
|
|
||||||
init(services: Services) {
|
init(services: Services) {
|
||||||
self.services = services
|
self.services = services
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Methods
|
|
||||||
|
|
||||||
@ViewBuilder func rootView() -> some View {
|
@ViewBuilder func rootView() -> some View {
|
||||||
// Add your content here
|
// Add your content here
|
||||||
NavigationView {
|
NavigationView {
|
||||||
AppRouterView(router: self)
|
AppRouterView(router: self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder func createNew() -> some View {
|
@ViewBuilder func createNew() -> some View {
|
||||||
Text("Create New")
|
Text("Create New")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder func home() -> some View {
|
@ViewBuilder func home() -> some View {
|
||||||
Text("Home Screen")
|
Text("Home Screen")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder func loadingScreen() -> some View {
|
@ViewBuilder func loadingScreen() -> some View {
|
||||||
Text("Loading")
|
Text("Loading")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct AppRouterView: View {
|
struct AppRouterView: View {
|
||||||
@StateObject var router: AppRouter
|
@StateObject var router: AppRouter
|
||||||
|
|
||||||
@ViewBuilder func viewForScreen(_ screen: AppRouterScreen) -> some View {
|
|
||||||
switch self.router.screen {
|
|
||||||
case .appLoading:
|
|
||||||
self.router.loadingScreen()
|
|
||||||
case .createRestoreWallet:
|
|
||||||
self.router.createNew()
|
|
||||||
case .home:
|
|
||||||
self.router.home()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
viewForScreen(router.screen)
|
viewForScreen(router.screen)
|
||||||
.onAppear() {
|
.onAppear {
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
|
||||||
if router.services.keyStorage.keysPresent {
|
if router.services.keyStorage.keysPresent {
|
||||||
router.screen = .home
|
router.screen = .home
|
||||||
|
@ -78,4 +58,12 @@ struct AppRouterView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ViewBuilder func viewForScreen(_ screen: AppRouterScreen) -> some View {
|
||||||
|
switch router.screen {
|
||||||
|
case .appLoading: router.loadingScreen()
|
||||||
|
case .createRestoreWallet: router.createNew()
|
||||||
|
case .home: router.home()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,16 +7,15 @@
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
protocol BackupWalletScreenRouter: AnyObject {
|
protocol BackupWalletScreenRouter: AnyObject {}
|
||||||
}
|
|
||||||
|
|
||||||
struct BackupWalletScreen: View {
|
struct BackupWalletScreen: View {
|
||||||
@State var router: BackupWalletScreenRouter?
|
|
||||||
|
|
||||||
@ObservedObject var viewModel: BackupWalletScreenViewModel
|
@ObservedObject var viewModel: BackupWalletScreenViewModel
|
||||||
|
|
||||||
|
@State var router: BackupWalletScreenRouter?
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
|
Text("Hello, World!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,7 @@
|
||||||
// Created by Francisco Gindre on 8/9/21.
|
// Created by Francisco Gindre on 8/9/21.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import Combine
|
import Combine
|
||||||
|
import Foundation
|
||||||
|
|
||||||
class BackupWalletScreenViewModel: BaseViewModel<Services>, ObservableObject {
|
class BackupWalletScreenViewModel: BaseViewModel<Services>, ObservableObject {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,16 +7,15 @@
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
protocol BalanceScreenRouter: AnyObject {
|
protocol BalanceScreenRouter: AnyObject {}
|
||||||
}
|
|
||||||
|
|
||||||
struct BalanceScreen: View {
|
struct BalanceScreen: View {
|
||||||
@State var router: BalanceScreenRouter?
|
|
||||||
|
|
||||||
@ObservedObject var viewModel: BalanceScreenViewModel
|
@ObservedObject var viewModel: BalanceScreenViewModel
|
||||||
|
|
||||||
|
@State var router: BalanceScreenRouter?
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
|
Text("Hello, World!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,7 @@
|
||||||
// Created by Francisco Gindre on 8/12/21.
|
// Created by Francisco Gindre on 8/12/21.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import Combine
|
import Combine
|
||||||
|
import Foundation
|
||||||
|
|
||||||
class BalanceScreenViewModel: BaseViewModel<Services>, ObservableObject {
|
class BalanceScreenViewModel: BaseViewModel<Services>, ObservableObject {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,16 +7,15 @@
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
protocol HistoryScreenRouter: AnyObject {
|
protocol HistoryScreenRouter: AnyObject {}
|
||||||
}
|
|
||||||
|
|
||||||
struct HistoryScreen: View {
|
struct HistoryScreen: View {
|
||||||
@State var router: HistoryScreenRouter?
|
|
||||||
|
|
||||||
@ObservedObject var viewModel: HistoryScreenViewModel
|
@ObservedObject var viewModel: HistoryScreenViewModel
|
||||||
|
|
||||||
|
@State var router: HistoryScreenRouter?
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
|
Text("Hello, World!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,7 @@
|
||||||
// Created by Francisco Gindre on 8/12/21.
|
// Created by Francisco Gindre on 8/12/21.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import Combine
|
import Combine
|
||||||
|
import Foundation
|
||||||
|
|
||||||
class HistoryScreenViewModel: BaseViewModel<Services>, ObservableObject {
|
class HistoryScreenViewModel: BaseViewModel<Services>, ObservableObject {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -17,9 +17,9 @@ protocol HomeScreenRouter: AnyObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct HomeScreen: View {
|
struct HomeScreen: View {
|
||||||
@State var router: HomeScreenRouter?
|
|
||||||
|
|
||||||
@ObservedObject var viewModel: HomeScreenViewModel
|
@ObservedObject var viewModel: HomeScreenViewModel
|
||||||
|
|
||||||
|
@State var router: HomeScreenRouter?
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack {
|
||||||
|
@ -32,18 +32,18 @@ struct HomeScreen: View {
|
||||||
.navigationBarTitle("", displayMode: .inline)
|
.navigationBarTitle("", displayMode: .inline)
|
||||||
.navigationBarItems(
|
.navigationBarItems(
|
||||||
leading: qrCodeButton,
|
leading: qrCodeButton,
|
||||||
trailing: profileButton)
|
trailing: profileButton
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder var qrCodeButton: some View {
|
@ViewBuilder var qrCodeButton: some View {
|
||||||
Button(action: {}, label: {
|
Button(action: {}, label: {
|
||||||
Image(systemName: "qrcode.viewfinder")
|
Image(systemName: "qrcode.viewfinder")
|
||||||
.frame(width: 20, height: 20, alignment: /*@START_MENU_TOKEN@*/.center/*@END_MENU_TOKEN@*/)
|
.frame(width: 20, height: 20, alignment: .center)
|
||||||
})
|
})
|
||||||
.contentShape(Circle())
|
.contentShape(Circle())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder var profileButton: some View {
|
@ViewBuilder var profileButton: some View {
|
||||||
Button(action: {}, label: {
|
Button(action: {}, label: {
|
||||||
Image(systemName: "person.crop.circle")
|
Image(systemName: "person.crop.circle")
|
||||||
|
@ -51,21 +51,21 @@ struct HomeScreen: View {
|
||||||
})
|
})
|
||||||
.contentShape(Circle())
|
.contentShape(Circle())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder var requestButton: some View {
|
@ViewBuilder var requestButton: some View {
|
||||||
Button(action: {}, label: {
|
Button(action: {}, label: {
|
||||||
Text("Request ZEC")
|
Text("Request ZEC")
|
||||||
})
|
})
|
||||||
.buttonStyle(PlainButton())
|
.buttonStyle(PlainButton())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder var sendButton: some View {
|
@ViewBuilder var sendButton: some View {
|
||||||
Button(action: {}, label: {
|
Button(action: {}, label: {
|
||||||
Text("Send ZEC")
|
Text("Send ZEC")
|
||||||
})
|
})
|
||||||
.buttonStyle(PlainButton())
|
.buttonStyle(PlainButton())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder var historyButton: some View {
|
@ViewBuilder var historyButton: some View {
|
||||||
Button(action: {}, label: {
|
Button(action: {}, label: {
|
||||||
Text("History")
|
Text("History")
|
||||||
|
@ -74,14 +74,33 @@ struct HomeScreen: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Previews
|
||||||
|
|
||||||
struct HomeScreenPreviews: PreviewProvider {
|
struct HomeScreenPreviews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
NavigationView {
|
NavigationView {
|
||||||
HomeScreen(viewModel: HomeScreenViewModel.mockWithValues(services: MockServices(), status: .offline, balance: mockBalance, fiatConversion: 1.12453))
|
HomeScreen(
|
||||||
|
viewModel: HomeScreenViewModel.mockWithValues(
|
||||||
|
services: MockServices(),
|
||||||
|
status: .offline,
|
||||||
|
balance: mockBalance,
|
||||||
|
fiatConversion: 1.12453
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static var mockBalance: WalletBalance {
|
static var mockBalance: WalletBalance {
|
||||||
Balance(transaparent: ZcashFunds.noFunds, sapling: ZcashFunds(confirmed: 123456790, unconfirmed: 0), orchard: ZcashFunds(confirmed: 0, unconfirmed: 0))
|
Balance(
|
||||||
|
transaparent: ZcashFunds.noFunds,
|
||||||
|
sapling: ZcashFunds(
|
||||||
|
confirmed: 123456790,
|
||||||
|
unconfirmed: 0
|
||||||
|
),
|
||||||
|
orchard: ZcashFunds(
|
||||||
|
confirmed: 0,
|
||||||
|
unconfirmed: 0
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
// Created by Francisco Gindre on 8/9/21.
|
// Created by Francisco Gindre on 8/9/21.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import Combine
|
import Combine
|
||||||
|
import Foundation
|
||||||
|
|
||||||
class HomeScreenViewModel: BaseViewModel<Services>, ObservableObject {
|
class HomeScreenViewModel: BaseViewModel<Services>, ObservableObject {
|
||||||
enum Status {
|
enum Status {
|
||||||
|
@ -14,24 +14,24 @@ class HomeScreenViewModel: BaseViewModel<Services>, ObservableObject {
|
||||||
case offline
|
case offline
|
||||||
case error(error: Error)
|
case error(error: Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Published var balance: WalletBalance = Balance.nullBalance
|
@Published var balance: WalletBalance = Balance.nullBalance
|
||||||
|
|
||||||
@Published var fiatConversion: Decimal = 0
|
@Published var fiatConversion: Decimal = 0
|
||||||
|
|
||||||
@Published var status = Status.offline
|
@Published var status = Status.offline
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension HomeScreenViewModel {
|
extension HomeScreenViewModel {
|
||||||
static func mockWithValues(services: Services,
|
static func mockWithValues(
|
||||||
status: Status,
|
services: Services,
|
||||||
balance: WalletBalance,
|
status: Status,
|
||||||
fiatConversion: Decimal) -> HomeScreenViewModel {
|
balance: WalletBalance,
|
||||||
let vm = HomeScreenViewModel(services: services)
|
fiatConversion: Decimal
|
||||||
vm.status = status
|
) -> HomeScreenViewModel {
|
||||||
vm.balance = balance
|
let viewModel = HomeScreenViewModel(services: services)
|
||||||
vm.fiatConversion = fiatConversion
|
viewModel.status = status
|
||||||
return vm
|
viewModel.balance = balance
|
||||||
|
viewModel.fiatConversion = fiatConversion
|
||||||
|
|
||||||
|
return viewModel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,16 +7,15 @@
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
protocol ProfileScreenRouter: AnyObject {
|
protocol ProfileScreenRouter: AnyObject {}
|
||||||
}
|
|
||||||
|
|
||||||
struct ProfileScreen: View {
|
struct ProfileScreen: View {
|
||||||
@State var router: ProfileScreenRouter?
|
|
||||||
|
|
||||||
@ObservedObject var viewModel: ProfileScreenViewModel
|
@ObservedObject var viewModel: ProfileScreenViewModel
|
||||||
|
|
||||||
|
@State var router: ProfileScreenRouter?
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
|
Text("Hello, World!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,7 @@
|
||||||
// Created by Francisco Gindre on 8/12/21.
|
// Created by Francisco Gindre on 8/12/21.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import Combine
|
import Combine
|
||||||
|
import Foundation
|
||||||
|
|
||||||
class ProfileScreenViewModel: BaseViewModel<Services>, ObservableObject {
|
class ProfileScreenViewModel: BaseViewModel<Services>, ObservableObject {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,16 +7,15 @@
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
protocol RequestZcashScreenRouter: AnyObject {
|
protocol RequestZcashScreenRouter: AnyObject {}
|
||||||
}
|
|
||||||
|
|
||||||
struct RequestZcashScreen: View {
|
struct RequestZcashScreen: View {
|
||||||
@State var router: RequestZcashScreenRouter?
|
|
||||||
|
|
||||||
@ObservedObject var viewModel: RequestZcashScreenViewModel
|
@ObservedObject var viewModel: RequestZcashScreenViewModel
|
||||||
|
|
||||||
|
@State var router: RequestZcashScreenRouter?
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
|
Text("Hello, World!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,7 @@
|
||||||
// Created by Francisco Gindre on 8/12/21.
|
// Created by Francisco Gindre on 8/12/21.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import Combine
|
import Combine
|
||||||
|
import Foundation
|
||||||
|
|
||||||
class RequestZcashScreenViewModel: BaseViewModel<Services>, ObservableObject {
|
class RequestZcashScreenViewModel: BaseViewModel<Services>, ObservableObject {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,20 +7,19 @@
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
protocol RestoreWalletScreenRouter: AnyObject {
|
protocol RestoreWalletScreenRouter: AnyObject {}
|
||||||
}
|
|
||||||
|
|
||||||
struct RestoreWalletScreen: View {
|
struct RestoreWalletScreen: View {
|
||||||
@State var router: RestoreWalletScreenRouter?
|
|
||||||
|
|
||||||
@ObservedObject var viewModel: RestoreWalletScreenViewModel
|
@ObservedObject var viewModel: RestoreWalletScreenViewModel
|
||||||
|
|
||||||
|
@State var router: RestoreWalletScreenRouter?
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack {
|
||||||
Text("Enter Seed Phrase")
|
Text("Enter Seed Phrase")
|
||||||
|
|
||||||
TextEditor(text: $viewModel.seedText)
|
TextEditor(text: $viewModel.seedText)
|
||||||
|
|
||||||
Button(action: {}, label: {
|
Button(action: {}, label: {
|
||||||
Text("Restore Seed Phrase")
|
Text("Restore Seed Phrase")
|
||||||
})
|
})
|
||||||
|
|
|
@ -5,12 +5,11 @@
|
||||||
// Created by Francisco Gindre on 8/9/21.
|
// Created by Francisco Gindre on 8/9/21.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import Combine
|
import Combine
|
||||||
|
import Foundation
|
||||||
|
|
||||||
class RestoreWalletScreenViewModel: BaseViewModel<Services>, ObservableObject {
|
class RestoreWalletScreenViewModel: BaseViewModel<Services>, ObservableObject {
|
||||||
|
|
||||||
@Published var seedText: String = ""
|
@Published var seedText: String = ""
|
||||||
|
|
||||||
func restore() {}
|
func restore() {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,16 +7,15 @@
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
protocol ScanQrScreenRouter: AnyObject {
|
protocol ScanQrScreenRouter: AnyObject {}
|
||||||
}
|
|
||||||
|
|
||||||
struct ScanQrScreen: View {
|
struct ScanQrScreen: View {
|
||||||
@State var router: ScanQrScreenRouter?
|
|
||||||
|
|
||||||
@ObservedObject var viewModel: ScanQrScreenViewModel
|
@ObservedObject var viewModel: ScanQrScreenViewModel
|
||||||
|
|
||||||
|
@State var router: ScanQrScreenRouter?
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
|
Text("Hello, World!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,7 @@
|
||||||
// Created by Francisco Gindre on 8/12/21.
|
// Created by Francisco Gindre on 8/12/21.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import Combine
|
import Combine
|
||||||
|
import Foundation
|
||||||
|
|
||||||
class ScanQrScreenViewModel: BaseViewModel<Services>, ObservableObject {
|
class ScanQrScreenViewModel: BaseViewModel<Services>, ObservableObject {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,16 +7,15 @@
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
protocol SendScreenRouter: AnyObject {
|
protocol SendScreenRouter: AnyObject {}
|
||||||
}
|
|
||||||
|
|
||||||
struct SendScreen: View {
|
struct SendScreen: View {
|
||||||
@State var router: SendScreenRouter?
|
|
||||||
|
|
||||||
@ObservedObject var viewModel: SendScreenViewModel
|
@ObservedObject var viewModel: SendScreenViewModel
|
||||||
|
|
||||||
|
@State var router: SendScreenRouter?
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
|
Text("Hello, World!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,7 @@
|
||||||
// Created by Francisco Gindre on 8/12/21.
|
// Created by Francisco Gindre on 8/12/21.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import Combine
|
import Combine
|
||||||
|
import Foundation
|
||||||
|
|
||||||
class SendScreenViewModel: BaseViewModel<Services>, ObservableObject {
|
class SendScreenViewModel: BaseViewModel<Services>, ObservableObject {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,22 +7,21 @@
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
protocol WelcomeScreenRouter: AnyObject {
|
protocol WelcomeScreenRouter: AnyObject {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
struct WelcomeScreen: View {
|
struct WelcomeScreen: View {
|
||||||
@State var router: WelcomeScreenRouter?
|
|
||||||
|
|
||||||
@ObservedObject var viewModel: WelcomeScreenViewModel
|
@ObservedObject var viewModel: WelcomeScreenViewModel
|
||||||
|
|
||||||
|
@State var router: WelcomeScreenRouter?
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack {
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
Text("Welcome and Onboarding")
|
Text("Welcome and Onboarding")
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
VStack(alignment: .center, spacing: 16) {
|
VStack(alignment: .center, spacing: 16) {
|
||||||
Button(action: {
|
Button(action: {
|
||||||
self.viewModel.restoreWallet()
|
self.viewModel.restoreWallet()
|
||||||
|
@ -30,7 +29,7 @@ struct WelcomeScreen: View {
|
||||||
Text("RESTORE WALLET")
|
Text("RESTORE WALLET")
|
||||||
})
|
})
|
||||||
.buttonStyle(PlainButton())
|
.buttonStyle(PlainButton())
|
||||||
|
|
||||||
Button(action: {
|
Button(action: {
|
||||||
self.viewModel.createNew()
|
self.viewModel.createNew()
|
||||||
}, label: {
|
}, label: {
|
||||||
|
|
|
@ -5,11 +5,10 @@
|
||||||
// Created by Francisco Gindre on 8/9/21.
|
// Created by Francisco Gindre on 8/9/21.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import Combine
|
import Combine
|
||||||
|
import Foundation
|
||||||
|
|
||||||
class WelcomeScreenViewModel: BaseViewModel<Services>, ObservableObject {
|
class WelcomeScreenViewModel: BaseViewModel<Services>, ObservableObject {
|
||||||
|
|
||||||
func createNew() {}
|
func createNew() {}
|
||||||
func restoreWallet() {}
|
func restoreWallet() {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,8 @@ import SwiftUI
|
||||||
|
|
||||||
@main
|
@main
|
||||||
struct SecantApp: App {
|
struct SecantApp: App {
|
||||||
|
|
||||||
@StateObject var appRouter = AppRouter(services: MockServices())
|
@StateObject var appRouter = AppRouter(services: MockServices())
|
||||||
|
|
||||||
var body: some Scene {
|
var body: some Scene {
|
||||||
WindowGroup {
|
WindowGroup {
|
||||||
appRouter.rootView()
|
appRouter.rootView()
|
||||||
|
|
|
@ -7,18 +7,21 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
// swiftlint:disable line_length
|
||||||
class MockServices: Services {
|
class MockServices: Services {
|
||||||
init(){}
|
|
||||||
var networkProvider: ZcashNetworkProvider {
|
var networkProvider: ZcashNetworkProvider {
|
||||||
MockNetworkProvider()
|
MockNetworkProvider()
|
||||||
}
|
}
|
||||||
|
|
||||||
var seedHandler: MnemonicSeedPhraseHandling {
|
var seedHandler: MnemonicSeedPhraseHandling {
|
||||||
MockMnemonicPhraseHandling()
|
MockMnemonicPhraseHandling()
|
||||||
}
|
}
|
||||||
|
|
||||||
var keyStorage: KeyStoring {
|
var keyStorage: KeyStoring {
|
||||||
MockKeyStoring()
|
MockKeyStoring()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
init() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MockNetworkProvider: ZcashNetworkProvider {
|
class MockNetworkProvider: ZcashNetworkProvider {
|
||||||
|
@ -28,87 +31,90 @@ class MockNetworkProvider: ZcashNetworkProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
class MockMnemonicPhraseHandling: MnemonicSeedPhraseHandling {
|
class MockMnemonicPhraseHandling: MnemonicSeedPhraseHandling {
|
||||||
|
|
||||||
class TestSeed {
|
class TestSeed {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
test account: "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread"
|
Test account: "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread"
|
||||||
*/
|
*/
|
||||||
let seedString = Data(base64Encoded: "9VDVOZZZOWWHpZtq1Ebridp3Qeux5C+HwiRR0g7Oi7HgnMs8Gfln83+/Q1NnvClcaSwM4ADFL1uZHxypEWlWXg==")!
|
let seedString = Data(
|
||||||
|
base64Encoded: "9VDVOZZZOWWHpZtq1Ebridp3Qeux5C+HwiRR0g7Oi7HgnMs8Gfln83+/Q1NnvClcaSwM4ADFL1uZHxypEWlWXg=="
|
||||||
|
)!// swiftlint:disable:this force_unwrapping
|
||||||
|
|
||||||
func seed() -> [UInt8] {
|
func seed() -> [UInt8] {
|
||||||
[UInt8](seedString)
|
[UInt8](seedString)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func randomMnemonic() throws -> String {
|
func randomMnemonic() throws -> String {
|
||||||
"still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread"
|
"still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread"
|
||||||
}
|
}
|
||||||
|
|
||||||
func randomMnemonicWords() throws -> [String] {
|
func randomMnemonicWords() throws -> [String] {
|
||||||
"still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread".components(separatedBy: " ")
|
"still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread"
|
||||||
|
.components(separatedBy: " ")
|
||||||
}
|
}
|
||||||
|
|
||||||
func toSeed(mnemonic: String) throws -> [UInt8] {
|
func toSeed(mnemonic: String) throws -> [UInt8] {
|
||||||
TestSeed().seed()
|
TestSeed().seed()
|
||||||
}
|
}
|
||||||
|
|
||||||
func asWords(mnemonic: String) throws -> [String] {
|
func asWords(mnemonic: String) throws -> [String] {
|
||||||
"still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread".components(separatedBy: " ")
|
"still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread"
|
||||||
|
.components(separatedBy: " ")
|
||||||
}
|
}
|
||||||
|
|
||||||
func isValid(mnemonic: String) throws {}
|
func isValid(mnemonic: String) throws {}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class MockKeyStoring: KeyStoring {
|
class MockKeyStoring: KeyStoring {
|
||||||
var birthday: BlockHeight?
|
var birthday: BlockHeight?
|
||||||
var phrase: String?
|
var phrase: String?
|
||||||
|
|
||||||
func importBirthday(_ height: BlockHeight) throws {
|
func importBirthday(_ height: BlockHeight) throws {
|
||||||
guard birthday == nil else {
|
guard birthday == nil else {
|
||||||
throw KeyStoringError.alreadyImported
|
throw KeyStoringError.alreadyImported
|
||||||
}
|
}
|
||||||
|
|
||||||
birthday = height
|
birthday = height
|
||||||
}
|
}
|
||||||
|
|
||||||
func exportBirthday() throws -> BlockHeight {
|
func exportBirthday() throws -> BlockHeight {
|
||||||
guard let b = birthday else {
|
guard let birthday = birthday else {
|
||||||
throw KeyStoringError.uninitializedWallet
|
throw KeyStoringError.uninitializedWallet
|
||||||
}
|
}
|
||||||
return b
|
|
||||||
|
return birthday
|
||||||
}
|
}
|
||||||
|
|
||||||
func importPhrase(bip39 phrase: String) throws {
|
func importPhrase(bip39 phrase: String) throws {
|
||||||
guard self.phrase == nil else {
|
guard self.phrase == nil else {
|
||||||
throw KeyStoringError.alreadyImported
|
throw KeyStoringError.alreadyImported
|
||||||
}
|
}
|
||||||
|
|
||||||
self.phrase = phrase
|
self.phrase = phrase
|
||||||
}
|
}
|
||||||
|
|
||||||
func exportPhrase() throws -> String {
|
func exportPhrase() throws -> String {
|
||||||
guard let p = self.phrase else {
|
guard let phrase = self.phrase else {
|
||||||
throw KeyStoringError.uninitializedWallet
|
throw KeyStoringError.uninitializedWallet
|
||||||
}
|
}
|
||||||
return p
|
|
||||||
|
return phrase
|
||||||
}
|
}
|
||||||
|
|
||||||
var keysPresent: Bool {
|
var keysPresent: Bool {
|
||||||
return self.phrase != nil && self.birthday != nil
|
return self.phrase != nil && self.birthday != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func nukePhrase() {
|
func nukePhrase() {
|
||||||
self.phrase = nil
|
self.phrase = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func nukeBirthday() {
|
func nukeBirthday() {
|
||||||
self.birthday = nil
|
self.birthday = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func nukeWallet() {
|
func nukeWallet() {
|
||||||
nukePhrase()
|
nukePhrase()
|
||||||
nukeBirthday()
|
nukeBirthday()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,9 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public typealias BlockHeight = Int
|
public typealias BlockHeight = Int
|
||||||
|
|
||||||
public protocol ZcashNetwork {
|
public protocol ZcashNetwork {
|
||||||
var networkType: NetworkType { get }
|
var networkType: NetworkType { get }
|
||||||
var constants: NetworkConstants.Type { get }
|
var constants: NetworkConstants.Type { get }
|
||||||
|
@ -15,13 +17,11 @@ public protocol ZcashNetwork {
|
||||||
public enum NetworkType {
|
public enum NetworkType {
|
||||||
case mainnet
|
case mainnet
|
||||||
case testnet
|
case testnet
|
||||||
|
|
||||||
var networkId: UInt32 {
|
var networkId: UInt32 {
|
||||||
switch self {
|
switch self {
|
||||||
case .mainnet:
|
case .mainnet: return 1
|
||||||
return 1
|
case .testnet: return 0
|
||||||
case .testnet:
|
|
||||||
return 0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,23 +29,18 @@ public enum NetworkType {
|
||||||
extension NetworkType {
|
extension NetworkType {
|
||||||
static func forChainName(_ chainame: String) -> NetworkType? {
|
static func forChainName(_ chainame: String) -> NetworkType? {
|
||||||
switch chainame {
|
switch chainame {
|
||||||
case "test":
|
case "test": return .testnet
|
||||||
return .testnet
|
case "main": return .mainnet
|
||||||
case "main":
|
default: return nil
|
||||||
return .mainnet
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ZcashNetworkBuilder {
|
public enum ZcashNetworkBuilder {
|
||||||
public static func network(for networkType: NetworkType) -> ZcashNetwork {
|
public static func network(for networkType: NetworkType) -> ZcashNetwork {
|
||||||
switch networkType {
|
switch networkType {
|
||||||
case .mainnet:
|
case .mainnet: return ZcashMainnet()
|
||||||
return ZcashMainnet()
|
case .testnet: return ZcashTestnet()
|
||||||
case .testnet:
|
|
||||||
return ZcashTestnet()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,182 +56,182 @@ class ZcashMainnet: ZcashNetwork {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Constants of ZcashLightClientKit. this constants don't
|
Constants of ZcashLightClientKit.
|
||||||
*/
|
*/
|
||||||
public class ZcashSDK {
|
public enum ZcashSDK {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The number of zatoshi that equal 1 ZEC.
|
The number of zatoshi that equal 1 ZEC.
|
||||||
*/
|
*/
|
||||||
public static var ZATOSHI_PER_ZEC: BlockHeight = 100_000_000
|
public static var zatoshiPerZEC: BlockHeight = 100_000_000
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The theoretical maximum number of blocks in a reorg, due to other bottlenecks in the protocol design.
|
The theoretical maximum number of blocks in a reorg, due to other bottlenecks in the protocol design.
|
||||||
*/
|
*/
|
||||||
public static var MAX_REORG_SIZE = 100
|
public static var maxReorgSize = 100
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The amount of blocks ahead of the current height where new transactions are set to expire. This value is controlled
|
The amount of blocks ahead of the current height where new transactions are set to expire. This value is controlled by the rust backend but it is helpful to know what it is set to and should be kept in sync.
|
||||||
by the rust backend but it is helpful to know what it is set to and should be kept in sync.
|
*/
|
||||||
*/
|
public static var expiryOffset = 20
|
||||||
public static var EXPIRY_OFFSET = 20
|
|
||||||
//
|
//
|
||||||
// Defaults
|
// Defaults
|
||||||
//
|
//
|
||||||
/**
|
/**
|
||||||
Default size of batches of blocks to request from the compact block service.
|
Default size of batches of blocks to request from the compact block service.
|
||||||
*/
|
*/
|
||||||
public static var DEFAULT_BATCH_SIZE = 100
|
public static var defaultBatchSize = 100
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Default amount of time, in in seconds, to poll for new blocks. Typically, this should be about half the average
|
Default amount of time, in in seconds, to poll for new blocks. Typically, this should be about half the average block time.
|
||||||
block time.
|
*/
|
||||||
*/
|
public static var defaultPollInterval: TimeInterval = 20
|
||||||
public static var DEFAULT_POLL_INTERVAL: TimeInterval = 20
|
|
||||||
/**
|
/**
|
||||||
Default attempts at retrying.
|
Default attempts at retrying.
|
||||||
*/
|
*/
|
||||||
public static var DEFAULT_RETRIES: Int = 5
|
public static var defaultRetrie: Int = 5
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The default maximum amount of time to wait during retry backoff intervals. Failed loops will never wait longer than
|
The default maximum amount of time to wait during retry backoff intervals. Failed loops will never wait longer than this before retyring.
|
||||||
this before retyring.
|
*/
|
||||||
*/
|
public static var defaultMaxBackoffInterval: TimeInterval = 600
|
||||||
public static var DEFAULT_MAX_BACKOFF_INTERVAL: TimeInterval = 600
|
|
||||||
/**
|
/**
|
||||||
Default number of blocks to rewind when a chain reorg is detected. This should be large enough to recover from the
|
Default number of blocks to rewind when a chain reorg is detected. This should be large enough to recover from the reorg but smaller than the theoretical max reorg size of 100.
|
||||||
reorg but smaller than the theoretical max reorg size of 100.
|
*/
|
||||||
*/
|
public static var defaultRewindDistance: Int = 10
|
||||||
public static var DEFAULT_REWIND_DISTANCE: Int = 10
|
|
||||||
/**
|
/**
|
||||||
The number of blocks to allow before considering our data to be stale. This usually helps with what to do when
|
The number of blocks to allow before considering our data to be stale. This usually helps with what to do when returning from the background and is exposed via the Synchronizer's isStale function.
|
||||||
returning from the background and is exposed via the Synchronizer's isStale function.
|
*/
|
||||||
*/
|
public static var defaultStaleTolerance: Int = 10
|
||||||
public static var DEFAULT_STALE_TOLERANCE: Int = 10
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Default Name for LibRustZcash data.db
|
Default Name for LibRustZcash data.db
|
||||||
*/
|
*/
|
||||||
public static var DEFAULT_DATA_DB_NAME = "data.db"
|
public static var defaultDataDbName = "data.db"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Default Name for Compact Block caches db
|
Default Name for Compact Block caches db
|
||||||
*/
|
*/
|
||||||
public static var DEFAULT_CACHES_DB_NAME = "caches.db"
|
public static var defaultCachesDbName = "caches.db"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Default name for pending transactions db
|
Default name for pending transactions db
|
||||||
*/
|
*/
|
||||||
public static var DEFAULT_PENDING_DB_NAME = "pending.db"
|
public static var defaultPendingDbName = "pending.db"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
File name for the sapling spend params
|
File name for the sapling spend params
|
||||||
*/
|
*/
|
||||||
public static var SPEND_PARAM_FILE_NAME = "sapling-spend.params"
|
public static var spendParamFileName = "sapling-spend.params"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
File name for the sapling output params
|
File name for the sapling output params
|
||||||
*/
|
*/
|
||||||
public static var OUTPUT_PARAM_FILE_NAME = "sapling-output.params"
|
public static var outputParamFileName = "sapling-output.params"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The Url that is used by default in zcashd.
|
The Url that is used by default in zcashd. We'll want to make this externally configurable, rather than baking it into the SDK but this will do for now, since we're using a cloudfront URL that already redirects.
|
||||||
We'll want to make this externally configurable, rather than baking it into the SDK but
|
*/
|
||||||
this will do for now, since we're using a cloudfront URL that already redirects.
|
public static var cloudParamDirURL = "https://z.cash/downloads/"
|
||||||
*/
|
|
||||||
public static var CLOUD_PARAM_DIR_URL = "https://z.cash/downloads/"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public protocol NetworkConstants {
|
public protocol NetworkConstants {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The height of the first sapling block. When it comes to shielded transactions, we do not need to consider any blocks
|
The height of the first sapling block. When it comes to shielded transactions, we do not need to consider any block prior to this height, at all.
|
||||||
prior to this height, at all.
|
*/
|
||||||
*/
|
static var saplingActivationHeight: BlockHeight { get }
|
||||||
static var SAPLING_ACTIVATION_HEIGHT: BlockHeight { get }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Default Name for LibRustZcash data.db
|
Default Name for LibRustZcash data.db
|
||||||
*/
|
*/
|
||||||
static var DEFAULT_DATA_DB_NAME: String { get }
|
static var defaultDataDbName: String { get }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Default Name for Compact Block caches db
|
Default Name for Compact Block caches db
|
||||||
*/
|
*/
|
||||||
static var DEFAULT_CACHES_DB_NAME: String { get }
|
static var defaultCachesDbName: String { get }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Default name for pending transactions db
|
Default name for pending transactions db
|
||||||
*/
|
*/
|
||||||
static var DEFAULT_PENDING_DB_NAME: String { get }
|
static var defaultPendingDbName: String { get }
|
||||||
static var DEFAULT_DB_NAME_PREFIX: String { get }
|
|
||||||
|
static var defaultDbNamePrefix: String { get }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
fixed height where the SDK considers that the ZIP-321 was deployed. This is a workaround
|
Fixed height where the SDK considers that the ZIP-321 was deployed. This is a workaround for librustzcash not figuring out the tx fee from the tx itself.
|
||||||
for librustzcash not figuring out the tx fee from the tx itself.
|
*/
|
||||||
*/
|
static var feeChangeHeight: BlockHeight { get }
|
||||||
static var FEE_CHANGE_HEIGHT: BlockHeight { get }
|
|
||||||
|
|
||||||
static func defaultFee(for height: BlockHeight) -> Int64
|
static func defaultFee(for height: BlockHeight) -> Int64
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension NetworkConstants {
|
public extension NetworkConstants {
|
||||||
|
|
||||||
static func defaultFee(for height: BlockHeight = BlockHeight.max) -> Int64 {
|
static func defaultFee(for height: BlockHeight = BlockHeight.max) -> Int64 {
|
||||||
guard height >= FEE_CHANGE_HEIGHT else { return 10_000 }
|
guard height >= feeChangeHeight else { return 10_000 }
|
||||||
|
|
||||||
return 1_000
|
return 1_000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ZcashSDKMainnetConstants: NetworkConstants {
|
public class ZcashSDKMainnetConstants: NetworkConstants {
|
||||||
|
/**
|
||||||
|
The height of the first sapling block. When it comes to shielded transactions, we do not need to consider any blocks prior to this height, at all.
|
||||||
|
*/
|
||||||
|
public static var saplingActivationHeight: BlockHeight = 419_200
|
||||||
|
|
||||||
|
/**
|
||||||
|
Default Name for LibRustZcash data.db
|
||||||
|
*/
|
||||||
|
public static var defaultDataDbName = "data.db"
|
||||||
|
|
||||||
|
/**
|
||||||
|
Default Name for Compact Block caches db
|
||||||
|
*/
|
||||||
|
public static var defaultCachesDbName = "caches.db"
|
||||||
|
|
||||||
|
/**
|
||||||
|
Default name for pending transactions db
|
||||||
|
*/
|
||||||
|
public static var defaultPendingDbName = "pending.db"
|
||||||
|
|
||||||
|
public static var defaultDbNamePrefix = "ZcashSdk_mainnet_"
|
||||||
|
|
||||||
|
public static var feeChangeHeight: BlockHeight = 1_077_550
|
||||||
|
|
||||||
private init() {}
|
private init() {}
|
||||||
|
|
||||||
/**
|
|
||||||
The height of the first sapling block. When it comes to shielded transactions, we do not need to consider any blocks
|
|
||||||
prior to this height, at all.
|
|
||||||
*/
|
|
||||||
public static var SAPLING_ACTIVATION_HEIGHT: BlockHeight = 419_200
|
|
||||||
|
|
||||||
/**
|
|
||||||
Default Name for LibRustZcash data.db
|
|
||||||
*/
|
|
||||||
public static var DEFAULT_DATA_DB_NAME = "data.db"
|
|
||||||
/**
|
|
||||||
Default Name for Compact Block caches db
|
|
||||||
*/
|
|
||||||
public static var DEFAULT_CACHES_DB_NAME = "caches.db"
|
|
||||||
/**
|
|
||||||
Default name for pending transactions db
|
|
||||||
*/
|
|
||||||
public static var DEFAULT_PENDING_DB_NAME = "pending.db"
|
|
||||||
|
|
||||||
public static var DEFAULT_DB_NAME_PREFIX = "ZcashSdk_mainnet_"
|
|
||||||
|
|
||||||
public static var FEE_CHANGE_HEIGHT: BlockHeight = 1_077_550
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ZcashSDKTestnetConstants: NetworkConstants {
|
public class ZcashSDKTestnetConstants: NetworkConstants {
|
||||||
|
/**
|
||||||
|
The height of the first sapling block. When it comes to shielded transactions, we do not need to consider any blocks prior to this height, at all.
|
||||||
|
*/
|
||||||
|
public static var saplingActivationHeight: BlockHeight = 280_000
|
||||||
|
|
||||||
|
/**
|
||||||
|
Default Name for LibRustZcash data.db
|
||||||
|
*/
|
||||||
|
public static var defaultDataDbName = "data.db"
|
||||||
|
|
||||||
|
/**
|
||||||
|
Default Name for Compact Block caches db
|
||||||
|
*/
|
||||||
|
public static var defaultCachesDbName = "caches.db"
|
||||||
|
|
||||||
|
/**
|
||||||
|
Default name for pending transactions db
|
||||||
|
*/
|
||||||
|
public static var defaultPendingDbName = "pending.db"
|
||||||
|
|
||||||
|
public static var defaultDbNamePrefix = "ZcashSdk_testnet_"
|
||||||
|
|
||||||
|
/**
|
||||||
|
Estimated height where wallets are supposed to change the fee
|
||||||
|
*/
|
||||||
|
public static var feeChangeHeight: BlockHeight = 1_028_500
|
||||||
|
|
||||||
private init() {}
|
private init() {}
|
||||||
|
|
||||||
/**
|
|
||||||
The height of the first sapling block. When it comes to shielded transactions, we do not need to consider any blocks
|
|
||||||
prior to this height, at all.
|
|
||||||
*/
|
|
||||||
public static var SAPLING_ACTIVATION_HEIGHT: BlockHeight = 280_000
|
|
||||||
|
|
||||||
/**
|
|
||||||
Default Name for LibRustZcash data.db
|
|
||||||
*/
|
|
||||||
public static var DEFAULT_DATA_DB_NAME = "data.db"
|
|
||||||
/**
|
|
||||||
Default Name for Compact Block caches db
|
|
||||||
*/
|
|
||||||
public static var DEFAULT_CACHES_DB_NAME = "caches.db"
|
|
||||||
/**
|
|
||||||
Default name for pending transactions db
|
|
||||||
*/
|
|
||||||
public static var DEFAULT_PENDING_DB_NAME = "pending.db"
|
|
||||||
|
|
||||||
public static var DEFAULT_DB_NAME_PREFIX = "ZcashSdk_testnet_"
|
|
||||||
|
|
||||||
/**
|
|
||||||
Estimated height where wallets are supposed to change the fee
|
|
||||||
*/
|
|
||||||
public static var FEE_CHANGE_HEIGHT: BlockHeight = 1_028_500
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,9 +12,9 @@ struct PlainButton: ButtonStyle {
|
||||||
case light
|
case light
|
||||||
case bold
|
case bold
|
||||||
}
|
}
|
||||||
|
|
||||||
var style = Theme.bold
|
var style = Theme.bold
|
||||||
|
|
||||||
func makeBody(configuration: Configuration) -> some View {
|
func makeBody(configuration: Configuration) -> some View {
|
||||||
configuration.label
|
configuration.label
|
||||||
.foregroundColor(style.foregroundColor)
|
.foregroundColor(style.foregroundColor)
|
||||||
|
@ -24,16 +24,18 @@ struct PlainButton: ButtonStyle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Previews
|
||||||
|
|
||||||
struct PlainButton_Previews: PreviewProvider {
|
struct PlainButton_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
VStack {
|
VStack {
|
||||||
Button(action: /*@START_MENU_TOKEN@*/{}/*@END_MENU_TOKEN@*/, label: {
|
Button(action: {}, label: {
|
||||||
/*@START_MENU_TOKEN@*/Text("Button")/*@END_MENU_TOKEN@*/
|
Text("Button")
|
||||||
})
|
})
|
||||||
.buttonStyle(PlainButton())
|
.buttonStyle(PlainButton())
|
||||||
|
|
||||||
Button(action: /*@START_MENU_TOKEN@*/{}/*@END_MENU_TOKEN@*/, label: {
|
Button(action: {}, label: {
|
||||||
/*@START_MENU_TOKEN@*/Text("Button")/*@END_MENU_TOKEN@*/
|
Text("Button")
|
||||||
})
|
})
|
||||||
.buttonStyle(PlainButton(style: .bold))
|
.buttonStyle(PlainButton(style: .bold))
|
||||||
}
|
}
|
||||||
|
@ -41,22 +43,20 @@ struct PlainButton_Previews: PreviewProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Theme
|
||||||
|
|
||||||
extension PlainButton.Theme {
|
extension PlainButton.Theme {
|
||||||
var background: some View {
|
var background: some View {
|
||||||
switch self {
|
switch self {
|
||||||
case .bold:
|
case .bold: return Color.black
|
||||||
return Color.black
|
default: return Color.white
|
||||||
default:
|
|
||||||
return Color.white
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var foregroundColor: Color {
|
var foregroundColor: Color {
|
||||||
switch self {
|
switch self {
|
||||||
case .bold:
|
case .bold: return Color.white
|
||||||
return Color.white
|
default: return Color.black
|
||||||
default:
|
|
||||||
return Color.black
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
|
|
||||||
extension Font {
|
extension Font {
|
||||||
static func zboto(_ size: CGFloat) -> Font {
|
static func zboto(_ size: CGFloat) -> Font {
|
||||||
Font.custom("Zboto", size: size)
|
Font.custom("Zboto", size: size)
|
||||||
|
|
|
@ -8,13 +8,14 @@
|
||||||
import XCTest
|
import XCTest
|
||||||
@testable import secant_testnet
|
@testable import secant_testnet
|
||||||
|
|
||||||
class secantTests: XCTestCase {
|
class SecantTests: XCTestCase {
|
||||||
|
override func setUp() {
|
||||||
override func setUpWithError() throws {
|
super.setUp()
|
||||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDownWithError() throws {
|
override func tearDown() {
|
||||||
|
super.tearDown()
|
||||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,5 +30,4 @@ class secantTests: XCTestCase {
|
||||||
// Put the code you want to measure the time of here.
|
// Put the code you want to measure the time of here.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,18 +7,21 @@
|
||||||
|
|
||||||
import XCTest
|
import XCTest
|
||||||
|
|
||||||
class secantUITests: XCTestCase {
|
class SecantUITests: XCTestCase {
|
||||||
|
override func setUp() {
|
||||||
override func setUpWithError() throws {
|
super.setUp()
|
||||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||||
|
|
||||||
// In UI tests it is usually best to stop immediately when a failure occurs.
|
// In UI tests it is usually best to stop immediately when a failure occurs.
|
||||||
continueAfterFailure = false
|
continueAfterFailure = false
|
||||||
|
|
||||||
// In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
|
// In UI tests it’s important to set the initial state - such as interface
|
||||||
|
// orientation - required for your tests before they run.
|
||||||
|
// The setUp method is a good place to do this.
|
||||||
}
|
}
|
||||||
|
|
||||||
override func tearDownWithError() throws {
|
override func tearDown() {
|
||||||
|
super.tearDown()
|
||||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,28 +4,16 @@ import Foundation
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
class ___FILEBASENAMEASIDENTIFIER___: Router {
|
class ___FILEBASENAMEASIDENTIFIER___: Router {
|
||||||
|
|
||||||
// MARK: - Published vars
|
|
||||||
// Put published vars here
|
|
||||||
|
|
||||||
// MARK: - Private vars
|
|
||||||
|
|
||||||
// MARK: - Internal vars
|
|
||||||
var services: Services
|
var services: Services
|
||||||
|
|
||||||
// MARK: - Initialization
|
|
||||||
|
|
||||||
init(services: Services) {
|
init(services: Services) {
|
||||||
self.services = services
|
self.services = services
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Methods
|
|
||||||
|
|
||||||
func rootView() -> some View {
|
func rootView() -> some View {
|
||||||
// Add your content here
|
// Add your content here
|
||||||
NavigationView {
|
NavigationView {
|
||||||
Text("Hello Word")
|
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,14 @@
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
protocol ___FILEBASENAMEASIDENTIFIER___Router: AnyObject {
|
protocol ___FILEBASENAMEASIDENTIFIER___Router: AnyObject {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ___FILEBASENAMEASIDENTIFIER___: View {
|
struct ___FILEBASENAMEASIDENTIFIER___: View {
|
||||||
@State var router: ___FILEBASENAMEASIDENTIFIER___Router?
|
|
||||||
|
|
||||||
@ObservedObject var viewModel: ___FILEBASENAME___ViewModel
|
@ObservedObject var viewModel: ___FILEBASENAME___ViewModel
|
||||||
|
|
||||||
|
@State var router: ___FILEBASENAMEASIDENTIFIER___Router?
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
|
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,5 +4,6 @@ import Foundation
|
||||||
import Combine
|
import Combine
|
||||||
|
|
||||||
class ___FILEBASENAMEASIDENTIFIER___: BaseViewModel<Services>, ObservableObject {
|
class ___FILEBASENAMEASIDENTIFIER___: BaseViewModel<Services>, ObservableObject {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue